@h-rig/runtime 0.0.6-alpha.28 → 0.0.6-alpha.29
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 +552 -483
- package/dist/bin/rig-agent.js +418 -364
- package/dist/src/control-plane/agent-wrapper.js +557 -488
- package/dist/src/control-plane/harness-main.js +559 -1418
- package/dist/src/control-plane/hooks/completion-verification.js +451 -808
- package/dist/src/control-plane/hooks/inject-context.js +191 -137
- package/dist/src/control-plane/hooks/submodule-branch.js +596 -542
- package/dist/src/control-plane/hooks/task-runtime-start.js +596 -542
- package/dist/src/control-plane/materialize-task-config.js +64 -8
- package/dist/src/control-plane/native/git-ops.js +3 -0
- package/dist/src/control-plane/native/harness-cli.js +544 -496
- package/dist/src/control-plane/native/repo-ops.js +3 -0
- package/dist/src/control-plane/native/run-ops.js +3 -0
- package/dist/src/control-plane/native/task-ops.js +418 -370
- package/dist/src/control-plane/native/validator.js +161 -107
- package/dist/src/control-plane/native/verifier.js +217 -169
- package/dist/src/control-plane/pi-sessiond/launcher.js +12 -2
- package/dist/src/control-plane/plugin-host-context.js +54 -0
- package/dist/src/control-plane/runtime/image/fingerprint-sidecar.js +3 -0
- package/dist/src/control-plane/runtime/image/index.js +3 -0
- package/dist/src/control-plane/runtime/image-fingerprint-sidecar.js +3 -0
- package/dist/src/control-plane/runtime/image.js +3 -0
- package/dist/src/control-plane/runtime/index.js +487 -718
- package/dist/src/control-plane/runtime/isolation/index.js +511 -457
- package/dist/src/control-plane/runtime/isolation.js +511 -457
- package/dist/src/control-plane/runtime/plugin-mode.js +3 -27
- package/dist/src/control-plane/runtime/queue.js +428 -381
- package/dist/src/control-plane/runtime/snapshot/task-run.js +3 -0
- package/dist/src/control-plane/runtime/task-run-snapshot.js +3 -0
- package/dist/src/control-plane/skill-materializer.js +46 -0
- package/dist/src/control-plane/tasks/source-lifecycle.js +84 -30
- package/dist/src/index.js +0 -278
- package/native/darwin-arm64/rig-shell +0 -0
- package/native/darwin-arm64/rig-shell.build-manifest.json +1 -1
- package/native/darwin-arm64/rig-tools +0 -0
- package/native/darwin-arm64/rig-tools.build-manifest.json +1 -1
- package/package.json +8 -7
- package/dist/src/control-plane/runtime/plugins.js +0 -1131
- package/dist/src/plugins.js +0 -329
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// packages/runtime/src/control-plane/harness-main.ts
|
|
5
|
-
import { resolve as
|
|
5
|
+
import { resolve as resolve33 } from "path";
|
|
6
6
|
|
|
7
7
|
// packages/runtime/src/control-plane/native/harness-cli.ts
|
|
8
|
-
import { existsSync as
|
|
9
|
-
import { resolve as
|
|
8
|
+
import { existsSync as existsSync29 } from "fs";
|
|
9
|
+
import { resolve as resolve30 } from "path";
|
|
10
10
|
|
|
11
11
|
// packages/runtime/src/control-plane/native/git-ops.ts
|
|
12
|
-
import { existsSync as
|
|
13
|
-
import { dirname as dirname11, isAbsolute as isAbsolute2, resolve as
|
|
12
|
+
import { existsSync as existsSync22, lstatSync, mkdirSync as mkdirSync11, readFileSync as readFileSync12, writeFileSync as writeFileSync11 } from "fs";
|
|
13
|
+
import { dirname as dirname11, isAbsolute as isAbsolute2, resolve as resolve25 } from "path";
|
|
14
14
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
15
15
|
|
|
16
16
|
// packages/runtime/src/control-plane/runtime/baked-secrets.ts
|
|
@@ -279,8 +279,8 @@ function isAgentRuntimeContextPath(path) {
|
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
// packages/runtime/src/control-plane/native/task-ops.ts
|
|
282
|
-
import { appendFileSync, existsSync as
|
|
283
|
-
import { resolve as
|
|
282
|
+
import { appendFileSync, existsSync as existsSync21, mkdirSync as mkdirSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync10 } from "fs";
|
|
283
|
+
import { resolve as resolve24 } from "path";
|
|
284
284
|
|
|
285
285
|
// packages/runtime/src/build-time-config.ts
|
|
286
286
|
function normalizeBuildConfig(value) {
|
|
@@ -765,6 +765,49 @@ function safeReadJson(path) {
|
|
|
765
765
|
}
|
|
766
766
|
}
|
|
767
767
|
|
|
768
|
+
// packages/runtime/src/control-plane/skill-materializer.ts
|
|
769
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, readdirSync, rmSync, writeFileSync as writeFileSync3 } from "fs";
|
|
770
|
+
import { resolve as resolve7 } from "path";
|
|
771
|
+
import { loadSkill } from "@rig/skill-loader";
|
|
772
|
+
var MARKER_FILENAME = ".rig-plugin";
|
|
773
|
+
function skillDirName(id) {
|
|
774
|
+
return id.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
775
|
+
}
|
|
776
|
+
async function materializeSkills(projectRoot, entries) {
|
|
777
|
+
const skillsRoot = resolve7(projectRoot, ".pi", "skills");
|
|
778
|
+
if (existsSync5(skillsRoot)) {
|
|
779
|
+
for (const name of readdirSync(skillsRoot)) {
|
|
780
|
+
const dir = resolve7(skillsRoot, name);
|
|
781
|
+
if (existsSync5(resolve7(dir, MARKER_FILENAME))) {
|
|
782
|
+
rmSync(dir, { recursive: true, force: true });
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
const written = [];
|
|
787
|
+
for (const { pluginName, skill } of entries) {
|
|
788
|
+
const sourcePath = resolve7(projectRoot, skill.path);
|
|
789
|
+
if (!existsSync5(sourcePath)) {
|
|
790
|
+
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${sourcePath} does not exist`);
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
793
|
+
let body;
|
|
794
|
+
try {
|
|
795
|
+
await loadSkill(sourcePath);
|
|
796
|
+
body = readFileSync4(sourcePath, "utf-8");
|
|
797
|
+
} catch (err) {
|
|
798
|
+
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${err instanceof Error ? err.message : err}`);
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
const dir = resolve7(skillsRoot, skillDirName(skill.id));
|
|
802
|
+
mkdirSync3(dir, { recursive: true });
|
|
803
|
+
writeFileSync3(resolve7(dir, "SKILL.md"), body, "utf-8");
|
|
804
|
+
writeFileSync3(resolve7(dir, MARKER_FILENAME), `${JSON.stringify({ plugin: pluginName, skillId: skill.id }, null, 2)}
|
|
805
|
+
`, "utf-8");
|
|
806
|
+
written.push({ id: skill.id, pluginName, directory: dir });
|
|
807
|
+
}
|
|
808
|
+
return written;
|
|
809
|
+
}
|
|
810
|
+
|
|
768
811
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
769
812
|
async function buildPluginHostContext(projectRoot) {
|
|
770
813
|
let config;
|
|
@@ -801,6 +844,17 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
801
844
|
} catch (err) {
|
|
802
845
|
console.warn(`[plugin-host] hook materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
803
846
|
}
|
|
847
|
+
try {
|
|
848
|
+
const skillEntries = config.plugins.flatMap((plugin) => (plugin.contributes?.skills ?? []).map((skill) => ({
|
|
849
|
+
pluginName: plugin.name,
|
|
850
|
+
skill
|
|
851
|
+
})));
|
|
852
|
+
if (skillEntries.length > 0) {
|
|
853
|
+
await materializeSkills(projectRoot, skillEntries);
|
|
854
|
+
}
|
|
855
|
+
} catch (err) {
|
|
856
|
+
console.warn(`[plugin-host] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
857
|
+
}
|
|
804
858
|
return {
|
|
805
859
|
config,
|
|
806
860
|
pluginHost,
|
|
@@ -814,12 +868,12 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
814
868
|
|
|
815
869
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
816
870
|
import { spawnSync } from "child_process";
|
|
817
|
-
import { existsSync as
|
|
818
|
-
import { basename as basename3, join as join2, resolve as
|
|
871
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync2, statSync, writeFileSync as writeFileSync4 } from "fs";
|
|
872
|
+
import { basename as basename3, join as join2, resolve as resolve9 } from "path";
|
|
819
873
|
|
|
820
874
|
// packages/runtime/src/control-plane/tasks/legacy-task-config-source.ts
|
|
821
|
-
import { existsSync as
|
|
822
|
-
import { resolve as
|
|
875
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
|
|
876
|
+
import { resolve as resolve8 } from "path";
|
|
823
877
|
|
|
824
878
|
// packages/runtime/src/control-plane/tasks/task-record-reader.ts
|
|
825
879
|
async function findTaskById(reader, id) {
|
|
@@ -842,7 +896,7 @@ class LegacyTaskConfigReadError extends Error {
|
|
|
842
896
|
}
|
|
843
897
|
}
|
|
844
898
|
function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
845
|
-
const configPath = options.configPath ??
|
|
899
|
+
const configPath = options.configPath ?? resolve8(projectRoot, ".rig", "task-config.json");
|
|
846
900
|
const reader = {
|
|
847
901
|
async listTasks() {
|
|
848
902
|
return readLegacyTaskRecords(projectRoot, configPath);
|
|
@@ -853,8 +907,8 @@ function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
|
853
907
|
};
|
|
854
908
|
return reader;
|
|
855
909
|
}
|
|
856
|
-
function readLegacyTaskRecords(projectRoot, configPath =
|
|
857
|
-
if (!
|
|
910
|
+
function readLegacyTaskRecords(projectRoot, configPath = resolve8(projectRoot, ".rig", "task-config.json")) {
|
|
911
|
+
if (!existsSync6(configPath)) {
|
|
858
912
|
return [];
|
|
859
913
|
}
|
|
860
914
|
const rawConfig = readLegacyTaskConfigJson(projectRoot, configPath);
|
|
@@ -862,7 +916,7 @@ function readLegacyTaskRecords(projectRoot, configPath = resolve7(projectRoot, "
|
|
|
862
916
|
}
|
|
863
917
|
function readLegacyTaskConfigJson(projectRoot, configPath) {
|
|
864
918
|
try {
|
|
865
|
-
const parsed = JSON.parse(
|
|
919
|
+
const parsed = JSON.parse(readFileSync5(configPath, "utf8"));
|
|
866
920
|
if (isPlainRecord(parsed)) {
|
|
867
921
|
return parsed;
|
|
868
922
|
}
|
|
@@ -946,7 +1000,7 @@ function isPlainRecord(candidate) {
|
|
|
946
1000
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
947
1001
|
var FILE_TASK_PATTERN = /\.(task\.)?json$/;
|
|
948
1002
|
function createSourceAwareTaskConfigRecordReader(projectRoot, options = {}) {
|
|
949
|
-
const configPath = options.configPath ??
|
|
1003
|
+
const configPath = options.configPath ?? resolve9(projectRoot, ".rig", "task-config.json");
|
|
950
1004
|
const legacy = createLegacyTaskConfigRecordReader(projectRoot, { configPath });
|
|
951
1005
|
const spawnFn = options.spawn ?? spawnSync;
|
|
952
1006
|
const ghBinary = options.ghBinary ?? "gh";
|
|
@@ -1029,10 +1083,10 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
1029
1083
|
return metadata;
|
|
1030
1084
|
}
|
|
1031
1085
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
1032
|
-
const jsonPath =
|
|
1033
|
-
if (
|
|
1086
|
+
const jsonPath = resolve9(projectRoot, "rig.config.json");
|
|
1087
|
+
if (existsSync7(jsonPath)) {
|
|
1034
1088
|
try {
|
|
1035
|
-
const parsed = JSON.parse(
|
|
1089
|
+
const parsed = JSON.parse(readFileSync6(jsonPath, "utf8"));
|
|
1036
1090
|
if (isPlainRecord2(parsed) && isPlainRecord2(parsed.taskSource)) {
|
|
1037
1091
|
const source = parsed.taskSource;
|
|
1038
1092
|
return source.kind === "files" && typeof source.path === "string" ? source.path : null;
|
|
@@ -1041,12 +1095,12 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
1041
1095
|
return null;
|
|
1042
1096
|
}
|
|
1043
1097
|
}
|
|
1044
|
-
const tsPath =
|
|
1045
|
-
if (!
|
|
1098
|
+
const tsPath = resolve9(projectRoot, "rig.config.ts");
|
|
1099
|
+
if (!existsSync7(tsPath)) {
|
|
1046
1100
|
return null;
|
|
1047
1101
|
}
|
|
1048
1102
|
try {
|
|
1049
|
-
const source =
|
|
1103
|
+
const source = readFileSync6(tsPath, "utf8");
|
|
1050
1104
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
1051
1105
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
1052
1106
|
if (kind !== "files") {
|
|
@@ -1066,10 +1120,10 @@ function readRawTaskEntry(configPath, taskId) {
|
|
|
1066
1120
|
return isPlainRecord2(entry) ? entry : null;
|
|
1067
1121
|
}
|
|
1068
1122
|
function readRawTaskConfig(configPath) {
|
|
1069
|
-
if (!
|
|
1123
|
+
if (!existsSync7(configPath)) {
|
|
1070
1124
|
return null;
|
|
1071
1125
|
}
|
|
1072
|
-
const parsed = JSON.parse(
|
|
1126
|
+
const parsed = JSON.parse(readFileSync6(configPath, "utf8"));
|
|
1073
1127
|
return isPlainRecord2(parsed) ? parsed : null;
|
|
1074
1128
|
}
|
|
1075
1129
|
function stripLegacyTaskConfigMetadata2(raw) {
|
|
@@ -1077,12 +1131,12 @@ function stripLegacyTaskConfigMetadata2(raw) {
|
|
|
1077
1131
|
return tasks;
|
|
1078
1132
|
}
|
|
1079
1133
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
1080
|
-
const directory =
|
|
1081
|
-
if (!
|
|
1134
|
+
const directory = resolve9(projectRoot, sourcePath);
|
|
1135
|
+
if (!existsSync7(directory)) {
|
|
1082
1136
|
return [];
|
|
1083
1137
|
}
|
|
1084
1138
|
const tasks = [];
|
|
1085
|
-
for (const name of
|
|
1139
|
+
for (const name of readdirSync2(directory)) {
|
|
1086
1140
|
if (!FILE_TASK_PATTERN.test(name))
|
|
1087
1141
|
continue;
|
|
1088
1142
|
const inferredId = basename3(name).replace(FILE_TASK_PATTERN, "");
|
|
@@ -1093,11 +1147,11 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
1093
1147
|
return tasks;
|
|
1094
1148
|
}
|
|
1095
1149
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
1096
|
-
const file = findFileBackedTaskFile(
|
|
1150
|
+
const file = findFileBackedTaskFile(resolve9(projectRoot, sourcePath), taskId);
|
|
1097
1151
|
if (!file) {
|
|
1098
1152
|
return null;
|
|
1099
1153
|
}
|
|
1100
|
-
const raw = JSON.parse(
|
|
1154
|
+
const raw = JSON.parse(readFileSync6(file, "utf8"));
|
|
1101
1155
|
if (!isPlainRecord2(raw)) {
|
|
1102
1156
|
return null;
|
|
1103
1157
|
}
|
|
@@ -1110,17 +1164,17 @@ function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
|
1110
1164
|
};
|
|
1111
1165
|
}
|
|
1112
1166
|
function findFileBackedTaskFile(directory, taskId) {
|
|
1113
|
-
if (!
|
|
1167
|
+
if (!existsSync7(directory)) {
|
|
1114
1168
|
return null;
|
|
1115
1169
|
}
|
|
1116
|
-
for (const name of
|
|
1170
|
+
for (const name of readdirSync2(directory)) {
|
|
1117
1171
|
if (!FILE_TASK_PATTERN.test(name))
|
|
1118
1172
|
continue;
|
|
1119
1173
|
const file = join2(directory, name);
|
|
1120
1174
|
try {
|
|
1121
1175
|
if (!statSync(file).isFile())
|
|
1122
1176
|
continue;
|
|
1123
|
-
const raw = JSON.parse(
|
|
1177
|
+
const raw = JSON.parse(readFileSync6(file, "utf8"));
|
|
1124
1178
|
const inferredId = basename3(file).replace(FILE_TASK_PATTERN, "");
|
|
1125
1179
|
const id = isPlainRecord2(raw) && typeof raw.id === "string" ? raw.id : inferredId;
|
|
1126
1180
|
if (id === taskId) {
|
|
@@ -1280,8 +1334,8 @@ async function readConfiguredTaskSourceTask(projectRoot, taskId) {
|
|
|
1280
1334
|
}
|
|
1281
1335
|
|
|
1282
1336
|
// packages/runtime/src/control-plane/native/task-state.ts
|
|
1283
|
-
import { existsSync as
|
|
1284
|
-
import { basename as basename6, resolve as
|
|
1337
|
+
import { existsSync as existsSync15, readFileSync as readFileSync10, readdirSync as readdirSync3, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
1338
|
+
import { basename as basename6, resolve as resolve17 } from "path";
|
|
1285
1339
|
|
|
1286
1340
|
// packages/runtime/src/control-plane/state-sync/types.ts
|
|
1287
1341
|
var SUPPORTED_TASK_STATE_SCHEMA_VERSION = 1;
|
|
@@ -1389,30 +1443,30 @@ function readTaskStateMetadataEnvelope(raw) {
|
|
|
1389
1443
|
};
|
|
1390
1444
|
}
|
|
1391
1445
|
// packages/runtime/src/control-plane/state-sync/read.ts
|
|
1392
|
-
import { existsSync as
|
|
1393
|
-
import { resolve as
|
|
1446
|
+
import { existsSync as existsSync14, readFileSync as readFileSync9 } from "fs";
|
|
1447
|
+
import { resolve as resolve16 } from "path";
|
|
1394
1448
|
|
|
1395
1449
|
// packages/runtime/src/control-plane/native/git-native.ts
|
|
1396
|
-
import { chmodSync, copyFileSync, existsSync as
|
|
1450
|
+
import { chmodSync, copyFileSync, existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync7, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
1397
1451
|
import { tmpdir as tmpdir3 } from "os";
|
|
1398
|
-
import { dirname as dirname5, isAbsolute, resolve as
|
|
1452
|
+
import { dirname as dirname5, isAbsolute, resolve as resolve10 } from "path";
|
|
1399
1453
|
import { createHash } from "crypto";
|
|
1400
1454
|
function isTextTreeCommitUpdate(update) {
|
|
1401
1455
|
return typeof update.content === "string";
|
|
1402
1456
|
}
|
|
1403
|
-
var sharedGitNativeOutputDir =
|
|
1404
|
-
var sharedGitNativeOutputPath =
|
|
1457
|
+
var sharedGitNativeOutputDir = resolve10(tmpdir3(), "rig-native");
|
|
1458
|
+
var sharedGitNativeOutputPath = resolve10(sharedGitNativeOutputDir, `rig-git-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
1405
1459
|
var trackerCommandUsageProbe = "usage: rig-git fetch-ref <repo-path> <remote> <branch>";
|
|
1406
1460
|
function temporaryGitBinaryOutputPath(outputPath) {
|
|
1407
1461
|
const suffix = process.platform === "win32" ? ".exe" : "";
|
|
1408
|
-
return
|
|
1462
|
+
return resolve10(dirname5(outputPath), `.rig-git-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}${suffix}`);
|
|
1409
1463
|
}
|
|
1410
1464
|
function publishGitBinary(tempOutputPath, outputPath) {
|
|
1411
1465
|
try {
|
|
1412
1466
|
renameSync(tempOutputPath, outputPath);
|
|
1413
1467
|
} catch (error) {
|
|
1414
|
-
if (process.platform === "win32" &&
|
|
1415
|
-
|
|
1468
|
+
if (process.platform === "win32" && existsSync8(outputPath)) {
|
|
1469
|
+
rmSync2(outputPath, { force: true });
|
|
1416
1470
|
renameSync(tempOutputPath, outputPath);
|
|
1417
1471
|
return;
|
|
1418
1472
|
}
|
|
@@ -1427,22 +1481,22 @@ function rigGitSourceCandidates() {
|
|
|
1427
1481
|
const cwd = process.cwd()?.trim() || "";
|
|
1428
1482
|
const projectRoot = process.env.PROJECT_RIG_ROOT?.trim() || "";
|
|
1429
1483
|
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || "";
|
|
1430
|
-
const moduleRelativeSource =
|
|
1484
|
+
const moduleRelativeSource = resolve10(import.meta.dir, "../../../native/rig-git.zig");
|
|
1431
1485
|
return [...new Set([
|
|
1432
1486
|
process.env.RIG_NATIVE_GIT_SOURCE?.trim() || "",
|
|
1433
1487
|
moduleRelativeSource,
|
|
1434
|
-
projectRoot ?
|
|
1435
|
-
hostProjectRoot ?
|
|
1436
|
-
cwd ?
|
|
1437
|
-
execDir ?
|
|
1438
|
-
execDir ?
|
|
1488
|
+
projectRoot ? resolve10(projectRoot, "packages/runtime/native/rig-git.zig") : "",
|
|
1489
|
+
hostProjectRoot ? resolve10(hostProjectRoot, "packages/runtime/native/rig-git.zig") : "",
|
|
1490
|
+
cwd ? resolve10(cwd, "packages/runtime/native/rig-git.zig") : "",
|
|
1491
|
+
execDir ? resolve10(execDir, "..", "..", "packages/runtime/native/rig-git.zig") : "",
|
|
1492
|
+
execDir ? resolve10(execDir, "..", "native", "rig-git.zig") : ""
|
|
1439
1493
|
].filter(Boolean))];
|
|
1440
1494
|
}
|
|
1441
1495
|
function nativePackageBinaryCandidates(fromDir, fileName) {
|
|
1442
1496
|
const candidates = [];
|
|
1443
|
-
let cursor =
|
|
1497
|
+
let cursor = resolve10(fromDir);
|
|
1444
1498
|
for (let index = 0;index < 8; index += 1) {
|
|
1445
|
-
candidates.push(
|
|
1499
|
+
candidates.push(resolve10(cursor, "native", `${process.platform}-${process.arch}`, fileName), resolve10(cursor, "native", `${process.platform}-${process.arch}`, "bin", fileName), resolve10(cursor, "native", fileName), resolve10(cursor, "native", "bin", fileName));
|
|
1446
1500
|
const parent = dirname5(cursor);
|
|
1447
1501
|
if (parent === cursor)
|
|
1448
1502
|
break;
|
|
@@ -1457,15 +1511,15 @@ function rigGitBinaryCandidates() {
|
|
|
1457
1511
|
return [...new Set([
|
|
1458
1512
|
explicit,
|
|
1459
1513
|
...nativePackageBinaryCandidates(import.meta.dir, fileName),
|
|
1460
|
-
execDir ?
|
|
1461
|
-
execDir ?
|
|
1462
|
-
execDir ?
|
|
1514
|
+
execDir ? resolve10(execDir, fileName) : "",
|
|
1515
|
+
execDir ? resolve10(execDir, "..", fileName) : "",
|
|
1516
|
+
execDir ? resolve10(execDir, "..", "bin", fileName) : "",
|
|
1463
1517
|
sharedGitNativeOutputPath
|
|
1464
1518
|
].filter(Boolean))];
|
|
1465
1519
|
}
|
|
1466
1520
|
function resolveGitSourcePath() {
|
|
1467
1521
|
for (const candidate of rigGitSourceCandidates()) {
|
|
1468
|
-
if (candidate &&
|
|
1522
|
+
if (candidate && existsSync8(candidate)) {
|
|
1469
1523
|
return candidate;
|
|
1470
1524
|
}
|
|
1471
1525
|
}
|
|
@@ -1476,7 +1530,7 @@ function resolveGitBinaryPath() {
|
|
|
1476
1530
|
return null;
|
|
1477
1531
|
}
|
|
1478
1532
|
for (const candidate of rigGitBinaryCandidates()) {
|
|
1479
|
-
if (candidate &&
|
|
1533
|
+
if (candidate && existsSync8(candidate)) {
|
|
1480
1534
|
return candidate;
|
|
1481
1535
|
}
|
|
1482
1536
|
}
|
|
@@ -1506,18 +1560,18 @@ function nativeBuildManifestPath(outputPath) {
|
|
|
1506
1560
|
return `${outputPath}.build-manifest.json`;
|
|
1507
1561
|
}
|
|
1508
1562
|
function hasMatchingNativeBuildManifestSync(manifestPath, buildKey) {
|
|
1509
|
-
if (!
|
|
1563
|
+
if (!existsSync8(manifestPath)) {
|
|
1510
1564
|
return false;
|
|
1511
1565
|
}
|
|
1512
1566
|
try {
|
|
1513
|
-
const manifest = JSON.parse(
|
|
1567
|
+
const manifest = JSON.parse(readFileSync7(manifestPath, "utf8"));
|
|
1514
1568
|
return manifest.version === 1 && manifest.buildKey === buildKey;
|
|
1515
1569
|
} catch {
|
|
1516
1570
|
return false;
|
|
1517
1571
|
}
|
|
1518
1572
|
}
|
|
1519
1573
|
function sha256FileSync(path) {
|
|
1520
|
-
return createHash("sha256").update(
|
|
1574
|
+
return createHash("sha256").update(readFileSync7(path)).digest("hex");
|
|
1521
1575
|
}
|
|
1522
1576
|
function ensureRigGitBinaryPathSync(outputPath = preferredGitBinaryOutputPath()) {
|
|
1523
1577
|
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
@@ -1535,7 +1589,7 @@ function ensureRigGitBinaryPathSync(outputPath = preferredGitBinaryOutputPath())
|
|
|
1535
1589
|
if (!zigBinary) {
|
|
1536
1590
|
throw new Error("zig is required to build native Rig git tools.");
|
|
1537
1591
|
}
|
|
1538
|
-
|
|
1592
|
+
mkdirSync4(dirname5(outputPath), { recursive: true });
|
|
1539
1593
|
const sourceDigest = sha256FileSync(sourcePath);
|
|
1540
1594
|
const buildKey = JSON.stringify({
|
|
1541
1595
|
version: 1,
|
|
@@ -1546,7 +1600,7 @@ function ensureRigGitBinaryPathSync(outputPath = preferredGitBinaryOutputPath())
|
|
|
1546
1600
|
sourceDigest
|
|
1547
1601
|
});
|
|
1548
1602
|
const manifestPath = nativeBuildManifestPath(outputPath);
|
|
1549
|
-
const needsBuild = !
|
|
1603
|
+
const needsBuild = !existsSync8(outputPath) || !hasMatchingNativeBuildManifestSync(manifestPath, buildKey) || !binarySupportsTrackerCommandsSync(outputPath);
|
|
1550
1604
|
if (!needsBuild) {
|
|
1551
1605
|
chmodSync(outputPath, 493);
|
|
1552
1606
|
return outputPath;
|
|
@@ -1564,7 +1618,7 @@ function ensureRigGitBinaryPathSync(outputPath = preferredGitBinaryOutputPath())
|
|
|
1564
1618
|
stdout: "pipe",
|
|
1565
1619
|
stderr: "pipe"
|
|
1566
1620
|
});
|
|
1567
|
-
if (build.exitCode !== 0 || !
|
|
1621
|
+
if (build.exitCode !== 0 || !existsSync8(tempOutputPath)) {
|
|
1568
1622
|
const stderr = build.stderr.toString().trim();
|
|
1569
1623
|
const stdout = build.stdout.toString().trim();
|
|
1570
1624
|
const details = [stderr, stdout].filter(Boolean).join(`
|
|
@@ -1572,17 +1626,17 @@ function ensureRigGitBinaryPathSync(outputPath = preferredGitBinaryOutputPath())
|
|
|
1572
1626
|
throw new Error(`Failed to build native Rig git tools: ${details || `zig exited with code ${build.exitCode}`}`);
|
|
1573
1627
|
}
|
|
1574
1628
|
chmodSync(tempOutputPath, 493);
|
|
1575
|
-
if (
|
|
1576
|
-
|
|
1629
|
+
if (existsSync8(outputPath) && hasMatchingNativeBuildManifestSync(manifestPath, buildKey)) {
|
|
1630
|
+
rmSync2(tempOutputPath, { force: true });
|
|
1577
1631
|
chmodSync(outputPath, 493);
|
|
1578
1632
|
return outputPath;
|
|
1579
1633
|
}
|
|
1580
1634
|
publishGitBinary(tempOutputPath, outputPath);
|
|
1581
1635
|
if (!binarySupportsTrackerCommandsSync(outputPath)) {
|
|
1582
|
-
|
|
1636
|
+
rmSync2(outputPath, { force: true });
|
|
1583
1637
|
throw new Error("Failed to build native Rig git tools: tracker command probe failed");
|
|
1584
1638
|
}
|
|
1585
|
-
|
|
1639
|
+
writeFileSync5(manifestPath, `${JSON.stringify({ version: 1, buildKey }, null, 2)}
|
|
1586
1640
|
`, "utf8");
|
|
1587
1641
|
return outputPath;
|
|
1588
1642
|
}
|
|
@@ -1604,7 +1658,7 @@ function runGitNative(command, args) {
|
|
|
1604
1658
|
}
|
|
1605
1659
|
} else {
|
|
1606
1660
|
const explicitBinaryPath = process.env.RIG_NATIVE_GIT_BIN?.trim() || "";
|
|
1607
|
-
binaryPath = explicitBinaryPath &&
|
|
1661
|
+
binaryPath = explicitBinaryPath && existsSync8(explicitBinaryPath) ? explicitBinaryPath : !explicitBinaryPath ? resolveGitBinaryPath() : null;
|
|
1608
1662
|
if (!binaryPath) {
|
|
1609
1663
|
try {
|
|
1610
1664
|
binaryPath = ensureRigGitBinaryPathSync(preferredGitBinaryOutputPath());
|
|
@@ -1701,25 +1755,25 @@ function nativeFetchRef(repoPath, remote, branch) {
|
|
|
1701
1755
|
return requireGitNativeString("fetch-ref", [repoPath, remote, branch]);
|
|
1702
1756
|
}
|
|
1703
1757
|
function nativeReadBlobAtRef(repoPath, ref, path) {
|
|
1704
|
-
const requestDir =
|
|
1705
|
-
|
|
1706
|
-
const outputPath =
|
|
1758
|
+
const requestDir = resolve10(sharedGitNativeOutputDir, "reads", `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`);
|
|
1759
|
+
mkdirSync4(requestDir, { recursive: true });
|
|
1760
|
+
const outputPath = resolve10(requestDir, "blob.txt");
|
|
1707
1761
|
try {
|
|
1708
1762
|
requireGitNative("read-blob-at-ref", [repoPath, ref, path, outputPath]);
|
|
1709
|
-
return
|
|
1763
|
+
return readFileSync7(outputPath, "utf8");
|
|
1710
1764
|
} finally {
|
|
1711
|
-
|
|
1765
|
+
rmSync2(requestDir, { recursive: true, force: true });
|
|
1712
1766
|
}
|
|
1713
1767
|
}
|
|
1714
1768
|
function nativeReadBlobBytesAtRef(repoPath, ref, path) {
|
|
1715
|
-
const requestDir =
|
|
1716
|
-
|
|
1717
|
-
const outputPath =
|
|
1769
|
+
const requestDir = resolve10(sharedGitNativeOutputDir, "reads", `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`);
|
|
1770
|
+
mkdirSync4(requestDir, { recursive: true });
|
|
1771
|
+
const outputPath = resolve10(requestDir, "blob.bin");
|
|
1718
1772
|
try {
|
|
1719
1773
|
requireGitNative("read-blob-at-ref", [repoPath, ref, path, outputPath]);
|
|
1720
|
-
return
|
|
1774
|
+
return readFileSync7(outputPath);
|
|
1721
1775
|
} finally {
|
|
1722
|
-
|
|
1776
|
+
rmSync2(requestDir, { recursive: true, force: true });
|
|
1723
1777
|
}
|
|
1724
1778
|
}
|
|
1725
1779
|
function serializeTreeCommitUpdates(updates) {
|
|
@@ -1738,16 +1792,16 @@ function buildTreeCommitUpdatesJson(updates) {
|
|
|
1738
1792
|
`;
|
|
1739
1793
|
}
|
|
1740
1794
|
function nativeWriteTreeCommit(repoPath, baseRef, updates, message) {
|
|
1741
|
-
const requestDir =
|
|
1742
|
-
|
|
1743
|
-
const messagePath =
|
|
1744
|
-
const updatesPath =
|
|
1795
|
+
const requestDir = resolve10(sharedGitNativeOutputDir, "requests", `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`);
|
|
1796
|
+
mkdirSync4(requestDir, { recursive: true });
|
|
1797
|
+
const messagePath = resolve10(requestDir, "message.txt");
|
|
1798
|
+
const updatesPath = resolve10(requestDir, "updates.json");
|
|
1745
1799
|
try {
|
|
1746
|
-
|
|
1747
|
-
|
|
1800
|
+
writeFileSync5(messagePath, message, "utf8");
|
|
1801
|
+
writeFileSync5(updatesPath, buildTreeCommitUpdatesJson(updates), "utf8");
|
|
1748
1802
|
return requireGitNativeString("write-tree-commit", [repoPath, baseRef, messagePath, updatesPath]);
|
|
1749
1803
|
} finally {
|
|
1750
|
-
|
|
1804
|
+
rmSync2(requestDir, { recursive: true, force: true });
|
|
1751
1805
|
}
|
|
1752
1806
|
}
|
|
1753
1807
|
function nativePushRefWithLease(repoPath, localOid, remoteRef, expectedOldOid, remote = "origin") {
|
|
@@ -1762,36 +1816,36 @@ function nativePushRefWithLease(repoPath, localOid, remoteRef, expectedOldOid, r
|
|
|
1762
1816
|
|
|
1763
1817
|
// packages/runtime/src/control-plane/native/utils.ts
|
|
1764
1818
|
import { ptr as ptr2 } from "bun:ffi";
|
|
1765
|
-
import { existsSync as
|
|
1766
|
-
import { resolve as
|
|
1819
|
+
import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
|
|
1820
|
+
import { resolve as resolve13 } from "path";
|
|
1767
1821
|
|
|
1768
1822
|
// packages/runtime/src/layout.ts
|
|
1769
|
-
import { existsSync as
|
|
1770
|
-
import { basename as basename4, dirname as dirname6, resolve as
|
|
1823
|
+
import { existsSync as existsSync9 } from "fs";
|
|
1824
|
+
import { basename as basename4, dirname as dirname6, resolve as resolve11 } from "path";
|
|
1771
1825
|
var RIG_DEFINITION_DIRNAME = "rig";
|
|
1772
1826
|
var RIG_STATE_DIRNAME = ".rig";
|
|
1773
1827
|
var RIG_ARTIFACTS_DIRNAME = "artifacts";
|
|
1774
1828
|
function resolveMonorepoRoot(projectRoot) {
|
|
1775
|
-
const normalizedProjectRoot =
|
|
1829
|
+
const normalizedProjectRoot = resolve11(projectRoot);
|
|
1776
1830
|
const explicit = process.env.MONOREPO_ROOT?.trim();
|
|
1777
1831
|
if (explicit) {
|
|
1778
|
-
const explicitRoot =
|
|
1832
|
+
const explicitRoot = resolve11(explicit);
|
|
1779
1833
|
const explicitParent = dirname6(explicitRoot);
|
|
1780
1834
|
if (basename4(explicitParent) === ".worktrees") {
|
|
1781
1835
|
const owner = dirname6(explicitParent);
|
|
1782
|
-
const ownerHasGit =
|
|
1783
|
-
const ownerHasTaskConfig =
|
|
1784
|
-
const ownerHasRigConfig =
|
|
1836
|
+
const ownerHasGit = existsSync9(resolve11(owner, ".git"));
|
|
1837
|
+
const ownerHasTaskConfig = existsSync9(resolve11(owner, ".rig", "task-config.json"));
|
|
1838
|
+
const ownerHasRigConfig = existsSync9(resolve11(owner, "rig.config.ts"));
|
|
1785
1839
|
if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
|
|
1786
1840
|
return owner;
|
|
1787
1841
|
}
|
|
1788
1842
|
throw new Error(`MONOREPO_ROOT points to worktree ${explicitRoot}, but the owner checkout is incomplete at ${owner}.`);
|
|
1789
1843
|
}
|
|
1790
|
-
if (!
|
|
1844
|
+
if (!existsSync9(resolve11(explicitRoot, ".git"))) {
|
|
1791
1845
|
throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but no git checkout was found there.`);
|
|
1792
1846
|
}
|
|
1793
|
-
const hasTaskConfig =
|
|
1794
|
-
const hasRigConfig =
|
|
1847
|
+
const hasTaskConfig = existsSync9(resolve11(explicitRoot, ".rig", "task-config.json"));
|
|
1848
|
+
const hasRigConfig = existsSync9(resolve11(explicitRoot, "rig.config.ts"));
|
|
1795
1849
|
if (!hasTaskConfig && !hasRigConfig) {
|
|
1796
1850
|
throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but neither .rig/task-config.json nor rig.config.ts exists there.`);
|
|
1797
1851
|
}
|
|
@@ -1800,9 +1854,9 @@ function resolveMonorepoRoot(projectRoot) {
|
|
|
1800
1854
|
const projectParent = dirname6(normalizedProjectRoot);
|
|
1801
1855
|
if (basename4(projectParent) === ".worktrees") {
|
|
1802
1856
|
const worktreeOwner = dirname6(projectParent);
|
|
1803
|
-
const ownerHasGit =
|
|
1804
|
-
const ownerHasTaskConfig =
|
|
1805
|
-
const ownerHasRigConfig =
|
|
1857
|
+
const ownerHasGit = existsSync9(resolve11(worktreeOwner, ".git"));
|
|
1858
|
+
const ownerHasTaskConfig = existsSync9(resolve11(worktreeOwner, ".rig", "task-config.json"));
|
|
1859
|
+
const ownerHasRigConfig = existsSync9(resolve11(worktreeOwner, "rig.config.ts"));
|
|
1806
1860
|
if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
|
|
1807
1861
|
return worktreeOwner;
|
|
1808
1862
|
}
|
|
@@ -1810,28 +1864,28 @@ function resolveMonorepoRoot(projectRoot) {
|
|
|
1810
1864
|
return normalizedProjectRoot;
|
|
1811
1865
|
}
|
|
1812
1866
|
function resolveRuntimeWorkspaceLayout(workspaceDir) {
|
|
1813
|
-
const root =
|
|
1814
|
-
const rigRoot =
|
|
1815
|
-
const logsDir =
|
|
1816
|
-
const stateDir =
|
|
1817
|
-
const runtimeDir =
|
|
1818
|
-
const binDir =
|
|
1867
|
+
const root = resolve11(workspaceDir);
|
|
1868
|
+
const rigRoot = resolve11(root, ".rig");
|
|
1869
|
+
const logsDir = resolve11(rigRoot, "logs");
|
|
1870
|
+
const stateDir = resolve11(rigRoot, "state");
|
|
1871
|
+
const runtimeDir = resolve11(rigRoot, "runtime");
|
|
1872
|
+
const binDir = resolve11(rigRoot, "bin");
|
|
1819
1873
|
return {
|
|
1820
1874
|
workspaceDir: root,
|
|
1821
1875
|
rigRoot,
|
|
1822
1876
|
stateDir,
|
|
1823
1877
|
logsDir,
|
|
1824
|
-
artifactsRoot:
|
|
1878
|
+
artifactsRoot: resolve11(root, RIG_ARTIFACTS_DIRNAME),
|
|
1825
1879
|
runtimeDir,
|
|
1826
|
-
homeDir:
|
|
1827
|
-
tmpDir:
|
|
1828
|
-
cacheDir:
|
|
1829
|
-
sessionDir:
|
|
1880
|
+
homeDir: resolve11(rigRoot, "home"),
|
|
1881
|
+
tmpDir: resolve11(rigRoot, "tmp"),
|
|
1882
|
+
cacheDir: resolve11(rigRoot, "cache"),
|
|
1883
|
+
sessionDir: resolve11(rigRoot, "session"),
|
|
1830
1884
|
binDir,
|
|
1831
|
-
distDir:
|
|
1832
|
-
pluginBinDir:
|
|
1833
|
-
contextPath:
|
|
1834
|
-
controlPlaneEventsFile:
|
|
1885
|
+
distDir: resolve11(rigRoot, "dist"),
|
|
1886
|
+
pluginBinDir: resolve11(binDir, "plugins"),
|
|
1887
|
+
contextPath: resolve11(rigRoot, "runtime-context.json"),
|
|
1888
|
+
controlPlaneEventsFile: resolve11(logsDir, "control-plane.events.jsonl")
|
|
1835
1889
|
};
|
|
1836
1890
|
}
|
|
1837
1891
|
function resolveActiveRuntimeWorkspaceRoot(monorepoRoot) {
|
|
@@ -1839,14 +1893,14 @@ function resolveActiveRuntimeWorkspaceRoot(monorepoRoot) {
|
|
|
1839
1893
|
if (!explicit) {
|
|
1840
1894
|
throw new Error("No active runtime workspace. Set RIG_TASK_WORKSPACE or provision a task runtime first.");
|
|
1841
1895
|
}
|
|
1842
|
-
return
|
|
1896
|
+
return resolve11(explicit);
|
|
1843
1897
|
}
|
|
1844
1898
|
function resolveRigLayout(projectRoot) {
|
|
1845
1899
|
const monorepoRoot = resolveMonorepoRoot(projectRoot);
|
|
1846
|
-
const definitionRoot =
|
|
1900
|
+
const definitionRoot = resolve11(projectRoot, RIG_DEFINITION_DIRNAME);
|
|
1847
1901
|
const runtimeWorkspaceRoot = resolveActiveRuntimeWorkspaceRoot(monorepoRoot);
|
|
1848
1902
|
const runtimeLayout = resolveRuntimeWorkspaceLayout(runtimeWorkspaceRoot);
|
|
1849
|
-
const policyDir =
|
|
1903
|
+
const policyDir = resolve11(definitionRoot, "policy");
|
|
1850
1904
|
return {
|
|
1851
1905
|
projectRoot,
|
|
1852
1906
|
monorepoRoot,
|
|
@@ -1854,34 +1908,34 @@ function resolveRigLayout(projectRoot) {
|
|
|
1854
1908
|
runtimeWorkspaceRoot,
|
|
1855
1909
|
stateRoot: runtimeLayout.rigRoot,
|
|
1856
1910
|
artifactsRoot: runtimeLayout.artifactsRoot,
|
|
1857
|
-
configPath:
|
|
1858
|
-
taskConfigPath:
|
|
1911
|
+
configPath: resolve11(definitionRoot, "config.sh"),
|
|
1912
|
+
taskConfigPath: resolve11(runtimeWorkspaceRoot, ".rig", "task-config.json"),
|
|
1859
1913
|
policyDir,
|
|
1860
|
-
policyFile:
|
|
1861
|
-
pluginsDir:
|
|
1862
|
-
hooksDir:
|
|
1863
|
-
toolsDir:
|
|
1864
|
-
templatesDir:
|
|
1865
|
-
validationDir:
|
|
1914
|
+
policyFile: resolve11(policyDir, "policy.json"),
|
|
1915
|
+
pluginsDir: resolve11(definitionRoot, "plugins"),
|
|
1916
|
+
hooksDir: resolve11(definitionRoot, "hooks"),
|
|
1917
|
+
toolsDir: resolve11(definitionRoot, "tools"),
|
|
1918
|
+
templatesDir: resolve11(definitionRoot, "templates"),
|
|
1919
|
+
validationDir: resolve11(definitionRoot, "validation"),
|
|
1866
1920
|
stateDir: runtimeLayout.stateDir,
|
|
1867
1921
|
logsDir: runtimeLayout.logsDir,
|
|
1868
|
-
notificationsDir:
|
|
1922
|
+
notificationsDir: resolve11(definitionRoot, "notifications"),
|
|
1869
1923
|
runtimeDir: runtimeLayout.runtimeDir,
|
|
1870
1924
|
distDir: runtimeLayout.distDir,
|
|
1871
1925
|
binDir: runtimeLayout.binDir,
|
|
1872
1926
|
pluginBinDir: runtimeLayout.pluginBinDir,
|
|
1873
|
-
keybindingsPath:
|
|
1927
|
+
keybindingsPath: resolve11(definitionRoot, "keybindings.json"),
|
|
1874
1928
|
controlPlaneEventsFile: runtimeLayout.controlPlaneEventsFile
|
|
1875
1929
|
};
|
|
1876
1930
|
}
|
|
1877
1931
|
|
|
1878
1932
|
// packages/runtime/src/control-plane/native/runtime-native.ts
|
|
1879
1933
|
import { dlopen, ptr, suffix, toBuffer } from "bun:ffi";
|
|
1880
|
-
import { copyFileSync as copyFileSync2, existsSync as
|
|
1934
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync10, mkdirSync as mkdirSync5, renameSync as renameSync2, rmSync as rmSync3, statSync as statSync2 } from "fs";
|
|
1881
1935
|
import { tmpdir as tmpdir4 } from "os";
|
|
1882
|
-
import { dirname as dirname7, resolve as
|
|
1883
|
-
var sharedNativeRuntimeOutputDir =
|
|
1884
|
-
var sharedNativeRuntimeOutputPath =
|
|
1936
|
+
import { dirname as dirname7, resolve as resolve12 } from "path";
|
|
1937
|
+
var sharedNativeRuntimeOutputDir = resolve12(tmpdir4(), "rig-native");
|
|
1938
|
+
var sharedNativeRuntimeOutputPath = resolve12(sharedNativeRuntimeOutputDir, `runtime-native-${process.platform}-${process.arch}.${suffix}`);
|
|
1885
1939
|
var colocatedNativeRuntimeFileName = `runtime-native.${suffix}`;
|
|
1886
1940
|
var nativeRuntimeLibrary = await loadNativeRuntimeLibrary();
|
|
1887
1941
|
function requireNativeRuntimeLibrary(feature) {
|
|
@@ -1894,14 +1948,14 @@ async function ensureNativeRuntimeLibraryPath(outputPath = sharedNativeRuntimeOu
|
|
|
1894
1948
|
if (await buildNativeRuntimeLibrary(outputPath, options)) {
|
|
1895
1949
|
return outputPath;
|
|
1896
1950
|
}
|
|
1897
|
-
return !options.force &&
|
|
1951
|
+
return !options.force && existsSync10(outputPath) ? outputPath : null;
|
|
1898
1952
|
}
|
|
1899
1953
|
async function loadNativeRuntimeLibrary() {
|
|
1900
1954
|
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
1901
1955
|
return null;
|
|
1902
1956
|
}
|
|
1903
1957
|
for (const candidate of nativeRuntimeLibraryCandidates()) {
|
|
1904
|
-
if (!candidate || !
|
|
1958
|
+
if (!candidate || !existsSync10(candidate)) {
|
|
1905
1959
|
continue;
|
|
1906
1960
|
}
|
|
1907
1961
|
const loaded = tryDlopenNativeRuntimeLibrary(candidate);
|
|
@@ -1917,10 +1971,10 @@ async function loadNativeRuntimeLibrary() {
|
|
|
1917
1971
|
}
|
|
1918
1972
|
function nativePackageLibraryCandidates(fromDir, names) {
|
|
1919
1973
|
const candidates = [];
|
|
1920
|
-
let cursor =
|
|
1974
|
+
let cursor = resolve12(fromDir);
|
|
1921
1975
|
for (let index = 0;index < 8; index += 1) {
|
|
1922
1976
|
for (const name of names) {
|
|
1923
|
-
candidates.push(
|
|
1977
|
+
candidates.push(resolve12(cursor, "native", `${process.platform}-${process.arch}`, name), resolve12(cursor, "native", `${process.platform}-${process.arch}`, "lib", name), resolve12(cursor, "native", name), resolve12(cursor, "native", "lib", name));
|
|
1924
1978
|
}
|
|
1925
1979
|
const parent = dirname7(cursor);
|
|
1926
1980
|
if (parent === cursor)
|
|
@@ -1936,22 +1990,22 @@ function nativeRuntimeLibraryCandidates() {
|
|
|
1936
1990
|
return [...new Set([
|
|
1937
1991
|
explicit,
|
|
1938
1992
|
...nativePackageLibraryCandidates(import.meta.dir, [colocatedNativeRuntimeFileName, platformSpecific]),
|
|
1939
|
-
execDir ?
|
|
1940
|
-
execDir ?
|
|
1941
|
-
execDir ?
|
|
1942
|
-
execDir ?
|
|
1943
|
-
execDir ?
|
|
1944
|
-
execDir ?
|
|
1993
|
+
execDir ? resolve12(execDir, colocatedNativeRuntimeFileName) : "",
|
|
1994
|
+
execDir ? resolve12(execDir, platformSpecific) : "",
|
|
1995
|
+
execDir ? resolve12(execDir, "..", colocatedNativeRuntimeFileName) : "",
|
|
1996
|
+
execDir ? resolve12(execDir, "..", platformSpecific) : "",
|
|
1997
|
+
execDir ? resolve12(execDir, "lib", colocatedNativeRuntimeFileName) : "",
|
|
1998
|
+
execDir ? resolve12(execDir, "..", "lib", colocatedNativeRuntimeFileName) : "",
|
|
1945
1999
|
sharedNativeRuntimeOutputPath
|
|
1946
2000
|
].filter(Boolean))];
|
|
1947
2001
|
}
|
|
1948
2002
|
function resolveNativeRuntimeSourcePath() {
|
|
1949
2003
|
const explicit = process.env.RIG_NATIVE_RUNTIME_SOURCE?.trim();
|
|
1950
|
-
if (explicit &&
|
|
2004
|
+
if (explicit && existsSync10(explicit)) {
|
|
1951
2005
|
return explicit;
|
|
1952
2006
|
}
|
|
1953
|
-
const bundled =
|
|
1954
|
-
return
|
|
2007
|
+
const bundled = resolve12(import.meta.dir, "../../../native/snapshot.zig");
|
|
2008
|
+
return existsSync10(bundled) ? bundled : null;
|
|
1955
2009
|
}
|
|
1956
2010
|
async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
1957
2011
|
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
@@ -1964,8 +2018,8 @@ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
|
1964
2018
|
}
|
|
1965
2019
|
const tempOutputPath = `${outputPath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
1966
2020
|
try {
|
|
1967
|
-
|
|
1968
|
-
const needsBuild = options.force === true || !
|
|
2021
|
+
mkdirSync5(dirname7(outputPath), { recursive: true });
|
|
2022
|
+
const needsBuild = options.force === true || !existsSync10(outputPath) || statSync2(sourcePath).mtimeMs > statSync2(outputPath).mtimeMs;
|
|
1969
2023
|
if (!needsBuild) {
|
|
1970
2024
|
return true;
|
|
1971
2025
|
}
|
|
@@ -1983,14 +2037,14 @@ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
|
1983
2037
|
stderr: "pipe"
|
|
1984
2038
|
});
|
|
1985
2039
|
const exitCode = await build.exited;
|
|
1986
|
-
if (exitCode !== 0 || !
|
|
1987
|
-
|
|
2040
|
+
if (exitCode !== 0 || !existsSync10(tempOutputPath)) {
|
|
2041
|
+
rmSync3(tempOutputPath, { force: true });
|
|
1988
2042
|
return false;
|
|
1989
2043
|
}
|
|
1990
2044
|
renameSync2(tempOutputPath, outputPath);
|
|
1991
2045
|
return true;
|
|
1992
2046
|
} catch {
|
|
1993
|
-
|
|
2047
|
+
rmSync3(tempOutputPath, { force: true });
|
|
1994
2048
|
return false;
|
|
1995
2049
|
}
|
|
1996
2050
|
}
|
|
@@ -2114,11 +2168,11 @@ async function runCaptureAsync(command, cwd, env, timeoutMs) {
|
|
|
2114
2168
|
return { exitCode, stdout, stderr };
|
|
2115
2169
|
}
|
|
2116
2170
|
function readJsonFile(path, fallback) {
|
|
2117
|
-
if (!
|
|
2171
|
+
if (!existsSync11(path)) {
|
|
2118
2172
|
return fallback;
|
|
2119
2173
|
}
|
|
2120
2174
|
try {
|
|
2121
|
-
return JSON.parse(
|
|
2175
|
+
return JSON.parse(readFileSync8(path, "utf-8"));
|
|
2122
2176
|
} catch {
|
|
2123
2177
|
return fallback;
|
|
2124
2178
|
}
|
|
@@ -2132,31 +2186,31 @@ function unique(values) {
|
|
|
2132
2186
|
function resolveHarnessPaths(projectRoot) {
|
|
2133
2187
|
const hasRuntimeWorkspace = Boolean(process.env.RIG_TASK_WORKSPACE?.trim());
|
|
2134
2188
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
2135
|
-
const harnessRoot =
|
|
2136
|
-
const stateRoot =
|
|
2189
|
+
const harnessRoot = resolve13(projectRoot, "rig");
|
|
2190
|
+
const stateRoot = resolve13(projectRoot, ".rig");
|
|
2137
2191
|
const layout = hasRuntimeWorkspace ? resolveRigLayout(projectRoot) : null;
|
|
2138
|
-
const stateDir = layout?.stateDir ??
|
|
2139
|
-
const logsDir = layout?.logsDir ??
|
|
2140
|
-
const artifactsDir = layout?.artifactsRoot ??
|
|
2141
|
-
const taskConfigPath = layout?.taskConfigPath ??
|
|
2142
|
-
const binDir = layout?.binDir ??
|
|
2192
|
+
const stateDir = layout?.stateDir ?? resolve13(stateRoot, "state");
|
|
2193
|
+
const logsDir = layout?.logsDir ?? resolve13(stateRoot, "logs");
|
|
2194
|
+
const artifactsDir = layout?.artifactsRoot ?? resolve13(monorepoRoot, "artifacts");
|
|
2195
|
+
const taskConfigPath = layout?.taskConfigPath ?? resolve13(monorepoRoot, ".rig", "task-config.json");
|
|
2196
|
+
const binDir = layout?.binDir ?? resolve13(stateRoot, "bin");
|
|
2143
2197
|
return {
|
|
2144
2198
|
harnessRoot,
|
|
2145
2199
|
stateDir: process.env.RIG_STATE_DIR || stateDir,
|
|
2146
2200
|
artifactsDir,
|
|
2147
2201
|
logsDir: process.env.RIG_LOGS_DIR || logsDir,
|
|
2148
2202
|
binDir,
|
|
2149
|
-
hooksDir:
|
|
2150
|
-
validationDir:
|
|
2203
|
+
hooksDir: resolve13(harnessRoot, "hooks"),
|
|
2204
|
+
validationDir: resolve13(harnessRoot, "validation"),
|
|
2151
2205
|
taskConfigPath,
|
|
2152
|
-
sessionPath: process.env.RIG_SESSION_FILE ||
|
|
2206
|
+
sessionPath: process.env.RIG_SESSION_FILE || resolve13(stateRoot, "session", "session.json"),
|
|
2153
2207
|
monorepoRoot,
|
|
2154
|
-
tsApiTestsDir: process.env.TS_API_TESTS_DIR ||
|
|
2155
|
-
taskRepoCommitsPath:
|
|
2156
|
-
baseRepoPinsPath:
|
|
2157
|
-
failedApproachesPath:
|
|
2158
|
-
agentProfilePath:
|
|
2159
|
-
reviewProfilePath:
|
|
2208
|
+
tsApiTestsDir: process.env.TS_API_TESTS_DIR || resolve13(monorepoRoot, "TSAPITests"),
|
|
2209
|
+
taskRepoCommitsPath: resolve13(stateDir, "task-repo-commits.json"),
|
|
2210
|
+
baseRepoPinsPath: resolve13(stateDir, "base-repo-pins.json"),
|
|
2211
|
+
failedApproachesPath: resolve13(stateDir, "failed_approaches.md"),
|
|
2212
|
+
agentProfilePath: resolve13(stateDir, "agent-profile.json"),
|
|
2213
|
+
reviewProfilePath: resolve13(stateDir, "review-profile.json")
|
|
2160
2214
|
};
|
|
2161
2215
|
}
|
|
2162
2216
|
function normalizeRelativeScopePath(inputPath) {
|
|
@@ -2249,34 +2303,34 @@ function createNativeScopeMatcher() {
|
|
|
2249
2303
|
}
|
|
2250
2304
|
|
|
2251
2305
|
// packages/runtime/src/control-plane/state-sync/repo.ts
|
|
2252
|
-
import { existsSync as
|
|
2253
|
-
import { resolve as
|
|
2306
|
+
import { existsSync as existsSync13 } from "fs";
|
|
2307
|
+
import { resolve as resolve15 } from "path";
|
|
2254
2308
|
|
|
2255
2309
|
// packages/runtime/src/control-plane/repos/layout.ts
|
|
2256
|
-
import { existsSync as
|
|
2257
|
-
import { basename as basename5, dirname as dirname8, join as join3, resolve as
|
|
2310
|
+
import { existsSync as existsSync12 } from "fs";
|
|
2311
|
+
import { basename as basename5, dirname as dirname8, join as join3, resolve as resolve14 } from "path";
|
|
2258
2312
|
function resolveRepoStateDir(projectRoot) {
|
|
2259
|
-
const normalizedProjectRoot =
|
|
2313
|
+
const normalizedProjectRoot = resolve14(projectRoot);
|
|
2260
2314
|
const projectParent = dirname8(normalizedProjectRoot);
|
|
2261
2315
|
if (basename5(projectParent) === ".worktrees") {
|
|
2262
2316
|
const ownerRoot = dirname8(projectParent);
|
|
2263
|
-
const ownerHasRepoMarkers =
|
|
2317
|
+
const ownerHasRepoMarkers = existsSync12(resolve14(ownerRoot, ".git")) || existsSync12(resolve14(ownerRoot, ".rig", "state"));
|
|
2264
2318
|
if (ownerHasRepoMarkers) {
|
|
2265
|
-
return
|
|
2319
|
+
return resolve14(ownerRoot, ".rig", "state");
|
|
2266
2320
|
}
|
|
2267
2321
|
}
|
|
2268
|
-
return
|
|
2322
|
+
return resolve14(projectRoot, ".rig", "state");
|
|
2269
2323
|
}
|
|
2270
2324
|
function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
2271
|
-
const normalizedProjectRoot =
|
|
2325
|
+
const normalizedProjectRoot = resolve14(projectRoot);
|
|
2272
2326
|
const entry = getManagedRepoEntry(repoId);
|
|
2273
2327
|
const stateDir = resolveRepoStateDir(normalizedProjectRoot);
|
|
2274
2328
|
const metadataRelativePath = join3("repos", entry.id);
|
|
2275
|
-
const metadataRoot =
|
|
2329
|
+
const metadataRoot = resolve14(stateDir, metadataRelativePath);
|
|
2276
2330
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
2277
|
-
const runsInsideTaskWorktree = runtimeWorkspace &&
|
|
2331
|
+
const runsInsideTaskWorktree = runtimeWorkspace && resolve14(runtimeWorkspace) === normalizedProjectRoot || basename5(dirname8(normalizedProjectRoot)) === ".worktrees";
|
|
2278
2332
|
const isPrimaryManagedRepo = listManagedRepoEntries()[0]?.id === repoId;
|
|
2279
|
-
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ?
|
|
2333
|
+
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ? resolve14(process.env[entry.checkoutEnvVar].trim()) : resolve14(normalizedProjectRoot, entry.alias);
|
|
2280
2334
|
return {
|
|
2281
2335
|
projectRoot: normalizedProjectRoot,
|
|
2282
2336
|
repoId: entry.id,
|
|
@@ -2284,12 +2338,12 @@ function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
|
2284
2338
|
defaultBranch: entry.defaultBranch,
|
|
2285
2339
|
remoteUrl: entry.remoteEnvVar && process.env[entry.remoteEnvVar]?.trim() ? process.env[entry.remoteEnvVar].trim() : entry.defaultRemoteUrl,
|
|
2286
2340
|
checkoutRoot,
|
|
2287
|
-
worktreesRoot:
|
|
2341
|
+
worktreesRoot: resolve14(checkoutRoot, ".worktrees"),
|
|
2288
2342
|
stateDir,
|
|
2289
2343
|
metadataRoot,
|
|
2290
2344
|
metadataRelativePath,
|
|
2291
|
-
mirrorRoot:
|
|
2292
|
-
mirrorStatePath:
|
|
2345
|
+
mirrorRoot: resolve14(metadataRoot, "mirror.git"),
|
|
2346
|
+
mirrorStatePath: resolve14(metadataRoot, "mirror-state.json"),
|
|
2293
2347
|
mirrorStateRelativePath: join3(metadataRelativePath, "mirror-state.json")
|
|
2294
2348
|
};
|
|
2295
2349
|
}
|
|
@@ -2311,7 +2365,7 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
2311
2365
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
2312
2366
|
try {
|
|
2313
2367
|
const layout = resolveMonorepoRepoLayout(projectRoot);
|
|
2314
|
-
if (
|
|
2368
|
+
if (existsSync13(resolve15(layout.mirrorRoot, "HEAD"))) {
|
|
2315
2369
|
return layout.mirrorRoot;
|
|
2316
2370
|
}
|
|
2317
2371
|
} catch {}
|
|
@@ -2322,8 +2376,8 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
2322
2376
|
var DEFAULT_READ_DEPS = {
|
|
2323
2377
|
fetchRef: nativeFetchRef,
|
|
2324
2378
|
readBlobAtRef: nativeReadBlobAtRef,
|
|
2325
|
-
exists:
|
|
2326
|
-
readFile: (path) =>
|
|
2379
|
+
exists: existsSync14,
|
|
2380
|
+
readFile: (path) => readFileSync9(path, "utf8")
|
|
2327
2381
|
};
|
|
2328
2382
|
function parseIssueStatus(rawStatus) {
|
|
2329
2383
|
const normalized = normalizeTaskLifecycleStatus(rawStatus);
|
|
@@ -2404,12 +2458,12 @@ function shouldPreferLocalTrackerState(options) {
|
|
|
2404
2458
|
if (runtimeContextPath) {
|
|
2405
2459
|
return true;
|
|
2406
2460
|
}
|
|
2407
|
-
return
|
|
2461
|
+
return existsSync14(resolve16(runtimeWorkspace, ".rig", "runtime-context.json"));
|
|
2408
2462
|
}
|
|
2409
2463
|
function readLocalTrackerState(projectRoot, deps) {
|
|
2410
2464
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
2411
|
-
const issuesPath =
|
|
2412
|
-
const taskStatePath =
|
|
2465
|
+
const issuesPath = resolve16(monorepoRoot, ".beads", "issues.jsonl");
|
|
2466
|
+
const taskStatePath = resolve16(monorepoRoot, ".beads", "task-state.json");
|
|
2413
2467
|
return projectSyncedTrackerSnapshot({
|
|
2414
2468
|
source: "local",
|
|
2415
2469
|
issuesBaseOid: null,
|
|
@@ -2471,7 +2525,7 @@ function readValidationDescriptions(projectRoot) {
|
|
|
2471
2525
|
return readValidationDescriptionMap(raw);
|
|
2472
2526
|
}
|
|
2473
2527
|
function readSourceValidationDescriptions(projectRoot) {
|
|
2474
|
-
const rootRaw = readJsonFile(
|
|
2528
|
+
const rootRaw = readJsonFile(resolve17(projectRoot, "rig", "task-config.json"), {});
|
|
2475
2529
|
const sourcePath = findSourceTaskConfigPath(projectRoot);
|
|
2476
2530
|
const sourceRaw = sourcePath ? readJsonFile(sourcePath, {}) : {};
|
|
2477
2531
|
const rootDescriptions = readValidationDescriptionMap(rootRaw);
|
|
@@ -2547,15 +2601,15 @@ function readValidationDescriptionsFromMeta(meta) {
|
|
|
2547
2601
|
return meta.validation_descriptions;
|
|
2548
2602
|
}
|
|
2549
2603
|
function readLocalSourceTaskStateEnvelope(projectRoot) {
|
|
2550
|
-
const taskStatePath =
|
|
2604
|
+
const taskStatePath = resolve17(resolveMonorepoRoot2(projectRoot), ".beads", "task-state.json");
|
|
2551
2605
|
return readTaskStateMetadataEnvelope(readJsonFile(taskStatePath, {}));
|
|
2552
2606
|
}
|
|
2553
2607
|
function readLocalSourceTaskLifecycleStatus(projectRoot, taskId) {
|
|
2554
|
-
const issuesPath =
|
|
2555
|
-
if (!
|
|
2608
|
+
const issuesPath = resolve17(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
2609
|
+
if (!existsSync15(issuesPath)) {
|
|
2556
2610
|
return null;
|
|
2557
2611
|
}
|
|
2558
|
-
for (const line of
|
|
2612
|
+
for (const line of readFileSync10(issuesPath, "utf8").split(/\r?\n/)) {
|
|
2559
2613
|
const trimmed = line.trim();
|
|
2560
2614
|
if (!trimmed) {
|
|
2561
2615
|
continue;
|
|
@@ -2596,25 +2650,25 @@ function lookupTask(projectRoot, input) {
|
|
|
2596
2650
|
function artifactDirForId(projectRoot, id) {
|
|
2597
2651
|
const workspaceDir = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
2598
2652
|
if (workspaceDir) {
|
|
2599
|
-
const worktreeArtifacts =
|
|
2600
|
-
if (
|
|
2653
|
+
const worktreeArtifacts = resolve17(workspaceDir, "artifacts", id);
|
|
2654
|
+
if (existsSync15(worktreeArtifacts) || existsSync15(resolve17(workspaceDir, "artifacts"))) {
|
|
2601
2655
|
return worktreeArtifacts;
|
|
2602
2656
|
}
|
|
2603
2657
|
}
|
|
2604
2658
|
try {
|
|
2605
2659
|
const paths = resolveHarnessPaths(projectRoot);
|
|
2606
|
-
return
|
|
2660
|
+
return resolve17(paths.artifactsDir, id);
|
|
2607
2661
|
} catch {
|
|
2608
|
-
return
|
|
2662
|
+
return resolve17(resolveMonorepoRoot2(projectRoot), "artifacts", id);
|
|
2609
2663
|
}
|
|
2610
2664
|
}
|
|
2611
2665
|
function resolveTaskConfigPath(projectRoot) {
|
|
2612
2666
|
const paths = resolveHarnessPaths(projectRoot);
|
|
2613
|
-
if (
|
|
2667
|
+
if (existsSync15(paths.taskConfigPath)) {
|
|
2614
2668
|
return paths.taskConfigPath;
|
|
2615
2669
|
}
|
|
2616
2670
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
2617
|
-
if (
|
|
2671
|
+
if (existsSync15(candidate)) {
|
|
2618
2672
|
return candidate;
|
|
2619
2673
|
}
|
|
2620
2674
|
}
|
|
@@ -2622,7 +2676,7 @@ function resolveTaskConfigPath(projectRoot) {
|
|
|
2622
2676
|
}
|
|
2623
2677
|
function findSourceTaskConfigPath(projectRoot) {
|
|
2624
2678
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
2625
|
-
if (
|
|
2679
|
+
if (existsSync15(candidate)) {
|
|
2626
2680
|
return candidate;
|
|
2627
2681
|
}
|
|
2628
2682
|
}
|
|
@@ -2635,7 +2689,7 @@ function readAndSyncSourceTaskConfig(projectRoot) {
|
|
|
2635
2689
|
const synced = synchronizeTaskConfigWithTracker(projectRoot, raw);
|
|
2636
2690
|
if (sourcePath && synced.updated) {
|
|
2637
2691
|
try {
|
|
2638
|
-
|
|
2692
|
+
writeFileSync6(sourcePath, `${JSON.stringify(synced.config, null, 2)}
|
|
2639
2693
|
`, "utf-8");
|
|
2640
2694
|
} catch {}
|
|
2641
2695
|
}
|
|
@@ -2687,12 +2741,12 @@ function shouldRefreshAutoSyncedTaskConfigEntry(entry) {
|
|
|
2687
2741
|
return !candidate.role;
|
|
2688
2742
|
}
|
|
2689
2743
|
function readSourceIssueRecords(projectRoot) {
|
|
2690
|
-
const issuesPath =
|
|
2691
|
-
if (!
|
|
2744
|
+
const issuesPath = resolve17(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
2745
|
+
if (!existsSync15(issuesPath)) {
|
|
2692
2746
|
return [];
|
|
2693
2747
|
}
|
|
2694
2748
|
const records = [];
|
|
2695
|
-
for (const line of
|
|
2749
|
+
for (const line of readFileSync10(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
2696
2750
|
const trimmed = line.trim();
|
|
2697
2751
|
if (!trimmed) {
|
|
2698
2752
|
continue;
|
|
@@ -2748,19 +2802,19 @@ function readConfiguredFileTaskConfig(projectRoot) {
|
|
|
2748
2802
|
if (!sourcePath) {
|
|
2749
2803
|
return {};
|
|
2750
2804
|
}
|
|
2751
|
-
const directory =
|
|
2752
|
-
if (!
|
|
2805
|
+
const directory = resolve17(projectRoot, sourcePath);
|
|
2806
|
+
if (!existsSync15(directory)) {
|
|
2753
2807
|
return {};
|
|
2754
2808
|
}
|
|
2755
2809
|
const config = {};
|
|
2756
|
-
for (const name of
|
|
2810
|
+
for (const name of readdirSync3(directory)) {
|
|
2757
2811
|
if (!FILE_TASK_PATTERN2.test(name))
|
|
2758
2812
|
continue;
|
|
2759
|
-
const file =
|
|
2813
|
+
const file = resolve17(directory, name);
|
|
2760
2814
|
try {
|
|
2761
2815
|
if (!statSync3(file).isFile())
|
|
2762
2816
|
continue;
|
|
2763
|
-
const raw = JSON.parse(
|
|
2817
|
+
const raw = JSON.parse(readFileSync10(file, "utf8"));
|
|
2764
2818
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
2765
2819
|
continue;
|
|
2766
2820
|
const record = raw;
|
|
@@ -2802,10 +2856,10 @@ function firstStringList2(...candidates) {
|
|
|
2802
2856
|
return [];
|
|
2803
2857
|
}
|
|
2804
2858
|
function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
2805
|
-
const jsonPath =
|
|
2806
|
-
if (
|
|
2859
|
+
const jsonPath = resolve17(projectRoot, "rig.config.json");
|
|
2860
|
+
if (existsSync15(jsonPath)) {
|
|
2807
2861
|
try {
|
|
2808
|
-
const parsed = JSON.parse(
|
|
2862
|
+
const parsed = JSON.parse(readFileSync10(jsonPath, "utf8"));
|
|
2809
2863
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
2810
2864
|
const taskSource = parsed.taskSource;
|
|
2811
2865
|
if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
|
|
@@ -2817,12 +2871,12 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
2817
2871
|
return null;
|
|
2818
2872
|
}
|
|
2819
2873
|
}
|
|
2820
|
-
const tsPath =
|
|
2821
|
-
if (!
|
|
2874
|
+
const tsPath = resolve17(projectRoot, "rig.config.ts");
|
|
2875
|
+
if (!existsSync15(tsPath)) {
|
|
2822
2876
|
return null;
|
|
2823
2877
|
}
|
|
2824
2878
|
try {
|
|
2825
|
-
const source =
|
|
2879
|
+
const source = readFileSync10(tsPath, "utf8");
|
|
2826
2880
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
2827
2881
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
2828
2882
|
if (kind !== "files") {
|
|
@@ -2836,23 +2890,23 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
2836
2890
|
function sourceTaskConfigCandidates(projectRoot) {
|
|
2837
2891
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
2838
2892
|
return [
|
|
2839
|
-
runtimeContext?.monorepoMainRoot ?
|
|
2840
|
-
process.env.MONOREPO_MAIN_ROOT?.trim() ?
|
|
2841
|
-
|
|
2893
|
+
runtimeContext?.monorepoMainRoot ? resolve17(runtimeContext.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
2894
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve17(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
2895
|
+
resolve17(resolveMonorepoRoot2(projectRoot), ".rig", "task-config.json")
|
|
2842
2896
|
].filter(Boolean);
|
|
2843
2897
|
}
|
|
2844
2898
|
|
|
2845
2899
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
2846
|
-
import { existsSync as
|
|
2847
|
-
import { resolve as
|
|
2900
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
2901
|
+
import { resolve as resolve22 } from "path";
|
|
2848
2902
|
|
|
2849
2903
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
2850
|
-
import { existsSync as
|
|
2851
|
-
import { dirname as dirname10, resolve as
|
|
2904
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync7, rmSync as rmSync5, statSync as statSync4 } from "fs";
|
|
2905
|
+
import { dirname as dirname10, resolve as resolve21 } from "path";
|
|
2852
2906
|
|
|
2853
2907
|
// packages/runtime/src/binary-run.ts
|
|
2854
|
-
import { chmodSync as chmodSync2, cpSync, existsSync as
|
|
2855
|
-
import { basename as basename7, dirname as dirname9, resolve as
|
|
2908
|
+
import { chmodSync as chmodSync2, cpSync, existsSync as existsSync16, mkdirSync as mkdirSync6, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
2909
|
+
import { basename as basename7, dirname as dirname9, resolve as resolve18 } from "path";
|
|
2856
2910
|
import { fileURLToPath } from "url";
|
|
2857
2911
|
import { drainMicrotasks, gcAndSweep } from "bun:jsc";
|
|
2858
2912
|
var runtimeBinaryBuildQueue = Promise.resolve();
|
|
@@ -2878,9 +2932,9 @@ async function buildRuntimeBinary(options) {
|
|
|
2878
2932
|
});
|
|
2879
2933
|
}
|
|
2880
2934
|
async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
2881
|
-
const tempBuildDir =
|
|
2882
|
-
const tempOutputPath =
|
|
2883
|
-
|
|
2935
|
+
const tempBuildDir = resolve18(dirname9(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
2936
|
+
const tempOutputPath = resolve18(tempBuildDir, basename7(options.outputPath));
|
|
2937
|
+
mkdirSync6(tempBuildDir, { recursive: true });
|
|
2884
2938
|
await withTemporaryEnv({
|
|
2885
2939
|
...options.env,
|
|
2886
2940
|
...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
|
|
@@ -2905,7 +2959,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
2905
2959
|
`);
|
|
2906
2960
|
throw new Error(`Failed to build ${options.entrypoint}: ${details || "Bun.build() returned errors"}`);
|
|
2907
2961
|
}
|
|
2908
|
-
if (!
|
|
2962
|
+
if (!existsSync16(tempOutputPath)) {
|
|
2909
2963
|
const emitted = buildResult.outputs.map((output) => output.path).join(", ") || "(none)";
|
|
2910
2964
|
throw new Error(`Failed to build ${options.entrypoint}: Bun.build() did not emit ${tempOutputPath}. Emitted: ${emitted}`);
|
|
2911
2965
|
}
|
|
@@ -2920,7 +2974,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
2920
2974
|
});
|
|
2921
2975
|
}
|
|
2922
2976
|
})).finally(() => {
|
|
2923
|
-
|
|
2977
|
+
rmSync4(tempBuildDir, { recursive: true, force: true });
|
|
2924
2978
|
});
|
|
2925
2979
|
}
|
|
2926
2980
|
function runBestEffortBuildGc() {
|
|
@@ -2937,8 +2991,8 @@ function runtimeBinaryCacheManifestPath(outputPath) {
|
|
|
2937
2991
|
function resolveRuntimeBinaryBuildOptions(options) {
|
|
2938
2992
|
return {
|
|
2939
2993
|
...options,
|
|
2940
|
-
entrypoint:
|
|
2941
|
-
outputPath:
|
|
2994
|
+
entrypoint: resolve18(options.cwd, options.sourcePath),
|
|
2995
|
+
outputPath: resolve18(options.outputPath)
|
|
2942
2996
|
};
|
|
2943
2997
|
}
|
|
2944
2998
|
function shouldUseRuntimeBinaryBuildWorker() {
|
|
@@ -2952,7 +3006,7 @@ function shouldUseRuntimeBinaryBuildWorker() {
|
|
|
2952
3006
|
}
|
|
2953
3007
|
async function buildRuntimeBinaryViaWorker(options) {
|
|
2954
3008
|
const workerSourcePath = resolveRuntimeBinaryBuildWorkerSourcePath(options);
|
|
2955
|
-
if (!workerSourcePath || !
|
|
3009
|
+
if (!workerSourcePath || !existsSync16(workerSourcePath)) {
|
|
2956
3010
|
await buildRuntimeBinaryInProcess(options, {
|
|
2957
3011
|
manifestPath: runtimeBinaryCacheManifestPath(options.outputPath),
|
|
2958
3012
|
buildKey: createRuntimeBinaryBuildKey({
|
|
@@ -2983,13 +3037,13 @@ async function buildRuntimeBinaryViaWorker(options) {
|
|
|
2983
3037
|
new Response(build.stdout).text(),
|
|
2984
3038
|
new Response(build.stderr).text()
|
|
2985
3039
|
]);
|
|
2986
|
-
|
|
3040
|
+
rmSync4(payloadPath, { force: true });
|
|
2987
3041
|
if (exitCode !== 0) {
|
|
2988
3042
|
throw new Error(`Failed to build ${options.entrypoint}: ${(stderr || stdout || `worker exited ${exitCode}`).trim()}`);
|
|
2989
3043
|
}
|
|
2990
3044
|
}
|
|
2991
3045
|
function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
|
|
2992
|
-
return
|
|
3046
|
+
return resolve18(dirname9(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
2993
3047
|
}
|
|
2994
3048
|
function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
2995
3049
|
const envRoots = [
|
|
@@ -2998,13 +3052,13 @@ function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
|
2998
3052
|
process.env.PROJECT_RIG_ROOT?.trim()
|
|
2999
3053
|
].filter(Boolean);
|
|
3000
3054
|
for (const root of envRoots) {
|
|
3001
|
-
const candidate =
|
|
3002
|
-
if (
|
|
3055
|
+
const candidate = resolve18(root, "packages/runtime/src/binary-build-worker.ts");
|
|
3056
|
+
if (existsSync16(candidate)) {
|
|
3003
3057
|
return candidate;
|
|
3004
3058
|
}
|
|
3005
3059
|
}
|
|
3006
|
-
const localCandidate =
|
|
3007
|
-
return
|
|
3060
|
+
const localCandidate = resolve18(import.meta.dir, "binary-build-worker.ts");
|
|
3061
|
+
return existsSync16(localCandidate) ? localCandidate : null;
|
|
3008
3062
|
}
|
|
3009
3063
|
function resolveRuntimeBinaryBuildWorkerInvocation() {
|
|
3010
3064
|
const bunPath = Bun.which("bun");
|
|
@@ -3040,7 +3094,7 @@ function createRuntimeBinaryBuildKey(input) {
|
|
|
3040
3094
|
});
|
|
3041
3095
|
}
|
|
3042
3096
|
async function isRuntimeBinaryBuildFresh(input) {
|
|
3043
|
-
if (!
|
|
3097
|
+
if (!existsSync16(input.outputPath) || !existsSync16(input.manifestPath)) {
|
|
3044
3098
|
return false;
|
|
3045
3099
|
}
|
|
3046
3100
|
let manifest = null;
|
|
@@ -3053,7 +3107,7 @@ async function isRuntimeBinaryBuildFresh(input) {
|
|
|
3053
3107
|
return false;
|
|
3054
3108
|
}
|
|
3055
3109
|
for (const [filePath, expectedDigest] of Object.entries(manifest.inputs || {})) {
|
|
3056
|
-
if (!
|
|
3110
|
+
if (!existsSync16(filePath)) {
|
|
3057
3111
|
return false;
|
|
3058
3112
|
}
|
|
3059
3113
|
if (await sha256File(filePath) !== expectedDigest) {
|
|
@@ -3066,7 +3120,7 @@ async function writeRuntimeBinaryCacheManifest(input) {
|
|
|
3066
3120
|
const inputs = {};
|
|
3067
3121
|
for (const inputPath of Object.keys(input.metafile?.inputs || {}).sort()) {
|
|
3068
3122
|
const normalized = normalizeBuildInputPath(input.cwd, inputPath);
|
|
3069
|
-
if (!normalized || !
|
|
3123
|
+
if (!normalized || !existsSync16(normalized)) {
|
|
3070
3124
|
continue;
|
|
3071
3125
|
}
|
|
3072
3126
|
inputs[normalized] = await sha256File(normalized);
|
|
@@ -3089,7 +3143,7 @@ function normalizeBuildInputPath(cwd, inputPath) {
|
|
|
3089
3143
|
if (inputPath.startsWith("<")) {
|
|
3090
3144
|
return null;
|
|
3091
3145
|
}
|
|
3092
|
-
return
|
|
3146
|
+
return resolve18(cwd, inputPath);
|
|
3093
3147
|
}
|
|
3094
3148
|
async function sha256File(path) {
|
|
3095
3149
|
const hasher = new Bun.CryptoHasher("sha256");
|
|
@@ -3105,8 +3159,8 @@ function sortRecord(value) {
|
|
|
3105
3159
|
async function runSerializedRuntimeBinaryBuild(action) {
|
|
3106
3160
|
const previous = runtimeBinaryBuildQueue;
|
|
3107
3161
|
let release;
|
|
3108
|
-
runtimeBinaryBuildQueue = new Promise((
|
|
3109
|
-
release =
|
|
3162
|
+
runtimeBinaryBuildQueue = new Promise((resolve19) => {
|
|
3163
|
+
release = resolve19;
|
|
3110
3164
|
});
|
|
3111
3165
|
await previous;
|
|
3112
3166
|
try {
|
|
@@ -3151,11 +3205,11 @@ async function withTemporaryCwd(cwd, action) {
|
|
|
3151
3205
|
}
|
|
3152
3206
|
|
|
3153
3207
|
// packages/runtime/src/control-plane/runtime/provisioning-env.ts
|
|
3154
|
-
import { delimiter, resolve as
|
|
3208
|
+
import { delimiter, resolve as resolve20 } from "path";
|
|
3155
3209
|
|
|
3156
3210
|
// packages/runtime/src/control-plane/runtime/runtime-paths.ts
|
|
3157
|
-
import { existsSync as
|
|
3158
|
-
import { resolve as
|
|
3211
|
+
import { existsSync as existsSync17, readdirSync as readdirSync4, realpathSync } from "fs";
|
|
3212
|
+
import { resolve as resolve19 } from "path";
|
|
3159
3213
|
|
|
3160
3214
|
// packages/runtime/src/control-plane/runtime/sandbox/utils.ts
|
|
3161
3215
|
function uniq(values) {
|
|
@@ -3173,7 +3227,7 @@ function resolveBunBinaryPath() {
|
|
|
3173
3227
|
}
|
|
3174
3228
|
const home = process.env.HOME?.trim();
|
|
3175
3229
|
const fallbackCandidates = [
|
|
3176
|
-
home ?
|
|
3230
|
+
home ? resolve19(home, ".bun/bin/bun") : "",
|
|
3177
3231
|
"/opt/homebrew/bin/bun",
|
|
3178
3232
|
"/usr/local/bin/bun",
|
|
3179
3233
|
"/usr/bin/bun"
|
|
@@ -3201,8 +3255,8 @@ function resolveClaudeBinaryPath() {
|
|
|
3201
3255
|
}
|
|
3202
3256
|
const home = process.env.HOME?.trim();
|
|
3203
3257
|
const fallbackCandidates = [
|
|
3204
|
-
home ?
|
|
3205
|
-
home ?
|
|
3258
|
+
home ? resolve19(home, ".local/bin/claude") : "",
|
|
3259
|
+
home ? resolve19(home, ".local/share/claude/local/claude") : "",
|
|
3206
3260
|
"/opt/homebrew/bin/claude",
|
|
3207
3261
|
"/usr/local/bin/claude",
|
|
3208
3262
|
"/usr/bin/claude"
|
|
@@ -3216,51 +3270,51 @@ function resolveClaudeBinaryPath() {
|
|
|
3216
3270
|
throw new Error("claude not found in PATH");
|
|
3217
3271
|
}
|
|
3218
3272
|
function resolveBunInstallDir(bunBinaryPath = resolveBunBinaryPath()) {
|
|
3219
|
-
return
|
|
3273
|
+
return resolve19(bunBinaryPath, "../..");
|
|
3220
3274
|
}
|
|
3221
3275
|
function resolveClaudeInstallDir() {
|
|
3222
3276
|
const realPath = resolveClaudeBinaryPath();
|
|
3223
|
-
return
|
|
3277
|
+
return resolve19(realPath, "..");
|
|
3224
3278
|
}
|
|
3225
3279
|
function resolveNodeInstallDir() {
|
|
3226
3280
|
const preferredNode = resolvePreferredNodeBinary();
|
|
3227
3281
|
if (!preferredNode)
|
|
3228
3282
|
return null;
|
|
3229
3283
|
const explicitNode = process.env.RIG_NODE_BIN?.trim();
|
|
3230
|
-
if (explicitNode &&
|
|
3231
|
-
return preferredNode.endsWith("/bin/node") ?
|
|
3284
|
+
if (explicitNode && resolve19(explicitNode) === resolve19(preferredNode)) {
|
|
3285
|
+
return preferredNode.endsWith("/bin/node") ? resolve19(preferredNode, "../..") : resolve19(preferredNode, "..");
|
|
3232
3286
|
}
|
|
3233
3287
|
try {
|
|
3234
3288
|
const realPath = realpathSync(preferredNode);
|
|
3235
3289
|
if (realPath.endsWith("/bin/node")) {
|
|
3236
|
-
return
|
|
3290
|
+
return resolve19(realPath, "../..");
|
|
3237
3291
|
}
|
|
3238
|
-
return
|
|
3292
|
+
return resolve19(realPath, "..");
|
|
3239
3293
|
} catch {
|
|
3240
|
-
return
|
|
3294
|
+
return resolve19(preferredNode, "..");
|
|
3241
3295
|
}
|
|
3242
3296
|
}
|
|
3243
3297
|
function resolvePreferredNodeBinary() {
|
|
3244
3298
|
const candidates = [];
|
|
3245
3299
|
const envNode = process.env.RIG_NODE_BIN?.trim();
|
|
3246
3300
|
if (envNode) {
|
|
3247
|
-
const explicit =
|
|
3248
|
-
if (
|
|
3301
|
+
const explicit = resolve19(envNode);
|
|
3302
|
+
if (existsSync17(explicit)) {
|
|
3249
3303
|
return explicit;
|
|
3250
3304
|
}
|
|
3251
3305
|
}
|
|
3252
3306
|
const nvmBin = process.env.NVM_BIN?.trim();
|
|
3253
3307
|
if (nvmBin) {
|
|
3254
|
-
candidates.push(
|
|
3308
|
+
candidates.push(resolve19(nvmBin, "node"));
|
|
3255
3309
|
}
|
|
3256
3310
|
const home = process.env.HOME?.trim();
|
|
3257
3311
|
if (home) {
|
|
3258
|
-
const nvmVersionsDir =
|
|
3259
|
-
if (
|
|
3312
|
+
const nvmVersionsDir = resolve19(home, ".nvm/versions/node");
|
|
3313
|
+
if (existsSync17(nvmVersionsDir)) {
|
|
3260
3314
|
try {
|
|
3261
|
-
const versionDirs =
|
|
3315
|
+
const versionDirs = readdirSync4(nvmVersionsDir).map((entry) => entry.trim()).filter((entry) => /^v\d+\.\d+\.\d+$/.test(entry)).sort((a, b) => Bun.semver.order(b.replace(/^v/, ""), a.replace(/^v/, "")));
|
|
3262
3316
|
for (const versionDir of versionDirs) {
|
|
3263
|
-
candidates.push(
|
|
3317
|
+
candidates.push(resolve19(nvmVersionsDir, versionDir, "bin/node"));
|
|
3264
3318
|
}
|
|
3265
3319
|
} catch {}
|
|
3266
3320
|
}
|
|
@@ -3269,8 +3323,8 @@ function resolvePreferredNodeBinary() {
|
|
|
3269
3323
|
if (whichNode) {
|
|
3270
3324
|
candidates.push(whichNode);
|
|
3271
3325
|
}
|
|
3272
|
-
const deduped = uniq(candidates.map((candidate) =>
|
|
3273
|
-
const existing = deduped.filter((candidate) =>
|
|
3326
|
+
const deduped = uniq(candidates.map((candidate) => resolve19(candidate)));
|
|
3327
|
+
const existing = deduped.filter((candidate) => existsSync17(candidate));
|
|
3274
3328
|
if (existing.length === 0) {
|
|
3275
3329
|
return null;
|
|
3276
3330
|
}
|
|
@@ -3284,7 +3338,7 @@ function resolvePreferredNodeBinary() {
|
|
|
3284
3338
|
return existing[0] ?? null;
|
|
3285
3339
|
}
|
|
3286
3340
|
function inferNodeMajor(nodeBinaryPath) {
|
|
3287
|
-
const normalized =
|
|
3341
|
+
const normalized = resolve19(nodeBinaryPath).replace(/\\/g, "/");
|
|
3288
3342
|
const match = normalized.match(/(?:^|\/)(?:node-)?v?(\d+)\.\d+\.\d+(?:\/|$)/);
|
|
3289
3343
|
if (!match) {
|
|
3290
3344
|
return null;
|
|
@@ -3296,8 +3350,8 @@ function normalizeExecutablePath(candidate) {
|
|
|
3296
3350
|
if (!candidate) {
|
|
3297
3351
|
return "";
|
|
3298
3352
|
}
|
|
3299
|
-
const normalized =
|
|
3300
|
-
if (!
|
|
3353
|
+
const normalized = resolve19(candidate);
|
|
3354
|
+
if (!existsSync17(normalized)) {
|
|
3301
3355
|
return "";
|
|
3302
3356
|
}
|
|
3303
3357
|
try {
|
|
@@ -3307,7 +3361,7 @@ function normalizeExecutablePath(candidate) {
|
|
|
3307
3361
|
}
|
|
3308
3362
|
}
|
|
3309
3363
|
function looksLikeRuntimeGateway(candidate) {
|
|
3310
|
-
const normalized =
|
|
3364
|
+
const normalized = resolve19(candidate).replace(/\\/g, "/");
|
|
3311
3365
|
return normalized.includes("/.rig/bin/") || normalized.endsWith("/rig-shell") || normalized.endsWith("/rig-agent");
|
|
3312
3366
|
}
|
|
3313
3367
|
|
|
@@ -3328,7 +3382,7 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
3328
3382
|
try {
|
|
3329
3383
|
return resolveClaudeInstallDir();
|
|
3330
3384
|
} catch {
|
|
3331
|
-
return
|
|
3385
|
+
return resolve20(claudeBinary, "..");
|
|
3332
3386
|
}
|
|
3333
3387
|
})() : "";
|
|
3334
3388
|
const nodeDir = resolveNodeInstallDir();
|
|
@@ -3338,8 +3392,8 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
3338
3392
|
`${bunDir}/bin`,
|
|
3339
3393
|
claudeDir,
|
|
3340
3394
|
nodeDir ? `${nodeDir}/bin` : "",
|
|
3341
|
-
realHome ?
|
|
3342
|
-
realHome ?
|
|
3395
|
+
realHome ? resolve20(realHome, ".local/bin") : "",
|
|
3396
|
+
realHome ? resolve20(realHome, ".cargo/bin") : "",
|
|
3343
3397
|
...inheritedPath,
|
|
3344
3398
|
"/usr/local/bin",
|
|
3345
3399
|
"/usr/local/sbin",
|
|
@@ -3370,9 +3424,9 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
3370
3424
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
3371
3425
|
function resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext) {
|
|
3372
3426
|
if (runtimeContext) {
|
|
3373
|
-
return
|
|
3427
|
+
return resolve21(runtimeContext.binDir, "validators", binaryName);
|
|
3374
3428
|
}
|
|
3375
|
-
return
|
|
3429
|
+
return resolve21(resolveHarnessPaths(projectRoot).binDir, "validators", binaryName);
|
|
3376
3430
|
}
|
|
3377
3431
|
async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
3378
3432
|
const match = checkId.match(/^([a-z][\w-]*):([a-z][\w-]*)$/);
|
|
@@ -3387,19 +3441,19 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
3387
3441
|
const binaryName = `${category}-${check}`;
|
|
3388
3442
|
const binaryPath = resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
3389
3443
|
const hostProjectRoot = runtimeContext?.hostProjectRoot?.trim() || projectRoot;
|
|
3390
|
-
const sourcePath =
|
|
3391
|
-
if (!
|
|
3444
|
+
const sourcePath = resolve21(hostProjectRoot, "packages/runtime/src/control-plane/validators", category, `${check}.ts`);
|
|
3445
|
+
if (!existsSync18(sourcePath)) {
|
|
3392
3446
|
return null;
|
|
3393
3447
|
}
|
|
3394
3448
|
const sourceMtime = statSync4(sourcePath).mtimeMs;
|
|
3395
|
-
const binaryExists =
|
|
3449
|
+
const binaryExists = existsSync18(binaryPath);
|
|
3396
3450
|
const binaryMtime = binaryExists ? statSync4(binaryPath).mtimeMs : 0;
|
|
3397
3451
|
if (!binaryExists || sourceMtime > binaryMtime) {
|
|
3398
3452
|
if (binaryExists) {
|
|
3399
|
-
|
|
3400
|
-
|
|
3453
|
+
rmSync5(binaryPath, { force: true });
|
|
3454
|
+
rmSync5(`${binaryPath}.build-manifest.json`, { force: true });
|
|
3401
3455
|
}
|
|
3402
|
-
|
|
3456
|
+
mkdirSync7(dirname10(binaryPath), { recursive: true });
|
|
3403
3457
|
await buildRuntimeBinary({
|
|
3404
3458
|
sourcePath: `packages/runtime/src/control-plane/validators/${category}/${check}.ts`,
|
|
3405
3459
|
outputPath: binaryPath,
|
|
@@ -3408,7 +3462,7 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
3408
3462
|
env: runtimeProvisioningEnv()
|
|
3409
3463
|
});
|
|
3410
3464
|
}
|
|
3411
|
-
return
|
|
3465
|
+
return existsSync18(binaryPath) ? binaryPath : null;
|
|
3412
3466
|
}
|
|
3413
3467
|
|
|
3414
3468
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
@@ -3445,20 +3499,20 @@ async function readTaskSourceValidation(projectRoot, taskId) {
|
|
|
3445
3499
|
function resolveValidationPaths(projectRoot, taskId, runtimeContext) {
|
|
3446
3500
|
if (runtimeContext) {
|
|
3447
3501
|
return {
|
|
3448
|
-
taskLogDir:
|
|
3449
|
-
artifactDir:
|
|
3502
|
+
taskLogDir: resolve22(runtimeContext.logsDir, taskId),
|
|
3503
|
+
artifactDir: resolve22(runtimeContext.workspaceDir, "artifacts", taskId)
|
|
3450
3504
|
};
|
|
3451
3505
|
}
|
|
3452
3506
|
const paths = resolveHarnessPaths(projectRoot);
|
|
3453
3507
|
return {
|
|
3454
|
-
taskLogDir:
|
|
3455
|
-
artifactDir:
|
|
3508
|
+
taskLogDir: resolve22(paths.logsDir, taskId),
|
|
3509
|
+
artifactDir: resolve22(paths.artifactsDir, taskId)
|
|
3456
3510
|
};
|
|
3457
3511
|
}
|
|
3458
3512
|
async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext) {
|
|
3459
3513
|
const binaryName = checkId.replace(":", "-");
|
|
3460
3514
|
const binaryPath = await ensureValidatorBinary(projectRoot, checkId, runtimeContext) ?? resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
3461
|
-
if (!
|
|
3515
|
+
if (!existsSync19(binaryPath)) {
|
|
3462
3516
|
return {
|
|
3463
3517
|
result: {
|
|
3464
3518
|
id: checkId,
|
|
@@ -3469,7 +3523,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
3469
3523
|
};
|
|
3470
3524
|
}
|
|
3471
3525
|
const validatorCwd = runtimeContext?.workspaceDir || resolveMonorepoRoot(projectRoot);
|
|
3472
|
-
const runtimeShellPath = runtimeContext ?
|
|
3526
|
+
const runtimeShellPath = runtimeContext ? resolve22(runtimeContext.binDir, "rig-shell") : "";
|
|
3473
3527
|
const monorepoMainRoot = runtimeContext?.monorepoMainRoot || process.env.MONOREPO_MAIN_ROOT?.trim() || resolveMonorepoRoot(projectRoot);
|
|
3474
3528
|
const validatorEnv = {
|
|
3475
3529
|
PROJECT_RIG_ROOT: runtimeContext?.hostProjectRoot || projectRoot,
|
|
@@ -3484,7 +3538,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
3484
3538
|
validatorEnv.RIG_LOGS_DIR = runtimeContext.logsDir;
|
|
3485
3539
|
validatorEnv.RIG_RUNTIME_BIN_DIR = runtimeContext.binDir;
|
|
3486
3540
|
}
|
|
3487
|
-
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath &&
|
|
3541
|
+
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath && existsSync19(runtimeShellPath) ? [runtimeShellPath, "run-binary", binaryPath] : [binaryPath], validatorCwd, validatorEnv);
|
|
3488
3542
|
try {
|
|
3489
3543
|
const result = JSON.parse(stdout.trim());
|
|
3490
3544
|
return { result, exitCode };
|
|
@@ -3524,8 +3578,8 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
3524
3578
|
const configuredValidation = stringArray(taskConfig[taskId]?.validation);
|
|
3525
3579
|
const commands = resolvedContext?.validation?.length ? resolvedContext.validation : configuredValidation.length > 0 ? configuredValidation : sourceValidation.validation;
|
|
3526
3580
|
const { taskLogDir, artifactDir } = resolveValidationPaths(projectRoot, taskId, resolvedContext);
|
|
3527
|
-
|
|
3528
|
-
|
|
3581
|
+
mkdirSync8(taskLogDir, { recursive: true });
|
|
3582
|
+
mkdirSync8(artifactDir, { recursive: true });
|
|
3529
3583
|
if (commands.length === 0) {
|
|
3530
3584
|
const skipped = {
|
|
3531
3585
|
status: "skipped",
|
|
@@ -3534,7 +3588,7 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
3534
3588
|
failed: 0,
|
|
3535
3589
|
categories: []
|
|
3536
3590
|
};
|
|
3537
|
-
|
|
3591
|
+
writeFileSync8(resolve22(artifactDir, "validation-summary.json"), `${JSON.stringify(skipped, null, 2)}
|
|
3538
3592
|
`, "utf-8");
|
|
3539
3593
|
return skipped;
|
|
3540
3594
|
}
|
|
@@ -3569,18 +3623,18 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
3569
3623
|
exit_code: 2,
|
|
3570
3624
|
duration_seconds: 0
|
|
3571
3625
|
});
|
|
3572
|
-
const logFile2 =
|
|
3573
|
-
|
|
3574
|
-
|
|
3626
|
+
const logFile2 = resolve22(taskLogDir, `invalid-entry-validation.log`);
|
|
3627
|
+
mkdirSync8(taskLogDir, { recursive: true });
|
|
3628
|
+
writeFileSync8(logFile2, `=== ${nowIso()} :: ${cmd} ===
|
|
3575
3629
|
Invalid validation entry: not a check-ID. All entries must use format "category:check-name".
|
|
3576
3630
|
`, "utf-8");
|
|
3577
3631
|
continue;
|
|
3578
3632
|
}
|
|
3579
3633
|
const { result, exitCode } = await dispatchValidator(cmd, effectiveRegistry, validatorCtx, (id) => runValidatorBinary(projectRoot, taskId, id, resolvedContext));
|
|
3580
3634
|
const durationSeconds = Math.max(0, Math.round((Date.now() - startedAt) / 1000));
|
|
3581
|
-
const logFile =
|
|
3582
|
-
|
|
3583
|
-
|
|
3635
|
+
const logFile = resolve22(taskLogDir, `${cmd.replace(":", "-")}-validation.log`);
|
|
3636
|
+
mkdirSync8(taskLogDir, { recursive: true });
|
|
3637
|
+
writeFileSync8(logFile, `=== ${nowIso()} :: ${cmd} ===
|
|
3584
3638
|
${JSON.stringify(result, null, 2)}
|
|
3585
3639
|
`, "utf-8");
|
|
3586
3640
|
if (result.passed) {
|
|
@@ -3602,15 +3656,15 @@ ${JSON.stringify(result, null, 2)}
|
|
|
3602
3656
|
failed,
|
|
3603
3657
|
categories
|
|
3604
3658
|
};
|
|
3605
|
-
|
|
3606
|
-
|
|
3659
|
+
mkdirSync8(artifactDir, { recursive: true });
|
|
3660
|
+
writeFileSync8(resolve22(artifactDir, "validation-summary.json"), `${JSON.stringify(summary, null, 2)}
|
|
3607
3661
|
`, "utf-8");
|
|
3608
3662
|
return summary;
|
|
3609
3663
|
}
|
|
3610
3664
|
|
|
3611
3665
|
// packages/runtime/src/control-plane/native/verifier.ts
|
|
3612
|
-
import { existsSync as
|
|
3613
|
-
import { resolve as
|
|
3666
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
3667
|
+
import { resolve as resolve23 } from "path";
|
|
3614
3668
|
|
|
3615
3669
|
// packages/runtime/src/control-plane/native/pr-review-gate.ts
|
|
3616
3670
|
function parseJsonObject(value) {
|
|
@@ -4861,11 +4915,11 @@ async function verifyTask(options) {
|
|
|
4861
4915
|
const taskId = options.taskId;
|
|
4862
4916
|
const normalizedTaskId = lookupTask(options.projectRoot, taskId);
|
|
4863
4917
|
const artifactDir = artifactDirForId(options.projectRoot, taskId);
|
|
4864
|
-
|
|
4865
|
-
const validationSummaryPath =
|
|
4866
|
-
const reviewFeedbackPath =
|
|
4867
|
-
const reviewStatePath =
|
|
4868
|
-
const greptileRawPath =
|
|
4918
|
+
mkdirSync9(artifactDir, { recursive: true });
|
|
4919
|
+
const validationSummaryPath = resolve23(artifactDir, "validation-summary.json");
|
|
4920
|
+
const reviewFeedbackPath = resolve23(artifactDir, "review-feedback.md");
|
|
4921
|
+
const reviewStatePath = resolve23(artifactDir, "review-state.json");
|
|
4922
|
+
const greptileRawPath = resolve23(artifactDir, "review-greptile-raw.json");
|
|
4869
4923
|
const prStates = readPrMetadata(options.projectRoot, taskId);
|
|
4870
4924
|
const prState = prStates[0] || null;
|
|
4871
4925
|
const localReasons = [];
|
|
@@ -4877,7 +4931,7 @@ async function verifyTask(options) {
|
|
|
4877
4931
|
if (!normalizedTaskId && !await hasConfiguredSourceTask(options.projectRoot, taskId)) {
|
|
4878
4932
|
localReasons.push(`[Task Config] Unknown task id '${taskId}' in task-config or configured task source.`);
|
|
4879
4933
|
}
|
|
4880
|
-
if (!
|
|
4934
|
+
if (!existsSync20(validationSummaryPath)) {
|
|
4881
4935
|
localReasons.push(`[Artifact Quality] validation-summary.json not found at ${validationSummaryPath}.`);
|
|
4882
4936
|
} else {
|
|
4883
4937
|
const summary = await parseValidationSummary(validationSummaryPath);
|
|
@@ -4886,13 +4940,13 @@ async function verifyTask(options) {
|
|
|
4886
4940
|
}
|
|
4887
4941
|
}
|
|
4888
4942
|
for (const file of ["task-result.json", "decision-log.md", "next-actions.md", "changed-files.txt"]) {
|
|
4889
|
-
const requiredPath =
|
|
4890
|
-
if (!
|
|
4943
|
+
const requiredPath = resolve23(artifactDir, file);
|
|
4944
|
+
if (!existsSync20(requiredPath)) {
|
|
4891
4945
|
localReasons.push(`[Artifact Quality] Missing required artifact file: ${requiredPath}`);
|
|
4892
4946
|
}
|
|
4893
4947
|
}
|
|
4894
|
-
const taskResultPath =
|
|
4895
|
-
if (
|
|
4948
|
+
const taskResultPath = resolve23(artifactDir, "task-result.json");
|
|
4949
|
+
if (existsSync20(taskResultPath)) {
|
|
4896
4950
|
const taskResult = await readJsonFile2(taskResultPath);
|
|
4897
4951
|
const artifactStatus = typeof taskResult?.status === "string" ? taskResult.status.trim().toLowerCase() : "";
|
|
4898
4952
|
if (artifactStatus === "partial") {
|
|
@@ -4905,8 +4959,8 @@ async function verifyTask(options) {
|
|
|
4905
4959
|
localReasons.push("[Artifact Quality] task-result.json next actions indicate remaining implementation scope.");
|
|
4906
4960
|
}
|
|
4907
4961
|
}
|
|
4908
|
-
const nextActionsPath =
|
|
4909
|
-
if (
|
|
4962
|
+
const nextActionsPath = resolve23(artifactDir, "next-actions.md");
|
|
4963
|
+
if (existsSync20(nextActionsPath)) {
|
|
4910
4964
|
const nextActionsContent = await Bun.file(nextActionsPath).text();
|
|
4911
4965
|
if (nextActionsContent.includes("TODO: Replace this scaffold") || nextActionsContent.includes("bd-<downstream-task-id>")) {
|
|
4912
4966
|
localReasons.push("[Artifact Quality] next-actions.md still contains scaffold placeholder text. Replace with real recommendations.");
|
|
@@ -4919,12 +4973,6 @@ async function verifyTask(options) {
|
|
|
4919
4973
|
if (sourceCloseoutIssueId) {
|
|
4920
4974
|
localReasons.push(...evaluateGithubSourceIssuePrCloseout(options.projectRoot, prStates, sourceCloseoutIssueId));
|
|
4921
4975
|
}
|
|
4922
|
-
const pluginResults = await options.plugins.runValidators(taskId);
|
|
4923
|
-
for (const result of pluginResults) {
|
|
4924
|
-
if (!result.passed) {
|
|
4925
|
-
localReasons.push(`[Plugin Validator] ${result.id}: ${result.summary}`);
|
|
4926
|
-
}
|
|
4927
|
-
}
|
|
4928
4976
|
const reviewMode = await loadReviewMode(paths.reviewProfilePath, process.env.AI_REVIEW_MODE || "advisory");
|
|
4929
4977
|
const reviewProvider = await loadReviewProvider(paths.reviewProfilePath, process.env.AI_REVIEW_PROVIDER || "greptile");
|
|
4930
4978
|
if (!options.skipAiReview && localReasons.length === 0 && reviewProvider === "greptile" && reviewMode !== "off") {
|
|
@@ -4943,7 +4991,7 @@ async function verifyTask(options) {
|
|
|
4943
4991
|
aiReasons.push(`[AI Review] Required mode needs a completed Greptile approval; current verdict is ${ai.verdict}.`);
|
|
4944
4992
|
}
|
|
4945
4993
|
if (persistArtifacts && ai.rawResponse) {
|
|
4946
|
-
|
|
4994
|
+
writeFileSync9(greptileRawPath, `${ai.rawResponse}
|
|
4947
4995
|
`, "utf-8");
|
|
4948
4996
|
}
|
|
4949
4997
|
} else if (!options.skipAiReview && reviewMode === "off") {
|
|
@@ -5282,7 +5330,7 @@ function isAcceptedValidationSummary(summary) {
|
|
|
5282
5330
|
return summary.status === "skipped" && summary.total === 0 && summary.failed === 0;
|
|
5283
5331
|
}
|
|
5284
5332
|
async function loadReviewMode(reviewProfilePath, fallback) {
|
|
5285
|
-
const parsed =
|
|
5333
|
+
const parsed = existsSync20(reviewProfilePath) ? await readJsonFile2(reviewProfilePath) : null;
|
|
5286
5334
|
const mode = parsed?.mode;
|
|
5287
5335
|
if (mode === "off" || mode === "advisory" || mode === "required") {
|
|
5288
5336
|
return mode;
|
|
@@ -5293,7 +5341,7 @@ async function loadReviewMode(reviewProfilePath, fallback) {
|
|
|
5293
5341
|
return "advisory";
|
|
5294
5342
|
}
|
|
5295
5343
|
async function loadReviewProvider(reviewProfilePath, fallback) {
|
|
5296
|
-
const parsed =
|
|
5344
|
+
const parsed = existsSync20(reviewProfilePath) ? await readJsonFile2(reviewProfilePath) : null;
|
|
5297
5345
|
const provider = parsed?.provider;
|
|
5298
5346
|
if (typeof provider === "string" && provider.trim().length > 0) {
|
|
5299
5347
|
return provider;
|
|
@@ -5452,7 +5500,7 @@ function writeFeedbackFile(options) {
|
|
|
5452
5500
|
if (options.aiRawFeedback) {
|
|
5453
5501
|
lines.push("## Raw Reviewer Feedback", "", "```text", options.aiRawFeedback, "```", "");
|
|
5454
5502
|
}
|
|
5455
|
-
|
|
5503
|
+
writeFileSync9(options.output, `${lines.join(`
|
|
5456
5504
|
`)}
|
|
5457
5505
|
`, "utf-8");
|
|
5458
5506
|
}
|
|
@@ -5469,7 +5517,7 @@ function writeReviewStateFile(options) {
|
|
|
5469
5517
|
ai_warnings: options.aiWarnings,
|
|
5470
5518
|
updated_at: nowIso()
|
|
5471
5519
|
};
|
|
5472
|
-
|
|
5520
|
+
writeFileSync9(options.output, `${JSON.stringify(payload, null, 2)}
|
|
5473
5521
|
`, "utf-8");
|
|
5474
5522
|
}
|
|
5475
5523
|
async function runGreptileReviewForPr(options) {
|
|
@@ -6256,7 +6304,7 @@ function filterActionableGithubGreptileThreads(threads) {
|
|
|
6256
6304
|
}
|
|
6257
6305
|
function resolvePrRepoRoot(projectRoot, prState) {
|
|
6258
6306
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
6259
|
-
if (prState.target === "monorepo" && runtimeWorkspace &&
|
|
6307
|
+
if (prState.target === "monorepo" && runtimeWorkspace && existsSync20(resolve23(runtimeWorkspace, ".git"))) {
|
|
6260
6308
|
return runtimeWorkspace;
|
|
6261
6309
|
}
|
|
6262
6310
|
const paths = resolveHarnessPaths(projectRoot);
|
|
@@ -6628,16 +6676,16 @@ async function taskDeps(projectRoot, taskId) {
|
|
|
6628
6676
|
for (const dep of deps) {
|
|
6629
6677
|
const artifactDir = artifactDirForId(projectRoot, dep);
|
|
6630
6678
|
console.log(`=== ${dep} ===`);
|
|
6631
|
-
if (!
|
|
6679
|
+
if (!existsSync21(artifactDir)) {
|
|
6632
6680
|
console.log(` (no artifacts yet)
|
|
6633
6681
|
`);
|
|
6634
6682
|
continue;
|
|
6635
6683
|
}
|
|
6636
|
-
printArtifactSection(
|
|
6637
|
-
printArtifactSection(
|
|
6638
|
-
const changedFiles =
|
|
6639
|
-
if (
|
|
6640
|
-
const lines =
|
|
6684
|
+
printArtifactSection(resolve24(artifactDir, "decision-log.md"), "--- Decisions ---");
|
|
6685
|
+
printArtifactSection(resolve24(artifactDir, "next-actions.md"), "--- Next Actions (for you) ---");
|
|
6686
|
+
const changedFiles = resolve24(artifactDir, "changed-files.txt");
|
|
6687
|
+
if (existsSync21(changedFiles)) {
|
|
6688
|
+
const lines = readFileSync11(changedFiles, "utf-8").split(/\r?\n/).filter(Boolean);
|
|
6641
6689
|
console.log(`--- Changed Files (${lines.length}) ---`);
|
|
6642
6690
|
for (const line of lines) {
|
|
6643
6691
|
console.log(line);
|
|
@@ -6682,12 +6730,12 @@ function taskRecord(projectRoot, type, text, taskId) {
|
|
|
6682
6730
|
throw new Error("No active task.");
|
|
6683
6731
|
}
|
|
6684
6732
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6685
|
-
|
|
6733
|
+
mkdirSync10(paths.stateDir, { recursive: true });
|
|
6686
6734
|
if (type === "decision") {
|
|
6687
|
-
const artifactDir =
|
|
6688
|
-
|
|
6735
|
+
const artifactDir = resolve24(paths.artifactsDir, activeTask);
|
|
6736
|
+
mkdirSync10(artifactDir, { recursive: true });
|
|
6689
6737
|
const timestamp = nowIso();
|
|
6690
|
-
appendFileSync(
|
|
6738
|
+
appendFileSync(resolve24(artifactDir, "decision-log.md"), `
|
|
6691
6739
|
### ${timestamp}
|
|
6692
6740
|
|
|
6693
6741
|
${text}
|
|
@@ -6697,14 +6745,14 @@ ${text}
|
|
|
6697
6745
|
return;
|
|
6698
6746
|
}
|
|
6699
6747
|
const failedPath = paths.failedApproachesPath;
|
|
6700
|
-
if (!
|
|
6701
|
-
|
|
6748
|
+
if (!existsSync21(failedPath)) {
|
|
6749
|
+
writeFileSync10(failedPath, `# Failed Approaches Log
|
|
6702
6750
|
|
|
6703
6751
|
This file records approaches that did not work.
|
|
6704
6752
|
|
|
6705
6753
|
`, "utf-8");
|
|
6706
6754
|
}
|
|
6707
|
-
const content =
|
|
6755
|
+
const content = readFileSync11(failedPath, "utf-8");
|
|
6708
6756
|
const attempts = (content.match(new RegExp(`^## ${escapeRegExp(activeTask)}\\b`, "gm")) || []).length + 1;
|
|
6709
6757
|
appendFileSync(failedPath, `
|
|
6710
6758
|
## ${activeTask} - Attempt ${attempts} (${nowIso()})
|
|
@@ -6721,40 +6769,40 @@ function taskArtifacts(projectRoot, taskId) {
|
|
|
6721
6769
|
throw new Error("No active task.");
|
|
6722
6770
|
}
|
|
6723
6771
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6724
|
-
const artifactDir =
|
|
6725
|
-
|
|
6772
|
+
const artifactDir = resolve24(paths.artifactsDir, activeTask);
|
|
6773
|
+
mkdirSync10(artifactDir, { recursive: true });
|
|
6726
6774
|
const changed = changedFilesForTask(projectRoot, activeTask, true);
|
|
6727
|
-
|
|
6775
|
+
writeFileSync10(resolve24(artifactDir, "changed-files.txt"), `${changed.join(`
|
|
6728
6776
|
`)}
|
|
6729
6777
|
`, "utf-8");
|
|
6730
6778
|
console.log(`changed-files.txt: ${changed.length} files`);
|
|
6731
|
-
const taskResultPath =
|
|
6732
|
-
if (!
|
|
6779
|
+
const taskResultPath = resolve24(artifactDir, "task-result.json");
|
|
6780
|
+
if (!existsSync21(taskResultPath)) {
|
|
6733
6781
|
const template = {
|
|
6734
6782
|
task_id: activeTask,
|
|
6735
6783
|
status: "completed",
|
|
6736
6784
|
summary: "TODO: Write a one-line summary of what you did",
|
|
6737
6785
|
completed_at: nowIso()
|
|
6738
6786
|
};
|
|
6739
|
-
|
|
6787
|
+
writeFileSync10(taskResultPath, `${JSON.stringify(template, null, 2)}
|
|
6740
6788
|
`, "utf-8");
|
|
6741
6789
|
console.log("task-result.json: created (update the summary!)");
|
|
6742
6790
|
} else {
|
|
6743
6791
|
console.log("task-result.json: already exists");
|
|
6744
6792
|
}
|
|
6745
|
-
const decisionLogPath =
|
|
6746
|
-
if (!
|
|
6793
|
+
const decisionLogPath = resolve24(artifactDir, "decision-log.md");
|
|
6794
|
+
if (!existsSync21(decisionLogPath)) {
|
|
6747
6795
|
const content = `# Decision Log: ${activeTask}
|
|
6748
6796
|
|
|
6749
6797
|
Record key decisions here using: rig-agent record decision "..."
|
|
6750
6798
|
`;
|
|
6751
|
-
|
|
6799
|
+
writeFileSync10(decisionLogPath, content, "utf-8");
|
|
6752
6800
|
console.log("decision-log.md: created (record your decisions!)");
|
|
6753
6801
|
} else {
|
|
6754
6802
|
console.log("decision-log.md: already exists");
|
|
6755
6803
|
}
|
|
6756
|
-
const nextActionsPath =
|
|
6757
|
-
if (!
|
|
6804
|
+
const nextActionsPath = resolve24(artifactDir, "next-actions.md");
|
|
6805
|
+
if (!existsSync21(nextActionsPath)) {
|
|
6758
6806
|
const content = [
|
|
6759
6807
|
`# Next Actions: ${activeTask}`,
|
|
6760
6808
|
"",
|
|
@@ -6771,13 +6819,13 @@ Record key decisions here using: rig-agent record decision "..."
|
|
|
6771
6819
|
""
|
|
6772
6820
|
].join(`
|
|
6773
6821
|
`);
|
|
6774
|
-
|
|
6822
|
+
writeFileSync10(nextActionsPath, content, "utf-8");
|
|
6775
6823
|
console.log("next-actions.md: created (add recommendations for downstream tasks!)");
|
|
6776
6824
|
} else {
|
|
6777
6825
|
console.log("next-actions.md: already exists");
|
|
6778
6826
|
}
|
|
6779
|
-
const validationSummaryPath =
|
|
6780
|
-
if (
|
|
6827
|
+
const validationSummaryPath = resolve24(artifactDir, "validation-summary.json");
|
|
6828
|
+
if (existsSync21(validationSummaryPath)) {
|
|
6781
6829
|
console.log("validation-summary.json: already exists");
|
|
6782
6830
|
} else {
|
|
6783
6831
|
console.log("validation-summary.json: not yet created (run: rig-agent validate)");
|
|
@@ -6820,12 +6868,12 @@ async function taskValidate(projectRoot, taskId, validatorRegistry) {
|
|
|
6820
6868
|
console.log(`Validation passed: ${summary.passed}/${summary.total}`);
|
|
6821
6869
|
return true;
|
|
6822
6870
|
}
|
|
6823
|
-
async function taskVerify(projectRoot,
|
|
6871
|
+
async function taskVerify(projectRoot, taskId) {
|
|
6824
6872
|
const activeTask = taskId || currentTaskId(projectRoot);
|
|
6825
6873
|
if (!activeTask) {
|
|
6826
6874
|
throw new Error("No active task.");
|
|
6827
6875
|
}
|
|
6828
|
-
const outcome = await verifyTask({ projectRoot, taskId: activeTask
|
|
6876
|
+
const outcome = await verifyTask({ projectRoot, taskId: activeTask });
|
|
6829
6877
|
if (!outcome.approved) {
|
|
6830
6878
|
console.log("REJECT:");
|
|
6831
6879
|
for (const reason of outcome.localReasons) {
|
|
@@ -6868,7 +6916,7 @@ function collectTaskChangedFiles(projectRoot, taskId, includeCommitted) {
|
|
|
6868
6916
|
[projectRoot, ""],
|
|
6869
6917
|
[monorepoRepoRoot, ""]
|
|
6870
6918
|
]) {
|
|
6871
|
-
if (!
|
|
6919
|
+
if (!existsSync21(resolve24(repo, ".git"))) {
|
|
6872
6920
|
continue;
|
|
6873
6921
|
}
|
|
6874
6922
|
if (includeCommitted && repo === monorepoRepoRoot) {
|
|
@@ -6906,8 +6954,8 @@ function filterTaskChangedFiles(projectRoot, taskId, files, scoped) {
|
|
|
6906
6954
|
}
|
|
6907
6955
|
function resolveTaskMonorepoRoot(projectRoot) {
|
|
6908
6956
|
const runtimeWorkspace = loadRuntimeContextFromEnv()?.workspaceDir || process.env.RIG_TASK_WORKSPACE?.trim();
|
|
6909
|
-
if (runtimeWorkspace &&
|
|
6910
|
-
return
|
|
6957
|
+
if (runtimeWorkspace && existsSync21(resolve24(runtimeWorkspace, ".git"))) {
|
|
6958
|
+
return resolve24(runtimeWorkspace);
|
|
6911
6959
|
}
|
|
6912
6960
|
return resolveHarnessPaths(projectRoot).monorepoRoot;
|
|
6913
6961
|
}
|
|
@@ -6935,7 +6983,7 @@ function resolveRuntimeInitialHeadCommit(projectRoot, repo) {
|
|
|
6935
6983
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
6936
6984
|
if (runtimeContext?.initialHeadCommits?.monorepo?.trim()) {
|
|
6937
6985
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6938
|
-
if (
|
|
6986
|
+
if (resolve24(monorepoRoot) === resolve24(repo)) {
|
|
6939
6987
|
return runtimeContext.initialHeadCommits.monorepo.trim();
|
|
6940
6988
|
}
|
|
6941
6989
|
}
|
|
@@ -6945,7 +6993,7 @@ function resolveMonorepoBaseCommit(projectRoot, repo) {
|
|
|
6945
6993
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
6946
6994
|
if (runtimeContext?.monorepoBaseCommit?.trim()) {
|
|
6947
6995
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6948
|
-
if (
|
|
6996
|
+
if (resolve24(monorepoRoot) === resolve24(repo)) {
|
|
6949
6997
|
return runtimeContext.monorepoBaseCommit.trim();
|
|
6950
6998
|
}
|
|
6951
6999
|
}
|
|
@@ -6979,7 +7027,7 @@ function resolveRuntimeDirtyBaseline(projectRoot, repo) {
|
|
|
6979
7027
|
return new Set;
|
|
6980
7028
|
}
|
|
6981
7029
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6982
|
-
const selected =
|
|
7030
|
+
const selected = resolve24(repo) === resolve24(monorepoRoot) ? dirtyFiles.monorepo : resolve24(repo) === resolve24(projectRoot) ? dirtyFiles.project : undefined;
|
|
6983
7031
|
return new Set((selected || []).map((file) => normalizeChangedFilePath(file)).filter(Boolean));
|
|
6984
7032
|
}
|
|
6985
7033
|
function normalizeChangedFilePath(file) {
|
|
@@ -7079,12 +7127,12 @@ function printIndented(text) {
|
|
|
7079
7127
|
}
|
|
7080
7128
|
}
|
|
7081
7129
|
function readLocalBeadsTasks(projectRoot) {
|
|
7082
|
-
const issuesPath =
|
|
7083
|
-
if (!
|
|
7130
|
+
const issuesPath = resolve24(resolveMonorepoRoot2(projectRoot), ".beads/issues.jsonl");
|
|
7131
|
+
if (!existsSync21(issuesPath)) {
|
|
7084
7132
|
return [];
|
|
7085
7133
|
}
|
|
7086
7134
|
const tasks = [];
|
|
7087
|
-
for (const line of
|
|
7135
|
+
for (const line of readFileSync11(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
7088
7136
|
const trimmed = line.trim();
|
|
7089
7137
|
if (!trimmed) {
|
|
7090
7138
|
continue;
|
|
@@ -7197,11 +7245,11 @@ function taskDependencies(projectRoot, taskId, tracker) {
|
|
|
7197
7245
|
return [...ids].sort();
|
|
7198
7246
|
}
|
|
7199
7247
|
function printArtifactSection(path, header) {
|
|
7200
|
-
if (!
|
|
7248
|
+
if (!existsSync21(path)) {
|
|
7201
7249
|
return;
|
|
7202
7250
|
}
|
|
7203
7251
|
console.log(header);
|
|
7204
|
-
process.stdout.write(
|
|
7252
|
+
process.stdout.write(readFileSync11(path, "utf-8"));
|
|
7205
7253
|
console.log("");
|
|
7206
7254
|
}
|
|
7207
7255
|
function escapeRegExp(value) {
|
|
@@ -7241,8 +7289,8 @@ function isRuntimeGatewayGhPath(candidate) {
|
|
|
7241
7289
|
}
|
|
7242
7290
|
function resolveOptionalMonorepoRoot(projectRoot) {
|
|
7243
7291
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
7244
|
-
if (runtimeWorkspace &&
|
|
7245
|
-
return
|
|
7292
|
+
if (runtimeWorkspace && existsSync22(resolve25(runtimeWorkspace, ".git"))) {
|
|
7293
|
+
return resolve25(runtimeWorkspace);
|
|
7246
7294
|
}
|
|
7247
7295
|
try {
|
|
7248
7296
|
return resolveMonorepoRoot2(projectRoot);
|
|
@@ -7267,7 +7315,7 @@ function resolveGitBinary(projectRoot) {
|
|
|
7267
7315
|
if (!candidate || isRuntimeGatewayGitPath(candidate)) {
|
|
7268
7316
|
continue;
|
|
7269
7317
|
}
|
|
7270
|
-
if (
|
|
7318
|
+
if (existsSync22(candidate)) {
|
|
7271
7319
|
return candidate;
|
|
7272
7320
|
}
|
|
7273
7321
|
}
|
|
@@ -7327,11 +7375,11 @@ function gitPreflight(projectRoot, taskId, strict) {
|
|
|
7327
7375
|
const expected = resolvedTask ? `rig/${resolveTaskBranchId(projectRoot, resolvedTask)}` : "";
|
|
7328
7376
|
console.log("=== Git Flow Preflight ===");
|
|
7329
7377
|
let issues = 0;
|
|
7330
|
-
if (!
|
|
7378
|
+
if (!existsSync22(resolve25(projectRoot, ".git"))) {
|
|
7331
7379
|
console.log(`ERROR: project root is not a git repo (${projectRoot})`);
|
|
7332
7380
|
issues += 1;
|
|
7333
7381
|
}
|
|
7334
|
-
if (monorepoRoot &&
|
|
7382
|
+
if (monorepoRoot && existsSync22(resolve25(monorepoRoot, ".git"))) {
|
|
7335
7383
|
const monoBranch = branchName(projectRoot, monorepoRoot);
|
|
7336
7384
|
if (expected && monoBranch !== expected) {
|
|
7337
7385
|
console.log(`WARN: monorepo branch is ${monoBranch}, expected ${expected} for task ${resolvedTask}`);
|
|
@@ -7365,7 +7413,7 @@ function gitSyncBranch(projectRoot, taskId, targetRepo = "monorepo") {
|
|
|
7365
7413
|
}
|
|
7366
7414
|
const repoRoot = targetRepo === "monorepo" ? resolveOptionalMonorepoRoot(projectRoot) || resolveMonorepoRoot2(projectRoot) : projectRoot;
|
|
7367
7415
|
const repoLabel = targetRepo === "monorepo" ? "Monorepo" : "Project";
|
|
7368
|
-
if (!
|
|
7416
|
+
if (!existsSync22(resolve25(repoRoot, ".git"))) {
|
|
7369
7417
|
throw new Error(`${repoLabel} repo not found at ${repoRoot}`);
|
|
7370
7418
|
}
|
|
7371
7419
|
const branchId = resolveTaskBranchId(projectRoot, resolvedTask);
|
|
@@ -7409,8 +7457,8 @@ function gitCommit(options) {
|
|
|
7409
7457
|
function gitSnapshot(projectRoot, taskId, outputPath) {
|
|
7410
7458
|
const monorepoRoot = resolveOptionalMonorepoRoot(projectRoot);
|
|
7411
7459
|
const resolvedTask = taskId || safeCurrentTaskId(projectRoot);
|
|
7412
|
-
const output = outputPath || (resolvedTask ? resolveArtifactSnapshot(projectRoot, resolvedTask) :
|
|
7413
|
-
|
|
7460
|
+
const output = outputPath || (resolvedTask ? resolveArtifactSnapshot(projectRoot, resolvedTask) : resolve25(resolve25(projectRoot, ".rig", "state"), "git-state.txt"));
|
|
7461
|
+
mkdirSync11(dirname11(output), { recursive: true });
|
|
7414
7462
|
const lines = ["# Git Snapshot", `timestamp: ${nowIso()}`];
|
|
7415
7463
|
if (resolvedTask) {
|
|
7416
7464
|
lines.push(`task: ${resolvedTask}`);
|
|
@@ -7420,7 +7468,7 @@ function gitSnapshot(projectRoot, taskId, outputPath) {
|
|
|
7420
7468
|
if (monorepoRoot && monorepoRoot !== projectRoot) {
|
|
7421
7469
|
lines.push(...snapshotRepo(projectRoot, "monorepo", monorepoRoot));
|
|
7422
7470
|
}
|
|
7423
|
-
|
|
7471
|
+
writeFileSync11(output, `${lines.join(`
|
|
7424
7472
|
`)}
|
|
7425
7473
|
`, "utf-8");
|
|
7426
7474
|
return output;
|
|
@@ -7444,7 +7492,7 @@ function gitOpenPr(options) {
|
|
|
7444
7492
|
} else if (taskId) {
|
|
7445
7493
|
gitSyncBranch(options.projectRoot, taskId, "project");
|
|
7446
7494
|
}
|
|
7447
|
-
if (!
|
|
7495
|
+
if (!existsSync22(resolve25(repoRoot, ".git"))) {
|
|
7448
7496
|
throw new Error(`Repository not available for open-pr target ${target}: ${repoRoot}`);
|
|
7449
7497
|
}
|
|
7450
7498
|
const branch = branchName(options.projectRoot, repoRoot);
|
|
@@ -7657,12 +7705,12 @@ function assertPrHasNoGitConflicts(prState, repoLabel, baseRef) {
|
|
|
7657
7705
|
}
|
|
7658
7706
|
function writePrMetadata(projectRoot, taskId, result) {
|
|
7659
7707
|
const dir = artifactDirForId(projectRoot, taskId);
|
|
7660
|
-
|
|
7661
|
-
const path =
|
|
7708
|
+
mkdirSync11(dir, { recursive: true });
|
|
7709
|
+
const path = resolve25(dir, "pr-state.json");
|
|
7662
7710
|
let prs = {};
|
|
7663
|
-
if (
|
|
7711
|
+
if (existsSync22(path)) {
|
|
7664
7712
|
try {
|
|
7665
|
-
const parsed = JSON.parse(
|
|
7713
|
+
const parsed = JSON.parse(readFileSync12(path, "utf-8"));
|
|
7666
7714
|
if (parsed && typeof parsed === "object" && parsed.prs && typeof parsed.prs === "object") {
|
|
7667
7715
|
prs = parsed.prs;
|
|
7668
7716
|
}
|
|
@@ -7678,16 +7726,16 @@ function writePrMetadata(projectRoot, taskId, result) {
|
|
|
7678
7726
|
...primary || {},
|
|
7679
7727
|
updated_at: nowIso()
|
|
7680
7728
|
};
|
|
7681
|
-
|
|
7729
|
+
writeFileSync11(path, `${JSON.stringify(artifact, null, 2)}
|
|
7682
7730
|
`, "utf-8");
|
|
7683
7731
|
}
|
|
7684
7732
|
function readPrMetadata(projectRoot, taskId) {
|
|
7685
|
-
const path =
|
|
7686
|
-
if (!
|
|
7733
|
+
const path = resolve25(artifactDirForId(projectRoot, taskId), "pr-state.json");
|
|
7734
|
+
if (!existsSync22(path)) {
|
|
7687
7735
|
return [];
|
|
7688
7736
|
}
|
|
7689
7737
|
try {
|
|
7690
|
-
const parsed = JSON.parse(
|
|
7738
|
+
const parsed = JSON.parse(readFileSync12(path, "utf-8"));
|
|
7691
7739
|
if (!parsed || typeof parsed !== "object") {
|
|
7692
7740
|
return [];
|
|
7693
7741
|
}
|
|
@@ -7700,8 +7748,8 @@ function readPrMetadata(projectRoot, taskId) {
|
|
|
7700
7748
|
}
|
|
7701
7749
|
}
|
|
7702
7750
|
function resolveArtifactSnapshot(projectRoot, taskId) {
|
|
7703
|
-
const artifactDir =
|
|
7704
|
-
return
|
|
7751
|
+
const artifactDir = resolve25(resolveHarnessPaths(projectRoot).artifactsDir, taskId);
|
|
7752
|
+
return resolve25(artifactDir, "git-state.txt");
|
|
7705
7753
|
}
|
|
7706
7754
|
function isGitOpenPrResult(value) {
|
|
7707
7755
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -7760,14 +7808,14 @@ function resolveGithubCliBinary(projectRoot) {
|
|
|
7760
7808
|
}
|
|
7761
7809
|
const explicitPathEntries = (process.env.PATH || "").split(":").map((entry) => entry.trim()).filter(Boolean);
|
|
7762
7810
|
for (const entry of explicitPathEntries) {
|
|
7763
|
-
candidates.add(
|
|
7811
|
+
candidates.add(resolve25(entry, "gh"));
|
|
7764
7812
|
}
|
|
7765
7813
|
const bunResolved = Bun.which("gh");
|
|
7766
7814
|
if (bunResolved) {
|
|
7767
7815
|
candidates.add(bunResolved);
|
|
7768
7816
|
}
|
|
7769
7817
|
for (const candidate of candidates) {
|
|
7770
|
-
if (candidate &&
|
|
7818
|
+
if (candidate && existsSync22(candidate) && !isRuntimeGatewayGhPath(candidate)) {
|
|
7771
7819
|
return candidate;
|
|
7772
7820
|
}
|
|
7773
7821
|
}
|
|
@@ -7797,7 +7845,7 @@ function resolveRepoNameWithOwner(projectRoot, repoRoot) {
|
|
|
7797
7845
|
return resolveGithubRepoNameWithOwnerFromGitRoot(projectRoot, repoRoot, repoRoot, visited);
|
|
7798
7846
|
}
|
|
7799
7847
|
function resolveGithubRepoNameWithOwnerFromGitRoot(projectRoot, gitRoot, cwd, visited) {
|
|
7800
|
-
const normalizedGitRoot =
|
|
7848
|
+
const normalizedGitRoot = resolve25(gitRoot);
|
|
7801
7849
|
if (visited.has(normalizedGitRoot)) {
|
|
7802
7850
|
return "";
|
|
7803
7851
|
}
|
|
@@ -7869,7 +7917,7 @@ function resolveNetworkRemoteName(projectRoot, repoRoot, repoNameWithOwner) {
|
|
|
7869
7917
|
return remotes.includes("origin") ? "origin" : remotes[0];
|
|
7870
7918
|
}
|
|
7871
7919
|
function gitQuery(projectRoot, gitRoot, cwd, ...args) {
|
|
7872
|
-
const gitArgs =
|
|
7920
|
+
const gitArgs = existsSync22(resolve25(gitRoot, ".git")) ? gitCmd(projectRoot, gitRoot, ...args) : [resolveGitBinary(projectRoot), "--git-dir", gitRoot, ...args];
|
|
7873
7921
|
return runCapture2(gitArgs, cwd, projectRoot);
|
|
7874
7922
|
}
|
|
7875
7923
|
function resolveLocalGitRemoteRoot(remoteUrl, gitRoot) {
|
|
@@ -7887,9 +7935,9 @@ function resolveLocalGitRemoteRoot(remoteUrl, gitRoot) {
|
|
|
7887
7935
|
} else if (/^[a-z][a-z0-9+.-]*:\/\//i.test(normalized) || /^[^@]+@[^:]+:.+$/.test(normalized)) {
|
|
7888
7936
|
return "";
|
|
7889
7937
|
} else if (!isAbsolute2(normalized)) {
|
|
7890
|
-
candidate =
|
|
7938
|
+
candidate = resolve25(gitRoot, normalized);
|
|
7891
7939
|
}
|
|
7892
|
-
return
|
|
7940
|
+
return existsSync22(candidate) ? candidate : "";
|
|
7893
7941
|
}
|
|
7894
7942
|
function normalizeGithubRepoNameWithOwner(value) {
|
|
7895
7943
|
const normalized = value.trim();
|
|
@@ -8016,7 +8064,7 @@ function inferReviewerFromChangedFiles(projectRoot, repoRoot, baseRef, branchRef
|
|
|
8016
8064
|
return best;
|
|
8017
8065
|
}
|
|
8018
8066
|
function snapshotRepo(projectRoot, label, repo) {
|
|
8019
|
-
if (!
|
|
8067
|
+
if (!existsSync22(resolve25(repo, ".git"))) {
|
|
8020
8068
|
return [`## ${label}`, `repo: ${repo}`, "status: unavailable", ""];
|
|
8021
8069
|
}
|
|
8022
8070
|
const status = runCapture2(gitCmd(projectRoot, repo, "status", "--short"), projectRoot).stdout.trim();
|
|
@@ -8039,7 +8087,7 @@ function snapshotRepo(projectRoot, label, repo) {
|
|
|
8039
8087
|
];
|
|
8040
8088
|
}
|
|
8041
8089
|
function commitRepo(projectRoot, repo, label, message, allowEmpty, scoped, files, changedFilesManifest) {
|
|
8042
|
-
if (!
|
|
8090
|
+
if (!existsSync22(resolve25(repo, ".git"))) {
|
|
8043
8091
|
console.log(`Skipping ${label}: repo not available (${repo})`);
|
|
8044
8092
|
return;
|
|
8045
8093
|
}
|
|
@@ -8071,18 +8119,18 @@ function commitRepo(projectRoot, repo, label, message, allowEmpty, scoped, files
|
|
|
8071
8119
|
console.log(`Committed ${label}: ${message}`);
|
|
8072
8120
|
}
|
|
8073
8121
|
function readChangedFilesManifest(projectRoot, taskId) {
|
|
8074
|
-
const manifestPath =
|
|
8075
|
-
if (!
|
|
8122
|
+
const manifestPath = resolve25(artifactDirForId(projectRoot, taskId), "changed-files.txt");
|
|
8123
|
+
if (!existsSync22(manifestPath)) {
|
|
8076
8124
|
return [];
|
|
8077
8125
|
}
|
|
8078
|
-
const files =
|
|
8126
|
+
const files = readFileSync12(manifestPath, "utf-8").split(/\r?\n/).map((line) => normalizeChangedFilePath2(line)).filter(Boolean);
|
|
8079
8127
|
return [...new Set(files)];
|
|
8080
8128
|
}
|
|
8081
8129
|
function refreshChangedFilesManifest(projectRoot, taskId) {
|
|
8082
|
-
const manifestPath =
|
|
8083
|
-
|
|
8130
|
+
const manifestPath = resolve25(artifactDirForId(projectRoot, taskId), "changed-files.txt");
|
|
8131
|
+
mkdirSync11(dirname11(manifestPath), { recursive: true });
|
|
8084
8132
|
const changedFiles = changedFilesForTask(projectRoot, taskId, true);
|
|
8085
|
-
|
|
8133
|
+
writeFileSync11(manifestPath, `${changedFiles.join(`
|
|
8086
8134
|
`)}
|
|
8087
8135
|
`, "utf-8");
|
|
8088
8136
|
return manifestPath;
|
|
@@ -8195,7 +8243,7 @@ function repoHasPathChange(projectRoot, repoRoot, relativePath) {
|
|
|
8195
8243
|
return result.exitCode === 0 && result.stdout.trim().length > 0;
|
|
8196
8244
|
}
|
|
8197
8245
|
function stageExcludePathspecs(repoRoot) {
|
|
8198
|
-
const patterns =
|
|
8246
|
+
const patterns = existsSync22(resolve25(repoRoot, ".rig", "task-config.json")) ? [...TASK_RUNTIME_STAGE_EXCLUDES, ...GENERATED_STAGE_EXCLUDES] : [".rig/**", ...GENERATED_STAGE_EXCLUDES];
|
|
8199
8247
|
return patterns.map((pattern) => `:(glob,exclude)${pattern}`);
|
|
8200
8248
|
}
|
|
8201
8249
|
function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
@@ -8205,7 +8253,7 @@ function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
|
8205
8253
|
}
|
|
8206
8254
|
let current = repoRoot;
|
|
8207
8255
|
for (let index = 0;index < parts.length - 1; index += 1) {
|
|
8208
|
-
current =
|
|
8256
|
+
current = resolve25(current, parts[index]);
|
|
8209
8257
|
try {
|
|
8210
8258
|
if (lstatSync(current).isSymbolicLink()) {
|
|
8211
8259
|
return true;
|
|
@@ -8217,7 +8265,7 @@ function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
|
8217
8265
|
return false;
|
|
8218
8266
|
}
|
|
8219
8267
|
function printRepoStatus(projectRoot, label, repo, expectedBranch) {
|
|
8220
|
-
if (!
|
|
8268
|
+
if (!existsSync22(resolve25(repo, ".git"))) {
|
|
8221
8269
|
console.log(`${label}: unavailable (${repo})`);
|
|
8222
8270
|
return;
|
|
8223
8271
|
}
|
|
@@ -8253,7 +8301,7 @@ function resolveTaskBranchId(projectRoot, taskId) {
|
|
|
8253
8301
|
}
|
|
8254
8302
|
} catch {}
|
|
8255
8303
|
const artifactDir = artifactDirForId(projectRoot, taskId);
|
|
8256
|
-
if (
|
|
8304
|
+
if (existsSync22(artifactDir)) {
|
|
8257
8305
|
return taskId;
|
|
8258
8306
|
}
|
|
8259
8307
|
throw new Error(`Unknown task id: ${taskId}`);
|
|
@@ -8289,11 +8337,11 @@ function runCapture2(command, cwd, projectRoot = cwd) {
|
|
|
8289
8337
|
}
|
|
8290
8338
|
function runtimeGitEnv(projectRoot) {
|
|
8291
8339
|
const { ctx, runtimeRoot } = resolveRuntimeMetadata(projectRoot);
|
|
8292
|
-
const runtimeHome = runtimeRoot ?
|
|
8293
|
-
const runtimeTmp = runtimeRoot ?
|
|
8294
|
-
const runtimeCache = runtimeRoot ?
|
|
8295
|
-
const runtimeKnownHosts = runtimeHome ?
|
|
8296
|
-
const runtimeKey = runtimeHome ?
|
|
8340
|
+
const runtimeHome = runtimeRoot ? resolve25(runtimeRoot, "home") : "";
|
|
8341
|
+
const runtimeTmp = runtimeRoot ? resolve25(runtimeRoot, "tmp") : "";
|
|
8342
|
+
const runtimeCache = runtimeRoot ? resolve25(runtimeRoot, "cache") : "";
|
|
8343
|
+
const runtimeKnownHosts = runtimeHome ? resolve25(runtimeHome, ".ssh", "known_hosts") : "";
|
|
8344
|
+
const runtimeKey = runtimeHome ? resolve25(runtimeHome, ".ssh", "rig-agent-key") : "";
|
|
8297
8345
|
const env = {};
|
|
8298
8346
|
if (ctx?.workspaceDir) {
|
|
8299
8347
|
env.PROJECT_RIG_ROOT = projectRoot;
|
|
@@ -8306,14 +8354,14 @@ function runtimeGitEnv(projectRoot) {
|
|
|
8306
8354
|
if (runtimeRoot) {
|
|
8307
8355
|
env.RIG_RUNTIME_HOME = runtimeRoot;
|
|
8308
8356
|
}
|
|
8309
|
-
if (runtimeHome &&
|
|
8357
|
+
if (runtimeHome && existsSync22(runtimeHome)) {
|
|
8310
8358
|
env.HOME = runtimeHome;
|
|
8311
8359
|
env.OPENSSL_CONF = ensureRuntimeOpenSslConfig(runtimeHome);
|
|
8312
8360
|
}
|
|
8313
|
-
if (runtimeTmp &&
|
|
8361
|
+
if (runtimeTmp && existsSync22(runtimeTmp)) {
|
|
8314
8362
|
env.TMPDIR = runtimeTmp;
|
|
8315
8363
|
}
|
|
8316
|
-
if (runtimeCache &&
|
|
8364
|
+
if (runtimeCache && existsSync22(runtimeCache)) {
|
|
8317
8365
|
env.XDG_CACHE_HOME = runtimeCache;
|
|
8318
8366
|
}
|
|
8319
8367
|
const workspaceSecrets = loadDotEnvSecrets(ctx?.workspaceDir || projectRoot, process.env);
|
|
@@ -8357,14 +8405,14 @@ function runtimeGitEnv(projectRoot) {
|
|
|
8357
8405
|
env.GH_TOKEN = env.GH_TOKEN || gitHubToken;
|
|
8358
8406
|
applyGitHubCredentialHelperEnv(env);
|
|
8359
8407
|
}
|
|
8360
|
-
if (runtimeKnownHosts &&
|
|
8408
|
+
if (runtimeKnownHosts && existsSync22(runtimeKnownHosts)) {
|
|
8361
8409
|
const sshParts = [
|
|
8362
8410
|
"ssh",
|
|
8363
8411
|
`-o UserKnownHostsFile="${runtimeKnownHosts}"`,
|
|
8364
8412
|
"-o StrictHostKeyChecking=yes",
|
|
8365
8413
|
"-F /dev/null"
|
|
8366
8414
|
];
|
|
8367
|
-
if (runtimeKey &&
|
|
8415
|
+
if (runtimeKey && existsSync22(runtimeKey)) {
|
|
8368
8416
|
sshParts.splice(1, 0, `-i "${runtimeKey}"`, "-o IdentitiesOnly=yes");
|
|
8369
8417
|
}
|
|
8370
8418
|
env.GIT_SSH_COMMAND = sshParts.join(" ");
|
|
@@ -8385,12 +8433,12 @@ function loadPersistedRuntimeSecrets(runtimeRoot) {
|
|
|
8385
8433
|
if (!runtimeRoot) {
|
|
8386
8434
|
return {};
|
|
8387
8435
|
}
|
|
8388
|
-
const path =
|
|
8389
|
-
if (!
|
|
8436
|
+
const path = resolve25(runtimeRoot, "runtime-secrets.json");
|
|
8437
|
+
if (!existsSync22(path)) {
|
|
8390
8438
|
return {};
|
|
8391
8439
|
}
|
|
8392
8440
|
try {
|
|
8393
|
-
const parsed = JSON.parse(
|
|
8441
|
+
const parsed = JSON.parse(readFileSync12(path, "utf-8"));
|
|
8394
8442
|
const entries = Object.entries(parsed).filter((entry) => typeof entry[1] === "string");
|
|
8395
8443
|
return Object.fromEntries(entries);
|
|
8396
8444
|
} catch {
|
|
@@ -8398,13 +8446,13 @@ function loadPersistedRuntimeSecrets(runtimeRoot) {
|
|
|
8398
8446
|
}
|
|
8399
8447
|
}
|
|
8400
8448
|
function ensureRuntimeOpenSslConfig(runtimeHome) {
|
|
8401
|
-
const sslDir =
|
|
8402
|
-
const sslConfig =
|
|
8403
|
-
if (!
|
|
8404
|
-
|
|
8449
|
+
const sslDir = resolve25(runtimeHome, ".ssl");
|
|
8450
|
+
const sslConfig = resolve25(sslDir, "openssl.cnf");
|
|
8451
|
+
if (!existsSync22(sslDir)) {
|
|
8452
|
+
mkdirSync11(sslDir, { recursive: true });
|
|
8405
8453
|
}
|
|
8406
|
-
if (!
|
|
8407
|
-
|
|
8454
|
+
if (!existsSync22(sslConfig)) {
|
|
8455
|
+
writeFileSync11(sslConfig, `# Rig runtime OpenSSL config placeholder
|
|
8408
8456
|
`);
|
|
8409
8457
|
}
|
|
8410
8458
|
return sslConfig;
|
|
@@ -8422,11 +8470,11 @@ function resolveRuntimeMetadata(projectRoot) {
|
|
|
8422
8470
|
if (contextFile) {
|
|
8423
8471
|
return {
|
|
8424
8472
|
ctx,
|
|
8425
|
-
runtimeRoot: dirname11(
|
|
8473
|
+
runtimeRoot: dirname11(resolve25(contextFile))
|
|
8426
8474
|
};
|
|
8427
8475
|
}
|
|
8428
8476
|
const inferredContextFile = findRuntimeContextFile2(projectRoot);
|
|
8429
|
-
if (
|
|
8477
|
+
if (existsSync22(inferredContextFile)) {
|
|
8430
8478
|
try {
|
|
8431
8479
|
ctx = loadRuntimeContext(inferredContextFile);
|
|
8432
8480
|
} catch {}
|
|
@@ -8438,10 +8486,10 @@ function resolveRuntimeMetadata(projectRoot) {
|
|
|
8438
8486
|
return { ctx, runtimeRoot: "" };
|
|
8439
8487
|
}
|
|
8440
8488
|
function findRuntimeContextFile2(startPath) {
|
|
8441
|
-
let current =
|
|
8489
|
+
let current = resolve25(startPath);
|
|
8442
8490
|
while (true) {
|
|
8443
|
-
const candidate =
|
|
8444
|
-
if (
|
|
8491
|
+
const candidate = resolve25(current, "runtime-context.json");
|
|
8492
|
+
if (existsSync22(candidate)) {
|
|
8445
8493
|
return candidate;
|
|
8446
8494
|
}
|
|
8447
8495
|
const parent = dirname11(current);
|
|
@@ -8453,7 +8501,7 @@ function findRuntimeContextFile2(startPath) {
|
|
|
8453
8501
|
}
|
|
8454
8502
|
|
|
8455
8503
|
// packages/runtime/src/control-plane/native/profile-ops.ts
|
|
8456
|
-
import { existsSync as
|
|
8504
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "fs";
|
|
8457
8505
|
var DEFAULTS = {
|
|
8458
8506
|
model: parseEnvOrDefault(process.env.DEFAULT_AGENT_MODEL, ["claude", "gpt-codex", "pi"], "pi"),
|
|
8459
8507
|
runtime: parseEnvOrDefault(process.env.DEFAULT_AGENT_RUNTIME, ["claude-code", "codex-app-server", "pi"], "pi"),
|
|
@@ -8468,7 +8516,7 @@ function parseEnvOrDefault(value, allowed, fallback) {
|
|
|
8468
8516
|
return allowed.includes(value) ? value : fallback;
|
|
8469
8517
|
}
|
|
8470
8518
|
async function readProfileFile(path) {
|
|
8471
|
-
if (!
|
|
8519
|
+
if (!existsSync23(path)) {
|
|
8472
8520
|
return null;
|
|
8473
8521
|
}
|
|
8474
8522
|
try {
|
|
@@ -8521,14 +8569,14 @@ async function setProfile(projectRoot, options) {
|
|
|
8521
8569
|
plugin = model === "gpt-codex" ? "codex" : model === "pi" ? "pi" : "claude";
|
|
8522
8570
|
}
|
|
8523
8571
|
const paths = resolveHarnessPaths(projectRoot);
|
|
8524
|
-
|
|
8572
|
+
mkdirSync12(paths.stateDir, { recursive: true });
|
|
8525
8573
|
const next = {
|
|
8526
8574
|
model,
|
|
8527
8575
|
runtime,
|
|
8528
8576
|
agent_plugin: plugin,
|
|
8529
8577
|
updated_at: new Date().toISOString()
|
|
8530
8578
|
};
|
|
8531
|
-
|
|
8579
|
+
writeFileSync12(paths.agentProfilePath, `${JSON.stringify(next, null, 2)}
|
|
8532
8580
|
`, "utf-8");
|
|
8533
8581
|
await showProfile(projectRoot, false);
|
|
8534
8582
|
}
|
|
@@ -8564,13 +8612,13 @@ async function setReviewProfile(projectRoot, mode, provider) {
|
|
|
8564
8612
|
throw new Error(`Invalid provider: ${resolvedProvider}. Supported: greptile.`);
|
|
8565
8613
|
}
|
|
8566
8614
|
const paths = resolveHarnessPaths(projectRoot);
|
|
8567
|
-
|
|
8615
|
+
mkdirSync12(paths.stateDir, { recursive: true });
|
|
8568
8616
|
const next = {
|
|
8569
8617
|
mode,
|
|
8570
8618
|
provider: resolvedProvider,
|
|
8571
8619
|
updated_at: new Date().toISOString()
|
|
8572
8620
|
};
|
|
8573
|
-
|
|
8621
|
+
writeFileSync12(paths.reviewProfilePath, `${JSON.stringify(next, null, 2)}
|
|
8574
8622
|
`, "utf-8");
|
|
8575
8623
|
await showReviewProfile(projectRoot);
|
|
8576
8624
|
}
|
|
@@ -8608,44 +8656,44 @@ async function loadReviewProfile(path) {
|
|
|
8608
8656
|
}
|
|
8609
8657
|
|
|
8610
8658
|
// packages/runtime/src/control-plane/native/repo-ops.ts
|
|
8611
|
-
import { existsSync as
|
|
8612
|
-
import { basename as basename8, dirname as dirname13, resolve as
|
|
8659
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync14, readdirSync as readdirSync6, rmSync as rmSync7, writeFileSync as writeFileSync14 } from "fs";
|
|
8660
|
+
import { basename as basename8, dirname as dirname13, resolve as resolve29 } from "path";
|
|
8613
8661
|
// packages/runtime/src/control-plane/repos/mirror/bootstrap.ts
|
|
8614
|
-
import { existsSync as
|
|
8615
|
-
import { resolve as
|
|
8662
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync14, realpathSync as realpathSync2 } from "fs";
|
|
8663
|
+
import { resolve as resolve27 } from "path";
|
|
8616
8664
|
|
|
8617
8665
|
// packages/runtime/src/control-plane/authority-files.ts
|
|
8618
|
-
import { existsSync as
|
|
8619
|
-
import { dirname as dirname12, join as join4, relative, resolve as
|
|
8666
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync13, readFileSync as readFileSync13, writeFileSync as writeFileSync13, appendFileSync as appendFileSync2, copyFileSync as copyFileSync3, statSync as statSync5, readdirSync as readdirSync5, chmodSync as chmodSync3 } from "fs";
|
|
8667
|
+
import { dirname as dirname12, join as join4, relative, resolve as resolve26 } from "path";
|
|
8620
8668
|
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
8621
8669
|
function resolveAuthorityProjectStateDir(projectRoot) {
|
|
8622
8670
|
const explicit = process.env.RIG_STATE_DIR?.trim();
|
|
8623
8671
|
if (explicit) {
|
|
8624
|
-
return
|
|
8672
|
+
return resolve26(explicit);
|
|
8625
8673
|
}
|
|
8626
|
-
return
|
|
8674
|
+
return resolve26(resolve26(projectRoot), ".rig", "state");
|
|
8627
8675
|
}
|
|
8628
8676
|
function readJsonAtPath(path, fallback) {
|
|
8629
|
-
if (!
|
|
8677
|
+
if (!existsSync24(path)) {
|
|
8630
8678
|
return fallback;
|
|
8631
8679
|
}
|
|
8632
8680
|
try {
|
|
8633
|
-
return JSON.parse(
|
|
8681
|
+
return JSON.parse(readFileSync13(path, "utf-8"));
|
|
8634
8682
|
} catch {
|
|
8635
8683
|
return fallback;
|
|
8636
8684
|
}
|
|
8637
8685
|
}
|
|
8638
8686
|
function writeJsonAtPath(path, value) {
|
|
8639
|
-
|
|
8640
|
-
|
|
8687
|
+
mkdirSync13(dirname12(path), { recursive: true });
|
|
8688
|
+
writeFileSync13(path, `${JSON.stringify(value, null, 2)}
|
|
8641
8689
|
`, "utf8");
|
|
8642
8690
|
return path;
|
|
8643
8691
|
}
|
|
8644
8692
|
function readAuthorityProjectStateJson(projectRoot, relativePath, fallback) {
|
|
8645
|
-
return readJsonAtPath(
|
|
8693
|
+
return readJsonAtPath(resolve26(resolveAuthorityProjectStateDir(projectRoot), relativePath), fallback);
|
|
8646
8694
|
}
|
|
8647
8695
|
function writeAuthorityProjectStateJson(projectRoot, relativePath, value) {
|
|
8648
|
-
return writeJsonAtPath(
|
|
8696
|
+
return writeJsonAtPath(resolve26(resolveAuthorityProjectStateDir(projectRoot), relativePath), value);
|
|
8649
8697
|
}
|
|
8650
8698
|
|
|
8651
8699
|
// packages/runtime/src/control-plane/repos/mirror/state.ts
|
|
@@ -8705,7 +8753,7 @@ function sameExistingPath(left, right) {
|
|
|
8705
8753
|
try {
|
|
8706
8754
|
return realpathSync2(left) === realpathSync2(right);
|
|
8707
8755
|
} catch {
|
|
8708
|
-
return
|
|
8756
|
+
return resolve27(left) === resolve27(right);
|
|
8709
8757
|
}
|
|
8710
8758
|
}
|
|
8711
8759
|
function repoLooksUsable(repoRoot, projectRoot) {
|
|
@@ -8741,7 +8789,7 @@ function resolveMirrorRemoteUrl(layout) {
|
|
|
8741
8789
|
}
|
|
8742
8790
|
}
|
|
8743
8791
|
}
|
|
8744
|
-
if (
|
|
8792
|
+
if (existsSync25(resolve27(layout.checkoutRoot, ".git")) && checkoutLooksUsable(layout)) {
|
|
8745
8793
|
const checkoutOrigin = runGit(["git", "-C", layout.checkoutRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
8746
8794
|
if (checkoutOrigin.exitCode === 0) {
|
|
8747
8795
|
const currentOrigin = checkoutOrigin.stdout.trim();
|
|
@@ -8754,9 +8802,9 @@ function resolveMirrorRemoteUrl(layout) {
|
|
|
8754
8802
|
}
|
|
8755
8803
|
function ensureManagedRepoMirror(projectRoot, repoId) {
|
|
8756
8804
|
const layout = resolveManagedRepoLayout(projectRoot, repoId);
|
|
8757
|
-
|
|
8805
|
+
mkdirSync14(layout.metadataRoot, { recursive: true });
|
|
8758
8806
|
const remoteUrl = resolveMirrorRemoteUrl(layout);
|
|
8759
|
-
if (!
|
|
8807
|
+
if (!existsSync25(resolve27(layout.mirrorRoot, "HEAD"))) {
|
|
8760
8808
|
ensureGitSuccess(runGit(["git", "init", "--bare", layout.mirrorRoot], layout.projectRoot), ["git", "init", "--bare", layout.mirrorRoot]);
|
|
8761
8809
|
}
|
|
8762
8810
|
const getOrigin = runGit(["git", "--git-dir", layout.mirrorRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
@@ -8776,8 +8824,8 @@ function ensureManagedRepoMirror(projectRoot, repoId) {
|
|
|
8776
8824
|
return layout;
|
|
8777
8825
|
}
|
|
8778
8826
|
// packages/runtime/src/control-plane/repos/mirror/refresh.ts
|
|
8779
|
-
import { existsSync as
|
|
8780
|
-
import { resolve as
|
|
8827
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync15, realpathSync as realpathSync3, rmSync as rmSync6 } from "fs";
|
|
8828
|
+
import { resolve as resolve28 } from "path";
|
|
8781
8829
|
function nowIso3() {
|
|
8782
8830
|
return new Date().toISOString();
|
|
8783
8831
|
}
|
|
@@ -8804,7 +8852,7 @@ function sameExistingPath2(left, right) {
|
|
|
8804
8852
|
try {
|
|
8805
8853
|
return realpathSync3(left) === realpathSync3(right);
|
|
8806
8854
|
} catch {
|
|
8807
|
-
return
|
|
8855
|
+
return resolve28(left) === resolve28(right);
|
|
8808
8856
|
}
|
|
8809
8857
|
}
|
|
8810
8858
|
function ensureMirrorHead(layout) {
|
|
@@ -8850,12 +8898,12 @@ function checkoutLooksUsable2(layout) {
|
|
|
8850
8898
|
return probe.exitCode === 0 && sameExistingPath2(probe.stdout.trim(), layout.checkoutRoot);
|
|
8851
8899
|
}
|
|
8852
8900
|
function ensureCheckoutFromMirror(layout) {
|
|
8853
|
-
|
|
8854
|
-
const gitPath =
|
|
8855
|
-
if (
|
|
8856
|
-
|
|
8901
|
+
mkdirSync15(resolve28(layout.checkoutRoot, ".."), { recursive: true });
|
|
8902
|
+
const gitPath = resolve28(layout.checkoutRoot, ".git");
|
|
8903
|
+
if (existsSync26(layout.checkoutRoot) && (!existsSync26(gitPath) || !checkoutLooksUsable2(layout))) {
|
|
8904
|
+
rmSync6(layout.checkoutRoot, { recursive: true, force: true });
|
|
8857
8905
|
}
|
|
8858
|
-
if (!
|
|
8906
|
+
if (!existsSync26(gitPath)) {
|
|
8859
8907
|
ensureGitSuccess2(runGit2(["git", "clone", layout.mirrorRoot, layout.checkoutRoot], layout.projectRoot), ["git", "clone", layout.mirrorRoot, layout.checkoutRoot]);
|
|
8860
8908
|
}
|
|
8861
8909
|
const getOrigin = runGit2(["git", "-C", layout.checkoutRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
@@ -8956,7 +9004,7 @@ function repoDiscover(projectRoot, taskId) {
|
|
|
8956
9004
|
}
|
|
8957
9005
|
function repoBaseline(projectRoot, refresh = false) {
|
|
8958
9006
|
const paths = resolveRepoDiscoveryPaths(projectRoot);
|
|
8959
|
-
if (!refresh &&
|
|
9007
|
+
if (!refresh && existsSync27(paths.baseRepoPinsPath)) {
|
|
8960
9008
|
const baseline = readJsonFile(paths.baseRepoPinsPath, { recorded_at: nowIso(), repos: {} });
|
|
8961
9009
|
return baseline.repos || {};
|
|
8962
9010
|
}
|
|
@@ -8980,8 +9028,8 @@ function ensureMonorepoReady(projectRoot) {
|
|
|
8980
9028
|
}
|
|
8981
9029
|
function persistBaselinePins(projectRoot, repos) {
|
|
8982
9030
|
const paths = resolveRepoDiscoveryPaths(projectRoot);
|
|
8983
|
-
|
|
8984
|
-
|
|
9031
|
+
mkdirSync16(resolve29(paths.baseRepoPinsPath, ".."), { recursive: true });
|
|
9032
|
+
writeFileSync14(paths.baseRepoPinsPath, `${JSON.stringify({ recorded_at: nowIso(), repos }, null, 2)}
|
|
8985
9033
|
`, "utf-8");
|
|
8986
9034
|
return repos;
|
|
8987
9035
|
}
|
|
@@ -9060,28 +9108,28 @@ function readRepoDiscoveryTaskConfig(projectRoot) {
|
|
|
9060
9108
|
function resolveRepoDiscoveryPaths(projectRoot) {
|
|
9061
9109
|
const monorepoRoot = resolveMonorepoRepoLayout(projectRoot).checkoutRoot;
|
|
9062
9110
|
const explicitHostProjectRoot = (process.env.RIG_HOST_PROJECT_ROOT || "").trim();
|
|
9063
|
-
const normalizedProjectRoot =
|
|
9111
|
+
const normalizedProjectRoot = resolve29(projectRoot);
|
|
9064
9112
|
const hostProjectRoot = explicitHostProjectRoot && shouldUseHostProjectStateRoot(normalizedProjectRoot) ? explicitHostProjectRoot : normalizedProjectRoot;
|
|
9065
|
-
const stateDir =
|
|
9113
|
+
const stateDir = resolve29(hostProjectRoot, ".rig", "state");
|
|
9066
9114
|
return {
|
|
9067
9115
|
monorepoRoot,
|
|
9068
|
-
taskRepoCommitsPath:
|
|
9069
|
-
baseRepoPinsPath:
|
|
9116
|
+
taskRepoCommitsPath: resolve29(stateDir, "task-repo-commits.json"),
|
|
9117
|
+
baseRepoPinsPath: resolve29(stateDir, "base-repo-pins.json")
|
|
9070
9118
|
};
|
|
9071
9119
|
}
|
|
9072
9120
|
function shouldUseHostProjectStateRoot(projectRoot) {
|
|
9073
9121
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
9074
|
-
if (runtimeWorkspace &&
|
|
9122
|
+
if (runtimeWorkspace && resolve29(runtimeWorkspace) === projectRoot) {
|
|
9075
9123
|
return true;
|
|
9076
9124
|
}
|
|
9077
9125
|
return basename8(dirname13(projectRoot)) === ".worktrees";
|
|
9078
9126
|
}
|
|
9079
9127
|
function readPinFromArtifact(projectRoot, depTask, repoKey) {
|
|
9080
|
-
const snapshot =
|
|
9081
|
-
if (!
|
|
9128
|
+
const snapshot = resolve29(artifactDirForId(projectRoot, depTask), "git-state.txt");
|
|
9129
|
+
if (!existsSync27(snapshot)) {
|
|
9082
9130
|
return "";
|
|
9083
9131
|
}
|
|
9084
|
-
const content =
|
|
9132
|
+
const content = readFileSync14(snapshot, "utf-8");
|
|
9085
9133
|
const chunk = content.split(/\r?\n/);
|
|
9086
9134
|
let inSection = false;
|
|
9087
9135
|
for (const line of chunk) {
|
|
@@ -9103,12 +9151,12 @@ function repoPath(projectRoot, key) {
|
|
|
9103
9151
|
if (managed) {
|
|
9104
9152
|
return managed.checkoutRoot;
|
|
9105
9153
|
}
|
|
9106
|
-
return key.startsWith("/") ? key :
|
|
9154
|
+
return key.startsWith("/") ? key : resolve29(projectRoot, key);
|
|
9107
9155
|
}
|
|
9108
9156
|
function applyPins(projectRoot, pins) {
|
|
9109
9157
|
for (const [key, commit] of Object.entries(pins)) {
|
|
9110
9158
|
const path = repoPath(projectRoot, key);
|
|
9111
|
-
if (!
|
|
9159
|
+
if (!existsSync27(resolve29(path, ".git"))) {
|
|
9112
9160
|
throw new Error(`Repo for pin not available: ${key} (${path})`);
|
|
9113
9161
|
}
|
|
9114
9162
|
let hasCommit = runGitCapture(["git", "-C", path, "cat-file", "-e", `${commit}^{commit}`], projectRoot).exitCode === 0;
|
|
@@ -9137,7 +9185,7 @@ function verifyPins(projectRoot, pins) {
|
|
|
9137
9185
|
let ok = true;
|
|
9138
9186
|
for (const [key, expected] of Object.entries(pins)) {
|
|
9139
9187
|
const path = repoPath(projectRoot, key);
|
|
9140
|
-
if (!
|
|
9188
|
+
if (!existsSync27(resolve29(path, ".git"))) {
|
|
9141
9189
|
console.error(`ERROR: repo missing during pin verification: ${key}`);
|
|
9142
9190
|
ok = false;
|
|
9143
9191
|
continue;
|
|
@@ -9162,23 +9210,23 @@ function resolveRuntimeGitEnv() {
|
|
|
9162
9210
|
GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND
|
|
9163
9211
|
};
|
|
9164
9212
|
}
|
|
9165
|
-
const runtimeRoot = process.env.RIG_RUNTIME_HOME?.trim() || (process.env.RIG_RUNTIME_CONTEXT_FILE?.trim() ?
|
|
9166
|
-
const runtimeHome = runtimeRoot ?
|
|
9213
|
+
const runtimeRoot = process.env.RIG_RUNTIME_HOME?.trim() || (process.env.RIG_RUNTIME_CONTEXT_FILE?.trim() ? resolve29(process.env.RIG_RUNTIME_CONTEXT_FILE, "..") : inferRuntimeRootFromWorkspace(process.cwd()));
|
|
9214
|
+
const runtimeHome = runtimeRoot ? resolve29(runtimeRoot, "home") : process.env.HOME?.trim() || "";
|
|
9167
9215
|
if (!runtimeHome) {
|
|
9168
9216
|
return;
|
|
9169
9217
|
}
|
|
9170
|
-
const knownHostsPath =
|
|
9171
|
-
if (!
|
|
9218
|
+
const knownHostsPath = resolve29(runtimeHome, ".ssh", "known_hosts");
|
|
9219
|
+
if (!existsSync27(knownHostsPath)) {
|
|
9172
9220
|
return { HOME: runtimeHome };
|
|
9173
9221
|
}
|
|
9174
|
-
const agentSshKey =
|
|
9222
|
+
const agentSshKey = resolve29(runtimeHome, ".ssh", "rig-agent-key");
|
|
9175
9223
|
const sshParts = [
|
|
9176
9224
|
"ssh",
|
|
9177
9225
|
`-o UserKnownHostsFile="${knownHostsPath}"`,
|
|
9178
9226
|
"-o StrictHostKeyChecking=yes",
|
|
9179
9227
|
"-F /dev/null"
|
|
9180
9228
|
];
|
|
9181
|
-
if (
|
|
9229
|
+
if (existsSync27(agentSshKey)) {
|
|
9182
9230
|
sshParts.splice(1, 0, `-i "${agentSshKey}"`, "-o IdentitiesOnly=yes");
|
|
9183
9231
|
}
|
|
9184
9232
|
return {
|
|
@@ -9188,24 +9236,24 @@ function resolveRuntimeGitEnv() {
|
|
|
9188
9236
|
}
|
|
9189
9237
|
function inferRuntimeRootFromWorkspace(cwd) {
|
|
9190
9238
|
const contextPath = findRuntimeContextFile3(cwd);
|
|
9191
|
-
if (!contextPath || !
|
|
9239
|
+
if (!contextPath || !existsSync27(contextPath)) {
|
|
9192
9240
|
return "";
|
|
9193
9241
|
}
|
|
9194
9242
|
try {
|
|
9195
9243
|
loadRuntimeContext(contextPath);
|
|
9196
|
-
return
|
|
9244
|
+
return resolve29(contextPath, "..");
|
|
9197
9245
|
} catch {
|
|
9198
9246
|
return "";
|
|
9199
9247
|
}
|
|
9200
9248
|
}
|
|
9201
9249
|
function findRuntimeContextFile3(startPath) {
|
|
9202
|
-
let current =
|
|
9250
|
+
let current = resolve29(startPath);
|
|
9203
9251
|
while (true) {
|
|
9204
|
-
const candidate =
|
|
9205
|
-
if (
|
|
9252
|
+
const candidate = resolve29(current, "runtime-context.json");
|
|
9253
|
+
if (existsSync27(candidate)) {
|
|
9206
9254
|
return candidate;
|
|
9207
9255
|
}
|
|
9208
|
-
const parent =
|
|
9256
|
+
const parent = resolve29(current, "..");
|
|
9209
9257
|
if (parent === current) {
|
|
9210
9258
|
return "";
|
|
9211
9259
|
}
|
|
@@ -9214,12 +9262,12 @@ function findRuntimeContextFile3(startPath) {
|
|
|
9214
9262
|
}
|
|
9215
9263
|
|
|
9216
9264
|
// packages/runtime/src/control-plane/memory-sync/cli.ts
|
|
9217
|
-
import { existsSync as
|
|
9265
|
+
import { existsSync as existsSync28 } from "fs";
|
|
9218
9266
|
import { randomUUID } from "crypto";
|
|
9219
9267
|
|
|
9220
9268
|
// packages/runtime/src/control-plane/memory-sync/db.ts
|
|
9221
9269
|
import { Database } from "bun:sqlite";
|
|
9222
|
-
import { mkdirSync as
|
|
9270
|
+
import { mkdirSync as mkdirSync17 } from "fs";
|
|
9223
9271
|
import { dirname as dirname14 } from "path";
|
|
9224
9272
|
|
|
9225
9273
|
// packages/runtime/src/control-plane/memory-sync/types.ts
|
|
@@ -9816,7 +9864,7 @@ async function validateEventTargets(executor, event) {
|
|
|
9816
9864
|
}
|
|
9817
9865
|
}
|
|
9818
9866
|
async function openMemoryDb(dbPath) {
|
|
9819
|
-
|
|
9867
|
+
mkdirSync17(dirname14(dbPath), { recursive: true });
|
|
9820
9868
|
const sqlite = new Database(dbPath, { create: true, strict: true });
|
|
9821
9869
|
const client = createMemoryDbClient(sqlite);
|
|
9822
9870
|
const db = {
|
|
@@ -10235,7 +10283,7 @@ function formatMemoryQueryResults(results) {
|
|
|
10235
10283
|
}
|
|
10236
10284
|
|
|
10237
10285
|
// packages/runtime/src/control-plane/memory-sync/read.ts
|
|
10238
|
-
import { mkdtempSync, rmSync as
|
|
10286
|
+
import { mkdtempSync, rmSync as rmSync8, writeFileSync as writeFileSync15 } from "fs";
|
|
10239
10287
|
import { tmpdir as tmpdir5 } from "os";
|
|
10240
10288
|
import { join as join5 } from "path";
|
|
10241
10289
|
var CANONICAL_MEMORY_DB_PATH = "rig/memory/project-memory.db";
|
|
@@ -10244,7 +10292,7 @@ var DEFAULT_READ_DEPS2 = {
|
|
|
10244
10292
|
readBlobBytesAtRef: nativeReadBlobBytesAtRef,
|
|
10245
10293
|
openMemoryDb,
|
|
10246
10294
|
makeTempDir: () => mkdtempSync(join5(tmpdir5(), "memory-sync-read-")),
|
|
10247
|
-
removeDir: (path) =>
|
|
10295
|
+
removeDir: (path) => rmSync8(path, { recursive: true, force: true })
|
|
10248
10296
|
};
|
|
10249
10297
|
function isMissingCanonicalMemoryBlobError(error) {
|
|
10250
10298
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -10264,7 +10312,7 @@ async function readCanonicalMemoryDb(projectRoot, deps = {}) {
|
|
|
10264
10312
|
try {
|
|
10265
10313
|
try {
|
|
10266
10314
|
const bytes = readDeps.readBlobBytesAtRef(repoPath2, baseOid, CANONICAL_MEMORY_DB_PATH);
|
|
10267
|
-
|
|
10315
|
+
writeFileSync15(dbPath, bytes);
|
|
10268
10316
|
} catch (error) {
|
|
10269
10317
|
if (!isMissingCanonicalMemoryBlobError(error)) {
|
|
10270
10318
|
throw error;
|
|
@@ -10422,7 +10470,7 @@ function requireRuntimeMemoryContext(runtimeContext) {
|
|
|
10422
10470
|
}
|
|
10423
10471
|
async function ensureRuntimeMemoryUsable(runtimeContext) {
|
|
10424
10472
|
const memory = requireRuntimeMemoryContext(runtimeContext);
|
|
10425
|
-
if (!
|
|
10473
|
+
if (!existsSync28(memory.hydratedPath)) {
|
|
10426
10474
|
throw new Error(`Shared memory database is missing: ${memory.hydratedPath}`);
|
|
10427
10475
|
}
|
|
10428
10476
|
const db = await openMemoryDb(memory.hydratedPath);
|
|
@@ -10685,7 +10733,7 @@ async function executeMemoryCommand(options, deps = {}) {
|
|
|
10685
10733
|
}
|
|
10686
10734
|
|
|
10687
10735
|
// packages/runtime/src/control-plane/native/harness-cli.ts
|
|
10688
|
-
async function executeHarnessCommand(projectRoot,
|
|
10736
|
+
async function executeHarnessCommand(projectRoot, args, eventBus, pluginHostCtx) {
|
|
10689
10737
|
const [command = "help", ...rest] = args;
|
|
10690
10738
|
switch (command) {
|
|
10691
10739
|
case "memory": {
|
|
@@ -10723,8 +10771,8 @@ async function executeHarnessCommand(projectRoot, plugins, args, eventBus, plugi
|
|
|
10723
10771
|
}
|
|
10724
10772
|
case "completion-verification":
|
|
10725
10773
|
case "completition-verification": {
|
|
10726
|
-
const hookPath =
|
|
10727
|
-
if (!
|
|
10774
|
+
const hookPath = resolve30(projectRoot, ".rig/bin/hooks/completion-verification");
|
|
10775
|
+
if (!existsSync29(hookPath)) {
|
|
10728
10776
|
throw new Error(`completion-verification hook binary not found: ${hookPath}`);
|
|
10729
10777
|
}
|
|
10730
10778
|
const proc = Bun.spawn([hookPath], {
|
|
@@ -10742,7 +10790,7 @@ async function executeHarnessCommand(projectRoot, plugins, args, eventBus, plugi
|
|
|
10742
10790
|
}
|
|
10743
10791
|
case "verify": {
|
|
10744
10792
|
const task = rest[0];
|
|
10745
|
-
const ok = await taskVerify(projectRoot,
|
|
10793
|
+
const ok = await taskVerify(projectRoot, task);
|
|
10746
10794
|
if (!ok) {
|
|
10747
10795
|
throw new Error("Verification rejected.");
|
|
10748
10796
|
}
|
|
@@ -11026,10 +11074,10 @@ function printHelp() {
|
|
|
11026
11074
|
}
|
|
11027
11075
|
|
|
11028
11076
|
// packages/runtime/src/control-plane/native/root-resolver.ts
|
|
11029
|
-
import { existsSync as
|
|
11030
|
-
import { dirname as dirname15, parse, resolve as
|
|
11077
|
+
import { existsSync as existsSync30, readFileSync as readFileSync15 } from "fs";
|
|
11078
|
+
import { dirname as dirname15, parse, resolve as resolve31 } from "path";
|
|
11031
11079
|
function hasProjectMarker(candidate) {
|
|
11032
|
-
return
|
|
11080
|
+
return existsSync30(resolve31(candidate, RIG_DEFINITION_DIRNAME)) || existsSync30(resolve31(candidate, RIG_STATE_DIRNAME));
|
|
11033
11081
|
}
|
|
11034
11082
|
function resolveProjectRoot(options) {
|
|
11035
11083
|
const cwd = options?.cwd || process.cwd();
|
|
@@ -11046,7 +11094,7 @@ function resolveProjectRoot(options) {
|
|
|
11046
11094
|
if (configRoot && hasProjectMarker(configRoot)) {
|
|
11047
11095
|
return configRoot;
|
|
11048
11096
|
}
|
|
11049
|
-
let fileDir =
|
|
11097
|
+
let fileDir = resolve31(fallbackFromDir);
|
|
11050
11098
|
for (let i = 0;i < 5; i += 1) {
|
|
11051
11099
|
if (hasProjectMarker(fileDir)) {
|
|
11052
11100
|
return fileDir;
|
|
@@ -11056,7 +11104,7 @@ function resolveProjectRoot(options) {
|
|
|
11056
11104
|
return cwd;
|
|
11057
11105
|
}
|
|
11058
11106
|
function walkUpForRoot(start) {
|
|
11059
|
-
let searchDir =
|
|
11107
|
+
let searchDir = resolve31(start);
|
|
11060
11108
|
const root = parse(searchDir).root || "/";
|
|
11061
11109
|
while (searchDir !== root) {
|
|
11062
11110
|
if (hasProjectMarker(searchDir)) {
|
|
@@ -11070,12 +11118,12 @@ function walkUpForRoot(start) {
|
|
|
11070
11118
|
return "";
|
|
11071
11119
|
}
|
|
11072
11120
|
function readConfiguredRoot() {
|
|
11073
|
-
const configPath =
|
|
11074
|
-
if (!
|
|
11121
|
+
const configPath = resolve31(process.env.HOME || "~", ".config", "project-rig", "root");
|
|
11122
|
+
if (!existsSync30(configPath)) {
|
|
11075
11123
|
return "";
|
|
11076
11124
|
}
|
|
11077
11125
|
try {
|
|
11078
|
-
const value =
|
|
11126
|
+
const value = readFileSync15(configPath, "utf-8").split(/\r?\n/)[0]?.trim() || "";
|
|
11079
11127
|
return value;
|
|
11080
11128
|
} catch {
|
|
11081
11129
|
return "";
|
|
@@ -11085,7 +11133,7 @@ function readConfiguredRoot() {
|
|
|
11085
11133
|
// packages/runtime/src/control-plane/runtime/events.ts
|
|
11086
11134
|
import { appendFile, mkdir } from "fs/promises";
|
|
11087
11135
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
11088
|
-
import { dirname as dirname16, resolve as
|
|
11136
|
+
import { dirname as dirname16, resolve as resolve32 } from "path";
|
|
11089
11137
|
async function appendEvent(eventsFile, event) {
|
|
11090
11138
|
await mkdir(dirname16(eventsFile), { recursive: true });
|
|
11091
11139
|
await appendFile(eventsFile, `${JSON.stringify(event)}
|
|
@@ -11149,7 +11197,7 @@ class GeneralCliEventBus {
|
|
|
11149
11197
|
runtimeBuses = new Map;
|
|
11150
11198
|
constructor(options) {
|
|
11151
11199
|
this.runId = options.runId || randomUUID2();
|
|
11152
|
-
this.eventsFile = options.eventsFile ??
|
|
11200
|
+
this.eventsFile = options.eventsFile ?? resolve32(options.projectRoot, ".rig", "logs", "control-plane.events.jsonl");
|
|
11153
11201
|
}
|
|
11154
11202
|
getRunId() {
|
|
11155
11203
|
return this.runId;
|
|
@@ -11184,919 +11232,25 @@ class GeneralCliEventBus {
|
|
|
11184
11232
|
}
|
|
11185
11233
|
}
|
|
11186
11234
|
|
|
11187
|
-
// packages/runtime/src/control-plane/runtime/plugins.ts
|
|
11188
|
-
import { existsSync as existsSync31, readdirSync as readdirSync6 } from "fs";
|
|
11189
|
-
import { resolve as resolve33, basename as basename9 } from "path";
|
|
11190
|
-
|
|
11191
|
-
// packages/runtime/src/control-plane/runtime/guard.ts
|
|
11192
|
-
import { optimizeNextInvocation } from "bun:jsc";
|
|
11193
|
-
import { existsSync as existsSync30, readFileSync as readFileSync15, statSync as statSync6 } from "fs";
|
|
11194
|
-
import { resolve as resolve32 } from "path";
|
|
11195
|
-
|
|
11196
|
-
// packages/runtime/src/control-plane/runtime/guard-types.ts
|
|
11197
|
-
var POLICY_VERSION = 1;
|
|
11198
|
-
|
|
11199
|
-
// packages/runtime/src/control-plane/runtime/guard.ts
|
|
11200
|
-
var DEFAULT_SCOPE = {
|
|
11201
|
-
fail_closed: true,
|
|
11202
|
-
harness_paths_exempt: true,
|
|
11203
|
-
runtime_paths_exempt: true
|
|
11204
|
-
};
|
|
11205
|
-
var DEFAULT_SANDBOX = {
|
|
11206
|
-
mode: "enforce",
|
|
11207
|
-
network: true,
|
|
11208
|
-
read_deny: [],
|
|
11209
|
-
write_allow_from_runtime: true
|
|
11210
|
-
};
|
|
11211
|
-
var DEFAULT_ISOLATION = {
|
|
11212
|
-
default_mode: "worktree",
|
|
11213
|
-
repo_symlink_fallback: false,
|
|
11214
|
-
strict_provisioning: true,
|
|
11215
|
-
fail_closed_on_provision_error: true
|
|
11216
|
-
};
|
|
11217
|
-
var DEFAULT_COMPLETION = {
|
|
11218
|
-
derive_checks_from_scope: true,
|
|
11219
|
-
checks: [],
|
|
11220
|
-
typescript_config_probe: ["tsconfig.json"],
|
|
11221
|
-
eslint_config_probe: [".eslintrc.js", ".eslintrc.json", "eslint.config.js"]
|
|
11222
|
-
};
|
|
11223
|
-
var DEFAULT_RUNTIME_IMAGE = {
|
|
11224
|
-
deps: {
|
|
11225
|
-
monorepo_install: false,
|
|
11226
|
-
hp_next_install: false
|
|
11227
|
-
},
|
|
11228
|
-
plugins_require_binaries: true
|
|
11229
|
-
};
|
|
11230
|
-
var DEFAULT_RUNTIME_SNAPSHOT = {
|
|
11231
|
-
enabled: true
|
|
11232
|
-
};
|
|
11233
|
-
function defaultPolicy() {
|
|
11234
|
-
return {
|
|
11235
|
-
version: POLICY_VERSION,
|
|
11236
|
-
mode: "enforce",
|
|
11237
|
-
scope: { ...DEFAULT_SCOPE },
|
|
11238
|
-
rules: [],
|
|
11239
|
-
sandbox: { ...DEFAULT_SANDBOX },
|
|
11240
|
-
isolation: { ...DEFAULT_ISOLATION },
|
|
11241
|
-
completion: { ...DEFAULT_COMPLETION },
|
|
11242
|
-
runtime_image: {
|
|
11243
|
-
deps: { ...DEFAULT_RUNTIME_IMAGE.deps },
|
|
11244
|
-
plugins_require_binaries: DEFAULT_RUNTIME_IMAGE.plugins_require_binaries
|
|
11245
|
-
},
|
|
11246
|
-
runtime_snapshot: { ...DEFAULT_RUNTIME_SNAPSHOT }
|
|
11247
|
-
};
|
|
11248
|
-
}
|
|
11249
|
-
var policyCache = null;
|
|
11250
|
-
var policyCachePath = null;
|
|
11251
|
-
var seededPolicyConfig = null;
|
|
11252
|
-
var compiledRegexCache = new Map;
|
|
11253
|
-
function loadPolicy(projectRoot) {
|
|
11254
|
-
if (seededPolicyConfig) {
|
|
11255
|
-
return seededPolicyConfig;
|
|
11256
|
-
}
|
|
11257
|
-
const configPath = resolve32(projectRoot, "rig/policy/policy.json");
|
|
11258
|
-
if (!existsSync30(configPath)) {
|
|
11259
|
-
return defaultPolicy();
|
|
11260
|
-
}
|
|
11261
|
-
let mtimeMs;
|
|
11262
|
-
try {
|
|
11263
|
-
mtimeMs = statSync6(configPath).mtimeMs;
|
|
11264
|
-
} catch {
|
|
11265
|
-
return defaultPolicy();
|
|
11266
|
-
}
|
|
11267
|
-
if (policyCache && policyCachePath === configPath && policyCache.mtimeMs === mtimeMs) {
|
|
11268
|
-
return policyCache.config;
|
|
11269
|
-
}
|
|
11270
|
-
let parsed;
|
|
11271
|
-
try {
|
|
11272
|
-
parsed = JSON.parse(readFileSync15(configPath, "utf-8"));
|
|
11273
|
-
} catch {
|
|
11274
|
-
return defaultPolicy();
|
|
11275
|
-
}
|
|
11276
|
-
const config = mergeWithDefaults(parsed);
|
|
11277
|
-
policyCache = { mtimeMs, config };
|
|
11278
|
-
policyCachePath = configPath;
|
|
11279
|
-
return config;
|
|
11280
|
-
}
|
|
11281
|
-
function mergeWithDefaults(parsed) {
|
|
11282
|
-
const base = defaultPolicy();
|
|
11283
|
-
if (typeof parsed.mode === "string" && isValidMode(parsed.mode)) {
|
|
11284
|
-
base.mode = parsed.mode;
|
|
11285
|
-
}
|
|
11286
|
-
if (parsed.scope && typeof parsed.scope === "object" && !Array.isArray(parsed.scope)) {
|
|
11287
|
-
const s = parsed.scope;
|
|
11288
|
-
if (typeof s.fail_closed === "boolean")
|
|
11289
|
-
base.scope.fail_closed = s.fail_closed;
|
|
11290
|
-
if (typeof s.harness_paths_exempt === "boolean")
|
|
11291
|
-
base.scope.harness_paths_exempt = s.harness_paths_exempt;
|
|
11292
|
-
if (typeof s.runtime_paths_exempt === "boolean")
|
|
11293
|
-
base.scope.runtime_paths_exempt = s.runtime_paths_exempt;
|
|
11294
|
-
}
|
|
11295
|
-
if (Array.isArray(parsed.rules)) {
|
|
11296
|
-
base.rules = precompilePolicyRuleRegexes(parsed.rules.filter(isValidRule));
|
|
11297
|
-
}
|
|
11298
|
-
if (Array.isArray(parsed.deny) && base.rules.length === 0) {
|
|
11299
|
-
base.rules = precompilePolicyRuleRegexes(migrateLegacyDeny(parsed.deny));
|
|
11300
|
-
}
|
|
11301
|
-
if (parsed.sandbox && typeof parsed.sandbox === "object" && !Array.isArray(parsed.sandbox)) {
|
|
11302
|
-
const sb = parsed.sandbox;
|
|
11303
|
-
if (typeof sb.mode === "string" && isValidMode(sb.mode))
|
|
11304
|
-
base.sandbox.mode = sb.mode;
|
|
11305
|
-
if (typeof sb.network === "boolean")
|
|
11306
|
-
base.sandbox.network = sb.network;
|
|
11307
|
-
if (Array.isArray(sb.read_deny))
|
|
11308
|
-
base.sandbox.read_deny = sb.read_deny.filter((v) => typeof v === "string");
|
|
11309
|
-
if (typeof sb.write_allow_from_runtime === "boolean")
|
|
11310
|
-
base.sandbox.write_allow_from_runtime = sb.write_allow_from_runtime;
|
|
11311
|
-
}
|
|
11312
|
-
if (parsed.isolation && typeof parsed.isolation === "object" && !Array.isArray(parsed.isolation)) {
|
|
11313
|
-
const iso = parsed.isolation;
|
|
11314
|
-
if (iso.default_mode === "worktree")
|
|
11315
|
-
base.isolation.default_mode = iso.default_mode;
|
|
11316
|
-
if (typeof iso.repo_symlink_fallback === "boolean")
|
|
11317
|
-
base.isolation.repo_symlink_fallback = iso.repo_symlink_fallback;
|
|
11318
|
-
if (typeof iso.strict_provisioning === "boolean")
|
|
11319
|
-
base.isolation.strict_provisioning = iso.strict_provisioning;
|
|
11320
|
-
if (typeof iso.fail_closed_on_provision_error === "boolean")
|
|
11321
|
-
base.isolation.fail_closed_on_provision_error = iso.fail_closed_on_provision_error;
|
|
11322
|
-
}
|
|
11323
|
-
if (parsed.completion && typeof parsed.completion === "object" && !Array.isArray(parsed.completion)) {
|
|
11324
|
-
const comp = parsed.completion;
|
|
11325
|
-
if (typeof comp.derive_checks_from_scope === "boolean")
|
|
11326
|
-
base.completion.derive_checks_from_scope = comp.derive_checks_from_scope;
|
|
11327
|
-
if (Array.isArray(comp.checks))
|
|
11328
|
-
base.completion.checks = comp.checks.filter((v) => typeof v === "string");
|
|
11329
|
-
if (Array.isArray(comp.typescript_config_probe))
|
|
11330
|
-
base.completion.typescript_config_probe = comp.typescript_config_probe.filter((v) => typeof v === "string");
|
|
11331
|
-
if (Array.isArray(comp.eslint_config_probe))
|
|
11332
|
-
base.completion.eslint_config_probe = comp.eslint_config_probe.filter((v) => typeof v === "string");
|
|
11333
|
-
}
|
|
11334
|
-
if (parsed.runtime_image && typeof parsed.runtime_image === "object" && !Array.isArray(parsed.runtime_image)) {
|
|
11335
|
-
const runtimeImage = parsed.runtime_image;
|
|
11336
|
-
if (runtimeImage.deps && typeof runtimeImage.deps === "object" && !Array.isArray(runtimeImage.deps)) {
|
|
11337
|
-
const deps = runtimeImage.deps;
|
|
11338
|
-
if (typeof deps.monorepo_install === "boolean") {
|
|
11339
|
-
base.runtime_image.deps.monorepo_install = deps.monorepo_install;
|
|
11340
|
-
}
|
|
11341
|
-
if (typeof deps.hp_next_install === "boolean") {
|
|
11342
|
-
base.runtime_image.deps.hp_next_install = deps.hp_next_install;
|
|
11343
|
-
}
|
|
11344
|
-
}
|
|
11345
|
-
if (typeof runtimeImage.plugins_require_binaries === "boolean") {
|
|
11346
|
-
base.runtime_image.plugins_require_binaries = runtimeImage.plugins_require_binaries;
|
|
11347
|
-
}
|
|
11348
|
-
}
|
|
11349
|
-
if (parsed.runtime_snapshot && typeof parsed.runtime_snapshot === "object" && !Array.isArray(parsed.runtime_snapshot)) {
|
|
11350
|
-
const runtimeSnapshot = parsed.runtime_snapshot;
|
|
11351
|
-
if (typeof runtimeSnapshot.enabled === "boolean") {
|
|
11352
|
-
base.runtime_snapshot.enabled = runtimeSnapshot.enabled;
|
|
11353
|
-
}
|
|
11354
|
-
}
|
|
11355
|
-
return base;
|
|
11356
|
-
}
|
|
11357
|
-
function isValidMode(value) {
|
|
11358
|
-
return value === "off" || value === "observe" || value === "enforce";
|
|
11359
|
-
}
|
|
11360
|
-
function isValidRule(value) {
|
|
11361
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
11362
|
-
return false;
|
|
11363
|
-
const r = value;
|
|
11364
|
-
return typeof r.id === "string" && typeof r.category === "string" && r.match != null && typeof r.match === "object";
|
|
11365
|
-
}
|
|
11366
|
-
function migrateLegacyDeny(deny) {
|
|
11367
|
-
const rules = [];
|
|
11368
|
-
for (const entry of deny) {
|
|
11369
|
-
if (typeof entry.id !== "string")
|
|
11370
|
-
continue;
|
|
11371
|
-
const match = {};
|
|
11372
|
-
if (typeof entry.pattern === "string")
|
|
11373
|
-
match.pattern = entry.pattern;
|
|
11374
|
-
if (typeof entry.regex === "string")
|
|
11375
|
-
match.regex = entry.regex;
|
|
11376
|
-
if (!match.pattern && !match.regex)
|
|
11377
|
-
continue;
|
|
11378
|
-
rules.push({
|
|
11379
|
-
id: entry.id,
|
|
11380
|
-
category: "command",
|
|
11381
|
-
match,
|
|
11382
|
-
action: "block",
|
|
11383
|
-
...typeof entry.description === "string" ? { description: entry.description } : {}
|
|
11384
|
-
});
|
|
11385
|
-
}
|
|
11386
|
-
return rules;
|
|
11387
|
-
}
|
|
11388
|
-
function precompilePolicyRuleRegexes(rules) {
|
|
11389
|
-
return rules.map((rule) => {
|
|
11390
|
-
const compiledRegex = rule.match.regex ? compileSafeRegex(rule.match.regex, `rules.${rule.id}.match.regex`, true) : undefined;
|
|
11391
|
-
const compiledUnlessRegex = rule.unless?.regex ? compileSafeRegex(rule.unless.regex, `rules.${rule.id}.unless.regex`, true) : undefined;
|
|
11392
|
-
return {
|
|
11393
|
-
...rule,
|
|
11394
|
-
...compiledRegex ? { compiledRegex } : {},
|
|
11395
|
-
...compiledUnlessRegex ? { compiledUnlessRegex } : {}
|
|
11396
|
-
};
|
|
11397
|
-
});
|
|
11398
|
-
}
|
|
11399
|
-
function getRegexUnsafeReason(pattern) {
|
|
11400
|
-
if (pattern.length > 512) {
|
|
11401
|
-
return "pattern exceeds max safe length (512 chars)";
|
|
11402
|
-
}
|
|
11403
|
-
if (/\\[1-9]/.test(pattern)) {
|
|
11404
|
-
return "pattern uses backreferences";
|
|
11405
|
-
}
|
|
11406
|
-
if (/\((?:[^()\\]|\\.)*[+*](?:[^()\\]|\\.)*\)\s*[*+{]/.test(pattern)) {
|
|
11407
|
-
return "pattern contains nested quantifiers";
|
|
11408
|
-
}
|
|
11409
|
-
if (/\((?:[^()\\]|\\.)*\.\\?[+*](?:[^()\\]|\\.)*\)\s*[*+{]/.test(pattern)) {
|
|
11410
|
-
return "pattern contains nested broad quantifiers";
|
|
11411
|
-
}
|
|
11412
|
-
return null;
|
|
11413
|
-
}
|
|
11414
|
-
function compileSafeRegex(pattern, sourceLabel, logOnFailure) {
|
|
11415
|
-
const cached = compiledRegexCache.get(pattern);
|
|
11416
|
-
if (cached !== undefined) {
|
|
11417
|
-
return cached ?? undefined;
|
|
11418
|
-
}
|
|
11419
|
-
const unsafeReason = getRegexUnsafeReason(pattern);
|
|
11420
|
-
if (unsafeReason) {
|
|
11421
|
-
if (logOnFailure) {
|
|
11422
|
-
console.warn(`[policy] Skipping unsafe regex in ${sourceLabel}: ${unsafeReason}`);
|
|
11423
|
-
}
|
|
11424
|
-
compiledRegexCache.set(pattern, null);
|
|
11425
|
-
return;
|
|
11426
|
-
}
|
|
11427
|
-
try {
|
|
11428
|
-
const compiled = new RegExp(pattern);
|
|
11429
|
-
compiledRegexCache.set(pattern, compiled);
|
|
11430
|
-
return compiled;
|
|
11431
|
-
} catch (error) {
|
|
11432
|
-
if (logOnFailure) {
|
|
11433
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
11434
|
-
console.warn(`[policy] Skipping invalid regex in ${sourceLabel}: ${message}`);
|
|
11435
|
-
}
|
|
11436
|
-
compiledRegexCache.set(pattern, null);
|
|
11437
|
-
return;
|
|
11438
|
-
}
|
|
11439
|
-
}
|
|
11440
|
-
function matchRule(rule, input) {
|
|
11441
|
-
const { match } = rule;
|
|
11442
|
-
if (match.pattern && input.includes(match.pattern)) {
|
|
11443
|
-
return true;
|
|
11444
|
-
}
|
|
11445
|
-
if (match.regex) {
|
|
11446
|
-
const compiled = rule.compiledRegex || compileSafeRegex(match.regex, `rules.${rule.id}.match.regex`, false);
|
|
11447
|
-
if (!compiled) {
|
|
11448
|
-
return false;
|
|
11449
|
-
}
|
|
11450
|
-
try {
|
|
11451
|
-
return compiled.test(input);
|
|
11452
|
-
} catch {
|
|
11453
|
-
return false;
|
|
11454
|
-
}
|
|
11455
|
-
}
|
|
11456
|
-
return false;
|
|
11457
|
-
}
|
|
11458
|
-
function matchRuleUnless(rule, command, taskId) {
|
|
11459
|
-
if (!rule.unless)
|
|
11460
|
-
return false;
|
|
11461
|
-
if (rule.unless.regex) {
|
|
11462
|
-
const compiled = rule.compiledUnlessRegex || compileSafeRegex(rule.unless.regex, `rules.${rule.id}.unless.regex`, false);
|
|
11463
|
-
if (!compiled) {
|
|
11464
|
-
return false;
|
|
11465
|
-
}
|
|
11466
|
-
try {
|
|
11467
|
-
if (compiled.test(command))
|
|
11468
|
-
return true;
|
|
11469
|
-
} catch {}
|
|
11470
|
-
}
|
|
11471
|
-
if (rule.unless.task_in && taskId) {
|
|
11472
|
-
if (rule.unless.task_in.includes(taskId))
|
|
11473
|
-
return true;
|
|
11474
|
-
}
|
|
11475
|
-
return false;
|
|
11476
|
-
}
|
|
11477
|
-
function resolveAction(mode, matched) {
|
|
11478
|
-
if (matched.length === 0)
|
|
11479
|
-
return "allow";
|
|
11480
|
-
if (mode === "off")
|
|
11481
|
-
return "allow";
|
|
11482
|
-
if (mode === "observe")
|
|
11483
|
-
return "warn";
|
|
11484
|
-
return "block";
|
|
11485
|
-
}
|
|
11486
|
-
function resolveAbsolutePath(projectRoot, rawPath) {
|
|
11487
|
-
if (rawPath.startsWith("/"))
|
|
11488
|
-
return resolve32(rawPath);
|
|
11489
|
-
return resolve32(projectRoot, rawPath);
|
|
11490
|
-
}
|
|
11491
|
-
function isHarnessPath(projectRoot, rawPath) {
|
|
11492
|
-
const absPath = resolveAbsolutePath(projectRoot, rawPath);
|
|
11493
|
-
const managedRoots = [
|
|
11494
|
-
resolve32(projectRoot, "rig"),
|
|
11495
|
-
resolve32(projectRoot, ".rig"),
|
|
11496
|
-
resolve32(projectRoot, "artifacts")
|
|
11497
|
-
];
|
|
11498
|
-
return managedRoots.some((root) => absPath === root || absPath.startsWith(root + "/"));
|
|
11499
|
-
}
|
|
11500
|
-
function isRuntimePath(projectRoot, rawPath, taskWorkspace) {
|
|
11501
|
-
const absPath = resolveAbsolutePath(projectRoot, rawPath);
|
|
11502
|
-
if (taskWorkspace) {
|
|
11503
|
-
const workspaceRigRoot = resolve32(taskWorkspace, ".rig");
|
|
11504
|
-
const workspaceArtifactsRoot = resolve32(taskWorkspace, "artifacts");
|
|
11505
|
-
if (absPath === workspaceRigRoot || absPath.startsWith(workspaceRigRoot + "/") || absPath === workspaceArtifactsRoot || absPath.startsWith(workspaceArtifactsRoot + "/")) {
|
|
11506
|
-
return true;
|
|
11507
|
-
}
|
|
11508
|
-
}
|
|
11509
|
-
const runtimeRoot = resolve32(projectRoot, ".rig/runtime/agents");
|
|
11510
|
-
return absPath === runtimeRoot || absPath.startsWith(runtimeRoot + "/");
|
|
11511
|
-
}
|
|
11512
|
-
function isTestFile(path) {
|
|
11513
|
-
return /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(path) || /\/(__tests__|tests|test)\//.test(path);
|
|
11514
|
-
}
|
|
11515
|
-
function evaluate(context) {
|
|
11516
|
-
const policy = loadPolicy(context.projectRoot);
|
|
11517
|
-
switch (context.evaluation.type) {
|
|
11518
|
-
case "tool-call":
|
|
11519
|
-
return evaluateToolCall(policy, context);
|
|
11520
|
-
case "command":
|
|
11521
|
-
return evaluateCommand(policy, context);
|
|
11522
|
-
case "content-write":
|
|
11523
|
-
return evaluateContent(policy, context);
|
|
11524
|
-
case "file-access":
|
|
11525
|
-
return evaluateScope(policy, context, context.evaluation.file_path, context.evaluation.access);
|
|
11526
|
-
}
|
|
11527
|
-
}
|
|
11528
|
-
function evaluateScope(policy, context, filePath, access) {
|
|
11529
|
-
const allowed = () => ({
|
|
11530
|
-
allowed: true,
|
|
11531
|
-
matchedRules: [],
|
|
11532
|
-
action: "allow",
|
|
11533
|
-
failClosed: false
|
|
11534
|
-
});
|
|
11535
|
-
if (policy.scope.harness_paths_exempt && isHarnessPath(context.projectRoot, filePath)) {
|
|
11536
|
-
return allowed();
|
|
11537
|
-
}
|
|
11538
|
-
if (policy.scope.runtime_paths_exempt && isRuntimePath(context.projectRoot, filePath, context.taskWorkspace)) {
|
|
11539
|
-
return allowed();
|
|
11540
|
-
}
|
|
11541
|
-
if (!context.taskId) {
|
|
11542
|
-
if (access === "write" && policy.scope.fail_closed) {
|
|
11543
|
-
return {
|
|
11544
|
-
allowed: false,
|
|
11545
|
-
matchedRules: [],
|
|
11546
|
-
action: resolveAction(policy.mode, [{ id: "scope:no-task", category: "command", reason: "No active task; fail-closed for write operations" }]),
|
|
11547
|
-
failClosed: true
|
|
11548
|
-
};
|
|
11549
|
-
}
|
|
11550
|
-
return allowed();
|
|
11551
|
-
}
|
|
11552
|
-
const scopes = context.taskScopes || [];
|
|
11553
|
-
if (scopes.length === 0) {
|
|
11554
|
-
return allowed();
|
|
11555
|
-
}
|
|
11556
|
-
if (context.taskWorkspace && context.taskWorkspace !== context.projectRoot && filePath.startsWith("/")) {
|
|
11557
|
-
const absPath = resolve32(filePath);
|
|
11558
|
-
if (!absPath.startsWith(context.taskWorkspace + "/") && !isHarnessPath(context.projectRoot, filePath)) {
|
|
11559
|
-
const reason2 = `Absolute path '${filePath}' is outside task runtime boundary. Allowed root: ${context.taskWorkspace}`;
|
|
11560
|
-
const matched2 = [{ id: "scope:workspace-boundary", category: "command", reason: reason2 }];
|
|
11561
|
-
return {
|
|
11562
|
-
allowed: policy.mode !== "enforce",
|
|
11563
|
-
matchedRules: matched2,
|
|
11564
|
-
action: resolveAction(policy.mode, matched2),
|
|
11565
|
-
failClosed: false
|
|
11566
|
-
};
|
|
11567
|
-
}
|
|
11568
|
-
}
|
|
11569
|
-
const monorepoRoot = context.monorepoRoot || process.env.MONOREPO_ROOT?.trim() || context.taskWorkspace || context.projectRoot;
|
|
11570
|
-
let normalizedPath = filePath;
|
|
11571
|
-
if (context.taskWorkspace && context.taskWorkspace !== context.projectRoot && filePath.startsWith(context.taskWorkspace + "/")) {
|
|
11572
|
-
normalizedPath = filePath.slice(context.taskWorkspace.length + 1);
|
|
11573
|
-
}
|
|
11574
|
-
normalizedPath = normalizePathToScope(context.projectRoot, monorepoRoot, normalizedPath);
|
|
11575
|
-
if (scopeMatches(filePath, scopes) || scopeMatches(normalizedPath, scopes)) {
|
|
11576
|
-
return allowed();
|
|
11577
|
-
}
|
|
11578
|
-
const reason = `File '${filePath}' (normalized: '${normalizedPath}') is outside scope of task ${context.taskId}`;
|
|
11579
|
-
const matched = [{ id: "scope:out-of-scope", category: "command", reason }];
|
|
11580
|
-
return {
|
|
11581
|
-
allowed: policy.mode !== "enforce",
|
|
11582
|
-
matchedRules: matched,
|
|
11583
|
-
action: resolveAction(policy.mode, matched),
|
|
11584
|
-
failClosed: false
|
|
11585
|
-
};
|
|
11586
|
-
}
|
|
11587
|
-
function evaluateCommand(policy, context) {
|
|
11588
|
-
const evaluation = context.evaluation;
|
|
11589
|
-
if (evaluation.type !== "command") {
|
|
11590
|
-
return { allowed: true, matchedRules: [], action: "allow", failClosed: false };
|
|
11591
|
-
}
|
|
11592
|
-
const command = evaluation.command;
|
|
11593
|
-
const matchedRules = [];
|
|
11594
|
-
for (const rule of policy.rules) {
|
|
11595
|
-
if (rule.category !== "command")
|
|
11596
|
-
continue;
|
|
11597
|
-
if (!matchRule(rule, command))
|
|
11598
|
-
continue;
|
|
11599
|
-
if (matchRuleUnless(rule, command, context.taskId))
|
|
11600
|
-
continue;
|
|
11601
|
-
matchedRules.push({
|
|
11602
|
-
id: rule.id,
|
|
11603
|
-
category: rule.category,
|
|
11604
|
-
description: rule.description,
|
|
11605
|
-
reason: rule.description || `Matched rule ${rule.id}`
|
|
11606
|
-
});
|
|
11607
|
-
}
|
|
11608
|
-
const writeTarget = extractWriteTarget(command);
|
|
11609
|
-
if (writeTarget && !/^\/dev\//.test(writeTarget) && !/^\/proc\//.test(writeTarget)) {
|
|
11610
|
-
const scopeResult = evaluateScope(policy, context, writeTarget, "write");
|
|
11611
|
-
if (!scopeResult.allowed || scopeResult.matchedRules.length > 0) {
|
|
11612
|
-
matchedRules.push(...scopeResult.matchedRules);
|
|
11613
|
-
}
|
|
11614
|
-
}
|
|
11615
|
-
const action = resolveAction(policy.mode, matchedRules);
|
|
11616
|
-
return {
|
|
11617
|
-
allowed: action !== "block",
|
|
11618
|
-
matchedRules,
|
|
11619
|
-
action,
|
|
11620
|
-
failClosed: false
|
|
11621
|
-
};
|
|
11622
|
-
}
|
|
11623
|
-
function extractWriteTarget(command) {
|
|
11624
|
-
const redirect = command.match(/>>?\s+([^\s;|&]+)/);
|
|
11625
|
-
if (redirect?.[1])
|
|
11626
|
-
return redirect[1];
|
|
11627
|
-
const tee = command.match(/tee\s+(-a\s+)?([^\s;|&]+)/);
|
|
11628
|
-
if (tee?.[2])
|
|
11629
|
-
return tee[2];
|
|
11630
|
-
return "";
|
|
11631
|
-
}
|
|
11632
|
-
function evaluateContent(policy, context) {
|
|
11633
|
-
const evaluation = context.evaluation;
|
|
11634
|
-
if (evaluation.type !== "content-write") {
|
|
11635
|
-
return { allowed: true, matchedRules: [], action: "allow", failClosed: false };
|
|
11636
|
-
}
|
|
11637
|
-
const { content, file_path } = evaluation;
|
|
11638
|
-
const matchedRules = [];
|
|
11639
|
-
const scopeResult = evaluateScope(policy, context, file_path, "write");
|
|
11640
|
-
if (scopeResult.matchedRules.length > 0) {
|
|
11641
|
-
matchedRules.push(...scopeResult.matchedRules);
|
|
11642
|
-
}
|
|
11643
|
-
for (const rule of policy.rules) {
|
|
11644
|
-
if (rule.category !== "content" && rule.category !== "import" && rule.category !== "test-integrity")
|
|
11645
|
-
continue;
|
|
11646
|
-
if (rule.applies_to === "test-files" && !isTestFile(file_path))
|
|
11647
|
-
continue;
|
|
11648
|
-
if (!matchRule(rule, content))
|
|
11649
|
-
continue;
|
|
11650
|
-
if (matchRuleUnless(rule, content, context.taskId))
|
|
11651
|
-
continue;
|
|
11652
|
-
matchedRules.push({
|
|
11653
|
-
id: rule.id,
|
|
11654
|
-
category: rule.category,
|
|
11655
|
-
description: rule.description,
|
|
11656
|
-
reason: rule.description || `Matched rule ${rule.id}`
|
|
11657
|
-
});
|
|
11658
|
-
}
|
|
11659
|
-
const action = resolveAction(policy.mode, matchedRules);
|
|
11660
|
-
return {
|
|
11661
|
-
allowed: action !== "block",
|
|
11662
|
-
matchedRules,
|
|
11663
|
-
action,
|
|
11664
|
-
failClosed: false
|
|
11665
|
-
};
|
|
11666
|
-
}
|
|
11667
|
-
function evaluateToolCall(policy, context) {
|
|
11668
|
-
const evaluation = context.evaluation;
|
|
11669
|
-
if (evaluation.type !== "tool-call") {
|
|
11670
|
-
return { allowed: true, matchedRules: [], action: "allow", failClosed: false };
|
|
11671
|
-
}
|
|
11672
|
-
const { tool_name, tool_input } = evaluation;
|
|
11673
|
-
const allMatched = [];
|
|
11674
|
-
const filePaths = extractFilePathsFromToolInput(tool_name, tool_input);
|
|
11675
|
-
for (const fp of filePaths) {
|
|
11676
|
-
const access = isWriteTool(tool_name) ? "write" : "read";
|
|
11677
|
-
const scopeResult = evaluateScope(policy, context, fp, access);
|
|
11678
|
-
if (scopeResult.matchedRules.length > 0) {
|
|
11679
|
-
allMatched.push(...scopeResult.matchedRules);
|
|
11680
|
-
}
|
|
11681
|
-
}
|
|
11682
|
-
const content = extractContentFromToolInput(tool_input);
|
|
11683
|
-
if (content) {
|
|
11684
|
-
const filePath = filePaths[0] || "";
|
|
11685
|
-
const contentContext = {
|
|
11686
|
-
...context,
|
|
11687
|
-
evaluation: { type: "content-write", file_path: filePath, content }
|
|
11688
|
-
};
|
|
11689
|
-
const contentPolicy = loadPolicy(context.projectRoot);
|
|
11690
|
-
for (const rule of contentPolicy.rules) {
|
|
11691
|
-
if (rule.category !== "content" && rule.category !== "import" && rule.category !== "test-integrity")
|
|
11692
|
-
continue;
|
|
11693
|
-
if (rule.applies_to === "test-files" && !isTestFile(filePath))
|
|
11694
|
-
continue;
|
|
11695
|
-
if (!matchRule(rule, content))
|
|
11696
|
-
continue;
|
|
11697
|
-
if (matchRuleUnless(rule, content, context.taskId))
|
|
11698
|
-
continue;
|
|
11699
|
-
allMatched.push({
|
|
11700
|
-
id: rule.id,
|
|
11701
|
-
category: rule.category,
|
|
11702
|
-
description: rule.description,
|
|
11703
|
-
reason: rule.description || `Matched rule ${rule.id}`
|
|
11704
|
-
});
|
|
11705
|
-
}
|
|
11706
|
-
}
|
|
11707
|
-
if (tool_name === "Bash") {
|
|
11708
|
-
const command = String(tool_input.command || tool_input.cmd || "");
|
|
11709
|
-
if (command) {
|
|
11710
|
-
const cmdContext = {
|
|
11711
|
-
...context,
|
|
11712
|
-
evaluation: { type: "command", command }
|
|
11713
|
-
};
|
|
11714
|
-
const cmdResult = evaluateCommand(policy, cmdContext);
|
|
11715
|
-
if (cmdResult.matchedRules.length > 0) {
|
|
11716
|
-
allMatched.push(...cmdResult.matchedRules);
|
|
11717
|
-
}
|
|
11718
|
-
}
|
|
11719
|
-
}
|
|
11720
|
-
const seen = new Set;
|
|
11721
|
-
const deduplicated = [];
|
|
11722
|
-
for (const rule of allMatched) {
|
|
11723
|
-
if (!seen.has(rule.id)) {
|
|
11724
|
-
seen.add(rule.id);
|
|
11725
|
-
deduplicated.push(rule);
|
|
11726
|
-
}
|
|
11727
|
-
}
|
|
11728
|
-
const action = resolveAction(policy.mode, deduplicated);
|
|
11729
|
-
return {
|
|
11730
|
-
allowed: action !== "block",
|
|
11731
|
-
matchedRules: deduplicated,
|
|
11732
|
-
action,
|
|
11733
|
-
failClosed: false
|
|
11734
|
-
};
|
|
11735
|
-
}
|
|
11736
|
-
function isWriteTool(toolName) {
|
|
11737
|
-
return toolName === "Write" || toolName === "Edit" || toolName === "MultiEdit";
|
|
11738
|
-
}
|
|
11739
|
-
function extractFilePathsFromToolInput(toolName, input) {
|
|
11740
|
-
const paths = [];
|
|
11741
|
-
const add = (value) => {
|
|
11742
|
-
if (typeof value === "string" && value.trim()) {
|
|
11743
|
-
paths.push(value.trim());
|
|
11744
|
-
}
|
|
11745
|
-
};
|
|
11746
|
-
if (toolName === "Read" || toolName === "Write" || toolName === "Edit" || toolName === "MultiEdit") {
|
|
11747
|
-
add(input.file_path);
|
|
11748
|
-
add(input.path);
|
|
11749
|
-
} else if (toolName === "Glob") {
|
|
11750
|
-
add(input.path);
|
|
11751
|
-
} else if (toolName === "Grep") {
|
|
11752
|
-
add(input.path);
|
|
11753
|
-
} else {
|
|
11754
|
-
add(input.file_path);
|
|
11755
|
-
add(input.path);
|
|
11756
|
-
}
|
|
11757
|
-
return paths;
|
|
11758
|
-
}
|
|
11759
|
-
function extractContentFromToolInput(input) {
|
|
11760
|
-
if (typeof input.content === "string")
|
|
11761
|
-
return input.content;
|
|
11762
|
-
if (typeof input.new_string === "string")
|
|
11763
|
-
return input.new_string;
|
|
11764
|
-
return "";
|
|
11765
|
-
}
|
|
11766
|
-
function loadRuntimeImageConfig(projectRoot) {
|
|
11767
|
-
return loadPolicy(projectRoot).runtime_image ?? {
|
|
11768
|
-
deps: { ...DEFAULT_RUNTIME_IMAGE.deps },
|
|
11769
|
-
plugins_require_binaries: DEFAULT_RUNTIME_IMAGE.plugins_require_binaries
|
|
11770
|
-
};
|
|
11771
|
-
}
|
|
11772
|
-
var guardHotPathPrimed = false;
|
|
11773
|
-
function primeGuardHotPaths() {
|
|
11774
|
-
if (guardHotPathPrimed) {
|
|
11775
|
-
return;
|
|
11776
|
-
}
|
|
11777
|
-
guardHotPathPrimed = true;
|
|
11778
|
-
try {
|
|
11779
|
-
optimizeNextInvocation(matchRule);
|
|
11780
|
-
optimizeNextInvocation(evaluate);
|
|
11781
|
-
} catch {}
|
|
11782
|
-
}
|
|
11783
|
-
primeGuardHotPaths();
|
|
11784
|
-
|
|
11785
11235
|
// packages/runtime/src/control-plane/runtime/plugin-mode.ts
|
|
11786
|
-
var LEGACY_PLUGIN_SCAN_ENV = "RIG_LEGACY_PLUGIN_SCAN";
|
|
11787
|
-
function isLegacyPluginScanEnabled(env = process.env) {
|
|
11788
|
-
const value = env[LEGACY_PLUGIN_SCAN_ENV]?.trim().toLowerCase();
|
|
11789
|
-
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
11790
|
-
}
|
|
11791
11236
|
function resolveHarnessPluginMode(options) {
|
|
11792
|
-
const legacyScanEnabled = isLegacyPluginScanEnabled(options.env);
|
|
11793
|
-
if (options.hasDeclarativeConfig && legacyScanEnabled) {
|
|
11794
|
-
return {
|
|
11795
|
-
kind: "declarative-with-legacy-compat",
|
|
11796
|
-
legacyScanEnabled: true,
|
|
11797
|
-
diagnostic: `[harness] plugin mode: declarative rig.config.ts plugins + legacy compatibility scan (${LEGACY_PLUGIN_SCAN_ENV}=1)`
|
|
11798
|
-
};
|
|
11799
|
-
}
|
|
11800
11237
|
if (options.hasDeclarativeConfig) {
|
|
11801
11238
|
return {
|
|
11802
11239
|
kind: "declarative",
|
|
11803
|
-
|
|
11804
|
-
diagnostic: `[harness] plugin mode: declarative rig.config.ts plugins (legacy scan disabled; set ${LEGACY_PLUGIN_SCAN_ENV}=1 only for compatibility)`
|
|
11805
|
-
};
|
|
11806
|
-
}
|
|
11807
|
-
if (legacyScanEnabled) {
|
|
11808
|
-
return {
|
|
11809
|
-
kind: "legacy-compat",
|
|
11810
|
-
legacyScanEnabled: true,
|
|
11811
|
-
diagnostic: `[harness] plugin mode: legacy compatibility scan (${LEGACY_PLUGIN_SCAN_ENV}=1; add rig.config.ts to use declarative plugins)`
|
|
11240
|
+
diagnostic: "[harness] plugin mode: declarative rig.config.ts plugins"
|
|
11812
11241
|
};
|
|
11813
11242
|
}
|
|
11814
11243
|
return {
|
|
11815
11244
|
kind: "none",
|
|
11816
|
-
|
|
11817
|
-
diagnostic: `[harness] plugin mode: none (no rig.config.ts found; legacy scan disabled; set ${LEGACY_PLUGIN_SCAN_ENV}=1 only for compatibility)`
|
|
11245
|
+
diagnostic: "[harness] plugin mode: none (no rig.config.ts found; add one to load plugins)"
|
|
11818
11246
|
};
|
|
11819
11247
|
}
|
|
11820
11248
|
|
|
11821
|
-
// packages/runtime/src/control-plane/runtime/plugins.ts
|
|
11822
|
-
class PluginManager {
|
|
11823
|
-
eventBus;
|
|
11824
|
-
context;
|
|
11825
|
-
pluginDir;
|
|
11826
|
-
pluginFiles;
|
|
11827
|
-
pluginNames;
|
|
11828
|
-
localBinDir;
|
|
11829
|
-
pluginsRequireBinaries;
|
|
11830
|
-
plugins;
|
|
11831
|
-
loadPromise;
|
|
11832
|
-
constructor(options) {
|
|
11833
|
-
this.eventBus = options.eventBus;
|
|
11834
|
-
this.context = options.context;
|
|
11835
|
-
this.pluginDir = options.pluginDir;
|
|
11836
|
-
this.pluginFiles = options.pluginFiles;
|
|
11837
|
-
this.pluginNames = options.pluginNames;
|
|
11838
|
-
this.localBinDir = options.localBinDir;
|
|
11839
|
-
this.pluginsRequireBinaries = options.pluginsRequireBinaries;
|
|
11840
|
-
this.plugins = options.preloadedPlugins ?? null;
|
|
11841
|
-
this.loadPromise = null;
|
|
11842
|
-
}
|
|
11843
|
-
static disabled(options) {
|
|
11844
|
-
const validatorProjectRoot = options.runtimeContext?.workspaceDir || options.projectRoot;
|
|
11845
|
-
return new PluginManager({
|
|
11846
|
-
eventBus: options.eventBus,
|
|
11847
|
-
context: {
|
|
11848
|
-
projectRoot: validatorProjectRoot,
|
|
11849
|
-
runId: options.runId,
|
|
11850
|
-
eventBus: options.eventBus
|
|
11851
|
-
},
|
|
11852
|
-
pluginDir: resolve33(options.projectRoot, "rig/plugins"),
|
|
11853
|
-
pluginFiles: [],
|
|
11854
|
-
pluginNames: [],
|
|
11855
|
-
localBinDir: options.runtimeContext ? resolve33(options.runtimeContext.binDir, "plugins") : resolve33(options.projectRoot, "rig/plugins"),
|
|
11856
|
-
pluginsRequireBinaries: false,
|
|
11857
|
-
preloadedPlugins: []
|
|
11858
|
-
});
|
|
11859
|
-
}
|
|
11860
|
-
static async load(options) {
|
|
11861
|
-
const pluginDir = resolve33(options.projectRoot, "rig/plugins");
|
|
11862
|
-
const runtimeImageConfig = loadRuntimeImageConfig(options.projectRoot);
|
|
11863
|
-
const localBinDir = options.runtimeContext ? resolve33(options.runtimeContext.binDir, "plugins") : resolve33(options.projectRoot, "rig/plugins");
|
|
11864
|
-
const legacyPluginScan = options.legacyPluginScan ?? isLegacyPluginScanEnabled(options.env);
|
|
11865
|
-
const files = legacyPluginScan ? safeReadDir(pluginDir).filter((entry) => /\.(ts|js|mjs|cjs)$/.test(entry)) : [];
|
|
11866
|
-
const pluginNames = files.map((file) => basename9(file).replace(/\.plugin\.(ts|js|mjs|cjs)$/, ""));
|
|
11867
|
-
const validatorProjectRoot = options.runtimeContext?.workspaceDir || options.projectRoot;
|
|
11868
|
-
const context = {
|
|
11869
|
-
projectRoot: validatorProjectRoot,
|
|
11870
|
-
runId: options.runId,
|
|
11871
|
-
eventBus: options.eventBus
|
|
11872
|
-
};
|
|
11873
|
-
return new PluginManager({
|
|
11874
|
-
eventBus: options.eventBus,
|
|
11875
|
-
context,
|
|
11876
|
-
pluginDir,
|
|
11877
|
-
pluginFiles: files,
|
|
11878
|
-
pluginNames,
|
|
11879
|
-
localBinDir,
|
|
11880
|
-
pluginsRequireBinaries: options.pluginsRequireBinaries ?? (runtimeImageConfig.plugins_require_binaries && Boolean(options.runtimeContext))
|
|
11881
|
-
});
|
|
11882
|
-
}
|
|
11883
|
-
list() {
|
|
11884
|
-
if (this.plugins) {
|
|
11885
|
-
return this.plugins.map((plugin) => ({
|
|
11886
|
-
name: plugin.name,
|
|
11887
|
-
validators: plugin.validators?.map((validator) => validator.id) ?? []
|
|
11888
|
-
}));
|
|
11889
|
-
}
|
|
11890
|
-
return this.pluginNames.map((name) => ({
|
|
11891
|
-
name,
|
|
11892
|
-
validators: []
|
|
11893
|
-
}));
|
|
11894
|
-
}
|
|
11895
|
-
async beforeCommand(ctx) {
|
|
11896
|
-
const plugins = await this.ensureLoaded();
|
|
11897
|
-
for (const plugin of plugins) {
|
|
11898
|
-
if (!plugin.beforeCommand) {
|
|
11899
|
-
continue;
|
|
11900
|
-
}
|
|
11901
|
-
await this.safeInvoke(plugin.name, "beforeCommand", () => plugin.beforeCommand?.(ctx, this.context));
|
|
11902
|
-
}
|
|
11903
|
-
}
|
|
11904
|
-
async afterCommand(result) {
|
|
11905
|
-
const plugins = await this.ensureLoaded();
|
|
11906
|
-
for (const plugin of plugins) {
|
|
11907
|
-
if (!plugin.afterCommand) {
|
|
11908
|
-
continue;
|
|
11909
|
-
}
|
|
11910
|
-
await this.safeInvoke(plugin.name, "afterCommand", () => plugin.afterCommand?.(result, this.context));
|
|
11911
|
-
}
|
|
11912
|
-
}
|
|
11913
|
-
async onEvent(event) {
|
|
11914
|
-
const plugins = this.plugins;
|
|
11915
|
-
if (!plugins) {
|
|
11916
|
-
return;
|
|
11917
|
-
}
|
|
11918
|
-
for (const plugin of plugins) {
|
|
11919
|
-
if (!plugin.onEvent) {
|
|
11920
|
-
continue;
|
|
11921
|
-
}
|
|
11922
|
-
await this.safeInvoke(plugin.name, "onEvent", () => plugin.onEvent?.(event, this.context));
|
|
11923
|
-
}
|
|
11924
|
-
}
|
|
11925
|
-
async runValidators(taskId) {
|
|
11926
|
-
const plugins = await this.ensureLoaded();
|
|
11927
|
-
const results = [];
|
|
11928
|
-
for (const plugin of plugins) {
|
|
11929
|
-
for (const validator of plugin.validators ?? []) {
|
|
11930
|
-
await this.eventBus.emit("validator.started", {
|
|
11931
|
-
plugin: plugin.name,
|
|
11932
|
-
validator: validator.id,
|
|
11933
|
-
taskId
|
|
11934
|
-
});
|
|
11935
|
-
try {
|
|
11936
|
-
const result = await validator.run({ taskId, projectRoot: this.context.projectRoot }, this.context);
|
|
11937
|
-
results.push(result);
|
|
11938
|
-
await this.eventBus.emit("validator.finished", {
|
|
11939
|
-
plugin: plugin.name,
|
|
11940
|
-
validator: validator.id,
|
|
11941
|
-
taskId,
|
|
11942
|
-
passed: result.passed,
|
|
11943
|
-
summary: result.summary
|
|
11944
|
-
});
|
|
11945
|
-
} catch (error) {
|
|
11946
|
-
const failed = {
|
|
11947
|
-
id: validator.id,
|
|
11948
|
-
passed: false,
|
|
11949
|
-
summary: `${plugin.name}/${validator.id} failed unexpectedly`,
|
|
11950
|
-
details: `${error}`
|
|
11951
|
-
};
|
|
11952
|
-
results.push(failed);
|
|
11953
|
-
await this.eventBus.emit("validator.finished", {
|
|
11954
|
-
plugin: plugin.name,
|
|
11955
|
-
validator: validator.id,
|
|
11956
|
-
taskId,
|
|
11957
|
-
passed: false,
|
|
11958
|
-
summary: failed.summary,
|
|
11959
|
-
details: failed.details
|
|
11960
|
-
});
|
|
11961
|
-
}
|
|
11962
|
-
}
|
|
11963
|
-
}
|
|
11964
|
-
return results;
|
|
11965
|
-
}
|
|
11966
|
-
async safeInvoke(pluginName, hook, call) {
|
|
11967
|
-
try {
|
|
11968
|
-
await call();
|
|
11969
|
-
} catch (error) {
|
|
11970
|
-
await this.eventBus.emit("plugin.error", {
|
|
11971
|
-
plugin: pluginName,
|
|
11972
|
-
phase: hook,
|
|
11973
|
-
error: `${error}`
|
|
11974
|
-
});
|
|
11975
|
-
}
|
|
11976
|
-
}
|
|
11977
|
-
async ensureLoaded() {
|
|
11978
|
-
if (this.plugins) {
|
|
11979
|
-
return this.plugins;
|
|
11980
|
-
}
|
|
11981
|
-
if (this.loadPromise) {
|
|
11982
|
-
return this.loadPromise;
|
|
11983
|
-
}
|
|
11984
|
-
this.loadPromise = this.loadCompiledPlugins();
|
|
11985
|
-
try {
|
|
11986
|
-
this.plugins = await this.loadPromise;
|
|
11987
|
-
return this.plugins;
|
|
11988
|
-
} finally {
|
|
11989
|
-
this.loadPromise = null;
|
|
11990
|
-
}
|
|
11991
|
-
}
|
|
11992
|
-
resolveBinPath(binName) {
|
|
11993
|
-
const candidates = [this.localBinDir].filter(Boolean).map((dir) => resolve33(dir, binName));
|
|
11994
|
-
return candidates.find((candidate) => existsSync31(candidate));
|
|
11995
|
-
}
|
|
11996
|
-
async loadCompiledPlugins() {
|
|
11997
|
-
const plugins = [];
|
|
11998
|
-
for (const file of this.pluginFiles) {
|
|
11999
|
-
const binName = basename9(file).replace(/\.plugin\.(ts|js|mjs|cjs)$/, "");
|
|
12000
|
-
let binPath = this.resolveBinPath(binName);
|
|
12001
|
-
if (!binPath) {
|
|
12002
|
-
const triedPaths = [this.localBinDir].filter(Boolean).map((dir) => resolve33(dir, binName));
|
|
12003
|
-
const missingError = `Compiled plugin binary not found for '${binName}'. Tried: ${triedPaths.join(", ")}`;
|
|
12004
|
-
await this.eventBus.emit("plugin.error", {
|
|
12005
|
-
file: resolve33(this.pluginDir, file),
|
|
12006
|
-
phase: "load",
|
|
12007
|
-
error: missingError
|
|
12008
|
-
});
|
|
12009
|
-
if (this.pluginsRequireBinaries) {
|
|
12010
|
-
throw new Error(missingError);
|
|
12011
|
-
}
|
|
12012
|
-
plugins.push({
|
|
12013
|
-
name: binName,
|
|
12014
|
-
validators: []
|
|
12015
|
-
});
|
|
12016
|
-
await this.eventBus.emit("plugin.loaded", {
|
|
12017
|
-
plugin: binName,
|
|
12018
|
-
file: resolve33(this.pluginDir, file),
|
|
12019
|
-
source: "metadata-only"
|
|
12020
|
-
});
|
|
12021
|
-
continue;
|
|
12022
|
-
}
|
|
12023
|
-
const wrapper = createBinaryPluginWrapper(binName, binPath, this.context.projectRoot);
|
|
12024
|
-
plugins.push(wrapper);
|
|
12025
|
-
await this.eventBus.emit("plugin.loaded", {
|
|
12026
|
-
plugin: wrapper.name,
|
|
12027
|
-
file: binPath,
|
|
12028
|
-
source: "compiled-binary"
|
|
12029
|
-
});
|
|
12030
|
-
}
|
|
12031
|
-
return plugins;
|
|
12032
|
-
}
|
|
12033
|
-
}
|
|
12034
|
-
function createBinaryPluginWrapper(name, binPath, projectRoot) {
|
|
12035
|
-
return {
|
|
12036
|
-
name,
|
|
12037
|
-
validators: [
|
|
12038
|
-
{
|
|
12039
|
-
id: `${name}:compiled`,
|
|
12040
|
-
async run(ctx) {
|
|
12041
|
-
const proc = Bun.spawn([binPath, "--validate", ctx.taskId, ctx.projectRoot], {
|
|
12042
|
-
cwd: projectRoot,
|
|
12043
|
-
stdout: "pipe",
|
|
12044
|
-
stderr: "pipe"
|
|
12045
|
-
});
|
|
12046
|
-
const exitCode = await proc.exited;
|
|
12047
|
-
const stdout = await new Response(proc.stdout).text();
|
|
12048
|
-
const stderr = await new Response(proc.stderr).text();
|
|
12049
|
-
if (exitCode !== 0) {
|
|
12050
|
-
return {
|
|
12051
|
-
id: `${name}:compiled`,
|
|
12052
|
-
passed: false,
|
|
12053
|
-
summary: `Plugin binary ${name} exited with code ${exitCode}`,
|
|
12054
|
-
details: stderr || stdout
|
|
12055
|
-
};
|
|
12056
|
-
}
|
|
12057
|
-
try {
|
|
12058
|
-
const results = JSON.parse(stdout.trim());
|
|
12059
|
-
const failed = results.filter((r) => !r.passed);
|
|
12060
|
-
if (failed.length > 0) {
|
|
12061
|
-
return {
|
|
12062
|
-
id: `${name}:compiled`,
|
|
12063
|
-
passed: false,
|
|
12064
|
-
summary: `${failed.length} of ${results.length} validator(s) failed`,
|
|
12065
|
-
details: failed.map((f) => `${f.id}: ${f.summary}`).join(`
|
|
12066
|
-
`)
|
|
12067
|
-
};
|
|
12068
|
-
}
|
|
12069
|
-
return {
|
|
12070
|
-
id: `${name}:compiled`,
|
|
12071
|
-
passed: true,
|
|
12072
|
-
summary: `All ${results.length} validator(s) passed`
|
|
12073
|
-
};
|
|
12074
|
-
} catch {
|
|
12075
|
-
return {
|
|
12076
|
-
id: `${name}:compiled`,
|
|
12077
|
-
passed: false,
|
|
12078
|
-
summary: `Failed to parse output from compiled plugin ${name}`,
|
|
12079
|
-
details: stdout.slice(0, 500)
|
|
12080
|
-
};
|
|
12081
|
-
}
|
|
12082
|
-
}
|
|
12083
|
-
}
|
|
12084
|
-
]
|
|
12085
|
-
};
|
|
12086
|
-
}
|
|
12087
|
-
function safeReadDir(path) {
|
|
12088
|
-
try {
|
|
12089
|
-
return readdirSync6(path, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
|
|
12090
|
-
} catch {
|
|
12091
|
-
return [];
|
|
12092
|
-
}
|
|
12093
|
-
}
|
|
12094
|
-
|
|
12095
11249
|
// packages/runtime/src/control-plane/harness-main.ts
|
|
12096
11250
|
async function main() {
|
|
12097
11251
|
const projectRoot = resolveProjectRoot({
|
|
12098
11252
|
cwd: process.cwd(),
|
|
12099
|
-
fallbackFromDir:
|
|
11253
|
+
fallbackFromDir: resolve33(import.meta.dir, "../..")
|
|
12100
11254
|
});
|
|
12101
11255
|
process.env.PROJECT_RIG_ROOT = projectRoot;
|
|
12102
11256
|
process.chdir(projectRoot);
|
|
@@ -12109,20 +11263,7 @@ async function main() {
|
|
|
12109
11263
|
});
|
|
12110
11264
|
console.error(pluginMode.diagnostic);
|
|
12111
11265
|
const eventBus = new GeneralCliEventBus({ projectRoot });
|
|
12112
|
-
|
|
12113
|
-
const plugins = pluginMode.legacyScanEnabled ? await PluginManager.load({
|
|
12114
|
-
projectRoot,
|
|
12115
|
-
runId: eventBus.getRunId(),
|
|
12116
|
-
eventBus,
|
|
12117
|
-
runtimeContext,
|
|
12118
|
-
legacyPluginScan: pluginMode.legacyScanEnabled
|
|
12119
|
-
}) : PluginManager.disabled({
|
|
12120
|
-
projectRoot,
|
|
12121
|
-
runId: eventBus.getRunId(),
|
|
12122
|
-
eventBus,
|
|
12123
|
-
runtimeContext
|
|
12124
|
-
});
|
|
12125
|
-
await executeHarnessCommand(projectRoot, plugins, process.argv.slice(2), eventBus, pluginHostCtx);
|
|
11266
|
+
await executeHarnessCommand(projectRoot, process.argv.slice(2), eventBus, pluginHostCtx);
|
|
12126
11267
|
}
|
|
12127
11268
|
main().catch((error) => {
|
|
12128
11269
|
console.error(error instanceof Error ? error.message : `${error}`);
|