@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/task-ops.ts
|
|
3
|
-
import { appendFileSync, existsSync as
|
|
4
|
-
import { resolve as
|
|
3
|
+
import { appendFileSync, existsSync as existsSync23, mkdirSync as mkdirSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync12 } from "fs";
|
|
4
|
+
import { resolve as resolve25 } from "path";
|
|
5
5
|
|
|
6
6
|
// packages/runtime/src/build-time-config.ts
|
|
7
7
|
function normalizeBuildConfig(value) {
|
|
@@ -680,6 +680,8 @@ function buildBrowserGuidanceLines(browser) {
|
|
|
680
680
|
}
|
|
681
681
|
|
|
682
682
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
683
|
+
import { existsSync as existsSync7 } from "fs";
|
|
684
|
+
import { resolve as resolvePath } from "path";
|
|
683
685
|
import { createPluginHost } from "@rig/core";
|
|
684
686
|
import { loadConfig } from "@rig/core/load-config";
|
|
685
687
|
|
|
@@ -1019,6 +1021,55 @@ async function materializeSkills(projectRoot, entries) {
|
|
|
1019
1021
|
return written;
|
|
1020
1022
|
}
|
|
1021
1023
|
|
|
1024
|
+
// packages/runtime/src/control-plane/pi-settings-materializer.ts
|
|
1025
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
1026
|
+
import { dirname as dirname6, resolve as resolve8 } from "path";
|
|
1027
|
+
var SETTINGS_RELATIVE_PATH = ".pi/settings.json";
|
|
1028
|
+
var MANAGED_RECORD_RELATIVE_PATH = ".rig/state/pi-managed-packages.json";
|
|
1029
|
+
function readJson(path, fallback) {
|
|
1030
|
+
if (!existsSync6(path))
|
|
1031
|
+
return fallback;
|
|
1032
|
+
try {
|
|
1033
|
+
return JSON.parse(readFileSync5(path, "utf-8"));
|
|
1034
|
+
} catch {
|
|
1035
|
+
return fallback;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
function packageKey(entry) {
|
|
1039
|
+
if (typeof entry === "string")
|
|
1040
|
+
return entry;
|
|
1041
|
+
if (entry && typeof entry === "object" && typeof entry.source === "string") {
|
|
1042
|
+
return entry.source;
|
|
1043
|
+
}
|
|
1044
|
+
return JSON.stringify(entry);
|
|
1045
|
+
}
|
|
1046
|
+
function materializePiPackages(projectRoot, declaredPackages) {
|
|
1047
|
+
const settingsPath = resolve8(projectRoot, SETTINGS_RELATIVE_PATH);
|
|
1048
|
+
const managedRecordPath = resolve8(projectRoot, MANAGED_RECORD_RELATIVE_PATH);
|
|
1049
|
+
const settings = readJson(settingsPath, {});
|
|
1050
|
+
const previouslyManaged = new Set(readJson(managedRecordPath, []));
|
|
1051
|
+
const existing = Array.isArray(settings.packages) ? settings.packages : [];
|
|
1052
|
+
const operatorEntries = existing.filter((entry) => !previouslyManaged.has(packageKey(entry)));
|
|
1053
|
+
const operatorKeys = new Set(operatorEntries.map(packageKey));
|
|
1054
|
+
const managedToAdd = declaredPackages.filter((pkg) => !operatorKeys.has(pkg));
|
|
1055
|
+
const nextPackages = [...operatorEntries, ...managedToAdd];
|
|
1056
|
+
if (nextPackages.length > 0 || existsSync6(settingsPath)) {
|
|
1057
|
+
const nextSettings = { ...settings };
|
|
1058
|
+
if (nextPackages.length > 0) {
|
|
1059
|
+
nextSettings.packages = nextPackages;
|
|
1060
|
+
} else {
|
|
1061
|
+
delete nextSettings.packages;
|
|
1062
|
+
}
|
|
1063
|
+
mkdirSync5(dirname6(settingsPath), { recursive: true });
|
|
1064
|
+
writeFileSync5(settingsPath, `${JSON.stringify(nextSettings, null, 2)}
|
|
1065
|
+
`, "utf-8");
|
|
1066
|
+
}
|
|
1067
|
+
mkdirSync5(dirname6(managedRecordPath), { recursive: true });
|
|
1068
|
+
writeFileSync5(managedRecordPath, `${JSON.stringify(managedToAdd, null, 2)}
|
|
1069
|
+
`, "utf-8");
|
|
1070
|
+
return { settingsPath, packages: managedToAdd };
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1022
1073
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
1023
1074
|
async function buildPluginHostContext(projectRoot) {
|
|
1024
1075
|
let config;
|
|
@@ -1066,6 +1117,14 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
1066
1117
|
} catch (err) {
|
|
1067
1118
|
console.warn(`[plugin-host] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
1068
1119
|
}
|
|
1120
|
+
try {
|
|
1121
|
+
const piPackages = config.runtime?.pi?.packages ?? [];
|
|
1122
|
+
if (piPackages.length > 0 || existsSync7(resolvePath(projectRoot, ".rig/state/pi-managed-packages.json"))) {
|
|
1123
|
+
materializePiPackages(projectRoot, piPackages);
|
|
1124
|
+
}
|
|
1125
|
+
} catch (err) {
|
|
1126
|
+
console.warn(`[plugin-host] Pi package materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
1127
|
+
}
|
|
1069
1128
|
return {
|
|
1070
1129
|
config,
|
|
1071
1130
|
pluginHost,
|
|
@@ -1079,12 +1138,12 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
1079
1138
|
|
|
1080
1139
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
1081
1140
|
import { spawnSync } from "child_process";
|
|
1082
|
-
import { existsSync as
|
|
1083
|
-
import { basename as basename3, join as join2, resolve as
|
|
1141
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7, readdirSync as readdirSync2, statSync, writeFileSync as writeFileSync6 } from "fs";
|
|
1142
|
+
import { basename as basename3, join as join2, resolve as resolve10 } from "path";
|
|
1084
1143
|
|
|
1085
1144
|
// packages/runtime/src/control-plane/tasks/legacy-task-config-source.ts
|
|
1086
|
-
import { existsSync as
|
|
1087
|
-
import { resolve as
|
|
1145
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
|
|
1146
|
+
import { resolve as resolve9 } from "path";
|
|
1088
1147
|
|
|
1089
1148
|
// packages/runtime/src/control-plane/tasks/task-record-reader.ts
|
|
1090
1149
|
async function findTaskById(reader, id) {
|
|
@@ -1107,7 +1166,7 @@ class LegacyTaskConfigReadError extends Error {
|
|
|
1107
1166
|
}
|
|
1108
1167
|
}
|
|
1109
1168
|
function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
1110
|
-
const configPath = options.configPath ??
|
|
1169
|
+
const configPath = options.configPath ?? resolve9(projectRoot, ".rig", "task-config.json");
|
|
1111
1170
|
const reader = {
|
|
1112
1171
|
async listTasks() {
|
|
1113
1172
|
return readLegacyTaskRecords(projectRoot, configPath);
|
|
@@ -1118,8 +1177,8 @@ function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
|
1118
1177
|
};
|
|
1119
1178
|
return reader;
|
|
1120
1179
|
}
|
|
1121
|
-
function readLegacyTaskRecords(projectRoot, configPath =
|
|
1122
|
-
if (!
|
|
1180
|
+
function readLegacyTaskRecords(projectRoot, configPath = resolve9(projectRoot, ".rig", "task-config.json")) {
|
|
1181
|
+
if (!existsSync8(configPath)) {
|
|
1123
1182
|
return [];
|
|
1124
1183
|
}
|
|
1125
1184
|
const rawConfig = readLegacyTaskConfigJson(projectRoot, configPath);
|
|
@@ -1127,7 +1186,7 @@ function readLegacyTaskRecords(projectRoot, configPath = resolve8(projectRoot, "
|
|
|
1127
1186
|
}
|
|
1128
1187
|
function readLegacyTaskConfigJson(projectRoot, configPath) {
|
|
1129
1188
|
try {
|
|
1130
|
-
const parsed = JSON.parse(
|
|
1189
|
+
const parsed = JSON.parse(readFileSync6(configPath, "utf8"));
|
|
1131
1190
|
if (isPlainRecord(parsed)) {
|
|
1132
1191
|
return parsed;
|
|
1133
1192
|
}
|
|
@@ -1211,7 +1270,7 @@ function isPlainRecord(candidate) {
|
|
|
1211
1270
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
1212
1271
|
var FILE_TASK_PATTERN = /\.(task\.)?json$/;
|
|
1213
1272
|
function createSourceAwareTaskConfigRecordReader(projectRoot, options = {}) {
|
|
1214
|
-
const configPath = options.configPath ??
|
|
1273
|
+
const configPath = options.configPath ?? resolve10(projectRoot, ".rig", "task-config.json");
|
|
1215
1274
|
const legacy = createLegacyTaskConfigRecordReader(projectRoot, { configPath });
|
|
1216
1275
|
const spawnFn = options.spawn ?? spawnSync;
|
|
1217
1276
|
const ghBinary = options.ghBinary ?? "gh";
|
|
@@ -1294,10 +1353,10 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
1294
1353
|
return metadata;
|
|
1295
1354
|
}
|
|
1296
1355
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
1297
|
-
const jsonPath =
|
|
1298
|
-
if (
|
|
1356
|
+
const jsonPath = resolve10(projectRoot, "rig.config.json");
|
|
1357
|
+
if (existsSync9(jsonPath)) {
|
|
1299
1358
|
try {
|
|
1300
|
-
const parsed = JSON.parse(
|
|
1359
|
+
const parsed = JSON.parse(readFileSync7(jsonPath, "utf8"));
|
|
1301
1360
|
if (isPlainRecord2(parsed) && isPlainRecord2(parsed.taskSource)) {
|
|
1302
1361
|
const source = parsed.taskSource;
|
|
1303
1362
|
return source.kind === "files" && typeof source.path === "string" ? source.path : null;
|
|
@@ -1306,12 +1365,12 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
1306
1365
|
return null;
|
|
1307
1366
|
}
|
|
1308
1367
|
}
|
|
1309
|
-
const tsPath =
|
|
1310
|
-
if (!
|
|
1368
|
+
const tsPath = resolve10(projectRoot, "rig.config.ts");
|
|
1369
|
+
if (!existsSync9(tsPath)) {
|
|
1311
1370
|
return null;
|
|
1312
1371
|
}
|
|
1313
1372
|
try {
|
|
1314
|
-
const source =
|
|
1373
|
+
const source = readFileSync7(tsPath, "utf8");
|
|
1315
1374
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
1316
1375
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
1317
1376
|
if (kind !== "files") {
|
|
@@ -1331,10 +1390,10 @@ function readRawTaskEntry(configPath, taskId) {
|
|
|
1331
1390
|
return isPlainRecord2(entry) ? entry : null;
|
|
1332
1391
|
}
|
|
1333
1392
|
function readRawTaskConfig(configPath) {
|
|
1334
|
-
if (!
|
|
1393
|
+
if (!existsSync9(configPath)) {
|
|
1335
1394
|
return null;
|
|
1336
1395
|
}
|
|
1337
|
-
const parsed = JSON.parse(
|
|
1396
|
+
const parsed = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
1338
1397
|
return isPlainRecord2(parsed) ? parsed : null;
|
|
1339
1398
|
}
|
|
1340
1399
|
function stripLegacyTaskConfigMetadata2(raw) {
|
|
@@ -1342,8 +1401,8 @@ function stripLegacyTaskConfigMetadata2(raw) {
|
|
|
1342
1401
|
return tasks;
|
|
1343
1402
|
}
|
|
1344
1403
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
1345
|
-
const directory =
|
|
1346
|
-
if (!
|
|
1404
|
+
const directory = resolve10(projectRoot, sourcePath);
|
|
1405
|
+
if (!existsSync9(directory)) {
|
|
1347
1406
|
return [];
|
|
1348
1407
|
}
|
|
1349
1408
|
const tasks = [];
|
|
@@ -1358,11 +1417,11 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
1358
1417
|
return tasks;
|
|
1359
1418
|
}
|
|
1360
1419
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
1361
|
-
const file = findFileBackedTaskFile(
|
|
1420
|
+
const file = findFileBackedTaskFile(resolve10(projectRoot, sourcePath), taskId);
|
|
1362
1421
|
if (!file) {
|
|
1363
1422
|
return null;
|
|
1364
1423
|
}
|
|
1365
|
-
const raw = JSON.parse(
|
|
1424
|
+
const raw = JSON.parse(readFileSync7(file, "utf8"));
|
|
1366
1425
|
if (!isPlainRecord2(raw)) {
|
|
1367
1426
|
return null;
|
|
1368
1427
|
}
|
|
@@ -1375,7 +1434,7 @@ function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
|
1375
1434
|
};
|
|
1376
1435
|
}
|
|
1377
1436
|
function findFileBackedTaskFile(directory, taskId) {
|
|
1378
|
-
if (!
|
|
1437
|
+
if (!existsSync9(directory)) {
|
|
1379
1438
|
return null;
|
|
1380
1439
|
}
|
|
1381
1440
|
for (const name of readdirSync2(directory)) {
|
|
@@ -1385,7 +1444,7 @@ function findFileBackedTaskFile(directory, taskId) {
|
|
|
1385
1444
|
try {
|
|
1386
1445
|
if (!statSync(file).isFile())
|
|
1387
1446
|
continue;
|
|
1388
|
-
const raw = JSON.parse(
|
|
1447
|
+
const raw = JSON.parse(readFileSync7(file, "utf8"));
|
|
1389
1448
|
const inferredId = basename3(file).replace(FILE_TASK_PATTERN, "");
|
|
1390
1449
|
const id = isPlainRecord2(raw) && typeof raw.id === "string" ? raw.id : inferredId;
|
|
1391
1450
|
if (id === taskId) {
|
|
@@ -1545,8 +1604,8 @@ async function readConfiguredTaskSourceTask(projectRoot, taskId) {
|
|
|
1545
1604
|
}
|
|
1546
1605
|
|
|
1547
1606
|
// packages/runtime/src/control-plane/native/task-state.ts
|
|
1548
|
-
import { existsSync as
|
|
1549
|
-
import { basename as basename6, resolve as
|
|
1607
|
+
import { existsSync as existsSync16, readFileSync as readFileSync10, readdirSync as readdirSync3, statSync as statSync3, writeFileSync as writeFileSync7 } from "fs";
|
|
1608
|
+
import { basename as basename6, resolve as resolve17 } from "path";
|
|
1550
1609
|
|
|
1551
1610
|
// packages/runtime/src/control-plane/state-sync/types.ts
|
|
1552
1611
|
var SUPPORTED_TASK_STATE_SCHEMA_VERSION = 1;
|
|
@@ -1654,50 +1713,50 @@ function readTaskStateMetadataEnvelope(raw) {
|
|
|
1654
1713
|
};
|
|
1655
1714
|
}
|
|
1656
1715
|
// packages/runtime/src/control-plane/state-sync/read.ts
|
|
1657
|
-
import { existsSync as
|
|
1658
|
-
import { resolve as
|
|
1716
|
+
import { existsSync as existsSync15, readFileSync as readFileSync9 } from "fs";
|
|
1717
|
+
import { resolve as resolve16 } from "path";
|
|
1659
1718
|
|
|
1660
1719
|
// packages/runtime/src/control-plane/native/utils.ts
|
|
1661
|
-
import { existsSync as
|
|
1662
|
-
import { resolve as
|
|
1720
|
+
import { existsSync as existsSync12, readFileSync as readFileSync8 } from "fs";
|
|
1721
|
+
import { resolve as resolve13 } from "path";
|
|
1663
1722
|
|
|
1664
1723
|
// packages/runtime/src/layout.ts
|
|
1665
|
-
import { existsSync as
|
|
1666
|
-
import { basename as basename4, dirname as
|
|
1724
|
+
import { existsSync as existsSync10 } from "fs";
|
|
1725
|
+
import { basename as basename4, dirname as dirname7, resolve as resolve11 } from "path";
|
|
1667
1726
|
var RIG_DEFINITION_DIRNAME = "rig";
|
|
1668
1727
|
var RIG_ARTIFACTS_DIRNAME = "artifacts";
|
|
1669
1728
|
function resolveMonorepoRoot(projectRoot) {
|
|
1670
|
-
const normalizedProjectRoot =
|
|
1729
|
+
const normalizedProjectRoot = resolve11(projectRoot);
|
|
1671
1730
|
const explicit = process.env.MONOREPO_ROOT?.trim();
|
|
1672
1731
|
if (explicit) {
|
|
1673
|
-
const explicitRoot =
|
|
1674
|
-
const explicitParent =
|
|
1732
|
+
const explicitRoot = resolve11(explicit);
|
|
1733
|
+
const explicitParent = dirname7(explicitRoot);
|
|
1675
1734
|
if (basename4(explicitParent) === ".worktrees") {
|
|
1676
|
-
const owner =
|
|
1677
|
-
const ownerHasGit =
|
|
1678
|
-
const ownerHasTaskConfig =
|
|
1679
|
-
const ownerHasRigConfig =
|
|
1735
|
+
const owner = dirname7(explicitParent);
|
|
1736
|
+
const ownerHasGit = existsSync10(resolve11(owner, ".git"));
|
|
1737
|
+
const ownerHasTaskConfig = existsSync10(resolve11(owner, ".rig", "task-config.json"));
|
|
1738
|
+
const ownerHasRigConfig = existsSync10(resolve11(owner, "rig.config.ts"));
|
|
1680
1739
|
if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
|
|
1681
1740
|
return owner;
|
|
1682
1741
|
}
|
|
1683
1742
|
throw new Error(`MONOREPO_ROOT points to worktree ${explicitRoot}, but the owner checkout is incomplete at ${owner}.`);
|
|
1684
1743
|
}
|
|
1685
|
-
if (!
|
|
1744
|
+
if (!existsSync10(resolve11(explicitRoot, ".git"))) {
|
|
1686
1745
|
throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but no git checkout was found there.`);
|
|
1687
1746
|
}
|
|
1688
|
-
const hasTaskConfig =
|
|
1689
|
-
const hasRigConfig =
|
|
1747
|
+
const hasTaskConfig = existsSync10(resolve11(explicitRoot, ".rig", "task-config.json"));
|
|
1748
|
+
const hasRigConfig = existsSync10(resolve11(explicitRoot, "rig.config.ts"));
|
|
1690
1749
|
if (!hasTaskConfig && !hasRigConfig) {
|
|
1691
1750
|
throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but neither .rig/task-config.json nor rig.config.ts exists there.`);
|
|
1692
1751
|
}
|
|
1693
1752
|
return explicitRoot;
|
|
1694
1753
|
}
|
|
1695
|
-
const projectParent =
|
|
1754
|
+
const projectParent = dirname7(normalizedProjectRoot);
|
|
1696
1755
|
if (basename4(projectParent) === ".worktrees") {
|
|
1697
|
-
const worktreeOwner =
|
|
1698
|
-
const ownerHasGit =
|
|
1699
|
-
const ownerHasTaskConfig =
|
|
1700
|
-
const ownerHasRigConfig =
|
|
1756
|
+
const worktreeOwner = dirname7(projectParent);
|
|
1757
|
+
const ownerHasGit = existsSync10(resolve11(worktreeOwner, ".git"));
|
|
1758
|
+
const ownerHasTaskConfig = existsSync10(resolve11(worktreeOwner, ".rig", "task-config.json"));
|
|
1759
|
+
const ownerHasRigConfig = existsSync10(resolve11(worktreeOwner, "rig.config.ts"));
|
|
1701
1760
|
if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
|
|
1702
1761
|
return worktreeOwner;
|
|
1703
1762
|
}
|
|
@@ -1705,28 +1764,28 @@ function resolveMonorepoRoot(projectRoot) {
|
|
|
1705
1764
|
return normalizedProjectRoot;
|
|
1706
1765
|
}
|
|
1707
1766
|
function resolveRuntimeWorkspaceLayout(workspaceDir) {
|
|
1708
|
-
const root =
|
|
1709
|
-
const rigRoot =
|
|
1710
|
-
const logsDir =
|
|
1711
|
-
const stateDir =
|
|
1712
|
-
const runtimeDir =
|
|
1713
|
-
const binDir =
|
|
1767
|
+
const root = resolve11(workspaceDir);
|
|
1768
|
+
const rigRoot = resolve11(root, ".rig");
|
|
1769
|
+
const logsDir = resolve11(rigRoot, "logs");
|
|
1770
|
+
const stateDir = resolve11(rigRoot, "state");
|
|
1771
|
+
const runtimeDir = resolve11(rigRoot, "runtime");
|
|
1772
|
+
const binDir = resolve11(rigRoot, "bin");
|
|
1714
1773
|
return {
|
|
1715
1774
|
workspaceDir: root,
|
|
1716
1775
|
rigRoot,
|
|
1717
1776
|
stateDir,
|
|
1718
1777
|
logsDir,
|
|
1719
|
-
artifactsRoot:
|
|
1778
|
+
artifactsRoot: resolve11(root, RIG_ARTIFACTS_DIRNAME),
|
|
1720
1779
|
runtimeDir,
|
|
1721
|
-
homeDir:
|
|
1722
|
-
tmpDir:
|
|
1723
|
-
cacheDir:
|
|
1724
|
-
sessionDir:
|
|
1780
|
+
homeDir: resolve11(rigRoot, "home"),
|
|
1781
|
+
tmpDir: resolve11(rigRoot, "tmp"),
|
|
1782
|
+
cacheDir: resolve11(rigRoot, "cache"),
|
|
1783
|
+
sessionDir: resolve11(rigRoot, "session"),
|
|
1725
1784
|
binDir,
|
|
1726
|
-
distDir:
|
|
1727
|
-
pluginBinDir:
|
|
1728
|
-
contextPath:
|
|
1729
|
-
controlPlaneEventsFile:
|
|
1785
|
+
distDir: resolve11(rigRoot, "dist"),
|
|
1786
|
+
pluginBinDir: resolve11(binDir, "plugins"),
|
|
1787
|
+
contextPath: resolve11(rigRoot, "runtime-context.json"),
|
|
1788
|
+
controlPlaneEventsFile: resolve11(logsDir, "control-plane.events.jsonl")
|
|
1730
1789
|
};
|
|
1731
1790
|
}
|
|
1732
1791
|
function resolveActiveRuntimeWorkspaceRoot(monorepoRoot) {
|
|
@@ -1734,14 +1793,14 @@ function resolveActiveRuntimeWorkspaceRoot(monorepoRoot) {
|
|
|
1734
1793
|
if (!explicit) {
|
|
1735
1794
|
throw new Error("No active runtime workspace. Set RIG_TASK_WORKSPACE or provision a task runtime first.");
|
|
1736
1795
|
}
|
|
1737
|
-
return
|
|
1796
|
+
return resolve11(explicit);
|
|
1738
1797
|
}
|
|
1739
1798
|
function resolveRigLayout(projectRoot) {
|
|
1740
1799
|
const monorepoRoot = resolveMonorepoRoot(projectRoot);
|
|
1741
|
-
const definitionRoot =
|
|
1800
|
+
const definitionRoot = resolve11(projectRoot, RIG_DEFINITION_DIRNAME);
|
|
1742
1801
|
const runtimeWorkspaceRoot = resolveActiveRuntimeWorkspaceRoot(monorepoRoot);
|
|
1743
1802
|
const runtimeLayout = resolveRuntimeWorkspaceLayout(runtimeWorkspaceRoot);
|
|
1744
|
-
const policyDir =
|
|
1803
|
+
const policyDir = resolve11(definitionRoot, "policy");
|
|
1745
1804
|
return {
|
|
1746
1805
|
projectRoot,
|
|
1747
1806
|
monorepoRoot,
|
|
@@ -1749,48 +1808,48 @@ function resolveRigLayout(projectRoot) {
|
|
|
1749
1808
|
runtimeWorkspaceRoot,
|
|
1750
1809
|
stateRoot: runtimeLayout.rigRoot,
|
|
1751
1810
|
artifactsRoot: runtimeLayout.artifactsRoot,
|
|
1752
|
-
configPath:
|
|
1753
|
-
taskConfigPath:
|
|
1811
|
+
configPath: resolve11(definitionRoot, "config.sh"),
|
|
1812
|
+
taskConfigPath: resolve11(runtimeWorkspaceRoot, ".rig", "task-config.json"),
|
|
1754
1813
|
policyDir,
|
|
1755
|
-
policyFile:
|
|
1756
|
-
pluginsDir:
|
|
1757
|
-
hooksDir:
|
|
1758
|
-
toolsDir:
|
|
1759
|
-
templatesDir:
|
|
1760
|
-
validationDir:
|
|
1814
|
+
policyFile: resolve11(policyDir, "policy.json"),
|
|
1815
|
+
pluginsDir: resolve11(definitionRoot, "plugins"),
|
|
1816
|
+
hooksDir: resolve11(definitionRoot, "hooks"),
|
|
1817
|
+
toolsDir: resolve11(definitionRoot, "tools"),
|
|
1818
|
+
templatesDir: resolve11(definitionRoot, "templates"),
|
|
1819
|
+
validationDir: resolve11(definitionRoot, "validation"),
|
|
1761
1820
|
stateDir: runtimeLayout.stateDir,
|
|
1762
1821
|
logsDir: runtimeLayout.logsDir,
|
|
1763
|
-
notificationsDir:
|
|
1822
|
+
notificationsDir: resolve11(definitionRoot, "notifications"),
|
|
1764
1823
|
runtimeDir: runtimeLayout.runtimeDir,
|
|
1765
1824
|
distDir: runtimeLayout.distDir,
|
|
1766
1825
|
binDir: runtimeLayout.binDir,
|
|
1767
1826
|
pluginBinDir: runtimeLayout.pluginBinDir,
|
|
1768
|
-
keybindingsPath:
|
|
1827
|
+
keybindingsPath: resolve11(definitionRoot, "keybindings.json"),
|
|
1769
1828
|
controlPlaneEventsFile: runtimeLayout.controlPlaneEventsFile
|
|
1770
1829
|
};
|
|
1771
1830
|
}
|
|
1772
1831
|
|
|
1773
1832
|
// packages/runtime/src/control-plane/native/runtime-native.ts
|
|
1774
1833
|
import { dlopen, ptr, suffix, toBuffer } from "bun:ffi";
|
|
1775
|
-
import { copyFileSync as copyFileSync2, existsSync as
|
|
1834
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync11, mkdirSync as mkdirSync6, renameSync as renameSync2, rmSync as rmSync3, statSync as statSync2 } from "fs";
|
|
1776
1835
|
import { tmpdir as tmpdir4 } from "os";
|
|
1777
|
-
import { dirname as
|
|
1778
|
-
var sharedNativeRuntimeOutputDir =
|
|
1779
|
-
var sharedNativeRuntimeOutputPath =
|
|
1836
|
+
import { dirname as dirname8, resolve as resolve12 } from "path";
|
|
1837
|
+
var sharedNativeRuntimeOutputDir = resolve12(tmpdir4(), "rig-native");
|
|
1838
|
+
var sharedNativeRuntimeOutputPath = resolve12(sharedNativeRuntimeOutputDir, `runtime-native-${process.platform}-${process.arch}.${suffix}`);
|
|
1780
1839
|
var colocatedNativeRuntimeFileName = `runtime-native.${suffix}`;
|
|
1781
1840
|
var nativeRuntimeLibrary = await loadNativeRuntimeLibrary();
|
|
1782
1841
|
async function ensureNativeRuntimeLibraryPath(outputPath = sharedNativeRuntimeOutputPath, options = {}) {
|
|
1783
1842
|
if (await buildNativeRuntimeLibrary(outputPath, options)) {
|
|
1784
1843
|
return outputPath;
|
|
1785
1844
|
}
|
|
1786
|
-
return !options.force &&
|
|
1845
|
+
return !options.force && existsSync11(outputPath) ? outputPath : null;
|
|
1787
1846
|
}
|
|
1788
1847
|
async function loadNativeRuntimeLibrary() {
|
|
1789
1848
|
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
1790
1849
|
return null;
|
|
1791
1850
|
}
|
|
1792
1851
|
for (const candidate of nativeRuntimeLibraryCandidates()) {
|
|
1793
|
-
if (!candidate || !
|
|
1852
|
+
if (!candidate || !existsSync11(candidate)) {
|
|
1794
1853
|
continue;
|
|
1795
1854
|
}
|
|
1796
1855
|
const loaded = tryDlopenNativeRuntimeLibrary(candidate);
|
|
@@ -1806,12 +1865,12 @@ async function loadNativeRuntimeLibrary() {
|
|
|
1806
1865
|
}
|
|
1807
1866
|
function nativePackageLibraryCandidates(fromDir, names) {
|
|
1808
1867
|
const candidates = [];
|
|
1809
|
-
let cursor =
|
|
1868
|
+
let cursor = resolve12(fromDir);
|
|
1810
1869
|
for (let index = 0;index < 8; index += 1) {
|
|
1811
1870
|
for (const name of names) {
|
|
1812
|
-
candidates.push(
|
|
1871
|
+
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));
|
|
1813
1872
|
}
|
|
1814
|
-
const parent =
|
|
1873
|
+
const parent = dirname8(cursor);
|
|
1815
1874
|
if (parent === cursor)
|
|
1816
1875
|
break;
|
|
1817
1876
|
cursor = parent;
|
|
@@ -1820,27 +1879,27 @@ function nativePackageLibraryCandidates(fromDir, names) {
|
|
|
1820
1879
|
}
|
|
1821
1880
|
function nativeRuntimeLibraryCandidates() {
|
|
1822
1881
|
const explicit = process.env.RIG_NATIVE_RUNTIME_LIB?.trim() || "";
|
|
1823
|
-
const execDir = process.execPath?.trim() ?
|
|
1882
|
+
const execDir = process.execPath?.trim() ? dirname8(process.execPath.trim()) : "";
|
|
1824
1883
|
const platformSpecific = `runtime-native-${process.platform}-${process.arch}.${suffix}`;
|
|
1825
1884
|
return [...new Set([
|
|
1826
1885
|
explicit,
|
|
1827
1886
|
...nativePackageLibraryCandidates(import.meta.dir, [colocatedNativeRuntimeFileName, platformSpecific]),
|
|
1828
|
-
execDir ?
|
|
1829
|
-
execDir ?
|
|
1830
|
-
execDir ?
|
|
1831
|
-
execDir ?
|
|
1832
|
-
execDir ?
|
|
1833
|
-
execDir ?
|
|
1887
|
+
execDir ? resolve12(execDir, colocatedNativeRuntimeFileName) : "",
|
|
1888
|
+
execDir ? resolve12(execDir, platformSpecific) : "",
|
|
1889
|
+
execDir ? resolve12(execDir, "..", colocatedNativeRuntimeFileName) : "",
|
|
1890
|
+
execDir ? resolve12(execDir, "..", platformSpecific) : "",
|
|
1891
|
+
execDir ? resolve12(execDir, "lib", colocatedNativeRuntimeFileName) : "",
|
|
1892
|
+
execDir ? resolve12(execDir, "..", "lib", colocatedNativeRuntimeFileName) : "",
|
|
1834
1893
|
sharedNativeRuntimeOutputPath
|
|
1835
1894
|
].filter(Boolean))];
|
|
1836
1895
|
}
|
|
1837
1896
|
function resolveNativeRuntimeSourcePath() {
|
|
1838
1897
|
const explicit = process.env.RIG_NATIVE_RUNTIME_SOURCE?.trim();
|
|
1839
|
-
if (explicit &&
|
|
1898
|
+
if (explicit && existsSync11(explicit)) {
|
|
1840
1899
|
return explicit;
|
|
1841
1900
|
}
|
|
1842
|
-
const bundled =
|
|
1843
|
-
return
|
|
1901
|
+
const bundled = resolve12(import.meta.dir, "../../../native/snapshot.zig");
|
|
1902
|
+
return existsSync11(bundled) ? bundled : null;
|
|
1844
1903
|
}
|
|
1845
1904
|
async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
1846
1905
|
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
@@ -1853,8 +1912,8 @@ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
|
1853
1912
|
}
|
|
1854
1913
|
const tempOutputPath = `${outputPath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
1855
1914
|
try {
|
|
1856
|
-
|
|
1857
|
-
const needsBuild = options.force === true || !
|
|
1915
|
+
mkdirSync6(dirname8(outputPath), { recursive: true });
|
|
1916
|
+
const needsBuild = options.force === true || !existsSync11(outputPath) || statSync2(sourcePath).mtimeMs > statSync2(outputPath).mtimeMs;
|
|
1858
1917
|
if (!needsBuild) {
|
|
1859
1918
|
return true;
|
|
1860
1919
|
}
|
|
@@ -1872,7 +1931,7 @@ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
|
1872
1931
|
stderr: "pipe"
|
|
1873
1932
|
});
|
|
1874
1933
|
const exitCode = await build.exited;
|
|
1875
|
-
if (exitCode !== 0 || !
|
|
1934
|
+
if (exitCode !== 0 || !existsSync11(tempOutputPath)) {
|
|
1876
1935
|
rmSync3(tempOutputPath, { force: true });
|
|
1877
1936
|
return false;
|
|
1878
1937
|
}
|
|
@@ -2002,11 +2061,11 @@ async function runCaptureAsync(command, cwd, env, timeoutMs) {
|
|
|
2002
2061
|
return { exitCode, stdout, stderr };
|
|
2003
2062
|
}
|
|
2004
2063
|
function readJsonFile(path, fallback) {
|
|
2005
|
-
if (!
|
|
2064
|
+
if (!existsSync12(path)) {
|
|
2006
2065
|
return fallback;
|
|
2007
2066
|
}
|
|
2008
2067
|
try {
|
|
2009
|
-
return JSON.parse(
|
|
2068
|
+
return JSON.parse(readFileSync8(path, "utf-8"));
|
|
2010
2069
|
} catch {
|
|
2011
2070
|
return fallback;
|
|
2012
2071
|
}
|
|
@@ -2020,31 +2079,31 @@ function unique(values) {
|
|
|
2020
2079
|
function resolveHarnessPaths(projectRoot) {
|
|
2021
2080
|
const hasRuntimeWorkspace = Boolean(process.env.RIG_TASK_WORKSPACE?.trim());
|
|
2022
2081
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
2023
|
-
const harnessRoot =
|
|
2024
|
-
const stateRoot =
|
|
2082
|
+
const harnessRoot = resolve13(projectRoot, "rig");
|
|
2083
|
+
const stateRoot = resolve13(projectRoot, ".rig");
|
|
2025
2084
|
const layout = hasRuntimeWorkspace ? resolveRigLayout(projectRoot) : null;
|
|
2026
|
-
const stateDir = layout?.stateDir ??
|
|
2027
|
-
const logsDir = layout?.logsDir ??
|
|
2028
|
-
const artifactsDir = layout?.artifactsRoot ??
|
|
2029
|
-
const taskConfigPath = layout?.taskConfigPath ??
|
|
2030
|
-
const binDir = layout?.binDir ??
|
|
2085
|
+
const stateDir = layout?.stateDir ?? resolve13(stateRoot, "state");
|
|
2086
|
+
const logsDir = layout?.logsDir ?? resolve13(stateRoot, "logs");
|
|
2087
|
+
const artifactsDir = layout?.artifactsRoot ?? resolve13(monorepoRoot, "artifacts");
|
|
2088
|
+
const taskConfigPath = layout?.taskConfigPath ?? resolve13(monorepoRoot, ".rig", "task-config.json");
|
|
2089
|
+
const binDir = layout?.binDir ?? resolve13(stateRoot, "bin");
|
|
2031
2090
|
return {
|
|
2032
2091
|
harnessRoot,
|
|
2033
2092
|
stateDir: process.env.RIG_STATE_DIR || stateDir,
|
|
2034
2093
|
artifactsDir,
|
|
2035
2094
|
logsDir: process.env.RIG_LOGS_DIR || logsDir,
|
|
2036
2095
|
binDir,
|
|
2037
|
-
hooksDir:
|
|
2038
|
-
validationDir:
|
|
2096
|
+
hooksDir: resolve13(harnessRoot, "hooks"),
|
|
2097
|
+
validationDir: resolve13(harnessRoot, "validation"),
|
|
2039
2098
|
taskConfigPath,
|
|
2040
|
-
sessionPath: process.env.RIG_SESSION_FILE ||
|
|
2099
|
+
sessionPath: process.env.RIG_SESSION_FILE || resolve13(stateRoot, "session", "session.json"),
|
|
2041
2100
|
monorepoRoot,
|
|
2042
|
-
tsApiTestsDir: process.env.TS_API_TESTS_DIR ||
|
|
2043
|
-
taskRepoCommitsPath:
|
|
2044
|
-
baseRepoPinsPath:
|
|
2045
|
-
failedApproachesPath:
|
|
2046
|
-
agentProfilePath:
|
|
2047
|
-
reviewProfilePath:
|
|
2101
|
+
tsApiTestsDir: process.env.TS_API_TESTS_DIR || resolve13(monorepoRoot, "TSAPITests"),
|
|
2102
|
+
taskRepoCommitsPath: resolve13(stateDir, "task-repo-commits.json"),
|
|
2103
|
+
baseRepoPinsPath: resolve13(stateDir, "base-repo-pins.json"),
|
|
2104
|
+
failedApproachesPath: resolve13(stateDir, "failed_approaches.md"),
|
|
2105
|
+
agentProfilePath: resolve13(stateDir, "agent-profile.json"),
|
|
2106
|
+
reviewProfilePath: resolve13(stateDir, "review-profile.json")
|
|
2048
2107
|
};
|
|
2049
2108
|
}
|
|
2050
2109
|
function normalizeRelativeScopePath(inputPath) {
|
|
@@ -2102,34 +2161,34 @@ function monorepoSearchCandidates(inputPath) {
|
|
|
2102
2161
|
}
|
|
2103
2162
|
|
|
2104
2163
|
// packages/runtime/src/control-plane/state-sync/repo.ts
|
|
2105
|
-
import { existsSync as
|
|
2106
|
-
import { resolve as
|
|
2164
|
+
import { existsSync as existsSync14 } from "fs";
|
|
2165
|
+
import { resolve as resolve15 } from "path";
|
|
2107
2166
|
|
|
2108
2167
|
// packages/runtime/src/control-plane/repos/layout.ts
|
|
2109
|
-
import { existsSync as
|
|
2110
|
-
import { basename as basename5, dirname as
|
|
2168
|
+
import { existsSync as existsSync13 } from "fs";
|
|
2169
|
+
import { basename as basename5, dirname as dirname9, join as join3, resolve as resolve14 } from "path";
|
|
2111
2170
|
function resolveRepoStateDir(projectRoot) {
|
|
2112
|
-
const normalizedProjectRoot =
|
|
2113
|
-
const projectParent =
|
|
2171
|
+
const normalizedProjectRoot = resolve14(projectRoot);
|
|
2172
|
+
const projectParent = dirname9(normalizedProjectRoot);
|
|
2114
2173
|
if (basename5(projectParent) === ".worktrees") {
|
|
2115
|
-
const ownerRoot =
|
|
2116
|
-
const ownerHasRepoMarkers =
|
|
2174
|
+
const ownerRoot = dirname9(projectParent);
|
|
2175
|
+
const ownerHasRepoMarkers = existsSync13(resolve14(ownerRoot, ".git")) || existsSync13(resolve14(ownerRoot, ".rig", "state"));
|
|
2117
2176
|
if (ownerHasRepoMarkers) {
|
|
2118
|
-
return
|
|
2177
|
+
return resolve14(ownerRoot, ".rig", "state");
|
|
2119
2178
|
}
|
|
2120
2179
|
}
|
|
2121
|
-
return
|
|
2180
|
+
return resolve14(projectRoot, ".rig", "state");
|
|
2122
2181
|
}
|
|
2123
2182
|
function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
2124
|
-
const normalizedProjectRoot =
|
|
2183
|
+
const normalizedProjectRoot = resolve14(projectRoot);
|
|
2125
2184
|
const entry = getManagedRepoEntry(repoId);
|
|
2126
2185
|
const stateDir = resolveRepoStateDir(normalizedProjectRoot);
|
|
2127
2186
|
const metadataRelativePath = join3("repos", entry.id);
|
|
2128
|
-
const metadataRoot =
|
|
2187
|
+
const metadataRoot = resolve14(stateDir, metadataRelativePath);
|
|
2129
2188
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
2130
|
-
const runsInsideTaskWorktree = runtimeWorkspace &&
|
|
2189
|
+
const runsInsideTaskWorktree = runtimeWorkspace && resolve14(runtimeWorkspace) === normalizedProjectRoot || basename5(dirname9(normalizedProjectRoot)) === ".worktrees";
|
|
2131
2190
|
const isPrimaryManagedRepo = listManagedRepoEntries()[0]?.id === repoId;
|
|
2132
|
-
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ?
|
|
2191
|
+
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ? resolve14(process.env[entry.checkoutEnvVar].trim()) : resolve14(normalizedProjectRoot, entry.alias);
|
|
2133
2192
|
return {
|
|
2134
2193
|
projectRoot: normalizedProjectRoot,
|
|
2135
2194
|
repoId: entry.id,
|
|
@@ -2137,12 +2196,12 @@ function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
|
2137
2196
|
defaultBranch: entry.defaultBranch,
|
|
2138
2197
|
remoteUrl: entry.remoteEnvVar && process.env[entry.remoteEnvVar]?.trim() ? process.env[entry.remoteEnvVar].trim() : entry.defaultRemoteUrl,
|
|
2139
2198
|
checkoutRoot,
|
|
2140
|
-
worktreesRoot:
|
|
2199
|
+
worktreesRoot: resolve14(checkoutRoot, ".worktrees"),
|
|
2141
2200
|
stateDir,
|
|
2142
2201
|
metadataRoot,
|
|
2143
2202
|
metadataRelativePath,
|
|
2144
|
-
mirrorRoot:
|
|
2145
|
-
mirrorStatePath:
|
|
2203
|
+
mirrorRoot: resolve14(metadataRoot, "mirror.git"),
|
|
2204
|
+
mirrorStatePath: resolve14(metadataRoot, "mirror-state.json"),
|
|
2146
2205
|
mirrorStateRelativePath: join3(metadataRelativePath, "mirror-state.json")
|
|
2147
2206
|
};
|
|
2148
2207
|
}
|
|
@@ -2160,7 +2219,7 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
2160
2219
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
2161
2220
|
try {
|
|
2162
2221
|
const layout = resolveMonorepoRepoLayout(projectRoot);
|
|
2163
|
-
if (
|
|
2222
|
+
if (existsSync14(resolve15(layout.mirrorRoot, "HEAD"))) {
|
|
2164
2223
|
return layout.mirrorRoot;
|
|
2165
2224
|
}
|
|
2166
2225
|
} catch {}
|
|
@@ -2171,8 +2230,8 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
2171
2230
|
var DEFAULT_READ_DEPS = {
|
|
2172
2231
|
fetchRef: nativeFetchRef,
|
|
2173
2232
|
readBlobAtRef: nativeReadBlobAtRef,
|
|
2174
|
-
exists:
|
|
2175
|
-
readFile: (path) =>
|
|
2233
|
+
exists: existsSync15,
|
|
2234
|
+
readFile: (path) => readFileSync9(path, "utf8")
|
|
2176
2235
|
};
|
|
2177
2236
|
function parseIssueStatus(rawStatus) {
|
|
2178
2237
|
const normalized = normalizeTaskLifecycleStatus(rawStatus);
|
|
@@ -2253,12 +2312,12 @@ function shouldPreferLocalTrackerState(options) {
|
|
|
2253
2312
|
if (runtimeContextPath) {
|
|
2254
2313
|
return true;
|
|
2255
2314
|
}
|
|
2256
|
-
return
|
|
2315
|
+
return existsSync15(resolve16(runtimeWorkspace, ".rig", "runtime-context.json"));
|
|
2257
2316
|
}
|
|
2258
2317
|
function readLocalTrackerState(projectRoot, deps) {
|
|
2259
2318
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
2260
|
-
const issuesPath =
|
|
2261
|
-
const taskStatePath =
|
|
2319
|
+
const issuesPath = resolve16(monorepoRoot, ".beads", "issues.jsonl");
|
|
2320
|
+
const taskStatePath = resolve16(monorepoRoot, ".beads", "task-state.json");
|
|
2262
2321
|
return projectSyncedTrackerSnapshot({
|
|
2263
2322
|
source: "local",
|
|
2264
2323
|
issuesBaseOid: null,
|
|
@@ -2572,7 +2631,7 @@ function readValidationDescriptions(projectRoot) {
|
|
|
2572
2631
|
return readValidationDescriptionMap(raw);
|
|
2573
2632
|
}
|
|
2574
2633
|
function readSourceValidationDescriptions(projectRoot) {
|
|
2575
|
-
const rootRaw = readJsonFile(
|
|
2634
|
+
const rootRaw = readJsonFile(resolve17(projectRoot, "rig", "task-config.json"), {});
|
|
2576
2635
|
const sourcePath = findSourceTaskConfigPath(projectRoot);
|
|
2577
2636
|
const sourceRaw = sourcePath ? readJsonFile(sourcePath, {}) : {};
|
|
2578
2637
|
const rootDescriptions = readValidationDescriptionMap(rootRaw);
|
|
@@ -2648,15 +2707,15 @@ function readValidationDescriptionsFromMeta(meta) {
|
|
|
2648
2707
|
return meta.validation_descriptions;
|
|
2649
2708
|
}
|
|
2650
2709
|
function readLocalSourceTaskStateEnvelope(projectRoot) {
|
|
2651
|
-
const taskStatePath =
|
|
2710
|
+
const taskStatePath = resolve17(resolveMonorepoRoot2(projectRoot), ".beads", "task-state.json");
|
|
2652
2711
|
return readTaskStateMetadataEnvelope(readJsonFile(taskStatePath, {}));
|
|
2653
2712
|
}
|
|
2654
2713
|
function readLocalSourceTaskLifecycleStatus(projectRoot, taskId) {
|
|
2655
|
-
const issuesPath =
|
|
2656
|
-
if (!
|
|
2714
|
+
const issuesPath = resolve17(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
2715
|
+
if (!existsSync16(issuesPath)) {
|
|
2657
2716
|
return null;
|
|
2658
2717
|
}
|
|
2659
|
-
for (const line of
|
|
2718
|
+
for (const line of readFileSync10(issuesPath, "utf8").split(/\r?\n/)) {
|
|
2660
2719
|
const trimmed = line.trim();
|
|
2661
2720
|
if (!trimmed) {
|
|
2662
2721
|
continue;
|
|
@@ -2697,25 +2756,25 @@ function lookupTask(projectRoot, input) {
|
|
|
2697
2756
|
function artifactDirForId(projectRoot, id) {
|
|
2698
2757
|
const workspaceDir = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
2699
2758
|
if (workspaceDir) {
|
|
2700
|
-
const worktreeArtifacts =
|
|
2701
|
-
if (
|
|
2759
|
+
const worktreeArtifacts = resolve17(workspaceDir, "artifacts", id);
|
|
2760
|
+
if (existsSync16(worktreeArtifacts) || existsSync16(resolve17(workspaceDir, "artifacts"))) {
|
|
2702
2761
|
return worktreeArtifacts;
|
|
2703
2762
|
}
|
|
2704
2763
|
}
|
|
2705
2764
|
try {
|
|
2706
2765
|
const paths = resolveHarnessPaths(projectRoot);
|
|
2707
|
-
return
|
|
2766
|
+
return resolve17(paths.artifactsDir, id);
|
|
2708
2767
|
} catch {
|
|
2709
|
-
return
|
|
2768
|
+
return resolve17(resolveMonorepoRoot2(projectRoot), "artifacts", id);
|
|
2710
2769
|
}
|
|
2711
2770
|
}
|
|
2712
2771
|
function resolveTaskConfigPath(projectRoot) {
|
|
2713
2772
|
const paths = resolveHarnessPaths(projectRoot);
|
|
2714
|
-
if (
|
|
2773
|
+
if (existsSync16(paths.taskConfigPath)) {
|
|
2715
2774
|
return paths.taskConfigPath;
|
|
2716
2775
|
}
|
|
2717
2776
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
2718
|
-
if (
|
|
2777
|
+
if (existsSync16(candidate)) {
|
|
2719
2778
|
return candidate;
|
|
2720
2779
|
}
|
|
2721
2780
|
}
|
|
@@ -2723,7 +2782,7 @@ function resolveTaskConfigPath(projectRoot) {
|
|
|
2723
2782
|
}
|
|
2724
2783
|
function findSourceTaskConfigPath(projectRoot) {
|
|
2725
2784
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
2726
|
-
if (
|
|
2785
|
+
if (existsSync16(candidate)) {
|
|
2727
2786
|
return candidate;
|
|
2728
2787
|
}
|
|
2729
2788
|
}
|
|
@@ -2736,7 +2795,7 @@ function readAndSyncSourceTaskConfig(projectRoot) {
|
|
|
2736
2795
|
const synced = synchronizeTaskConfigWithTracker(projectRoot, raw);
|
|
2737
2796
|
if (sourcePath && synced.updated) {
|
|
2738
2797
|
try {
|
|
2739
|
-
|
|
2798
|
+
writeFileSync7(sourcePath, `${JSON.stringify(synced.config, null, 2)}
|
|
2740
2799
|
`, "utf-8");
|
|
2741
2800
|
} catch {}
|
|
2742
2801
|
}
|
|
@@ -2788,12 +2847,12 @@ function shouldRefreshAutoSyncedTaskConfigEntry(entry) {
|
|
|
2788
2847
|
return !candidate.role;
|
|
2789
2848
|
}
|
|
2790
2849
|
function readSourceIssueRecords(projectRoot) {
|
|
2791
|
-
const issuesPath =
|
|
2792
|
-
if (!
|
|
2850
|
+
const issuesPath = resolve17(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
2851
|
+
if (!existsSync16(issuesPath)) {
|
|
2793
2852
|
return [];
|
|
2794
2853
|
}
|
|
2795
2854
|
const records = [];
|
|
2796
|
-
for (const line of
|
|
2855
|
+
for (const line of readFileSync10(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
2797
2856
|
const trimmed = line.trim();
|
|
2798
2857
|
if (!trimmed) {
|
|
2799
2858
|
continue;
|
|
@@ -2849,19 +2908,19 @@ function readConfiguredFileTaskConfig(projectRoot) {
|
|
|
2849
2908
|
if (!sourcePath) {
|
|
2850
2909
|
return {};
|
|
2851
2910
|
}
|
|
2852
|
-
const directory =
|
|
2853
|
-
if (!
|
|
2911
|
+
const directory = resolve17(projectRoot, sourcePath);
|
|
2912
|
+
if (!existsSync16(directory)) {
|
|
2854
2913
|
return {};
|
|
2855
2914
|
}
|
|
2856
2915
|
const config = {};
|
|
2857
2916
|
for (const name of readdirSync3(directory)) {
|
|
2858
2917
|
if (!FILE_TASK_PATTERN2.test(name))
|
|
2859
2918
|
continue;
|
|
2860
|
-
const file =
|
|
2919
|
+
const file = resolve17(directory, name);
|
|
2861
2920
|
try {
|
|
2862
2921
|
if (!statSync3(file).isFile())
|
|
2863
2922
|
continue;
|
|
2864
|
-
const raw = JSON.parse(
|
|
2923
|
+
const raw = JSON.parse(readFileSync10(file, "utf8"));
|
|
2865
2924
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
2866
2925
|
continue;
|
|
2867
2926
|
const record = raw;
|
|
@@ -2903,10 +2962,10 @@ function firstStringList2(...candidates) {
|
|
|
2903
2962
|
return [];
|
|
2904
2963
|
}
|
|
2905
2964
|
function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
2906
|
-
const jsonPath =
|
|
2907
|
-
if (
|
|
2965
|
+
const jsonPath = resolve17(projectRoot, "rig.config.json");
|
|
2966
|
+
if (existsSync16(jsonPath)) {
|
|
2908
2967
|
try {
|
|
2909
|
-
const parsed = JSON.parse(
|
|
2968
|
+
const parsed = JSON.parse(readFileSync10(jsonPath, "utf8"));
|
|
2910
2969
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
2911
2970
|
const taskSource = parsed.taskSource;
|
|
2912
2971
|
if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
|
|
@@ -2918,12 +2977,12 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
2918
2977
|
return null;
|
|
2919
2978
|
}
|
|
2920
2979
|
}
|
|
2921
|
-
const tsPath =
|
|
2922
|
-
if (!
|
|
2980
|
+
const tsPath = resolve17(projectRoot, "rig.config.ts");
|
|
2981
|
+
if (!existsSync16(tsPath)) {
|
|
2923
2982
|
return null;
|
|
2924
2983
|
}
|
|
2925
2984
|
try {
|
|
2926
|
-
const source =
|
|
2985
|
+
const source = readFileSync10(tsPath, "utf8");
|
|
2927
2986
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
2928
2987
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
2929
2988
|
if (kind !== "files") {
|
|
@@ -2937,23 +2996,23 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
2937
2996
|
function sourceTaskConfigCandidates(projectRoot) {
|
|
2938
2997
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
2939
2998
|
return [
|
|
2940
|
-
runtimeContext?.monorepoMainRoot ?
|
|
2941
|
-
process.env.MONOREPO_MAIN_ROOT?.trim() ?
|
|
2942
|
-
|
|
2999
|
+
runtimeContext?.monorepoMainRoot ? resolve17(runtimeContext.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
3000
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve17(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
3001
|
+
resolve17(resolveMonorepoRoot2(projectRoot), ".rig", "task-config.json")
|
|
2943
3002
|
].filter(Boolean);
|
|
2944
3003
|
}
|
|
2945
3004
|
|
|
2946
3005
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
2947
|
-
import { existsSync as
|
|
2948
|
-
import { resolve as
|
|
3006
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
3007
|
+
import { resolve as resolve22 } from "path";
|
|
2949
3008
|
|
|
2950
3009
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
2951
|
-
import { existsSync as
|
|
2952
|
-
import { dirname as
|
|
3010
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync8, rmSync as rmSync5, statSync as statSync4 } from "fs";
|
|
3011
|
+
import { dirname as dirname11, resolve as resolve21 } from "path";
|
|
2953
3012
|
|
|
2954
3013
|
// packages/runtime/src/binary-run.ts
|
|
2955
|
-
import { chmodSync as chmodSync2, cpSync, existsSync as
|
|
2956
|
-
import { basename as basename7, dirname as
|
|
3014
|
+
import { chmodSync as chmodSync2, cpSync, existsSync as existsSync17, mkdirSync as mkdirSync7, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
3015
|
+
import { basename as basename7, dirname as dirname10, resolve as resolve18 } from "path";
|
|
2957
3016
|
import { fileURLToPath } from "url";
|
|
2958
3017
|
import { drainMicrotasks, gcAndSweep } from "bun:jsc";
|
|
2959
3018
|
var runtimeBinaryBuildQueue = Promise.resolve();
|
|
@@ -2979,9 +3038,9 @@ async function buildRuntimeBinary(options) {
|
|
|
2979
3038
|
});
|
|
2980
3039
|
}
|
|
2981
3040
|
async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
2982
|
-
const tempBuildDir =
|
|
2983
|
-
const tempOutputPath =
|
|
2984
|
-
|
|
3041
|
+
const tempBuildDir = resolve18(dirname10(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
3042
|
+
const tempOutputPath = resolve18(tempBuildDir, basename7(options.outputPath));
|
|
3043
|
+
mkdirSync7(tempBuildDir, { recursive: true });
|
|
2985
3044
|
await withTemporaryEnv({
|
|
2986
3045
|
...options.env,
|
|
2987
3046
|
...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
|
|
@@ -3006,7 +3065,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
3006
3065
|
`);
|
|
3007
3066
|
throw new Error(`Failed to build ${options.entrypoint}: ${details || "Bun.build() returned errors"}`);
|
|
3008
3067
|
}
|
|
3009
|
-
if (!
|
|
3068
|
+
if (!existsSync17(tempOutputPath)) {
|
|
3010
3069
|
const emitted = buildResult.outputs.map((output) => output.path).join(", ") || "(none)";
|
|
3011
3070
|
throw new Error(`Failed to build ${options.entrypoint}: Bun.build() did not emit ${tempOutputPath}. Emitted: ${emitted}`);
|
|
3012
3071
|
}
|
|
@@ -3038,8 +3097,8 @@ function runtimeBinaryCacheManifestPath(outputPath) {
|
|
|
3038
3097
|
function resolveRuntimeBinaryBuildOptions(options) {
|
|
3039
3098
|
return {
|
|
3040
3099
|
...options,
|
|
3041
|
-
entrypoint:
|
|
3042
|
-
outputPath:
|
|
3100
|
+
entrypoint: resolve18(options.cwd, options.sourcePath),
|
|
3101
|
+
outputPath: resolve18(options.outputPath)
|
|
3043
3102
|
};
|
|
3044
3103
|
}
|
|
3045
3104
|
function shouldUseRuntimeBinaryBuildWorker() {
|
|
@@ -3053,7 +3112,7 @@ function shouldUseRuntimeBinaryBuildWorker() {
|
|
|
3053
3112
|
}
|
|
3054
3113
|
async function buildRuntimeBinaryViaWorker(options) {
|
|
3055
3114
|
const workerSourcePath = resolveRuntimeBinaryBuildWorkerSourcePath(options);
|
|
3056
|
-
if (!workerSourcePath || !
|
|
3115
|
+
if (!workerSourcePath || !existsSync17(workerSourcePath)) {
|
|
3057
3116
|
await buildRuntimeBinaryInProcess(options, {
|
|
3058
3117
|
manifestPath: runtimeBinaryCacheManifestPath(options.outputPath),
|
|
3059
3118
|
buildKey: createRuntimeBinaryBuildKey({
|
|
@@ -3090,7 +3149,7 @@ async function buildRuntimeBinaryViaWorker(options) {
|
|
|
3090
3149
|
}
|
|
3091
3150
|
}
|
|
3092
3151
|
function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
|
|
3093
|
-
return
|
|
3152
|
+
return resolve18(dirname10(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
3094
3153
|
}
|
|
3095
3154
|
function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
3096
3155
|
const envRoots = [
|
|
@@ -3099,13 +3158,13 @@ function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
|
3099
3158
|
process.env.PROJECT_RIG_ROOT?.trim()
|
|
3100
3159
|
].filter(Boolean);
|
|
3101
3160
|
for (const root of envRoots) {
|
|
3102
|
-
const candidate =
|
|
3103
|
-
if (
|
|
3161
|
+
const candidate = resolve18(root, "packages/runtime/src/binary-build-worker.ts");
|
|
3162
|
+
if (existsSync17(candidate)) {
|
|
3104
3163
|
return candidate;
|
|
3105
3164
|
}
|
|
3106
3165
|
}
|
|
3107
|
-
const localCandidate =
|
|
3108
|
-
return
|
|
3166
|
+
const localCandidate = resolve18(import.meta.dir, "binary-build-worker.ts");
|
|
3167
|
+
return existsSync17(localCandidate) ? localCandidate : null;
|
|
3109
3168
|
}
|
|
3110
3169
|
function resolveRuntimeBinaryBuildWorkerInvocation() {
|
|
3111
3170
|
const bunPath = Bun.which("bun");
|
|
@@ -3141,7 +3200,7 @@ function createRuntimeBinaryBuildKey(input) {
|
|
|
3141
3200
|
});
|
|
3142
3201
|
}
|
|
3143
3202
|
async function isRuntimeBinaryBuildFresh(input) {
|
|
3144
|
-
if (!
|
|
3203
|
+
if (!existsSync17(input.outputPath) || !existsSync17(input.manifestPath)) {
|
|
3145
3204
|
return false;
|
|
3146
3205
|
}
|
|
3147
3206
|
let manifest = null;
|
|
@@ -3154,7 +3213,7 @@ async function isRuntimeBinaryBuildFresh(input) {
|
|
|
3154
3213
|
return false;
|
|
3155
3214
|
}
|
|
3156
3215
|
for (const [filePath, expectedDigest] of Object.entries(manifest.inputs || {})) {
|
|
3157
|
-
if (!
|
|
3216
|
+
if (!existsSync17(filePath)) {
|
|
3158
3217
|
return false;
|
|
3159
3218
|
}
|
|
3160
3219
|
if (await sha256File(filePath) !== expectedDigest) {
|
|
@@ -3167,7 +3226,7 @@ async function writeRuntimeBinaryCacheManifest(input) {
|
|
|
3167
3226
|
const inputs = {};
|
|
3168
3227
|
for (const inputPath of Object.keys(input.metafile?.inputs || {}).sort()) {
|
|
3169
3228
|
const normalized = normalizeBuildInputPath(input.cwd, inputPath);
|
|
3170
|
-
if (!normalized || !
|
|
3229
|
+
if (!normalized || !existsSync17(normalized)) {
|
|
3171
3230
|
continue;
|
|
3172
3231
|
}
|
|
3173
3232
|
inputs[normalized] = await sha256File(normalized);
|
|
@@ -3190,7 +3249,7 @@ function normalizeBuildInputPath(cwd, inputPath) {
|
|
|
3190
3249
|
if (inputPath.startsWith("<")) {
|
|
3191
3250
|
return null;
|
|
3192
3251
|
}
|
|
3193
|
-
return
|
|
3252
|
+
return resolve18(cwd, inputPath);
|
|
3194
3253
|
}
|
|
3195
3254
|
async function sha256File(path) {
|
|
3196
3255
|
const hasher = new Bun.CryptoHasher("sha256");
|
|
@@ -3206,8 +3265,8 @@ function sortRecord(value) {
|
|
|
3206
3265
|
async function runSerializedRuntimeBinaryBuild(action) {
|
|
3207
3266
|
const previous = runtimeBinaryBuildQueue;
|
|
3208
3267
|
let release;
|
|
3209
|
-
runtimeBinaryBuildQueue = new Promise((
|
|
3210
|
-
release =
|
|
3268
|
+
runtimeBinaryBuildQueue = new Promise((resolve19) => {
|
|
3269
|
+
release = resolve19;
|
|
3211
3270
|
});
|
|
3212
3271
|
await previous;
|
|
3213
3272
|
try {
|
|
@@ -3252,11 +3311,11 @@ async function withTemporaryCwd(cwd, action) {
|
|
|
3252
3311
|
}
|
|
3253
3312
|
|
|
3254
3313
|
// packages/runtime/src/control-plane/runtime/provisioning-env.ts
|
|
3255
|
-
import { delimiter, resolve as
|
|
3314
|
+
import { delimiter, resolve as resolve20 } from "path";
|
|
3256
3315
|
|
|
3257
3316
|
// packages/runtime/src/control-plane/runtime/runtime-paths.ts
|
|
3258
|
-
import { existsSync as
|
|
3259
|
-
import { resolve as
|
|
3317
|
+
import { existsSync as existsSync18, readdirSync as readdirSync4, realpathSync } from "fs";
|
|
3318
|
+
import { resolve as resolve19 } from "path";
|
|
3260
3319
|
|
|
3261
3320
|
// packages/runtime/src/control-plane/runtime/sandbox/utils.ts
|
|
3262
3321
|
function uniq(values) {
|
|
@@ -3274,7 +3333,7 @@ function resolveBunBinaryPath() {
|
|
|
3274
3333
|
}
|
|
3275
3334
|
const home = process.env.HOME?.trim();
|
|
3276
3335
|
const fallbackCandidates = [
|
|
3277
|
-
home ?
|
|
3336
|
+
home ? resolve19(home, ".bun/bin/bun") : "",
|
|
3278
3337
|
"/opt/homebrew/bin/bun",
|
|
3279
3338
|
"/usr/local/bin/bun",
|
|
3280
3339
|
"/usr/bin/bun"
|
|
@@ -3302,8 +3361,8 @@ function resolveClaudeBinaryPath() {
|
|
|
3302
3361
|
}
|
|
3303
3362
|
const home = process.env.HOME?.trim();
|
|
3304
3363
|
const fallbackCandidates = [
|
|
3305
|
-
home ?
|
|
3306
|
-
home ?
|
|
3364
|
+
home ? resolve19(home, ".local/bin/claude") : "",
|
|
3365
|
+
home ? resolve19(home, ".local/share/claude/local/claude") : "",
|
|
3307
3366
|
"/opt/homebrew/bin/claude",
|
|
3308
3367
|
"/usr/local/bin/claude",
|
|
3309
3368
|
"/usr/bin/claude"
|
|
@@ -3317,51 +3376,51 @@ function resolveClaudeBinaryPath() {
|
|
|
3317
3376
|
throw new Error("claude not found in PATH");
|
|
3318
3377
|
}
|
|
3319
3378
|
function resolveBunInstallDir(bunBinaryPath = resolveBunBinaryPath()) {
|
|
3320
|
-
return
|
|
3379
|
+
return resolve19(bunBinaryPath, "../..");
|
|
3321
3380
|
}
|
|
3322
3381
|
function resolveClaudeInstallDir() {
|
|
3323
3382
|
const realPath = resolveClaudeBinaryPath();
|
|
3324
|
-
return
|
|
3383
|
+
return resolve19(realPath, "..");
|
|
3325
3384
|
}
|
|
3326
3385
|
function resolveNodeInstallDir() {
|
|
3327
3386
|
const preferredNode = resolvePreferredNodeBinary();
|
|
3328
3387
|
if (!preferredNode)
|
|
3329
3388
|
return null;
|
|
3330
3389
|
const explicitNode = process.env.RIG_NODE_BIN?.trim();
|
|
3331
|
-
if (explicitNode &&
|
|
3332
|
-
return preferredNode.endsWith("/bin/node") ?
|
|
3390
|
+
if (explicitNode && resolve19(explicitNode) === resolve19(preferredNode)) {
|
|
3391
|
+
return preferredNode.endsWith("/bin/node") ? resolve19(preferredNode, "../..") : resolve19(preferredNode, "..");
|
|
3333
3392
|
}
|
|
3334
3393
|
try {
|
|
3335
3394
|
const realPath = realpathSync(preferredNode);
|
|
3336
3395
|
if (realPath.endsWith("/bin/node")) {
|
|
3337
|
-
return
|
|
3396
|
+
return resolve19(realPath, "../..");
|
|
3338
3397
|
}
|
|
3339
|
-
return
|
|
3398
|
+
return resolve19(realPath, "..");
|
|
3340
3399
|
} catch {
|
|
3341
|
-
return
|
|
3400
|
+
return resolve19(preferredNode, "..");
|
|
3342
3401
|
}
|
|
3343
3402
|
}
|
|
3344
3403
|
function resolvePreferredNodeBinary() {
|
|
3345
3404
|
const candidates = [];
|
|
3346
3405
|
const envNode = process.env.RIG_NODE_BIN?.trim();
|
|
3347
3406
|
if (envNode) {
|
|
3348
|
-
const explicit =
|
|
3349
|
-
if (
|
|
3407
|
+
const explicit = resolve19(envNode);
|
|
3408
|
+
if (existsSync18(explicit)) {
|
|
3350
3409
|
return explicit;
|
|
3351
3410
|
}
|
|
3352
3411
|
}
|
|
3353
3412
|
const nvmBin = process.env.NVM_BIN?.trim();
|
|
3354
3413
|
if (nvmBin) {
|
|
3355
|
-
candidates.push(
|
|
3414
|
+
candidates.push(resolve19(nvmBin, "node"));
|
|
3356
3415
|
}
|
|
3357
3416
|
const home = process.env.HOME?.trim();
|
|
3358
3417
|
if (home) {
|
|
3359
|
-
const nvmVersionsDir =
|
|
3360
|
-
if (
|
|
3418
|
+
const nvmVersionsDir = resolve19(home, ".nvm/versions/node");
|
|
3419
|
+
if (existsSync18(nvmVersionsDir)) {
|
|
3361
3420
|
try {
|
|
3362
3421
|
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/, "")));
|
|
3363
3422
|
for (const versionDir of versionDirs) {
|
|
3364
|
-
candidates.push(
|
|
3423
|
+
candidates.push(resolve19(nvmVersionsDir, versionDir, "bin/node"));
|
|
3365
3424
|
}
|
|
3366
3425
|
} catch {}
|
|
3367
3426
|
}
|
|
@@ -3370,8 +3429,8 @@ function resolvePreferredNodeBinary() {
|
|
|
3370
3429
|
if (whichNode) {
|
|
3371
3430
|
candidates.push(whichNode);
|
|
3372
3431
|
}
|
|
3373
|
-
const deduped = uniq(candidates.map((candidate) =>
|
|
3374
|
-
const existing = deduped.filter((candidate) =>
|
|
3432
|
+
const deduped = uniq(candidates.map((candidate) => resolve19(candidate)));
|
|
3433
|
+
const existing = deduped.filter((candidate) => existsSync18(candidate));
|
|
3375
3434
|
if (existing.length === 0) {
|
|
3376
3435
|
return null;
|
|
3377
3436
|
}
|
|
@@ -3385,7 +3444,7 @@ function resolvePreferredNodeBinary() {
|
|
|
3385
3444
|
return existing[0] ?? null;
|
|
3386
3445
|
}
|
|
3387
3446
|
function inferNodeMajor(nodeBinaryPath) {
|
|
3388
|
-
const normalized =
|
|
3447
|
+
const normalized = resolve19(nodeBinaryPath).replace(/\\/g, "/");
|
|
3389
3448
|
const match = normalized.match(/(?:^|\/)(?:node-)?v?(\d+)\.\d+\.\d+(?:\/|$)/);
|
|
3390
3449
|
if (!match) {
|
|
3391
3450
|
return null;
|
|
@@ -3397,8 +3456,8 @@ function normalizeExecutablePath(candidate) {
|
|
|
3397
3456
|
if (!candidate) {
|
|
3398
3457
|
return "";
|
|
3399
3458
|
}
|
|
3400
|
-
const normalized =
|
|
3401
|
-
if (!
|
|
3459
|
+
const normalized = resolve19(candidate);
|
|
3460
|
+
if (!existsSync18(normalized)) {
|
|
3402
3461
|
return "";
|
|
3403
3462
|
}
|
|
3404
3463
|
try {
|
|
@@ -3408,7 +3467,7 @@ function normalizeExecutablePath(candidate) {
|
|
|
3408
3467
|
}
|
|
3409
3468
|
}
|
|
3410
3469
|
function looksLikeRuntimeGateway(candidate) {
|
|
3411
|
-
const normalized =
|
|
3470
|
+
const normalized = resolve19(candidate).replace(/\\/g, "/");
|
|
3412
3471
|
return normalized.includes("/.rig/bin/") || normalized.endsWith("/rig-shell") || normalized.endsWith("/rig-agent");
|
|
3413
3472
|
}
|
|
3414
3473
|
|
|
@@ -3429,7 +3488,7 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
3429
3488
|
try {
|
|
3430
3489
|
return resolveClaudeInstallDir();
|
|
3431
3490
|
} catch {
|
|
3432
|
-
return
|
|
3491
|
+
return resolve20(claudeBinary, "..");
|
|
3433
3492
|
}
|
|
3434
3493
|
})() : "";
|
|
3435
3494
|
const nodeDir = resolveNodeInstallDir();
|
|
@@ -3439,8 +3498,8 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
3439
3498
|
`${bunDir}/bin`,
|
|
3440
3499
|
claudeDir,
|
|
3441
3500
|
nodeDir ? `${nodeDir}/bin` : "",
|
|
3442
|
-
realHome ?
|
|
3443
|
-
realHome ?
|
|
3501
|
+
realHome ? resolve20(realHome, ".local/bin") : "",
|
|
3502
|
+
realHome ? resolve20(realHome, ".cargo/bin") : "",
|
|
3444
3503
|
...inheritedPath,
|
|
3445
3504
|
"/usr/local/bin",
|
|
3446
3505
|
"/usr/local/sbin",
|
|
@@ -3471,9 +3530,9 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
3471
3530
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
3472
3531
|
function resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext) {
|
|
3473
3532
|
if (runtimeContext) {
|
|
3474
|
-
return
|
|
3533
|
+
return resolve21(runtimeContext.binDir, "validators", binaryName);
|
|
3475
3534
|
}
|
|
3476
|
-
return
|
|
3535
|
+
return resolve21(resolveHarnessPaths(projectRoot).binDir, "validators", binaryName);
|
|
3477
3536
|
}
|
|
3478
3537
|
async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
3479
3538
|
const match = checkId.match(/^([a-z][\w-]*):([a-z][\w-]*)$/);
|
|
@@ -3488,19 +3547,19 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
3488
3547
|
const binaryName = `${category}-${check}`;
|
|
3489
3548
|
const binaryPath = resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
3490
3549
|
const hostProjectRoot = runtimeContext?.hostProjectRoot?.trim() || projectRoot;
|
|
3491
|
-
const sourcePath =
|
|
3492
|
-
if (!
|
|
3550
|
+
const sourcePath = resolve21(hostProjectRoot, "packages/runtime/src/control-plane/validators", category, `${check}.ts`);
|
|
3551
|
+
if (!existsSync19(sourcePath)) {
|
|
3493
3552
|
return null;
|
|
3494
3553
|
}
|
|
3495
3554
|
const sourceMtime = statSync4(sourcePath).mtimeMs;
|
|
3496
|
-
const binaryExists =
|
|
3555
|
+
const binaryExists = existsSync19(binaryPath);
|
|
3497
3556
|
const binaryMtime = binaryExists ? statSync4(binaryPath).mtimeMs : 0;
|
|
3498
3557
|
if (!binaryExists || sourceMtime > binaryMtime) {
|
|
3499
3558
|
if (binaryExists) {
|
|
3500
3559
|
rmSync5(binaryPath, { force: true });
|
|
3501
3560
|
rmSync5(`${binaryPath}.build-manifest.json`, { force: true });
|
|
3502
3561
|
}
|
|
3503
|
-
|
|
3562
|
+
mkdirSync8(dirname11(binaryPath), { recursive: true });
|
|
3504
3563
|
await buildRuntimeBinary({
|
|
3505
3564
|
sourcePath: `packages/runtime/src/control-plane/validators/${category}/${check}.ts`,
|
|
3506
3565
|
outputPath: binaryPath,
|
|
@@ -3509,7 +3568,7 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
3509
3568
|
env: runtimeProvisioningEnv()
|
|
3510
3569
|
});
|
|
3511
3570
|
}
|
|
3512
|
-
return
|
|
3571
|
+
return existsSync19(binaryPath) ? binaryPath : null;
|
|
3513
3572
|
}
|
|
3514
3573
|
|
|
3515
3574
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
@@ -3546,20 +3605,20 @@ async function readTaskSourceValidation(projectRoot, taskId) {
|
|
|
3546
3605
|
function resolveValidationPaths(projectRoot, taskId, runtimeContext) {
|
|
3547
3606
|
if (runtimeContext) {
|
|
3548
3607
|
return {
|
|
3549
|
-
taskLogDir:
|
|
3550
|
-
artifactDir:
|
|
3608
|
+
taskLogDir: resolve22(runtimeContext.logsDir, taskId),
|
|
3609
|
+
artifactDir: resolve22(runtimeContext.workspaceDir, "artifacts", taskId)
|
|
3551
3610
|
};
|
|
3552
3611
|
}
|
|
3553
3612
|
const paths = resolveHarnessPaths(projectRoot);
|
|
3554
3613
|
return {
|
|
3555
|
-
taskLogDir:
|
|
3556
|
-
artifactDir:
|
|
3614
|
+
taskLogDir: resolve22(paths.logsDir, taskId),
|
|
3615
|
+
artifactDir: resolve22(paths.artifactsDir, taskId)
|
|
3557
3616
|
};
|
|
3558
3617
|
}
|
|
3559
3618
|
async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext) {
|
|
3560
3619
|
const binaryName = checkId.replace(":", "-");
|
|
3561
3620
|
const binaryPath = await ensureValidatorBinary(projectRoot, checkId, runtimeContext) ?? resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
3562
|
-
if (!
|
|
3621
|
+
if (!existsSync20(binaryPath)) {
|
|
3563
3622
|
return {
|
|
3564
3623
|
result: {
|
|
3565
3624
|
id: checkId,
|
|
@@ -3570,7 +3629,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
3570
3629
|
};
|
|
3571
3630
|
}
|
|
3572
3631
|
const validatorCwd = runtimeContext?.workspaceDir || resolveMonorepoRoot(projectRoot);
|
|
3573
|
-
const runtimeShellPath = runtimeContext ?
|
|
3632
|
+
const runtimeShellPath = runtimeContext ? resolve22(runtimeContext.binDir, "rig-shell") : "";
|
|
3574
3633
|
const monorepoMainRoot = runtimeContext?.monorepoMainRoot || process.env.MONOREPO_MAIN_ROOT?.trim() || resolveMonorepoRoot(projectRoot);
|
|
3575
3634
|
const validatorEnv = {
|
|
3576
3635
|
PROJECT_RIG_ROOT: runtimeContext?.hostProjectRoot || projectRoot,
|
|
@@ -3585,7 +3644,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
3585
3644
|
validatorEnv.RIG_LOGS_DIR = runtimeContext.logsDir;
|
|
3586
3645
|
validatorEnv.RIG_RUNTIME_BIN_DIR = runtimeContext.binDir;
|
|
3587
3646
|
}
|
|
3588
|
-
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath &&
|
|
3647
|
+
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath && existsSync20(runtimeShellPath) ? [runtimeShellPath, "run-binary", binaryPath] : [binaryPath], validatorCwd, validatorEnv);
|
|
3589
3648
|
try {
|
|
3590
3649
|
const result = JSON.parse(stdout.trim());
|
|
3591
3650
|
return { result, exitCode };
|
|
@@ -3625,8 +3684,8 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
3625
3684
|
const configuredValidation = stringArray(taskConfig[taskId]?.validation);
|
|
3626
3685
|
const commands = resolvedContext?.validation?.length ? resolvedContext.validation : configuredValidation.length > 0 ? configuredValidation : sourceValidation.validation;
|
|
3627
3686
|
const { taskLogDir, artifactDir } = resolveValidationPaths(projectRoot, taskId, resolvedContext);
|
|
3628
|
-
|
|
3629
|
-
|
|
3687
|
+
mkdirSync9(taskLogDir, { recursive: true });
|
|
3688
|
+
mkdirSync9(artifactDir, { recursive: true });
|
|
3630
3689
|
if (commands.length === 0) {
|
|
3631
3690
|
const skipped = {
|
|
3632
3691
|
status: "skipped",
|
|
@@ -3635,7 +3694,7 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
3635
3694
|
failed: 0,
|
|
3636
3695
|
categories: []
|
|
3637
3696
|
};
|
|
3638
|
-
|
|
3697
|
+
writeFileSync9(resolve22(artifactDir, "validation-summary.json"), `${JSON.stringify(skipped, null, 2)}
|
|
3639
3698
|
`, "utf-8");
|
|
3640
3699
|
return skipped;
|
|
3641
3700
|
}
|
|
@@ -3670,18 +3729,18 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
3670
3729
|
exit_code: 2,
|
|
3671
3730
|
duration_seconds: 0
|
|
3672
3731
|
});
|
|
3673
|
-
const logFile2 =
|
|
3674
|
-
|
|
3675
|
-
|
|
3732
|
+
const logFile2 = resolve22(taskLogDir, `invalid-entry-validation.log`);
|
|
3733
|
+
mkdirSync9(taskLogDir, { recursive: true });
|
|
3734
|
+
writeFileSync9(logFile2, `=== ${nowIso()} :: ${cmd} ===
|
|
3676
3735
|
Invalid validation entry: not a check-ID. All entries must use format "category:check-name".
|
|
3677
3736
|
`, "utf-8");
|
|
3678
3737
|
continue;
|
|
3679
3738
|
}
|
|
3680
3739
|
const { result, exitCode } = await dispatchValidator(cmd, effectiveRegistry, validatorCtx, (id) => runValidatorBinary(projectRoot, taskId, id, resolvedContext));
|
|
3681
3740
|
const durationSeconds = Math.max(0, Math.round((Date.now() - startedAt) / 1000));
|
|
3682
|
-
const logFile =
|
|
3683
|
-
|
|
3684
|
-
|
|
3741
|
+
const logFile = resolve22(taskLogDir, `${cmd.replace(":", "-")}-validation.log`);
|
|
3742
|
+
mkdirSync9(taskLogDir, { recursive: true });
|
|
3743
|
+
writeFileSync9(logFile, `=== ${nowIso()} :: ${cmd} ===
|
|
3685
3744
|
${JSON.stringify(result, null, 2)}
|
|
3686
3745
|
`, "utf-8");
|
|
3687
3746
|
if (result.passed) {
|
|
@@ -3703,15 +3762,15 @@ ${JSON.stringify(result, null, 2)}
|
|
|
3703
3762
|
failed,
|
|
3704
3763
|
categories
|
|
3705
3764
|
};
|
|
3706
|
-
|
|
3707
|
-
|
|
3765
|
+
mkdirSync9(artifactDir, { recursive: true });
|
|
3766
|
+
writeFileSync9(resolve22(artifactDir, "validation-summary.json"), `${JSON.stringify(summary, null, 2)}
|
|
3708
3767
|
`, "utf-8");
|
|
3709
3768
|
return summary;
|
|
3710
3769
|
}
|
|
3711
3770
|
|
|
3712
3771
|
// packages/runtime/src/control-plane/native/verifier.ts
|
|
3713
|
-
import { existsSync as
|
|
3714
|
-
import { resolve as
|
|
3772
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
|
|
3773
|
+
import { resolve as resolve24 } from "path";
|
|
3715
3774
|
|
|
3716
3775
|
// packages/runtime/src/control-plane/runtime/baked-secrets.ts
|
|
3717
3776
|
var BAKED_RUNTIME_SECRETS = {
|
|
@@ -3757,8 +3816,8 @@ function resolveRuntimeSecrets(env, baked = BAKED_RUNTIME_SECRETS) {
|
|
|
3757
3816
|
}
|
|
3758
3817
|
|
|
3759
3818
|
// packages/runtime/src/control-plane/native/git-ops.ts
|
|
3760
|
-
import { existsSync as
|
|
3761
|
-
import { dirname as
|
|
3819
|
+
import { existsSync as existsSync21, lstatSync, mkdirSync as mkdirSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync10 } from "fs";
|
|
3820
|
+
import { dirname as dirname12, isAbsolute as isAbsolute2, resolve as resolve23 } from "path";
|
|
3762
3821
|
|
|
3763
3822
|
// packages/runtime/src/control-plane/native/pr-review-gate.ts
|
|
3764
3823
|
function parseJsonObject(value) {
|
|
@@ -5015,12 +5074,12 @@ var TASK_ARTIFACT_STAGE_FALLBACK = new Set([
|
|
|
5015
5074
|
"validation-summary.json"
|
|
5016
5075
|
]);
|
|
5017
5076
|
function readPrMetadata(projectRoot, taskId) {
|
|
5018
|
-
const path =
|
|
5019
|
-
if (!
|
|
5077
|
+
const path = resolve23(artifactDirForId(projectRoot, taskId), "pr-state.json");
|
|
5078
|
+
if (!existsSync21(path)) {
|
|
5020
5079
|
return [];
|
|
5021
5080
|
}
|
|
5022
5081
|
try {
|
|
5023
|
-
const parsed = JSON.parse(
|
|
5082
|
+
const parsed = JSON.parse(readFileSync11(path, "utf-8"));
|
|
5024
5083
|
if (!parsed || typeof parsed !== "object") {
|
|
5025
5084
|
return [];
|
|
5026
5085
|
}
|
|
@@ -5046,11 +5105,11 @@ async function verifyTask(options) {
|
|
|
5046
5105
|
const taskId = options.taskId;
|
|
5047
5106
|
const normalizedTaskId = lookupTask(options.projectRoot, taskId);
|
|
5048
5107
|
const artifactDir = artifactDirForId(options.projectRoot, taskId);
|
|
5049
|
-
|
|
5050
|
-
const validationSummaryPath =
|
|
5051
|
-
const reviewFeedbackPath =
|
|
5052
|
-
const reviewStatePath =
|
|
5053
|
-
const greptileRawPath =
|
|
5108
|
+
mkdirSync11(artifactDir, { recursive: true });
|
|
5109
|
+
const validationSummaryPath = resolve24(artifactDir, "validation-summary.json");
|
|
5110
|
+
const reviewFeedbackPath = resolve24(artifactDir, "review-feedback.md");
|
|
5111
|
+
const reviewStatePath = resolve24(artifactDir, "review-state.json");
|
|
5112
|
+
const greptileRawPath = resolve24(artifactDir, "review-greptile-raw.json");
|
|
5054
5113
|
const prStates = readPrMetadata(options.projectRoot, taskId);
|
|
5055
5114
|
const prState = prStates[0] || null;
|
|
5056
5115
|
const localReasons = [];
|
|
@@ -5062,7 +5121,7 @@ async function verifyTask(options) {
|
|
|
5062
5121
|
if (!normalizedTaskId && !await hasConfiguredSourceTask(options.projectRoot, taskId)) {
|
|
5063
5122
|
localReasons.push(`[Task Config] Unknown task id '${taskId}' in task-config or configured task source.`);
|
|
5064
5123
|
}
|
|
5065
|
-
if (!
|
|
5124
|
+
if (!existsSync22(validationSummaryPath)) {
|
|
5066
5125
|
localReasons.push(`[Artifact Quality] validation-summary.json not found at ${validationSummaryPath}.`);
|
|
5067
5126
|
} else {
|
|
5068
5127
|
const summary = await parseValidationSummary(validationSummaryPath);
|
|
@@ -5071,13 +5130,13 @@ async function verifyTask(options) {
|
|
|
5071
5130
|
}
|
|
5072
5131
|
}
|
|
5073
5132
|
for (const file of ["task-result.json", "decision-log.md", "next-actions.md", "changed-files.txt"]) {
|
|
5074
|
-
const requiredPath =
|
|
5075
|
-
if (!
|
|
5133
|
+
const requiredPath = resolve24(artifactDir, file);
|
|
5134
|
+
if (!existsSync22(requiredPath)) {
|
|
5076
5135
|
localReasons.push(`[Artifact Quality] Missing required artifact file: ${requiredPath}`);
|
|
5077
5136
|
}
|
|
5078
5137
|
}
|
|
5079
|
-
const taskResultPath =
|
|
5080
|
-
if (
|
|
5138
|
+
const taskResultPath = resolve24(artifactDir, "task-result.json");
|
|
5139
|
+
if (existsSync22(taskResultPath)) {
|
|
5081
5140
|
const taskResult = await readJsonFile2(taskResultPath);
|
|
5082
5141
|
const artifactStatus = typeof taskResult?.status === "string" ? taskResult.status.trim().toLowerCase() : "";
|
|
5083
5142
|
if (artifactStatus === "partial") {
|
|
@@ -5090,8 +5149,8 @@ async function verifyTask(options) {
|
|
|
5090
5149
|
localReasons.push("[Artifact Quality] task-result.json next actions indicate remaining implementation scope.");
|
|
5091
5150
|
}
|
|
5092
5151
|
}
|
|
5093
|
-
const nextActionsPath =
|
|
5094
|
-
if (
|
|
5152
|
+
const nextActionsPath = resolve24(artifactDir, "next-actions.md");
|
|
5153
|
+
if (existsSync22(nextActionsPath)) {
|
|
5095
5154
|
const nextActionsContent = await Bun.file(nextActionsPath).text();
|
|
5096
5155
|
if (nextActionsContent.includes("TODO: Replace this scaffold") || nextActionsContent.includes("bd-<downstream-task-id>")) {
|
|
5097
5156
|
localReasons.push("[Artifact Quality] next-actions.md still contains scaffold placeholder text. Replace with real recommendations.");
|
|
@@ -5122,7 +5181,7 @@ async function verifyTask(options) {
|
|
|
5122
5181
|
aiReasons.push(`[AI Review] Required mode needs a completed Greptile approval; current verdict is ${ai.verdict}.`);
|
|
5123
5182
|
}
|
|
5124
5183
|
if (persistArtifacts && ai.rawResponse) {
|
|
5125
|
-
|
|
5184
|
+
writeFileSync11(greptileRawPath, `${ai.rawResponse}
|
|
5126
5185
|
`, "utf-8");
|
|
5127
5186
|
}
|
|
5128
5187
|
} else if (!options.skipAiReview && reviewMode === "off") {
|
|
@@ -5365,7 +5424,7 @@ function evaluateSourceCloseoutChecks(prState, prLabel) {
|
|
|
5365
5424
|
if (!Array.isArray(checks) || checks.length === 0) {
|
|
5366
5425
|
return [`[Source Issue] PR ${prLabel} must have green check evidence before completion.`];
|
|
5367
5426
|
}
|
|
5368
|
-
const ciGate = evaluatePullRequestCiChecks(checks, "PR", 0);
|
|
5427
|
+
const ciGate = evaluatePullRequestCiChecks(checks, "PR", 0, { mergeStateStatus: prState.mergeStateStatus });
|
|
5369
5428
|
if (ciGate.verdict === "APPROVE") {
|
|
5370
5429
|
return [];
|
|
5371
5430
|
}
|
|
@@ -5461,7 +5520,7 @@ function isAcceptedValidationSummary(summary) {
|
|
|
5461
5520
|
return summary.status === "skipped" && summary.total === 0 && summary.failed === 0;
|
|
5462
5521
|
}
|
|
5463
5522
|
async function loadReviewMode(reviewProfilePath, fallback) {
|
|
5464
|
-
const parsed =
|
|
5523
|
+
const parsed = existsSync22(reviewProfilePath) ? await readJsonFile2(reviewProfilePath) : null;
|
|
5465
5524
|
const mode = parsed?.mode;
|
|
5466
5525
|
if (mode === "off" || mode === "advisory" || mode === "required") {
|
|
5467
5526
|
return mode;
|
|
@@ -5472,7 +5531,7 @@ async function loadReviewMode(reviewProfilePath, fallback) {
|
|
|
5472
5531
|
return "advisory";
|
|
5473
5532
|
}
|
|
5474
5533
|
async function loadReviewProvider(reviewProfilePath, fallback) {
|
|
5475
|
-
const parsed =
|
|
5534
|
+
const parsed = existsSync22(reviewProfilePath) ? await readJsonFile2(reviewProfilePath) : null;
|
|
5476
5535
|
const provider = parsed?.provider;
|
|
5477
5536
|
if (typeof provider === "string" && provider.trim().length > 0) {
|
|
5478
5537
|
return provider;
|
|
@@ -5631,7 +5690,7 @@ function writeFeedbackFile(options) {
|
|
|
5631
5690
|
if (options.aiRawFeedback) {
|
|
5632
5691
|
lines.push("## Raw Reviewer Feedback", "", "```text", options.aiRawFeedback, "```", "");
|
|
5633
5692
|
}
|
|
5634
|
-
|
|
5693
|
+
writeFileSync11(options.output, `${lines.join(`
|
|
5635
5694
|
`)}
|
|
5636
5695
|
`, "utf-8");
|
|
5637
5696
|
}
|
|
@@ -5648,7 +5707,7 @@ function writeReviewStateFile(options) {
|
|
|
5648
5707
|
ai_warnings: options.aiWarnings,
|
|
5649
5708
|
updated_at: nowIso()
|
|
5650
5709
|
};
|
|
5651
|
-
|
|
5710
|
+
writeFileSync11(options.output, `${JSON.stringify(payload, null, 2)}
|
|
5652
5711
|
`, "utf-8");
|
|
5653
5712
|
}
|
|
5654
5713
|
async function runGreptileReviewForPr(options) {
|
|
@@ -5729,7 +5788,7 @@ async function runGreptileReviewForPr(options) {
|
|
|
5729
5788
|
}
|
|
5730
5789
|
await Bun.sleep(options.pollIntervalMs);
|
|
5731
5790
|
}
|
|
5732
|
-
const ciGate = evaluatePullRequestCiChecks(githubCheckRollup, repoName, prNumber);
|
|
5791
|
+
const ciGate = evaluatePullRequestCiChecks(githubCheckRollup, repoName, prNumber, { mergeStateStatus: options.prState.mergeStateStatus });
|
|
5733
5792
|
if (ciGate.verdict !== "APPROVE") {
|
|
5734
5793
|
return {
|
|
5735
5794
|
verdict: ciGate.verdict,
|
|
@@ -5987,7 +6046,7 @@ async function runGithubGreptileFallbackReviewForPr(options) {
|
|
|
5987
6046
|
}
|
|
5988
6047
|
await Bun.sleep(options.pollIntervalMs);
|
|
5989
6048
|
}
|
|
5990
|
-
const ciGate = evaluatePullRequestCiChecks(checkRollup, repoName, prNumber);
|
|
6049
|
+
const ciGate = evaluatePullRequestCiChecks(checkRollup, repoName, prNumber, { mergeStateStatus: options.prState.mergeStateStatus });
|
|
5991
6050
|
if (ciGate.verdict !== "APPROVE") {
|
|
5992
6051
|
return {
|
|
5993
6052
|
verdict: ciGate.verdict,
|
|
@@ -6342,7 +6401,7 @@ function loadGithubPullRequestCheckRollup(projectRoot, repoName, prNumber) {
|
|
|
6342
6401
|
]);
|
|
6343
6402
|
return response.statusCheckRollup || [];
|
|
6344
6403
|
}
|
|
6345
|
-
function evaluatePullRequestCiChecks(checks, repoName, prNumber) {
|
|
6404
|
+
function evaluatePullRequestCiChecks(checks, repoName, prNumber, options = {}) {
|
|
6346
6405
|
const nonGreptileChecks = checks.filter((check) => {
|
|
6347
6406
|
const label = (check.name || check.context || "").toLowerCase();
|
|
6348
6407
|
return label.length > 0 && !label.includes("greptile");
|
|
@@ -6354,7 +6413,8 @@ function evaluatePullRequestCiChecks(checks, repoName, prNumber) {
|
|
|
6354
6413
|
const state = (check.state || check.status || "").toUpperCase();
|
|
6355
6414
|
return state === "PENDING" || state === "EXPECTED" || state === "QUEUED" || state === "IN_PROGRESS";
|
|
6356
6415
|
});
|
|
6357
|
-
|
|
6416
|
+
const mergeClean = (options.mergeStateStatus || "").toUpperCase() === "CLEAN";
|
|
6417
|
+
if (pending.length > 0 && !mergeClean) {
|
|
6358
6418
|
return {
|
|
6359
6419
|
verdict: "SKIP",
|
|
6360
6420
|
reasons: pending.map((check) => `[CI] ${repoName}#${prNumber} check is still pending: ${check.name || check.context || "unknown"}.`)
|
|
@@ -6435,7 +6495,7 @@ function filterActionableGithubGreptileThreads(threads) {
|
|
|
6435
6495
|
}
|
|
6436
6496
|
function resolvePrRepoRoot(projectRoot, prState) {
|
|
6437
6497
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
6438
|
-
if (prState.target === "monorepo" && runtimeWorkspace &&
|
|
6498
|
+
if (prState.target === "monorepo" && runtimeWorkspace && existsSync22(resolve24(runtimeWorkspace, ".git"))) {
|
|
6439
6499
|
return runtimeWorkspace;
|
|
6440
6500
|
}
|
|
6441
6501
|
const paths = resolveHarnessPaths(projectRoot);
|
|
@@ -6815,16 +6875,16 @@ async function taskDeps(projectRoot, taskId) {
|
|
|
6815
6875
|
for (const dep of deps) {
|
|
6816
6876
|
const artifactDir = artifactDirForId(projectRoot, dep);
|
|
6817
6877
|
console.log(`=== ${dep} ===`);
|
|
6818
|
-
if (!
|
|
6878
|
+
if (!existsSync23(artifactDir)) {
|
|
6819
6879
|
console.log(` (no artifacts yet)
|
|
6820
6880
|
`);
|
|
6821
6881
|
continue;
|
|
6822
6882
|
}
|
|
6823
|
-
printArtifactSection(
|
|
6824
|
-
printArtifactSection(
|
|
6825
|
-
const changedFiles =
|
|
6826
|
-
if (
|
|
6827
|
-
const lines =
|
|
6883
|
+
printArtifactSection(resolve25(artifactDir, "decision-log.md"), "--- Decisions ---");
|
|
6884
|
+
printArtifactSection(resolve25(artifactDir, "next-actions.md"), "--- Next Actions (for you) ---");
|
|
6885
|
+
const changedFiles = resolve25(artifactDir, "changed-files.txt");
|
|
6886
|
+
if (existsSync23(changedFiles)) {
|
|
6887
|
+
const lines = readFileSync12(changedFiles, "utf-8").split(/\r?\n/).filter(Boolean);
|
|
6828
6888
|
console.log(`--- Changed Files (${lines.length}) ---`);
|
|
6829
6889
|
for (const line of lines) {
|
|
6830
6890
|
console.log(line);
|
|
@@ -6869,12 +6929,12 @@ function taskRecord(projectRoot, type, text, taskId) {
|
|
|
6869
6929
|
throw new Error("No active task.");
|
|
6870
6930
|
}
|
|
6871
6931
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6872
|
-
|
|
6932
|
+
mkdirSync12(paths.stateDir, { recursive: true });
|
|
6873
6933
|
if (type === "decision") {
|
|
6874
|
-
const artifactDir =
|
|
6875
|
-
|
|
6934
|
+
const artifactDir = resolve25(paths.artifactsDir, activeTask);
|
|
6935
|
+
mkdirSync12(artifactDir, { recursive: true });
|
|
6876
6936
|
const timestamp = nowIso();
|
|
6877
|
-
appendFileSync(
|
|
6937
|
+
appendFileSync(resolve25(artifactDir, "decision-log.md"), `
|
|
6878
6938
|
### ${timestamp}
|
|
6879
6939
|
|
|
6880
6940
|
${text}
|
|
@@ -6884,14 +6944,14 @@ ${text}
|
|
|
6884
6944
|
return;
|
|
6885
6945
|
}
|
|
6886
6946
|
const failedPath = paths.failedApproachesPath;
|
|
6887
|
-
if (!
|
|
6888
|
-
|
|
6947
|
+
if (!existsSync23(failedPath)) {
|
|
6948
|
+
writeFileSync12(failedPath, `# Failed Approaches Log
|
|
6889
6949
|
|
|
6890
6950
|
This file records approaches that did not work.
|
|
6891
6951
|
|
|
6892
6952
|
`, "utf-8");
|
|
6893
6953
|
}
|
|
6894
|
-
const content =
|
|
6954
|
+
const content = readFileSync12(failedPath, "utf-8");
|
|
6895
6955
|
const attempts = (content.match(new RegExp(`^## ${escapeRegExp(activeTask)}\\b`, "gm")) || []).length + 1;
|
|
6896
6956
|
appendFileSync(failedPath, `
|
|
6897
6957
|
## ${activeTask} - Attempt ${attempts} (${nowIso()})
|
|
@@ -6908,40 +6968,40 @@ function taskArtifacts(projectRoot, taskId) {
|
|
|
6908
6968
|
throw new Error("No active task.");
|
|
6909
6969
|
}
|
|
6910
6970
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6911
|
-
const artifactDir =
|
|
6912
|
-
|
|
6971
|
+
const artifactDir = resolve25(paths.artifactsDir, activeTask);
|
|
6972
|
+
mkdirSync12(artifactDir, { recursive: true });
|
|
6913
6973
|
const changed = changedFilesForTask(projectRoot, activeTask, true);
|
|
6914
|
-
|
|
6974
|
+
writeFileSync12(resolve25(artifactDir, "changed-files.txt"), `${changed.join(`
|
|
6915
6975
|
`)}
|
|
6916
6976
|
`, "utf-8");
|
|
6917
6977
|
console.log(`changed-files.txt: ${changed.length} files`);
|
|
6918
|
-
const taskResultPath =
|
|
6919
|
-
if (!
|
|
6978
|
+
const taskResultPath = resolve25(artifactDir, "task-result.json");
|
|
6979
|
+
if (!existsSync23(taskResultPath)) {
|
|
6920
6980
|
const template = {
|
|
6921
6981
|
task_id: activeTask,
|
|
6922
6982
|
status: "completed",
|
|
6923
6983
|
summary: "TODO: Write a one-line summary of what you did",
|
|
6924
6984
|
completed_at: nowIso()
|
|
6925
6985
|
};
|
|
6926
|
-
|
|
6986
|
+
writeFileSync12(taskResultPath, `${JSON.stringify(template, null, 2)}
|
|
6927
6987
|
`, "utf-8");
|
|
6928
6988
|
console.log("task-result.json: created (update the summary!)");
|
|
6929
6989
|
} else {
|
|
6930
6990
|
console.log("task-result.json: already exists");
|
|
6931
6991
|
}
|
|
6932
|
-
const decisionLogPath =
|
|
6933
|
-
if (!
|
|
6992
|
+
const decisionLogPath = resolve25(artifactDir, "decision-log.md");
|
|
6993
|
+
if (!existsSync23(decisionLogPath)) {
|
|
6934
6994
|
const content = `# Decision Log: ${activeTask}
|
|
6935
6995
|
|
|
6936
6996
|
Record key decisions here using: rig-agent record decision "..."
|
|
6937
6997
|
`;
|
|
6938
|
-
|
|
6998
|
+
writeFileSync12(decisionLogPath, content, "utf-8");
|
|
6939
6999
|
console.log("decision-log.md: created (record your decisions!)");
|
|
6940
7000
|
} else {
|
|
6941
7001
|
console.log("decision-log.md: already exists");
|
|
6942
7002
|
}
|
|
6943
|
-
const nextActionsPath =
|
|
6944
|
-
if (!
|
|
7003
|
+
const nextActionsPath = resolve25(artifactDir, "next-actions.md");
|
|
7004
|
+
if (!existsSync23(nextActionsPath)) {
|
|
6945
7005
|
const content = [
|
|
6946
7006
|
`# Next Actions: ${activeTask}`,
|
|
6947
7007
|
"",
|
|
@@ -6958,13 +7018,13 @@ Record key decisions here using: rig-agent record decision "..."
|
|
|
6958
7018
|
""
|
|
6959
7019
|
].join(`
|
|
6960
7020
|
`);
|
|
6961
|
-
|
|
7021
|
+
writeFileSync12(nextActionsPath, content, "utf-8");
|
|
6962
7022
|
console.log("next-actions.md: created (add recommendations for downstream tasks!)");
|
|
6963
7023
|
} else {
|
|
6964
7024
|
console.log("next-actions.md: already exists");
|
|
6965
7025
|
}
|
|
6966
|
-
const validationSummaryPath =
|
|
6967
|
-
if (
|
|
7026
|
+
const validationSummaryPath = resolve25(artifactDir, "validation-summary.json");
|
|
7027
|
+
if (existsSync23(validationSummaryPath)) {
|
|
6968
7028
|
console.log("validation-summary.json: already exists");
|
|
6969
7029
|
} else {
|
|
6970
7030
|
console.log("validation-summary.json: not yet created (run: rig-agent validate)");
|
|
@@ -6978,8 +7038,8 @@ function taskArtifactDir(projectRoot, taskId) {
|
|
|
6978
7038
|
throw new Error("No active task.");
|
|
6979
7039
|
}
|
|
6980
7040
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6981
|
-
const artifactDir =
|
|
6982
|
-
|
|
7041
|
+
const artifactDir = resolve25(paths.artifactsDir, activeTask);
|
|
7042
|
+
mkdirSync12(artifactDir, { recursive: true });
|
|
6983
7043
|
return artifactDir;
|
|
6984
7044
|
}
|
|
6985
7045
|
function taskArtifactWrite(projectRoot, filename, content, taskId) {
|
|
@@ -6988,10 +7048,10 @@ function taskArtifactWrite(projectRoot, filename, content, taskId) {
|
|
|
6988
7048
|
throw new Error("No active task.");
|
|
6989
7049
|
}
|
|
6990
7050
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6991
|
-
const artifactDir =
|
|
6992
|
-
|
|
6993
|
-
const targetPath =
|
|
6994
|
-
|
|
7051
|
+
const artifactDir = resolve25(paths.artifactsDir, activeTask);
|
|
7052
|
+
mkdirSync12(artifactDir, { recursive: true });
|
|
7053
|
+
const targetPath = resolve25(artifactDir, filename);
|
|
7054
|
+
writeFileSync12(targetPath, content, "utf-8");
|
|
6995
7055
|
console.log(`Wrote: ${targetPath}`);
|
|
6996
7056
|
}
|
|
6997
7057
|
function taskArtifactRead(projectRoot, filename, options) {
|
|
@@ -7000,11 +7060,11 @@ function taskArtifactRead(projectRoot, filename, options) {
|
|
|
7000
7060
|
throw new Error("No active task.");
|
|
7001
7061
|
}
|
|
7002
7062
|
const maxBytes = options?.maxBytes ?? 64 * 1024;
|
|
7003
|
-
const targetPath =
|
|
7004
|
-
if (!
|
|
7063
|
+
const targetPath = resolve25(taskArtifactDir(projectRoot, activeTask), filename);
|
|
7064
|
+
if (!existsSync23(targetPath)) {
|
|
7005
7065
|
throw new Error(`Artifact not found: ${targetPath}`);
|
|
7006
7066
|
}
|
|
7007
|
-
const buffer =
|
|
7067
|
+
const buffer = readFileSync12(targetPath);
|
|
7008
7068
|
const preview = buffer.subarray(0, maxBytes);
|
|
7009
7069
|
return {
|
|
7010
7070
|
path: targetPath,
|
|
@@ -7154,7 +7214,7 @@ function collectTaskChangedFiles(projectRoot, taskId, includeCommitted) {
|
|
|
7154
7214
|
[projectRoot, ""],
|
|
7155
7215
|
[monorepoRepoRoot, ""]
|
|
7156
7216
|
]) {
|
|
7157
|
-
if (!
|
|
7217
|
+
if (!existsSync23(resolve25(repo, ".git"))) {
|
|
7158
7218
|
continue;
|
|
7159
7219
|
}
|
|
7160
7220
|
if (includeCommitted && repo === monorepoRepoRoot) {
|
|
@@ -7179,12 +7239,22 @@ function filterTaskChangedFiles(projectRoot, taskId, files, scoped) {
|
|
|
7179
7239
|
}
|
|
7180
7240
|
function resolveTaskMonorepoRoot(projectRoot) {
|
|
7181
7241
|
const runtimeWorkspace = loadRuntimeContextFromEnv()?.workspaceDir || process.env.RIG_TASK_WORKSPACE?.trim();
|
|
7182
|
-
if (runtimeWorkspace &&
|
|
7183
|
-
return
|
|
7242
|
+
if (runtimeWorkspace && existsSync23(resolve25(runtimeWorkspace, ".git"))) {
|
|
7243
|
+
return resolve25(runtimeWorkspace);
|
|
7184
7244
|
}
|
|
7185
7245
|
return resolveHarnessPaths(projectRoot).monorepoRoot;
|
|
7186
7246
|
}
|
|
7187
7247
|
function collectCommittedMonorepoFiles(projectRoot, repo) {
|
|
7248
|
+
const defaultRef = runCapture(["git", "-C", repo, "rev-parse", "--abbrev-ref", "origin/HEAD"], projectRoot);
|
|
7249
|
+
if (defaultRef.exitCode === 0 && defaultRef.stdout.trim()) {
|
|
7250
|
+
const mergeBase = runCapture(["git", "-C", repo, "merge-base", "HEAD", defaultRef.stdout.trim()], projectRoot);
|
|
7251
|
+
if (mergeBase.exitCode === 0 && mergeBase.stdout.trim()) {
|
|
7252
|
+
const result = runCapture(["git", "-C", repo, "diff", "--name-only", `${mergeBase.stdout.trim()}..HEAD`], projectRoot);
|
|
7253
|
+
if (result.exitCode === 0) {
|
|
7254
|
+
return result.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
7255
|
+
}
|
|
7256
|
+
}
|
|
7257
|
+
}
|
|
7188
7258
|
const initialHeadCommit = resolveRuntimeInitialHeadCommit(projectRoot, repo);
|
|
7189
7259
|
if (initialHeadCommit) {
|
|
7190
7260
|
const result = runCapture(["git", "-C", repo, "diff", "--name-only", `${initialHeadCommit}..HEAD`], projectRoot);
|
|
@@ -7208,7 +7278,7 @@ function resolveRuntimeInitialHeadCommit(projectRoot, repo) {
|
|
|
7208
7278
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
7209
7279
|
if (runtimeContext?.initialHeadCommits?.monorepo?.trim()) {
|
|
7210
7280
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
7211
|
-
if (
|
|
7281
|
+
if (resolve25(monorepoRoot) === resolve25(repo)) {
|
|
7212
7282
|
return runtimeContext.initialHeadCommits.monorepo.trim();
|
|
7213
7283
|
}
|
|
7214
7284
|
}
|
|
@@ -7218,7 +7288,7 @@ function resolveMonorepoBaseCommit(projectRoot, repo) {
|
|
|
7218
7288
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
7219
7289
|
if (runtimeContext?.monorepoBaseCommit?.trim()) {
|
|
7220
7290
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
7221
|
-
if (
|
|
7291
|
+
if (resolve25(monorepoRoot) === resolve25(repo)) {
|
|
7222
7292
|
return runtimeContext.monorepoBaseCommit.trim();
|
|
7223
7293
|
}
|
|
7224
7294
|
}
|
|
@@ -7263,7 +7333,7 @@ function resolveRuntimeDirtyBaseline(projectRoot, repo) {
|
|
|
7263
7333
|
return new Set;
|
|
7264
7334
|
}
|
|
7265
7335
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
7266
|
-
const selected =
|
|
7336
|
+
const selected = resolve25(repo) === resolve25(monorepoRoot) ? dirtyFiles.monorepo : resolve25(repo) === resolve25(projectRoot) ? dirtyFiles.project : undefined;
|
|
7267
7337
|
return new Set((selected || []).map((file) => normalizeChangedFilePath(file)).filter(Boolean));
|
|
7268
7338
|
}
|
|
7269
7339
|
function normalizeChangedFilePath(file) {
|
|
@@ -7363,12 +7433,12 @@ function printIndented(text) {
|
|
|
7363
7433
|
}
|
|
7364
7434
|
}
|
|
7365
7435
|
function readLocalBeadsTasks(projectRoot) {
|
|
7366
|
-
const issuesPath =
|
|
7367
|
-
if (!
|
|
7436
|
+
const issuesPath = resolve25(resolveMonorepoRoot2(projectRoot), ".beads/issues.jsonl");
|
|
7437
|
+
if (!existsSync23(issuesPath)) {
|
|
7368
7438
|
return [];
|
|
7369
7439
|
}
|
|
7370
7440
|
const tasks = [];
|
|
7371
|
-
for (const line of
|
|
7441
|
+
for (const line of readFileSync12(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
7372
7442
|
const trimmed = line.trim();
|
|
7373
7443
|
if (!trimmed) {
|
|
7374
7444
|
continue;
|
|
@@ -7539,11 +7609,11 @@ function taskDependencies(projectRoot, taskId, tracker) {
|
|
|
7539
7609
|
return [...ids].sort();
|
|
7540
7610
|
}
|
|
7541
7611
|
function printArtifactSection(path, header) {
|
|
7542
|
-
if (!
|
|
7612
|
+
if (!existsSync23(path)) {
|
|
7543
7613
|
return;
|
|
7544
7614
|
}
|
|
7545
7615
|
console.log(header);
|
|
7546
|
-
process.stdout.write(
|
|
7616
|
+
process.stdout.write(readFileSync12(path, "utf-8"));
|
|
7547
7617
|
console.log("");
|
|
7548
7618
|
}
|
|
7549
7619
|
function escapeRegExp(value) {
|