@h-rig/runtime 0.0.6-alpha.33 → 0.0.6-alpha.35
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 +518 -459
- package/dist/bin/rig-agent.js +431 -362
- package/dist/src/control-plane/agent-wrapper.js +523 -464
- package/dist/src/control-plane/harness-main.js +529 -459
- package/dist/src/control-plane/hooks/completion-verification.js +353 -283
- package/dist/src/control-plane/hooks/inject-context.js +158 -99
- package/dist/src/control-plane/hooks/submodule-branch.js +538 -479
- package/dist/src/control-plane/hooks/task-runtime-start.js +538 -479
- package/dist/src/control-plane/materialize-task-config.js +68 -8
- package/dist/src/control-plane/native/git-ops.js +11 -1
- package/dist/src/control-plane/native/harness-cli.js +514 -444
- package/dist/src/control-plane/native/task-ops.js +392 -322
- package/dist/src/control-plane/native/validator.js +159 -100
- package/dist/src/control-plane/native/verifier.js +227 -166
- package/dist/src/control-plane/pi-sessiond/bin.js +62 -0
- package/dist/src/control-plane/pi-sessiond/server.js +62 -0
- package/dist/src/control-plane/pi-sessiond/session-service.js +62 -0
- package/dist/src/control-plane/pi-settings-materializer.js +52 -0
- package/dist/src/control-plane/plugin-host-context.js +59 -0
- package/dist/src/control-plane/runtime/index.js +469 -410
- package/dist/src/control-plane/runtime/isolation/index.js +493 -434
- package/dist/src/control-plane/runtime/isolation.js +493 -434
- package/dist/src/control-plane/runtime/queue.js +411 -352
- package/dist/src/control-plane/tasks/source-lifecycle.js +87 -28
- package/package.json +8 -8
|
@@ -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 existsSync16, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
4
|
+
import { resolve as resolve16 } from "path";
|
|
5
5
|
|
|
6
6
|
// packages/runtime/src/layout.ts
|
|
7
7
|
import { existsSync } from "fs";
|
|
@@ -678,6 +678,8 @@ function sourceTaskConfigCandidates(projectRoot) {
|
|
|
678
678
|
}
|
|
679
679
|
|
|
680
680
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
681
|
+
import { existsSync as existsSync10 } from "fs";
|
|
682
|
+
import { resolve as resolvePath } from "path";
|
|
681
683
|
import { createPluginHost } from "@rig/core";
|
|
682
684
|
import { loadConfig } from "@rig/core/load-config";
|
|
683
685
|
|
|
@@ -959,6 +961,55 @@ async function materializeSkills(projectRoot, entries) {
|
|
|
959
961
|
return written;
|
|
960
962
|
}
|
|
961
963
|
|
|
964
|
+
// packages/runtime/src/control-plane/pi-settings-materializer.ts
|
|
965
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
966
|
+
import { dirname as dirname6, resolve as resolve9 } from "path";
|
|
967
|
+
var SETTINGS_RELATIVE_PATH = ".pi/settings.json";
|
|
968
|
+
var MANAGED_RECORD_RELATIVE_PATH = ".rig/state/pi-managed-packages.json";
|
|
969
|
+
function readJson(path, fallback) {
|
|
970
|
+
if (!existsSync9(path))
|
|
971
|
+
return fallback;
|
|
972
|
+
try {
|
|
973
|
+
return JSON.parse(readFileSync6(path, "utf-8"));
|
|
974
|
+
} catch {
|
|
975
|
+
return fallback;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
function packageKey(entry) {
|
|
979
|
+
if (typeof entry === "string")
|
|
980
|
+
return entry;
|
|
981
|
+
if (entry && typeof entry === "object" && typeof entry.source === "string") {
|
|
982
|
+
return entry.source;
|
|
983
|
+
}
|
|
984
|
+
return JSON.stringify(entry);
|
|
985
|
+
}
|
|
986
|
+
function materializePiPackages(projectRoot, declaredPackages) {
|
|
987
|
+
const settingsPath = resolve9(projectRoot, SETTINGS_RELATIVE_PATH);
|
|
988
|
+
const managedRecordPath = resolve9(projectRoot, MANAGED_RECORD_RELATIVE_PATH);
|
|
989
|
+
const settings = readJson(settingsPath, {});
|
|
990
|
+
const previouslyManaged = new Set(readJson(managedRecordPath, []));
|
|
991
|
+
const existing = Array.isArray(settings.packages) ? settings.packages : [];
|
|
992
|
+
const operatorEntries = existing.filter((entry) => !previouslyManaged.has(packageKey(entry)));
|
|
993
|
+
const operatorKeys = new Set(operatorEntries.map(packageKey));
|
|
994
|
+
const managedToAdd = declaredPackages.filter((pkg) => !operatorKeys.has(pkg));
|
|
995
|
+
const nextPackages = [...operatorEntries, ...managedToAdd];
|
|
996
|
+
if (nextPackages.length > 0 || existsSync9(settingsPath)) {
|
|
997
|
+
const nextSettings = { ...settings };
|
|
998
|
+
if (nextPackages.length > 0) {
|
|
999
|
+
nextSettings.packages = nextPackages;
|
|
1000
|
+
} else {
|
|
1001
|
+
delete nextSettings.packages;
|
|
1002
|
+
}
|
|
1003
|
+
mkdirSync5(dirname6(settingsPath), { recursive: true });
|
|
1004
|
+
writeFileSync5(settingsPath, `${JSON.stringify(nextSettings, null, 2)}
|
|
1005
|
+
`, "utf-8");
|
|
1006
|
+
}
|
|
1007
|
+
mkdirSync5(dirname6(managedRecordPath), { recursive: true });
|
|
1008
|
+
writeFileSync5(managedRecordPath, `${JSON.stringify(managedToAdd, null, 2)}
|
|
1009
|
+
`, "utf-8");
|
|
1010
|
+
return { settingsPath, packages: managedToAdd };
|
|
1011
|
+
}
|
|
1012
|
+
|
|
962
1013
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
963
1014
|
async function buildPluginHostContext(projectRoot) {
|
|
964
1015
|
let config;
|
|
@@ -1006,6 +1057,14 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
1006
1057
|
} catch (err) {
|
|
1007
1058
|
console.warn(`[plugin-host] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
1008
1059
|
}
|
|
1060
|
+
try {
|
|
1061
|
+
const piPackages = config.runtime?.pi?.packages ?? [];
|
|
1062
|
+
if (piPackages.length > 0 || existsSync10(resolvePath(projectRoot, ".rig/state/pi-managed-packages.json"))) {
|
|
1063
|
+
materializePiPackages(projectRoot, piPackages);
|
|
1064
|
+
}
|
|
1065
|
+
} catch (err) {
|
|
1066
|
+
console.warn(`[plugin-host] Pi package materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
1067
|
+
}
|
|
1009
1068
|
return {
|
|
1010
1069
|
config,
|
|
1011
1070
|
pluginHost,
|
|
@@ -1019,12 +1078,12 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
1019
1078
|
|
|
1020
1079
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
1021
1080
|
import { spawnSync } from "child_process";
|
|
1022
|
-
import { existsSync as
|
|
1023
|
-
import { basename as basename3, join as join2, resolve as
|
|
1081
|
+
import { existsSync as existsSync12, readFileSync as readFileSync8, readdirSync as readdirSync3, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
1082
|
+
import { basename as basename3, join as join2, resolve as resolve11 } from "path";
|
|
1024
1083
|
|
|
1025
1084
|
// packages/runtime/src/control-plane/tasks/legacy-task-config-source.ts
|
|
1026
|
-
import { existsSync as
|
|
1027
|
-
import { resolve as
|
|
1085
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7 } from "fs";
|
|
1086
|
+
import { resolve as resolve10 } from "path";
|
|
1028
1087
|
|
|
1029
1088
|
// packages/runtime/src/control-plane/tasks/task-record-reader.ts
|
|
1030
1089
|
async function findTaskById(reader, id) {
|
|
@@ -1047,7 +1106,7 @@ class LegacyTaskConfigReadError extends Error {
|
|
|
1047
1106
|
}
|
|
1048
1107
|
}
|
|
1049
1108
|
function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
1050
|
-
const configPath = options.configPath ??
|
|
1109
|
+
const configPath = options.configPath ?? resolve10(projectRoot, ".rig", "task-config.json");
|
|
1051
1110
|
const reader = {
|
|
1052
1111
|
async listTasks() {
|
|
1053
1112
|
return readLegacyTaskRecords(projectRoot, configPath);
|
|
@@ -1058,8 +1117,8 @@ function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
|
1058
1117
|
};
|
|
1059
1118
|
return reader;
|
|
1060
1119
|
}
|
|
1061
|
-
function readLegacyTaskRecords(projectRoot, configPath =
|
|
1062
|
-
if (!
|
|
1120
|
+
function readLegacyTaskRecords(projectRoot, configPath = resolve10(projectRoot, ".rig", "task-config.json")) {
|
|
1121
|
+
if (!existsSync11(configPath)) {
|
|
1063
1122
|
return [];
|
|
1064
1123
|
}
|
|
1065
1124
|
const rawConfig = readLegacyTaskConfigJson(projectRoot, configPath);
|
|
@@ -1067,7 +1126,7 @@ function readLegacyTaskRecords(projectRoot, configPath = resolve9(projectRoot, "
|
|
|
1067
1126
|
}
|
|
1068
1127
|
function readLegacyTaskConfigJson(projectRoot, configPath) {
|
|
1069
1128
|
try {
|
|
1070
|
-
const parsed = JSON.parse(
|
|
1129
|
+
const parsed = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
1071
1130
|
if (isPlainRecord(parsed)) {
|
|
1072
1131
|
return parsed;
|
|
1073
1132
|
}
|
|
@@ -1151,7 +1210,7 @@ function isPlainRecord(candidate) {
|
|
|
1151
1210
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
1152
1211
|
var FILE_TASK_PATTERN = /\.(task\.)?json$/;
|
|
1153
1212
|
function createSourceAwareTaskConfigRecordReader(projectRoot, options = {}) {
|
|
1154
|
-
const configPath = options.configPath ??
|
|
1213
|
+
const configPath = options.configPath ?? resolve11(projectRoot, ".rig", "task-config.json");
|
|
1155
1214
|
const legacy = createLegacyTaskConfigRecordReader(projectRoot, { configPath });
|
|
1156
1215
|
const spawnFn = options.spawn ?? spawnSync;
|
|
1157
1216
|
const ghBinary = options.ghBinary ?? "gh";
|
|
@@ -1234,10 +1293,10 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
1234
1293
|
return metadata;
|
|
1235
1294
|
}
|
|
1236
1295
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
1237
|
-
const jsonPath =
|
|
1238
|
-
if (
|
|
1296
|
+
const jsonPath = resolve11(projectRoot, "rig.config.json");
|
|
1297
|
+
if (existsSync12(jsonPath)) {
|
|
1239
1298
|
try {
|
|
1240
|
-
const parsed = JSON.parse(
|
|
1299
|
+
const parsed = JSON.parse(readFileSync8(jsonPath, "utf8"));
|
|
1241
1300
|
if (isPlainRecord2(parsed) && isPlainRecord2(parsed.taskSource)) {
|
|
1242
1301
|
const source = parsed.taskSource;
|
|
1243
1302
|
return source.kind === "files" && typeof source.path === "string" ? source.path : null;
|
|
@@ -1246,12 +1305,12 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
1246
1305
|
return null;
|
|
1247
1306
|
}
|
|
1248
1307
|
}
|
|
1249
|
-
const tsPath =
|
|
1250
|
-
if (!
|
|
1308
|
+
const tsPath = resolve11(projectRoot, "rig.config.ts");
|
|
1309
|
+
if (!existsSync12(tsPath)) {
|
|
1251
1310
|
return null;
|
|
1252
1311
|
}
|
|
1253
1312
|
try {
|
|
1254
|
-
const source =
|
|
1313
|
+
const source = readFileSync8(tsPath, "utf8");
|
|
1255
1314
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
1256
1315
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
1257
1316
|
if (kind !== "files") {
|
|
@@ -1271,10 +1330,10 @@ function readRawTaskEntry(configPath, taskId) {
|
|
|
1271
1330
|
return isPlainRecord2(entry) ? entry : null;
|
|
1272
1331
|
}
|
|
1273
1332
|
function readRawTaskConfig(configPath) {
|
|
1274
|
-
if (!
|
|
1333
|
+
if (!existsSync12(configPath)) {
|
|
1275
1334
|
return null;
|
|
1276
1335
|
}
|
|
1277
|
-
const parsed = JSON.parse(
|
|
1336
|
+
const parsed = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
1278
1337
|
return isPlainRecord2(parsed) ? parsed : null;
|
|
1279
1338
|
}
|
|
1280
1339
|
function stripLegacyTaskConfigMetadata2(raw) {
|
|
@@ -1282,8 +1341,8 @@ function stripLegacyTaskConfigMetadata2(raw) {
|
|
|
1282
1341
|
return tasks;
|
|
1283
1342
|
}
|
|
1284
1343
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
1285
|
-
const directory =
|
|
1286
|
-
if (!
|
|
1344
|
+
const directory = resolve11(projectRoot, sourcePath);
|
|
1345
|
+
if (!existsSync12(directory)) {
|
|
1287
1346
|
return [];
|
|
1288
1347
|
}
|
|
1289
1348
|
const tasks = [];
|
|
@@ -1298,11 +1357,11 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
1298
1357
|
return tasks;
|
|
1299
1358
|
}
|
|
1300
1359
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
1301
|
-
const file = findFileBackedTaskFile(
|
|
1360
|
+
const file = findFileBackedTaskFile(resolve11(projectRoot, sourcePath), taskId);
|
|
1302
1361
|
if (!file) {
|
|
1303
1362
|
return null;
|
|
1304
1363
|
}
|
|
1305
|
-
const raw = JSON.parse(
|
|
1364
|
+
const raw = JSON.parse(readFileSync8(file, "utf8"));
|
|
1306
1365
|
if (!isPlainRecord2(raw)) {
|
|
1307
1366
|
return null;
|
|
1308
1367
|
}
|
|
@@ -1315,7 +1374,7 @@ function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
|
1315
1374
|
};
|
|
1316
1375
|
}
|
|
1317
1376
|
function findFileBackedTaskFile(directory, taskId) {
|
|
1318
|
-
if (!
|
|
1377
|
+
if (!existsSync12(directory)) {
|
|
1319
1378
|
return null;
|
|
1320
1379
|
}
|
|
1321
1380
|
for (const name of readdirSync3(directory)) {
|
|
@@ -1325,7 +1384,7 @@ function findFileBackedTaskFile(directory, taskId) {
|
|
|
1325
1384
|
try {
|
|
1326
1385
|
if (!statSync3(file).isFile())
|
|
1327
1386
|
continue;
|
|
1328
|
-
const raw = JSON.parse(
|
|
1387
|
+
const raw = JSON.parse(readFileSync8(file, "utf8"));
|
|
1329
1388
|
const inferredId = basename3(file).replace(FILE_TASK_PATTERN, "");
|
|
1330
1389
|
const id = isPlainRecord2(raw) && typeof raw.id === "string" ? raw.id : inferredId;
|
|
1331
1390
|
if (id === taskId) {
|
|
@@ -1485,12 +1544,12 @@ async function readConfiguredTaskSourceTask(projectRoot, taskId) {
|
|
|
1485
1544
|
}
|
|
1486
1545
|
|
|
1487
1546
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
1488
|
-
import { existsSync as
|
|
1489
|
-
import { dirname as
|
|
1547
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync7, rmSync as rmSync4, statSync as statSync4 } from "fs";
|
|
1548
|
+
import { dirname as dirname8, resolve as resolve15 } from "path";
|
|
1490
1549
|
|
|
1491
1550
|
// packages/runtime/src/binary-run.ts
|
|
1492
|
-
import { chmodSync, cpSync, existsSync as
|
|
1493
|
-
import { basename as basename4, dirname as
|
|
1551
|
+
import { chmodSync, cpSync, existsSync as existsSync13, mkdirSync as mkdirSync6, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync7 } from "fs";
|
|
1552
|
+
import { basename as basename4, dirname as dirname7, resolve as resolve12 } from "path";
|
|
1494
1553
|
import { fileURLToPath } from "url";
|
|
1495
1554
|
import { drainMicrotasks, gcAndSweep } from "bun:jsc";
|
|
1496
1555
|
var runtimeBinaryBuildQueue = Promise.resolve();
|
|
@@ -1516,9 +1575,9 @@ async function buildRuntimeBinary(options) {
|
|
|
1516
1575
|
});
|
|
1517
1576
|
}
|
|
1518
1577
|
async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
1519
|
-
const tempBuildDir =
|
|
1520
|
-
const tempOutputPath =
|
|
1521
|
-
|
|
1578
|
+
const tempBuildDir = resolve12(dirname7(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
1579
|
+
const tempOutputPath = resolve12(tempBuildDir, basename4(options.outputPath));
|
|
1580
|
+
mkdirSync6(tempBuildDir, { recursive: true });
|
|
1522
1581
|
await withTemporaryEnv({
|
|
1523
1582
|
...options.env,
|
|
1524
1583
|
...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
|
|
@@ -1543,7 +1602,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
1543
1602
|
`);
|
|
1544
1603
|
throw new Error(`Failed to build ${options.entrypoint}: ${details || "Bun.build() returned errors"}`);
|
|
1545
1604
|
}
|
|
1546
|
-
if (!
|
|
1605
|
+
if (!existsSync13(tempOutputPath)) {
|
|
1547
1606
|
const emitted = buildResult.outputs.map((output) => output.path).join(", ") || "(none)";
|
|
1548
1607
|
throw new Error(`Failed to build ${options.entrypoint}: Bun.build() did not emit ${tempOutputPath}. Emitted: ${emitted}`);
|
|
1549
1608
|
}
|
|
@@ -1575,8 +1634,8 @@ function runtimeBinaryCacheManifestPath(outputPath) {
|
|
|
1575
1634
|
function resolveRuntimeBinaryBuildOptions(options) {
|
|
1576
1635
|
return {
|
|
1577
1636
|
...options,
|
|
1578
|
-
entrypoint:
|
|
1579
|
-
outputPath:
|
|
1637
|
+
entrypoint: resolve12(options.cwd, options.sourcePath),
|
|
1638
|
+
outputPath: resolve12(options.outputPath)
|
|
1580
1639
|
};
|
|
1581
1640
|
}
|
|
1582
1641
|
function shouldUseRuntimeBinaryBuildWorker() {
|
|
@@ -1590,7 +1649,7 @@ function shouldUseRuntimeBinaryBuildWorker() {
|
|
|
1590
1649
|
}
|
|
1591
1650
|
async function buildRuntimeBinaryViaWorker(options) {
|
|
1592
1651
|
const workerSourcePath = resolveRuntimeBinaryBuildWorkerSourcePath(options);
|
|
1593
|
-
if (!workerSourcePath || !
|
|
1652
|
+
if (!workerSourcePath || !existsSync13(workerSourcePath)) {
|
|
1594
1653
|
await buildRuntimeBinaryInProcess(options, {
|
|
1595
1654
|
manifestPath: runtimeBinaryCacheManifestPath(options.outputPath),
|
|
1596
1655
|
buildKey: createRuntimeBinaryBuildKey({
|
|
@@ -1627,7 +1686,7 @@ async function buildRuntimeBinaryViaWorker(options) {
|
|
|
1627
1686
|
}
|
|
1628
1687
|
}
|
|
1629
1688
|
function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
|
|
1630
|
-
return
|
|
1689
|
+
return resolve12(dirname7(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
1631
1690
|
}
|
|
1632
1691
|
function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
1633
1692
|
const envRoots = [
|
|
@@ -1636,13 +1695,13 @@ function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
|
1636
1695
|
process.env.PROJECT_RIG_ROOT?.trim()
|
|
1637
1696
|
].filter(Boolean);
|
|
1638
1697
|
for (const root of envRoots) {
|
|
1639
|
-
const candidate =
|
|
1640
|
-
if (
|
|
1698
|
+
const candidate = resolve12(root, "packages/runtime/src/binary-build-worker.ts");
|
|
1699
|
+
if (existsSync13(candidate)) {
|
|
1641
1700
|
return candidate;
|
|
1642
1701
|
}
|
|
1643
1702
|
}
|
|
1644
|
-
const localCandidate =
|
|
1645
|
-
return
|
|
1703
|
+
const localCandidate = resolve12(import.meta.dir, "binary-build-worker.ts");
|
|
1704
|
+
return existsSync13(localCandidate) ? localCandidate : null;
|
|
1646
1705
|
}
|
|
1647
1706
|
function resolveRuntimeBinaryBuildWorkerInvocation() {
|
|
1648
1707
|
const bunPath = Bun.which("bun");
|
|
@@ -1678,7 +1737,7 @@ function createRuntimeBinaryBuildKey(input) {
|
|
|
1678
1737
|
});
|
|
1679
1738
|
}
|
|
1680
1739
|
async function isRuntimeBinaryBuildFresh(input) {
|
|
1681
|
-
if (!
|
|
1740
|
+
if (!existsSync13(input.outputPath) || !existsSync13(input.manifestPath)) {
|
|
1682
1741
|
return false;
|
|
1683
1742
|
}
|
|
1684
1743
|
let manifest = null;
|
|
@@ -1691,7 +1750,7 @@ async function isRuntimeBinaryBuildFresh(input) {
|
|
|
1691
1750
|
return false;
|
|
1692
1751
|
}
|
|
1693
1752
|
for (const [filePath, expectedDigest] of Object.entries(manifest.inputs || {})) {
|
|
1694
|
-
if (!
|
|
1753
|
+
if (!existsSync13(filePath)) {
|
|
1695
1754
|
return false;
|
|
1696
1755
|
}
|
|
1697
1756
|
if (await sha256File(filePath) !== expectedDigest) {
|
|
@@ -1704,7 +1763,7 @@ async function writeRuntimeBinaryCacheManifest(input) {
|
|
|
1704
1763
|
const inputs = {};
|
|
1705
1764
|
for (const inputPath of Object.keys(input.metafile?.inputs || {}).sort()) {
|
|
1706
1765
|
const normalized = normalizeBuildInputPath(input.cwd, inputPath);
|
|
1707
|
-
if (!normalized || !
|
|
1766
|
+
if (!normalized || !existsSync13(normalized)) {
|
|
1708
1767
|
continue;
|
|
1709
1768
|
}
|
|
1710
1769
|
inputs[normalized] = await sha256File(normalized);
|
|
@@ -1727,7 +1786,7 @@ function normalizeBuildInputPath(cwd, inputPath) {
|
|
|
1727
1786
|
if (inputPath.startsWith("<")) {
|
|
1728
1787
|
return null;
|
|
1729
1788
|
}
|
|
1730
|
-
return
|
|
1789
|
+
return resolve12(cwd, inputPath);
|
|
1731
1790
|
}
|
|
1732
1791
|
async function sha256File(path) {
|
|
1733
1792
|
const hasher = new Bun.CryptoHasher("sha256");
|
|
@@ -1743,8 +1802,8 @@ function sortRecord(value) {
|
|
|
1743
1802
|
async function runSerializedRuntimeBinaryBuild(action) {
|
|
1744
1803
|
const previous = runtimeBinaryBuildQueue;
|
|
1745
1804
|
let release;
|
|
1746
|
-
runtimeBinaryBuildQueue = new Promise((
|
|
1747
|
-
release =
|
|
1805
|
+
runtimeBinaryBuildQueue = new Promise((resolve13) => {
|
|
1806
|
+
release = resolve13;
|
|
1748
1807
|
});
|
|
1749
1808
|
await previous;
|
|
1750
1809
|
try {
|
|
@@ -1789,11 +1848,11 @@ async function withTemporaryCwd(cwd, action) {
|
|
|
1789
1848
|
}
|
|
1790
1849
|
|
|
1791
1850
|
// packages/runtime/src/control-plane/runtime/provisioning-env.ts
|
|
1792
|
-
import { delimiter, resolve as
|
|
1851
|
+
import { delimiter, resolve as resolve14 } from "path";
|
|
1793
1852
|
|
|
1794
1853
|
// packages/runtime/src/control-plane/runtime/runtime-paths.ts
|
|
1795
|
-
import { existsSync as
|
|
1796
|
-
import { resolve as
|
|
1854
|
+
import { existsSync as existsSync14, readdirSync as readdirSync4, realpathSync } from "fs";
|
|
1855
|
+
import { resolve as resolve13 } from "path";
|
|
1797
1856
|
|
|
1798
1857
|
// packages/runtime/src/control-plane/runtime/sandbox/utils.ts
|
|
1799
1858
|
function uniq(values) {
|
|
@@ -1811,7 +1870,7 @@ function resolveBunBinaryPath() {
|
|
|
1811
1870
|
}
|
|
1812
1871
|
const home = process.env.HOME?.trim();
|
|
1813
1872
|
const fallbackCandidates = [
|
|
1814
|
-
home ?
|
|
1873
|
+
home ? resolve13(home, ".bun/bin/bun") : "",
|
|
1815
1874
|
"/opt/homebrew/bin/bun",
|
|
1816
1875
|
"/usr/local/bin/bun",
|
|
1817
1876
|
"/usr/bin/bun"
|
|
@@ -1839,8 +1898,8 @@ function resolveClaudeBinaryPath() {
|
|
|
1839
1898
|
}
|
|
1840
1899
|
const home = process.env.HOME?.trim();
|
|
1841
1900
|
const fallbackCandidates = [
|
|
1842
|
-
home ?
|
|
1843
|
-
home ?
|
|
1901
|
+
home ? resolve13(home, ".local/bin/claude") : "",
|
|
1902
|
+
home ? resolve13(home, ".local/share/claude/local/claude") : "",
|
|
1844
1903
|
"/opt/homebrew/bin/claude",
|
|
1845
1904
|
"/usr/local/bin/claude",
|
|
1846
1905
|
"/usr/bin/claude"
|
|
@@ -1854,51 +1913,51 @@ function resolveClaudeBinaryPath() {
|
|
|
1854
1913
|
throw new Error("claude not found in PATH");
|
|
1855
1914
|
}
|
|
1856
1915
|
function resolveBunInstallDir(bunBinaryPath = resolveBunBinaryPath()) {
|
|
1857
|
-
return
|
|
1916
|
+
return resolve13(bunBinaryPath, "../..");
|
|
1858
1917
|
}
|
|
1859
1918
|
function resolveClaudeInstallDir() {
|
|
1860
1919
|
const realPath = resolveClaudeBinaryPath();
|
|
1861
|
-
return
|
|
1920
|
+
return resolve13(realPath, "..");
|
|
1862
1921
|
}
|
|
1863
1922
|
function resolveNodeInstallDir() {
|
|
1864
1923
|
const preferredNode = resolvePreferredNodeBinary();
|
|
1865
1924
|
if (!preferredNode)
|
|
1866
1925
|
return null;
|
|
1867
1926
|
const explicitNode = process.env.RIG_NODE_BIN?.trim();
|
|
1868
|
-
if (explicitNode &&
|
|
1869
|
-
return preferredNode.endsWith("/bin/node") ?
|
|
1927
|
+
if (explicitNode && resolve13(explicitNode) === resolve13(preferredNode)) {
|
|
1928
|
+
return preferredNode.endsWith("/bin/node") ? resolve13(preferredNode, "../..") : resolve13(preferredNode, "..");
|
|
1870
1929
|
}
|
|
1871
1930
|
try {
|
|
1872
1931
|
const realPath = realpathSync(preferredNode);
|
|
1873
1932
|
if (realPath.endsWith("/bin/node")) {
|
|
1874
|
-
return
|
|
1933
|
+
return resolve13(realPath, "../..");
|
|
1875
1934
|
}
|
|
1876
|
-
return
|
|
1935
|
+
return resolve13(realPath, "..");
|
|
1877
1936
|
} catch {
|
|
1878
|
-
return
|
|
1937
|
+
return resolve13(preferredNode, "..");
|
|
1879
1938
|
}
|
|
1880
1939
|
}
|
|
1881
1940
|
function resolvePreferredNodeBinary() {
|
|
1882
1941
|
const candidates = [];
|
|
1883
1942
|
const envNode = process.env.RIG_NODE_BIN?.trim();
|
|
1884
1943
|
if (envNode) {
|
|
1885
|
-
const explicit =
|
|
1886
|
-
if (
|
|
1944
|
+
const explicit = resolve13(envNode);
|
|
1945
|
+
if (existsSync14(explicit)) {
|
|
1887
1946
|
return explicit;
|
|
1888
1947
|
}
|
|
1889
1948
|
}
|
|
1890
1949
|
const nvmBin = process.env.NVM_BIN?.trim();
|
|
1891
1950
|
if (nvmBin) {
|
|
1892
|
-
candidates.push(
|
|
1951
|
+
candidates.push(resolve13(nvmBin, "node"));
|
|
1893
1952
|
}
|
|
1894
1953
|
const home = process.env.HOME?.trim();
|
|
1895
1954
|
if (home) {
|
|
1896
|
-
const nvmVersionsDir =
|
|
1897
|
-
if (
|
|
1955
|
+
const nvmVersionsDir = resolve13(home, ".nvm/versions/node");
|
|
1956
|
+
if (existsSync14(nvmVersionsDir)) {
|
|
1898
1957
|
try {
|
|
1899
1958
|
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/, "")));
|
|
1900
1959
|
for (const versionDir of versionDirs) {
|
|
1901
|
-
candidates.push(
|
|
1960
|
+
candidates.push(resolve13(nvmVersionsDir, versionDir, "bin/node"));
|
|
1902
1961
|
}
|
|
1903
1962
|
} catch {}
|
|
1904
1963
|
}
|
|
@@ -1907,8 +1966,8 @@ function resolvePreferredNodeBinary() {
|
|
|
1907
1966
|
if (whichNode) {
|
|
1908
1967
|
candidates.push(whichNode);
|
|
1909
1968
|
}
|
|
1910
|
-
const deduped = uniq(candidates.map((candidate) =>
|
|
1911
|
-
const existing = deduped.filter((candidate) =>
|
|
1969
|
+
const deduped = uniq(candidates.map((candidate) => resolve13(candidate)));
|
|
1970
|
+
const existing = deduped.filter((candidate) => existsSync14(candidate));
|
|
1912
1971
|
if (existing.length === 0) {
|
|
1913
1972
|
return null;
|
|
1914
1973
|
}
|
|
@@ -1922,7 +1981,7 @@ function resolvePreferredNodeBinary() {
|
|
|
1922
1981
|
return existing[0] ?? null;
|
|
1923
1982
|
}
|
|
1924
1983
|
function inferNodeMajor(nodeBinaryPath) {
|
|
1925
|
-
const normalized =
|
|
1984
|
+
const normalized = resolve13(nodeBinaryPath).replace(/\\/g, "/");
|
|
1926
1985
|
const match = normalized.match(/(?:^|\/)(?:node-)?v?(\d+)\.\d+\.\d+(?:\/|$)/);
|
|
1927
1986
|
if (!match) {
|
|
1928
1987
|
return null;
|
|
@@ -1934,8 +1993,8 @@ function normalizeExecutablePath(candidate) {
|
|
|
1934
1993
|
if (!candidate) {
|
|
1935
1994
|
return "";
|
|
1936
1995
|
}
|
|
1937
|
-
const normalized =
|
|
1938
|
-
if (!
|
|
1996
|
+
const normalized = resolve13(candidate);
|
|
1997
|
+
if (!existsSync14(normalized)) {
|
|
1939
1998
|
return "";
|
|
1940
1999
|
}
|
|
1941
2000
|
try {
|
|
@@ -1945,7 +2004,7 @@ function normalizeExecutablePath(candidate) {
|
|
|
1945
2004
|
}
|
|
1946
2005
|
}
|
|
1947
2006
|
function looksLikeRuntimeGateway(candidate) {
|
|
1948
|
-
const normalized =
|
|
2007
|
+
const normalized = resolve13(candidate).replace(/\\/g, "/");
|
|
1949
2008
|
return normalized.includes("/.rig/bin/") || normalized.endsWith("/rig-shell") || normalized.endsWith("/rig-agent");
|
|
1950
2009
|
}
|
|
1951
2010
|
|
|
@@ -1966,7 +2025,7 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
1966
2025
|
try {
|
|
1967
2026
|
return resolveClaudeInstallDir();
|
|
1968
2027
|
} catch {
|
|
1969
|
-
return
|
|
2028
|
+
return resolve14(claudeBinary, "..");
|
|
1970
2029
|
}
|
|
1971
2030
|
})() : "";
|
|
1972
2031
|
const nodeDir = resolveNodeInstallDir();
|
|
@@ -1976,8 +2035,8 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
1976
2035
|
`${bunDir}/bin`,
|
|
1977
2036
|
claudeDir,
|
|
1978
2037
|
nodeDir ? `${nodeDir}/bin` : "",
|
|
1979
|
-
realHome ?
|
|
1980
|
-
realHome ?
|
|
2038
|
+
realHome ? resolve14(realHome, ".local/bin") : "",
|
|
2039
|
+
realHome ? resolve14(realHome, ".cargo/bin") : "",
|
|
1981
2040
|
...inheritedPath,
|
|
1982
2041
|
"/usr/local/bin",
|
|
1983
2042
|
"/usr/local/sbin",
|
|
@@ -2008,9 +2067,9 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
2008
2067
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
2009
2068
|
function resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext) {
|
|
2010
2069
|
if (runtimeContext) {
|
|
2011
|
-
return
|
|
2070
|
+
return resolve15(runtimeContext.binDir, "validators", binaryName);
|
|
2012
2071
|
}
|
|
2013
|
-
return
|
|
2072
|
+
return resolve15(resolveHarnessPaths(projectRoot).binDir, "validators", binaryName);
|
|
2014
2073
|
}
|
|
2015
2074
|
async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
2016
2075
|
const match = checkId.match(/^([a-z][\w-]*):([a-z][\w-]*)$/);
|
|
@@ -2025,19 +2084,19 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
2025
2084
|
const binaryName = `${category}-${check}`;
|
|
2026
2085
|
const binaryPath = resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
2027
2086
|
const hostProjectRoot = runtimeContext?.hostProjectRoot?.trim() || projectRoot;
|
|
2028
|
-
const sourcePath =
|
|
2029
|
-
if (!
|
|
2087
|
+
const sourcePath = resolve15(hostProjectRoot, "packages/runtime/src/control-plane/validators", category, `${check}.ts`);
|
|
2088
|
+
if (!existsSync15(sourcePath)) {
|
|
2030
2089
|
return null;
|
|
2031
2090
|
}
|
|
2032
2091
|
const sourceMtime = statSync4(sourcePath).mtimeMs;
|
|
2033
|
-
const binaryExists =
|
|
2092
|
+
const binaryExists = existsSync15(binaryPath);
|
|
2034
2093
|
const binaryMtime = binaryExists ? statSync4(binaryPath).mtimeMs : 0;
|
|
2035
2094
|
if (!binaryExists || sourceMtime > binaryMtime) {
|
|
2036
2095
|
if (binaryExists) {
|
|
2037
2096
|
rmSync4(binaryPath, { force: true });
|
|
2038
2097
|
rmSync4(`${binaryPath}.build-manifest.json`, { force: true });
|
|
2039
2098
|
}
|
|
2040
|
-
|
|
2099
|
+
mkdirSync7(dirname8(binaryPath), { recursive: true });
|
|
2041
2100
|
await buildRuntimeBinary({
|
|
2042
2101
|
sourcePath: `packages/runtime/src/control-plane/validators/${category}/${check}.ts`,
|
|
2043
2102
|
outputPath: binaryPath,
|
|
@@ -2046,7 +2105,7 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
2046
2105
|
env: runtimeProvisioningEnv()
|
|
2047
2106
|
});
|
|
2048
2107
|
}
|
|
2049
|
-
return
|
|
2108
|
+
return existsSync15(binaryPath) ? binaryPath : null;
|
|
2050
2109
|
}
|
|
2051
2110
|
|
|
2052
2111
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
@@ -2083,20 +2142,20 @@ async function readTaskSourceValidation(projectRoot, taskId) {
|
|
|
2083
2142
|
function resolveValidationPaths(projectRoot, taskId, runtimeContext) {
|
|
2084
2143
|
if (runtimeContext) {
|
|
2085
2144
|
return {
|
|
2086
|
-
taskLogDir:
|
|
2087
|
-
artifactDir:
|
|
2145
|
+
taskLogDir: resolve16(runtimeContext.logsDir, taskId),
|
|
2146
|
+
artifactDir: resolve16(runtimeContext.workspaceDir, "artifacts", taskId)
|
|
2088
2147
|
};
|
|
2089
2148
|
}
|
|
2090
2149
|
const paths = resolveHarnessPaths(projectRoot);
|
|
2091
2150
|
return {
|
|
2092
|
-
taskLogDir:
|
|
2093
|
-
artifactDir:
|
|
2151
|
+
taskLogDir: resolve16(paths.logsDir, taskId),
|
|
2152
|
+
artifactDir: resolve16(paths.artifactsDir, taskId)
|
|
2094
2153
|
};
|
|
2095
2154
|
}
|
|
2096
2155
|
async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext) {
|
|
2097
2156
|
const binaryName = checkId.replace(":", "-");
|
|
2098
2157
|
const binaryPath = await ensureValidatorBinary(projectRoot, checkId, runtimeContext) ?? resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
2099
|
-
if (!
|
|
2158
|
+
if (!existsSync16(binaryPath)) {
|
|
2100
2159
|
return {
|
|
2101
2160
|
result: {
|
|
2102
2161
|
id: checkId,
|
|
@@ -2107,7 +2166,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
2107
2166
|
};
|
|
2108
2167
|
}
|
|
2109
2168
|
const validatorCwd = runtimeContext?.workspaceDir || resolveMonorepoRoot(projectRoot);
|
|
2110
|
-
const runtimeShellPath = runtimeContext ?
|
|
2169
|
+
const runtimeShellPath = runtimeContext ? resolve16(runtimeContext.binDir, "rig-shell") : "";
|
|
2111
2170
|
const monorepoMainRoot = runtimeContext?.monorepoMainRoot || process.env.MONOREPO_MAIN_ROOT?.trim() || resolveMonorepoRoot(projectRoot);
|
|
2112
2171
|
const validatorEnv = {
|
|
2113
2172
|
PROJECT_RIG_ROOT: runtimeContext?.hostProjectRoot || projectRoot,
|
|
@@ -2122,7 +2181,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
2122
2181
|
validatorEnv.RIG_LOGS_DIR = runtimeContext.logsDir;
|
|
2123
2182
|
validatorEnv.RIG_RUNTIME_BIN_DIR = runtimeContext.binDir;
|
|
2124
2183
|
}
|
|
2125
|
-
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath &&
|
|
2184
|
+
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath && existsSync16(runtimeShellPath) ? [runtimeShellPath, "run-binary", binaryPath] : [binaryPath], validatorCwd, validatorEnv);
|
|
2126
2185
|
try {
|
|
2127
2186
|
const result = JSON.parse(stdout.trim());
|
|
2128
2187
|
return { result, exitCode };
|
|
@@ -2162,8 +2221,8 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
2162
2221
|
const configuredValidation = stringArray(taskConfig[taskId]?.validation);
|
|
2163
2222
|
const commands = resolvedContext?.validation?.length ? resolvedContext.validation : configuredValidation.length > 0 ? configuredValidation : sourceValidation.validation;
|
|
2164
2223
|
const { taskLogDir, artifactDir } = resolveValidationPaths(projectRoot, taskId, resolvedContext);
|
|
2165
|
-
|
|
2166
|
-
|
|
2224
|
+
mkdirSync8(taskLogDir, { recursive: true });
|
|
2225
|
+
mkdirSync8(artifactDir, { recursive: true });
|
|
2167
2226
|
if (commands.length === 0) {
|
|
2168
2227
|
const skipped = {
|
|
2169
2228
|
status: "skipped",
|
|
@@ -2172,7 +2231,7 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
2172
2231
|
failed: 0,
|
|
2173
2232
|
categories: []
|
|
2174
2233
|
};
|
|
2175
|
-
|
|
2234
|
+
writeFileSync8(resolve16(artifactDir, "validation-summary.json"), `${JSON.stringify(skipped, null, 2)}
|
|
2176
2235
|
`, "utf-8");
|
|
2177
2236
|
return skipped;
|
|
2178
2237
|
}
|
|
@@ -2207,18 +2266,18 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
2207
2266
|
exit_code: 2,
|
|
2208
2267
|
duration_seconds: 0
|
|
2209
2268
|
});
|
|
2210
|
-
const logFile2 =
|
|
2211
|
-
|
|
2212
|
-
|
|
2269
|
+
const logFile2 = resolve16(taskLogDir, `invalid-entry-validation.log`);
|
|
2270
|
+
mkdirSync8(taskLogDir, { recursive: true });
|
|
2271
|
+
writeFileSync8(logFile2, `=== ${nowIso()} :: ${cmd} ===
|
|
2213
2272
|
Invalid validation entry: not a check-ID. All entries must use format "category:check-name".
|
|
2214
2273
|
`, "utf-8");
|
|
2215
2274
|
continue;
|
|
2216
2275
|
}
|
|
2217
2276
|
const { result, exitCode } = await dispatchValidator(cmd, effectiveRegistry, validatorCtx, (id) => runValidatorBinary(projectRoot, taskId, id, resolvedContext));
|
|
2218
2277
|
const durationSeconds = Math.max(0, Math.round((Date.now() - startedAt) / 1000));
|
|
2219
|
-
const logFile =
|
|
2220
|
-
|
|
2221
|
-
|
|
2278
|
+
const logFile = resolve16(taskLogDir, `${cmd.replace(":", "-")}-validation.log`);
|
|
2279
|
+
mkdirSync8(taskLogDir, { recursive: true });
|
|
2280
|
+
writeFileSync8(logFile, `=== ${nowIso()} :: ${cmd} ===
|
|
2222
2281
|
${JSON.stringify(result, null, 2)}
|
|
2223
2282
|
`, "utf-8");
|
|
2224
2283
|
if (result.passed) {
|
|
@@ -2240,8 +2299,8 @@ ${JSON.stringify(result, null, 2)}
|
|
|
2240
2299
|
failed,
|
|
2241
2300
|
categories
|
|
2242
2301
|
};
|
|
2243
|
-
|
|
2244
|
-
|
|
2302
|
+
mkdirSync8(artifactDir, { recursive: true });
|
|
2303
|
+
writeFileSync8(resolve16(artifactDir, "validation-summary.json"), `${JSON.stringify(summary, null, 2)}
|
|
2245
2304
|
`, "utf-8");
|
|
2246
2305
|
return summary;
|
|
2247
2306
|
}
|