@h-rig/runtime 0.0.6-alpha.27 → 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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
3
|
-
import { existsSync as
|
|
4
|
-
import { resolve as
|
|
3
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
4
|
+
import { resolve as resolve15 } from "path";
|
|
5
5
|
|
|
6
6
|
// packages/runtime/src/layout.ts
|
|
7
7
|
import { existsSync } from "fs";
|
|
@@ -916,6 +916,49 @@ function safeReadJson(path) {
|
|
|
916
916
|
}
|
|
917
917
|
}
|
|
918
918
|
|
|
919
|
+
// packages/runtime/src/control-plane/skill-materializer.ts
|
|
920
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync5, readdirSync as readdirSync2, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
921
|
+
import { resolve as resolve8 } from "path";
|
|
922
|
+
import { loadSkill } from "@rig/skill-loader";
|
|
923
|
+
var MARKER_FILENAME = ".rig-plugin";
|
|
924
|
+
function skillDirName(id) {
|
|
925
|
+
return id.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
926
|
+
}
|
|
927
|
+
async function materializeSkills(projectRoot, entries) {
|
|
928
|
+
const skillsRoot = resolve8(projectRoot, ".pi", "skills");
|
|
929
|
+
if (existsSync8(skillsRoot)) {
|
|
930
|
+
for (const name of readdirSync2(skillsRoot)) {
|
|
931
|
+
const dir = resolve8(skillsRoot, name);
|
|
932
|
+
if (existsSync8(resolve8(dir, MARKER_FILENAME))) {
|
|
933
|
+
rmSync2(dir, { recursive: true, force: true });
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
const written = [];
|
|
938
|
+
for (const { pluginName, skill } of entries) {
|
|
939
|
+
const sourcePath = resolve8(projectRoot, skill.path);
|
|
940
|
+
if (!existsSync8(sourcePath)) {
|
|
941
|
+
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${sourcePath} does not exist`);
|
|
942
|
+
continue;
|
|
943
|
+
}
|
|
944
|
+
let body;
|
|
945
|
+
try {
|
|
946
|
+
await loadSkill(sourcePath);
|
|
947
|
+
body = readFileSync5(sourcePath, "utf-8");
|
|
948
|
+
} catch (err) {
|
|
949
|
+
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${err instanceof Error ? err.message : err}`);
|
|
950
|
+
continue;
|
|
951
|
+
}
|
|
952
|
+
const dir = resolve8(skillsRoot, skillDirName(skill.id));
|
|
953
|
+
mkdirSync4(dir, { recursive: true });
|
|
954
|
+
writeFileSync4(resolve8(dir, "SKILL.md"), body, "utf-8");
|
|
955
|
+
writeFileSync4(resolve8(dir, MARKER_FILENAME), `${JSON.stringify({ plugin: pluginName, skillId: skill.id }, null, 2)}
|
|
956
|
+
`, "utf-8");
|
|
957
|
+
written.push({ id: skill.id, pluginName, directory: dir });
|
|
958
|
+
}
|
|
959
|
+
return written;
|
|
960
|
+
}
|
|
961
|
+
|
|
919
962
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
920
963
|
async function buildPluginHostContext(projectRoot) {
|
|
921
964
|
let config;
|
|
@@ -952,6 +995,17 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
952
995
|
} catch (err) {
|
|
953
996
|
console.warn(`[plugin-host] hook materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
954
997
|
}
|
|
998
|
+
try {
|
|
999
|
+
const skillEntries = config.plugins.flatMap((plugin) => (plugin.contributes?.skills ?? []).map((skill) => ({
|
|
1000
|
+
pluginName: plugin.name,
|
|
1001
|
+
skill
|
|
1002
|
+
})));
|
|
1003
|
+
if (skillEntries.length > 0) {
|
|
1004
|
+
await materializeSkills(projectRoot, skillEntries);
|
|
1005
|
+
}
|
|
1006
|
+
} catch (err) {
|
|
1007
|
+
console.warn(`[plugin-host] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
1008
|
+
}
|
|
955
1009
|
return {
|
|
956
1010
|
config,
|
|
957
1011
|
pluginHost,
|
|
@@ -965,12 +1019,12 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
965
1019
|
|
|
966
1020
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
967
1021
|
import { spawnSync } from "child_process";
|
|
968
|
-
import { existsSync as
|
|
969
|
-
import { basename as basename3, join as join2, resolve as
|
|
1022
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7, readdirSync as readdirSync3, statSync as statSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
1023
|
+
import { basename as basename3, join as join2, resolve as resolve10 } from "path";
|
|
970
1024
|
|
|
971
1025
|
// packages/runtime/src/control-plane/tasks/legacy-task-config-source.ts
|
|
972
|
-
import { existsSync as
|
|
973
|
-
import { resolve as
|
|
1026
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
|
|
1027
|
+
import { resolve as resolve9 } from "path";
|
|
974
1028
|
|
|
975
1029
|
// packages/runtime/src/control-plane/tasks/task-record-reader.ts
|
|
976
1030
|
async function findTaskById(reader, id) {
|
|
@@ -993,7 +1047,7 @@ class LegacyTaskConfigReadError extends Error {
|
|
|
993
1047
|
}
|
|
994
1048
|
}
|
|
995
1049
|
function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
996
|
-
const configPath = options.configPath ??
|
|
1050
|
+
const configPath = options.configPath ?? resolve9(projectRoot, ".rig", "task-config.json");
|
|
997
1051
|
const reader = {
|
|
998
1052
|
async listTasks() {
|
|
999
1053
|
return readLegacyTaskRecords(projectRoot, configPath);
|
|
@@ -1004,8 +1058,8 @@ function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
|
1004
1058
|
};
|
|
1005
1059
|
return reader;
|
|
1006
1060
|
}
|
|
1007
|
-
function readLegacyTaskRecords(projectRoot, configPath =
|
|
1008
|
-
if (!
|
|
1061
|
+
function readLegacyTaskRecords(projectRoot, configPath = resolve9(projectRoot, ".rig", "task-config.json")) {
|
|
1062
|
+
if (!existsSync9(configPath)) {
|
|
1009
1063
|
return [];
|
|
1010
1064
|
}
|
|
1011
1065
|
const rawConfig = readLegacyTaskConfigJson(projectRoot, configPath);
|
|
@@ -1013,7 +1067,7 @@ function readLegacyTaskRecords(projectRoot, configPath = resolve8(projectRoot, "
|
|
|
1013
1067
|
}
|
|
1014
1068
|
function readLegacyTaskConfigJson(projectRoot, configPath) {
|
|
1015
1069
|
try {
|
|
1016
|
-
const parsed = JSON.parse(
|
|
1070
|
+
const parsed = JSON.parse(readFileSync6(configPath, "utf8"));
|
|
1017
1071
|
if (isPlainRecord(parsed)) {
|
|
1018
1072
|
return parsed;
|
|
1019
1073
|
}
|
|
@@ -1097,7 +1151,7 @@ function isPlainRecord(candidate) {
|
|
|
1097
1151
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
1098
1152
|
var FILE_TASK_PATTERN = /\.(task\.)?json$/;
|
|
1099
1153
|
function createSourceAwareTaskConfigRecordReader(projectRoot, options = {}) {
|
|
1100
|
-
const configPath = options.configPath ??
|
|
1154
|
+
const configPath = options.configPath ?? resolve10(projectRoot, ".rig", "task-config.json");
|
|
1101
1155
|
const legacy = createLegacyTaskConfigRecordReader(projectRoot, { configPath });
|
|
1102
1156
|
const spawnFn = options.spawn ?? spawnSync;
|
|
1103
1157
|
const ghBinary = options.ghBinary ?? "gh";
|
|
@@ -1180,10 +1234,10 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
1180
1234
|
return metadata;
|
|
1181
1235
|
}
|
|
1182
1236
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
1183
|
-
const jsonPath =
|
|
1184
|
-
if (
|
|
1237
|
+
const jsonPath = resolve10(projectRoot, "rig.config.json");
|
|
1238
|
+
if (existsSync10(jsonPath)) {
|
|
1185
1239
|
try {
|
|
1186
|
-
const parsed = JSON.parse(
|
|
1240
|
+
const parsed = JSON.parse(readFileSync7(jsonPath, "utf8"));
|
|
1187
1241
|
if (isPlainRecord2(parsed) && isPlainRecord2(parsed.taskSource)) {
|
|
1188
1242
|
const source = parsed.taskSource;
|
|
1189
1243
|
return source.kind === "files" && typeof source.path === "string" ? source.path : null;
|
|
@@ -1192,12 +1246,12 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
1192
1246
|
return null;
|
|
1193
1247
|
}
|
|
1194
1248
|
}
|
|
1195
|
-
const tsPath =
|
|
1196
|
-
if (!
|
|
1249
|
+
const tsPath = resolve10(projectRoot, "rig.config.ts");
|
|
1250
|
+
if (!existsSync10(tsPath)) {
|
|
1197
1251
|
return null;
|
|
1198
1252
|
}
|
|
1199
1253
|
try {
|
|
1200
|
-
const source =
|
|
1254
|
+
const source = readFileSync7(tsPath, "utf8");
|
|
1201
1255
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
1202
1256
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
1203
1257
|
if (kind !== "files") {
|
|
@@ -1217,10 +1271,10 @@ function readRawTaskEntry(configPath, taskId) {
|
|
|
1217
1271
|
return isPlainRecord2(entry) ? entry : null;
|
|
1218
1272
|
}
|
|
1219
1273
|
function readRawTaskConfig(configPath) {
|
|
1220
|
-
if (!
|
|
1274
|
+
if (!existsSync10(configPath)) {
|
|
1221
1275
|
return null;
|
|
1222
1276
|
}
|
|
1223
|
-
const parsed = JSON.parse(
|
|
1277
|
+
const parsed = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
1224
1278
|
return isPlainRecord2(parsed) ? parsed : null;
|
|
1225
1279
|
}
|
|
1226
1280
|
function stripLegacyTaskConfigMetadata2(raw) {
|
|
@@ -1228,12 +1282,12 @@ function stripLegacyTaskConfigMetadata2(raw) {
|
|
|
1228
1282
|
return tasks;
|
|
1229
1283
|
}
|
|
1230
1284
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
1231
|
-
const directory =
|
|
1232
|
-
if (!
|
|
1285
|
+
const directory = resolve10(projectRoot, sourcePath);
|
|
1286
|
+
if (!existsSync10(directory)) {
|
|
1233
1287
|
return [];
|
|
1234
1288
|
}
|
|
1235
1289
|
const tasks = [];
|
|
1236
|
-
for (const name of
|
|
1290
|
+
for (const name of readdirSync3(directory)) {
|
|
1237
1291
|
if (!FILE_TASK_PATTERN.test(name))
|
|
1238
1292
|
continue;
|
|
1239
1293
|
const inferredId = basename3(name).replace(FILE_TASK_PATTERN, "");
|
|
@@ -1244,11 +1298,11 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
1244
1298
|
return tasks;
|
|
1245
1299
|
}
|
|
1246
1300
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
1247
|
-
const file = findFileBackedTaskFile(
|
|
1301
|
+
const file = findFileBackedTaskFile(resolve10(projectRoot, sourcePath), taskId);
|
|
1248
1302
|
if (!file) {
|
|
1249
1303
|
return null;
|
|
1250
1304
|
}
|
|
1251
|
-
const raw = JSON.parse(
|
|
1305
|
+
const raw = JSON.parse(readFileSync7(file, "utf8"));
|
|
1252
1306
|
if (!isPlainRecord2(raw)) {
|
|
1253
1307
|
return null;
|
|
1254
1308
|
}
|
|
@@ -1261,17 +1315,17 @@ function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
|
1261
1315
|
};
|
|
1262
1316
|
}
|
|
1263
1317
|
function findFileBackedTaskFile(directory, taskId) {
|
|
1264
|
-
if (!
|
|
1318
|
+
if (!existsSync10(directory)) {
|
|
1265
1319
|
return null;
|
|
1266
1320
|
}
|
|
1267
|
-
for (const name of
|
|
1321
|
+
for (const name of readdirSync3(directory)) {
|
|
1268
1322
|
if (!FILE_TASK_PATTERN.test(name))
|
|
1269
1323
|
continue;
|
|
1270
1324
|
const file = join2(directory, name);
|
|
1271
1325
|
try {
|
|
1272
1326
|
if (!statSync3(file).isFile())
|
|
1273
1327
|
continue;
|
|
1274
|
-
const raw = JSON.parse(
|
|
1328
|
+
const raw = JSON.parse(readFileSync7(file, "utf8"));
|
|
1275
1329
|
const inferredId = basename3(file).replace(FILE_TASK_PATTERN, "");
|
|
1276
1330
|
const id = isPlainRecord2(raw) && typeof raw.id === "string" ? raw.id : inferredId;
|
|
1277
1331
|
if (id === taskId) {
|
|
@@ -1431,12 +1485,12 @@ async function readConfiguredTaskSourceTask(projectRoot, taskId) {
|
|
|
1431
1485
|
}
|
|
1432
1486
|
|
|
1433
1487
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
1434
|
-
import { existsSync as
|
|
1435
|
-
import { dirname as dirname7, resolve as
|
|
1488
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync6, rmSync as rmSync4, statSync as statSync4 } from "fs";
|
|
1489
|
+
import { dirname as dirname7, resolve as resolve14 } from "path";
|
|
1436
1490
|
|
|
1437
1491
|
// packages/runtime/src/binary-run.ts
|
|
1438
|
-
import { chmodSync, cpSync, existsSync as
|
|
1439
|
-
import { basename as basename4, dirname as dirname6, resolve as
|
|
1492
|
+
import { chmodSync, cpSync, existsSync as existsSync11, mkdirSync as mkdirSync5, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
1493
|
+
import { basename as basename4, dirname as dirname6, resolve as resolve11 } from "path";
|
|
1440
1494
|
import { fileURLToPath } from "url";
|
|
1441
1495
|
import { drainMicrotasks, gcAndSweep } from "bun:jsc";
|
|
1442
1496
|
var runtimeBinaryBuildQueue = Promise.resolve();
|
|
@@ -1462,9 +1516,9 @@ async function buildRuntimeBinary(options) {
|
|
|
1462
1516
|
});
|
|
1463
1517
|
}
|
|
1464
1518
|
async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
1465
|
-
const tempBuildDir =
|
|
1466
|
-
const tempOutputPath =
|
|
1467
|
-
|
|
1519
|
+
const tempBuildDir = resolve11(dirname6(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
1520
|
+
const tempOutputPath = resolve11(tempBuildDir, basename4(options.outputPath));
|
|
1521
|
+
mkdirSync5(tempBuildDir, { recursive: true });
|
|
1468
1522
|
await withTemporaryEnv({
|
|
1469
1523
|
...options.env,
|
|
1470
1524
|
...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
|
|
@@ -1489,7 +1543,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
1489
1543
|
`);
|
|
1490
1544
|
throw new Error(`Failed to build ${options.entrypoint}: ${details || "Bun.build() returned errors"}`);
|
|
1491
1545
|
}
|
|
1492
|
-
if (!
|
|
1546
|
+
if (!existsSync11(tempOutputPath)) {
|
|
1493
1547
|
const emitted = buildResult.outputs.map((output) => output.path).join(", ") || "(none)";
|
|
1494
1548
|
throw new Error(`Failed to build ${options.entrypoint}: Bun.build() did not emit ${tempOutputPath}. Emitted: ${emitted}`);
|
|
1495
1549
|
}
|
|
@@ -1504,7 +1558,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
1504
1558
|
});
|
|
1505
1559
|
}
|
|
1506
1560
|
})).finally(() => {
|
|
1507
|
-
|
|
1561
|
+
rmSync3(tempBuildDir, { recursive: true, force: true });
|
|
1508
1562
|
});
|
|
1509
1563
|
}
|
|
1510
1564
|
function runBestEffortBuildGc() {
|
|
@@ -1521,8 +1575,8 @@ function runtimeBinaryCacheManifestPath(outputPath) {
|
|
|
1521
1575
|
function resolveRuntimeBinaryBuildOptions(options) {
|
|
1522
1576
|
return {
|
|
1523
1577
|
...options,
|
|
1524
|
-
entrypoint:
|
|
1525
|
-
outputPath:
|
|
1578
|
+
entrypoint: resolve11(options.cwd, options.sourcePath),
|
|
1579
|
+
outputPath: resolve11(options.outputPath)
|
|
1526
1580
|
};
|
|
1527
1581
|
}
|
|
1528
1582
|
function shouldUseRuntimeBinaryBuildWorker() {
|
|
@@ -1536,7 +1590,7 @@ function shouldUseRuntimeBinaryBuildWorker() {
|
|
|
1536
1590
|
}
|
|
1537
1591
|
async function buildRuntimeBinaryViaWorker(options) {
|
|
1538
1592
|
const workerSourcePath = resolveRuntimeBinaryBuildWorkerSourcePath(options);
|
|
1539
|
-
if (!workerSourcePath || !
|
|
1593
|
+
if (!workerSourcePath || !existsSync11(workerSourcePath)) {
|
|
1540
1594
|
await buildRuntimeBinaryInProcess(options, {
|
|
1541
1595
|
manifestPath: runtimeBinaryCacheManifestPath(options.outputPath),
|
|
1542
1596
|
buildKey: createRuntimeBinaryBuildKey({
|
|
@@ -1567,13 +1621,13 @@ async function buildRuntimeBinaryViaWorker(options) {
|
|
|
1567
1621
|
new Response(build.stdout).text(),
|
|
1568
1622
|
new Response(build.stderr).text()
|
|
1569
1623
|
]);
|
|
1570
|
-
|
|
1624
|
+
rmSync3(payloadPath, { force: true });
|
|
1571
1625
|
if (exitCode !== 0) {
|
|
1572
1626
|
throw new Error(`Failed to build ${options.entrypoint}: ${(stderr || stdout || `worker exited ${exitCode}`).trim()}`);
|
|
1573
1627
|
}
|
|
1574
1628
|
}
|
|
1575
1629
|
function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
|
|
1576
|
-
return
|
|
1630
|
+
return resolve11(dirname6(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
1577
1631
|
}
|
|
1578
1632
|
function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
1579
1633
|
const envRoots = [
|
|
@@ -1582,13 +1636,13 @@ function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
|
1582
1636
|
process.env.PROJECT_RIG_ROOT?.trim()
|
|
1583
1637
|
].filter(Boolean);
|
|
1584
1638
|
for (const root of envRoots) {
|
|
1585
|
-
const candidate =
|
|
1586
|
-
if (
|
|
1639
|
+
const candidate = resolve11(root, "packages/runtime/src/binary-build-worker.ts");
|
|
1640
|
+
if (existsSync11(candidate)) {
|
|
1587
1641
|
return candidate;
|
|
1588
1642
|
}
|
|
1589
1643
|
}
|
|
1590
|
-
const localCandidate =
|
|
1591
|
-
return
|
|
1644
|
+
const localCandidate = resolve11(import.meta.dir, "binary-build-worker.ts");
|
|
1645
|
+
return existsSync11(localCandidate) ? localCandidate : null;
|
|
1592
1646
|
}
|
|
1593
1647
|
function resolveRuntimeBinaryBuildWorkerInvocation() {
|
|
1594
1648
|
const bunPath = Bun.which("bun");
|
|
@@ -1624,7 +1678,7 @@ function createRuntimeBinaryBuildKey(input) {
|
|
|
1624
1678
|
});
|
|
1625
1679
|
}
|
|
1626
1680
|
async function isRuntimeBinaryBuildFresh(input) {
|
|
1627
|
-
if (!
|
|
1681
|
+
if (!existsSync11(input.outputPath) || !existsSync11(input.manifestPath)) {
|
|
1628
1682
|
return false;
|
|
1629
1683
|
}
|
|
1630
1684
|
let manifest = null;
|
|
@@ -1637,7 +1691,7 @@ async function isRuntimeBinaryBuildFresh(input) {
|
|
|
1637
1691
|
return false;
|
|
1638
1692
|
}
|
|
1639
1693
|
for (const [filePath, expectedDigest] of Object.entries(manifest.inputs || {})) {
|
|
1640
|
-
if (!
|
|
1694
|
+
if (!existsSync11(filePath)) {
|
|
1641
1695
|
return false;
|
|
1642
1696
|
}
|
|
1643
1697
|
if (await sha256File(filePath) !== expectedDigest) {
|
|
@@ -1650,7 +1704,7 @@ async function writeRuntimeBinaryCacheManifest(input) {
|
|
|
1650
1704
|
const inputs = {};
|
|
1651
1705
|
for (const inputPath of Object.keys(input.metafile?.inputs || {}).sort()) {
|
|
1652
1706
|
const normalized = normalizeBuildInputPath(input.cwd, inputPath);
|
|
1653
|
-
if (!normalized || !
|
|
1707
|
+
if (!normalized || !existsSync11(normalized)) {
|
|
1654
1708
|
continue;
|
|
1655
1709
|
}
|
|
1656
1710
|
inputs[normalized] = await sha256File(normalized);
|
|
@@ -1673,7 +1727,7 @@ function normalizeBuildInputPath(cwd, inputPath) {
|
|
|
1673
1727
|
if (inputPath.startsWith("<")) {
|
|
1674
1728
|
return null;
|
|
1675
1729
|
}
|
|
1676
|
-
return
|
|
1730
|
+
return resolve11(cwd, inputPath);
|
|
1677
1731
|
}
|
|
1678
1732
|
async function sha256File(path) {
|
|
1679
1733
|
const hasher = new Bun.CryptoHasher("sha256");
|
|
@@ -1689,8 +1743,8 @@ function sortRecord(value) {
|
|
|
1689
1743
|
async function runSerializedRuntimeBinaryBuild(action) {
|
|
1690
1744
|
const previous = runtimeBinaryBuildQueue;
|
|
1691
1745
|
let release;
|
|
1692
|
-
runtimeBinaryBuildQueue = new Promise((
|
|
1693
|
-
release =
|
|
1746
|
+
runtimeBinaryBuildQueue = new Promise((resolve12) => {
|
|
1747
|
+
release = resolve12;
|
|
1694
1748
|
});
|
|
1695
1749
|
await previous;
|
|
1696
1750
|
try {
|
|
@@ -1735,11 +1789,11 @@ async function withTemporaryCwd(cwd, action) {
|
|
|
1735
1789
|
}
|
|
1736
1790
|
|
|
1737
1791
|
// packages/runtime/src/control-plane/runtime/provisioning-env.ts
|
|
1738
|
-
import { delimiter, resolve as
|
|
1792
|
+
import { delimiter, resolve as resolve13 } from "path";
|
|
1739
1793
|
|
|
1740
1794
|
// packages/runtime/src/control-plane/runtime/runtime-paths.ts
|
|
1741
|
-
import { existsSync as
|
|
1742
|
-
import { resolve as
|
|
1795
|
+
import { existsSync as existsSync12, readdirSync as readdirSync4, realpathSync } from "fs";
|
|
1796
|
+
import { resolve as resolve12 } from "path";
|
|
1743
1797
|
|
|
1744
1798
|
// packages/runtime/src/control-plane/runtime/sandbox/utils.ts
|
|
1745
1799
|
function uniq(values) {
|
|
@@ -1757,7 +1811,7 @@ function resolveBunBinaryPath() {
|
|
|
1757
1811
|
}
|
|
1758
1812
|
const home = process.env.HOME?.trim();
|
|
1759
1813
|
const fallbackCandidates = [
|
|
1760
|
-
home ?
|
|
1814
|
+
home ? resolve12(home, ".bun/bin/bun") : "",
|
|
1761
1815
|
"/opt/homebrew/bin/bun",
|
|
1762
1816
|
"/usr/local/bin/bun",
|
|
1763
1817
|
"/usr/bin/bun"
|
|
@@ -1785,8 +1839,8 @@ function resolveClaudeBinaryPath() {
|
|
|
1785
1839
|
}
|
|
1786
1840
|
const home = process.env.HOME?.trim();
|
|
1787
1841
|
const fallbackCandidates = [
|
|
1788
|
-
home ?
|
|
1789
|
-
home ?
|
|
1842
|
+
home ? resolve12(home, ".local/bin/claude") : "",
|
|
1843
|
+
home ? resolve12(home, ".local/share/claude/local/claude") : "",
|
|
1790
1844
|
"/opt/homebrew/bin/claude",
|
|
1791
1845
|
"/usr/local/bin/claude",
|
|
1792
1846
|
"/usr/bin/claude"
|
|
@@ -1800,51 +1854,51 @@ function resolveClaudeBinaryPath() {
|
|
|
1800
1854
|
throw new Error("claude not found in PATH");
|
|
1801
1855
|
}
|
|
1802
1856
|
function resolveBunInstallDir(bunBinaryPath = resolveBunBinaryPath()) {
|
|
1803
|
-
return
|
|
1857
|
+
return resolve12(bunBinaryPath, "../..");
|
|
1804
1858
|
}
|
|
1805
1859
|
function resolveClaudeInstallDir() {
|
|
1806
1860
|
const realPath = resolveClaudeBinaryPath();
|
|
1807
|
-
return
|
|
1861
|
+
return resolve12(realPath, "..");
|
|
1808
1862
|
}
|
|
1809
1863
|
function resolveNodeInstallDir() {
|
|
1810
1864
|
const preferredNode = resolvePreferredNodeBinary();
|
|
1811
1865
|
if (!preferredNode)
|
|
1812
1866
|
return null;
|
|
1813
1867
|
const explicitNode = process.env.RIG_NODE_BIN?.trim();
|
|
1814
|
-
if (explicitNode &&
|
|
1815
|
-
return preferredNode.endsWith("/bin/node") ?
|
|
1868
|
+
if (explicitNode && resolve12(explicitNode) === resolve12(preferredNode)) {
|
|
1869
|
+
return preferredNode.endsWith("/bin/node") ? resolve12(preferredNode, "../..") : resolve12(preferredNode, "..");
|
|
1816
1870
|
}
|
|
1817
1871
|
try {
|
|
1818
1872
|
const realPath = realpathSync(preferredNode);
|
|
1819
1873
|
if (realPath.endsWith("/bin/node")) {
|
|
1820
|
-
return
|
|
1874
|
+
return resolve12(realPath, "../..");
|
|
1821
1875
|
}
|
|
1822
|
-
return
|
|
1876
|
+
return resolve12(realPath, "..");
|
|
1823
1877
|
} catch {
|
|
1824
|
-
return
|
|
1878
|
+
return resolve12(preferredNode, "..");
|
|
1825
1879
|
}
|
|
1826
1880
|
}
|
|
1827
1881
|
function resolvePreferredNodeBinary() {
|
|
1828
1882
|
const candidates = [];
|
|
1829
1883
|
const envNode = process.env.RIG_NODE_BIN?.trim();
|
|
1830
1884
|
if (envNode) {
|
|
1831
|
-
const explicit =
|
|
1832
|
-
if (
|
|
1885
|
+
const explicit = resolve12(envNode);
|
|
1886
|
+
if (existsSync12(explicit)) {
|
|
1833
1887
|
return explicit;
|
|
1834
1888
|
}
|
|
1835
1889
|
}
|
|
1836
1890
|
const nvmBin = process.env.NVM_BIN?.trim();
|
|
1837
1891
|
if (nvmBin) {
|
|
1838
|
-
candidates.push(
|
|
1892
|
+
candidates.push(resolve12(nvmBin, "node"));
|
|
1839
1893
|
}
|
|
1840
1894
|
const home = process.env.HOME?.trim();
|
|
1841
1895
|
if (home) {
|
|
1842
|
-
const nvmVersionsDir =
|
|
1843
|
-
if (
|
|
1896
|
+
const nvmVersionsDir = resolve12(home, ".nvm/versions/node");
|
|
1897
|
+
if (existsSync12(nvmVersionsDir)) {
|
|
1844
1898
|
try {
|
|
1845
|
-
const versionDirs =
|
|
1899
|
+
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/, "")));
|
|
1846
1900
|
for (const versionDir of versionDirs) {
|
|
1847
|
-
candidates.push(
|
|
1901
|
+
candidates.push(resolve12(nvmVersionsDir, versionDir, "bin/node"));
|
|
1848
1902
|
}
|
|
1849
1903
|
} catch {}
|
|
1850
1904
|
}
|
|
@@ -1853,8 +1907,8 @@ function resolvePreferredNodeBinary() {
|
|
|
1853
1907
|
if (whichNode) {
|
|
1854
1908
|
candidates.push(whichNode);
|
|
1855
1909
|
}
|
|
1856
|
-
const deduped = uniq(candidates.map((candidate) =>
|
|
1857
|
-
const existing = deduped.filter((candidate) =>
|
|
1910
|
+
const deduped = uniq(candidates.map((candidate) => resolve12(candidate)));
|
|
1911
|
+
const existing = deduped.filter((candidate) => existsSync12(candidate));
|
|
1858
1912
|
if (existing.length === 0) {
|
|
1859
1913
|
return null;
|
|
1860
1914
|
}
|
|
@@ -1868,7 +1922,7 @@ function resolvePreferredNodeBinary() {
|
|
|
1868
1922
|
return existing[0] ?? null;
|
|
1869
1923
|
}
|
|
1870
1924
|
function inferNodeMajor(nodeBinaryPath) {
|
|
1871
|
-
const normalized =
|
|
1925
|
+
const normalized = resolve12(nodeBinaryPath).replace(/\\/g, "/");
|
|
1872
1926
|
const match = normalized.match(/(?:^|\/)(?:node-)?v?(\d+)\.\d+\.\d+(?:\/|$)/);
|
|
1873
1927
|
if (!match) {
|
|
1874
1928
|
return null;
|
|
@@ -1880,8 +1934,8 @@ function normalizeExecutablePath(candidate) {
|
|
|
1880
1934
|
if (!candidate) {
|
|
1881
1935
|
return "";
|
|
1882
1936
|
}
|
|
1883
|
-
const normalized =
|
|
1884
|
-
if (!
|
|
1937
|
+
const normalized = resolve12(candidate);
|
|
1938
|
+
if (!existsSync12(normalized)) {
|
|
1885
1939
|
return "";
|
|
1886
1940
|
}
|
|
1887
1941
|
try {
|
|
@@ -1891,7 +1945,7 @@ function normalizeExecutablePath(candidate) {
|
|
|
1891
1945
|
}
|
|
1892
1946
|
}
|
|
1893
1947
|
function looksLikeRuntimeGateway(candidate) {
|
|
1894
|
-
const normalized =
|
|
1948
|
+
const normalized = resolve12(candidate).replace(/\\/g, "/");
|
|
1895
1949
|
return normalized.includes("/.rig/bin/") || normalized.endsWith("/rig-shell") || normalized.endsWith("/rig-agent");
|
|
1896
1950
|
}
|
|
1897
1951
|
|
|
@@ -1912,7 +1966,7 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
1912
1966
|
try {
|
|
1913
1967
|
return resolveClaudeInstallDir();
|
|
1914
1968
|
} catch {
|
|
1915
|
-
return
|
|
1969
|
+
return resolve13(claudeBinary, "..");
|
|
1916
1970
|
}
|
|
1917
1971
|
})() : "";
|
|
1918
1972
|
const nodeDir = resolveNodeInstallDir();
|
|
@@ -1922,8 +1976,8 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
1922
1976
|
`${bunDir}/bin`,
|
|
1923
1977
|
claudeDir,
|
|
1924
1978
|
nodeDir ? `${nodeDir}/bin` : "",
|
|
1925
|
-
realHome ?
|
|
1926
|
-
realHome ?
|
|
1979
|
+
realHome ? resolve13(realHome, ".local/bin") : "",
|
|
1980
|
+
realHome ? resolve13(realHome, ".cargo/bin") : "",
|
|
1927
1981
|
...inheritedPath,
|
|
1928
1982
|
"/usr/local/bin",
|
|
1929
1983
|
"/usr/local/sbin",
|
|
@@ -1954,9 +2008,9 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
1954
2008
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
1955
2009
|
function resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext) {
|
|
1956
2010
|
if (runtimeContext) {
|
|
1957
|
-
return
|
|
2011
|
+
return resolve14(runtimeContext.binDir, "validators", binaryName);
|
|
1958
2012
|
}
|
|
1959
|
-
return
|
|
2013
|
+
return resolve14(resolveHarnessPaths(projectRoot).binDir, "validators", binaryName);
|
|
1960
2014
|
}
|
|
1961
2015
|
async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
1962
2016
|
const match = checkId.match(/^([a-z][\w-]*):([a-z][\w-]*)$/);
|
|
@@ -1971,19 +2025,19 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
1971
2025
|
const binaryName = `${category}-${check}`;
|
|
1972
2026
|
const binaryPath = resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
1973
2027
|
const hostProjectRoot = runtimeContext?.hostProjectRoot?.trim() || projectRoot;
|
|
1974
|
-
const sourcePath =
|
|
1975
|
-
if (!
|
|
2028
|
+
const sourcePath = resolve14(hostProjectRoot, "packages/runtime/src/control-plane/validators", category, `${check}.ts`);
|
|
2029
|
+
if (!existsSync13(sourcePath)) {
|
|
1976
2030
|
return null;
|
|
1977
2031
|
}
|
|
1978
2032
|
const sourceMtime = statSync4(sourcePath).mtimeMs;
|
|
1979
|
-
const binaryExists =
|
|
2033
|
+
const binaryExists = existsSync13(binaryPath);
|
|
1980
2034
|
const binaryMtime = binaryExists ? statSync4(binaryPath).mtimeMs : 0;
|
|
1981
2035
|
if (!binaryExists || sourceMtime > binaryMtime) {
|
|
1982
2036
|
if (binaryExists) {
|
|
1983
|
-
|
|
1984
|
-
|
|
2037
|
+
rmSync4(binaryPath, { force: true });
|
|
2038
|
+
rmSync4(`${binaryPath}.build-manifest.json`, { force: true });
|
|
1985
2039
|
}
|
|
1986
|
-
|
|
2040
|
+
mkdirSync6(dirname7(binaryPath), { recursive: true });
|
|
1987
2041
|
await buildRuntimeBinary({
|
|
1988
2042
|
sourcePath: `packages/runtime/src/control-plane/validators/${category}/${check}.ts`,
|
|
1989
2043
|
outputPath: binaryPath,
|
|
@@ -1992,7 +2046,7 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
1992
2046
|
env: runtimeProvisioningEnv()
|
|
1993
2047
|
});
|
|
1994
2048
|
}
|
|
1995
|
-
return
|
|
2049
|
+
return existsSync13(binaryPath) ? binaryPath : null;
|
|
1996
2050
|
}
|
|
1997
2051
|
|
|
1998
2052
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
@@ -2029,20 +2083,20 @@ async function readTaskSourceValidation(projectRoot, taskId) {
|
|
|
2029
2083
|
function resolveValidationPaths(projectRoot, taskId, runtimeContext) {
|
|
2030
2084
|
if (runtimeContext) {
|
|
2031
2085
|
return {
|
|
2032
|
-
taskLogDir:
|
|
2033
|
-
artifactDir:
|
|
2086
|
+
taskLogDir: resolve15(runtimeContext.logsDir, taskId),
|
|
2087
|
+
artifactDir: resolve15(runtimeContext.workspaceDir, "artifacts", taskId)
|
|
2034
2088
|
};
|
|
2035
2089
|
}
|
|
2036
2090
|
const paths = resolveHarnessPaths(projectRoot);
|
|
2037
2091
|
return {
|
|
2038
|
-
taskLogDir:
|
|
2039
|
-
artifactDir:
|
|
2092
|
+
taskLogDir: resolve15(paths.logsDir, taskId),
|
|
2093
|
+
artifactDir: resolve15(paths.artifactsDir, taskId)
|
|
2040
2094
|
};
|
|
2041
2095
|
}
|
|
2042
2096
|
async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext) {
|
|
2043
2097
|
const binaryName = checkId.replace(":", "-");
|
|
2044
2098
|
const binaryPath = await ensureValidatorBinary(projectRoot, checkId, runtimeContext) ?? resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
2045
|
-
if (!
|
|
2099
|
+
if (!existsSync14(binaryPath)) {
|
|
2046
2100
|
return {
|
|
2047
2101
|
result: {
|
|
2048
2102
|
id: checkId,
|
|
@@ -2053,7 +2107,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
2053
2107
|
};
|
|
2054
2108
|
}
|
|
2055
2109
|
const validatorCwd = runtimeContext?.workspaceDir || resolveMonorepoRoot(projectRoot);
|
|
2056
|
-
const runtimeShellPath = runtimeContext ?
|
|
2110
|
+
const runtimeShellPath = runtimeContext ? resolve15(runtimeContext.binDir, "rig-shell") : "";
|
|
2057
2111
|
const monorepoMainRoot = runtimeContext?.monorepoMainRoot || process.env.MONOREPO_MAIN_ROOT?.trim() || resolveMonorepoRoot(projectRoot);
|
|
2058
2112
|
const validatorEnv = {
|
|
2059
2113
|
PROJECT_RIG_ROOT: runtimeContext?.hostProjectRoot || projectRoot,
|
|
@@ -2068,7 +2122,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
2068
2122
|
validatorEnv.RIG_LOGS_DIR = runtimeContext.logsDir;
|
|
2069
2123
|
validatorEnv.RIG_RUNTIME_BIN_DIR = runtimeContext.binDir;
|
|
2070
2124
|
}
|
|
2071
|
-
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath &&
|
|
2125
|
+
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath && existsSync14(runtimeShellPath) ? [runtimeShellPath, "run-binary", binaryPath] : [binaryPath], validatorCwd, validatorEnv);
|
|
2072
2126
|
try {
|
|
2073
2127
|
const result = JSON.parse(stdout.trim());
|
|
2074
2128
|
return { result, exitCode };
|
|
@@ -2108,8 +2162,8 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
2108
2162
|
const configuredValidation = stringArray(taskConfig[taskId]?.validation);
|
|
2109
2163
|
const commands = resolvedContext?.validation?.length ? resolvedContext.validation : configuredValidation.length > 0 ? configuredValidation : sourceValidation.validation;
|
|
2110
2164
|
const { taskLogDir, artifactDir } = resolveValidationPaths(projectRoot, taskId, resolvedContext);
|
|
2111
|
-
|
|
2112
|
-
|
|
2165
|
+
mkdirSync7(taskLogDir, { recursive: true });
|
|
2166
|
+
mkdirSync7(artifactDir, { recursive: true });
|
|
2113
2167
|
if (commands.length === 0) {
|
|
2114
2168
|
const skipped = {
|
|
2115
2169
|
status: "skipped",
|
|
@@ -2118,7 +2172,7 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
2118
2172
|
failed: 0,
|
|
2119
2173
|
categories: []
|
|
2120
2174
|
};
|
|
2121
|
-
|
|
2175
|
+
writeFileSync7(resolve15(artifactDir, "validation-summary.json"), `${JSON.stringify(skipped, null, 2)}
|
|
2122
2176
|
`, "utf-8");
|
|
2123
2177
|
return skipped;
|
|
2124
2178
|
}
|
|
@@ -2153,18 +2207,18 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
2153
2207
|
exit_code: 2,
|
|
2154
2208
|
duration_seconds: 0
|
|
2155
2209
|
});
|
|
2156
|
-
const logFile2 =
|
|
2157
|
-
|
|
2158
|
-
|
|
2210
|
+
const logFile2 = resolve15(taskLogDir, `invalid-entry-validation.log`);
|
|
2211
|
+
mkdirSync7(taskLogDir, { recursive: true });
|
|
2212
|
+
writeFileSync7(logFile2, `=== ${nowIso()} :: ${cmd} ===
|
|
2159
2213
|
Invalid validation entry: not a check-ID. All entries must use format "category:check-name".
|
|
2160
2214
|
`, "utf-8");
|
|
2161
2215
|
continue;
|
|
2162
2216
|
}
|
|
2163
2217
|
const { result, exitCode } = await dispatchValidator(cmd, effectiveRegistry, validatorCtx, (id) => runValidatorBinary(projectRoot, taskId, id, resolvedContext));
|
|
2164
2218
|
const durationSeconds = Math.max(0, Math.round((Date.now() - startedAt) / 1000));
|
|
2165
|
-
const logFile =
|
|
2166
|
-
|
|
2167
|
-
|
|
2219
|
+
const logFile = resolve15(taskLogDir, `${cmd.replace(":", "-")}-validation.log`);
|
|
2220
|
+
mkdirSync7(taskLogDir, { recursive: true });
|
|
2221
|
+
writeFileSync7(logFile, `=== ${nowIso()} :: ${cmd} ===
|
|
2168
2222
|
${JSON.stringify(result, null, 2)}
|
|
2169
2223
|
`, "utf-8");
|
|
2170
2224
|
if (result.passed) {
|
|
@@ -2186,8 +2240,8 @@ ${JSON.stringify(result, null, 2)}
|
|
|
2186
2240
|
failed,
|
|
2187
2241
|
categories
|
|
2188
2242
|
};
|
|
2189
|
-
|
|
2190
|
-
|
|
2243
|
+
mkdirSync7(artifactDir, { recursive: true });
|
|
2244
|
+
writeFileSync7(resolve15(artifactDir, "validation-summary.json"), `${JSON.stringify(summary, null, 2)}
|
|
2191
2245
|
`, "utf-8");
|
|
2192
2246
|
return summary;
|
|
2193
2247
|
}
|