@h-rig/runtime 0.0.6-alpha.34 → 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 +430 -361
- package/dist/src/control-plane/agent-wrapper.js +523 -464
- package/dist/src/control-plane/harness-main.js +528 -458
- 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 +10 -0
- package/dist/src/control-plane/native/harness-cli.js +513 -443
- 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-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
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// packages/runtime/src/control-plane/harness-main.ts
|
|
5
|
-
import { resolve as
|
|
5
|
+
import { resolve as resolve34 } from "path";
|
|
6
6
|
|
|
7
7
|
// packages/runtime/src/control-plane/native/harness-cli.ts
|
|
8
|
-
import { existsSync as
|
|
9
|
-
import { resolve as
|
|
8
|
+
import { existsSync as existsSync31 } from "fs";
|
|
9
|
+
import { resolve as resolve31 } from "path";
|
|
10
10
|
|
|
11
11
|
// packages/runtime/src/control-plane/native/git-ops.ts
|
|
12
|
-
import { existsSync as
|
|
13
|
-
import { dirname as
|
|
12
|
+
import { existsSync as existsSync24, lstatSync, mkdirSync as mkdirSync12, readFileSync as readFileSync13, writeFileSync as writeFileSync12 } from "fs";
|
|
13
|
+
import { dirname as dirname12, isAbsolute as isAbsolute2, resolve as resolve26 } from "path";
|
|
14
14
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
15
15
|
|
|
16
16
|
// packages/runtime/src/control-plane/runtime/baked-secrets.ts
|
|
@@ -279,8 +279,8 @@ function isAgentRuntimeContextPath(path) {
|
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
// packages/runtime/src/control-plane/native/task-ops.ts
|
|
282
|
-
import { appendFileSync, existsSync as
|
|
283
|
-
import { resolve as
|
|
282
|
+
import { appendFileSync, existsSync as existsSync23, mkdirSync as mkdirSync11, readFileSync as readFileSync12, writeFileSync as writeFileSync11 } from "fs";
|
|
283
|
+
import { resolve as resolve25 } from "path";
|
|
284
284
|
|
|
285
285
|
// packages/runtime/src/build-time-config.ts
|
|
286
286
|
function normalizeBuildConfig(value) {
|
|
@@ -829,6 +829,8 @@ function buildBrowserGuidanceLines(browser) {
|
|
|
829
829
|
}
|
|
830
830
|
|
|
831
831
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
832
|
+
import { existsSync as existsSync8 } from "fs";
|
|
833
|
+
import { resolve as resolvePath } from "path";
|
|
832
834
|
import { createPluginHost } from "@rig/core";
|
|
833
835
|
import { loadConfig } from "@rig/core/load-config";
|
|
834
836
|
|
|
@@ -1176,6 +1178,55 @@ async function materializeSkills(projectRoot, entries) {
|
|
|
1176
1178
|
return written;
|
|
1177
1179
|
}
|
|
1178
1180
|
|
|
1181
|
+
// packages/runtime/src/control-plane/pi-settings-materializer.ts
|
|
1182
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
1183
|
+
import { dirname as dirname6, resolve as resolve9 } from "path";
|
|
1184
|
+
var SETTINGS_RELATIVE_PATH = ".pi/settings.json";
|
|
1185
|
+
var MANAGED_RECORD_RELATIVE_PATH = ".rig/state/pi-managed-packages.json";
|
|
1186
|
+
function readJson(path, fallback) {
|
|
1187
|
+
if (!existsSync7(path))
|
|
1188
|
+
return fallback;
|
|
1189
|
+
try {
|
|
1190
|
+
return JSON.parse(readFileSync6(path, "utf-8"));
|
|
1191
|
+
} catch {
|
|
1192
|
+
return fallback;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
function packageKey(entry) {
|
|
1196
|
+
if (typeof entry === "string")
|
|
1197
|
+
return entry;
|
|
1198
|
+
if (entry && typeof entry === "object" && typeof entry.source === "string") {
|
|
1199
|
+
return entry.source;
|
|
1200
|
+
}
|
|
1201
|
+
return JSON.stringify(entry);
|
|
1202
|
+
}
|
|
1203
|
+
function materializePiPackages(projectRoot, declaredPackages) {
|
|
1204
|
+
const settingsPath = resolve9(projectRoot, SETTINGS_RELATIVE_PATH);
|
|
1205
|
+
const managedRecordPath = resolve9(projectRoot, MANAGED_RECORD_RELATIVE_PATH);
|
|
1206
|
+
const settings = readJson(settingsPath, {});
|
|
1207
|
+
const previouslyManaged = new Set(readJson(managedRecordPath, []));
|
|
1208
|
+
const existing = Array.isArray(settings.packages) ? settings.packages : [];
|
|
1209
|
+
const operatorEntries = existing.filter((entry) => !previouslyManaged.has(packageKey(entry)));
|
|
1210
|
+
const operatorKeys = new Set(operatorEntries.map(packageKey));
|
|
1211
|
+
const managedToAdd = declaredPackages.filter((pkg) => !operatorKeys.has(pkg));
|
|
1212
|
+
const nextPackages = [...operatorEntries, ...managedToAdd];
|
|
1213
|
+
if (nextPackages.length > 0 || existsSync7(settingsPath)) {
|
|
1214
|
+
const nextSettings = { ...settings };
|
|
1215
|
+
if (nextPackages.length > 0) {
|
|
1216
|
+
nextSettings.packages = nextPackages;
|
|
1217
|
+
} else {
|
|
1218
|
+
delete nextSettings.packages;
|
|
1219
|
+
}
|
|
1220
|
+
mkdirSync5(dirname6(settingsPath), { recursive: true });
|
|
1221
|
+
writeFileSync5(settingsPath, `${JSON.stringify(nextSettings, null, 2)}
|
|
1222
|
+
`, "utf-8");
|
|
1223
|
+
}
|
|
1224
|
+
mkdirSync5(dirname6(managedRecordPath), { recursive: true });
|
|
1225
|
+
writeFileSync5(managedRecordPath, `${JSON.stringify(managedToAdd, null, 2)}
|
|
1226
|
+
`, "utf-8");
|
|
1227
|
+
return { settingsPath, packages: managedToAdd };
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1179
1230
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
1180
1231
|
async function buildPluginHostContext(projectRoot) {
|
|
1181
1232
|
let config;
|
|
@@ -1223,6 +1274,14 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
1223
1274
|
} catch (err) {
|
|
1224
1275
|
console.warn(`[plugin-host] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
1225
1276
|
}
|
|
1277
|
+
try {
|
|
1278
|
+
const piPackages = config.runtime?.pi?.packages ?? [];
|
|
1279
|
+
if (piPackages.length > 0 || existsSync8(resolvePath(projectRoot, ".rig/state/pi-managed-packages.json"))) {
|
|
1280
|
+
materializePiPackages(projectRoot, piPackages);
|
|
1281
|
+
}
|
|
1282
|
+
} catch (err) {
|
|
1283
|
+
console.warn(`[plugin-host] Pi package materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
1284
|
+
}
|
|
1226
1285
|
return {
|
|
1227
1286
|
config,
|
|
1228
1287
|
pluginHost,
|
|
@@ -1236,12 +1295,12 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
1236
1295
|
|
|
1237
1296
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
1238
1297
|
import { spawnSync } from "child_process";
|
|
1239
|
-
import { existsSync as
|
|
1240
|
-
import { basename as basename3, join as join2, resolve as
|
|
1298
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, readdirSync as readdirSync2, statSync, writeFileSync as writeFileSync6 } from "fs";
|
|
1299
|
+
import { basename as basename3, join as join2, resolve as resolve11 } from "path";
|
|
1241
1300
|
|
|
1242
1301
|
// packages/runtime/src/control-plane/tasks/legacy-task-config-source.ts
|
|
1243
|
-
import { existsSync as
|
|
1244
|
-
import { resolve as
|
|
1302
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
|
|
1303
|
+
import { resolve as resolve10 } from "path";
|
|
1245
1304
|
|
|
1246
1305
|
// packages/runtime/src/control-plane/tasks/task-record-reader.ts
|
|
1247
1306
|
async function findTaskById(reader, id) {
|
|
@@ -1264,7 +1323,7 @@ class LegacyTaskConfigReadError extends Error {
|
|
|
1264
1323
|
}
|
|
1265
1324
|
}
|
|
1266
1325
|
function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
1267
|
-
const configPath = options.configPath ??
|
|
1326
|
+
const configPath = options.configPath ?? resolve10(projectRoot, ".rig", "task-config.json");
|
|
1268
1327
|
const reader = {
|
|
1269
1328
|
async listTasks() {
|
|
1270
1329
|
return readLegacyTaskRecords(projectRoot, configPath);
|
|
@@ -1275,8 +1334,8 @@ function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
|
1275
1334
|
};
|
|
1276
1335
|
return reader;
|
|
1277
1336
|
}
|
|
1278
|
-
function readLegacyTaskRecords(projectRoot, configPath =
|
|
1279
|
-
if (!
|
|
1337
|
+
function readLegacyTaskRecords(projectRoot, configPath = resolve10(projectRoot, ".rig", "task-config.json")) {
|
|
1338
|
+
if (!existsSync9(configPath)) {
|
|
1280
1339
|
return [];
|
|
1281
1340
|
}
|
|
1282
1341
|
const rawConfig = readLegacyTaskConfigJson(projectRoot, configPath);
|
|
@@ -1284,7 +1343,7 @@ function readLegacyTaskRecords(projectRoot, configPath = resolve9(projectRoot, "
|
|
|
1284
1343
|
}
|
|
1285
1344
|
function readLegacyTaskConfigJson(projectRoot, configPath) {
|
|
1286
1345
|
try {
|
|
1287
|
-
const parsed = JSON.parse(
|
|
1346
|
+
const parsed = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
1288
1347
|
if (isPlainRecord(parsed)) {
|
|
1289
1348
|
return parsed;
|
|
1290
1349
|
}
|
|
@@ -1368,7 +1427,7 @@ function isPlainRecord(candidate) {
|
|
|
1368
1427
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
1369
1428
|
var FILE_TASK_PATTERN = /\.(task\.)?json$/;
|
|
1370
1429
|
function createSourceAwareTaskConfigRecordReader(projectRoot, options = {}) {
|
|
1371
|
-
const configPath = options.configPath ??
|
|
1430
|
+
const configPath = options.configPath ?? resolve11(projectRoot, ".rig", "task-config.json");
|
|
1372
1431
|
const legacy = createLegacyTaskConfigRecordReader(projectRoot, { configPath });
|
|
1373
1432
|
const spawnFn = options.spawn ?? spawnSync;
|
|
1374
1433
|
const ghBinary = options.ghBinary ?? "gh";
|
|
@@ -1451,10 +1510,10 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
1451
1510
|
return metadata;
|
|
1452
1511
|
}
|
|
1453
1512
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
1454
|
-
const jsonPath =
|
|
1455
|
-
if (
|
|
1513
|
+
const jsonPath = resolve11(projectRoot, "rig.config.json");
|
|
1514
|
+
if (existsSync10(jsonPath)) {
|
|
1456
1515
|
try {
|
|
1457
|
-
const parsed = JSON.parse(
|
|
1516
|
+
const parsed = JSON.parse(readFileSync8(jsonPath, "utf8"));
|
|
1458
1517
|
if (isPlainRecord2(parsed) && isPlainRecord2(parsed.taskSource)) {
|
|
1459
1518
|
const source = parsed.taskSource;
|
|
1460
1519
|
return source.kind === "files" && typeof source.path === "string" ? source.path : null;
|
|
@@ -1463,12 +1522,12 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
1463
1522
|
return null;
|
|
1464
1523
|
}
|
|
1465
1524
|
}
|
|
1466
|
-
const tsPath =
|
|
1467
|
-
if (!
|
|
1525
|
+
const tsPath = resolve11(projectRoot, "rig.config.ts");
|
|
1526
|
+
if (!existsSync10(tsPath)) {
|
|
1468
1527
|
return null;
|
|
1469
1528
|
}
|
|
1470
1529
|
try {
|
|
1471
|
-
const source =
|
|
1530
|
+
const source = readFileSync8(tsPath, "utf8");
|
|
1472
1531
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
1473
1532
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
1474
1533
|
if (kind !== "files") {
|
|
@@ -1488,10 +1547,10 @@ function readRawTaskEntry(configPath, taskId) {
|
|
|
1488
1547
|
return isPlainRecord2(entry) ? entry : null;
|
|
1489
1548
|
}
|
|
1490
1549
|
function readRawTaskConfig(configPath) {
|
|
1491
|
-
if (!
|
|
1550
|
+
if (!existsSync10(configPath)) {
|
|
1492
1551
|
return null;
|
|
1493
1552
|
}
|
|
1494
|
-
const parsed = JSON.parse(
|
|
1553
|
+
const parsed = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
1495
1554
|
return isPlainRecord2(parsed) ? parsed : null;
|
|
1496
1555
|
}
|
|
1497
1556
|
function stripLegacyTaskConfigMetadata2(raw) {
|
|
@@ -1499,8 +1558,8 @@ function stripLegacyTaskConfigMetadata2(raw) {
|
|
|
1499
1558
|
return tasks;
|
|
1500
1559
|
}
|
|
1501
1560
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
1502
|
-
const directory =
|
|
1503
|
-
if (!
|
|
1561
|
+
const directory = resolve11(projectRoot, sourcePath);
|
|
1562
|
+
if (!existsSync10(directory)) {
|
|
1504
1563
|
return [];
|
|
1505
1564
|
}
|
|
1506
1565
|
const tasks = [];
|
|
@@ -1515,11 +1574,11 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
1515
1574
|
return tasks;
|
|
1516
1575
|
}
|
|
1517
1576
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
1518
|
-
const file = findFileBackedTaskFile(
|
|
1577
|
+
const file = findFileBackedTaskFile(resolve11(projectRoot, sourcePath), taskId);
|
|
1519
1578
|
if (!file) {
|
|
1520
1579
|
return null;
|
|
1521
1580
|
}
|
|
1522
|
-
const raw = JSON.parse(
|
|
1581
|
+
const raw = JSON.parse(readFileSync8(file, "utf8"));
|
|
1523
1582
|
if (!isPlainRecord2(raw)) {
|
|
1524
1583
|
return null;
|
|
1525
1584
|
}
|
|
@@ -1532,7 +1591,7 @@ function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
|
1532
1591
|
};
|
|
1533
1592
|
}
|
|
1534
1593
|
function findFileBackedTaskFile(directory, taskId) {
|
|
1535
|
-
if (!
|
|
1594
|
+
if (!existsSync10(directory)) {
|
|
1536
1595
|
return null;
|
|
1537
1596
|
}
|
|
1538
1597
|
for (const name of readdirSync2(directory)) {
|
|
@@ -1542,7 +1601,7 @@ function findFileBackedTaskFile(directory, taskId) {
|
|
|
1542
1601
|
try {
|
|
1543
1602
|
if (!statSync(file).isFile())
|
|
1544
1603
|
continue;
|
|
1545
|
-
const raw = JSON.parse(
|
|
1604
|
+
const raw = JSON.parse(readFileSync8(file, "utf8"));
|
|
1546
1605
|
const inferredId = basename3(file).replace(FILE_TASK_PATTERN, "");
|
|
1547
1606
|
const id = isPlainRecord2(raw) && typeof raw.id === "string" ? raw.id : inferredId;
|
|
1548
1607
|
if (id === taskId) {
|
|
@@ -1702,8 +1761,8 @@ async function readConfiguredTaskSourceTask(projectRoot, taskId) {
|
|
|
1702
1761
|
}
|
|
1703
1762
|
|
|
1704
1763
|
// packages/runtime/src/control-plane/native/task-state.ts
|
|
1705
|
-
import { existsSync as
|
|
1706
|
-
import { basename as basename6, resolve as
|
|
1764
|
+
import { existsSync as existsSync17, readFileSync as readFileSync11, readdirSync as readdirSync3, statSync as statSync3, writeFileSync as writeFileSync7 } from "fs";
|
|
1765
|
+
import { basename as basename6, resolve as resolve18 } from "path";
|
|
1707
1766
|
|
|
1708
1767
|
// packages/runtime/src/control-plane/state-sync/types.ts
|
|
1709
1768
|
var SUPPORTED_TASK_STATE_SCHEMA_VERSION = 1;
|
|
@@ -1811,51 +1870,51 @@ function readTaskStateMetadataEnvelope(raw) {
|
|
|
1811
1870
|
};
|
|
1812
1871
|
}
|
|
1813
1872
|
// packages/runtime/src/control-plane/state-sync/read.ts
|
|
1814
|
-
import { existsSync as
|
|
1815
|
-
import { resolve as
|
|
1873
|
+
import { existsSync as existsSync16, readFileSync as readFileSync10 } from "fs";
|
|
1874
|
+
import { resolve as resolve17 } from "path";
|
|
1816
1875
|
|
|
1817
1876
|
// packages/runtime/src/control-plane/native/utils.ts
|
|
1818
|
-
import { existsSync as
|
|
1819
|
-
import { resolve as
|
|
1877
|
+
import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
|
|
1878
|
+
import { resolve as resolve14 } from "path";
|
|
1820
1879
|
|
|
1821
1880
|
// packages/runtime/src/layout.ts
|
|
1822
|
-
import { existsSync as
|
|
1823
|
-
import { basename as basename4, dirname as
|
|
1881
|
+
import { existsSync as existsSync11 } from "fs";
|
|
1882
|
+
import { basename as basename4, dirname as dirname7, resolve as resolve12 } from "path";
|
|
1824
1883
|
var RIG_DEFINITION_DIRNAME = "rig";
|
|
1825
1884
|
var RIG_STATE_DIRNAME = ".rig";
|
|
1826
1885
|
var RIG_ARTIFACTS_DIRNAME = "artifacts";
|
|
1827
1886
|
function resolveMonorepoRoot(projectRoot) {
|
|
1828
|
-
const normalizedProjectRoot =
|
|
1887
|
+
const normalizedProjectRoot = resolve12(projectRoot);
|
|
1829
1888
|
const explicit = process.env.MONOREPO_ROOT?.trim();
|
|
1830
1889
|
if (explicit) {
|
|
1831
|
-
const explicitRoot =
|
|
1832
|
-
const explicitParent =
|
|
1890
|
+
const explicitRoot = resolve12(explicit);
|
|
1891
|
+
const explicitParent = dirname7(explicitRoot);
|
|
1833
1892
|
if (basename4(explicitParent) === ".worktrees") {
|
|
1834
|
-
const owner =
|
|
1835
|
-
const ownerHasGit =
|
|
1836
|
-
const ownerHasTaskConfig =
|
|
1837
|
-
const ownerHasRigConfig =
|
|
1893
|
+
const owner = dirname7(explicitParent);
|
|
1894
|
+
const ownerHasGit = existsSync11(resolve12(owner, ".git"));
|
|
1895
|
+
const ownerHasTaskConfig = existsSync11(resolve12(owner, ".rig", "task-config.json"));
|
|
1896
|
+
const ownerHasRigConfig = existsSync11(resolve12(owner, "rig.config.ts"));
|
|
1838
1897
|
if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
|
|
1839
1898
|
return owner;
|
|
1840
1899
|
}
|
|
1841
1900
|
throw new Error(`MONOREPO_ROOT points to worktree ${explicitRoot}, but the owner checkout is incomplete at ${owner}.`);
|
|
1842
1901
|
}
|
|
1843
|
-
if (!
|
|
1902
|
+
if (!existsSync11(resolve12(explicitRoot, ".git"))) {
|
|
1844
1903
|
throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but no git checkout was found there.`);
|
|
1845
1904
|
}
|
|
1846
|
-
const hasTaskConfig =
|
|
1847
|
-
const hasRigConfig =
|
|
1905
|
+
const hasTaskConfig = existsSync11(resolve12(explicitRoot, ".rig", "task-config.json"));
|
|
1906
|
+
const hasRigConfig = existsSync11(resolve12(explicitRoot, "rig.config.ts"));
|
|
1848
1907
|
if (!hasTaskConfig && !hasRigConfig) {
|
|
1849
1908
|
throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but neither .rig/task-config.json nor rig.config.ts exists there.`);
|
|
1850
1909
|
}
|
|
1851
1910
|
return explicitRoot;
|
|
1852
1911
|
}
|
|
1853
|
-
const projectParent =
|
|
1912
|
+
const projectParent = dirname7(normalizedProjectRoot);
|
|
1854
1913
|
if (basename4(projectParent) === ".worktrees") {
|
|
1855
|
-
const worktreeOwner =
|
|
1856
|
-
const ownerHasGit =
|
|
1857
|
-
const ownerHasTaskConfig =
|
|
1858
|
-
const ownerHasRigConfig =
|
|
1914
|
+
const worktreeOwner = dirname7(projectParent);
|
|
1915
|
+
const ownerHasGit = existsSync11(resolve12(worktreeOwner, ".git"));
|
|
1916
|
+
const ownerHasTaskConfig = existsSync11(resolve12(worktreeOwner, ".rig", "task-config.json"));
|
|
1917
|
+
const ownerHasRigConfig = existsSync11(resolve12(worktreeOwner, "rig.config.ts"));
|
|
1859
1918
|
if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
|
|
1860
1919
|
return worktreeOwner;
|
|
1861
1920
|
}
|
|
@@ -1863,28 +1922,28 @@ function resolveMonorepoRoot(projectRoot) {
|
|
|
1863
1922
|
return normalizedProjectRoot;
|
|
1864
1923
|
}
|
|
1865
1924
|
function resolveRuntimeWorkspaceLayout(workspaceDir) {
|
|
1866
|
-
const root =
|
|
1867
|
-
const rigRoot =
|
|
1868
|
-
const logsDir =
|
|
1869
|
-
const stateDir =
|
|
1870
|
-
const runtimeDir =
|
|
1871
|
-
const binDir =
|
|
1925
|
+
const root = resolve12(workspaceDir);
|
|
1926
|
+
const rigRoot = resolve12(root, ".rig");
|
|
1927
|
+
const logsDir = resolve12(rigRoot, "logs");
|
|
1928
|
+
const stateDir = resolve12(rigRoot, "state");
|
|
1929
|
+
const runtimeDir = resolve12(rigRoot, "runtime");
|
|
1930
|
+
const binDir = resolve12(rigRoot, "bin");
|
|
1872
1931
|
return {
|
|
1873
1932
|
workspaceDir: root,
|
|
1874
1933
|
rigRoot,
|
|
1875
1934
|
stateDir,
|
|
1876
1935
|
logsDir,
|
|
1877
|
-
artifactsRoot:
|
|
1936
|
+
artifactsRoot: resolve12(root, RIG_ARTIFACTS_DIRNAME),
|
|
1878
1937
|
runtimeDir,
|
|
1879
|
-
homeDir:
|
|
1880
|
-
tmpDir:
|
|
1881
|
-
cacheDir:
|
|
1882
|
-
sessionDir:
|
|
1938
|
+
homeDir: resolve12(rigRoot, "home"),
|
|
1939
|
+
tmpDir: resolve12(rigRoot, "tmp"),
|
|
1940
|
+
cacheDir: resolve12(rigRoot, "cache"),
|
|
1941
|
+
sessionDir: resolve12(rigRoot, "session"),
|
|
1883
1942
|
binDir,
|
|
1884
|
-
distDir:
|
|
1885
|
-
pluginBinDir:
|
|
1886
|
-
contextPath:
|
|
1887
|
-
controlPlaneEventsFile:
|
|
1943
|
+
distDir: resolve12(rigRoot, "dist"),
|
|
1944
|
+
pluginBinDir: resolve12(binDir, "plugins"),
|
|
1945
|
+
contextPath: resolve12(rigRoot, "runtime-context.json"),
|
|
1946
|
+
controlPlaneEventsFile: resolve12(logsDir, "control-plane.events.jsonl")
|
|
1888
1947
|
};
|
|
1889
1948
|
}
|
|
1890
1949
|
function resolveActiveRuntimeWorkspaceRoot(monorepoRoot) {
|
|
@@ -1892,14 +1951,14 @@ function resolveActiveRuntimeWorkspaceRoot(monorepoRoot) {
|
|
|
1892
1951
|
if (!explicit) {
|
|
1893
1952
|
throw new Error("No active runtime workspace. Set RIG_TASK_WORKSPACE or provision a task runtime first.");
|
|
1894
1953
|
}
|
|
1895
|
-
return
|
|
1954
|
+
return resolve12(explicit);
|
|
1896
1955
|
}
|
|
1897
1956
|
function resolveRigLayout(projectRoot) {
|
|
1898
1957
|
const monorepoRoot = resolveMonorepoRoot(projectRoot);
|
|
1899
|
-
const definitionRoot =
|
|
1958
|
+
const definitionRoot = resolve12(projectRoot, RIG_DEFINITION_DIRNAME);
|
|
1900
1959
|
const runtimeWorkspaceRoot = resolveActiveRuntimeWorkspaceRoot(monorepoRoot);
|
|
1901
1960
|
const runtimeLayout = resolveRuntimeWorkspaceLayout(runtimeWorkspaceRoot);
|
|
1902
|
-
const policyDir =
|
|
1961
|
+
const policyDir = resolve12(definitionRoot, "policy");
|
|
1903
1962
|
return {
|
|
1904
1963
|
projectRoot,
|
|
1905
1964
|
monorepoRoot,
|
|
@@ -1907,48 +1966,48 @@ function resolveRigLayout(projectRoot) {
|
|
|
1907
1966
|
runtimeWorkspaceRoot,
|
|
1908
1967
|
stateRoot: runtimeLayout.rigRoot,
|
|
1909
1968
|
artifactsRoot: runtimeLayout.artifactsRoot,
|
|
1910
|
-
configPath:
|
|
1911
|
-
taskConfigPath:
|
|
1969
|
+
configPath: resolve12(definitionRoot, "config.sh"),
|
|
1970
|
+
taskConfigPath: resolve12(runtimeWorkspaceRoot, ".rig", "task-config.json"),
|
|
1912
1971
|
policyDir,
|
|
1913
|
-
policyFile:
|
|
1914
|
-
pluginsDir:
|
|
1915
|
-
hooksDir:
|
|
1916
|
-
toolsDir:
|
|
1917
|
-
templatesDir:
|
|
1918
|
-
validationDir:
|
|
1972
|
+
policyFile: resolve12(policyDir, "policy.json"),
|
|
1973
|
+
pluginsDir: resolve12(definitionRoot, "plugins"),
|
|
1974
|
+
hooksDir: resolve12(definitionRoot, "hooks"),
|
|
1975
|
+
toolsDir: resolve12(definitionRoot, "tools"),
|
|
1976
|
+
templatesDir: resolve12(definitionRoot, "templates"),
|
|
1977
|
+
validationDir: resolve12(definitionRoot, "validation"),
|
|
1919
1978
|
stateDir: runtimeLayout.stateDir,
|
|
1920
1979
|
logsDir: runtimeLayout.logsDir,
|
|
1921
|
-
notificationsDir:
|
|
1980
|
+
notificationsDir: resolve12(definitionRoot, "notifications"),
|
|
1922
1981
|
runtimeDir: runtimeLayout.runtimeDir,
|
|
1923
1982
|
distDir: runtimeLayout.distDir,
|
|
1924
1983
|
binDir: runtimeLayout.binDir,
|
|
1925
1984
|
pluginBinDir: runtimeLayout.pluginBinDir,
|
|
1926
|
-
keybindingsPath:
|
|
1985
|
+
keybindingsPath: resolve12(definitionRoot, "keybindings.json"),
|
|
1927
1986
|
controlPlaneEventsFile: runtimeLayout.controlPlaneEventsFile
|
|
1928
1987
|
};
|
|
1929
1988
|
}
|
|
1930
1989
|
|
|
1931
1990
|
// packages/runtime/src/control-plane/native/runtime-native.ts
|
|
1932
1991
|
import { dlopen, ptr, suffix, toBuffer } from "bun:ffi";
|
|
1933
|
-
import { copyFileSync as copyFileSync2, existsSync as
|
|
1992
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync12, mkdirSync as mkdirSync6, renameSync as renameSync2, rmSync as rmSync3, statSync as statSync2 } from "fs";
|
|
1934
1993
|
import { tmpdir as tmpdir4 } from "os";
|
|
1935
|
-
import { dirname as
|
|
1936
|
-
var sharedNativeRuntimeOutputDir =
|
|
1937
|
-
var sharedNativeRuntimeOutputPath =
|
|
1994
|
+
import { dirname as dirname8, resolve as resolve13 } from "path";
|
|
1995
|
+
var sharedNativeRuntimeOutputDir = resolve13(tmpdir4(), "rig-native");
|
|
1996
|
+
var sharedNativeRuntimeOutputPath = resolve13(sharedNativeRuntimeOutputDir, `runtime-native-${process.platform}-${process.arch}.${suffix}`);
|
|
1938
1997
|
var colocatedNativeRuntimeFileName = `runtime-native.${suffix}`;
|
|
1939
1998
|
var nativeRuntimeLibrary = await loadNativeRuntimeLibrary();
|
|
1940
1999
|
async function ensureNativeRuntimeLibraryPath(outputPath = sharedNativeRuntimeOutputPath, options = {}) {
|
|
1941
2000
|
if (await buildNativeRuntimeLibrary(outputPath, options)) {
|
|
1942
2001
|
return outputPath;
|
|
1943
2002
|
}
|
|
1944
|
-
return !options.force &&
|
|
2003
|
+
return !options.force && existsSync12(outputPath) ? outputPath : null;
|
|
1945
2004
|
}
|
|
1946
2005
|
async function loadNativeRuntimeLibrary() {
|
|
1947
2006
|
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
1948
2007
|
return null;
|
|
1949
2008
|
}
|
|
1950
2009
|
for (const candidate of nativeRuntimeLibraryCandidates()) {
|
|
1951
|
-
if (!candidate || !
|
|
2010
|
+
if (!candidate || !existsSync12(candidate)) {
|
|
1952
2011
|
continue;
|
|
1953
2012
|
}
|
|
1954
2013
|
const loaded = tryDlopenNativeRuntimeLibrary(candidate);
|
|
@@ -1964,12 +2023,12 @@ async function loadNativeRuntimeLibrary() {
|
|
|
1964
2023
|
}
|
|
1965
2024
|
function nativePackageLibraryCandidates(fromDir, names) {
|
|
1966
2025
|
const candidates = [];
|
|
1967
|
-
let cursor =
|
|
2026
|
+
let cursor = resolve13(fromDir);
|
|
1968
2027
|
for (let index = 0;index < 8; index += 1) {
|
|
1969
2028
|
for (const name of names) {
|
|
1970
|
-
candidates.push(
|
|
2029
|
+
candidates.push(resolve13(cursor, "native", `${process.platform}-${process.arch}`, name), resolve13(cursor, "native", `${process.platform}-${process.arch}`, "lib", name), resolve13(cursor, "native", name), resolve13(cursor, "native", "lib", name));
|
|
1971
2030
|
}
|
|
1972
|
-
const parent =
|
|
2031
|
+
const parent = dirname8(cursor);
|
|
1973
2032
|
if (parent === cursor)
|
|
1974
2033
|
break;
|
|
1975
2034
|
cursor = parent;
|
|
@@ -1978,27 +2037,27 @@ function nativePackageLibraryCandidates(fromDir, names) {
|
|
|
1978
2037
|
}
|
|
1979
2038
|
function nativeRuntimeLibraryCandidates() {
|
|
1980
2039
|
const explicit = process.env.RIG_NATIVE_RUNTIME_LIB?.trim() || "";
|
|
1981
|
-
const execDir = process.execPath?.trim() ?
|
|
2040
|
+
const execDir = process.execPath?.trim() ? dirname8(process.execPath.trim()) : "";
|
|
1982
2041
|
const platformSpecific = `runtime-native-${process.platform}-${process.arch}.${suffix}`;
|
|
1983
2042
|
return [...new Set([
|
|
1984
2043
|
explicit,
|
|
1985
2044
|
...nativePackageLibraryCandidates(import.meta.dir, [colocatedNativeRuntimeFileName, platformSpecific]),
|
|
1986
|
-
execDir ?
|
|
1987
|
-
execDir ?
|
|
1988
|
-
execDir ?
|
|
1989
|
-
execDir ?
|
|
1990
|
-
execDir ?
|
|
1991
|
-
execDir ?
|
|
2045
|
+
execDir ? resolve13(execDir, colocatedNativeRuntimeFileName) : "",
|
|
2046
|
+
execDir ? resolve13(execDir, platformSpecific) : "",
|
|
2047
|
+
execDir ? resolve13(execDir, "..", colocatedNativeRuntimeFileName) : "",
|
|
2048
|
+
execDir ? resolve13(execDir, "..", platformSpecific) : "",
|
|
2049
|
+
execDir ? resolve13(execDir, "lib", colocatedNativeRuntimeFileName) : "",
|
|
2050
|
+
execDir ? resolve13(execDir, "..", "lib", colocatedNativeRuntimeFileName) : "",
|
|
1992
2051
|
sharedNativeRuntimeOutputPath
|
|
1993
2052
|
].filter(Boolean))];
|
|
1994
2053
|
}
|
|
1995
2054
|
function resolveNativeRuntimeSourcePath() {
|
|
1996
2055
|
const explicit = process.env.RIG_NATIVE_RUNTIME_SOURCE?.trim();
|
|
1997
|
-
if (explicit &&
|
|
2056
|
+
if (explicit && existsSync12(explicit)) {
|
|
1998
2057
|
return explicit;
|
|
1999
2058
|
}
|
|
2000
|
-
const bundled =
|
|
2001
|
-
return
|
|
2059
|
+
const bundled = resolve13(import.meta.dir, "../../../native/snapshot.zig");
|
|
2060
|
+
return existsSync12(bundled) ? bundled : null;
|
|
2002
2061
|
}
|
|
2003
2062
|
async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
2004
2063
|
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
@@ -2011,8 +2070,8 @@ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
|
2011
2070
|
}
|
|
2012
2071
|
const tempOutputPath = `${outputPath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
2013
2072
|
try {
|
|
2014
|
-
|
|
2015
|
-
const needsBuild = options.force === true || !
|
|
2073
|
+
mkdirSync6(dirname8(outputPath), { recursive: true });
|
|
2074
|
+
const needsBuild = options.force === true || !existsSync12(outputPath) || statSync2(sourcePath).mtimeMs > statSync2(outputPath).mtimeMs;
|
|
2016
2075
|
if (!needsBuild) {
|
|
2017
2076
|
return true;
|
|
2018
2077
|
}
|
|
@@ -2030,7 +2089,7 @@ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
|
2030
2089
|
stderr: "pipe"
|
|
2031
2090
|
});
|
|
2032
2091
|
const exitCode = await build.exited;
|
|
2033
|
-
if (exitCode !== 0 || !
|
|
2092
|
+
if (exitCode !== 0 || !existsSync12(tempOutputPath)) {
|
|
2034
2093
|
rmSync3(tempOutputPath, { force: true });
|
|
2035
2094
|
return false;
|
|
2036
2095
|
}
|
|
@@ -2160,11 +2219,11 @@ async function runCaptureAsync(command, cwd, env, timeoutMs) {
|
|
|
2160
2219
|
return { exitCode, stdout, stderr };
|
|
2161
2220
|
}
|
|
2162
2221
|
function readJsonFile(path, fallback) {
|
|
2163
|
-
if (!
|
|
2222
|
+
if (!existsSync13(path)) {
|
|
2164
2223
|
return fallback;
|
|
2165
2224
|
}
|
|
2166
2225
|
try {
|
|
2167
|
-
return JSON.parse(
|
|
2226
|
+
return JSON.parse(readFileSync9(path, "utf-8"));
|
|
2168
2227
|
} catch {
|
|
2169
2228
|
return fallback;
|
|
2170
2229
|
}
|
|
@@ -2178,31 +2237,31 @@ function unique(values) {
|
|
|
2178
2237
|
function resolveHarnessPaths(projectRoot) {
|
|
2179
2238
|
const hasRuntimeWorkspace = Boolean(process.env.RIG_TASK_WORKSPACE?.trim());
|
|
2180
2239
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
2181
|
-
const harnessRoot =
|
|
2182
|
-
const stateRoot =
|
|
2240
|
+
const harnessRoot = resolve14(projectRoot, "rig");
|
|
2241
|
+
const stateRoot = resolve14(projectRoot, ".rig");
|
|
2183
2242
|
const layout = hasRuntimeWorkspace ? resolveRigLayout(projectRoot) : null;
|
|
2184
|
-
const stateDir = layout?.stateDir ??
|
|
2185
|
-
const logsDir = layout?.logsDir ??
|
|
2186
|
-
const artifactsDir = layout?.artifactsRoot ??
|
|
2187
|
-
const taskConfigPath = layout?.taskConfigPath ??
|
|
2188
|
-
const binDir = layout?.binDir ??
|
|
2243
|
+
const stateDir = layout?.stateDir ?? resolve14(stateRoot, "state");
|
|
2244
|
+
const logsDir = layout?.logsDir ?? resolve14(stateRoot, "logs");
|
|
2245
|
+
const artifactsDir = layout?.artifactsRoot ?? resolve14(monorepoRoot, "artifacts");
|
|
2246
|
+
const taskConfigPath = layout?.taskConfigPath ?? resolve14(monorepoRoot, ".rig", "task-config.json");
|
|
2247
|
+
const binDir = layout?.binDir ?? resolve14(stateRoot, "bin");
|
|
2189
2248
|
return {
|
|
2190
2249
|
harnessRoot,
|
|
2191
2250
|
stateDir: process.env.RIG_STATE_DIR || stateDir,
|
|
2192
2251
|
artifactsDir,
|
|
2193
2252
|
logsDir: process.env.RIG_LOGS_DIR || logsDir,
|
|
2194
2253
|
binDir,
|
|
2195
|
-
hooksDir:
|
|
2196
|
-
validationDir:
|
|
2254
|
+
hooksDir: resolve14(harnessRoot, "hooks"),
|
|
2255
|
+
validationDir: resolve14(harnessRoot, "validation"),
|
|
2197
2256
|
taskConfigPath,
|
|
2198
|
-
sessionPath: process.env.RIG_SESSION_FILE ||
|
|
2257
|
+
sessionPath: process.env.RIG_SESSION_FILE || resolve14(stateRoot, "session", "session.json"),
|
|
2199
2258
|
monorepoRoot,
|
|
2200
|
-
tsApiTestsDir: process.env.TS_API_TESTS_DIR ||
|
|
2201
|
-
taskRepoCommitsPath:
|
|
2202
|
-
baseRepoPinsPath:
|
|
2203
|
-
failedApproachesPath:
|
|
2204
|
-
agentProfilePath:
|
|
2205
|
-
reviewProfilePath:
|
|
2259
|
+
tsApiTestsDir: process.env.TS_API_TESTS_DIR || resolve14(monorepoRoot, "TSAPITests"),
|
|
2260
|
+
taskRepoCommitsPath: resolve14(stateDir, "task-repo-commits.json"),
|
|
2261
|
+
baseRepoPinsPath: resolve14(stateDir, "base-repo-pins.json"),
|
|
2262
|
+
failedApproachesPath: resolve14(stateDir, "failed_approaches.md"),
|
|
2263
|
+
agentProfilePath: resolve14(stateDir, "agent-profile.json"),
|
|
2264
|
+
reviewProfilePath: resolve14(stateDir, "review-profile.json")
|
|
2206
2265
|
};
|
|
2207
2266
|
}
|
|
2208
2267
|
function normalizeRelativeScopePath(inputPath) {
|
|
@@ -2260,34 +2319,34 @@ function monorepoSearchCandidates(inputPath) {
|
|
|
2260
2319
|
}
|
|
2261
2320
|
|
|
2262
2321
|
// packages/runtime/src/control-plane/state-sync/repo.ts
|
|
2263
|
-
import { existsSync as
|
|
2264
|
-
import { resolve as
|
|
2322
|
+
import { existsSync as existsSync15 } from "fs";
|
|
2323
|
+
import { resolve as resolve16 } from "path";
|
|
2265
2324
|
|
|
2266
2325
|
// packages/runtime/src/control-plane/repos/layout.ts
|
|
2267
|
-
import { existsSync as
|
|
2268
|
-
import { basename as basename5, dirname as
|
|
2326
|
+
import { existsSync as existsSync14 } from "fs";
|
|
2327
|
+
import { basename as basename5, dirname as dirname9, join as join3, resolve as resolve15 } from "path";
|
|
2269
2328
|
function resolveRepoStateDir(projectRoot) {
|
|
2270
|
-
const normalizedProjectRoot =
|
|
2271
|
-
const projectParent =
|
|
2329
|
+
const normalizedProjectRoot = resolve15(projectRoot);
|
|
2330
|
+
const projectParent = dirname9(normalizedProjectRoot);
|
|
2272
2331
|
if (basename5(projectParent) === ".worktrees") {
|
|
2273
|
-
const ownerRoot =
|
|
2274
|
-
const ownerHasRepoMarkers =
|
|
2332
|
+
const ownerRoot = dirname9(projectParent);
|
|
2333
|
+
const ownerHasRepoMarkers = existsSync14(resolve15(ownerRoot, ".git")) || existsSync14(resolve15(ownerRoot, ".rig", "state"));
|
|
2275
2334
|
if (ownerHasRepoMarkers) {
|
|
2276
|
-
return
|
|
2335
|
+
return resolve15(ownerRoot, ".rig", "state");
|
|
2277
2336
|
}
|
|
2278
2337
|
}
|
|
2279
|
-
return
|
|
2338
|
+
return resolve15(projectRoot, ".rig", "state");
|
|
2280
2339
|
}
|
|
2281
2340
|
function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
2282
|
-
const normalizedProjectRoot =
|
|
2341
|
+
const normalizedProjectRoot = resolve15(projectRoot);
|
|
2283
2342
|
const entry = getManagedRepoEntry(repoId);
|
|
2284
2343
|
const stateDir = resolveRepoStateDir(normalizedProjectRoot);
|
|
2285
2344
|
const metadataRelativePath = join3("repos", entry.id);
|
|
2286
|
-
const metadataRoot =
|
|
2345
|
+
const metadataRoot = resolve15(stateDir, metadataRelativePath);
|
|
2287
2346
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
2288
|
-
const runsInsideTaskWorktree = runtimeWorkspace &&
|
|
2347
|
+
const runsInsideTaskWorktree = runtimeWorkspace && resolve15(runtimeWorkspace) === normalizedProjectRoot || basename5(dirname9(normalizedProjectRoot)) === ".worktrees";
|
|
2289
2348
|
const isPrimaryManagedRepo = listManagedRepoEntries()[0]?.id === repoId;
|
|
2290
|
-
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ?
|
|
2349
|
+
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ? resolve15(process.env[entry.checkoutEnvVar].trim()) : resolve15(normalizedProjectRoot, entry.alias);
|
|
2291
2350
|
return {
|
|
2292
2351
|
projectRoot: normalizedProjectRoot,
|
|
2293
2352
|
repoId: entry.id,
|
|
@@ -2295,12 +2354,12 @@ function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
|
2295
2354
|
defaultBranch: entry.defaultBranch,
|
|
2296
2355
|
remoteUrl: entry.remoteEnvVar && process.env[entry.remoteEnvVar]?.trim() ? process.env[entry.remoteEnvVar].trim() : entry.defaultRemoteUrl,
|
|
2297
2356
|
checkoutRoot,
|
|
2298
|
-
worktreesRoot:
|
|
2357
|
+
worktreesRoot: resolve15(checkoutRoot, ".worktrees"),
|
|
2299
2358
|
stateDir,
|
|
2300
2359
|
metadataRoot,
|
|
2301
2360
|
metadataRelativePath,
|
|
2302
|
-
mirrorRoot:
|
|
2303
|
-
mirrorStatePath:
|
|
2361
|
+
mirrorRoot: resolve15(metadataRoot, "mirror.git"),
|
|
2362
|
+
mirrorStatePath: resolve15(metadataRoot, "mirror-state.json"),
|
|
2304
2363
|
mirrorStateRelativePath: join3(metadataRelativePath, "mirror-state.json")
|
|
2305
2364
|
};
|
|
2306
2365
|
}
|
|
@@ -2322,7 +2381,7 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
2322
2381
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
2323
2382
|
try {
|
|
2324
2383
|
const layout = resolveMonorepoRepoLayout(projectRoot);
|
|
2325
|
-
if (
|
|
2384
|
+
if (existsSync15(resolve16(layout.mirrorRoot, "HEAD"))) {
|
|
2326
2385
|
return layout.mirrorRoot;
|
|
2327
2386
|
}
|
|
2328
2387
|
} catch {}
|
|
@@ -2333,8 +2392,8 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
2333
2392
|
var DEFAULT_READ_DEPS = {
|
|
2334
2393
|
fetchRef: nativeFetchRef,
|
|
2335
2394
|
readBlobAtRef: nativeReadBlobAtRef,
|
|
2336
|
-
exists:
|
|
2337
|
-
readFile: (path) =>
|
|
2395
|
+
exists: existsSync16,
|
|
2396
|
+
readFile: (path) => readFileSync10(path, "utf8")
|
|
2338
2397
|
};
|
|
2339
2398
|
function parseIssueStatus(rawStatus) {
|
|
2340
2399
|
const normalized = normalizeTaskLifecycleStatus(rawStatus);
|
|
@@ -2415,12 +2474,12 @@ function shouldPreferLocalTrackerState(options) {
|
|
|
2415
2474
|
if (runtimeContextPath) {
|
|
2416
2475
|
return true;
|
|
2417
2476
|
}
|
|
2418
|
-
return
|
|
2477
|
+
return existsSync16(resolve17(runtimeWorkspace, ".rig", "runtime-context.json"));
|
|
2419
2478
|
}
|
|
2420
2479
|
function readLocalTrackerState(projectRoot, deps) {
|
|
2421
2480
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
2422
|
-
const issuesPath =
|
|
2423
|
-
const taskStatePath =
|
|
2481
|
+
const issuesPath = resolve17(monorepoRoot, ".beads", "issues.jsonl");
|
|
2482
|
+
const taskStatePath = resolve17(monorepoRoot, ".beads", "task-state.json");
|
|
2424
2483
|
return projectSyncedTrackerSnapshot({
|
|
2425
2484
|
source: "local",
|
|
2426
2485
|
issuesBaseOid: null,
|
|
@@ -2482,7 +2541,7 @@ function readValidationDescriptions(projectRoot) {
|
|
|
2482
2541
|
return readValidationDescriptionMap(raw);
|
|
2483
2542
|
}
|
|
2484
2543
|
function readSourceValidationDescriptions(projectRoot) {
|
|
2485
|
-
const rootRaw = readJsonFile(
|
|
2544
|
+
const rootRaw = readJsonFile(resolve18(projectRoot, "rig", "task-config.json"), {});
|
|
2486
2545
|
const sourcePath = findSourceTaskConfigPath(projectRoot);
|
|
2487
2546
|
const sourceRaw = sourcePath ? readJsonFile(sourcePath, {}) : {};
|
|
2488
2547
|
const rootDescriptions = readValidationDescriptionMap(rootRaw);
|
|
@@ -2558,15 +2617,15 @@ function readValidationDescriptionsFromMeta(meta) {
|
|
|
2558
2617
|
return meta.validation_descriptions;
|
|
2559
2618
|
}
|
|
2560
2619
|
function readLocalSourceTaskStateEnvelope(projectRoot) {
|
|
2561
|
-
const taskStatePath =
|
|
2620
|
+
const taskStatePath = resolve18(resolveMonorepoRoot2(projectRoot), ".beads", "task-state.json");
|
|
2562
2621
|
return readTaskStateMetadataEnvelope(readJsonFile(taskStatePath, {}));
|
|
2563
2622
|
}
|
|
2564
2623
|
function readLocalSourceTaskLifecycleStatus(projectRoot, taskId) {
|
|
2565
|
-
const issuesPath =
|
|
2566
|
-
if (!
|
|
2624
|
+
const issuesPath = resolve18(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
2625
|
+
if (!existsSync17(issuesPath)) {
|
|
2567
2626
|
return null;
|
|
2568
2627
|
}
|
|
2569
|
-
for (const line of
|
|
2628
|
+
for (const line of readFileSync11(issuesPath, "utf8").split(/\r?\n/)) {
|
|
2570
2629
|
const trimmed = line.trim();
|
|
2571
2630
|
if (!trimmed) {
|
|
2572
2631
|
continue;
|
|
@@ -2607,25 +2666,25 @@ function lookupTask(projectRoot, input) {
|
|
|
2607
2666
|
function artifactDirForId(projectRoot, id) {
|
|
2608
2667
|
const workspaceDir = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
2609
2668
|
if (workspaceDir) {
|
|
2610
|
-
const worktreeArtifacts =
|
|
2611
|
-
if (
|
|
2669
|
+
const worktreeArtifacts = resolve18(workspaceDir, "artifacts", id);
|
|
2670
|
+
if (existsSync17(worktreeArtifacts) || existsSync17(resolve18(workspaceDir, "artifacts"))) {
|
|
2612
2671
|
return worktreeArtifacts;
|
|
2613
2672
|
}
|
|
2614
2673
|
}
|
|
2615
2674
|
try {
|
|
2616
2675
|
const paths = resolveHarnessPaths(projectRoot);
|
|
2617
|
-
return
|
|
2676
|
+
return resolve18(paths.artifactsDir, id);
|
|
2618
2677
|
} catch {
|
|
2619
|
-
return
|
|
2678
|
+
return resolve18(resolveMonorepoRoot2(projectRoot), "artifacts", id);
|
|
2620
2679
|
}
|
|
2621
2680
|
}
|
|
2622
2681
|
function resolveTaskConfigPath(projectRoot) {
|
|
2623
2682
|
const paths = resolveHarnessPaths(projectRoot);
|
|
2624
|
-
if (
|
|
2683
|
+
if (existsSync17(paths.taskConfigPath)) {
|
|
2625
2684
|
return paths.taskConfigPath;
|
|
2626
2685
|
}
|
|
2627
2686
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
2628
|
-
if (
|
|
2687
|
+
if (existsSync17(candidate)) {
|
|
2629
2688
|
return candidate;
|
|
2630
2689
|
}
|
|
2631
2690
|
}
|
|
@@ -2633,7 +2692,7 @@ function resolveTaskConfigPath(projectRoot) {
|
|
|
2633
2692
|
}
|
|
2634
2693
|
function findSourceTaskConfigPath(projectRoot) {
|
|
2635
2694
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
2636
|
-
if (
|
|
2695
|
+
if (existsSync17(candidate)) {
|
|
2637
2696
|
return candidate;
|
|
2638
2697
|
}
|
|
2639
2698
|
}
|
|
@@ -2646,7 +2705,7 @@ function readAndSyncSourceTaskConfig(projectRoot) {
|
|
|
2646
2705
|
const synced = synchronizeTaskConfigWithTracker(projectRoot, raw);
|
|
2647
2706
|
if (sourcePath && synced.updated) {
|
|
2648
2707
|
try {
|
|
2649
|
-
|
|
2708
|
+
writeFileSync7(sourcePath, `${JSON.stringify(synced.config, null, 2)}
|
|
2650
2709
|
`, "utf-8");
|
|
2651
2710
|
} catch {}
|
|
2652
2711
|
}
|
|
@@ -2698,12 +2757,12 @@ function shouldRefreshAutoSyncedTaskConfigEntry(entry) {
|
|
|
2698
2757
|
return !candidate.role;
|
|
2699
2758
|
}
|
|
2700
2759
|
function readSourceIssueRecords(projectRoot) {
|
|
2701
|
-
const issuesPath =
|
|
2702
|
-
if (!
|
|
2760
|
+
const issuesPath = resolve18(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
2761
|
+
if (!existsSync17(issuesPath)) {
|
|
2703
2762
|
return [];
|
|
2704
2763
|
}
|
|
2705
2764
|
const records = [];
|
|
2706
|
-
for (const line of
|
|
2765
|
+
for (const line of readFileSync11(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
2707
2766
|
const trimmed = line.trim();
|
|
2708
2767
|
if (!trimmed) {
|
|
2709
2768
|
continue;
|
|
@@ -2759,19 +2818,19 @@ function readConfiguredFileTaskConfig(projectRoot) {
|
|
|
2759
2818
|
if (!sourcePath) {
|
|
2760
2819
|
return {};
|
|
2761
2820
|
}
|
|
2762
|
-
const directory =
|
|
2763
|
-
if (!
|
|
2821
|
+
const directory = resolve18(projectRoot, sourcePath);
|
|
2822
|
+
if (!existsSync17(directory)) {
|
|
2764
2823
|
return {};
|
|
2765
2824
|
}
|
|
2766
2825
|
const config = {};
|
|
2767
2826
|
for (const name of readdirSync3(directory)) {
|
|
2768
2827
|
if (!FILE_TASK_PATTERN2.test(name))
|
|
2769
2828
|
continue;
|
|
2770
|
-
const file =
|
|
2829
|
+
const file = resolve18(directory, name);
|
|
2771
2830
|
try {
|
|
2772
2831
|
if (!statSync3(file).isFile())
|
|
2773
2832
|
continue;
|
|
2774
|
-
const raw = JSON.parse(
|
|
2833
|
+
const raw = JSON.parse(readFileSync11(file, "utf8"));
|
|
2775
2834
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
2776
2835
|
continue;
|
|
2777
2836
|
const record = raw;
|
|
@@ -2813,10 +2872,10 @@ function firstStringList2(...candidates) {
|
|
|
2813
2872
|
return [];
|
|
2814
2873
|
}
|
|
2815
2874
|
function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
2816
|
-
const jsonPath =
|
|
2817
|
-
if (
|
|
2875
|
+
const jsonPath = resolve18(projectRoot, "rig.config.json");
|
|
2876
|
+
if (existsSync17(jsonPath)) {
|
|
2818
2877
|
try {
|
|
2819
|
-
const parsed = JSON.parse(
|
|
2878
|
+
const parsed = JSON.parse(readFileSync11(jsonPath, "utf8"));
|
|
2820
2879
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
2821
2880
|
const taskSource = parsed.taskSource;
|
|
2822
2881
|
if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
|
|
@@ -2828,12 +2887,12 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
2828
2887
|
return null;
|
|
2829
2888
|
}
|
|
2830
2889
|
}
|
|
2831
|
-
const tsPath =
|
|
2832
|
-
if (!
|
|
2890
|
+
const tsPath = resolve18(projectRoot, "rig.config.ts");
|
|
2891
|
+
if (!existsSync17(tsPath)) {
|
|
2833
2892
|
return null;
|
|
2834
2893
|
}
|
|
2835
2894
|
try {
|
|
2836
|
-
const source =
|
|
2895
|
+
const source = readFileSync11(tsPath, "utf8");
|
|
2837
2896
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
2838
2897
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
2839
2898
|
if (kind !== "files") {
|
|
@@ -2847,23 +2906,23 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
2847
2906
|
function sourceTaskConfigCandidates(projectRoot) {
|
|
2848
2907
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
2849
2908
|
return [
|
|
2850
|
-
runtimeContext?.monorepoMainRoot ?
|
|
2851
|
-
process.env.MONOREPO_MAIN_ROOT?.trim() ?
|
|
2852
|
-
|
|
2909
|
+
runtimeContext?.monorepoMainRoot ? resolve18(runtimeContext.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
2910
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve18(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
2911
|
+
resolve18(resolveMonorepoRoot2(projectRoot), ".rig", "task-config.json")
|
|
2853
2912
|
].filter(Boolean);
|
|
2854
2913
|
}
|
|
2855
2914
|
|
|
2856
2915
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
2857
|
-
import { existsSync as
|
|
2858
|
-
import { resolve as
|
|
2916
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
2917
|
+
import { resolve as resolve23 } from "path";
|
|
2859
2918
|
|
|
2860
2919
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
2861
|
-
import { existsSync as
|
|
2862
|
-
import { dirname as
|
|
2920
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync8, rmSync as rmSync5, statSync as statSync4 } from "fs";
|
|
2921
|
+
import { dirname as dirname11, resolve as resolve22 } from "path";
|
|
2863
2922
|
|
|
2864
2923
|
// packages/runtime/src/binary-run.ts
|
|
2865
|
-
import { chmodSync as chmodSync2, cpSync, existsSync as
|
|
2866
|
-
import { basename as basename7, dirname as
|
|
2924
|
+
import { chmodSync as chmodSync2, cpSync, existsSync as existsSync18, mkdirSync as mkdirSync7, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
2925
|
+
import { basename as basename7, dirname as dirname10, resolve as resolve19 } from "path";
|
|
2867
2926
|
import { fileURLToPath } from "url";
|
|
2868
2927
|
import { drainMicrotasks, gcAndSweep } from "bun:jsc";
|
|
2869
2928
|
var runtimeBinaryBuildQueue = Promise.resolve();
|
|
@@ -2889,9 +2948,9 @@ async function buildRuntimeBinary(options) {
|
|
|
2889
2948
|
});
|
|
2890
2949
|
}
|
|
2891
2950
|
async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
2892
|
-
const tempBuildDir =
|
|
2893
|
-
const tempOutputPath =
|
|
2894
|
-
|
|
2951
|
+
const tempBuildDir = resolve19(dirname10(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
2952
|
+
const tempOutputPath = resolve19(tempBuildDir, basename7(options.outputPath));
|
|
2953
|
+
mkdirSync7(tempBuildDir, { recursive: true });
|
|
2895
2954
|
await withTemporaryEnv({
|
|
2896
2955
|
...options.env,
|
|
2897
2956
|
...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
|
|
@@ -2916,7 +2975,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
2916
2975
|
`);
|
|
2917
2976
|
throw new Error(`Failed to build ${options.entrypoint}: ${details || "Bun.build() returned errors"}`);
|
|
2918
2977
|
}
|
|
2919
|
-
if (!
|
|
2978
|
+
if (!existsSync18(tempOutputPath)) {
|
|
2920
2979
|
const emitted = buildResult.outputs.map((output) => output.path).join(", ") || "(none)";
|
|
2921
2980
|
throw new Error(`Failed to build ${options.entrypoint}: Bun.build() did not emit ${tempOutputPath}. Emitted: ${emitted}`);
|
|
2922
2981
|
}
|
|
@@ -2948,8 +3007,8 @@ function runtimeBinaryCacheManifestPath(outputPath) {
|
|
|
2948
3007
|
function resolveRuntimeBinaryBuildOptions(options) {
|
|
2949
3008
|
return {
|
|
2950
3009
|
...options,
|
|
2951
|
-
entrypoint:
|
|
2952
|
-
outputPath:
|
|
3010
|
+
entrypoint: resolve19(options.cwd, options.sourcePath),
|
|
3011
|
+
outputPath: resolve19(options.outputPath)
|
|
2953
3012
|
};
|
|
2954
3013
|
}
|
|
2955
3014
|
function shouldUseRuntimeBinaryBuildWorker() {
|
|
@@ -2963,7 +3022,7 @@ function shouldUseRuntimeBinaryBuildWorker() {
|
|
|
2963
3022
|
}
|
|
2964
3023
|
async function buildRuntimeBinaryViaWorker(options) {
|
|
2965
3024
|
const workerSourcePath = resolveRuntimeBinaryBuildWorkerSourcePath(options);
|
|
2966
|
-
if (!workerSourcePath || !
|
|
3025
|
+
if (!workerSourcePath || !existsSync18(workerSourcePath)) {
|
|
2967
3026
|
await buildRuntimeBinaryInProcess(options, {
|
|
2968
3027
|
manifestPath: runtimeBinaryCacheManifestPath(options.outputPath),
|
|
2969
3028
|
buildKey: createRuntimeBinaryBuildKey({
|
|
@@ -3000,7 +3059,7 @@ async function buildRuntimeBinaryViaWorker(options) {
|
|
|
3000
3059
|
}
|
|
3001
3060
|
}
|
|
3002
3061
|
function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
|
|
3003
|
-
return
|
|
3062
|
+
return resolve19(dirname10(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
3004
3063
|
}
|
|
3005
3064
|
function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
3006
3065
|
const envRoots = [
|
|
@@ -3009,13 +3068,13 @@ function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
|
3009
3068
|
process.env.PROJECT_RIG_ROOT?.trim()
|
|
3010
3069
|
].filter(Boolean);
|
|
3011
3070
|
for (const root of envRoots) {
|
|
3012
|
-
const candidate =
|
|
3013
|
-
if (
|
|
3071
|
+
const candidate = resolve19(root, "packages/runtime/src/binary-build-worker.ts");
|
|
3072
|
+
if (existsSync18(candidate)) {
|
|
3014
3073
|
return candidate;
|
|
3015
3074
|
}
|
|
3016
3075
|
}
|
|
3017
|
-
const localCandidate =
|
|
3018
|
-
return
|
|
3076
|
+
const localCandidate = resolve19(import.meta.dir, "binary-build-worker.ts");
|
|
3077
|
+
return existsSync18(localCandidate) ? localCandidate : null;
|
|
3019
3078
|
}
|
|
3020
3079
|
function resolveRuntimeBinaryBuildWorkerInvocation() {
|
|
3021
3080
|
const bunPath = Bun.which("bun");
|
|
@@ -3051,7 +3110,7 @@ function createRuntimeBinaryBuildKey(input) {
|
|
|
3051
3110
|
});
|
|
3052
3111
|
}
|
|
3053
3112
|
async function isRuntimeBinaryBuildFresh(input) {
|
|
3054
|
-
if (!
|
|
3113
|
+
if (!existsSync18(input.outputPath) || !existsSync18(input.manifestPath)) {
|
|
3055
3114
|
return false;
|
|
3056
3115
|
}
|
|
3057
3116
|
let manifest = null;
|
|
@@ -3064,7 +3123,7 @@ async function isRuntimeBinaryBuildFresh(input) {
|
|
|
3064
3123
|
return false;
|
|
3065
3124
|
}
|
|
3066
3125
|
for (const [filePath, expectedDigest] of Object.entries(manifest.inputs || {})) {
|
|
3067
|
-
if (!
|
|
3126
|
+
if (!existsSync18(filePath)) {
|
|
3068
3127
|
return false;
|
|
3069
3128
|
}
|
|
3070
3129
|
if (await sha256File(filePath) !== expectedDigest) {
|
|
@@ -3077,7 +3136,7 @@ async function writeRuntimeBinaryCacheManifest(input) {
|
|
|
3077
3136
|
const inputs = {};
|
|
3078
3137
|
for (const inputPath of Object.keys(input.metafile?.inputs || {}).sort()) {
|
|
3079
3138
|
const normalized = normalizeBuildInputPath(input.cwd, inputPath);
|
|
3080
|
-
if (!normalized || !
|
|
3139
|
+
if (!normalized || !existsSync18(normalized)) {
|
|
3081
3140
|
continue;
|
|
3082
3141
|
}
|
|
3083
3142
|
inputs[normalized] = await sha256File(normalized);
|
|
@@ -3100,7 +3159,7 @@ function normalizeBuildInputPath(cwd, inputPath) {
|
|
|
3100
3159
|
if (inputPath.startsWith("<")) {
|
|
3101
3160
|
return null;
|
|
3102
3161
|
}
|
|
3103
|
-
return
|
|
3162
|
+
return resolve19(cwd, inputPath);
|
|
3104
3163
|
}
|
|
3105
3164
|
async function sha256File(path) {
|
|
3106
3165
|
const hasher = new Bun.CryptoHasher("sha256");
|
|
@@ -3116,8 +3175,8 @@ function sortRecord(value) {
|
|
|
3116
3175
|
async function runSerializedRuntimeBinaryBuild(action) {
|
|
3117
3176
|
const previous = runtimeBinaryBuildQueue;
|
|
3118
3177
|
let release;
|
|
3119
|
-
runtimeBinaryBuildQueue = new Promise((
|
|
3120
|
-
release =
|
|
3178
|
+
runtimeBinaryBuildQueue = new Promise((resolve20) => {
|
|
3179
|
+
release = resolve20;
|
|
3121
3180
|
});
|
|
3122
3181
|
await previous;
|
|
3123
3182
|
try {
|
|
@@ -3162,11 +3221,11 @@ async function withTemporaryCwd(cwd, action) {
|
|
|
3162
3221
|
}
|
|
3163
3222
|
|
|
3164
3223
|
// packages/runtime/src/control-plane/runtime/provisioning-env.ts
|
|
3165
|
-
import { delimiter, resolve as
|
|
3224
|
+
import { delimiter, resolve as resolve21 } from "path";
|
|
3166
3225
|
|
|
3167
3226
|
// packages/runtime/src/control-plane/runtime/runtime-paths.ts
|
|
3168
|
-
import { existsSync as
|
|
3169
|
-
import { resolve as
|
|
3227
|
+
import { existsSync as existsSync19, readdirSync as readdirSync4, realpathSync } from "fs";
|
|
3228
|
+
import { resolve as resolve20 } from "path";
|
|
3170
3229
|
|
|
3171
3230
|
// packages/runtime/src/control-plane/runtime/sandbox/utils.ts
|
|
3172
3231
|
function uniq(values) {
|
|
@@ -3184,7 +3243,7 @@ function resolveBunBinaryPath() {
|
|
|
3184
3243
|
}
|
|
3185
3244
|
const home = process.env.HOME?.trim();
|
|
3186
3245
|
const fallbackCandidates = [
|
|
3187
|
-
home ?
|
|
3246
|
+
home ? resolve20(home, ".bun/bin/bun") : "",
|
|
3188
3247
|
"/opt/homebrew/bin/bun",
|
|
3189
3248
|
"/usr/local/bin/bun",
|
|
3190
3249
|
"/usr/bin/bun"
|
|
@@ -3212,8 +3271,8 @@ function resolveClaudeBinaryPath() {
|
|
|
3212
3271
|
}
|
|
3213
3272
|
const home = process.env.HOME?.trim();
|
|
3214
3273
|
const fallbackCandidates = [
|
|
3215
|
-
home ?
|
|
3216
|
-
home ?
|
|
3274
|
+
home ? resolve20(home, ".local/bin/claude") : "",
|
|
3275
|
+
home ? resolve20(home, ".local/share/claude/local/claude") : "",
|
|
3217
3276
|
"/opt/homebrew/bin/claude",
|
|
3218
3277
|
"/usr/local/bin/claude",
|
|
3219
3278
|
"/usr/bin/claude"
|
|
@@ -3227,51 +3286,51 @@ function resolveClaudeBinaryPath() {
|
|
|
3227
3286
|
throw new Error("claude not found in PATH");
|
|
3228
3287
|
}
|
|
3229
3288
|
function resolveBunInstallDir(bunBinaryPath = resolveBunBinaryPath()) {
|
|
3230
|
-
return
|
|
3289
|
+
return resolve20(bunBinaryPath, "../..");
|
|
3231
3290
|
}
|
|
3232
3291
|
function resolveClaudeInstallDir() {
|
|
3233
3292
|
const realPath = resolveClaudeBinaryPath();
|
|
3234
|
-
return
|
|
3293
|
+
return resolve20(realPath, "..");
|
|
3235
3294
|
}
|
|
3236
3295
|
function resolveNodeInstallDir() {
|
|
3237
3296
|
const preferredNode = resolvePreferredNodeBinary();
|
|
3238
3297
|
if (!preferredNode)
|
|
3239
3298
|
return null;
|
|
3240
3299
|
const explicitNode = process.env.RIG_NODE_BIN?.trim();
|
|
3241
|
-
if (explicitNode &&
|
|
3242
|
-
return preferredNode.endsWith("/bin/node") ?
|
|
3300
|
+
if (explicitNode && resolve20(explicitNode) === resolve20(preferredNode)) {
|
|
3301
|
+
return preferredNode.endsWith("/bin/node") ? resolve20(preferredNode, "../..") : resolve20(preferredNode, "..");
|
|
3243
3302
|
}
|
|
3244
3303
|
try {
|
|
3245
3304
|
const realPath = realpathSync(preferredNode);
|
|
3246
3305
|
if (realPath.endsWith("/bin/node")) {
|
|
3247
|
-
return
|
|
3306
|
+
return resolve20(realPath, "../..");
|
|
3248
3307
|
}
|
|
3249
|
-
return
|
|
3308
|
+
return resolve20(realPath, "..");
|
|
3250
3309
|
} catch {
|
|
3251
|
-
return
|
|
3310
|
+
return resolve20(preferredNode, "..");
|
|
3252
3311
|
}
|
|
3253
3312
|
}
|
|
3254
3313
|
function resolvePreferredNodeBinary() {
|
|
3255
3314
|
const candidates = [];
|
|
3256
3315
|
const envNode = process.env.RIG_NODE_BIN?.trim();
|
|
3257
3316
|
if (envNode) {
|
|
3258
|
-
const explicit =
|
|
3259
|
-
if (
|
|
3317
|
+
const explicit = resolve20(envNode);
|
|
3318
|
+
if (existsSync19(explicit)) {
|
|
3260
3319
|
return explicit;
|
|
3261
3320
|
}
|
|
3262
3321
|
}
|
|
3263
3322
|
const nvmBin = process.env.NVM_BIN?.trim();
|
|
3264
3323
|
if (nvmBin) {
|
|
3265
|
-
candidates.push(
|
|
3324
|
+
candidates.push(resolve20(nvmBin, "node"));
|
|
3266
3325
|
}
|
|
3267
3326
|
const home = process.env.HOME?.trim();
|
|
3268
3327
|
if (home) {
|
|
3269
|
-
const nvmVersionsDir =
|
|
3270
|
-
if (
|
|
3328
|
+
const nvmVersionsDir = resolve20(home, ".nvm/versions/node");
|
|
3329
|
+
if (existsSync19(nvmVersionsDir)) {
|
|
3271
3330
|
try {
|
|
3272
3331
|
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/, "")));
|
|
3273
3332
|
for (const versionDir of versionDirs) {
|
|
3274
|
-
candidates.push(
|
|
3333
|
+
candidates.push(resolve20(nvmVersionsDir, versionDir, "bin/node"));
|
|
3275
3334
|
}
|
|
3276
3335
|
} catch {}
|
|
3277
3336
|
}
|
|
@@ -3280,8 +3339,8 @@ function resolvePreferredNodeBinary() {
|
|
|
3280
3339
|
if (whichNode) {
|
|
3281
3340
|
candidates.push(whichNode);
|
|
3282
3341
|
}
|
|
3283
|
-
const deduped = uniq(candidates.map((candidate) =>
|
|
3284
|
-
const existing = deduped.filter((candidate) =>
|
|
3342
|
+
const deduped = uniq(candidates.map((candidate) => resolve20(candidate)));
|
|
3343
|
+
const existing = deduped.filter((candidate) => existsSync19(candidate));
|
|
3285
3344
|
if (existing.length === 0) {
|
|
3286
3345
|
return null;
|
|
3287
3346
|
}
|
|
@@ -3295,7 +3354,7 @@ function resolvePreferredNodeBinary() {
|
|
|
3295
3354
|
return existing[0] ?? null;
|
|
3296
3355
|
}
|
|
3297
3356
|
function inferNodeMajor(nodeBinaryPath) {
|
|
3298
|
-
const normalized =
|
|
3357
|
+
const normalized = resolve20(nodeBinaryPath).replace(/\\/g, "/");
|
|
3299
3358
|
const match = normalized.match(/(?:^|\/)(?:node-)?v?(\d+)\.\d+\.\d+(?:\/|$)/);
|
|
3300
3359
|
if (!match) {
|
|
3301
3360
|
return null;
|
|
@@ -3307,8 +3366,8 @@ function normalizeExecutablePath(candidate) {
|
|
|
3307
3366
|
if (!candidate) {
|
|
3308
3367
|
return "";
|
|
3309
3368
|
}
|
|
3310
|
-
const normalized =
|
|
3311
|
-
if (!
|
|
3369
|
+
const normalized = resolve20(candidate);
|
|
3370
|
+
if (!existsSync19(normalized)) {
|
|
3312
3371
|
return "";
|
|
3313
3372
|
}
|
|
3314
3373
|
try {
|
|
@@ -3318,7 +3377,7 @@ function normalizeExecutablePath(candidate) {
|
|
|
3318
3377
|
}
|
|
3319
3378
|
}
|
|
3320
3379
|
function looksLikeRuntimeGateway(candidate) {
|
|
3321
|
-
const normalized =
|
|
3380
|
+
const normalized = resolve20(candidate).replace(/\\/g, "/");
|
|
3322
3381
|
return normalized.includes("/.rig/bin/") || normalized.endsWith("/rig-shell") || normalized.endsWith("/rig-agent");
|
|
3323
3382
|
}
|
|
3324
3383
|
|
|
@@ -3339,7 +3398,7 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
3339
3398
|
try {
|
|
3340
3399
|
return resolveClaudeInstallDir();
|
|
3341
3400
|
} catch {
|
|
3342
|
-
return
|
|
3401
|
+
return resolve21(claudeBinary, "..");
|
|
3343
3402
|
}
|
|
3344
3403
|
})() : "";
|
|
3345
3404
|
const nodeDir = resolveNodeInstallDir();
|
|
@@ -3349,8 +3408,8 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
3349
3408
|
`${bunDir}/bin`,
|
|
3350
3409
|
claudeDir,
|
|
3351
3410
|
nodeDir ? `${nodeDir}/bin` : "",
|
|
3352
|
-
realHome ?
|
|
3353
|
-
realHome ?
|
|
3411
|
+
realHome ? resolve21(realHome, ".local/bin") : "",
|
|
3412
|
+
realHome ? resolve21(realHome, ".cargo/bin") : "",
|
|
3354
3413
|
...inheritedPath,
|
|
3355
3414
|
"/usr/local/bin",
|
|
3356
3415
|
"/usr/local/sbin",
|
|
@@ -3381,9 +3440,9 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
3381
3440
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
3382
3441
|
function resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext) {
|
|
3383
3442
|
if (runtimeContext) {
|
|
3384
|
-
return
|
|
3443
|
+
return resolve22(runtimeContext.binDir, "validators", binaryName);
|
|
3385
3444
|
}
|
|
3386
|
-
return
|
|
3445
|
+
return resolve22(resolveHarnessPaths(projectRoot).binDir, "validators", binaryName);
|
|
3387
3446
|
}
|
|
3388
3447
|
async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
3389
3448
|
const match = checkId.match(/^([a-z][\w-]*):([a-z][\w-]*)$/);
|
|
@@ -3398,19 +3457,19 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
3398
3457
|
const binaryName = `${category}-${check}`;
|
|
3399
3458
|
const binaryPath = resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
3400
3459
|
const hostProjectRoot = runtimeContext?.hostProjectRoot?.trim() || projectRoot;
|
|
3401
|
-
const sourcePath =
|
|
3402
|
-
if (!
|
|
3460
|
+
const sourcePath = resolve22(hostProjectRoot, "packages/runtime/src/control-plane/validators", category, `${check}.ts`);
|
|
3461
|
+
if (!existsSync20(sourcePath)) {
|
|
3403
3462
|
return null;
|
|
3404
3463
|
}
|
|
3405
3464
|
const sourceMtime = statSync4(sourcePath).mtimeMs;
|
|
3406
|
-
const binaryExists =
|
|
3465
|
+
const binaryExists = existsSync20(binaryPath);
|
|
3407
3466
|
const binaryMtime = binaryExists ? statSync4(binaryPath).mtimeMs : 0;
|
|
3408
3467
|
if (!binaryExists || sourceMtime > binaryMtime) {
|
|
3409
3468
|
if (binaryExists) {
|
|
3410
3469
|
rmSync5(binaryPath, { force: true });
|
|
3411
3470
|
rmSync5(`${binaryPath}.build-manifest.json`, { force: true });
|
|
3412
3471
|
}
|
|
3413
|
-
|
|
3472
|
+
mkdirSync8(dirname11(binaryPath), { recursive: true });
|
|
3414
3473
|
await buildRuntimeBinary({
|
|
3415
3474
|
sourcePath: `packages/runtime/src/control-plane/validators/${category}/${check}.ts`,
|
|
3416
3475
|
outputPath: binaryPath,
|
|
@@ -3419,7 +3478,7 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
3419
3478
|
env: runtimeProvisioningEnv()
|
|
3420
3479
|
});
|
|
3421
3480
|
}
|
|
3422
|
-
return
|
|
3481
|
+
return existsSync20(binaryPath) ? binaryPath : null;
|
|
3423
3482
|
}
|
|
3424
3483
|
|
|
3425
3484
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
@@ -3456,20 +3515,20 @@ async function readTaskSourceValidation(projectRoot, taskId) {
|
|
|
3456
3515
|
function resolveValidationPaths(projectRoot, taskId, runtimeContext) {
|
|
3457
3516
|
if (runtimeContext) {
|
|
3458
3517
|
return {
|
|
3459
|
-
taskLogDir:
|
|
3460
|
-
artifactDir:
|
|
3518
|
+
taskLogDir: resolve23(runtimeContext.logsDir, taskId),
|
|
3519
|
+
artifactDir: resolve23(runtimeContext.workspaceDir, "artifacts", taskId)
|
|
3461
3520
|
};
|
|
3462
3521
|
}
|
|
3463
3522
|
const paths = resolveHarnessPaths(projectRoot);
|
|
3464
3523
|
return {
|
|
3465
|
-
taskLogDir:
|
|
3466
|
-
artifactDir:
|
|
3524
|
+
taskLogDir: resolve23(paths.logsDir, taskId),
|
|
3525
|
+
artifactDir: resolve23(paths.artifactsDir, taskId)
|
|
3467
3526
|
};
|
|
3468
3527
|
}
|
|
3469
3528
|
async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext) {
|
|
3470
3529
|
const binaryName = checkId.replace(":", "-");
|
|
3471
3530
|
const binaryPath = await ensureValidatorBinary(projectRoot, checkId, runtimeContext) ?? resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
3472
|
-
if (!
|
|
3531
|
+
if (!existsSync21(binaryPath)) {
|
|
3473
3532
|
return {
|
|
3474
3533
|
result: {
|
|
3475
3534
|
id: checkId,
|
|
@@ -3480,7 +3539,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
3480
3539
|
};
|
|
3481
3540
|
}
|
|
3482
3541
|
const validatorCwd = runtimeContext?.workspaceDir || resolveMonorepoRoot(projectRoot);
|
|
3483
|
-
const runtimeShellPath = runtimeContext ?
|
|
3542
|
+
const runtimeShellPath = runtimeContext ? resolve23(runtimeContext.binDir, "rig-shell") : "";
|
|
3484
3543
|
const monorepoMainRoot = runtimeContext?.monorepoMainRoot || process.env.MONOREPO_MAIN_ROOT?.trim() || resolveMonorepoRoot(projectRoot);
|
|
3485
3544
|
const validatorEnv = {
|
|
3486
3545
|
PROJECT_RIG_ROOT: runtimeContext?.hostProjectRoot || projectRoot,
|
|
@@ -3495,7 +3554,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
3495
3554
|
validatorEnv.RIG_LOGS_DIR = runtimeContext.logsDir;
|
|
3496
3555
|
validatorEnv.RIG_RUNTIME_BIN_DIR = runtimeContext.binDir;
|
|
3497
3556
|
}
|
|
3498
|
-
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath &&
|
|
3557
|
+
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath && existsSync21(runtimeShellPath) ? [runtimeShellPath, "run-binary", binaryPath] : [binaryPath], validatorCwd, validatorEnv);
|
|
3499
3558
|
try {
|
|
3500
3559
|
const result = JSON.parse(stdout.trim());
|
|
3501
3560
|
return { result, exitCode };
|
|
@@ -3535,8 +3594,8 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
3535
3594
|
const configuredValidation = stringArray(taskConfig[taskId]?.validation);
|
|
3536
3595
|
const commands = resolvedContext?.validation?.length ? resolvedContext.validation : configuredValidation.length > 0 ? configuredValidation : sourceValidation.validation;
|
|
3537
3596
|
const { taskLogDir, artifactDir } = resolveValidationPaths(projectRoot, taskId, resolvedContext);
|
|
3538
|
-
|
|
3539
|
-
|
|
3597
|
+
mkdirSync9(taskLogDir, { recursive: true });
|
|
3598
|
+
mkdirSync9(artifactDir, { recursive: true });
|
|
3540
3599
|
if (commands.length === 0) {
|
|
3541
3600
|
const skipped = {
|
|
3542
3601
|
status: "skipped",
|
|
@@ -3545,7 +3604,7 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
3545
3604
|
failed: 0,
|
|
3546
3605
|
categories: []
|
|
3547
3606
|
};
|
|
3548
|
-
|
|
3607
|
+
writeFileSync9(resolve23(artifactDir, "validation-summary.json"), `${JSON.stringify(skipped, null, 2)}
|
|
3549
3608
|
`, "utf-8");
|
|
3550
3609
|
return skipped;
|
|
3551
3610
|
}
|
|
@@ -3580,18 +3639,18 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
3580
3639
|
exit_code: 2,
|
|
3581
3640
|
duration_seconds: 0
|
|
3582
3641
|
});
|
|
3583
|
-
const logFile2 =
|
|
3584
|
-
|
|
3585
|
-
|
|
3642
|
+
const logFile2 = resolve23(taskLogDir, `invalid-entry-validation.log`);
|
|
3643
|
+
mkdirSync9(taskLogDir, { recursive: true });
|
|
3644
|
+
writeFileSync9(logFile2, `=== ${nowIso()} :: ${cmd} ===
|
|
3586
3645
|
Invalid validation entry: not a check-ID. All entries must use format "category:check-name".
|
|
3587
3646
|
`, "utf-8");
|
|
3588
3647
|
continue;
|
|
3589
3648
|
}
|
|
3590
3649
|
const { result, exitCode } = await dispatchValidator(cmd, effectiveRegistry, validatorCtx, (id) => runValidatorBinary(projectRoot, taskId, id, resolvedContext));
|
|
3591
3650
|
const durationSeconds = Math.max(0, Math.round((Date.now() - startedAt) / 1000));
|
|
3592
|
-
const logFile =
|
|
3593
|
-
|
|
3594
|
-
|
|
3651
|
+
const logFile = resolve23(taskLogDir, `${cmd.replace(":", "-")}-validation.log`);
|
|
3652
|
+
mkdirSync9(taskLogDir, { recursive: true });
|
|
3653
|
+
writeFileSync9(logFile, `=== ${nowIso()} :: ${cmd} ===
|
|
3595
3654
|
${JSON.stringify(result, null, 2)}
|
|
3596
3655
|
`, "utf-8");
|
|
3597
3656
|
if (result.passed) {
|
|
@@ -3613,15 +3672,15 @@ ${JSON.stringify(result, null, 2)}
|
|
|
3613
3672
|
failed,
|
|
3614
3673
|
categories
|
|
3615
3674
|
};
|
|
3616
|
-
|
|
3617
|
-
|
|
3675
|
+
mkdirSync9(artifactDir, { recursive: true });
|
|
3676
|
+
writeFileSync9(resolve23(artifactDir, "validation-summary.json"), `${JSON.stringify(summary, null, 2)}
|
|
3618
3677
|
`, "utf-8");
|
|
3619
3678
|
return summary;
|
|
3620
3679
|
}
|
|
3621
3680
|
|
|
3622
3681
|
// packages/runtime/src/control-plane/native/verifier.ts
|
|
3623
|
-
import { existsSync as
|
|
3624
|
-
import { resolve as
|
|
3682
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
|
|
3683
|
+
import { resolve as resolve24 } from "path";
|
|
3625
3684
|
|
|
3626
3685
|
// packages/runtime/src/control-plane/native/pr-review-gate.ts
|
|
3627
3686
|
function parseJsonObject(value) {
|
|
@@ -4872,11 +4931,11 @@ async function verifyTask(options) {
|
|
|
4872
4931
|
const taskId = options.taskId;
|
|
4873
4932
|
const normalizedTaskId = lookupTask(options.projectRoot, taskId);
|
|
4874
4933
|
const artifactDir = artifactDirForId(options.projectRoot, taskId);
|
|
4875
|
-
|
|
4876
|
-
const validationSummaryPath =
|
|
4877
|
-
const reviewFeedbackPath =
|
|
4878
|
-
const reviewStatePath =
|
|
4879
|
-
const greptileRawPath =
|
|
4934
|
+
mkdirSync10(artifactDir, { recursive: true });
|
|
4935
|
+
const validationSummaryPath = resolve24(artifactDir, "validation-summary.json");
|
|
4936
|
+
const reviewFeedbackPath = resolve24(artifactDir, "review-feedback.md");
|
|
4937
|
+
const reviewStatePath = resolve24(artifactDir, "review-state.json");
|
|
4938
|
+
const greptileRawPath = resolve24(artifactDir, "review-greptile-raw.json");
|
|
4880
4939
|
const prStates = readPrMetadata(options.projectRoot, taskId);
|
|
4881
4940
|
const prState = prStates[0] || null;
|
|
4882
4941
|
const localReasons = [];
|
|
@@ -4888,7 +4947,7 @@ async function verifyTask(options) {
|
|
|
4888
4947
|
if (!normalizedTaskId && !await hasConfiguredSourceTask(options.projectRoot, taskId)) {
|
|
4889
4948
|
localReasons.push(`[Task Config] Unknown task id '${taskId}' in task-config or configured task source.`);
|
|
4890
4949
|
}
|
|
4891
|
-
if (!
|
|
4950
|
+
if (!existsSync22(validationSummaryPath)) {
|
|
4892
4951
|
localReasons.push(`[Artifact Quality] validation-summary.json not found at ${validationSummaryPath}.`);
|
|
4893
4952
|
} else {
|
|
4894
4953
|
const summary = await parseValidationSummary(validationSummaryPath);
|
|
@@ -4897,13 +4956,13 @@ async function verifyTask(options) {
|
|
|
4897
4956
|
}
|
|
4898
4957
|
}
|
|
4899
4958
|
for (const file of ["task-result.json", "decision-log.md", "next-actions.md", "changed-files.txt"]) {
|
|
4900
|
-
const requiredPath =
|
|
4901
|
-
if (!
|
|
4959
|
+
const requiredPath = resolve24(artifactDir, file);
|
|
4960
|
+
if (!existsSync22(requiredPath)) {
|
|
4902
4961
|
localReasons.push(`[Artifact Quality] Missing required artifact file: ${requiredPath}`);
|
|
4903
4962
|
}
|
|
4904
4963
|
}
|
|
4905
|
-
const taskResultPath =
|
|
4906
|
-
if (
|
|
4964
|
+
const taskResultPath = resolve24(artifactDir, "task-result.json");
|
|
4965
|
+
if (existsSync22(taskResultPath)) {
|
|
4907
4966
|
const taskResult = await readJsonFile2(taskResultPath);
|
|
4908
4967
|
const artifactStatus = typeof taskResult?.status === "string" ? taskResult.status.trim().toLowerCase() : "";
|
|
4909
4968
|
if (artifactStatus === "partial") {
|
|
@@ -4916,8 +4975,8 @@ async function verifyTask(options) {
|
|
|
4916
4975
|
localReasons.push("[Artifact Quality] task-result.json next actions indicate remaining implementation scope.");
|
|
4917
4976
|
}
|
|
4918
4977
|
}
|
|
4919
|
-
const nextActionsPath =
|
|
4920
|
-
if (
|
|
4978
|
+
const nextActionsPath = resolve24(artifactDir, "next-actions.md");
|
|
4979
|
+
if (existsSync22(nextActionsPath)) {
|
|
4921
4980
|
const nextActionsContent = await Bun.file(nextActionsPath).text();
|
|
4922
4981
|
if (nextActionsContent.includes("TODO: Replace this scaffold") || nextActionsContent.includes("bd-<downstream-task-id>")) {
|
|
4923
4982
|
localReasons.push("[Artifact Quality] next-actions.md still contains scaffold placeholder text. Replace with real recommendations.");
|
|
@@ -4948,7 +5007,7 @@ async function verifyTask(options) {
|
|
|
4948
5007
|
aiReasons.push(`[AI Review] Required mode needs a completed Greptile approval; current verdict is ${ai.verdict}.`);
|
|
4949
5008
|
}
|
|
4950
5009
|
if (persistArtifacts && ai.rawResponse) {
|
|
4951
|
-
|
|
5010
|
+
writeFileSync10(greptileRawPath, `${ai.rawResponse}
|
|
4952
5011
|
`, "utf-8");
|
|
4953
5012
|
}
|
|
4954
5013
|
} else if (!options.skipAiReview && reviewMode === "off") {
|
|
@@ -5191,7 +5250,7 @@ function evaluateSourceCloseoutChecks(prState, prLabel) {
|
|
|
5191
5250
|
if (!Array.isArray(checks) || checks.length === 0) {
|
|
5192
5251
|
return [`[Source Issue] PR ${prLabel} must have green check evidence before completion.`];
|
|
5193
5252
|
}
|
|
5194
|
-
const ciGate = evaluatePullRequestCiChecks(checks, "PR", 0);
|
|
5253
|
+
const ciGate = evaluatePullRequestCiChecks(checks, "PR", 0, { mergeStateStatus: prState.mergeStateStatus });
|
|
5195
5254
|
if (ciGate.verdict === "APPROVE") {
|
|
5196
5255
|
return [];
|
|
5197
5256
|
}
|
|
@@ -5287,7 +5346,7 @@ function isAcceptedValidationSummary(summary) {
|
|
|
5287
5346
|
return summary.status === "skipped" && summary.total === 0 && summary.failed === 0;
|
|
5288
5347
|
}
|
|
5289
5348
|
async function loadReviewMode(reviewProfilePath, fallback) {
|
|
5290
|
-
const parsed =
|
|
5349
|
+
const parsed = existsSync22(reviewProfilePath) ? await readJsonFile2(reviewProfilePath) : null;
|
|
5291
5350
|
const mode = parsed?.mode;
|
|
5292
5351
|
if (mode === "off" || mode === "advisory" || mode === "required") {
|
|
5293
5352
|
return mode;
|
|
@@ -5298,7 +5357,7 @@ async function loadReviewMode(reviewProfilePath, fallback) {
|
|
|
5298
5357
|
return "advisory";
|
|
5299
5358
|
}
|
|
5300
5359
|
async function loadReviewProvider(reviewProfilePath, fallback) {
|
|
5301
|
-
const parsed =
|
|
5360
|
+
const parsed = existsSync22(reviewProfilePath) ? await readJsonFile2(reviewProfilePath) : null;
|
|
5302
5361
|
const provider = parsed?.provider;
|
|
5303
5362
|
if (typeof provider === "string" && provider.trim().length > 0) {
|
|
5304
5363
|
return provider;
|
|
@@ -5457,7 +5516,7 @@ function writeFeedbackFile(options) {
|
|
|
5457
5516
|
if (options.aiRawFeedback) {
|
|
5458
5517
|
lines.push("## Raw Reviewer Feedback", "", "```text", options.aiRawFeedback, "```", "");
|
|
5459
5518
|
}
|
|
5460
|
-
|
|
5519
|
+
writeFileSync10(options.output, `${lines.join(`
|
|
5461
5520
|
`)}
|
|
5462
5521
|
`, "utf-8");
|
|
5463
5522
|
}
|
|
@@ -5474,7 +5533,7 @@ function writeReviewStateFile(options) {
|
|
|
5474
5533
|
ai_warnings: options.aiWarnings,
|
|
5475
5534
|
updated_at: nowIso()
|
|
5476
5535
|
};
|
|
5477
|
-
|
|
5536
|
+
writeFileSync10(options.output, `${JSON.stringify(payload, null, 2)}
|
|
5478
5537
|
`, "utf-8");
|
|
5479
5538
|
}
|
|
5480
5539
|
async function runGreptileReviewForPr(options) {
|
|
@@ -5555,7 +5614,7 @@ async function runGreptileReviewForPr(options) {
|
|
|
5555
5614
|
}
|
|
5556
5615
|
await Bun.sleep(options.pollIntervalMs);
|
|
5557
5616
|
}
|
|
5558
|
-
const ciGate = evaluatePullRequestCiChecks(githubCheckRollup, repoName, prNumber);
|
|
5617
|
+
const ciGate = evaluatePullRequestCiChecks(githubCheckRollup, repoName, prNumber, { mergeStateStatus: options.prState.mergeStateStatus });
|
|
5559
5618
|
if (ciGate.verdict !== "APPROVE") {
|
|
5560
5619
|
return {
|
|
5561
5620
|
verdict: ciGate.verdict,
|
|
@@ -5813,7 +5872,7 @@ async function runGithubGreptileFallbackReviewForPr(options) {
|
|
|
5813
5872
|
}
|
|
5814
5873
|
await Bun.sleep(options.pollIntervalMs);
|
|
5815
5874
|
}
|
|
5816
|
-
const ciGate = evaluatePullRequestCiChecks(checkRollup, repoName, prNumber);
|
|
5875
|
+
const ciGate = evaluatePullRequestCiChecks(checkRollup, repoName, prNumber, { mergeStateStatus: options.prState.mergeStateStatus });
|
|
5817
5876
|
if (ciGate.verdict !== "APPROVE") {
|
|
5818
5877
|
return {
|
|
5819
5878
|
verdict: ciGate.verdict,
|
|
@@ -6168,7 +6227,7 @@ function loadGithubPullRequestCheckRollup(projectRoot, repoName, prNumber) {
|
|
|
6168
6227
|
]);
|
|
6169
6228
|
return response.statusCheckRollup || [];
|
|
6170
6229
|
}
|
|
6171
|
-
function evaluatePullRequestCiChecks(checks, repoName, prNumber) {
|
|
6230
|
+
function evaluatePullRequestCiChecks(checks, repoName, prNumber, options = {}) {
|
|
6172
6231
|
const nonGreptileChecks = checks.filter((check) => {
|
|
6173
6232
|
const label = (check.name || check.context || "").toLowerCase();
|
|
6174
6233
|
return label.length > 0 && !label.includes("greptile");
|
|
@@ -6180,7 +6239,8 @@ function evaluatePullRequestCiChecks(checks, repoName, prNumber) {
|
|
|
6180
6239
|
const state = (check.state || check.status || "").toUpperCase();
|
|
6181
6240
|
return state === "PENDING" || state === "EXPECTED" || state === "QUEUED" || state === "IN_PROGRESS";
|
|
6182
6241
|
});
|
|
6183
|
-
|
|
6242
|
+
const mergeClean = (options.mergeStateStatus || "").toUpperCase() === "CLEAN";
|
|
6243
|
+
if (pending.length > 0 && !mergeClean) {
|
|
6184
6244
|
return {
|
|
6185
6245
|
verdict: "SKIP",
|
|
6186
6246
|
reasons: pending.map((check) => `[CI] ${repoName}#${prNumber} check is still pending: ${check.name || check.context || "unknown"}.`)
|
|
@@ -6261,7 +6321,7 @@ function filterActionableGithubGreptileThreads(threads) {
|
|
|
6261
6321
|
}
|
|
6262
6322
|
function resolvePrRepoRoot(projectRoot, prState) {
|
|
6263
6323
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
6264
|
-
if (prState.target === "monorepo" && runtimeWorkspace &&
|
|
6324
|
+
if (prState.target === "monorepo" && runtimeWorkspace && existsSync22(resolve24(runtimeWorkspace, ".git"))) {
|
|
6265
6325
|
return runtimeWorkspace;
|
|
6266
6326
|
}
|
|
6267
6327
|
const paths = resolveHarnessPaths(projectRoot);
|
|
@@ -6633,16 +6693,16 @@ async function taskDeps(projectRoot, taskId) {
|
|
|
6633
6693
|
for (const dep of deps) {
|
|
6634
6694
|
const artifactDir = artifactDirForId(projectRoot, dep);
|
|
6635
6695
|
console.log(`=== ${dep} ===`);
|
|
6636
|
-
if (!
|
|
6696
|
+
if (!existsSync23(artifactDir)) {
|
|
6637
6697
|
console.log(` (no artifacts yet)
|
|
6638
6698
|
`);
|
|
6639
6699
|
continue;
|
|
6640
6700
|
}
|
|
6641
|
-
printArtifactSection(
|
|
6642
|
-
printArtifactSection(
|
|
6643
|
-
const changedFiles =
|
|
6644
|
-
if (
|
|
6645
|
-
const lines =
|
|
6701
|
+
printArtifactSection(resolve25(artifactDir, "decision-log.md"), "--- Decisions ---");
|
|
6702
|
+
printArtifactSection(resolve25(artifactDir, "next-actions.md"), "--- Next Actions (for you) ---");
|
|
6703
|
+
const changedFiles = resolve25(artifactDir, "changed-files.txt");
|
|
6704
|
+
if (existsSync23(changedFiles)) {
|
|
6705
|
+
const lines = readFileSync12(changedFiles, "utf-8").split(/\r?\n/).filter(Boolean);
|
|
6646
6706
|
console.log(`--- Changed Files (${lines.length}) ---`);
|
|
6647
6707
|
for (const line of lines) {
|
|
6648
6708
|
console.log(line);
|
|
@@ -6687,12 +6747,12 @@ function taskRecord(projectRoot, type, text, taskId) {
|
|
|
6687
6747
|
throw new Error("No active task.");
|
|
6688
6748
|
}
|
|
6689
6749
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6690
|
-
|
|
6750
|
+
mkdirSync11(paths.stateDir, { recursive: true });
|
|
6691
6751
|
if (type === "decision") {
|
|
6692
|
-
const artifactDir =
|
|
6693
|
-
|
|
6752
|
+
const artifactDir = resolve25(paths.artifactsDir, activeTask);
|
|
6753
|
+
mkdirSync11(artifactDir, { recursive: true });
|
|
6694
6754
|
const timestamp = nowIso();
|
|
6695
|
-
appendFileSync(
|
|
6755
|
+
appendFileSync(resolve25(artifactDir, "decision-log.md"), `
|
|
6696
6756
|
### ${timestamp}
|
|
6697
6757
|
|
|
6698
6758
|
${text}
|
|
@@ -6702,14 +6762,14 @@ ${text}
|
|
|
6702
6762
|
return;
|
|
6703
6763
|
}
|
|
6704
6764
|
const failedPath = paths.failedApproachesPath;
|
|
6705
|
-
if (!
|
|
6706
|
-
|
|
6765
|
+
if (!existsSync23(failedPath)) {
|
|
6766
|
+
writeFileSync11(failedPath, `# Failed Approaches Log
|
|
6707
6767
|
|
|
6708
6768
|
This file records approaches that did not work.
|
|
6709
6769
|
|
|
6710
6770
|
`, "utf-8");
|
|
6711
6771
|
}
|
|
6712
|
-
const content =
|
|
6772
|
+
const content = readFileSync12(failedPath, "utf-8");
|
|
6713
6773
|
const attempts = (content.match(new RegExp(`^## ${escapeRegExp(activeTask)}\\b`, "gm")) || []).length + 1;
|
|
6714
6774
|
appendFileSync(failedPath, `
|
|
6715
6775
|
## ${activeTask} - Attempt ${attempts} (${nowIso()})
|
|
@@ -6726,40 +6786,40 @@ function taskArtifacts(projectRoot, taskId) {
|
|
|
6726
6786
|
throw new Error("No active task.");
|
|
6727
6787
|
}
|
|
6728
6788
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6729
|
-
const artifactDir =
|
|
6730
|
-
|
|
6789
|
+
const artifactDir = resolve25(paths.artifactsDir, activeTask);
|
|
6790
|
+
mkdirSync11(artifactDir, { recursive: true });
|
|
6731
6791
|
const changed = changedFilesForTask(projectRoot, activeTask, true);
|
|
6732
|
-
|
|
6792
|
+
writeFileSync11(resolve25(artifactDir, "changed-files.txt"), `${changed.join(`
|
|
6733
6793
|
`)}
|
|
6734
6794
|
`, "utf-8");
|
|
6735
6795
|
console.log(`changed-files.txt: ${changed.length} files`);
|
|
6736
|
-
const taskResultPath =
|
|
6737
|
-
if (!
|
|
6796
|
+
const taskResultPath = resolve25(artifactDir, "task-result.json");
|
|
6797
|
+
if (!existsSync23(taskResultPath)) {
|
|
6738
6798
|
const template = {
|
|
6739
6799
|
task_id: activeTask,
|
|
6740
6800
|
status: "completed",
|
|
6741
6801
|
summary: "TODO: Write a one-line summary of what you did",
|
|
6742
6802
|
completed_at: nowIso()
|
|
6743
6803
|
};
|
|
6744
|
-
|
|
6804
|
+
writeFileSync11(taskResultPath, `${JSON.stringify(template, null, 2)}
|
|
6745
6805
|
`, "utf-8");
|
|
6746
6806
|
console.log("task-result.json: created (update the summary!)");
|
|
6747
6807
|
} else {
|
|
6748
6808
|
console.log("task-result.json: already exists");
|
|
6749
6809
|
}
|
|
6750
|
-
const decisionLogPath =
|
|
6751
|
-
if (!
|
|
6810
|
+
const decisionLogPath = resolve25(artifactDir, "decision-log.md");
|
|
6811
|
+
if (!existsSync23(decisionLogPath)) {
|
|
6752
6812
|
const content = `# Decision Log: ${activeTask}
|
|
6753
6813
|
|
|
6754
6814
|
Record key decisions here using: rig-agent record decision "..."
|
|
6755
6815
|
`;
|
|
6756
|
-
|
|
6816
|
+
writeFileSync11(decisionLogPath, content, "utf-8");
|
|
6757
6817
|
console.log("decision-log.md: created (record your decisions!)");
|
|
6758
6818
|
} else {
|
|
6759
6819
|
console.log("decision-log.md: already exists");
|
|
6760
6820
|
}
|
|
6761
|
-
const nextActionsPath =
|
|
6762
|
-
if (!
|
|
6821
|
+
const nextActionsPath = resolve25(artifactDir, "next-actions.md");
|
|
6822
|
+
if (!existsSync23(nextActionsPath)) {
|
|
6763
6823
|
const content = [
|
|
6764
6824
|
`# Next Actions: ${activeTask}`,
|
|
6765
6825
|
"",
|
|
@@ -6776,13 +6836,13 @@ Record key decisions here using: rig-agent record decision "..."
|
|
|
6776
6836
|
""
|
|
6777
6837
|
].join(`
|
|
6778
6838
|
`);
|
|
6779
|
-
|
|
6839
|
+
writeFileSync11(nextActionsPath, content, "utf-8");
|
|
6780
6840
|
console.log("next-actions.md: created (add recommendations for downstream tasks!)");
|
|
6781
6841
|
} else {
|
|
6782
6842
|
console.log("next-actions.md: already exists");
|
|
6783
6843
|
}
|
|
6784
|
-
const validationSummaryPath =
|
|
6785
|
-
if (
|
|
6844
|
+
const validationSummaryPath = resolve25(artifactDir, "validation-summary.json");
|
|
6845
|
+
if (existsSync23(validationSummaryPath)) {
|
|
6786
6846
|
console.log("validation-summary.json: already exists");
|
|
6787
6847
|
} else {
|
|
6788
6848
|
console.log("validation-summary.json: not yet created (run: rig-agent validate)");
|
|
@@ -6873,7 +6933,7 @@ function collectTaskChangedFiles(projectRoot, taskId, includeCommitted) {
|
|
|
6873
6933
|
[projectRoot, ""],
|
|
6874
6934
|
[monorepoRepoRoot, ""]
|
|
6875
6935
|
]) {
|
|
6876
|
-
if (!
|
|
6936
|
+
if (!existsSync23(resolve25(repo, ".git"))) {
|
|
6877
6937
|
continue;
|
|
6878
6938
|
}
|
|
6879
6939
|
if (includeCommitted && repo === monorepoRepoRoot) {
|
|
@@ -6898,12 +6958,22 @@ function filterTaskChangedFiles(projectRoot, taskId, files, scoped) {
|
|
|
6898
6958
|
}
|
|
6899
6959
|
function resolveTaskMonorepoRoot(projectRoot) {
|
|
6900
6960
|
const runtimeWorkspace = loadRuntimeContextFromEnv()?.workspaceDir || process.env.RIG_TASK_WORKSPACE?.trim();
|
|
6901
|
-
if (runtimeWorkspace &&
|
|
6902
|
-
return
|
|
6961
|
+
if (runtimeWorkspace && existsSync23(resolve25(runtimeWorkspace, ".git"))) {
|
|
6962
|
+
return resolve25(runtimeWorkspace);
|
|
6903
6963
|
}
|
|
6904
6964
|
return resolveHarnessPaths(projectRoot).monorepoRoot;
|
|
6905
6965
|
}
|
|
6906
6966
|
function collectCommittedMonorepoFiles(projectRoot, repo) {
|
|
6967
|
+
const defaultRef = runCapture(["git", "-C", repo, "rev-parse", "--abbrev-ref", "origin/HEAD"], projectRoot);
|
|
6968
|
+
if (defaultRef.exitCode === 0 && defaultRef.stdout.trim()) {
|
|
6969
|
+
const mergeBase = runCapture(["git", "-C", repo, "merge-base", "HEAD", defaultRef.stdout.trim()], projectRoot);
|
|
6970
|
+
if (mergeBase.exitCode === 0 && mergeBase.stdout.trim()) {
|
|
6971
|
+
const result = runCapture(["git", "-C", repo, "diff", "--name-only", `${mergeBase.stdout.trim()}..HEAD`], projectRoot);
|
|
6972
|
+
if (result.exitCode === 0) {
|
|
6973
|
+
return result.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
6974
|
+
}
|
|
6975
|
+
}
|
|
6976
|
+
}
|
|
6907
6977
|
const initialHeadCommit = resolveRuntimeInitialHeadCommit(projectRoot, repo);
|
|
6908
6978
|
if (initialHeadCommit) {
|
|
6909
6979
|
const result = runCapture(["git", "-C", repo, "diff", "--name-only", `${initialHeadCommit}..HEAD`], projectRoot);
|
|
@@ -6927,7 +6997,7 @@ function resolveRuntimeInitialHeadCommit(projectRoot, repo) {
|
|
|
6927
6997
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
6928
6998
|
if (runtimeContext?.initialHeadCommits?.monorepo?.trim()) {
|
|
6929
6999
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6930
|
-
if (
|
|
7000
|
+
if (resolve25(monorepoRoot) === resolve25(repo)) {
|
|
6931
7001
|
return runtimeContext.initialHeadCommits.monorepo.trim();
|
|
6932
7002
|
}
|
|
6933
7003
|
}
|
|
@@ -6937,7 +7007,7 @@ function resolveMonorepoBaseCommit(projectRoot, repo) {
|
|
|
6937
7007
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
6938
7008
|
if (runtimeContext?.monorepoBaseCommit?.trim()) {
|
|
6939
7009
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6940
|
-
if (
|
|
7010
|
+
if (resolve25(monorepoRoot) === resolve25(repo)) {
|
|
6941
7011
|
return runtimeContext.monorepoBaseCommit.trim();
|
|
6942
7012
|
}
|
|
6943
7013
|
}
|
|
@@ -6982,7 +7052,7 @@ function resolveRuntimeDirtyBaseline(projectRoot, repo) {
|
|
|
6982
7052
|
return new Set;
|
|
6983
7053
|
}
|
|
6984
7054
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6985
|
-
const selected =
|
|
7055
|
+
const selected = resolve25(repo) === resolve25(monorepoRoot) ? dirtyFiles.monorepo : resolve25(repo) === resolve25(projectRoot) ? dirtyFiles.project : undefined;
|
|
6986
7056
|
return new Set((selected || []).map((file) => normalizeChangedFilePath(file)).filter(Boolean));
|
|
6987
7057
|
}
|
|
6988
7058
|
function normalizeChangedFilePath(file) {
|
|
@@ -7082,12 +7152,12 @@ function printIndented(text) {
|
|
|
7082
7152
|
}
|
|
7083
7153
|
}
|
|
7084
7154
|
function readLocalBeadsTasks(projectRoot) {
|
|
7085
|
-
const issuesPath =
|
|
7086
|
-
if (!
|
|
7155
|
+
const issuesPath = resolve25(resolveMonorepoRoot2(projectRoot), ".beads/issues.jsonl");
|
|
7156
|
+
if (!existsSync23(issuesPath)) {
|
|
7087
7157
|
return [];
|
|
7088
7158
|
}
|
|
7089
7159
|
const tasks = [];
|
|
7090
|
-
for (const line of
|
|
7160
|
+
for (const line of readFileSync12(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
7091
7161
|
const trimmed = line.trim();
|
|
7092
7162
|
if (!trimmed) {
|
|
7093
7163
|
continue;
|
|
@@ -7200,11 +7270,11 @@ function taskDependencies(projectRoot, taskId, tracker) {
|
|
|
7200
7270
|
return [...ids].sort();
|
|
7201
7271
|
}
|
|
7202
7272
|
function printArtifactSection(path, header) {
|
|
7203
|
-
if (!
|
|
7273
|
+
if (!existsSync23(path)) {
|
|
7204
7274
|
return;
|
|
7205
7275
|
}
|
|
7206
7276
|
console.log(header);
|
|
7207
|
-
process.stdout.write(
|
|
7277
|
+
process.stdout.write(readFileSync12(path, "utf-8"));
|
|
7208
7278
|
console.log("");
|
|
7209
7279
|
}
|
|
7210
7280
|
function escapeRegExp(value) {
|
|
@@ -7244,8 +7314,8 @@ function isRuntimeGatewayGhPath(candidate) {
|
|
|
7244
7314
|
}
|
|
7245
7315
|
function resolveOptionalMonorepoRoot(projectRoot) {
|
|
7246
7316
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
7247
|
-
if (runtimeWorkspace &&
|
|
7248
|
-
return
|
|
7317
|
+
if (runtimeWorkspace && existsSync24(resolve26(runtimeWorkspace, ".git"))) {
|
|
7318
|
+
return resolve26(runtimeWorkspace);
|
|
7249
7319
|
}
|
|
7250
7320
|
try {
|
|
7251
7321
|
return resolveMonorepoRoot2(projectRoot);
|
|
@@ -7270,7 +7340,7 @@ function resolveGitBinary(projectRoot) {
|
|
|
7270
7340
|
if (!candidate || isRuntimeGatewayGitPath(candidate)) {
|
|
7271
7341
|
continue;
|
|
7272
7342
|
}
|
|
7273
|
-
if (
|
|
7343
|
+
if (existsSync24(candidate)) {
|
|
7274
7344
|
return candidate;
|
|
7275
7345
|
}
|
|
7276
7346
|
}
|
|
@@ -7330,11 +7400,11 @@ function gitPreflight(projectRoot, taskId, strict) {
|
|
|
7330
7400
|
const expected = resolvedTask ? `rig/${resolveTaskBranchId(projectRoot, resolvedTask)}` : "";
|
|
7331
7401
|
console.log("=== Git Flow Preflight ===");
|
|
7332
7402
|
let issues = 0;
|
|
7333
|
-
if (!
|
|
7403
|
+
if (!existsSync24(resolve26(projectRoot, ".git"))) {
|
|
7334
7404
|
console.log(`ERROR: project root is not a git repo (${projectRoot})`);
|
|
7335
7405
|
issues += 1;
|
|
7336
7406
|
}
|
|
7337
|
-
if (monorepoRoot &&
|
|
7407
|
+
if (monorepoRoot && existsSync24(resolve26(monorepoRoot, ".git"))) {
|
|
7338
7408
|
const monoBranch = branchName(projectRoot, monorepoRoot);
|
|
7339
7409
|
if (expected && monoBranch !== expected) {
|
|
7340
7410
|
console.log(`WARN: monorepo branch is ${monoBranch}, expected ${expected} for task ${resolvedTask}`);
|
|
@@ -7368,7 +7438,7 @@ function gitSyncBranch(projectRoot, taskId, targetRepo = "monorepo") {
|
|
|
7368
7438
|
}
|
|
7369
7439
|
const repoRoot = targetRepo === "monorepo" ? resolveOptionalMonorepoRoot(projectRoot) || resolveMonorepoRoot2(projectRoot) : projectRoot;
|
|
7370
7440
|
const repoLabel = targetRepo === "monorepo" ? "Monorepo" : "Project";
|
|
7371
|
-
if (!
|
|
7441
|
+
if (!existsSync24(resolve26(repoRoot, ".git"))) {
|
|
7372
7442
|
throw new Error(`${repoLabel} repo not found at ${repoRoot}`);
|
|
7373
7443
|
}
|
|
7374
7444
|
const branchId = resolveTaskBranchId(projectRoot, resolvedTask);
|
|
@@ -7412,8 +7482,8 @@ function gitCommit(options) {
|
|
|
7412
7482
|
function gitSnapshot(projectRoot, taskId, outputPath) {
|
|
7413
7483
|
const monorepoRoot = resolveOptionalMonorepoRoot(projectRoot);
|
|
7414
7484
|
const resolvedTask = taskId || safeCurrentTaskId(projectRoot);
|
|
7415
|
-
const output = outputPath || (resolvedTask ? resolveArtifactSnapshot(projectRoot, resolvedTask) :
|
|
7416
|
-
|
|
7485
|
+
const output = outputPath || (resolvedTask ? resolveArtifactSnapshot(projectRoot, resolvedTask) : resolve26(resolve26(projectRoot, ".rig", "state"), "git-state.txt"));
|
|
7486
|
+
mkdirSync12(dirname12(output), { recursive: true });
|
|
7417
7487
|
const lines = ["# Git Snapshot", `timestamp: ${nowIso()}`];
|
|
7418
7488
|
if (resolvedTask) {
|
|
7419
7489
|
lines.push(`task: ${resolvedTask}`);
|
|
@@ -7423,7 +7493,7 @@ function gitSnapshot(projectRoot, taskId, outputPath) {
|
|
|
7423
7493
|
if (monorepoRoot && monorepoRoot !== projectRoot) {
|
|
7424
7494
|
lines.push(...snapshotRepo(projectRoot, "monorepo", monorepoRoot));
|
|
7425
7495
|
}
|
|
7426
|
-
|
|
7496
|
+
writeFileSync12(output, `${lines.join(`
|
|
7427
7497
|
`)}
|
|
7428
7498
|
`, "utf-8");
|
|
7429
7499
|
return output;
|
|
@@ -7447,7 +7517,7 @@ function gitOpenPr(options) {
|
|
|
7447
7517
|
} else if (taskId) {
|
|
7448
7518
|
gitSyncBranch(options.projectRoot, taskId, "project");
|
|
7449
7519
|
}
|
|
7450
|
-
if (!
|
|
7520
|
+
if (!existsSync24(resolve26(repoRoot, ".git"))) {
|
|
7451
7521
|
throw new Error(`Repository not available for open-pr target ${target}: ${repoRoot}`);
|
|
7452
7522
|
}
|
|
7453
7523
|
const branch = branchName(options.projectRoot, repoRoot);
|
|
@@ -7660,12 +7730,12 @@ function assertPrHasNoGitConflicts(prState, repoLabel, baseRef) {
|
|
|
7660
7730
|
}
|
|
7661
7731
|
function writePrMetadata(projectRoot, taskId, result) {
|
|
7662
7732
|
const dir = artifactDirForId(projectRoot, taskId);
|
|
7663
|
-
|
|
7664
|
-
const path =
|
|
7733
|
+
mkdirSync12(dir, { recursive: true });
|
|
7734
|
+
const path = resolve26(dir, "pr-state.json");
|
|
7665
7735
|
let prs = {};
|
|
7666
|
-
if (
|
|
7736
|
+
if (existsSync24(path)) {
|
|
7667
7737
|
try {
|
|
7668
|
-
const parsed = JSON.parse(
|
|
7738
|
+
const parsed = JSON.parse(readFileSync13(path, "utf-8"));
|
|
7669
7739
|
if (parsed && typeof parsed === "object" && parsed.prs && typeof parsed.prs === "object") {
|
|
7670
7740
|
prs = parsed.prs;
|
|
7671
7741
|
}
|
|
@@ -7681,16 +7751,16 @@ function writePrMetadata(projectRoot, taskId, result) {
|
|
|
7681
7751
|
...primary || {},
|
|
7682
7752
|
updated_at: nowIso()
|
|
7683
7753
|
};
|
|
7684
|
-
|
|
7754
|
+
writeFileSync12(path, `${JSON.stringify(artifact, null, 2)}
|
|
7685
7755
|
`, "utf-8");
|
|
7686
7756
|
}
|
|
7687
7757
|
function readPrMetadata(projectRoot, taskId) {
|
|
7688
|
-
const path =
|
|
7689
|
-
if (!
|
|
7758
|
+
const path = resolve26(artifactDirForId(projectRoot, taskId), "pr-state.json");
|
|
7759
|
+
if (!existsSync24(path)) {
|
|
7690
7760
|
return [];
|
|
7691
7761
|
}
|
|
7692
7762
|
try {
|
|
7693
|
-
const parsed = JSON.parse(
|
|
7763
|
+
const parsed = JSON.parse(readFileSync13(path, "utf-8"));
|
|
7694
7764
|
if (!parsed || typeof parsed !== "object") {
|
|
7695
7765
|
return [];
|
|
7696
7766
|
}
|
|
@@ -7703,8 +7773,8 @@ function readPrMetadata(projectRoot, taskId) {
|
|
|
7703
7773
|
}
|
|
7704
7774
|
}
|
|
7705
7775
|
function resolveArtifactSnapshot(projectRoot, taskId) {
|
|
7706
|
-
const artifactDir =
|
|
7707
|
-
return
|
|
7776
|
+
const artifactDir = resolve26(resolveHarnessPaths(projectRoot).artifactsDir, taskId);
|
|
7777
|
+
return resolve26(artifactDir, "git-state.txt");
|
|
7708
7778
|
}
|
|
7709
7779
|
function isGitOpenPrResult(value) {
|
|
7710
7780
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -7763,14 +7833,14 @@ function resolveGithubCliBinary(projectRoot) {
|
|
|
7763
7833
|
}
|
|
7764
7834
|
const explicitPathEntries = (process.env.PATH || "").split(":").map((entry) => entry.trim()).filter(Boolean);
|
|
7765
7835
|
for (const entry of explicitPathEntries) {
|
|
7766
|
-
candidates.add(
|
|
7836
|
+
candidates.add(resolve26(entry, "gh"));
|
|
7767
7837
|
}
|
|
7768
7838
|
const bunResolved = Bun.which("gh");
|
|
7769
7839
|
if (bunResolved) {
|
|
7770
7840
|
candidates.add(bunResolved);
|
|
7771
7841
|
}
|
|
7772
7842
|
for (const candidate of candidates) {
|
|
7773
|
-
if (candidate &&
|
|
7843
|
+
if (candidate && existsSync24(candidate) && !isRuntimeGatewayGhPath(candidate)) {
|
|
7774
7844
|
return candidate;
|
|
7775
7845
|
}
|
|
7776
7846
|
}
|
|
@@ -7800,7 +7870,7 @@ function resolveRepoNameWithOwner(projectRoot, repoRoot) {
|
|
|
7800
7870
|
return resolveGithubRepoNameWithOwnerFromGitRoot(projectRoot, repoRoot, repoRoot, visited);
|
|
7801
7871
|
}
|
|
7802
7872
|
function resolveGithubRepoNameWithOwnerFromGitRoot(projectRoot, gitRoot, cwd, visited) {
|
|
7803
|
-
const normalizedGitRoot =
|
|
7873
|
+
const normalizedGitRoot = resolve26(gitRoot);
|
|
7804
7874
|
if (visited.has(normalizedGitRoot)) {
|
|
7805
7875
|
return "";
|
|
7806
7876
|
}
|
|
@@ -7872,7 +7942,7 @@ function resolveNetworkRemoteName(projectRoot, repoRoot, repoNameWithOwner) {
|
|
|
7872
7942
|
return remotes.includes("origin") ? "origin" : remotes[0];
|
|
7873
7943
|
}
|
|
7874
7944
|
function gitQuery(projectRoot, gitRoot, cwd, ...args) {
|
|
7875
|
-
const gitArgs =
|
|
7945
|
+
const gitArgs = existsSync24(resolve26(gitRoot, ".git")) ? gitCmd(projectRoot, gitRoot, ...args) : [resolveGitBinary(projectRoot), "--git-dir", gitRoot, ...args];
|
|
7876
7946
|
return runCapture2(gitArgs, cwd, projectRoot);
|
|
7877
7947
|
}
|
|
7878
7948
|
function resolveLocalGitRemoteRoot(remoteUrl, gitRoot) {
|
|
@@ -7890,9 +7960,9 @@ function resolveLocalGitRemoteRoot(remoteUrl, gitRoot) {
|
|
|
7890
7960
|
} else if (/^[a-z][a-z0-9+.-]*:\/\//i.test(normalized) || /^[^@]+@[^:]+:.+$/.test(normalized)) {
|
|
7891
7961
|
return "";
|
|
7892
7962
|
} else if (!isAbsolute2(normalized)) {
|
|
7893
|
-
candidate =
|
|
7963
|
+
candidate = resolve26(gitRoot, normalized);
|
|
7894
7964
|
}
|
|
7895
|
-
return
|
|
7965
|
+
return existsSync24(candidate) ? candidate : "";
|
|
7896
7966
|
}
|
|
7897
7967
|
function normalizeGithubRepoNameWithOwner(value) {
|
|
7898
7968
|
const normalized = value.trim();
|
|
@@ -8019,7 +8089,7 @@ function inferReviewerFromChangedFiles(projectRoot, repoRoot, baseRef, branchRef
|
|
|
8019
8089
|
return best;
|
|
8020
8090
|
}
|
|
8021
8091
|
function snapshotRepo(projectRoot, label, repo) {
|
|
8022
|
-
if (!
|
|
8092
|
+
if (!existsSync24(resolve26(repo, ".git"))) {
|
|
8023
8093
|
return [`## ${label}`, `repo: ${repo}`, "status: unavailable", ""];
|
|
8024
8094
|
}
|
|
8025
8095
|
const status = runCapture2(gitCmd(projectRoot, repo, "status", "--short"), projectRoot).stdout.trim();
|
|
@@ -8042,7 +8112,7 @@ function snapshotRepo(projectRoot, label, repo) {
|
|
|
8042
8112
|
];
|
|
8043
8113
|
}
|
|
8044
8114
|
function commitRepo(projectRoot, repo, label, message, allowEmpty, scoped, files, changedFilesManifest) {
|
|
8045
|
-
if (!
|
|
8115
|
+
if (!existsSync24(resolve26(repo, ".git"))) {
|
|
8046
8116
|
console.log(`Skipping ${label}: repo not available (${repo})`);
|
|
8047
8117
|
return;
|
|
8048
8118
|
}
|
|
@@ -8074,18 +8144,18 @@ function commitRepo(projectRoot, repo, label, message, allowEmpty, scoped, files
|
|
|
8074
8144
|
console.log(`Committed ${label}: ${message}`);
|
|
8075
8145
|
}
|
|
8076
8146
|
function readChangedFilesManifest(projectRoot, taskId) {
|
|
8077
|
-
const manifestPath =
|
|
8078
|
-
if (!
|
|
8147
|
+
const manifestPath = resolve26(artifactDirForId(projectRoot, taskId), "changed-files.txt");
|
|
8148
|
+
if (!existsSync24(manifestPath)) {
|
|
8079
8149
|
return [];
|
|
8080
8150
|
}
|
|
8081
|
-
const files =
|
|
8151
|
+
const files = readFileSync13(manifestPath, "utf-8").split(/\r?\n/).map((line) => normalizeChangedFilePath2(line)).filter(Boolean);
|
|
8082
8152
|
return [...new Set(files)];
|
|
8083
8153
|
}
|
|
8084
8154
|
function refreshChangedFilesManifest(projectRoot, taskId) {
|
|
8085
|
-
const manifestPath =
|
|
8086
|
-
|
|
8155
|
+
const manifestPath = resolve26(artifactDirForId(projectRoot, taskId), "changed-files.txt");
|
|
8156
|
+
mkdirSync12(dirname12(manifestPath), { recursive: true });
|
|
8087
8157
|
const changedFiles = changedFilesForTask(projectRoot, taskId, true);
|
|
8088
|
-
|
|
8158
|
+
writeFileSync12(manifestPath, `${changedFiles.join(`
|
|
8089
8159
|
`)}
|
|
8090
8160
|
`, "utf-8");
|
|
8091
8161
|
return manifestPath;
|
|
@@ -8198,7 +8268,7 @@ function repoHasPathChange(projectRoot, repoRoot, relativePath) {
|
|
|
8198
8268
|
return result.exitCode === 0 && result.stdout.trim().length > 0;
|
|
8199
8269
|
}
|
|
8200
8270
|
function stageExcludePathspecs(repoRoot) {
|
|
8201
|
-
const patterns =
|
|
8271
|
+
const patterns = existsSync24(resolve26(repoRoot, ".rig", "task-config.json")) ? [...TASK_RUNTIME_STAGE_EXCLUDES, ...GENERATED_STAGE_EXCLUDES] : [".rig/**", ...GENERATED_STAGE_EXCLUDES];
|
|
8202
8272
|
return patterns.map((pattern) => `:(glob,exclude)${pattern}`);
|
|
8203
8273
|
}
|
|
8204
8274
|
function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
@@ -8208,7 +8278,7 @@ function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
|
8208
8278
|
}
|
|
8209
8279
|
let current = repoRoot;
|
|
8210
8280
|
for (let index = 0;index < parts.length - 1; index += 1) {
|
|
8211
|
-
current =
|
|
8281
|
+
current = resolve26(current, parts[index]);
|
|
8212
8282
|
try {
|
|
8213
8283
|
if (lstatSync(current).isSymbolicLink()) {
|
|
8214
8284
|
return true;
|
|
@@ -8220,7 +8290,7 @@ function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
|
8220
8290
|
return false;
|
|
8221
8291
|
}
|
|
8222
8292
|
function printRepoStatus(projectRoot, label, repo, expectedBranch) {
|
|
8223
|
-
if (!
|
|
8293
|
+
if (!existsSync24(resolve26(repo, ".git"))) {
|
|
8224
8294
|
console.log(`${label}: unavailable (${repo})`);
|
|
8225
8295
|
return;
|
|
8226
8296
|
}
|
|
@@ -8256,7 +8326,7 @@ function resolveTaskBranchId(projectRoot, taskId) {
|
|
|
8256
8326
|
}
|
|
8257
8327
|
} catch {}
|
|
8258
8328
|
const artifactDir = artifactDirForId(projectRoot, taskId);
|
|
8259
|
-
if (
|
|
8329
|
+
if (existsSync24(artifactDir)) {
|
|
8260
8330
|
return taskId;
|
|
8261
8331
|
}
|
|
8262
8332
|
throw new Error(`Unknown task id: ${taskId}`);
|
|
@@ -8292,11 +8362,11 @@ function runCapture2(command, cwd, projectRoot = cwd) {
|
|
|
8292
8362
|
}
|
|
8293
8363
|
function runtimeGitEnv(projectRoot) {
|
|
8294
8364
|
const { ctx, runtimeRoot } = resolveRuntimeMetadata(projectRoot);
|
|
8295
|
-
const runtimeHome = runtimeRoot ?
|
|
8296
|
-
const runtimeTmp = runtimeRoot ?
|
|
8297
|
-
const runtimeCache = runtimeRoot ?
|
|
8298
|
-
const runtimeKnownHosts = runtimeHome ?
|
|
8299
|
-
const runtimeKey = runtimeHome ?
|
|
8365
|
+
const runtimeHome = runtimeRoot ? resolve26(runtimeRoot, "home") : "";
|
|
8366
|
+
const runtimeTmp = runtimeRoot ? resolve26(runtimeRoot, "tmp") : "";
|
|
8367
|
+
const runtimeCache = runtimeRoot ? resolve26(runtimeRoot, "cache") : "";
|
|
8368
|
+
const runtimeKnownHosts = runtimeHome ? resolve26(runtimeHome, ".ssh", "known_hosts") : "";
|
|
8369
|
+
const runtimeKey = runtimeHome ? resolve26(runtimeHome, ".ssh", "rig-agent-key") : "";
|
|
8300
8370
|
const env = {};
|
|
8301
8371
|
if (ctx?.workspaceDir) {
|
|
8302
8372
|
env.PROJECT_RIG_ROOT = projectRoot;
|
|
@@ -8309,14 +8379,14 @@ function runtimeGitEnv(projectRoot) {
|
|
|
8309
8379
|
if (runtimeRoot) {
|
|
8310
8380
|
env.RIG_RUNTIME_HOME = runtimeRoot;
|
|
8311
8381
|
}
|
|
8312
|
-
if (runtimeHome &&
|
|
8382
|
+
if (runtimeHome && existsSync24(runtimeHome)) {
|
|
8313
8383
|
env.HOME = runtimeHome;
|
|
8314
8384
|
env.OPENSSL_CONF = ensureRuntimeOpenSslConfig(runtimeHome);
|
|
8315
8385
|
}
|
|
8316
|
-
if (runtimeTmp &&
|
|
8386
|
+
if (runtimeTmp && existsSync24(runtimeTmp)) {
|
|
8317
8387
|
env.TMPDIR = runtimeTmp;
|
|
8318
8388
|
}
|
|
8319
|
-
if (runtimeCache &&
|
|
8389
|
+
if (runtimeCache && existsSync24(runtimeCache)) {
|
|
8320
8390
|
env.XDG_CACHE_HOME = runtimeCache;
|
|
8321
8391
|
}
|
|
8322
8392
|
const workspaceSecrets = loadDotEnvSecrets(ctx?.workspaceDir || projectRoot, process.env);
|
|
@@ -8360,14 +8430,14 @@ function runtimeGitEnv(projectRoot) {
|
|
|
8360
8430
|
env.GH_TOKEN = env.GH_TOKEN || gitHubToken;
|
|
8361
8431
|
applyGitHubCredentialHelperEnv(env);
|
|
8362
8432
|
}
|
|
8363
|
-
if (runtimeKnownHosts &&
|
|
8433
|
+
if (runtimeKnownHosts && existsSync24(runtimeKnownHosts)) {
|
|
8364
8434
|
const sshParts = [
|
|
8365
8435
|
"ssh",
|
|
8366
8436
|
`-o UserKnownHostsFile="${runtimeKnownHosts}"`,
|
|
8367
8437
|
"-o StrictHostKeyChecking=yes",
|
|
8368
8438
|
"-F /dev/null"
|
|
8369
8439
|
];
|
|
8370
|
-
if (runtimeKey &&
|
|
8440
|
+
if (runtimeKey && existsSync24(runtimeKey)) {
|
|
8371
8441
|
sshParts.splice(1, 0, `-i "${runtimeKey}"`, "-o IdentitiesOnly=yes");
|
|
8372
8442
|
}
|
|
8373
8443
|
env.GIT_SSH_COMMAND = sshParts.join(" ");
|
|
@@ -8388,12 +8458,12 @@ function loadPersistedRuntimeSecrets(runtimeRoot) {
|
|
|
8388
8458
|
if (!runtimeRoot) {
|
|
8389
8459
|
return {};
|
|
8390
8460
|
}
|
|
8391
|
-
const path =
|
|
8392
|
-
if (!
|
|
8461
|
+
const path = resolve26(runtimeRoot, "runtime-secrets.json");
|
|
8462
|
+
if (!existsSync24(path)) {
|
|
8393
8463
|
return {};
|
|
8394
8464
|
}
|
|
8395
8465
|
try {
|
|
8396
|
-
const parsed = JSON.parse(
|
|
8466
|
+
const parsed = JSON.parse(readFileSync13(path, "utf-8"));
|
|
8397
8467
|
const entries = Object.entries(parsed).filter((entry) => typeof entry[1] === "string");
|
|
8398
8468
|
return Object.fromEntries(entries);
|
|
8399
8469
|
} catch {
|
|
@@ -8401,13 +8471,13 @@ function loadPersistedRuntimeSecrets(runtimeRoot) {
|
|
|
8401
8471
|
}
|
|
8402
8472
|
}
|
|
8403
8473
|
function ensureRuntimeOpenSslConfig(runtimeHome) {
|
|
8404
|
-
const sslDir =
|
|
8405
|
-
const sslConfig =
|
|
8406
|
-
if (!
|
|
8407
|
-
|
|
8474
|
+
const sslDir = resolve26(runtimeHome, ".ssl");
|
|
8475
|
+
const sslConfig = resolve26(sslDir, "openssl.cnf");
|
|
8476
|
+
if (!existsSync24(sslDir)) {
|
|
8477
|
+
mkdirSync12(sslDir, { recursive: true });
|
|
8408
8478
|
}
|
|
8409
|
-
if (!
|
|
8410
|
-
|
|
8479
|
+
if (!existsSync24(sslConfig)) {
|
|
8480
|
+
writeFileSync12(sslConfig, `# Rig runtime OpenSSL config placeholder
|
|
8411
8481
|
`);
|
|
8412
8482
|
}
|
|
8413
8483
|
return sslConfig;
|
|
@@ -8425,29 +8495,29 @@ function resolveRuntimeMetadata(projectRoot) {
|
|
|
8425
8495
|
if (contextFile) {
|
|
8426
8496
|
return {
|
|
8427
8497
|
ctx,
|
|
8428
|
-
runtimeRoot:
|
|
8498
|
+
runtimeRoot: dirname12(resolve26(contextFile))
|
|
8429
8499
|
};
|
|
8430
8500
|
}
|
|
8431
8501
|
const inferredContextFile = findRuntimeContextFile2(projectRoot);
|
|
8432
|
-
if (
|
|
8502
|
+
if (existsSync24(inferredContextFile)) {
|
|
8433
8503
|
try {
|
|
8434
8504
|
ctx = loadRuntimeContext(inferredContextFile);
|
|
8435
8505
|
} catch {}
|
|
8436
8506
|
return {
|
|
8437
8507
|
ctx,
|
|
8438
|
-
runtimeRoot:
|
|
8508
|
+
runtimeRoot: dirname12(inferredContextFile)
|
|
8439
8509
|
};
|
|
8440
8510
|
}
|
|
8441
8511
|
return { ctx, runtimeRoot: "" };
|
|
8442
8512
|
}
|
|
8443
8513
|
function findRuntimeContextFile2(startPath) {
|
|
8444
|
-
let current =
|
|
8514
|
+
let current = resolve26(startPath);
|
|
8445
8515
|
while (true) {
|
|
8446
|
-
const candidate =
|
|
8447
|
-
if (
|
|
8516
|
+
const candidate = resolve26(current, "runtime-context.json");
|
|
8517
|
+
if (existsSync24(candidate)) {
|
|
8448
8518
|
return candidate;
|
|
8449
8519
|
}
|
|
8450
|
-
const parent =
|
|
8520
|
+
const parent = dirname12(current);
|
|
8451
8521
|
if (parent === current) {
|
|
8452
8522
|
return "";
|
|
8453
8523
|
}
|
|
@@ -8456,7 +8526,7 @@ function findRuntimeContextFile2(startPath) {
|
|
|
8456
8526
|
}
|
|
8457
8527
|
|
|
8458
8528
|
// packages/runtime/src/control-plane/native/profile-ops.ts
|
|
8459
|
-
import { existsSync as
|
|
8529
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync13, writeFileSync as writeFileSync13 } from "fs";
|
|
8460
8530
|
var DEFAULTS = {
|
|
8461
8531
|
model: parseEnvOrDefault(process.env.DEFAULT_AGENT_MODEL, ["claude", "gpt-codex", "pi"], "pi"),
|
|
8462
8532
|
runtime: parseEnvOrDefault(process.env.DEFAULT_AGENT_RUNTIME, ["claude-code", "codex-app-server", "pi"], "pi"),
|
|
@@ -8471,7 +8541,7 @@ function parseEnvOrDefault(value, allowed, fallback) {
|
|
|
8471
8541
|
return allowed.includes(value) ? value : fallback;
|
|
8472
8542
|
}
|
|
8473
8543
|
async function readProfileFile(path) {
|
|
8474
|
-
if (!
|
|
8544
|
+
if (!existsSync25(path)) {
|
|
8475
8545
|
return null;
|
|
8476
8546
|
}
|
|
8477
8547
|
try {
|
|
@@ -8524,14 +8594,14 @@ async function setProfile(projectRoot, options) {
|
|
|
8524
8594
|
plugin = model === "gpt-codex" ? "codex" : model === "pi" ? "pi" : "claude";
|
|
8525
8595
|
}
|
|
8526
8596
|
const paths = resolveHarnessPaths(projectRoot);
|
|
8527
|
-
|
|
8597
|
+
mkdirSync13(paths.stateDir, { recursive: true });
|
|
8528
8598
|
const next = {
|
|
8529
8599
|
model,
|
|
8530
8600
|
runtime,
|
|
8531
8601
|
agent_plugin: plugin,
|
|
8532
8602
|
updated_at: new Date().toISOString()
|
|
8533
8603
|
};
|
|
8534
|
-
|
|
8604
|
+
writeFileSync13(paths.agentProfilePath, `${JSON.stringify(next, null, 2)}
|
|
8535
8605
|
`, "utf-8");
|
|
8536
8606
|
await showProfile(projectRoot, false);
|
|
8537
8607
|
}
|
|
@@ -8567,13 +8637,13 @@ async function setReviewProfile(projectRoot, mode, provider) {
|
|
|
8567
8637
|
throw new Error(`Invalid provider: ${resolvedProvider}. Supported: greptile.`);
|
|
8568
8638
|
}
|
|
8569
8639
|
const paths = resolveHarnessPaths(projectRoot);
|
|
8570
|
-
|
|
8640
|
+
mkdirSync13(paths.stateDir, { recursive: true });
|
|
8571
8641
|
const next = {
|
|
8572
8642
|
mode,
|
|
8573
8643
|
provider: resolvedProvider,
|
|
8574
8644
|
updated_at: new Date().toISOString()
|
|
8575
8645
|
};
|
|
8576
|
-
|
|
8646
|
+
writeFileSync13(paths.reviewProfilePath, `${JSON.stringify(next, null, 2)}
|
|
8577
8647
|
`, "utf-8");
|
|
8578
8648
|
await showReviewProfile(projectRoot);
|
|
8579
8649
|
}
|
|
@@ -8611,44 +8681,44 @@ async function loadReviewProfile(path) {
|
|
|
8611
8681
|
}
|
|
8612
8682
|
|
|
8613
8683
|
// packages/runtime/src/control-plane/native/repo-ops.ts
|
|
8614
|
-
import { existsSync as
|
|
8615
|
-
import { basename as basename8, dirname as
|
|
8684
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync17, readFileSync as readFileSync15, readdirSync as readdirSync6, rmSync as rmSync7, writeFileSync as writeFileSync15 } from "fs";
|
|
8685
|
+
import { basename as basename8, dirname as dirname14, resolve as resolve30 } from "path";
|
|
8616
8686
|
// packages/runtime/src/control-plane/repos/mirror/bootstrap.ts
|
|
8617
|
-
import { existsSync as
|
|
8618
|
-
import { resolve as
|
|
8687
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync15, realpathSync as realpathSync2 } from "fs";
|
|
8688
|
+
import { resolve as resolve28 } from "path";
|
|
8619
8689
|
|
|
8620
8690
|
// packages/runtime/src/control-plane/authority-files.ts
|
|
8621
|
-
import { existsSync as
|
|
8622
|
-
import { dirname as
|
|
8691
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync14, readFileSync as readFileSync14, writeFileSync as writeFileSync14, appendFileSync as appendFileSync2, copyFileSync as copyFileSync3, statSync as statSync5, readdirSync as readdirSync5, chmodSync as chmodSync3 } from "fs";
|
|
8692
|
+
import { dirname as dirname13, join as join4, relative, resolve as resolve27 } from "path";
|
|
8623
8693
|
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
8624
8694
|
function resolveAuthorityProjectStateDir(projectRoot) {
|
|
8625
8695
|
const explicit = process.env.RIG_STATE_DIR?.trim();
|
|
8626
8696
|
if (explicit) {
|
|
8627
|
-
return
|
|
8697
|
+
return resolve27(explicit);
|
|
8628
8698
|
}
|
|
8629
|
-
return
|
|
8699
|
+
return resolve27(resolve27(projectRoot), ".rig", "state");
|
|
8630
8700
|
}
|
|
8631
8701
|
function readJsonAtPath(path, fallback) {
|
|
8632
|
-
if (!
|
|
8702
|
+
if (!existsSync26(path)) {
|
|
8633
8703
|
return fallback;
|
|
8634
8704
|
}
|
|
8635
8705
|
try {
|
|
8636
|
-
return JSON.parse(
|
|
8706
|
+
return JSON.parse(readFileSync14(path, "utf-8"));
|
|
8637
8707
|
} catch {
|
|
8638
8708
|
return fallback;
|
|
8639
8709
|
}
|
|
8640
8710
|
}
|
|
8641
8711
|
function writeJsonAtPath(path, value) {
|
|
8642
|
-
|
|
8643
|
-
|
|
8712
|
+
mkdirSync14(dirname13(path), { recursive: true });
|
|
8713
|
+
writeFileSync14(path, `${JSON.stringify(value, null, 2)}
|
|
8644
8714
|
`, "utf8");
|
|
8645
8715
|
return path;
|
|
8646
8716
|
}
|
|
8647
8717
|
function readAuthorityProjectStateJson(projectRoot, relativePath, fallback) {
|
|
8648
|
-
return readJsonAtPath(
|
|
8718
|
+
return readJsonAtPath(resolve27(resolveAuthorityProjectStateDir(projectRoot), relativePath), fallback);
|
|
8649
8719
|
}
|
|
8650
8720
|
function writeAuthorityProjectStateJson(projectRoot, relativePath, value) {
|
|
8651
|
-
return writeJsonAtPath(
|
|
8721
|
+
return writeJsonAtPath(resolve27(resolveAuthorityProjectStateDir(projectRoot), relativePath), value);
|
|
8652
8722
|
}
|
|
8653
8723
|
|
|
8654
8724
|
// packages/runtime/src/control-plane/repos/mirror/state.ts
|
|
@@ -8708,7 +8778,7 @@ function sameExistingPath(left, right) {
|
|
|
8708
8778
|
try {
|
|
8709
8779
|
return realpathSync2(left) === realpathSync2(right);
|
|
8710
8780
|
} catch {
|
|
8711
|
-
return
|
|
8781
|
+
return resolve28(left) === resolve28(right);
|
|
8712
8782
|
}
|
|
8713
8783
|
}
|
|
8714
8784
|
function repoLooksUsable(repoRoot, projectRoot) {
|
|
@@ -8744,7 +8814,7 @@ function resolveMirrorRemoteUrl(layout) {
|
|
|
8744
8814
|
}
|
|
8745
8815
|
}
|
|
8746
8816
|
}
|
|
8747
|
-
if (
|
|
8817
|
+
if (existsSync27(resolve28(layout.checkoutRoot, ".git")) && checkoutLooksUsable(layout)) {
|
|
8748
8818
|
const checkoutOrigin = runGit(["git", "-C", layout.checkoutRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
8749
8819
|
if (checkoutOrigin.exitCode === 0) {
|
|
8750
8820
|
const currentOrigin = checkoutOrigin.stdout.trim();
|
|
@@ -8757,9 +8827,9 @@ function resolveMirrorRemoteUrl(layout) {
|
|
|
8757
8827
|
}
|
|
8758
8828
|
function ensureManagedRepoMirror(projectRoot, repoId) {
|
|
8759
8829
|
const layout = resolveManagedRepoLayout(projectRoot, repoId);
|
|
8760
|
-
|
|
8830
|
+
mkdirSync15(layout.metadataRoot, { recursive: true });
|
|
8761
8831
|
const remoteUrl = resolveMirrorRemoteUrl(layout);
|
|
8762
|
-
if (!
|
|
8832
|
+
if (!existsSync27(resolve28(layout.mirrorRoot, "HEAD"))) {
|
|
8763
8833
|
ensureGitSuccess(runGit(["git", "init", "--bare", layout.mirrorRoot], layout.projectRoot), ["git", "init", "--bare", layout.mirrorRoot]);
|
|
8764
8834
|
}
|
|
8765
8835
|
const getOrigin = runGit(["git", "--git-dir", layout.mirrorRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
@@ -8779,8 +8849,8 @@ function ensureManagedRepoMirror(projectRoot, repoId) {
|
|
|
8779
8849
|
return layout;
|
|
8780
8850
|
}
|
|
8781
8851
|
// packages/runtime/src/control-plane/repos/mirror/refresh.ts
|
|
8782
|
-
import { existsSync as
|
|
8783
|
-
import { resolve as
|
|
8852
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync16, realpathSync as realpathSync3, rmSync as rmSync6 } from "fs";
|
|
8853
|
+
import { resolve as resolve29 } from "path";
|
|
8784
8854
|
function nowIso3() {
|
|
8785
8855
|
return new Date().toISOString();
|
|
8786
8856
|
}
|
|
@@ -8807,7 +8877,7 @@ function sameExistingPath2(left, right) {
|
|
|
8807
8877
|
try {
|
|
8808
8878
|
return realpathSync3(left) === realpathSync3(right);
|
|
8809
8879
|
} catch {
|
|
8810
|
-
return
|
|
8880
|
+
return resolve29(left) === resolve29(right);
|
|
8811
8881
|
}
|
|
8812
8882
|
}
|
|
8813
8883
|
function ensureMirrorHead(layout) {
|
|
@@ -8853,12 +8923,12 @@ function checkoutLooksUsable2(layout) {
|
|
|
8853
8923
|
return probe.exitCode === 0 && sameExistingPath2(probe.stdout.trim(), layout.checkoutRoot);
|
|
8854
8924
|
}
|
|
8855
8925
|
function ensureCheckoutFromMirror(layout) {
|
|
8856
|
-
|
|
8857
|
-
const gitPath =
|
|
8858
|
-
if (
|
|
8926
|
+
mkdirSync16(resolve29(layout.checkoutRoot, ".."), { recursive: true });
|
|
8927
|
+
const gitPath = resolve29(layout.checkoutRoot, ".git");
|
|
8928
|
+
if (existsSync28(layout.checkoutRoot) && (!existsSync28(gitPath) || !checkoutLooksUsable2(layout))) {
|
|
8859
8929
|
rmSync6(layout.checkoutRoot, { recursive: true, force: true });
|
|
8860
8930
|
}
|
|
8861
|
-
if (!
|
|
8931
|
+
if (!existsSync28(gitPath)) {
|
|
8862
8932
|
ensureGitSuccess2(runGit2(["git", "clone", layout.mirrorRoot, layout.checkoutRoot], layout.projectRoot), ["git", "clone", layout.mirrorRoot, layout.checkoutRoot]);
|
|
8863
8933
|
}
|
|
8864
8934
|
const getOrigin = runGit2(["git", "-C", layout.checkoutRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
@@ -8959,7 +9029,7 @@ function repoDiscover(projectRoot, taskId) {
|
|
|
8959
9029
|
}
|
|
8960
9030
|
function repoBaseline(projectRoot, refresh = false) {
|
|
8961
9031
|
const paths = resolveRepoDiscoveryPaths(projectRoot);
|
|
8962
|
-
if (!refresh &&
|
|
9032
|
+
if (!refresh && existsSync29(paths.baseRepoPinsPath)) {
|
|
8963
9033
|
const baseline = readJsonFile(paths.baseRepoPinsPath, { recorded_at: nowIso(), repos: {} });
|
|
8964
9034
|
return baseline.repos || {};
|
|
8965
9035
|
}
|
|
@@ -8983,8 +9053,8 @@ function ensureMonorepoReady(projectRoot) {
|
|
|
8983
9053
|
}
|
|
8984
9054
|
function persistBaselinePins(projectRoot, repos) {
|
|
8985
9055
|
const paths = resolveRepoDiscoveryPaths(projectRoot);
|
|
8986
|
-
|
|
8987
|
-
|
|
9056
|
+
mkdirSync17(resolve30(paths.baseRepoPinsPath, ".."), { recursive: true });
|
|
9057
|
+
writeFileSync15(paths.baseRepoPinsPath, `${JSON.stringify({ recorded_at: nowIso(), repos }, null, 2)}
|
|
8988
9058
|
`, "utf-8");
|
|
8989
9059
|
return repos;
|
|
8990
9060
|
}
|
|
@@ -9063,28 +9133,28 @@ function readRepoDiscoveryTaskConfig(projectRoot) {
|
|
|
9063
9133
|
function resolveRepoDiscoveryPaths(projectRoot) {
|
|
9064
9134
|
const monorepoRoot = resolveMonorepoRepoLayout(projectRoot).checkoutRoot;
|
|
9065
9135
|
const explicitHostProjectRoot = (process.env.RIG_HOST_PROJECT_ROOT || "").trim();
|
|
9066
|
-
const normalizedProjectRoot =
|
|
9136
|
+
const normalizedProjectRoot = resolve30(projectRoot);
|
|
9067
9137
|
const hostProjectRoot = explicitHostProjectRoot && shouldUseHostProjectStateRoot(normalizedProjectRoot) ? explicitHostProjectRoot : normalizedProjectRoot;
|
|
9068
|
-
const stateDir =
|
|
9138
|
+
const stateDir = resolve30(hostProjectRoot, ".rig", "state");
|
|
9069
9139
|
return {
|
|
9070
9140
|
monorepoRoot,
|
|
9071
|
-
taskRepoCommitsPath:
|
|
9072
|
-
baseRepoPinsPath:
|
|
9141
|
+
taskRepoCommitsPath: resolve30(stateDir, "task-repo-commits.json"),
|
|
9142
|
+
baseRepoPinsPath: resolve30(stateDir, "base-repo-pins.json")
|
|
9073
9143
|
};
|
|
9074
9144
|
}
|
|
9075
9145
|
function shouldUseHostProjectStateRoot(projectRoot) {
|
|
9076
9146
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
9077
|
-
if (runtimeWorkspace &&
|
|
9147
|
+
if (runtimeWorkspace && resolve30(runtimeWorkspace) === projectRoot) {
|
|
9078
9148
|
return true;
|
|
9079
9149
|
}
|
|
9080
|
-
return basename8(
|
|
9150
|
+
return basename8(dirname14(projectRoot)) === ".worktrees";
|
|
9081
9151
|
}
|
|
9082
9152
|
function readPinFromArtifact(projectRoot, depTask, repoKey) {
|
|
9083
|
-
const snapshot =
|
|
9084
|
-
if (!
|
|
9153
|
+
const snapshot = resolve30(artifactDirForId(projectRoot, depTask), "git-state.txt");
|
|
9154
|
+
if (!existsSync29(snapshot)) {
|
|
9085
9155
|
return "";
|
|
9086
9156
|
}
|
|
9087
|
-
const content =
|
|
9157
|
+
const content = readFileSync15(snapshot, "utf-8");
|
|
9088
9158
|
const chunk = content.split(/\r?\n/);
|
|
9089
9159
|
let inSection = false;
|
|
9090
9160
|
for (const line of chunk) {
|
|
@@ -9106,12 +9176,12 @@ function repoPath(projectRoot, key) {
|
|
|
9106
9176
|
if (managed) {
|
|
9107
9177
|
return managed.checkoutRoot;
|
|
9108
9178
|
}
|
|
9109
|
-
return key.startsWith("/") ? key :
|
|
9179
|
+
return key.startsWith("/") ? key : resolve30(projectRoot, key);
|
|
9110
9180
|
}
|
|
9111
9181
|
function applyPins(projectRoot, pins) {
|
|
9112
9182
|
for (const [key, commit] of Object.entries(pins)) {
|
|
9113
9183
|
const path = repoPath(projectRoot, key);
|
|
9114
|
-
if (!
|
|
9184
|
+
if (!existsSync29(resolve30(path, ".git"))) {
|
|
9115
9185
|
throw new Error(`Repo for pin not available: ${key} (${path})`);
|
|
9116
9186
|
}
|
|
9117
9187
|
let hasCommit = runGitCapture(["git", "-C", path, "cat-file", "-e", `${commit}^{commit}`], projectRoot).exitCode === 0;
|
|
@@ -9140,7 +9210,7 @@ function verifyPins(projectRoot, pins) {
|
|
|
9140
9210
|
let ok = true;
|
|
9141
9211
|
for (const [key, expected] of Object.entries(pins)) {
|
|
9142
9212
|
const path = repoPath(projectRoot, key);
|
|
9143
|
-
if (!
|
|
9213
|
+
if (!existsSync29(resolve30(path, ".git"))) {
|
|
9144
9214
|
console.error(`ERROR: repo missing during pin verification: ${key}`);
|
|
9145
9215
|
ok = false;
|
|
9146
9216
|
continue;
|
|
@@ -9165,23 +9235,23 @@ function resolveRuntimeGitEnv() {
|
|
|
9165
9235
|
GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND
|
|
9166
9236
|
};
|
|
9167
9237
|
}
|
|
9168
|
-
const runtimeRoot = process.env.RIG_RUNTIME_HOME?.trim() || (process.env.RIG_RUNTIME_CONTEXT_FILE?.trim() ?
|
|
9169
|
-
const runtimeHome = runtimeRoot ?
|
|
9238
|
+
const runtimeRoot = process.env.RIG_RUNTIME_HOME?.trim() || (process.env.RIG_RUNTIME_CONTEXT_FILE?.trim() ? resolve30(process.env.RIG_RUNTIME_CONTEXT_FILE, "..") : inferRuntimeRootFromWorkspace(process.cwd()));
|
|
9239
|
+
const runtimeHome = runtimeRoot ? resolve30(runtimeRoot, "home") : process.env.HOME?.trim() || "";
|
|
9170
9240
|
if (!runtimeHome) {
|
|
9171
9241
|
return;
|
|
9172
9242
|
}
|
|
9173
|
-
const knownHostsPath =
|
|
9174
|
-
if (!
|
|
9243
|
+
const knownHostsPath = resolve30(runtimeHome, ".ssh", "known_hosts");
|
|
9244
|
+
if (!existsSync29(knownHostsPath)) {
|
|
9175
9245
|
return { HOME: runtimeHome };
|
|
9176
9246
|
}
|
|
9177
|
-
const agentSshKey =
|
|
9247
|
+
const agentSshKey = resolve30(runtimeHome, ".ssh", "rig-agent-key");
|
|
9178
9248
|
const sshParts = [
|
|
9179
9249
|
"ssh",
|
|
9180
9250
|
`-o UserKnownHostsFile="${knownHostsPath}"`,
|
|
9181
9251
|
"-o StrictHostKeyChecking=yes",
|
|
9182
9252
|
"-F /dev/null"
|
|
9183
9253
|
];
|
|
9184
|
-
if (
|
|
9254
|
+
if (existsSync29(agentSshKey)) {
|
|
9185
9255
|
sshParts.splice(1, 0, `-i "${agentSshKey}"`, "-o IdentitiesOnly=yes");
|
|
9186
9256
|
}
|
|
9187
9257
|
return {
|
|
@@ -9191,24 +9261,24 @@ function resolveRuntimeGitEnv() {
|
|
|
9191
9261
|
}
|
|
9192
9262
|
function inferRuntimeRootFromWorkspace(cwd) {
|
|
9193
9263
|
const contextPath = findRuntimeContextFile3(cwd);
|
|
9194
|
-
if (!contextPath || !
|
|
9264
|
+
if (!contextPath || !existsSync29(contextPath)) {
|
|
9195
9265
|
return "";
|
|
9196
9266
|
}
|
|
9197
9267
|
try {
|
|
9198
9268
|
loadRuntimeContext(contextPath);
|
|
9199
|
-
return
|
|
9269
|
+
return resolve30(contextPath, "..");
|
|
9200
9270
|
} catch {
|
|
9201
9271
|
return "";
|
|
9202
9272
|
}
|
|
9203
9273
|
}
|
|
9204
9274
|
function findRuntimeContextFile3(startPath) {
|
|
9205
|
-
let current =
|
|
9275
|
+
let current = resolve30(startPath);
|
|
9206
9276
|
while (true) {
|
|
9207
|
-
const candidate =
|
|
9208
|
-
if (
|
|
9277
|
+
const candidate = resolve30(current, "runtime-context.json");
|
|
9278
|
+
if (existsSync29(candidate)) {
|
|
9209
9279
|
return candidate;
|
|
9210
9280
|
}
|
|
9211
|
-
const parent =
|
|
9281
|
+
const parent = resolve30(current, "..");
|
|
9212
9282
|
if (parent === current) {
|
|
9213
9283
|
return "";
|
|
9214
9284
|
}
|
|
@@ -9217,13 +9287,13 @@ function findRuntimeContextFile3(startPath) {
|
|
|
9217
9287
|
}
|
|
9218
9288
|
|
|
9219
9289
|
// packages/runtime/src/control-plane/memory-sync/cli.ts
|
|
9220
|
-
import { existsSync as
|
|
9290
|
+
import { existsSync as existsSync30 } from "fs";
|
|
9221
9291
|
import { randomUUID } from "crypto";
|
|
9222
9292
|
|
|
9223
9293
|
// packages/runtime/src/control-plane/memory-sync/db.ts
|
|
9224
9294
|
import { Database } from "bun:sqlite";
|
|
9225
|
-
import { mkdirSync as
|
|
9226
|
-
import { dirname as
|
|
9295
|
+
import { mkdirSync as mkdirSync18 } from "fs";
|
|
9296
|
+
import { dirname as dirname15 } from "path";
|
|
9227
9297
|
|
|
9228
9298
|
// packages/runtime/src/control-plane/memory-sync/types.ts
|
|
9229
9299
|
var NO_MATCH_RETRIEVAL_CANONICAL_KEY = "__memory_recall__:none";
|
|
@@ -9819,7 +9889,7 @@ async function validateEventTargets(executor, event) {
|
|
|
9819
9889
|
}
|
|
9820
9890
|
}
|
|
9821
9891
|
async function openMemoryDb(dbPath) {
|
|
9822
|
-
|
|
9892
|
+
mkdirSync18(dirname15(dbPath), { recursive: true });
|
|
9823
9893
|
const sqlite = new Database(dbPath, { create: true, strict: true });
|
|
9824
9894
|
const client = createMemoryDbClient(sqlite);
|
|
9825
9895
|
const db = {
|
|
@@ -10238,7 +10308,7 @@ function formatMemoryQueryResults(results) {
|
|
|
10238
10308
|
}
|
|
10239
10309
|
|
|
10240
10310
|
// packages/runtime/src/control-plane/memory-sync/read.ts
|
|
10241
|
-
import { mkdtempSync, rmSync as rmSync8, writeFileSync as
|
|
10311
|
+
import { mkdtempSync, rmSync as rmSync8, writeFileSync as writeFileSync16 } from "fs";
|
|
10242
10312
|
import { tmpdir as tmpdir5 } from "os";
|
|
10243
10313
|
import { join as join5 } from "path";
|
|
10244
10314
|
var CANONICAL_MEMORY_DB_PATH = "rig/memory/project-memory.db";
|
|
@@ -10267,7 +10337,7 @@ async function readCanonicalMemoryDb(projectRoot, deps = {}) {
|
|
|
10267
10337
|
try {
|
|
10268
10338
|
try {
|
|
10269
10339
|
const bytes = readDeps.readBlobBytesAtRef(repoPath2, baseOid, CANONICAL_MEMORY_DB_PATH);
|
|
10270
|
-
|
|
10340
|
+
writeFileSync16(dbPath, bytes);
|
|
10271
10341
|
} catch (error) {
|
|
10272
10342
|
if (!isMissingCanonicalMemoryBlobError(error)) {
|
|
10273
10343
|
throw error;
|
|
@@ -10425,7 +10495,7 @@ function requireRuntimeMemoryContext(runtimeContext) {
|
|
|
10425
10495
|
}
|
|
10426
10496
|
async function ensureRuntimeMemoryUsable(runtimeContext) {
|
|
10427
10497
|
const memory = requireRuntimeMemoryContext(runtimeContext);
|
|
10428
|
-
if (!
|
|
10498
|
+
if (!existsSync30(memory.hydratedPath)) {
|
|
10429
10499
|
throw new Error(`Shared memory database is missing: ${memory.hydratedPath}`);
|
|
10430
10500
|
}
|
|
10431
10501
|
const db = await openMemoryDb(memory.hydratedPath);
|
|
@@ -10726,8 +10796,8 @@ async function executeHarnessCommand(projectRoot, args, eventBus, pluginHostCtx)
|
|
|
10726
10796
|
}
|
|
10727
10797
|
case "completion-verification":
|
|
10728
10798
|
case "completition-verification": {
|
|
10729
|
-
const hookPath =
|
|
10730
|
-
if (!
|
|
10799
|
+
const hookPath = resolve31(projectRoot, ".rig/bin/hooks/completion-verification");
|
|
10800
|
+
if (!existsSync31(hookPath)) {
|
|
10731
10801
|
throw new Error(`completion-verification hook binary not found: ${hookPath}`);
|
|
10732
10802
|
}
|
|
10733
10803
|
const proc = Bun.spawn([hookPath], {
|
|
@@ -11029,10 +11099,10 @@ function printHelp() {
|
|
|
11029
11099
|
}
|
|
11030
11100
|
|
|
11031
11101
|
// packages/runtime/src/control-plane/native/root-resolver.ts
|
|
11032
|
-
import { existsSync as
|
|
11033
|
-
import { dirname as
|
|
11102
|
+
import { existsSync as existsSync32, readFileSync as readFileSync16 } from "fs";
|
|
11103
|
+
import { dirname as dirname16, parse, resolve as resolve32 } from "path";
|
|
11034
11104
|
function hasProjectMarker(candidate) {
|
|
11035
|
-
return
|
|
11105
|
+
return existsSync32(resolve32(candidate, RIG_DEFINITION_DIRNAME)) || existsSync32(resolve32(candidate, RIG_STATE_DIRNAME));
|
|
11036
11106
|
}
|
|
11037
11107
|
function resolveProjectRoot(options) {
|
|
11038
11108
|
const cwd = options?.cwd || process.cwd();
|
|
@@ -11049,23 +11119,23 @@ function resolveProjectRoot(options) {
|
|
|
11049
11119
|
if (configRoot && hasProjectMarker(configRoot)) {
|
|
11050
11120
|
return configRoot;
|
|
11051
11121
|
}
|
|
11052
|
-
let fileDir =
|
|
11122
|
+
let fileDir = resolve32(fallbackFromDir);
|
|
11053
11123
|
for (let i = 0;i < 5; i += 1) {
|
|
11054
11124
|
if (hasProjectMarker(fileDir)) {
|
|
11055
11125
|
return fileDir;
|
|
11056
11126
|
}
|
|
11057
|
-
fileDir =
|
|
11127
|
+
fileDir = dirname16(fileDir);
|
|
11058
11128
|
}
|
|
11059
11129
|
return cwd;
|
|
11060
11130
|
}
|
|
11061
11131
|
function walkUpForRoot(start) {
|
|
11062
|
-
let searchDir =
|
|
11132
|
+
let searchDir = resolve32(start);
|
|
11063
11133
|
const root = parse(searchDir).root || "/";
|
|
11064
11134
|
while (searchDir !== root) {
|
|
11065
11135
|
if (hasProjectMarker(searchDir)) {
|
|
11066
11136
|
return searchDir;
|
|
11067
11137
|
}
|
|
11068
|
-
searchDir =
|
|
11138
|
+
searchDir = dirname16(searchDir);
|
|
11069
11139
|
}
|
|
11070
11140
|
if (hasProjectMarker(root)) {
|
|
11071
11141
|
return root;
|
|
@@ -11073,12 +11143,12 @@ function walkUpForRoot(start) {
|
|
|
11073
11143
|
return "";
|
|
11074
11144
|
}
|
|
11075
11145
|
function readConfiguredRoot() {
|
|
11076
|
-
const configPath =
|
|
11077
|
-
if (!
|
|
11146
|
+
const configPath = resolve32(process.env.HOME || "~", ".config", "project-rig", "root");
|
|
11147
|
+
if (!existsSync32(configPath)) {
|
|
11078
11148
|
return "";
|
|
11079
11149
|
}
|
|
11080
11150
|
try {
|
|
11081
|
-
const value =
|
|
11151
|
+
const value = readFileSync16(configPath, "utf-8").split(/\r?\n/)[0]?.trim() || "";
|
|
11082
11152
|
return value;
|
|
11083
11153
|
} catch {
|
|
11084
11154
|
return "";
|
|
@@ -11088,9 +11158,9 @@ function readConfiguredRoot() {
|
|
|
11088
11158
|
// packages/runtime/src/control-plane/runtime/events.ts
|
|
11089
11159
|
import { appendFile, mkdir } from "fs/promises";
|
|
11090
11160
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
11091
|
-
import { dirname as
|
|
11161
|
+
import { dirname as dirname17, resolve as resolve33 } from "path";
|
|
11092
11162
|
async function appendEvent(eventsFile, event) {
|
|
11093
|
-
await mkdir(
|
|
11163
|
+
await mkdir(dirname17(eventsFile), { recursive: true });
|
|
11094
11164
|
await appendFile(eventsFile, `${JSON.stringify(event)}
|
|
11095
11165
|
`, "utf-8");
|
|
11096
11166
|
}
|
|
@@ -11152,7 +11222,7 @@ class GeneralCliEventBus {
|
|
|
11152
11222
|
runtimeBuses = new Map;
|
|
11153
11223
|
constructor(options) {
|
|
11154
11224
|
this.runId = options.runId || randomUUID2();
|
|
11155
|
-
this.eventsFile = options.eventsFile ??
|
|
11225
|
+
this.eventsFile = options.eventsFile ?? resolve33(options.projectRoot, ".rig", "logs", "control-plane.events.jsonl");
|
|
11156
11226
|
}
|
|
11157
11227
|
getRunId() {
|
|
11158
11228
|
return this.runId;
|
|
@@ -11205,7 +11275,7 @@ function resolveHarnessPluginMode(options) {
|
|
|
11205
11275
|
async function main() {
|
|
11206
11276
|
const projectRoot = resolveProjectRoot({
|
|
11207
11277
|
cwd: process.cwd(),
|
|
11208
|
-
fallbackFromDir:
|
|
11278
|
+
fallbackFromDir: resolve34(import.meta.dir, "../..")
|
|
11209
11279
|
});
|
|
11210
11280
|
process.env.PROJECT_RIG_ROOT = projectRoot;
|
|
11211
11281
|
process.chdir(projectRoot);
|