@h-rig/runtime 0.0.6-alpha.34 → 0.0.6-alpha.36
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 +544 -463
- package/dist/src/control-plane/hooks/completion-verification.js +369 -288
- 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 +529 -448
- package/dist/src/control-plane/native/task-ops.js +408 -327
- package/dist/src/control-plane/native/validator.js +159 -100
- package/dist/src/control-plane/native/verifier.js +243 -171
- package/dist/src/control-plane/pi-sessiond/bin.js +0 -7
- package/dist/src/control-plane/pi-sessiond/server.js +0 -7
- package/dist/src/control-plane/pi-sessiond/session-service.js +0 -3
- 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/dist/src/index.js +16 -8
- package/dist/src/local-server.js +17 -8
- package/package.json +8 -8
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/runtime/src/control-plane/native/harness-cli.ts
|
|
3
|
-
import { existsSync as
|
|
4
|
-
import { resolve as
|
|
3
|
+
import { existsSync as existsSync31 } from "fs";
|
|
4
|
+
import { resolve as resolve31 } from "path";
|
|
5
5
|
|
|
6
6
|
// packages/runtime/src/control-plane/native/git-ops.ts
|
|
7
|
-
import { existsSync as
|
|
8
|
-
import { dirname as
|
|
7
|
+
import { existsSync as existsSync24, lstatSync, mkdirSync as mkdirSync12, readFileSync as readFileSync13, writeFileSync as writeFileSync12 } from "fs";
|
|
8
|
+
import { dirname as dirname12, isAbsolute as isAbsolute2, resolve as resolve26 } from "path";
|
|
9
9
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
10
10
|
|
|
11
11
|
// packages/runtime/src/control-plane/runtime/baked-secrets.ts
|
|
@@ -274,8 +274,8 @@ function isAgentRuntimeContextPath(path) {
|
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
// packages/runtime/src/control-plane/native/task-ops.ts
|
|
277
|
-
import { appendFileSync, existsSync as
|
|
278
|
-
import { resolve as
|
|
277
|
+
import { appendFileSync, existsSync as existsSync23, mkdirSync as mkdirSync11, readFileSync as readFileSync12, writeFileSync as writeFileSync11 } from "fs";
|
|
278
|
+
import { resolve as resolve25 } from "path";
|
|
279
279
|
|
|
280
280
|
// packages/runtime/src/build-time-config.ts
|
|
281
281
|
function normalizeBuildConfig(value) {
|
|
@@ -824,6 +824,8 @@ function buildBrowserGuidanceLines(browser) {
|
|
|
824
824
|
}
|
|
825
825
|
|
|
826
826
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
827
|
+
import { existsSync as existsSync8 } from "fs";
|
|
828
|
+
import { resolve as resolvePath } from "path";
|
|
827
829
|
import { createPluginHost } from "@rig/core";
|
|
828
830
|
import { loadConfig } from "@rig/core/load-config";
|
|
829
831
|
|
|
@@ -1171,6 +1173,55 @@ async function materializeSkills(projectRoot, entries) {
|
|
|
1171
1173
|
return written;
|
|
1172
1174
|
}
|
|
1173
1175
|
|
|
1176
|
+
// packages/runtime/src/control-plane/pi-settings-materializer.ts
|
|
1177
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
1178
|
+
import { dirname as dirname6, resolve as resolve9 } from "path";
|
|
1179
|
+
var SETTINGS_RELATIVE_PATH = ".pi/settings.json";
|
|
1180
|
+
var MANAGED_RECORD_RELATIVE_PATH = ".rig/state/pi-managed-packages.json";
|
|
1181
|
+
function readJson(path, fallback) {
|
|
1182
|
+
if (!existsSync7(path))
|
|
1183
|
+
return fallback;
|
|
1184
|
+
try {
|
|
1185
|
+
return JSON.parse(readFileSync6(path, "utf-8"));
|
|
1186
|
+
} catch {
|
|
1187
|
+
return fallback;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
function packageKey(entry) {
|
|
1191
|
+
if (typeof entry === "string")
|
|
1192
|
+
return entry;
|
|
1193
|
+
if (entry && typeof entry === "object" && typeof entry.source === "string") {
|
|
1194
|
+
return entry.source;
|
|
1195
|
+
}
|
|
1196
|
+
return JSON.stringify(entry);
|
|
1197
|
+
}
|
|
1198
|
+
function materializePiPackages(projectRoot, declaredPackages) {
|
|
1199
|
+
const settingsPath = resolve9(projectRoot, SETTINGS_RELATIVE_PATH);
|
|
1200
|
+
const managedRecordPath = resolve9(projectRoot, MANAGED_RECORD_RELATIVE_PATH);
|
|
1201
|
+
const settings = readJson(settingsPath, {});
|
|
1202
|
+
const previouslyManaged = new Set(readJson(managedRecordPath, []));
|
|
1203
|
+
const existing = Array.isArray(settings.packages) ? settings.packages : [];
|
|
1204
|
+
const operatorEntries = existing.filter((entry) => !previouslyManaged.has(packageKey(entry)));
|
|
1205
|
+
const operatorKeys = new Set(operatorEntries.map(packageKey));
|
|
1206
|
+
const managedToAdd = declaredPackages.filter((pkg) => !operatorKeys.has(pkg));
|
|
1207
|
+
const nextPackages = [...operatorEntries, ...managedToAdd];
|
|
1208
|
+
if (nextPackages.length > 0 || existsSync7(settingsPath)) {
|
|
1209
|
+
const nextSettings = { ...settings };
|
|
1210
|
+
if (nextPackages.length > 0) {
|
|
1211
|
+
nextSettings.packages = nextPackages;
|
|
1212
|
+
} else {
|
|
1213
|
+
delete nextSettings.packages;
|
|
1214
|
+
}
|
|
1215
|
+
mkdirSync5(dirname6(settingsPath), { recursive: true });
|
|
1216
|
+
writeFileSync5(settingsPath, `${JSON.stringify(nextSettings, null, 2)}
|
|
1217
|
+
`, "utf-8");
|
|
1218
|
+
}
|
|
1219
|
+
mkdirSync5(dirname6(managedRecordPath), { recursive: true });
|
|
1220
|
+
writeFileSync5(managedRecordPath, `${JSON.stringify(managedToAdd, null, 2)}
|
|
1221
|
+
`, "utf-8");
|
|
1222
|
+
return { settingsPath, packages: managedToAdd };
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1174
1225
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
1175
1226
|
async function buildPluginHostContext(projectRoot) {
|
|
1176
1227
|
let config;
|
|
@@ -1218,6 +1269,14 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
1218
1269
|
} catch (err) {
|
|
1219
1270
|
console.warn(`[plugin-host] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
1220
1271
|
}
|
|
1272
|
+
try {
|
|
1273
|
+
const piPackages = config.runtime?.pi?.packages ?? [];
|
|
1274
|
+
if (piPackages.length > 0 || existsSync8(resolvePath(projectRoot, ".rig/state/pi-managed-packages.json"))) {
|
|
1275
|
+
materializePiPackages(projectRoot, piPackages);
|
|
1276
|
+
}
|
|
1277
|
+
} catch (err) {
|
|
1278
|
+
console.warn(`[plugin-host] Pi package materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
1279
|
+
}
|
|
1221
1280
|
return {
|
|
1222
1281
|
config,
|
|
1223
1282
|
pluginHost,
|
|
@@ -1231,12 +1290,12 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
1231
1290
|
|
|
1232
1291
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
1233
1292
|
import { spawnSync } from "child_process";
|
|
1234
|
-
import { existsSync as
|
|
1235
|
-
import { basename as basename3, join as join2, resolve as
|
|
1293
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, readdirSync as readdirSync2, statSync, writeFileSync as writeFileSync6 } from "fs";
|
|
1294
|
+
import { basename as basename3, join as join2, resolve as resolve11 } from "path";
|
|
1236
1295
|
|
|
1237
1296
|
// packages/runtime/src/control-plane/tasks/legacy-task-config-source.ts
|
|
1238
|
-
import { existsSync as
|
|
1239
|
-
import { resolve as
|
|
1297
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
|
|
1298
|
+
import { resolve as resolve10 } from "path";
|
|
1240
1299
|
|
|
1241
1300
|
// packages/runtime/src/control-plane/tasks/task-record-reader.ts
|
|
1242
1301
|
async function findTaskById(reader, id) {
|
|
@@ -1259,7 +1318,7 @@ class LegacyTaskConfigReadError extends Error {
|
|
|
1259
1318
|
}
|
|
1260
1319
|
}
|
|
1261
1320
|
function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
1262
|
-
const configPath = options.configPath ??
|
|
1321
|
+
const configPath = options.configPath ?? resolve10(projectRoot, ".rig", "task-config.json");
|
|
1263
1322
|
const reader = {
|
|
1264
1323
|
async listTasks() {
|
|
1265
1324
|
return readLegacyTaskRecords(projectRoot, configPath);
|
|
@@ -1270,8 +1329,8 @@ function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
|
1270
1329
|
};
|
|
1271
1330
|
return reader;
|
|
1272
1331
|
}
|
|
1273
|
-
function readLegacyTaskRecords(projectRoot, configPath =
|
|
1274
|
-
if (!
|
|
1332
|
+
function readLegacyTaskRecords(projectRoot, configPath = resolve10(projectRoot, ".rig", "task-config.json")) {
|
|
1333
|
+
if (!existsSync9(configPath)) {
|
|
1275
1334
|
return [];
|
|
1276
1335
|
}
|
|
1277
1336
|
const rawConfig = readLegacyTaskConfigJson(projectRoot, configPath);
|
|
@@ -1279,7 +1338,7 @@ function readLegacyTaskRecords(projectRoot, configPath = resolve9(projectRoot, "
|
|
|
1279
1338
|
}
|
|
1280
1339
|
function readLegacyTaskConfigJson(projectRoot, configPath) {
|
|
1281
1340
|
try {
|
|
1282
|
-
const parsed = JSON.parse(
|
|
1341
|
+
const parsed = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
1283
1342
|
if (isPlainRecord(parsed)) {
|
|
1284
1343
|
return parsed;
|
|
1285
1344
|
}
|
|
@@ -1363,7 +1422,7 @@ function isPlainRecord(candidate) {
|
|
|
1363
1422
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
1364
1423
|
var FILE_TASK_PATTERN = /\.(task\.)?json$/;
|
|
1365
1424
|
function createSourceAwareTaskConfigRecordReader(projectRoot, options = {}) {
|
|
1366
|
-
const configPath = options.configPath ??
|
|
1425
|
+
const configPath = options.configPath ?? resolve11(projectRoot, ".rig", "task-config.json");
|
|
1367
1426
|
const legacy = createLegacyTaskConfigRecordReader(projectRoot, { configPath });
|
|
1368
1427
|
const spawnFn = options.spawn ?? spawnSync;
|
|
1369
1428
|
const ghBinary = options.ghBinary ?? "gh";
|
|
@@ -1446,10 +1505,10 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
1446
1505
|
return metadata;
|
|
1447
1506
|
}
|
|
1448
1507
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
1449
|
-
const jsonPath =
|
|
1450
|
-
if (
|
|
1508
|
+
const jsonPath = resolve11(projectRoot, "rig.config.json");
|
|
1509
|
+
if (existsSync10(jsonPath)) {
|
|
1451
1510
|
try {
|
|
1452
|
-
const parsed = JSON.parse(
|
|
1511
|
+
const parsed = JSON.parse(readFileSync8(jsonPath, "utf8"));
|
|
1453
1512
|
if (isPlainRecord2(parsed) && isPlainRecord2(parsed.taskSource)) {
|
|
1454
1513
|
const source = parsed.taskSource;
|
|
1455
1514
|
return source.kind === "files" && typeof source.path === "string" ? source.path : null;
|
|
@@ -1458,12 +1517,12 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
1458
1517
|
return null;
|
|
1459
1518
|
}
|
|
1460
1519
|
}
|
|
1461
|
-
const tsPath =
|
|
1462
|
-
if (!
|
|
1520
|
+
const tsPath = resolve11(projectRoot, "rig.config.ts");
|
|
1521
|
+
if (!existsSync10(tsPath)) {
|
|
1463
1522
|
return null;
|
|
1464
1523
|
}
|
|
1465
1524
|
try {
|
|
1466
|
-
const source =
|
|
1525
|
+
const source = readFileSync8(tsPath, "utf8");
|
|
1467
1526
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
1468
1527
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
1469
1528
|
if (kind !== "files") {
|
|
@@ -1483,10 +1542,10 @@ function readRawTaskEntry(configPath, taskId) {
|
|
|
1483
1542
|
return isPlainRecord2(entry) ? entry : null;
|
|
1484
1543
|
}
|
|
1485
1544
|
function readRawTaskConfig(configPath) {
|
|
1486
|
-
if (!
|
|
1545
|
+
if (!existsSync10(configPath)) {
|
|
1487
1546
|
return null;
|
|
1488
1547
|
}
|
|
1489
|
-
const parsed = JSON.parse(
|
|
1548
|
+
const parsed = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
1490
1549
|
return isPlainRecord2(parsed) ? parsed : null;
|
|
1491
1550
|
}
|
|
1492
1551
|
function stripLegacyTaskConfigMetadata2(raw) {
|
|
@@ -1494,8 +1553,8 @@ function stripLegacyTaskConfigMetadata2(raw) {
|
|
|
1494
1553
|
return tasks;
|
|
1495
1554
|
}
|
|
1496
1555
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
1497
|
-
const directory =
|
|
1498
|
-
if (!
|
|
1556
|
+
const directory = resolve11(projectRoot, sourcePath);
|
|
1557
|
+
if (!existsSync10(directory)) {
|
|
1499
1558
|
return [];
|
|
1500
1559
|
}
|
|
1501
1560
|
const tasks = [];
|
|
@@ -1510,11 +1569,11 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
1510
1569
|
return tasks;
|
|
1511
1570
|
}
|
|
1512
1571
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
1513
|
-
const file = findFileBackedTaskFile(
|
|
1572
|
+
const file = findFileBackedTaskFile(resolve11(projectRoot, sourcePath), taskId);
|
|
1514
1573
|
if (!file) {
|
|
1515
1574
|
return null;
|
|
1516
1575
|
}
|
|
1517
|
-
const raw = JSON.parse(
|
|
1576
|
+
const raw = JSON.parse(readFileSync8(file, "utf8"));
|
|
1518
1577
|
if (!isPlainRecord2(raw)) {
|
|
1519
1578
|
return null;
|
|
1520
1579
|
}
|
|
@@ -1527,7 +1586,7 @@ function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
|
1527
1586
|
};
|
|
1528
1587
|
}
|
|
1529
1588
|
function findFileBackedTaskFile(directory, taskId) {
|
|
1530
|
-
if (!
|
|
1589
|
+
if (!existsSync10(directory)) {
|
|
1531
1590
|
return null;
|
|
1532
1591
|
}
|
|
1533
1592
|
for (const name of readdirSync2(directory)) {
|
|
@@ -1537,7 +1596,7 @@ function findFileBackedTaskFile(directory, taskId) {
|
|
|
1537
1596
|
try {
|
|
1538
1597
|
if (!statSync(file).isFile())
|
|
1539
1598
|
continue;
|
|
1540
|
-
const raw = JSON.parse(
|
|
1599
|
+
const raw = JSON.parse(readFileSync8(file, "utf8"));
|
|
1541
1600
|
const inferredId = basename3(file).replace(FILE_TASK_PATTERN, "");
|
|
1542
1601
|
const id = isPlainRecord2(raw) && typeof raw.id === "string" ? raw.id : inferredId;
|
|
1543
1602
|
if (id === taskId) {
|
|
@@ -1697,8 +1756,8 @@ async function readConfiguredTaskSourceTask(projectRoot, taskId) {
|
|
|
1697
1756
|
}
|
|
1698
1757
|
|
|
1699
1758
|
// packages/runtime/src/control-plane/native/task-state.ts
|
|
1700
|
-
import { existsSync as
|
|
1701
|
-
import { basename as basename6, resolve as
|
|
1759
|
+
import { existsSync as existsSync17, readFileSync as readFileSync11, readdirSync as readdirSync3, statSync as statSync3, writeFileSync as writeFileSync7 } from "fs";
|
|
1760
|
+
import { basename as basename6, resolve as resolve18 } from "path";
|
|
1702
1761
|
|
|
1703
1762
|
// packages/runtime/src/control-plane/state-sync/types.ts
|
|
1704
1763
|
var SUPPORTED_TASK_STATE_SCHEMA_VERSION = 1;
|
|
@@ -1806,50 +1865,50 @@ function readTaskStateMetadataEnvelope(raw) {
|
|
|
1806
1865
|
};
|
|
1807
1866
|
}
|
|
1808
1867
|
// packages/runtime/src/control-plane/state-sync/read.ts
|
|
1809
|
-
import { existsSync as
|
|
1810
|
-
import { resolve as
|
|
1868
|
+
import { existsSync as existsSync16, readFileSync as readFileSync10 } from "fs";
|
|
1869
|
+
import { resolve as resolve17 } from "path";
|
|
1811
1870
|
|
|
1812
1871
|
// packages/runtime/src/control-plane/native/utils.ts
|
|
1813
|
-
import { existsSync as
|
|
1814
|
-
import { resolve as
|
|
1872
|
+
import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
|
|
1873
|
+
import { resolve as resolve14 } from "path";
|
|
1815
1874
|
|
|
1816
1875
|
// packages/runtime/src/layout.ts
|
|
1817
|
-
import { existsSync as
|
|
1818
|
-
import { basename as basename4, dirname as
|
|
1876
|
+
import { existsSync as existsSync11 } from "fs";
|
|
1877
|
+
import { basename as basename4, dirname as dirname7, resolve as resolve12 } from "path";
|
|
1819
1878
|
var RIG_DEFINITION_DIRNAME = "rig";
|
|
1820
1879
|
var RIG_ARTIFACTS_DIRNAME = "artifacts";
|
|
1821
1880
|
function resolveMonorepoRoot(projectRoot) {
|
|
1822
|
-
const normalizedProjectRoot =
|
|
1881
|
+
const normalizedProjectRoot = resolve12(projectRoot);
|
|
1823
1882
|
const explicit = process.env.MONOREPO_ROOT?.trim();
|
|
1824
1883
|
if (explicit) {
|
|
1825
|
-
const explicitRoot =
|
|
1826
|
-
const explicitParent =
|
|
1884
|
+
const explicitRoot = resolve12(explicit);
|
|
1885
|
+
const explicitParent = dirname7(explicitRoot);
|
|
1827
1886
|
if (basename4(explicitParent) === ".worktrees") {
|
|
1828
|
-
const owner =
|
|
1829
|
-
const ownerHasGit =
|
|
1830
|
-
const ownerHasTaskConfig =
|
|
1831
|
-
const ownerHasRigConfig =
|
|
1887
|
+
const owner = dirname7(explicitParent);
|
|
1888
|
+
const ownerHasGit = existsSync11(resolve12(owner, ".git"));
|
|
1889
|
+
const ownerHasTaskConfig = existsSync11(resolve12(owner, ".rig", "task-config.json"));
|
|
1890
|
+
const ownerHasRigConfig = existsSync11(resolve12(owner, "rig.config.ts"));
|
|
1832
1891
|
if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
|
|
1833
1892
|
return owner;
|
|
1834
1893
|
}
|
|
1835
1894
|
throw new Error(`MONOREPO_ROOT points to worktree ${explicitRoot}, but the owner checkout is incomplete at ${owner}.`);
|
|
1836
1895
|
}
|
|
1837
|
-
if (!
|
|
1896
|
+
if (!existsSync11(resolve12(explicitRoot, ".git"))) {
|
|
1838
1897
|
throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but no git checkout was found there.`);
|
|
1839
1898
|
}
|
|
1840
|
-
const hasTaskConfig =
|
|
1841
|
-
const hasRigConfig =
|
|
1899
|
+
const hasTaskConfig = existsSync11(resolve12(explicitRoot, ".rig", "task-config.json"));
|
|
1900
|
+
const hasRigConfig = existsSync11(resolve12(explicitRoot, "rig.config.ts"));
|
|
1842
1901
|
if (!hasTaskConfig && !hasRigConfig) {
|
|
1843
1902
|
throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but neither .rig/task-config.json nor rig.config.ts exists there.`);
|
|
1844
1903
|
}
|
|
1845
1904
|
return explicitRoot;
|
|
1846
1905
|
}
|
|
1847
|
-
const projectParent =
|
|
1906
|
+
const projectParent = dirname7(normalizedProjectRoot);
|
|
1848
1907
|
if (basename4(projectParent) === ".worktrees") {
|
|
1849
|
-
const worktreeOwner =
|
|
1850
|
-
const ownerHasGit =
|
|
1851
|
-
const ownerHasTaskConfig =
|
|
1852
|
-
const ownerHasRigConfig =
|
|
1908
|
+
const worktreeOwner = dirname7(projectParent);
|
|
1909
|
+
const ownerHasGit = existsSync11(resolve12(worktreeOwner, ".git"));
|
|
1910
|
+
const ownerHasTaskConfig = existsSync11(resolve12(worktreeOwner, ".rig", "task-config.json"));
|
|
1911
|
+
const ownerHasRigConfig = existsSync11(resolve12(worktreeOwner, "rig.config.ts"));
|
|
1853
1912
|
if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
|
|
1854
1913
|
return worktreeOwner;
|
|
1855
1914
|
}
|
|
@@ -1857,28 +1916,28 @@ function resolveMonorepoRoot(projectRoot) {
|
|
|
1857
1916
|
return normalizedProjectRoot;
|
|
1858
1917
|
}
|
|
1859
1918
|
function resolveRuntimeWorkspaceLayout(workspaceDir) {
|
|
1860
|
-
const root =
|
|
1861
|
-
const rigRoot =
|
|
1862
|
-
const logsDir =
|
|
1863
|
-
const stateDir =
|
|
1864
|
-
const runtimeDir =
|
|
1865
|
-
const binDir =
|
|
1919
|
+
const root = resolve12(workspaceDir);
|
|
1920
|
+
const rigRoot = resolve12(root, ".rig");
|
|
1921
|
+
const logsDir = resolve12(rigRoot, "logs");
|
|
1922
|
+
const stateDir = resolve12(rigRoot, "state");
|
|
1923
|
+
const runtimeDir = resolve12(rigRoot, "runtime");
|
|
1924
|
+
const binDir = resolve12(rigRoot, "bin");
|
|
1866
1925
|
return {
|
|
1867
1926
|
workspaceDir: root,
|
|
1868
1927
|
rigRoot,
|
|
1869
1928
|
stateDir,
|
|
1870
1929
|
logsDir,
|
|
1871
|
-
artifactsRoot:
|
|
1930
|
+
artifactsRoot: resolve12(root, RIG_ARTIFACTS_DIRNAME),
|
|
1872
1931
|
runtimeDir,
|
|
1873
|
-
homeDir:
|
|
1874
|
-
tmpDir:
|
|
1875
|
-
cacheDir:
|
|
1876
|
-
sessionDir:
|
|
1932
|
+
homeDir: resolve12(rigRoot, "home"),
|
|
1933
|
+
tmpDir: resolve12(rigRoot, "tmp"),
|
|
1934
|
+
cacheDir: resolve12(rigRoot, "cache"),
|
|
1935
|
+
sessionDir: resolve12(rigRoot, "session"),
|
|
1877
1936
|
binDir,
|
|
1878
|
-
distDir:
|
|
1879
|
-
pluginBinDir:
|
|
1880
|
-
contextPath:
|
|
1881
|
-
controlPlaneEventsFile:
|
|
1937
|
+
distDir: resolve12(rigRoot, "dist"),
|
|
1938
|
+
pluginBinDir: resolve12(binDir, "plugins"),
|
|
1939
|
+
contextPath: resolve12(rigRoot, "runtime-context.json"),
|
|
1940
|
+
controlPlaneEventsFile: resolve12(logsDir, "control-plane.events.jsonl")
|
|
1882
1941
|
};
|
|
1883
1942
|
}
|
|
1884
1943
|
function resolveActiveRuntimeWorkspaceRoot(monorepoRoot) {
|
|
@@ -1886,14 +1945,14 @@ function resolveActiveRuntimeWorkspaceRoot(monorepoRoot) {
|
|
|
1886
1945
|
if (!explicit) {
|
|
1887
1946
|
throw new Error("No active runtime workspace. Set RIG_TASK_WORKSPACE or provision a task runtime first.");
|
|
1888
1947
|
}
|
|
1889
|
-
return
|
|
1948
|
+
return resolve12(explicit);
|
|
1890
1949
|
}
|
|
1891
1950
|
function resolveRigLayout(projectRoot) {
|
|
1892
1951
|
const monorepoRoot = resolveMonorepoRoot(projectRoot);
|
|
1893
|
-
const definitionRoot =
|
|
1952
|
+
const definitionRoot = resolve12(projectRoot, RIG_DEFINITION_DIRNAME);
|
|
1894
1953
|
const runtimeWorkspaceRoot = resolveActiveRuntimeWorkspaceRoot(monorepoRoot);
|
|
1895
1954
|
const runtimeLayout = resolveRuntimeWorkspaceLayout(runtimeWorkspaceRoot);
|
|
1896
|
-
const policyDir =
|
|
1955
|
+
const policyDir = resolve12(definitionRoot, "policy");
|
|
1897
1956
|
return {
|
|
1898
1957
|
projectRoot,
|
|
1899
1958
|
monorepoRoot,
|
|
@@ -1901,48 +1960,48 @@ function resolveRigLayout(projectRoot) {
|
|
|
1901
1960
|
runtimeWorkspaceRoot,
|
|
1902
1961
|
stateRoot: runtimeLayout.rigRoot,
|
|
1903
1962
|
artifactsRoot: runtimeLayout.artifactsRoot,
|
|
1904
|
-
configPath:
|
|
1905
|
-
taskConfigPath:
|
|
1963
|
+
configPath: resolve12(definitionRoot, "config.sh"),
|
|
1964
|
+
taskConfigPath: resolve12(runtimeWorkspaceRoot, ".rig", "task-config.json"),
|
|
1906
1965
|
policyDir,
|
|
1907
|
-
policyFile:
|
|
1908
|
-
pluginsDir:
|
|
1909
|
-
hooksDir:
|
|
1910
|
-
toolsDir:
|
|
1911
|
-
templatesDir:
|
|
1912
|
-
validationDir:
|
|
1966
|
+
policyFile: resolve12(policyDir, "policy.json"),
|
|
1967
|
+
pluginsDir: resolve12(definitionRoot, "plugins"),
|
|
1968
|
+
hooksDir: resolve12(definitionRoot, "hooks"),
|
|
1969
|
+
toolsDir: resolve12(definitionRoot, "tools"),
|
|
1970
|
+
templatesDir: resolve12(definitionRoot, "templates"),
|
|
1971
|
+
validationDir: resolve12(definitionRoot, "validation"),
|
|
1913
1972
|
stateDir: runtimeLayout.stateDir,
|
|
1914
1973
|
logsDir: runtimeLayout.logsDir,
|
|
1915
|
-
notificationsDir:
|
|
1974
|
+
notificationsDir: resolve12(definitionRoot, "notifications"),
|
|
1916
1975
|
runtimeDir: runtimeLayout.runtimeDir,
|
|
1917
1976
|
distDir: runtimeLayout.distDir,
|
|
1918
1977
|
binDir: runtimeLayout.binDir,
|
|
1919
1978
|
pluginBinDir: runtimeLayout.pluginBinDir,
|
|
1920
|
-
keybindingsPath:
|
|
1979
|
+
keybindingsPath: resolve12(definitionRoot, "keybindings.json"),
|
|
1921
1980
|
controlPlaneEventsFile: runtimeLayout.controlPlaneEventsFile
|
|
1922
1981
|
};
|
|
1923
1982
|
}
|
|
1924
1983
|
|
|
1925
1984
|
// packages/runtime/src/control-plane/native/runtime-native.ts
|
|
1926
1985
|
import { dlopen, ptr, suffix, toBuffer } from "bun:ffi";
|
|
1927
|
-
import { copyFileSync as copyFileSync2, existsSync as
|
|
1986
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync12, mkdirSync as mkdirSync6, renameSync as renameSync2, rmSync as rmSync3, statSync as statSync2 } from "fs";
|
|
1928
1987
|
import { tmpdir as tmpdir4 } from "os";
|
|
1929
|
-
import { dirname as
|
|
1930
|
-
var sharedNativeRuntimeOutputDir =
|
|
1931
|
-
var sharedNativeRuntimeOutputPath =
|
|
1988
|
+
import { dirname as dirname8, resolve as resolve13 } from "path";
|
|
1989
|
+
var sharedNativeRuntimeOutputDir = resolve13(tmpdir4(), "rig-native");
|
|
1990
|
+
var sharedNativeRuntimeOutputPath = resolve13(sharedNativeRuntimeOutputDir, `runtime-native-${process.platform}-${process.arch}.${suffix}`);
|
|
1932
1991
|
var colocatedNativeRuntimeFileName = `runtime-native.${suffix}`;
|
|
1933
1992
|
var nativeRuntimeLibrary = await loadNativeRuntimeLibrary();
|
|
1934
1993
|
async function ensureNativeRuntimeLibraryPath(outputPath = sharedNativeRuntimeOutputPath, options = {}) {
|
|
1935
1994
|
if (await buildNativeRuntimeLibrary(outputPath, options)) {
|
|
1936
1995
|
return outputPath;
|
|
1937
1996
|
}
|
|
1938
|
-
return !options.force &&
|
|
1997
|
+
return !options.force && existsSync12(outputPath) ? outputPath : null;
|
|
1939
1998
|
}
|
|
1940
1999
|
async function loadNativeRuntimeLibrary() {
|
|
1941
2000
|
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
1942
2001
|
return null;
|
|
1943
2002
|
}
|
|
1944
2003
|
for (const candidate of nativeRuntimeLibraryCandidates()) {
|
|
1945
|
-
if (!candidate || !
|
|
2004
|
+
if (!candidate || !existsSync12(candidate)) {
|
|
1946
2005
|
continue;
|
|
1947
2006
|
}
|
|
1948
2007
|
const loaded = tryDlopenNativeRuntimeLibrary(candidate);
|
|
@@ -1958,12 +2017,12 @@ async function loadNativeRuntimeLibrary() {
|
|
|
1958
2017
|
}
|
|
1959
2018
|
function nativePackageLibraryCandidates(fromDir, names) {
|
|
1960
2019
|
const candidates = [];
|
|
1961
|
-
let cursor =
|
|
2020
|
+
let cursor = resolve13(fromDir);
|
|
1962
2021
|
for (let index = 0;index < 8; index += 1) {
|
|
1963
2022
|
for (const name of names) {
|
|
1964
|
-
candidates.push(
|
|
2023
|
+
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));
|
|
1965
2024
|
}
|
|
1966
|
-
const parent =
|
|
2025
|
+
const parent = dirname8(cursor);
|
|
1967
2026
|
if (parent === cursor)
|
|
1968
2027
|
break;
|
|
1969
2028
|
cursor = parent;
|
|
@@ -1972,27 +2031,27 @@ function nativePackageLibraryCandidates(fromDir, names) {
|
|
|
1972
2031
|
}
|
|
1973
2032
|
function nativeRuntimeLibraryCandidates() {
|
|
1974
2033
|
const explicit = process.env.RIG_NATIVE_RUNTIME_LIB?.trim() || "";
|
|
1975
|
-
const execDir = process.execPath?.trim() ?
|
|
2034
|
+
const execDir = process.execPath?.trim() ? dirname8(process.execPath.trim()) : "";
|
|
1976
2035
|
const platformSpecific = `runtime-native-${process.platform}-${process.arch}.${suffix}`;
|
|
1977
2036
|
return [...new Set([
|
|
1978
2037
|
explicit,
|
|
1979
2038
|
...nativePackageLibraryCandidates(import.meta.dir, [colocatedNativeRuntimeFileName, platformSpecific]),
|
|
1980
|
-
execDir ?
|
|
1981
|
-
execDir ?
|
|
1982
|
-
execDir ?
|
|
1983
|
-
execDir ?
|
|
1984
|
-
execDir ?
|
|
1985
|
-
execDir ?
|
|
2039
|
+
execDir ? resolve13(execDir, colocatedNativeRuntimeFileName) : "",
|
|
2040
|
+
execDir ? resolve13(execDir, platformSpecific) : "",
|
|
2041
|
+
execDir ? resolve13(execDir, "..", colocatedNativeRuntimeFileName) : "",
|
|
2042
|
+
execDir ? resolve13(execDir, "..", platformSpecific) : "",
|
|
2043
|
+
execDir ? resolve13(execDir, "lib", colocatedNativeRuntimeFileName) : "",
|
|
2044
|
+
execDir ? resolve13(execDir, "..", "lib", colocatedNativeRuntimeFileName) : "",
|
|
1986
2045
|
sharedNativeRuntimeOutputPath
|
|
1987
2046
|
].filter(Boolean))];
|
|
1988
2047
|
}
|
|
1989
2048
|
function resolveNativeRuntimeSourcePath() {
|
|
1990
2049
|
const explicit = process.env.RIG_NATIVE_RUNTIME_SOURCE?.trim();
|
|
1991
|
-
if (explicit &&
|
|
2050
|
+
if (explicit && existsSync12(explicit)) {
|
|
1992
2051
|
return explicit;
|
|
1993
2052
|
}
|
|
1994
|
-
const bundled =
|
|
1995
|
-
return
|
|
2053
|
+
const bundled = resolve13(import.meta.dir, "../../../native/snapshot.zig");
|
|
2054
|
+
return existsSync12(bundled) ? bundled : null;
|
|
1996
2055
|
}
|
|
1997
2056
|
async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
1998
2057
|
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
@@ -2005,8 +2064,8 @@ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
|
2005
2064
|
}
|
|
2006
2065
|
const tempOutputPath = `${outputPath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
2007
2066
|
try {
|
|
2008
|
-
|
|
2009
|
-
const needsBuild = options.force === true || !
|
|
2067
|
+
mkdirSync6(dirname8(outputPath), { recursive: true });
|
|
2068
|
+
const needsBuild = options.force === true || !existsSync12(outputPath) || statSync2(sourcePath).mtimeMs > statSync2(outputPath).mtimeMs;
|
|
2010
2069
|
if (!needsBuild) {
|
|
2011
2070
|
return true;
|
|
2012
2071
|
}
|
|
@@ -2024,7 +2083,7 @@ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
|
2024
2083
|
stderr: "pipe"
|
|
2025
2084
|
});
|
|
2026
2085
|
const exitCode = await build.exited;
|
|
2027
|
-
if (exitCode !== 0 || !
|
|
2086
|
+
if (exitCode !== 0 || !existsSync12(tempOutputPath)) {
|
|
2028
2087
|
rmSync3(tempOutputPath, { force: true });
|
|
2029
2088
|
return false;
|
|
2030
2089
|
}
|
|
@@ -2154,11 +2213,11 @@ async function runCaptureAsync(command, cwd, env, timeoutMs) {
|
|
|
2154
2213
|
return { exitCode, stdout, stderr };
|
|
2155
2214
|
}
|
|
2156
2215
|
function readJsonFile(path, fallback) {
|
|
2157
|
-
if (!
|
|
2216
|
+
if (!existsSync13(path)) {
|
|
2158
2217
|
return fallback;
|
|
2159
2218
|
}
|
|
2160
2219
|
try {
|
|
2161
|
-
return JSON.parse(
|
|
2220
|
+
return JSON.parse(readFileSync9(path, "utf-8"));
|
|
2162
2221
|
} catch {
|
|
2163
2222
|
return fallback;
|
|
2164
2223
|
}
|
|
@@ -2172,31 +2231,31 @@ function unique(values) {
|
|
|
2172
2231
|
function resolveHarnessPaths(projectRoot) {
|
|
2173
2232
|
const hasRuntimeWorkspace = Boolean(process.env.RIG_TASK_WORKSPACE?.trim());
|
|
2174
2233
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
2175
|
-
const harnessRoot =
|
|
2176
|
-
const stateRoot =
|
|
2234
|
+
const harnessRoot = resolve14(projectRoot, "rig");
|
|
2235
|
+
const stateRoot = resolve14(projectRoot, ".rig");
|
|
2177
2236
|
const layout = hasRuntimeWorkspace ? resolveRigLayout(projectRoot) : null;
|
|
2178
|
-
const stateDir = layout?.stateDir ??
|
|
2179
|
-
const logsDir = layout?.logsDir ??
|
|
2180
|
-
const artifactsDir = layout?.artifactsRoot ??
|
|
2181
|
-
const taskConfigPath = layout?.taskConfigPath ??
|
|
2182
|
-
const binDir = layout?.binDir ??
|
|
2237
|
+
const stateDir = layout?.stateDir ?? resolve14(stateRoot, "state");
|
|
2238
|
+
const logsDir = layout?.logsDir ?? resolve14(stateRoot, "logs");
|
|
2239
|
+
const artifactsDir = layout?.artifactsRoot ?? resolve14(monorepoRoot, "artifacts");
|
|
2240
|
+
const taskConfigPath = layout?.taskConfigPath ?? resolve14(monorepoRoot, ".rig", "task-config.json");
|
|
2241
|
+
const binDir = layout?.binDir ?? resolve14(stateRoot, "bin");
|
|
2183
2242
|
return {
|
|
2184
2243
|
harnessRoot,
|
|
2185
2244
|
stateDir: process.env.RIG_STATE_DIR || stateDir,
|
|
2186
2245
|
artifactsDir,
|
|
2187
2246
|
logsDir: process.env.RIG_LOGS_DIR || logsDir,
|
|
2188
2247
|
binDir,
|
|
2189
|
-
hooksDir:
|
|
2190
|
-
validationDir:
|
|
2248
|
+
hooksDir: resolve14(harnessRoot, "hooks"),
|
|
2249
|
+
validationDir: resolve14(harnessRoot, "validation"),
|
|
2191
2250
|
taskConfigPath,
|
|
2192
|
-
sessionPath: process.env.RIG_SESSION_FILE ||
|
|
2251
|
+
sessionPath: process.env.RIG_SESSION_FILE || resolve14(stateRoot, "session", "session.json"),
|
|
2193
2252
|
monorepoRoot,
|
|
2194
|
-
tsApiTestsDir: process.env.TS_API_TESTS_DIR ||
|
|
2195
|
-
taskRepoCommitsPath:
|
|
2196
|
-
baseRepoPinsPath:
|
|
2197
|
-
failedApproachesPath:
|
|
2198
|
-
agentProfilePath:
|
|
2199
|
-
reviewProfilePath:
|
|
2253
|
+
tsApiTestsDir: process.env.TS_API_TESTS_DIR || resolve14(monorepoRoot, "TSAPITests"),
|
|
2254
|
+
taskRepoCommitsPath: resolve14(stateDir, "task-repo-commits.json"),
|
|
2255
|
+
baseRepoPinsPath: resolve14(stateDir, "base-repo-pins.json"),
|
|
2256
|
+
failedApproachesPath: resolve14(stateDir, "failed_approaches.md"),
|
|
2257
|
+
agentProfilePath: resolve14(stateDir, "agent-profile.json"),
|
|
2258
|
+
reviewProfilePath: resolve14(stateDir, "review-profile.json")
|
|
2200
2259
|
};
|
|
2201
2260
|
}
|
|
2202
2261
|
function normalizeRelativeScopePath(inputPath) {
|
|
@@ -2254,34 +2313,34 @@ function monorepoSearchCandidates(inputPath) {
|
|
|
2254
2313
|
}
|
|
2255
2314
|
|
|
2256
2315
|
// packages/runtime/src/control-plane/state-sync/repo.ts
|
|
2257
|
-
import { existsSync as
|
|
2258
|
-
import { resolve as
|
|
2316
|
+
import { existsSync as existsSync15 } from "fs";
|
|
2317
|
+
import { resolve as resolve16 } from "path";
|
|
2259
2318
|
|
|
2260
2319
|
// packages/runtime/src/control-plane/repos/layout.ts
|
|
2261
|
-
import { existsSync as
|
|
2262
|
-
import { basename as basename5, dirname as
|
|
2320
|
+
import { existsSync as existsSync14 } from "fs";
|
|
2321
|
+
import { basename as basename5, dirname as dirname9, join as join3, resolve as resolve15 } from "path";
|
|
2263
2322
|
function resolveRepoStateDir(projectRoot) {
|
|
2264
|
-
const normalizedProjectRoot =
|
|
2265
|
-
const projectParent =
|
|
2323
|
+
const normalizedProjectRoot = resolve15(projectRoot);
|
|
2324
|
+
const projectParent = dirname9(normalizedProjectRoot);
|
|
2266
2325
|
if (basename5(projectParent) === ".worktrees") {
|
|
2267
|
-
const ownerRoot =
|
|
2268
|
-
const ownerHasRepoMarkers =
|
|
2326
|
+
const ownerRoot = dirname9(projectParent);
|
|
2327
|
+
const ownerHasRepoMarkers = existsSync14(resolve15(ownerRoot, ".git")) || existsSync14(resolve15(ownerRoot, ".rig", "state"));
|
|
2269
2328
|
if (ownerHasRepoMarkers) {
|
|
2270
|
-
return
|
|
2329
|
+
return resolve15(ownerRoot, ".rig", "state");
|
|
2271
2330
|
}
|
|
2272
2331
|
}
|
|
2273
|
-
return
|
|
2332
|
+
return resolve15(projectRoot, ".rig", "state");
|
|
2274
2333
|
}
|
|
2275
2334
|
function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
2276
|
-
const normalizedProjectRoot =
|
|
2335
|
+
const normalizedProjectRoot = resolve15(projectRoot);
|
|
2277
2336
|
const entry = getManagedRepoEntry(repoId);
|
|
2278
2337
|
const stateDir = resolveRepoStateDir(normalizedProjectRoot);
|
|
2279
2338
|
const metadataRelativePath = join3("repos", entry.id);
|
|
2280
|
-
const metadataRoot =
|
|
2339
|
+
const metadataRoot = resolve15(stateDir, metadataRelativePath);
|
|
2281
2340
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
2282
|
-
const runsInsideTaskWorktree = runtimeWorkspace &&
|
|
2341
|
+
const runsInsideTaskWorktree = runtimeWorkspace && resolve15(runtimeWorkspace) === normalizedProjectRoot || basename5(dirname9(normalizedProjectRoot)) === ".worktrees";
|
|
2283
2342
|
const isPrimaryManagedRepo = listManagedRepoEntries()[0]?.id === repoId;
|
|
2284
|
-
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ?
|
|
2343
|
+
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ? resolve15(process.env[entry.checkoutEnvVar].trim()) : resolve15(normalizedProjectRoot, entry.alias);
|
|
2285
2344
|
return {
|
|
2286
2345
|
projectRoot: normalizedProjectRoot,
|
|
2287
2346
|
repoId: entry.id,
|
|
@@ -2289,12 +2348,12 @@ function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
|
2289
2348
|
defaultBranch: entry.defaultBranch,
|
|
2290
2349
|
remoteUrl: entry.remoteEnvVar && process.env[entry.remoteEnvVar]?.trim() ? process.env[entry.remoteEnvVar].trim() : entry.defaultRemoteUrl,
|
|
2291
2350
|
checkoutRoot,
|
|
2292
|
-
worktreesRoot:
|
|
2351
|
+
worktreesRoot: resolve15(checkoutRoot, ".worktrees"),
|
|
2293
2352
|
stateDir,
|
|
2294
2353
|
metadataRoot,
|
|
2295
2354
|
metadataRelativePath,
|
|
2296
|
-
mirrorRoot:
|
|
2297
|
-
mirrorStatePath:
|
|
2355
|
+
mirrorRoot: resolve15(metadataRoot, "mirror.git"),
|
|
2356
|
+
mirrorStatePath: resolve15(metadataRoot, "mirror-state.json"),
|
|
2298
2357
|
mirrorStateRelativePath: join3(metadataRelativePath, "mirror-state.json")
|
|
2299
2358
|
};
|
|
2300
2359
|
}
|
|
@@ -2316,7 +2375,7 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
2316
2375
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
2317
2376
|
try {
|
|
2318
2377
|
const layout = resolveMonorepoRepoLayout(projectRoot);
|
|
2319
|
-
if (
|
|
2378
|
+
if (existsSync15(resolve16(layout.mirrorRoot, "HEAD"))) {
|
|
2320
2379
|
return layout.mirrorRoot;
|
|
2321
2380
|
}
|
|
2322
2381
|
} catch {}
|
|
@@ -2327,8 +2386,8 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
2327
2386
|
var DEFAULT_READ_DEPS = {
|
|
2328
2387
|
fetchRef: nativeFetchRef,
|
|
2329
2388
|
readBlobAtRef: nativeReadBlobAtRef,
|
|
2330
|
-
exists:
|
|
2331
|
-
readFile: (path) =>
|
|
2389
|
+
exists: existsSync16,
|
|
2390
|
+
readFile: (path) => readFileSync10(path, "utf8")
|
|
2332
2391
|
};
|
|
2333
2392
|
function parseIssueStatus(rawStatus) {
|
|
2334
2393
|
const normalized = normalizeTaskLifecycleStatus(rawStatus);
|
|
@@ -2409,12 +2468,12 @@ function shouldPreferLocalTrackerState(options) {
|
|
|
2409
2468
|
if (runtimeContextPath) {
|
|
2410
2469
|
return true;
|
|
2411
2470
|
}
|
|
2412
|
-
return
|
|
2471
|
+
return existsSync16(resolve17(runtimeWorkspace, ".rig", "runtime-context.json"));
|
|
2413
2472
|
}
|
|
2414
2473
|
function readLocalTrackerState(projectRoot, deps) {
|
|
2415
2474
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
2416
|
-
const issuesPath =
|
|
2417
|
-
const taskStatePath =
|
|
2475
|
+
const issuesPath = resolve17(monorepoRoot, ".beads", "issues.jsonl");
|
|
2476
|
+
const taskStatePath = resolve17(monorepoRoot, ".beads", "task-state.json");
|
|
2418
2477
|
return projectSyncedTrackerSnapshot({
|
|
2419
2478
|
source: "local",
|
|
2420
2479
|
issuesBaseOid: null,
|
|
@@ -2476,7 +2535,7 @@ function readValidationDescriptions(projectRoot) {
|
|
|
2476
2535
|
return readValidationDescriptionMap(raw);
|
|
2477
2536
|
}
|
|
2478
2537
|
function readSourceValidationDescriptions(projectRoot) {
|
|
2479
|
-
const rootRaw = readJsonFile(
|
|
2538
|
+
const rootRaw = readJsonFile(resolve18(projectRoot, "rig", "task-config.json"), {});
|
|
2480
2539
|
const sourcePath = findSourceTaskConfigPath(projectRoot);
|
|
2481
2540
|
const sourceRaw = sourcePath ? readJsonFile(sourcePath, {}) : {};
|
|
2482
2541
|
const rootDescriptions = readValidationDescriptionMap(rootRaw);
|
|
@@ -2552,15 +2611,15 @@ function readValidationDescriptionsFromMeta(meta) {
|
|
|
2552
2611
|
return meta.validation_descriptions;
|
|
2553
2612
|
}
|
|
2554
2613
|
function readLocalSourceTaskStateEnvelope(projectRoot) {
|
|
2555
|
-
const taskStatePath =
|
|
2614
|
+
const taskStatePath = resolve18(resolveMonorepoRoot2(projectRoot), ".beads", "task-state.json");
|
|
2556
2615
|
return readTaskStateMetadataEnvelope(readJsonFile(taskStatePath, {}));
|
|
2557
2616
|
}
|
|
2558
2617
|
function readLocalSourceTaskLifecycleStatus(projectRoot, taskId) {
|
|
2559
|
-
const issuesPath =
|
|
2560
|
-
if (!
|
|
2618
|
+
const issuesPath = resolve18(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
2619
|
+
if (!existsSync17(issuesPath)) {
|
|
2561
2620
|
return null;
|
|
2562
2621
|
}
|
|
2563
|
-
for (const line of
|
|
2622
|
+
for (const line of readFileSync11(issuesPath, "utf8").split(/\r?\n/)) {
|
|
2564
2623
|
const trimmed = line.trim();
|
|
2565
2624
|
if (!trimmed) {
|
|
2566
2625
|
continue;
|
|
@@ -2601,25 +2660,25 @@ function lookupTask(projectRoot, input) {
|
|
|
2601
2660
|
function artifactDirForId(projectRoot, id) {
|
|
2602
2661
|
const workspaceDir = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
2603
2662
|
if (workspaceDir) {
|
|
2604
|
-
const worktreeArtifacts =
|
|
2605
|
-
if (
|
|
2663
|
+
const worktreeArtifacts = resolve18(workspaceDir, "artifacts", id);
|
|
2664
|
+
if (existsSync17(worktreeArtifacts) || existsSync17(resolve18(workspaceDir, "artifacts"))) {
|
|
2606
2665
|
return worktreeArtifacts;
|
|
2607
2666
|
}
|
|
2608
2667
|
}
|
|
2609
2668
|
try {
|
|
2610
2669
|
const paths = resolveHarnessPaths(projectRoot);
|
|
2611
|
-
return
|
|
2670
|
+
return resolve18(paths.artifactsDir, id);
|
|
2612
2671
|
} catch {
|
|
2613
|
-
return
|
|
2672
|
+
return resolve18(resolveMonorepoRoot2(projectRoot), "artifacts", id);
|
|
2614
2673
|
}
|
|
2615
2674
|
}
|
|
2616
2675
|
function resolveTaskConfigPath(projectRoot) {
|
|
2617
2676
|
const paths = resolveHarnessPaths(projectRoot);
|
|
2618
|
-
if (
|
|
2677
|
+
if (existsSync17(paths.taskConfigPath)) {
|
|
2619
2678
|
return paths.taskConfigPath;
|
|
2620
2679
|
}
|
|
2621
2680
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
2622
|
-
if (
|
|
2681
|
+
if (existsSync17(candidate)) {
|
|
2623
2682
|
return candidate;
|
|
2624
2683
|
}
|
|
2625
2684
|
}
|
|
@@ -2627,7 +2686,7 @@ function resolveTaskConfigPath(projectRoot) {
|
|
|
2627
2686
|
}
|
|
2628
2687
|
function findSourceTaskConfigPath(projectRoot) {
|
|
2629
2688
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
2630
|
-
if (
|
|
2689
|
+
if (existsSync17(candidate)) {
|
|
2631
2690
|
return candidate;
|
|
2632
2691
|
}
|
|
2633
2692
|
}
|
|
@@ -2640,7 +2699,7 @@ function readAndSyncSourceTaskConfig(projectRoot) {
|
|
|
2640
2699
|
const synced = synchronizeTaskConfigWithTracker(projectRoot, raw);
|
|
2641
2700
|
if (sourcePath && synced.updated) {
|
|
2642
2701
|
try {
|
|
2643
|
-
|
|
2702
|
+
writeFileSync7(sourcePath, `${JSON.stringify(synced.config, null, 2)}
|
|
2644
2703
|
`, "utf-8");
|
|
2645
2704
|
} catch {}
|
|
2646
2705
|
}
|
|
@@ -2692,12 +2751,12 @@ function shouldRefreshAutoSyncedTaskConfigEntry(entry) {
|
|
|
2692
2751
|
return !candidate.role;
|
|
2693
2752
|
}
|
|
2694
2753
|
function readSourceIssueRecords(projectRoot) {
|
|
2695
|
-
const issuesPath =
|
|
2696
|
-
if (!
|
|
2754
|
+
const issuesPath = resolve18(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
2755
|
+
if (!existsSync17(issuesPath)) {
|
|
2697
2756
|
return [];
|
|
2698
2757
|
}
|
|
2699
2758
|
const records = [];
|
|
2700
|
-
for (const line of
|
|
2759
|
+
for (const line of readFileSync11(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
2701
2760
|
const trimmed = line.trim();
|
|
2702
2761
|
if (!trimmed) {
|
|
2703
2762
|
continue;
|
|
@@ -2753,19 +2812,19 @@ function readConfiguredFileTaskConfig(projectRoot) {
|
|
|
2753
2812
|
if (!sourcePath) {
|
|
2754
2813
|
return {};
|
|
2755
2814
|
}
|
|
2756
|
-
const directory =
|
|
2757
|
-
if (!
|
|
2815
|
+
const directory = resolve18(projectRoot, sourcePath);
|
|
2816
|
+
if (!existsSync17(directory)) {
|
|
2758
2817
|
return {};
|
|
2759
2818
|
}
|
|
2760
2819
|
const config = {};
|
|
2761
2820
|
for (const name of readdirSync3(directory)) {
|
|
2762
2821
|
if (!FILE_TASK_PATTERN2.test(name))
|
|
2763
2822
|
continue;
|
|
2764
|
-
const file =
|
|
2823
|
+
const file = resolve18(directory, name);
|
|
2765
2824
|
try {
|
|
2766
2825
|
if (!statSync3(file).isFile())
|
|
2767
2826
|
continue;
|
|
2768
|
-
const raw = JSON.parse(
|
|
2827
|
+
const raw = JSON.parse(readFileSync11(file, "utf8"));
|
|
2769
2828
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
2770
2829
|
continue;
|
|
2771
2830
|
const record = raw;
|
|
@@ -2807,10 +2866,10 @@ function firstStringList2(...candidates) {
|
|
|
2807
2866
|
return [];
|
|
2808
2867
|
}
|
|
2809
2868
|
function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
2810
|
-
const jsonPath =
|
|
2811
|
-
if (
|
|
2869
|
+
const jsonPath = resolve18(projectRoot, "rig.config.json");
|
|
2870
|
+
if (existsSync17(jsonPath)) {
|
|
2812
2871
|
try {
|
|
2813
|
-
const parsed = JSON.parse(
|
|
2872
|
+
const parsed = JSON.parse(readFileSync11(jsonPath, "utf8"));
|
|
2814
2873
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
2815
2874
|
const taskSource = parsed.taskSource;
|
|
2816
2875
|
if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
|
|
@@ -2822,12 +2881,12 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
2822
2881
|
return null;
|
|
2823
2882
|
}
|
|
2824
2883
|
}
|
|
2825
|
-
const tsPath =
|
|
2826
|
-
if (!
|
|
2884
|
+
const tsPath = resolve18(projectRoot, "rig.config.ts");
|
|
2885
|
+
if (!existsSync17(tsPath)) {
|
|
2827
2886
|
return null;
|
|
2828
2887
|
}
|
|
2829
2888
|
try {
|
|
2830
|
-
const source =
|
|
2889
|
+
const source = readFileSync11(tsPath, "utf8");
|
|
2831
2890
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
2832
2891
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
2833
2892
|
if (kind !== "files") {
|
|
@@ -2841,23 +2900,23 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
2841
2900
|
function sourceTaskConfigCandidates(projectRoot) {
|
|
2842
2901
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
2843
2902
|
return [
|
|
2844
|
-
runtimeContext?.monorepoMainRoot ?
|
|
2845
|
-
process.env.MONOREPO_MAIN_ROOT?.trim() ?
|
|
2846
|
-
|
|
2903
|
+
runtimeContext?.monorepoMainRoot ? resolve18(runtimeContext.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
2904
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve18(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
2905
|
+
resolve18(resolveMonorepoRoot2(projectRoot), ".rig", "task-config.json")
|
|
2847
2906
|
].filter(Boolean);
|
|
2848
2907
|
}
|
|
2849
2908
|
|
|
2850
2909
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
2851
|
-
import { existsSync as
|
|
2852
|
-
import { resolve as
|
|
2910
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
2911
|
+
import { resolve as resolve23 } from "path";
|
|
2853
2912
|
|
|
2854
2913
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
2855
|
-
import { existsSync as
|
|
2856
|
-
import { dirname as
|
|
2914
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync8, rmSync as rmSync5, statSync as statSync4 } from "fs";
|
|
2915
|
+
import { dirname as dirname11, resolve as resolve22 } from "path";
|
|
2857
2916
|
|
|
2858
2917
|
// packages/runtime/src/binary-run.ts
|
|
2859
|
-
import { chmodSync as chmodSync2, cpSync, existsSync as
|
|
2860
|
-
import { basename as basename7, dirname as
|
|
2918
|
+
import { chmodSync as chmodSync2, cpSync, existsSync as existsSync18, mkdirSync as mkdirSync7, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
2919
|
+
import { basename as basename7, dirname as dirname10, resolve as resolve19 } from "path";
|
|
2861
2920
|
import { fileURLToPath } from "url";
|
|
2862
2921
|
import { drainMicrotasks, gcAndSweep } from "bun:jsc";
|
|
2863
2922
|
var runtimeBinaryBuildQueue = Promise.resolve();
|
|
@@ -2883,9 +2942,9 @@ async function buildRuntimeBinary(options) {
|
|
|
2883
2942
|
});
|
|
2884
2943
|
}
|
|
2885
2944
|
async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
2886
|
-
const tempBuildDir =
|
|
2887
|
-
const tempOutputPath =
|
|
2888
|
-
|
|
2945
|
+
const tempBuildDir = resolve19(dirname10(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
2946
|
+
const tempOutputPath = resolve19(tempBuildDir, basename7(options.outputPath));
|
|
2947
|
+
mkdirSync7(tempBuildDir, { recursive: true });
|
|
2889
2948
|
await withTemporaryEnv({
|
|
2890
2949
|
...options.env,
|
|
2891
2950
|
...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
|
|
@@ -2910,7 +2969,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
2910
2969
|
`);
|
|
2911
2970
|
throw new Error(`Failed to build ${options.entrypoint}: ${details || "Bun.build() returned errors"}`);
|
|
2912
2971
|
}
|
|
2913
|
-
if (!
|
|
2972
|
+
if (!existsSync18(tempOutputPath)) {
|
|
2914
2973
|
const emitted = buildResult.outputs.map((output) => output.path).join(", ") || "(none)";
|
|
2915
2974
|
throw new Error(`Failed to build ${options.entrypoint}: Bun.build() did not emit ${tempOutputPath}. Emitted: ${emitted}`);
|
|
2916
2975
|
}
|
|
@@ -2942,8 +3001,8 @@ function runtimeBinaryCacheManifestPath(outputPath) {
|
|
|
2942
3001
|
function resolveRuntimeBinaryBuildOptions(options) {
|
|
2943
3002
|
return {
|
|
2944
3003
|
...options,
|
|
2945
|
-
entrypoint:
|
|
2946
|
-
outputPath:
|
|
3004
|
+
entrypoint: resolve19(options.cwd, options.sourcePath),
|
|
3005
|
+
outputPath: resolve19(options.outputPath)
|
|
2947
3006
|
};
|
|
2948
3007
|
}
|
|
2949
3008
|
function shouldUseRuntimeBinaryBuildWorker() {
|
|
@@ -2957,7 +3016,7 @@ function shouldUseRuntimeBinaryBuildWorker() {
|
|
|
2957
3016
|
}
|
|
2958
3017
|
async function buildRuntimeBinaryViaWorker(options) {
|
|
2959
3018
|
const workerSourcePath = resolveRuntimeBinaryBuildWorkerSourcePath(options);
|
|
2960
|
-
if (!workerSourcePath || !
|
|
3019
|
+
if (!workerSourcePath || !existsSync18(workerSourcePath)) {
|
|
2961
3020
|
await buildRuntimeBinaryInProcess(options, {
|
|
2962
3021
|
manifestPath: runtimeBinaryCacheManifestPath(options.outputPath),
|
|
2963
3022
|
buildKey: createRuntimeBinaryBuildKey({
|
|
@@ -2994,7 +3053,7 @@ async function buildRuntimeBinaryViaWorker(options) {
|
|
|
2994
3053
|
}
|
|
2995
3054
|
}
|
|
2996
3055
|
function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
|
|
2997
|
-
return
|
|
3056
|
+
return resolve19(dirname10(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
2998
3057
|
}
|
|
2999
3058
|
function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
3000
3059
|
const envRoots = [
|
|
@@ -3003,13 +3062,13 @@ function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
|
3003
3062
|
process.env.PROJECT_RIG_ROOT?.trim()
|
|
3004
3063
|
].filter(Boolean);
|
|
3005
3064
|
for (const root of envRoots) {
|
|
3006
|
-
const candidate =
|
|
3007
|
-
if (
|
|
3065
|
+
const candidate = resolve19(root, "packages/runtime/src/binary-build-worker.ts");
|
|
3066
|
+
if (existsSync18(candidate)) {
|
|
3008
3067
|
return candidate;
|
|
3009
3068
|
}
|
|
3010
3069
|
}
|
|
3011
|
-
const localCandidate =
|
|
3012
|
-
return
|
|
3070
|
+
const localCandidate = resolve19(import.meta.dir, "binary-build-worker.ts");
|
|
3071
|
+
return existsSync18(localCandidate) ? localCandidate : null;
|
|
3013
3072
|
}
|
|
3014
3073
|
function resolveRuntimeBinaryBuildWorkerInvocation() {
|
|
3015
3074
|
const bunPath = Bun.which("bun");
|
|
@@ -3045,7 +3104,7 @@ function createRuntimeBinaryBuildKey(input) {
|
|
|
3045
3104
|
});
|
|
3046
3105
|
}
|
|
3047
3106
|
async function isRuntimeBinaryBuildFresh(input) {
|
|
3048
|
-
if (!
|
|
3107
|
+
if (!existsSync18(input.outputPath) || !existsSync18(input.manifestPath)) {
|
|
3049
3108
|
return false;
|
|
3050
3109
|
}
|
|
3051
3110
|
let manifest = null;
|
|
@@ -3058,7 +3117,7 @@ async function isRuntimeBinaryBuildFresh(input) {
|
|
|
3058
3117
|
return false;
|
|
3059
3118
|
}
|
|
3060
3119
|
for (const [filePath, expectedDigest] of Object.entries(manifest.inputs || {})) {
|
|
3061
|
-
if (!
|
|
3120
|
+
if (!existsSync18(filePath)) {
|
|
3062
3121
|
return false;
|
|
3063
3122
|
}
|
|
3064
3123
|
if (await sha256File(filePath) !== expectedDigest) {
|
|
@@ -3071,7 +3130,7 @@ async function writeRuntimeBinaryCacheManifest(input) {
|
|
|
3071
3130
|
const inputs = {};
|
|
3072
3131
|
for (const inputPath of Object.keys(input.metafile?.inputs || {}).sort()) {
|
|
3073
3132
|
const normalized = normalizeBuildInputPath(input.cwd, inputPath);
|
|
3074
|
-
if (!normalized || !
|
|
3133
|
+
if (!normalized || !existsSync18(normalized)) {
|
|
3075
3134
|
continue;
|
|
3076
3135
|
}
|
|
3077
3136
|
inputs[normalized] = await sha256File(normalized);
|
|
@@ -3094,7 +3153,7 @@ function normalizeBuildInputPath(cwd, inputPath) {
|
|
|
3094
3153
|
if (inputPath.startsWith("<")) {
|
|
3095
3154
|
return null;
|
|
3096
3155
|
}
|
|
3097
|
-
return
|
|
3156
|
+
return resolve19(cwd, inputPath);
|
|
3098
3157
|
}
|
|
3099
3158
|
async function sha256File(path) {
|
|
3100
3159
|
const hasher = new Bun.CryptoHasher("sha256");
|
|
@@ -3110,8 +3169,8 @@ function sortRecord(value) {
|
|
|
3110
3169
|
async function runSerializedRuntimeBinaryBuild(action) {
|
|
3111
3170
|
const previous = runtimeBinaryBuildQueue;
|
|
3112
3171
|
let release;
|
|
3113
|
-
runtimeBinaryBuildQueue = new Promise((
|
|
3114
|
-
release =
|
|
3172
|
+
runtimeBinaryBuildQueue = new Promise((resolve20) => {
|
|
3173
|
+
release = resolve20;
|
|
3115
3174
|
});
|
|
3116
3175
|
await previous;
|
|
3117
3176
|
try {
|
|
@@ -3156,11 +3215,11 @@ async function withTemporaryCwd(cwd, action) {
|
|
|
3156
3215
|
}
|
|
3157
3216
|
|
|
3158
3217
|
// packages/runtime/src/control-plane/runtime/provisioning-env.ts
|
|
3159
|
-
import { delimiter, resolve as
|
|
3218
|
+
import { delimiter, resolve as resolve21 } from "path";
|
|
3160
3219
|
|
|
3161
3220
|
// packages/runtime/src/control-plane/runtime/runtime-paths.ts
|
|
3162
|
-
import { existsSync as
|
|
3163
|
-
import { resolve as
|
|
3221
|
+
import { existsSync as existsSync19, readdirSync as readdirSync4, realpathSync } from "fs";
|
|
3222
|
+
import { resolve as resolve20 } from "path";
|
|
3164
3223
|
|
|
3165
3224
|
// packages/runtime/src/control-plane/runtime/sandbox/utils.ts
|
|
3166
3225
|
function uniq(values) {
|
|
@@ -3178,7 +3237,7 @@ function resolveBunBinaryPath() {
|
|
|
3178
3237
|
}
|
|
3179
3238
|
const home = process.env.HOME?.trim();
|
|
3180
3239
|
const fallbackCandidates = [
|
|
3181
|
-
home ?
|
|
3240
|
+
home ? resolve20(home, ".bun/bin/bun") : "",
|
|
3182
3241
|
"/opt/homebrew/bin/bun",
|
|
3183
3242
|
"/usr/local/bin/bun",
|
|
3184
3243
|
"/usr/bin/bun"
|
|
@@ -3206,8 +3265,8 @@ function resolveClaudeBinaryPath() {
|
|
|
3206
3265
|
}
|
|
3207
3266
|
const home = process.env.HOME?.trim();
|
|
3208
3267
|
const fallbackCandidates = [
|
|
3209
|
-
home ?
|
|
3210
|
-
home ?
|
|
3268
|
+
home ? resolve20(home, ".local/bin/claude") : "",
|
|
3269
|
+
home ? resolve20(home, ".local/share/claude/local/claude") : "",
|
|
3211
3270
|
"/opt/homebrew/bin/claude",
|
|
3212
3271
|
"/usr/local/bin/claude",
|
|
3213
3272
|
"/usr/bin/claude"
|
|
@@ -3221,51 +3280,51 @@ function resolveClaudeBinaryPath() {
|
|
|
3221
3280
|
throw new Error("claude not found in PATH");
|
|
3222
3281
|
}
|
|
3223
3282
|
function resolveBunInstallDir(bunBinaryPath = resolveBunBinaryPath()) {
|
|
3224
|
-
return
|
|
3283
|
+
return resolve20(bunBinaryPath, "../..");
|
|
3225
3284
|
}
|
|
3226
3285
|
function resolveClaudeInstallDir() {
|
|
3227
3286
|
const realPath = resolveClaudeBinaryPath();
|
|
3228
|
-
return
|
|
3287
|
+
return resolve20(realPath, "..");
|
|
3229
3288
|
}
|
|
3230
3289
|
function resolveNodeInstallDir() {
|
|
3231
3290
|
const preferredNode = resolvePreferredNodeBinary();
|
|
3232
3291
|
if (!preferredNode)
|
|
3233
3292
|
return null;
|
|
3234
3293
|
const explicitNode = process.env.RIG_NODE_BIN?.trim();
|
|
3235
|
-
if (explicitNode &&
|
|
3236
|
-
return preferredNode.endsWith("/bin/node") ?
|
|
3294
|
+
if (explicitNode && resolve20(explicitNode) === resolve20(preferredNode)) {
|
|
3295
|
+
return preferredNode.endsWith("/bin/node") ? resolve20(preferredNode, "../..") : resolve20(preferredNode, "..");
|
|
3237
3296
|
}
|
|
3238
3297
|
try {
|
|
3239
3298
|
const realPath = realpathSync(preferredNode);
|
|
3240
3299
|
if (realPath.endsWith("/bin/node")) {
|
|
3241
|
-
return
|
|
3300
|
+
return resolve20(realPath, "../..");
|
|
3242
3301
|
}
|
|
3243
|
-
return
|
|
3302
|
+
return resolve20(realPath, "..");
|
|
3244
3303
|
} catch {
|
|
3245
|
-
return
|
|
3304
|
+
return resolve20(preferredNode, "..");
|
|
3246
3305
|
}
|
|
3247
3306
|
}
|
|
3248
3307
|
function resolvePreferredNodeBinary() {
|
|
3249
3308
|
const candidates = [];
|
|
3250
3309
|
const envNode = process.env.RIG_NODE_BIN?.trim();
|
|
3251
3310
|
if (envNode) {
|
|
3252
|
-
const explicit =
|
|
3253
|
-
if (
|
|
3311
|
+
const explicit = resolve20(envNode);
|
|
3312
|
+
if (existsSync19(explicit)) {
|
|
3254
3313
|
return explicit;
|
|
3255
3314
|
}
|
|
3256
3315
|
}
|
|
3257
3316
|
const nvmBin = process.env.NVM_BIN?.trim();
|
|
3258
3317
|
if (nvmBin) {
|
|
3259
|
-
candidates.push(
|
|
3318
|
+
candidates.push(resolve20(nvmBin, "node"));
|
|
3260
3319
|
}
|
|
3261
3320
|
const home = process.env.HOME?.trim();
|
|
3262
3321
|
if (home) {
|
|
3263
|
-
const nvmVersionsDir =
|
|
3264
|
-
if (
|
|
3322
|
+
const nvmVersionsDir = resolve20(home, ".nvm/versions/node");
|
|
3323
|
+
if (existsSync19(nvmVersionsDir)) {
|
|
3265
3324
|
try {
|
|
3266
3325
|
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/, "")));
|
|
3267
3326
|
for (const versionDir of versionDirs) {
|
|
3268
|
-
candidates.push(
|
|
3327
|
+
candidates.push(resolve20(nvmVersionsDir, versionDir, "bin/node"));
|
|
3269
3328
|
}
|
|
3270
3329
|
} catch {}
|
|
3271
3330
|
}
|
|
@@ -3274,8 +3333,8 @@ function resolvePreferredNodeBinary() {
|
|
|
3274
3333
|
if (whichNode) {
|
|
3275
3334
|
candidates.push(whichNode);
|
|
3276
3335
|
}
|
|
3277
|
-
const deduped = uniq(candidates.map((candidate) =>
|
|
3278
|
-
const existing = deduped.filter((candidate) =>
|
|
3336
|
+
const deduped = uniq(candidates.map((candidate) => resolve20(candidate)));
|
|
3337
|
+
const existing = deduped.filter((candidate) => existsSync19(candidate));
|
|
3279
3338
|
if (existing.length === 0) {
|
|
3280
3339
|
return null;
|
|
3281
3340
|
}
|
|
@@ -3289,7 +3348,7 @@ function resolvePreferredNodeBinary() {
|
|
|
3289
3348
|
return existing[0] ?? null;
|
|
3290
3349
|
}
|
|
3291
3350
|
function inferNodeMajor(nodeBinaryPath) {
|
|
3292
|
-
const normalized =
|
|
3351
|
+
const normalized = resolve20(nodeBinaryPath).replace(/\\/g, "/");
|
|
3293
3352
|
const match = normalized.match(/(?:^|\/)(?:node-)?v?(\d+)\.\d+\.\d+(?:\/|$)/);
|
|
3294
3353
|
if (!match) {
|
|
3295
3354
|
return null;
|
|
@@ -3301,8 +3360,8 @@ function normalizeExecutablePath(candidate) {
|
|
|
3301
3360
|
if (!candidate) {
|
|
3302
3361
|
return "";
|
|
3303
3362
|
}
|
|
3304
|
-
const normalized =
|
|
3305
|
-
if (!
|
|
3363
|
+
const normalized = resolve20(candidate);
|
|
3364
|
+
if (!existsSync19(normalized)) {
|
|
3306
3365
|
return "";
|
|
3307
3366
|
}
|
|
3308
3367
|
try {
|
|
@@ -3312,7 +3371,7 @@ function normalizeExecutablePath(candidate) {
|
|
|
3312
3371
|
}
|
|
3313
3372
|
}
|
|
3314
3373
|
function looksLikeRuntimeGateway(candidate) {
|
|
3315
|
-
const normalized =
|
|
3374
|
+
const normalized = resolve20(candidate).replace(/\\/g, "/");
|
|
3316
3375
|
return normalized.includes("/.rig/bin/") || normalized.endsWith("/rig-shell") || normalized.endsWith("/rig-agent");
|
|
3317
3376
|
}
|
|
3318
3377
|
|
|
@@ -3333,7 +3392,7 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
3333
3392
|
try {
|
|
3334
3393
|
return resolveClaudeInstallDir();
|
|
3335
3394
|
} catch {
|
|
3336
|
-
return
|
|
3395
|
+
return resolve21(claudeBinary, "..");
|
|
3337
3396
|
}
|
|
3338
3397
|
})() : "";
|
|
3339
3398
|
const nodeDir = resolveNodeInstallDir();
|
|
@@ -3343,8 +3402,8 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
3343
3402
|
`${bunDir}/bin`,
|
|
3344
3403
|
claudeDir,
|
|
3345
3404
|
nodeDir ? `${nodeDir}/bin` : "",
|
|
3346
|
-
realHome ?
|
|
3347
|
-
realHome ?
|
|
3405
|
+
realHome ? resolve21(realHome, ".local/bin") : "",
|
|
3406
|
+
realHome ? resolve21(realHome, ".cargo/bin") : "",
|
|
3348
3407
|
...inheritedPath,
|
|
3349
3408
|
"/usr/local/bin",
|
|
3350
3409
|
"/usr/local/sbin",
|
|
@@ -3375,9 +3434,9 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
3375
3434
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
3376
3435
|
function resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext) {
|
|
3377
3436
|
if (runtimeContext) {
|
|
3378
|
-
return
|
|
3437
|
+
return resolve22(runtimeContext.binDir, "validators", binaryName);
|
|
3379
3438
|
}
|
|
3380
|
-
return
|
|
3439
|
+
return resolve22(resolveHarnessPaths(projectRoot).binDir, "validators", binaryName);
|
|
3381
3440
|
}
|
|
3382
3441
|
async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
3383
3442
|
const match = checkId.match(/^([a-z][\w-]*):([a-z][\w-]*)$/);
|
|
@@ -3392,19 +3451,19 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
3392
3451
|
const binaryName = `${category}-${check}`;
|
|
3393
3452
|
const binaryPath = resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
3394
3453
|
const hostProjectRoot = runtimeContext?.hostProjectRoot?.trim() || projectRoot;
|
|
3395
|
-
const sourcePath =
|
|
3396
|
-
if (!
|
|
3454
|
+
const sourcePath = resolve22(hostProjectRoot, "packages/runtime/src/control-plane/validators", category, `${check}.ts`);
|
|
3455
|
+
if (!existsSync20(sourcePath)) {
|
|
3397
3456
|
return null;
|
|
3398
3457
|
}
|
|
3399
3458
|
const sourceMtime = statSync4(sourcePath).mtimeMs;
|
|
3400
|
-
const binaryExists =
|
|
3459
|
+
const binaryExists = existsSync20(binaryPath);
|
|
3401
3460
|
const binaryMtime = binaryExists ? statSync4(binaryPath).mtimeMs : 0;
|
|
3402
3461
|
if (!binaryExists || sourceMtime > binaryMtime) {
|
|
3403
3462
|
if (binaryExists) {
|
|
3404
3463
|
rmSync5(binaryPath, { force: true });
|
|
3405
3464
|
rmSync5(`${binaryPath}.build-manifest.json`, { force: true });
|
|
3406
3465
|
}
|
|
3407
|
-
|
|
3466
|
+
mkdirSync8(dirname11(binaryPath), { recursive: true });
|
|
3408
3467
|
await buildRuntimeBinary({
|
|
3409
3468
|
sourcePath: `packages/runtime/src/control-plane/validators/${category}/${check}.ts`,
|
|
3410
3469
|
outputPath: binaryPath,
|
|
@@ -3413,7 +3472,7 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
3413
3472
|
env: runtimeProvisioningEnv()
|
|
3414
3473
|
});
|
|
3415
3474
|
}
|
|
3416
|
-
return
|
|
3475
|
+
return existsSync20(binaryPath) ? binaryPath : null;
|
|
3417
3476
|
}
|
|
3418
3477
|
|
|
3419
3478
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
@@ -3450,20 +3509,20 @@ async function readTaskSourceValidation(projectRoot, taskId) {
|
|
|
3450
3509
|
function resolveValidationPaths(projectRoot, taskId, runtimeContext) {
|
|
3451
3510
|
if (runtimeContext) {
|
|
3452
3511
|
return {
|
|
3453
|
-
taskLogDir:
|
|
3454
|
-
artifactDir:
|
|
3512
|
+
taskLogDir: resolve23(runtimeContext.logsDir, taskId),
|
|
3513
|
+
artifactDir: resolve23(runtimeContext.workspaceDir, "artifacts", taskId)
|
|
3455
3514
|
};
|
|
3456
3515
|
}
|
|
3457
3516
|
const paths = resolveHarnessPaths(projectRoot);
|
|
3458
3517
|
return {
|
|
3459
|
-
taskLogDir:
|
|
3460
|
-
artifactDir:
|
|
3518
|
+
taskLogDir: resolve23(paths.logsDir, taskId),
|
|
3519
|
+
artifactDir: resolve23(paths.artifactsDir, taskId)
|
|
3461
3520
|
};
|
|
3462
3521
|
}
|
|
3463
3522
|
async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext) {
|
|
3464
3523
|
const binaryName = checkId.replace(":", "-");
|
|
3465
3524
|
const binaryPath = await ensureValidatorBinary(projectRoot, checkId, runtimeContext) ?? resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
3466
|
-
if (!
|
|
3525
|
+
if (!existsSync21(binaryPath)) {
|
|
3467
3526
|
return {
|
|
3468
3527
|
result: {
|
|
3469
3528
|
id: checkId,
|
|
@@ -3474,7 +3533,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
3474
3533
|
};
|
|
3475
3534
|
}
|
|
3476
3535
|
const validatorCwd = runtimeContext?.workspaceDir || resolveMonorepoRoot(projectRoot);
|
|
3477
|
-
const runtimeShellPath = runtimeContext ?
|
|
3536
|
+
const runtimeShellPath = runtimeContext ? resolve23(runtimeContext.binDir, "rig-shell") : "";
|
|
3478
3537
|
const monorepoMainRoot = runtimeContext?.monorepoMainRoot || process.env.MONOREPO_MAIN_ROOT?.trim() || resolveMonorepoRoot(projectRoot);
|
|
3479
3538
|
const validatorEnv = {
|
|
3480
3539
|
PROJECT_RIG_ROOT: runtimeContext?.hostProjectRoot || projectRoot,
|
|
@@ -3489,7 +3548,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
3489
3548
|
validatorEnv.RIG_LOGS_DIR = runtimeContext.logsDir;
|
|
3490
3549
|
validatorEnv.RIG_RUNTIME_BIN_DIR = runtimeContext.binDir;
|
|
3491
3550
|
}
|
|
3492
|
-
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath &&
|
|
3551
|
+
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath && existsSync21(runtimeShellPath) ? [runtimeShellPath, "run-binary", binaryPath] : [binaryPath], validatorCwd, validatorEnv);
|
|
3493
3552
|
try {
|
|
3494
3553
|
const result = JSON.parse(stdout.trim());
|
|
3495
3554
|
return { result, exitCode };
|
|
@@ -3529,8 +3588,8 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
3529
3588
|
const configuredValidation = stringArray(taskConfig[taskId]?.validation);
|
|
3530
3589
|
const commands = resolvedContext?.validation?.length ? resolvedContext.validation : configuredValidation.length > 0 ? configuredValidation : sourceValidation.validation;
|
|
3531
3590
|
const { taskLogDir, artifactDir } = resolveValidationPaths(projectRoot, taskId, resolvedContext);
|
|
3532
|
-
|
|
3533
|
-
|
|
3591
|
+
mkdirSync9(taskLogDir, { recursive: true });
|
|
3592
|
+
mkdirSync9(artifactDir, { recursive: true });
|
|
3534
3593
|
if (commands.length === 0) {
|
|
3535
3594
|
const skipped = {
|
|
3536
3595
|
status: "skipped",
|
|
@@ -3539,7 +3598,7 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
3539
3598
|
failed: 0,
|
|
3540
3599
|
categories: []
|
|
3541
3600
|
};
|
|
3542
|
-
|
|
3601
|
+
writeFileSync9(resolve23(artifactDir, "validation-summary.json"), `${JSON.stringify(skipped, null, 2)}
|
|
3543
3602
|
`, "utf-8");
|
|
3544
3603
|
return skipped;
|
|
3545
3604
|
}
|
|
@@ -3574,18 +3633,18 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
3574
3633
|
exit_code: 2,
|
|
3575
3634
|
duration_seconds: 0
|
|
3576
3635
|
});
|
|
3577
|
-
const logFile2 =
|
|
3578
|
-
|
|
3579
|
-
|
|
3636
|
+
const logFile2 = resolve23(taskLogDir, `invalid-entry-validation.log`);
|
|
3637
|
+
mkdirSync9(taskLogDir, { recursive: true });
|
|
3638
|
+
writeFileSync9(logFile2, `=== ${nowIso()} :: ${cmd} ===
|
|
3580
3639
|
Invalid validation entry: not a check-ID. All entries must use format "category:check-name".
|
|
3581
3640
|
`, "utf-8");
|
|
3582
3641
|
continue;
|
|
3583
3642
|
}
|
|
3584
3643
|
const { result, exitCode } = await dispatchValidator(cmd, effectiveRegistry, validatorCtx, (id) => runValidatorBinary(projectRoot, taskId, id, resolvedContext));
|
|
3585
3644
|
const durationSeconds = Math.max(0, Math.round((Date.now() - startedAt) / 1000));
|
|
3586
|
-
const logFile =
|
|
3587
|
-
|
|
3588
|
-
|
|
3645
|
+
const logFile = resolve23(taskLogDir, `${cmd.replace(":", "-")}-validation.log`);
|
|
3646
|
+
mkdirSync9(taskLogDir, { recursive: true });
|
|
3647
|
+
writeFileSync9(logFile, `=== ${nowIso()} :: ${cmd} ===
|
|
3589
3648
|
${JSON.stringify(result, null, 2)}
|
|
3590
3649
|
`, "utf-8");
|
|
3591
3650
|
if (result.passed) {
|
|
@@ -3607,15 +3666,15 @@ ${JSON.stringify(result, null, 2)}
|
|
|
3607
3666
|
failed,
|
|
3608
3667
|
categories
|
|
3609
3668
|
};
|
|
3610
|
-
|
|
3611
|
-
|
|
3669
|
+
mkdirSync9(artifactDir, { recursive: true });
|
|
3670
|
+
writeFileSync9(resolve23(artifactDir, "validation-summary.json"), `${JSON.stringify(summary, null, 2)}
|
|
3612
3671
|
`, "utf-8");
|
|
3613
3672
|
return summary;
|
|
3614
3673
|
}
|
|
3615
3674
|
|
|
3616
3675
|
// packages/runtime/src/control-plane/native/verifier.ts
|
|
3617
|
-
import { existsSync as
|
|
3618
|
-
import { resolve as
|
|
3676
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
|
|
3677
|
+
import { resolve as resolve24 } from "path";
|
|
3619
3678
|
|
|
3620
3679
|
// packages/runtime/src/control-plane/native/pr-review-gate.ts
|
|
3621
3680
|
function parseJsonObject(value) {
|
|
@@ -4866,11 +4925,11 @@ async function verifyTask(options) {
|
|
|
4866
4925
|
const taskId = options.taskId;
|
|
4867
4926
|
const normalizedTaskId = lookupTask(options.projectRoot, taskId);
|
|
4868
4927
|
const artifactDir = artifactDirForId(options.projectRoot, taskId);
|
|
4869
|
-
|
|
4870
|
-
const validationSummaryPath =
|
|
4871
|
-
const reviewFeedbackPath =
|
|
4872
|
-
const reviewStatePath =
|
|
4873
|
-
const greptileRawPath =
|
|
4928
|
+
mkdirSync10(artifactDir, { recursive: true });
|
|
4929
|
+
const validationSummaryPath = resolve24(artifactDir, "validation-summary.json");
|
|
4930
|
+
const reviewFeedbackPath = resolve24(artifactDir, "review-feedback.md");
|
|
4931
|
+
const reviewStatePath = resolve24(artifactDir, "review-state.json");
|
|
4932
|
+
const greptileRawPath = resolve24(artifactDir, "review-greptile-raw.json");
|
|
4874
4933
|
const prStates = readPrMetadata(options.projectRoot, taskId);
|
|
4875
4934
|
const prState = prStates[0] || null;
|
|
4876
4935
|
const localReasons = [];
|
|
@@ -4882,7 +4941,7 @@ async function verifyTask(options) {
|
|
|
4882
4941
|
if (!normalizedTaskId && !await hasConfiguredSourceTask(options.projectRoot, taskId)) {
|
|
4883
4942
|
localReasons.push(`[Task Config] Unknown task id '${taskId}' in task-config or configured task source.`);
|
|
4884
4943
|
}
|
|
4885
|
-
if (!
|
|
4944
|
+
if (!existsSync22(validationSummaryPath)) {
|
|
4886
4945
|
localReasons.push(`[Artifact Quality] validation-summary.json not found at ${validationSummaryPath}.`);
|
|
4887
4946
|
} else {
|
|
4888
4947
|
const summary = await parseValidationSummary(validationSummaryPath);
|
|
@@ -4891,13 +4950,13 @@ async function verifyTask(options) {
|
|
|
4891
4950
|
}
|
|
4892
4951
|
}
|
|
4893
4952
|
for (const file of ["task-result.json", "decision-log.md", "next-actions.md", "changed-files.txt"]) {
|
|
4894
|
-
const requiredPath =
|
|
4895
|
-
if (!
|
|
4953
|
+
const requiredPath = resolve24(artifactDir, file);
|
|
4954
|
+
if (!existsSync22(requiredPath)) {
|
|
4896
4955
|
localReasons.push(`[Artifact Quality] Missing required artifact file: ${requiredPath}`);
|
|
4897
4956
|
}
|
|
4898
4957
|
}
|
|
4899
|
-
const taskResultPath =
|
|
4900
|
-
if (
|
|
4958
|
+
const taskResultPath = resolve24(artifactDir, "task-result.json");
|
|
4959
|
+
if (existsSync22(taskResultPath)) {
|
|
4901
4960
|
const taskResult = await readJsonFile2(taskResultPath);
|
|
4902
4961
|
const artifactStatus = typeof taskResult?.status === "string" ? taskResult.status.trim().toLowerCase() : "";
|
|
4903
4962
|
if (artifactStatus === "partial") {
|
|
@@ -4910,8 +4969,8 @@ async function verifyTask(options) {
|
|
|
4910
4969
|
localReasons.push("[Artifact Quality] task-result.json next actions indicate remaining implementation scope.");
|
|
4911
4970
|
}
|
|
4912
4971
|
}
|
|
4913
|
-
const nextActionsPath =
|
|
4914
|
-
if (
|
|
4972
|
+
const nextActionsPath = resolve24(artifactDir, "next-actions.md");
|
|
4973
|
+
if (existsSync22(nextActionsPath)) {
|
|
4915
4974
|
const nextActionsContent = await Bun.file(nextActionsPath).text();
|
|
4916
4975
|
if (nextActionsContent.includes("TODO: Replace this scaffold") || nextActionsContent.includes("bd-<downstream-task-id>")) {
|
|
4917
4976
|
localReasons.push("[Artifact Quality] next-actions.md still contains scaffold placeholder text. Replace with real recommendations.");
|
|
@@ -4942,7 +5001,7 @@ async function verifyTask(options) {
|
|
|
4942
5001
|
aiReasons.push(`[AI Review] Required mode needs a completed Greptile approval; current verdict is ${ai.verdict}.`);
|
|
4943
5002
|
}
|
|
4944
5003
|
if (persistArtifacts && ai.rawResponse) {
|
|
4945
|
-
|
|
5004
|
+
writeFileSync10(greptileRawPath, `${ai.rawResponse}
|
|
4946
5005
|
`, "utf-8");
|
|
4947
5006
|
}
|
|
4948
5007
|
} else if (!options.skipAiReview && reviewMode === "off") {
|
|
@@ -5185,7 +5244,7 @@ function evaluateSourceCloseoutChecks(prState, prLabel) {
|
|
|
5185
5244
|
if (!Array.isArray(checks) || checks.length === 0) {
|
|
5186
5245
|
return [`[Source Issue] PR ${prLabel} must have green check evidence before completion.`];
|
|
5187
5246
|
}
|
|
5188
|
-
const ciGate = evaluatePullRequestCiChecks(checks, "PR", 0);
|
|
5247
|
+
const ciGate = evaluatePullRequestCiChecks(checks, "PR", 0, { mergeStateStatus: prState.mergeStateStatus });
|
|
5189
5248
|
if (ciGate.verdict === "APPROVE") {
|
|
5190
5249
|
return [];
|
|
5191
5250
|
}
|
|
@@ -5281,7 +5340,7 @@ function isAcceptedValidationSummary(summary) {
|
|
|
5281
5340
|
return summary.status === "skipped" && summary.total === 0 && summary.failed === 0;
|
|
5282
5341
|
}
|
|
5283
5342
|
async function loadReviewMode(reviewProfilePath, fallback) {
|
|
5284
|
-
const parsed =
|
|
5343
|
+
const parsed = existsSync22(reviewProfilePath) ? await readJsonFile2(reviewProfilePath) : null;
|
|
5285
5344
|
const mode = parsed?.mode;
|
|
5286
5345
|
if (mode === "off" || mode === "advisory" || mode === "required") {
|
|
5287
5346
|
return mode;
|
|
@@ -5292,7 +5351,7 @@ async function loadReviewMode(reviewProfilePath, fallback) {
|
|
|
5292
5351
|
return "advisory";
|
|
5293
5352
|
}
|
|
5294
5353
|
async function loadReviewProvider(reviewProfilePath, fallback) {
|
|
5295
|
-
const parsed =
|
|
5354
|
+
const parsed = existsSync22(reviewProfilePath) ? await readJsonFile2(reviewProfilePath) : null;
|
|
5296
5355
|
const provider = parsed?.provider;
|
|
5297
5356
|
if (typeof provider === "string" && provider.trim().length > 0) {
|
|
5298
5357
|
return provider;
|
|
@@ -5451,7 +5510,7 @@ function writeFeedbackFile(options) {
|
|
|
5451
5510
|
if (options.aiRawFeedback) {
|
|
5452
5511
|
lines.push("## Raw Reviewer Feedback", "", "```text", options.aiRawFeedback, "```", "");
|
|
5453
5512
|
}
|
|
5454
|
-
|
|
5513
|
+
writeFileSync10(options.output, `${lines.join(`
|
|
5455
5514
|
`)}
|
|
5456
5515
|
`, "utf-8");
|
|
5457
5516
|
}
|
|
@@ -5468,7 +5527,7 @@ function writeReviewStateFile(options) {
|
|
|
5468
5527
|
ai_warnings: options.aiWarnings,
|
|
5469
5528
|
updated_at: nowIso()
|
|
5470
5529
|
};
|
|
5471
|
-
|
|
5530
|
+
writeFileSync10(options.output, `${JSON.stringify(payload, null, 2)}
|
|
5472
5531
|
`, "utf-8");
|
|
5473
5532
|
}
|
|
5474
5533
|
async function runGreptileReviewForPr(options) {
|
|
@@ -5549,7 +5608,7 @@ async function runGreptileReviewForPr(options) {
|
|
|
5549
5608
|
}
|
|
5550
5609
|
await Bun.sleep(options.pollIntervalMs);
|
|
5551
5610
|
}
|
|
5552
|
-
const ciGate = evaluatePullRequestCiChecks(githubCheckRollup, repoName, prNumber);
|
|
5611
|
+
const ciGate = evaluatePullRequestCiChecks(githubCheckRollup, repoName, prNumber, { mergeStateStatus: options.prState.mergeStateStatus });
|
|
5553
5612
|
if (ciGate.verdict !== "APPROVE") {
|
|
5554
5613
|
return {
|
|
5555
5614
|
verdict: ciGate.verdict,
|
|
@@ -5807,7 +5866,7 @@ async function runGithubGreptileFallbackReviewForPr(options) {
|
|
|
5807
5866
|
}
|
|
5808
5867
|
await Bun.sleep(options.pollIntervalMs);
|
|
5809
5868
|
}
|
|
5810
|
-
const ciGate = evaluatePullRequestCiChecks(checkRollup, repoName, prNumber);
|
|
5869
|
+
const ciGate = evaluatePullRequestCiChecks(checkRollup, repoName, prNumber, { mergeStateStatus: options.prState.mergeStateStatus });
|
|
5811
5870
|
if (ciGate.verdict !== "APPROVE") {
|
|
5812
5871
|
return {
|
|
5813
5872
|
verdict: ciGate.verdict,
|
|
@@ -6162,19 +6221,31 @@ function loadGithubPullRequestCheckRollup(projectRoot, repoName, prNumber) {
|
|
|
6162
6221
|
]);
|
|
6163
6222
|
return response.statusCheckRollup || [];
|
|
6164
6223
|
}
|
|
6165
|
-
function evaluatePullRequestCiChecks(checks, repoName, prNumber) {
|
|
6166
|
-
const
|
|
6167
|
-
const label = (check.name || check.context || "").toLowerCase();
|
|
6168
|
-
return label.length > 0 && !label.includes("greptile");
|
|
6169
|
-
});
|
|
6170
|
-
const pending = nonGreptileChecks.filter((check) => {
|
|
6224
|
+
function evaluatePullRequestCiChecks(checks, repoName, prNumber, options = {}) {
|
|
6225
|
+
const isPendingCheck2 = (check) => {
|
|
6171
6226
|
if ((check.__typename || "") === "CheckRun") {
|
|
6172
6227
|
return (check.status || "").toUpperCase() !== "COMPLETED";
|
|
6173
6228
|
}
|
|
6174
6229
|
const state = (check.state || check.status || "").toUpperCase();
|
|
6175
6230
|
return state === "PENDING" || state === "EXPECTED" || state === "QUEUED" || state === "IN_PROGRESS";
|
|
6231
|
+
};
|
|
6232
|
+
const pendingGreptile = checks.filter((check) => {
|
|
6233
|
+
const label = (check.name || check.context || "").toLowerCase();
|
|
6234
|
+
return label.includes("greptile") && isPendingCheck2(check);
|
|
6176
6235
|
});
|
|
6177
|
-
if (
|
|
6236
|
+
if (pendingGreptile.length > 0) {
|
|
6237
|
+
return {
|
|
6238
|
+
verdict: "SKIP",
|
|
6239
|
+
reasons: pendingGreptile.map((check) => `[CI] ${repoName}#${prNumber} mandatory Greptile check is still pending: ${check.name || check.context || "unknown"}.`)
|
|
6240
|
+
};
|
|
6241
|
+
}
|
|
6242
|
+
const nonGreptileChecks = checks.filter((check) => {
|
|
6243
|
+
const label = (check.name || check.context || "").toLowerCase();
|
|
6244
|
+
return label.length > 0 && !label.includes("greptile");
|
|
6245
|
+
});
|
|
6246
|
+
const pending = nonGreptileChecks.filter(isPendingCheck2);
|
|
6247
|
+
const mergeClean = (options.mergeStateStatus || "").toUpperCase() === "CLEAN";
|
|
6248
|
+
if (pending.length > 0 && !mergeClean) {
|
|
6178
6249
|
return {
|
|
6179
6250
|
verdict: "SKIP",
|
|
6180
6251
|
reasons: pending.map((check) => `[CI] ${repoName}#${prNumber} check is still pending: ${check.name || check.context || "unknown"}.`)
|
|
@@ -6255,7 +6326,7 @@ function filterActionableGithubGreptileThreads(threads) {
|
|
|
6255
6326
|
}
|
|
6256
6327
|
function resolvePrRepoRoot(projectRoot, prState) {
|
|
6257
6328
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
6258
|
-
if (prState.target === "monorepo" && runtimeWorkspace &&
|
|
6329
|
+
if (prState.target === "monorepo" && runtimeWorkspace && existsSync22(resolve24(runtimeWorkspace, ".git"))) {
|
|
6259
6330
|
return runtimeWorkspace;
|
|
6260
6331
|
}
|
|
6261
6332
|
const paths = resolveHarnessPaths(projectRoot);
|
|
@@ -6627,16 +6698,16 @@ async function taskDeps(projectRoot, taskId) {
|
|
|
6627
6698
|
for (const dep of deps) {
|
|
6628
6699
|
const artifactDir = artifactDirForId(projectRoot, dep);
|
|
6629
6700
|
console.log(`=== ${dep} ===`);
|
|
6630
|
-
if (!
|
|
6701
|
+
if (!existsSync23(artifactDir)) {
|
|
6631
6702
|
console.log(` (no artifacts yet)
|
|
6632
6703
|
`);
|
|
6633
6704
|
continue;
|
|
6634
6705
|
}
|
|
6635
|
-
printArtifactSection(
|
|
6636
|
-
printArtifactSection(
|
|
6637
|
-
const changedFiles =
|
|
6638
|
-
if (
|
|
6639
|
-
const lines =
|
|
6706
|
+
printArtifactSection(resolve25(artifactDir, "decision-log.md"), "--- Decisions ---");
|
|
6707
|
+
printArtifactSection(resolve25(artifactDir, "next-actions.md"), "--- Next Actions (for you) ---");
|
|
6708
|
+
const changedFiles = resolve25(artifactDir, "changed-files.txt");
|
|
6709
|
+
if (existsSync23(changedFiles)) {
|
|
6710
|
+
const lines = readFileSync12(changedFiles, "utf-8").split(/\r?\n/).filter(Boolean);
|
|
6640
6711
|
console.log(`--- Changed Files (${lines.length}) ---`);
|
|
6641
6712
|
for (const line of lines) {
|
|
6642
6713
|
console.log(line);
|
|
@@ -6681,12 +6752,12 @@ function taskRecord(projectRoot, type, text, taskId) {
|
|
|
6681
6752
|
throw new Error("No active task.");
|
|
6682
6753
|
}
|
|
6683
6754
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6684
|
-
|
|
6755
|
+
mkdirSync11(paths.stateDir, { recursive: true });
|
|
6685
6756
|
if (type === "decision") {
|
|
6686
|
-
const artifactDir =
|
|
6687
|
-
|
|
6757
|
+
const artifactDir = resolve25(paths.artifactsDir, activeTask);
|
|
6758
|
+
mkdirSync11(artifactDir, { recursive: true });
|
|
6688
6759
|
const timestamp = nowIso();
|
|
6689
|
-
appendFileSync(
|
|
6760
|
+
appendFileSync(resolve25(artifactDir, "decision-log.md"), `
|
|
6690
6761
|
### ${timestamp}
|
|
6691
6762
|
|
|
6692
6763
|
${text}
|
|
@@ -6696,14 +6767,14 @@ ${text}
|
|
|
6696
6767
|
return;
|
|
6697
6768
|
}
|
|
6698
6769
|
const failedPath = paths.failedApproachesPath;
|
|
6699
|
-
if (!
|
|
6700
|
-
|
|
6770
|
+
if (!existsSync23(failedPath)) {
|
|
6771
|
+
writeFileSync11(failedPath, `# Failed Approaches Log
|
|
6701
6772
|
|
|
6702
6773
|
This file records approaches that did not work.
|
|
6703
6774
|
|
|
6704
6775
|
`, "utf-8");
|
|
6705
6776
|
}
|
|
6706
|
-
const content =
|
|
6777
|
+
const content = readFileSync12(failedPath, "utf-8");
|
|
6707
6778
|
const attempts = (content.match(new RegExp(`^## ${escapeRegExp(activeTask)}\\b`, "gm")) || []).length + 1;
|
|
6708
6779
|
appendFileSync(failedPath, `
|
|
6709
6780
|
## ${activeTask} - Attempt ${attempts} (${nowIso()})
|
|
@@ -6720,40 +6791,40 @@ function taskArtifacts(projectRoot, taskId) {
|
|
|
6720
6791
|
throw new Error("No active task.");
|
|
6721
6792
|
}
|
|
6722
6793
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6723
|
-
const artifactDir =
|
|
6724
|
-
|
|
6794
|
+
const artifactDir = resolve25(paths.artifactsDir, activeTask);
|
|
6795
|
+
mkdirSync11(artifactDir, { recursive: true });
|
|
6725
6796
|
const changed = changedFilesForTask(projectRoot, activeTask, true);
|
|
6726
|
-
|
|
6797
|
+
writeFileSync11(resolve25(artifactDir, "changed-files.txt"), `${changed.join(`
|
|
6727
6798
|
`)}
|
|
6728
6799
|
`, "utf-8");
|
|
6729
6800
|
console.log(`changed-files.txt: ${changed.length} files`);
|
|
6730
|
-
const taskResultPath =
|
|
6731
|
-
if (!
|
|
6801
|
+
const taskResultPath = resolve25(artifactDir, "task-result.json");
|
|
6802
|
+
if (!existsSync23(taskResultPath)) {
|
|
6732
6803
|
const template = {
|
|
6733
6804
|
task_id: activeTask,
|
|
6734
6805
|
status: "completed",
|
|
6735
6806
|
summary: "TODO: Write a one-line summary of what you did",
|
|
6736
6807
|
completed_at: nowIso()
|
|
6737
6808
|
};
|
|
6738
|
-
|
|
6809
|
+
writeFileSync11(taskResultPath, `${JSON.stringify(template, null, 2)}
|
|
6739
6810
|
`, "utf-8");
|
|
6740
6811
|
console.log("task-result.json: created (update the summary!)");
|
|
6741
6812
|
} else {
|
|
6742
6813
|
console.log("task-result.json: already exists");
|
|
6743
6814
|
}
|
|
6744
|
-
const decisionLogPath =
|
|
6745
|
-
if (!
|
|
6815
|
+
const decisionLogPath = resolve25(artifactDir, "decision-log.md");
|
|
6816
|
+
if (!existsSync23(decisionLogPath)) {
|
|
6746
6817
|
const content = `# Decision Log: ${activeTask}
|
|
6747
6818
|
|
|
6748
6819
|
Record key decisions here using: rig-agent record decision "..."
|
|
6749
6820
|
`;
|
|
6750
|
-
|
|
6821
|
+
writeFileSync11(decisionLogPath, content, "utf-8");
|
|
6751
6822
|
console.log("decision-log.md: created (record your decisions!)");
|
|
6752
6823
|
} else {
|
|
6753
6824
|
console.log("decision-log.md: already exists");
|
|
6754
6825
|
}
|
|
6755
|
-
const nextActionsPath =
|
|
6756
|
-
if (!
|
|
6826
|
+
const nextActionsPath = resolve25(artifactDir, "next-actions.md");
|
|
6827
|
+
if (!existsSync23(nextActionsPath)) {
|
|
6757
6828
|
const content = [
|
|
6758
6829
|
`# Next Actions: ${activeTask}`,
|
|
6759
6830
|
"",
|
|
@@ -6770,13 +6841,13 @@ Record key decisions here using: rig-agent record decision "..."
|
|
|
6770
6841
|
""
|
|
6771
6842
|
].join(`
|
|
6772
6843
|
`);
|
|
6773
|
-
|
|
6844
|
+
writeFileSync11(nextActionsPath, content, "utf-8");
|
|
6774
6845
|
console.log("next-actions.md: created (add recommendations for downstream tasks!)");
|
|
6775
6846
|
} else {
|
|
6776
6847
|
console.log("next-actions.md: already exists");
|
|
6777
6848
|
}
|
|
6778
|
-
const validationSummaryPath =
|
|
6779
|
-
if (
|
|
6849
|
+
const validationSummaryPath = resolve25(artifactDir, "validation-summary.json");
|
|
6850
|
+
if (existsSync23(validationSummaryPath)) {
|
|
6780
6851
|
console.log("validation-summary.json: already exists");
|
|
6781
6852
|
} else {
|
|
6782
6853
|
console.log("validation-summary.json: not yet created (run: rig-agent validate)");
|
|
@@ -6867,7 +6938,7 @@ function collectTaskChangedFiles(projectRoot, taskId, includeCommitted) {
|
|
|
6867
6938
|
[projectRoot, ""],
|
|
6868
6939
|
[monorepoRepoRoot, ""]
|
|
6869
6940
|
]) {
|
|
6870
|
-
if (!
|
|
6941
|
+
if (!existsSync23(resolve25(repo, ".git"))) {
|
|
6871
6942
|
continue;
|
|
6872
6943
|
}
|
|
6873
6944
|
if (includeCommitted && repo === monorepoRepoRoot) {
|
|
@@ -6892,12 +6963,22 @@ function filterTaskChangedFiles(projectRoot, taskId, files, scoped) {
|
|
|
6892
6963
|
}
|
|
6893
6964
|
function resolveTaskMonorepoRoot(projectRoot) {
|
|
6894
6965
|
const runtimeWorkspace = loadRuntimeContextFromEnv()?.workspaceDir || process.env.RIG_TASK_WORKSPACE?.trim();
|
|
6895
|
-
if (runtimeWorkspace &&
|
|
6896
|
-
return
|
|
6966
|
+
if (runtimeWorkspace && existsSync23(resolve25(runtimeWorkspace, ".git"))) {
|
|
6967
|
+
return resolve25(runtimeWorkspace);
|
|
6897
6968
|
}
|
|
6898
6969
|
return resolveHarnessPaths(projectRoot).monorepoRoot;
|
|
6899
6970
|
}
|
|
6900
6971
|
function collectCommittedMonorepoFiles(projectRoot, repo) {
|
|
6972
|
+
const defaultRef = runCapture(["git", "-C", repo, "rev-parse", "--abbrev-ref", "origin/HEAD"], projectRoot);
|
|
6973
|
+
if (defaultRef.exitCode === 0 && defaultRef.stdout.trim()) {
|
|
6974
|
+
const mergeBase = runCapture(["git", "-C", repo, "merge-base", "HEAD", defaultRef.stdout.trim()], projectRoot);
|
|
6975
|
+
if (mergeBase.exitCode === 0 && mergeBase.stdout.trim()) {
|
|
6976
|
+
const result = runCapture(["git", "-C", repo, "diff", "--name-only", `${mergeBase.stdout.trim()}..HEAD`], projectRoot);
|
|
6977
|
+
if (result.exitCode === 0) {
|
|
6978
|
+
return result.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
6979
|
+
}
|
|
6980
|
+
}
|
|
6981
|
+
}
|
|
6901
6982
|
const initialHeadCommit = resolveRuntimeInitialHeadCommit(projectRoot, repo);
|
|
6902
6983
|
if (initialHeadCommit) {
|
|
6903
6984
|
const result = runCapture(["git", "-C", repo, "diff", "--name-only", `${initialHeadCommit}..HEAD`], projectRoot);
|
|
@@ -6921,7 +7002,7 @@ function resolveRuntimeInitialHeadCommit(projectRoot, repo) {
|
|
|
6921
7002
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
6922
7003
|
if (runtimeContext?.initialHeadCommits?.monorepo?.trim()) {
|
|
6923
7004
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6924
|
-
if (
|
|
7005
|
+
if (resolve25(monorepoRoot) === resolve25(repo)) {
|
|
6925
7006
|
return runtimeContext.initialHeadCommits.monorepo.trim();
|
|
6926
7007
|
}
|
|
6927
7008
|
}
|
|
@@ -6931,7 +7012,7 @@ function resolveMonorepoBaseCommit(projectRoot, repo) {
|
|
|
6931
7012
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
6932
7013
|
if (runtimeContext?.monorepoBaseCommit?.trim()) {
|
|
6933
7014
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6934
|
-
if (
|
|
7015
|
+
if (resolve25(monorepoRoot) === resolve25(repo)) {
|
|
6935
7016
|
return runtimeContext.monorepoBaseCommit.trim();
|
|
6936
7017
|
}
|
|
6937
7018
|
}
|
|
@@ -6976,7 +7057,7 @@ function resolveRuntimeDirtyBaseline(projectRoot, repo) {
|
|
|
6976
7057
|
return new Set;
|
|
6977
7058
|
}
|
|
6978
7059
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6979
|
-
const selected =
|
|
7060
|
+
const selected = resolve25(repo) === resolve25(monorepoRoot) ? dirtyFiles.monorepo : resolve25(repo) === resolve25(projectRoot) ? dirtyFiles.project : undefined;
|
|
6980
7061
|
return new Set((selected || []).map((file) => normalizeChangedFilePath(file)).filter(Boolean));
|
|
6981
7062
|
}
|
|
6982
7063
|
function normalizeChangedFilePath(file) {
|
|
@@ -7076,12 +7157,12 @@ function printIndented(text) {
|
|
|
7076
7157
|
}
|
|
7077
7158
|
}
|
|
7078
7159
|
function readLocalBeadsTasks(projectRoot) {
|
|
7079
|
-
const issuesPath =
|
|
7080
|
-
if (!
|
|
7160
|
+
const issuesPath = resolve25(resolveMonorepoRoot2(projectRoot), ".beads/issues.jsonl");
|
|
7161
|
+
if (!existsSync23(issuesPath)) {
|
|
7081
7162
|
return [];
|
|
7082
7163
|
}
|
|
7083
7164
|
const tasks = [];
|
|
7084
|
-
for (const line of
|
|
7165
|
+
for (const line of readFileSync12(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
7085
7166
|
const trimmed = line.trim();
|
|
7086
7167
|
if (!trimmed) {
|
|
7087
7168
|
continue;
|
|
@@ -7194,11 +7275,11 @@ function taskDependencies(projectRoot, taskId, tracker) {
|
|
|
7194
7275
|
return [...ids].sort();
|
|
7195
7276
|
}
|
|
7196
7277
|
function printArtifactSection(path, header) {
|
|
7197
|
-
if (!
|
|
7278
|
+
if (!existsSync23(path)) {
|
|
7198
7279
|
return;
|
|
7199
7280
|
}
|
|
7200
7281
|
console.log(header);
|
|
7201
|
-
process.stdout.write(
|
|
7282
|
+
process.stdout.write(readFileSync12(path, "utf-8"));
|
|
7202
7283
|
console.log("");
|
|
7203
7284
|
}
|
|
7204
7285
|
function escapeRegExp(value) {
|
|
@@ -7238,8 +7319,8 @@ function isRuntimeGatewayGhPath(candidate) {
|
|
|
7238
7319
|
}
|
|
7239
7320
|
function resolveOptionalMonorepoRoot(projectRoot) {
|
|
7240
7321
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
7241
|
-
if (runtimeWorkspace &&
|
|
7242
|
-
return
|
|
7322
|
+
if (runtimeWorkspace && existsSync24(resolve26(runtimeWorkspace, ".git"))) {
|
|
7323
|
+
return resolve26(runtimeWorkspace);
|
|
7243
7324
|
}
|
|
7244
7325
|
try {
|
|
7245
7326
|
return resolveMonorepoRoot2(projectRoot);
|
|
@@ -7264,7 +7345,7 @@ function resolveGitBinary(projectRoot) {
|
|
|
7264
7345
|
if (!candidate || isRuntimeGatewayGitPath(candidate)) {
|
|
7265
7346
|
continue;
|
|
7266
7347
|
}
|
|
7267
|
-
if (
|
|
7348
|
+
if (existsSync24(candidate)) {
|
|
7268
7349
|
return candidate;
|
|
7269
7350
|
}
|
|
7270
7351
|
}
|
|
@@ -7324,11 +7405,11 @@ function gitPreflight(projectRoot, taskId, strict) {
|
|
|
7324
7405
|
const expected = resolvedTask ? `rig/${resolveTaskBranchId(projectRoot, resolvedTask)}` : "";
|
|
7325
7406
|
console.log("=== Git Flow Preflight ===");
|
|
7326
7407
|
let issues = 0;
|
|
7327
|
-
if (!
|
|
7408
|
+
if (!existsSync24(resolve26(projectRoot, ".git"))) {
|
|
7328
7409
|
console.log(`ERROR: project root is not a git repo (${projectRoot})`);
|
|
7329
7410
|
issues += 1;
|
|
7330
7411
|
}
|
|
7331
|
-
if (monorepoRoot &&
|
|
7412
|
+
if (monorepoRoot && existsSync24(resolve26(monorepoRoot, ".git"))) {
|
|
7332
7413
|
const monoBranch = branchName(projectRoot, monorepoRoot);
|
|
7333
7414
|
if (expected && monoBranch !== expected) {
|
|
7334
7415
|
console.log(`WARN: monorepo branch is ${monoBranch}, expected ${expected} for task ${resolvedTask}`);
|
|
@@ -7362,7 +7443,7 @@ function gitSyncBranch(projectRoot, taskId, targetRepo = "monorepo") {
|
|
|
7362
7443
|
}
|
|
7363
7444
|
const repoRoot = targetRepo === "monorepo" ? resolveOptionalMonorepoRoot(projectRoot) || resolveMonorepoRoot2(projectRoot) : projectRoot;
|
|
7364
7445
|
const repoLabel = targetRepo === "monorepo" ? "Monorepo" : "Project";
|
|
7365
|
-
if (!
|
|
7446
|
+
if (!existsSync24(resolve26(repoRoot, ".git"))) {
|
|
7366
7447
|
throw new Error(`${repoLabel} repo not found at ${repoRoot}`);
|
|
7367
7448
|
}
|
|
7368
7449
|
const branchId = resolveTaskBranchId(projectRoot, resolvedTask);
|
|
@@ -7406,8 +7487,8 @@ function gitCommit(options) {
|
|
|
7406
7487
|
function gitSnapshot(projectRoot, taskId, outputPath) {
|
|
7407
7488
|
const monorepoRoot = resolveOptionalMonorepoRoot(projectRoot);
|
|
7408
7489
|
const resolvedTask = taskId || safeCurrentTaskId(projectRoot);
|
|
7409
|
-
const output = outputPath || (resolvedTask ? resolveArtifactSnapshot(projectRoot, resolvedTask) :
|
|
7410
|
-
|
|
7490
|
+
const output = outputPath || (resolvedTask ? resolveArtifactSnapshot(projectRoot, resolvedTask) : resolve26(resolve26(projectRoot, ".rig", "state"), "git-state.txt"));
|
|
7491
|
+
mkdirSync12(dirname12(output), { recursive: true });
|
|
7411
7492
|
const lines = ["# Git Snapshot", `timestamp: ${nowIso()}`];
|
|
7412
7493
|
if (resolvedTask) {
|
|
7413
7494
|
lines.push(`task: ${resolvedTask}`);
|
|
@@ -7417,7 +7498,7 @@ function gitSnapshot(projectRoot, taskId, outputPath) {
|
|
|
7417
7498
|
if (monorepoRoot && monorepoRoot !== projectRoot) {
|
|
7418
7499
|
lines.push(...snapshotRepo(projectRoot, "monorepo", monorepoRoot));
|
|
7419
7500
|
}
|
|
7420
|
-
|
|
7501
|
+
writeFileSync12(output, `${lines.join(`
|
|
7421
7502
|
`)}
|
|
7422
7503
|
`, "utf-8");
|
|
7423
7504
|
return output;
|
|
@@ -7441,7 +7522,7 @@ function gitOpenPr(options) {
|
|
|
7441
7522
|
} else if (taskId) {
|
|
7442
7523
|
gitSyncBranch(options.projectRoot, taskId, "project");
|
|
7443
7524
|
}
|
|
7444
|
-
if (!
|
|
7525
|
+
if (!existsSync24(resolve26(repoRoot, ".git"))) {
|
|
7445
7526
|
throw new Error(`Repository not available for open-pr target ${target}: ${repoRoot}`);
|
|
7446
7527
|
}
|
|
7447
7528
|
const branch = branchName(options.projectRoot, repoRoot);
|
|
@@ -7654,12 +7735,12 @@ function assertPrHasNoGitConflicts(prState, repoLabel, baseRef) {
|
|
|
7654
7735
|
}
|
|
7655
7736
|
function writePrMetadata(projectRoot, taskId, result) {
|
|
7656
7737
|
const dir = artifactDirForId(projectRoot, taskId);
|
|
7657
|
-
|
|
7658
|
-
const path =
|
|
7738
|
+
mkdirSync12(dir, { recursive: true });
|
|
7739
|
+
const path = resolve26(dir, "pr-state.json");
|
|
7659
7740
|
let prs = {};
|
|
7660
|
-
if (
|
|
7741
|
+
if (existsSync24(path)) {
|
|
7661
7742
|
try {
|
|
7662
|
-
const parsed = JSON.parse(
|
|
7743
|
+
const parsed = JSON.parse(readFileSync13(path, "utf-8"));
|
|
7663
7744
|
if (parsed && typeof parsed === "object" && parsed.prs && typeof parsed.prs === "object") {
|
|
7664
7745
|
prs = parsed.prs;
|
|
7665
7746
|
}
|
|
@@ -7675,16 +7756,16 @@ function writePrMetadata(projectRoot, taskId, result) {
|
|
|
7675
7756
|
...primary || {},
|
|
7676
7757
|
updated_at: nowIso()
|
|
7677
7758
|
};
|
|
7678
|
-
|
|
7759
|
+
writeFileSync12(path, `${JSON.stringify(artifact, null, 2)}
|
|
7679
7760
|
`, "utf-8");
|
|
7680
7761
|
}
|
|
7681
7762
|
function readPrMetadata(projectRoot, taskId) {
|
|
7682
|
-
const path =
|
|
7683
|
-
if (!
|
|
7763
|
+
const path = resolve26(artifactDirForId(projectRoot, taskId), "pr-state.json");
|
|
7764
|
+
if (!existsSync24(path)) {
|
|
7684
7765
|
return [];
|
|
7685
7766
|
}
|
|
7686
7767
|
try {
|
|
7687
|
-
const parsed = JSON.parse(
|
|
7768
|
+
const parsed = JSON.parse(readFileSync13(path, "utf-8"));
|
|
7688
7769
|
if (!parsed || typeof parsed !== "object") {
|
|
7689
7770
|
return [];
|
|
7690
7771
|
}
|
|
@@ -7697,8 +7778,8 @@ function readPrMetadata(projectRoot, taskId) {
|
|
|
7697
7778
|
}
|
|
7698
7779
|
}
|
|
7699
7780
|
function resolveArtifactSnapshot(projectRoot, taskId) {
|
|
7700
|
-
const artifactDir =
|
|
7701
|
-
return
|
|
7781
|
+
const artifactDir = resolve26(resolveHarnessPaths(projectRoot).artifactsDir, taskId);
|
|
7782
|
+
return resolve26(artifactDir, "git-state.txt");
|
|
7702
7783
|
}
|
|
7703
7784
|
function isGitOpenPrResult(value) {
|
|
7704
7785
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -7757,14 +7838,14 @@ function resolveGithubCliBinary(projectRoot) {
|
|
|
7757
7838
|
}
|
|
7758
7839
|
const explicitPathEntries = (process.env.PATH || "").split(":").map((entry) => entry.trim()).filter(Boolean);
|
|
7759
7840
|
for (const entry of explicitPathEntries) {
|
|
7760
|
-
candidates.add(
|
|
7841
|
+
candidates.add(resolve26(entry, "gh"));
|
|
7761
7842
|
}
|
|
7762
7843
|
const bunResolved = Bun.which("gh");
|
|
7763
7844
|
if (bunResolved) {
|
|
7764
7845
|
candidates.add(bunResolved);
|
|
7765
7846
|
}
|
|
7766
7847
|
for (const candidate of candidates) {
|
|
7767
|
-
if (candidate &&
|
|
7848
|
+
if (candidate && existsSync24(candidate) && !isRuntimeGatewayGhPath(candidate)) {
|
|
7768
7849
|
return candidate;
|
|
7769
7850
|
}
|
|
7770
7851
|
}
|
|
@@ -7794,7 +7875,7 @@ function resolveRepoNameWithOwner(projectRoot, repoRoot) {
|
|
|
7794
7875
|
return resolveGithubRepoNameWithOwnerFromGitRoot(projectRoot, repoRoot, repoRoot, visited);
|
|
7795
7876
|
}
|
|
7796
7877
|
function resolveGithubRepoNameWithOwnerFromGitRoot(projectRoot, gitRoot, cwd, visited) {
|
|
7797
|
-
const normalizedGitRoot =
|
|
7878
|
+
const normalizedGitRoot = resolve26(gitRoot);
|
|
7798
7879
|
if (visited.has(normalizedGitRoot)) {
|
|
7799
7880
|
return "";
|
|
7800
7881
|
}
|
|
@@ -7866,7 +7947,7 @@ function resolveNetworkRemoteName(projectRoot, repoRoot, repoNameWithOwner) {
|
|
|
7866
7947
|
return remotes.includes("origin") ? "origin" : remotes[0];
|
|
7867
7948
|
}
|
|
7868
7949
|
function gitQuery(projectRoot, gitRoot, cwd, ...args) {
|
|
7869
|
-
const gitArgs =
|
|
7950
|
+
const gitArgs = existsSync24(resolve26(gitRoot, ".git")) ? gitCmd(projectRoot, gitRoot, ...args) : [resolveGitBinary(projectRoot), "--git-dir", gitRoot, ...args];
|
|
7870
7951
|
return runCapture2(gitArgs, cwd, projectRoot);
|
|
7871
7952
|
}
|
|
7872
7953
|
function resolveLocalGitRemoteRoot(remoteUrl, gitRoot) {
|
|
@@ -7884,9 +7965,9 @@ function resolveLocalGitRemoteRoot(remoteUrl, gitRoot) {
|
|
|
7884
7965
|
} else if (/^[a-z][a-z0-9+.-]*:\/\//i.test(normalized) || /^[^@]+@[^:]+:.+$/.test(normalized)) {
|
|
7885
7966
|
return "";
|
|
7886
7967
|
} else if (!isAbsolute2(normalized)) {
|
|
7887
|
-
candidate =
|
|
7968
|
+
candidate = resolve26(gitRoot, normalized);
|
|
7888
7969
|
}
|
|
7889
|
-
return
|
|
7970
|
+
return existsSync24(candidate) ? candidate : "";
|
|
7890
7971
|
}
|
|
7891
7972
|
function normalizeGithubRepoNameWithOwner(value) {
|
|
7892
7973
|
const normalized = value.trim();
|
|
@@ -8013,7 +8094,7 @@ function inferReviewerFromChangedFiles(projectRoot, repoRoot, baseRef, branchRef
|
|
|
8013
8094
|
return best;
|
|
8014
8095
|
}
|
|
8015
8096
|
function snapshotRepo(projectRoot, label, repo) {
|
|
8016
|
-
if (!
|
|
8097
|
+
if (!existsSync24(resolve26(repo, ".git"))) {
|
|
8017
8098
|
return [`## ${label}`, `repo: ${repo}`, "status: unavailable", ""];
|
|
8018
8099
|
}
|
|
8019
8100
|
const status = runCapture2(gitCmd(projectRoot, repo, "status", "--short"), projectRoot).stdout.trim();
|
|
@@ -8036,7 +8117,7 @@ function snapshotRepo(projectRoot, label, repo) {
|
|
|
8036
8117
|
];
|
|
8037
8118
|
}
|
|
8038
8119
|
function commitRepo(projectRoot, repo, label, message, allowEmpty, scoped, files, changedFilesManifest) {
|
|
8039
|
-
if (!
|
|
8120
|
+
if (!existsSync24(resolve26(repo, ".git"))) {
|
|
8040
8121
|
console.log(`Skipping ${label}: repo not available (${repo})`);
|
|
8041
8122
|
return;
|
|
8042
8123
|
}
|
|
@@ -8068,18 +8149,18 @@ function commitRepo(projectRoot, repo, label, message, allowEmpty, scoped, files
|
|
|
8068
8149
|
console.log(`Committed ${label}: ${message}`);
|
|
8069
8150
|
}
|
|
8070
8151
|
function readChangedFilesManifest(projectRoot, taskId) {
|
|
8071
|
-
const manifestPath =
|
|
8072
|
-
if (!
|
|
8152
|
+
const manifestPath = resolve26(artifactDirForId(projectRoot, taskId), "changed-files.txt");
|
|
8153
|
+
if (!existsSync24(manifestPath)) {
|
|
8073
8154
|
return [];
|
|
8074
8155
|
}
|
|
8075
|
-
const files =
|
|
8156
|
+
const files = readFileSync13(manifestPath, "utf-8").split(/\r?\n/).map((line) => normalizeChangedFilePath2(line)).filter(Boolean);
|
|
8076
8157
|
return [...new Set(files)];
|
|
8077
8158
|
}
|
|
8078
8159
|
function refreshChangedFilesManifest(projectRoot, taskId) {
|
|
8079
|
-
const manifestPath =
|
|
8080
|
-
|
|
8160
|
+
const manifestPath = resolve26(artifactDirForId(projectRoot, taskId), "changed-files.txt");
|
|
8161
|
+
mkdirSync12(dirname12(manifestPath), { recursive: true });
|
|
8081
8162
|
const changedFiles = changedFilesForTask(projectRoot, taskId, true);
|
|
8082
|
-
|
|
8163
|
+
writeFileSync12(manifestPath, `${changedFiles.join(`
|
|
8083
8164
|
`)}
|
|
8084
8165
|
`, "utf-8");
|
|
8085
8166
|
return manifestPath;
|
|
@@ -8192,7 +8273,7 @@ function repoHasPathChange(projectRoot, repoRoot, relativePath) {
|
|
|
8192
8273
|
return result.exitCode === 0 && result.stdout.trim().length > 0;
|
|
8193
8274
|
}
|
|
8194
8275
|
function stageExcludePathspecs(repoRoot) {
|
|
8195
|
-
const patterns =
|
|
8276
|
+
const patterns = existsSync24(resolve26(repoRoot, ".rig", "task-config.json")) ? [...TASK_RUNTIME_STAGE_EXCLUDES, ...GENERATED_STAGE_EXCLUDES] : [".rig/**", ...GENERATED_STAGE_EXCLUDES];
|
|
8196
8277
|
return patterns.map((pattern) => `:(glob,exclude)${pattern}`);
|
|
8197
8278
|
}
|
|
8198
8279
|
function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
@@ -8202,7 +8283,7 @@ function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
|
8202
8283
|
}
|
|
8203
8284
|
let current = repoRoot;
|
|
8204
8285
|
for (let index = 0;index < parts.length - 1; index += 1) {
|
|
8205
|
-
current =
|
|
8286
|
+
current = resolve26(current, parts[index]);
|
|
8206
8287
|
try {
|
|
8207
8288
|
if (lstatSync(current).isSymbolicLink()) {
|
|
8208
8289
|
return true;
|
|
@@ -8214,7 +8295,7 @@ function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
|
8214
8295
|
return false;
|
|
8215
8296
|
}
|
|
8216
8297
|
function printRepoStatus(projectRoot, label, repo, expectedBranch) {
|
|
8217
|
-
if (!
|
|
8298
|
+
if (!existsSync24(resolve26(repo, ".git"))) {
|
|
8218
8299
|
console.log(`${label}: unavailable (${repo})`);
|
|
8219
8300
|
return;
|
|
8220
8301
|
}
|
|
@@ -8250,7 +8331,7 @@ function resolveTaskBranchId(projectRoot, taskId) {
|
|
|
8250
8331
|
}
|
|
8251
8332
|
} catch {}
|
|
8252
8333
|
const artifactDir = artifactDirForId(projectRoot, taskId);
|
|
8253
|
-
if (
|
|
8334
|
+
if (existsSync24(artifactDir)) {
|
|
8254
8335
|
return taskId;
|
|
8255
8336
|
}
|
|
8256
8337
|
throw new Error(`Unknown task id: ${taskId}`);
|
|
@@ -8286,11 +8367,11 @@ function runCapture2(command, cwd, projectRoot = cwd) {
|
|
|
8286
8367
|
}
|
|
8287
8368
|
function runtimeGitEnv(projectRoot) {
|
|
8288
8369
|
const { ctx, runtimeRoot } = resolveRuntimeMetadata(projectRoot);
|
|
8289
|
-
const runtimeHome = runtimeRoot ?
|
|
8290
|
-
const runtimeTmp = runtimeRoot ?
|
|
8291
|
-
const runtimeCache = runtimeRoot ?
|
|
8292
|
-
const runtimeKnownHosts = runtimeHome ?
|
|
8293
|
-
const runtimeKey = runtimeHome ?
|
|
8370
|
+
const runtimeHome = runtimeRoot ? resolve26(runtimeRoot, "home") : "";
|
|
8371
|
+
const runtimeTmp = runtimeRoot ? resolve26(runtimeRoot, "tmp") : "";
|
|
8372
|
+
const runtimeCache = runtimeRoot ? resolve26(runtimeRoot, "cache") : "";
|
|
8373
|
+
const runtimeKnownHosts = runtimeHome ? resolve26(runtimeHome, ".ssh", "known_hosts") : "";
|
|
8374
|
+
const runtimeKey = runtimeHome ? resolve26(runtimeHome, ".ssh", "rig-agent-key") : "";
|
|
8294
8375
|
const env = {};
|
|
8295
8376
|
if (ctx?.workspaceDir) {
|
|
8296
8377
|
env.PROJECT_RIG_ROOT = projectRoot;
|
|
@@ -8303,14 +8384,14 @@ function runtimeGitEnv(projectRoot) {
|
|
|
8303
8384
|
if (runtimeRoot) {
|
|
8304
8385
|
env.RIG_RUNTIME_HOME = runtimeRoot;
|
|
8305
8386
|
}
|
|
8306
|
-
if (runtimeHome &&
|
|
8387
|
+
if (runtimeHome && existsSync24(runtimeHome)) {
|
|
8307
8388
|
env.HOME = runtimeHome;
|
|
8308
8389
|
env.OPENSSL_CONF = ensureRuntimeOpenSslConfig(runtimeHome);
|
|
8309
8390
|
}
|
|
8310
|
-
if (runtimeTmp &&
|
|
8391
|
+
if (runtimeTmp && existsSync24(runtimeTmp)) {
|
|
8311
8392
|
env.TMPDIR = runtimeTmp;
|
|
8312
8393
|
}
|
|
8313
|
-
if (runtimeCache &&
|
|
8394
|
+
if (runtimeCache && existsSync24(runtimeCache)) {
|
|
8314
8395
|
env.XDG_CACHE_HOME = runtimeCache;
|
|
8315
8396
|
}
|
|
8316
8397
|
const workspaceSecrets = loadDotEnvSecrets(ctx?.workspaceDir || projectRoot, process.env);
|
|
@@ -8354,14 +8435,14 @@ function runtimeGitEnv(projectRoot) {
|
|
|
8354
8435
|
env.GH_TOKEN = env.GH_TOKEN || gitHubToken;
|
|
8355
8436
|
applyGitHubCredentialHelperEnv(env);
|
|
8356
8437
|
}
|
|
8357
|
-
if (runtimeKnownHosts &&
|
|
8438
|
+
if (runtimeKnownHosts && existsSync24(runtimeKnownHosts)) {
|
|
8358
8439
|
const sshParts = [
|
|
8359
8440
|
"ssh",
|
|
8360
8441
|
`-o UserKnownHostsFile="${runtimeKnownHosts}"`,
|
|
8361
8442
|
"-o StrictHostKeyChecking=yes",
|
|
8362
8443
|
"-F /dev/null"
|
|
8363
8444
|
];
|
|
8364
|
-
if (runtimeKey &&
|
|
8445
|
+
if (runtimeKey && existsSync24(runtimeKey)) {
|
|
8365
8446
|
sshParts.splice(1, 0, `-i "${runtimeKey}"`, "-o IdentitiesOnly=yes");
|
|
8366
8447
|
}
|
|
8367
8448
|
env.GIT_SSH_COMMAND = sshParts.join(" ");
|
|
@@ -8382,12 +8463,12 @@ function loadPersistedRuntimeSecrets(runtimeRoot) {
|
|
|
8382
8463
|
if (!runtimeRoot) {
|
|
8383
8464
|
return {};
|
|
8384
8465
|
}
|
|
8385
|
-
const path =
|
|
8386
|
-
if (!
|
|
8466
|
+
const path = resolve26(runtimeRoot, "runtime-secrets.json");
|
|
8467
|
+
if (!existsSync24(path)) {
|
|
8387
8468
|
return {};
|
|
8388
8469
|
}
|
|
8389
8470
|
try {
|
|
8390
|
-
const parsed = JSON.parse(
|
|
8471
|
+
const parsed = JSON.parse(readFileSync13(path, "utf-8"));
|
|
8391
8472
|
const entries = Object.entries(parsed).filter((entry) => typeof entry[1] === "string");
|
|
8392
8473
|
return Object.fromEntries(entries);
|
|
8393
8474
|
} catch {
|
|
@@ -8395,13 +8476,13 @@ function loadPersistedRuntimeSecrets(runtimeRoot) {
|
|
|
8395
8476
|
}
|
|
8396
8477
|
}
|
|
8397
8478
|
function ensureRuntimeOpenSslConfig(runtimeHome) {
|
|
8398
|
-
const sslDir =
|
|
8399
|
-
const sslConfig =
|
|
8400
|
-
if (!
|
|
8401
|
-
|
|
8479
|
+
const sslDir = resolve26(runtimeHome, ".ssl");
|
|
8480
|
+
const sslConfig = resolve26(sslDir, "openssl.cnf");
|
|
8481
|
+
if (!existsSync24(sslDir)) {
|
|
8482
|
+
mkdirSync12(sslDir, { recursive: true });
|
|
8402
8483
|
}
|
|
8403
|
-
if (!
|
|
8404
|
-
|
|
8484
|
+
if (!existsSync24(sslConfig)) {
|
|
8485
|
+
writeFileSync12(sslConfig, `# Rig runtime OpenSSL config placeholder
|
|
8405
8486
|
`);
|
|
8406
8487
|
}
|
|
8407
8488
|
return sslConfig;
|
|
@@ -8419,29 +8500,29 @@ function resolveRuntimeMetadata(projectRoot) {
|
|
|
8419
8500
|
if (contextFile) {
|
|
8420
8501
|
return {
|
|
8421
8502
|
ctx,
|
|
8422
|
-
runtimeRoot:
|
|
8503
|
+
runtimeRoot: dirname12(resolve26(contextFile))
|
|
8423
8504
|
};
|
|
8424
8505
|
}
|
|
8425
8506
|
const inferredContextFile = findRuntimeContextFile2(projectRoot);
|
|
8426
|
-
if (
|
|
8507
|
+
if (existsSync24(inferredContextFile)) {
|
|
8427
8508
|
try {
|
|
8428
8509
|
ctx = loadRuntimeContext(inferredContextFile);
|
|
8429
8510
|
} catch {}
|
|
8430
8511
|
return {
|
|
8431
8512
|
ctx,
|
|
8432
|
-
runtimeRoot:
|
|
8513
|
+
runtimeRoot: dirname12(inferredContextFile)
|
|
8433
8514
|
};
|
|
8434
8515
|
}
|
|
8435
8516
|
return { ctx, runtimeRoot: "" };
|
|
8436
8517
|
}
|
|
8437
8518
|
function findRuntimeContextFile2(startPath) {
|
|
8438
|
-
let current =
|
|
8519
|
+
let current = resolve26(startPath);
|
|
8439
8520
|
while (true) {
|
|
8440
|
-
const candidate =
|
|
8441
|
-
if (
|
|
8521
|
+
const candidate = resolve26(current, "runtime-context.json");
|
|
8522
|
+
if (existsSync24(candidate)) {
|
|
8442
8523
|
return candidate;
|
|
8443
8524
|
}
|
|
8444
|
-
const parent =
|
|
8525
|
+
const parent = dirname12(current);
|
|
8445
8526
|
if (parent === current) {
|
|
8446
8527
|
return "";
|
|
8447
8528
|
}
|
|
@@ -8450,7 +8531,7 @@ function findRuntimeContextFile2(startPath) {
|
|
|
8450
8531
|
}
|
|
8451
8532
|
|
|
8452
8533
|
// packages/runtime/src/control-plane/native/profile-ops.ts
|
|
8453
|
-
import { existsSync as
|
|
8534
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync13, writeFileSync as writeFileSync13 } from "fs";
|
|
8454
8535
|
var DEFAULTS = {
|
|
8455
8536
|
model: parseEnvOrDefault(process.env.DEFAULT_AGENT_MODEL, ["claude", "gpt-codex", "pi"], "pi"),
|
|
8456
8537
|
runtime: parseEnvOrDefault(process.env.DEFAULT_AGENT_RUNTIME, ["claude-code", "codex-app-server", "pi"], "pi"),
|
|
@@ -8465,7 +8546,7 @@ function parseEnvOrDefault(value, allowed, fallback) {
|
|
|
8465
8546
|
return allowed.includes(value) ? value : fallback;
|
|
8466
8547
|
}
|
|
8467
8548
|
async function readProfileFile(path) {
|
|
8468
|
-
if (!
|
|
8549
|
+
if (!existsSync25(path)) {
|
|
8469
8550
|
return null;
|
|
8470
8551
|
}
|
|
8471
8552
|
try {
|
|
@@ -8518,14 +8599,14 @@ async function setProfile(projectRoot, options) {
|
|
|
8518
8599
|
plugin = model === "gpt-codex" ? "codex" : model === "pi" ? "pi" : "claude";
|
|
8519
8600
|
}
|
|
8520
8601
|
const paths = resolveHarnessPaths(projectRoot);
|
|
8521
|
-
|
|
8602
|
+
mkdirSync13(paths.stateDir, { recursive: true });
|
|
8522
8603
|
const next = {
|
|
8523
8604
|
model,
|
|
8524
8605
|
runtime,
|
|
8525
8606
|
agent_plugin: plugin,
|
|
8526
8607
|
updated_at: new Date().toISOString()
|
|
8527
8608
|
};
|
|
8528
|
-
|
|
8609
|
+
writeFileSync13(paths.agentProfilePath, `${JSON.stringify(next, null, 2)}
|
|
8529
8610
|
`, "utf-8");
|
|
8530
8611
|
await showProfile(projectRoot, false);
|
|
8531
8612
|
}
|
|
@@ -8561,13 +8642,13 @@ async function setReviewProfile(projectRoot, mode, provider) {
|
|
|
8561
8642
|
throw new Error(`Invalid provider: ${resolvedProvider}. Supported: greptile.`);
|
|
8562
8643
|
}
|
|
8563
8644
|
const paths = resolveHarnessPaths(projectRoot);
|
|
8564
|
-
|
|
8645
|
+
mkdirSync13(paths.stateDir, { recursive: true });
|
|
8565
8646
|
const next = {
|
|
8566
8647
|
mode,
|
|
8567
8648
|
provider: resolvedProvider,
|
|
8568
8649
|
updated_at: new Date().toISOString()
|
|
8569
8650
|
};
|
|
8570
|
-
|
|
8651
|
+
writeFileSync13(paths.reviewProfilePath, `${JSON.stringify(next, null, 2)}
|
|
8571
8652
|
`, "utf-8");
|
|
8572
8653
|
await showReviewProfile(projectRoot);
|
|
8573
8654
|
}
|
|
@@ -8605,44 +8686,44 @@ async function loadReviewProfile(path) {
|
|
|
8605
8686
|
}
|
|
8606
8687
|
|
|
8607
8688
|
// packages/runtime/src/control-plane/native/repo-ops.ts
|
|
8608
|
-
import { existsSync as
|
|
8609
|
-
import { basename as basename8, dirname as
|
|
8689
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync17, readFileSync as readFileSync15, readdirSync as readdirSync6, rmSync as rmSync7, writeFileSync as writeFileSync15 } from "fs";
|
|
8690
|
+
import { basename as basename8, dirname as dirname14, resolve as resolve30 } from "path";
|
|
8610
8691
|
// packages/runtime/src/control-plane/repos/mirror/bootstrap.ts
|
|
8611
|
-
import { existsSync as
|
|
8612
|
-
import { resolve as
|
|
8692
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync15, realpathSync as realpathSync2 } from "fs";
|
|
8693
|
+
import { resolve as resolve28 } from "path";
|
|
8613
8694
|
|
|
8614
8695
|
// packages/runtime/src/control-plane/authority-files.ts
|
|
8615
|
-
import { existsSync as
|
|
8616
|
-
import { dirname as
|
|
8696
|
+
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";
|
|
8697
|
+
import { dirname as dirname13, join as join4, relative, resolve as resolve27 } from "path";
|
|
8617
8698
|
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
8618
8699
|
function resolveAuthorityProjectStateDir(projectRoot) {
|
|
8619
8700
|
const explicit = process.env.RIG_STATE_DIR?.trim();
|
|
8620
8701
|
if (explicit) {
|
|
8621
|
-
return
|
|
8702
|
+
return resolve27(explicit);
|
|
8622
8703
|
}
|
|
8623
|
-
return
|
|
8704
|
+
return resolve27(resolve27(projectRoot), ".rig", "state");
|
|
8624
8705
|
}
|
|
8625
8706
|
function readJsonAtPath(path, fallback) {
|
|
8626
|
-
if (!
|
|
8707
|
+
if (!existsSync26(path)) {
|
|
8627
8708
|
return fallback;
|
|
8628
8709
|
}
|
|
8629
8710
|
try {
|
|
8630
|
-
return JSON.parse(
|
|
8711
|
+
return JSON.parse(readFileSync14(path, "utf-8"));
|
|
8631
8712
|
} catch {
|
|
8632
8713
|
return fallback;
|
|
8633
8714
|
}
|
|
8634
8715
|
}
|
|
8635
8716
|
function writeJsonAtPath(path, value) {
|
|
8636
|
-
|
|
8637
|
-
|
|
8717
|
+
mkdirSync14(dirname13(path), { recursive: true });
|
|
8718
|
+
writeFileSync14(path, `${JSON.stringify(value, null, 2)}
|
|
8638
8719
|
`, "utf8");
|
|
8639
8720
|
return path;
|
|
8640
8721
|
}
|
|
8641
8722
|
function readAuthorityProjectStateJson(projectRoot, relativePath, fallback) {
|
|
8642
|
-
return readJsonAtPath(
|
|
8723
|
+
return readJsonAtPath(resolve27(resolveAuthorityProjectStateDir(projectRoot), relativePath), fallback);
|
|
8643
8724
|
}
|
|
8644
8725
|
function writeAuthorityProjectStateJson(projectRoot, relativePath, value) {
|
|
8645
|
-
return writeJsonAtPath(
|
|
8726
|
+
return writeJsonAtPath(resolve27(resolveAuthorityProjectStateDir(projectRoot), relativePath), value);
|
|
8646
8727
|
}
|
|
8647
8728
|
|
|
8648
8729
|
// packages/runtime/src/control-plane/repos/mirror/state.ts
|
|
@@ -8702,7 +8783,7 @@ function sameExistingPath(left, right) {
|
|
|
8702
8783
|
try {
|
|
8703
8784
|
return realpathSync2(left) === realpathSync2(right);
|
|
8704
8785
|
} catch {
|
|
8705
|
-
return
|
|
8786
|
+
return resolve28(left) === resolve28(right);
|
|
8706
8787
|
}
|
|
8707
8788
|
}
|
|
8708
8789
|
function repoLooksUsable(repoRoot, projectRoot) {
|
|
@@ -8738,7 +8819,7 @@ function resolveMirrorRemoteUrl(layout) {
|
|
|
8738
8819
|
}
|
|
8739
8820
|
}
|
|
8740
8821
|
}
|
|
8741
|
-
if (
|
|
8822
|
+
if (existsSync27(resolve28(layout.checkoutRoot, ".git")) && checkoutLooksUsable(layout)) {
|
|
8742
8823
|
const checkoutOrigin = runGit(["git", "-C", layout.checkoutRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
8743
8824
|
if (checkoutOrigin.exitCode === 0) {
|
|
8744
8825
|
const currentOrigin = checkoutOrigin.stdout.trim();
|
|
@@ -8751,9 +8832,9 @@ function resolveMirrorRemoteUrl(layout) {
|
|
|
8751
8832
|
}
|
|
8752
8833
|
function ensureManagedRepoMirror(projectRoot, repoId) {
|
|
8753
8834
|
const layout = resolveManagedRepoLayout(projectRoot, repoId);
|
|
8754
|
-
|
|
8835
|
+
mkdirSync15(layout.metadataRoot, { recursive: true });
|
|
8755
8836
|
const remoteUrl = resolveMirrorRemoteUrl(layout);
|
|
8756
|
-
if (!
|
|
8837
|
+
if (!existsSync27(resolve28(layout.mirrorRoot, "HEAD"))) {
|
|
8757
8838
|
ensureGitSuccess(runGit(["git", "init", "--bare", layout.mirrorRoot], layout.projectRoot), ["git", "init", "--bare", layout.mirrorRoot]);
|
|
8758
8839
|
}
|
|
8759
8840
|
const getOrigin = runGit(["git", "--git-dir", layout.mirrorRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
@@ -8773,8 +8854,8 @@ function ensureManagedRepoMirror(projectRoot, repoId) {
|
|
|
8773
8854
|
return layout;
|
|
8774
8855
|
}
|
|
8775
8856
|
// packages/runtime/src/control-plane/repos/mirror/refresh.ts
|
|
8776
|
-
import { existsSync as
|
|
8777
|
-
import { resolve as
|
|
8857
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync16, realpathSync as realpathSync3, rmSync as rmSync6 } from "fs";
|
|
8858
|
+
import { resolve as resolve29 } from "path";
|
|
8778
8859
|
function nowIso3() {
|
|
8779
8860
|
return new Date().toISOString();
|
|
8780
8861
|
}
|
|
@@ -8801,7 +8882,7 @@ function sameExistingPath2(left, right) {
|
|
|
8801
8882
|
try {
|
|
8802
8883
|
return realpathSync3(left) === realpathSync3(right);
|
|
8803
8884
|
} catch {
|
|
8804
|
-
return
|
|
8885
|
+
return resolve29(left) === resolve29(right);
|
|
8805
8886
|
}
|
|
8806
8887
|
}
|
|
8807
8888
|
function ensureMirrorHead(layout) {
|
|
@@ -8847,12 +8928,12 @@ function checkoutLooksUsable2(layout) {
|
|
|
8847
8928
|
return probe.exitCode === 0 && sameExistingPath2(probe.stdout.trim(), layout.checkoutRoot);
|
|
8848
8929
|
}
|
|
8849
8930
|
function ensureCheckoutFromMirror(layout) {
|
|
8850
|
-
|
|
8851
|
-
const gitPath =
|
|
8852
|
-
if (
|
|
8931
|
+
mkdirSync16(resolve29(layout.checkoutRoot, ".."), { recursive: true });
|
|
8932
|
+
const gitPath = resolve29(layout.checkoutRoot, ".git");
|
|
8933
|
+
if (existsSync28(layout.checkoutRoot) && (!existsSync28(gitPath) || !checkoutLooksUsable2(layout))) {
|
|
8853
8934
|
rmSync6(layout.checkoutRoot, { recursive: true, force: true });
|
|
8854
8935
|
}
|
|
8855
|
-
if (!
|
|
8936
|
+
if (!existsSync28(gitPath)) {
|
|
8856
8937
|
ensureGitSuccess2(runGit2(["git", "clone", layout.mirrorRoot, layout.checkoutRoot], layout.projectRoot), ["git", "clone", layout.mirrorRoot, layout.checkoutRoot]);
|
|
8857
8938
|
}
|
|
8858
8939
|
const getOrigin = runGit2(["git", "-C", layout.checkoutRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
@@ -8953,7 +9034,7 @@ function repoDiscover(projectRoot, taskId) {
|
|
|
8953
9034
|
}
|
|
8954
9035
|
function repoBaseline(projectRoot, refresh = false) {
|
|
8955
9036
|
const paths = resolveRepoDiscoveryPaths(projectRoot);
|
|
8956
|
-
if (!refresh &&
|
|
9037
|
+
if (!refresh && existsSync29(paths.baseRepoPinsPath)) {
|
|
8957
9038
|
const baseline = readJsonFile(paths.baseRepoPinsPath, { recorded_at: nowIso(), repos: {} });
|
|
8958
9039
|
return baseline.repos || {};
|
|
8959
9040
|
}
|
|
@@ -8977,8 +9058,8 @@ function ensureMonorepoReady(projectRoot) {
|
|
|
8977
9058
|
}
|
|
8978
9059
|
function persistBaselinePins(projectRoot, repos) {
|
|
8979
9060
|
const paths = resolveRepoDiscoveryPaths(projectRoot);
|
|
8980
|
-
|
|
8981
|
-
|
|
9061
|
+
mkdirSync17(resolve30(paths.baseRepoPinsPath, ".."), { recursive: true });
|
|
9062
|
+
writeFileSync15(paths.baseRepoPinsPath, `${JSON.stringify({ recorded_at: nowIso(), repos }, null, 2)}
|
|
8982
9063
|
`, "utf-8");
|
|
8983
9064
|
return repos;
|
|
8984
9065
|
}
|
|
@@ -9057,28 +9138,28 @@ function readRepoDiscoveryTaskConfig(projectRoot) {
|
|
|
9057
9138
|
function resolveRepoDiscoveryPaths(projectRoot) {
|
|
9058
9139
|
const monorepoRoot = resolveMonorepoRepoLayout(projectRoot).checkoutRoot;
|
|
9059
9140
|
const explicitHostProjectRoot = (process.env.RIG_HOST_PROJECT_ROOT || "").trim();
|
|
9060
|
-
const normalizedProjectRoot =
|
|
9141
|
+
const normalizedProjectRoot = resolve30(projectRoot);
|
|
9061
9142
|
const hostProjectRoot = explicitHostProjectRoot && shouldUseHostProjectStateRoot(normalizedProjectRoot) ? explicitHostProjectRoot : normalizedProjectRoot;
|
|
9062
|
-
const stateDir =
|
|
9143
|
+
const stateDir = resolve30(hostProjectRoot, ".rig", "state");
|
|
9063
9144
|
return {
|
|
9064
9145
|
monorepoRoot,
|
|
9065
|
-
taskRepoCommitsPath:
|
|
9066
|
-
baseRepoPinsPath:
|
|
9146
|
+
taskRepoCommitsPath: resolve30(stateDir, "task-repo-commits.json"),
|
|
9147
|
+
baseRepoPinsPath: resolve30(stateDir, "base-repo-pins.json")
|
|
9067
9148
|
};
|
|
9068
9149
|
}
|
|
9069
9150
|
function shouldUseHostProjectStateRoot(projectRoot) {
|
|
9070
9151
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
9071
|
-
if (runtimeWorkspace &&
|
|
9152
|
+
if (runtimeWorkspace && resolve30(runtimeWorkspace) === projectRoot) {
|
|
9072
9153
|
return true;
|
|
9073
9154
|
}
|
|
9074
|
-
return basename8(
|
|
9155
|
+
return basename8(dirname14(projectRoot)) === ".worktrees";
|
|
9075
9156
|
}
|
|
9076
9157
|
function readPinFromArtifact(projectRoot, depTask, repoKey) {
|
|
9077
|
-
const snapshot =
|
|
9078
|
-
if (!
|
|
9158
|
+
const snapshot = resolve30(artifactDirForId(projectRoot, depTask), "git-state.txt");
|
|
9159
|
+
if (!existsSync29(snapshot)) {
|
|
9079
9160
|
return "";
|
|
9080
9161
|
}
|
|
9081
|
-
const content =
|
|
9162
|
+
const content = readFileSync15(snapshot, "utf-8");
|
|
9082
9163
|
const chunk = content.split(/\r?\n/);
|
|
9083
9164
|
let inSection = false;
|
|
9084
9165
|
for (const line of chunk) {
|
|
@@ -9100,12 +9181,12 @@ function repoPath(projectRoot, key) {
|
|
|
9100
9181
|
if (managed) {
|
|
9101
9182
|
return managed.checkoutRoot;
|
|
9102
9183
|
}
|
|
9103
|
-
return key.startsWith("/") ? key :
|
|
9184
|
+
return key.startsWith("/") ? key : resolve30(projectRoot, key);
|
|
9104
9185
|
}
|
|
9105
9186
|
function applyPins(projectRoot, pins) {
|
|
9106
9187
|
for (const [key, commit] of Object.entries(pins)) {
|
|
9107
9188
|
const path = repoPath(projectRoot, key);
|
|
9108
|
-
if (!
|
|
9189
|
+
if (!existsSync29(resolve30(path, ".git"))) {
|
|
9109
9190
|
throw new Error(`Repo for pin not available: ${key} (${path})`);
|
|
9110
9191
|
}
|
|
9111
9192
|
let hasCommit = runGitCapture(["git", "-C", path, "cat-file", "-e", `${commit}^{commit}`], projectRoot).exitCode === 0;
|
|
@@ -9134,7 +9215,7 @@ function verifyPins(projectRoot, pins) {
|
|
|
9134
9215
|
let ok = true;
|
|
9135
9216
|
for (const [key, expected] of Object.entries(pins)) {
|
|
9136
9217
|
const path = repoPath(projectRoot, key);
|
|
9137
|
-
if (!
|
|
9218
|
+
if (!existsSync29(resolve30(path, ".git"))) {
|
|
9138
9219
|
console.error(`ERROR: repo missing during pin verification: ${key}`);
|
|
9139
9220
|
ok = false;
|
|
9140
9221
|
continue;
|
|
@@ -9159,23 +9240,23 @@ function resolveRuntimeGitEnv() {
|
|
|
9159
9240
|
GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND
|
|
9160
9241
|
};
|
|
9161
9242
|
}
|
|
9162
|
-
const runtimeRoot = process.env.RIG_RUNTIME_HOME?.trim() || (process.env.RIG_RUNTIME_CONTEXT_FILE?.trim() ?
|
|
9163
|
-
const runtimeHome = runtimeRoot ?
|
|
9243
|
+
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()));
|
|
9244
|
+
const runtimeHome = runtimeRoot ? resolve30(runtimeRoot, "home") : process.env.HOME?.trim() || "";
|
|
9164
9245
|
if (!runtimeHome) {
|
|
9165
9246
|
return;
|
|
9166
9247
|
}
|
|
9167
|
-
const knownHostsPath =
|
|
9168
|
-
if (!
|
|
9248
|
+
const knownHostsPath = resolve30(runtimeHome, ".ssh", "known_hosts");
|
|
9249
|
+
if (!existsSync29(knownHostsPath)) {
|
|
9169
9250
|
return { HOME: runtimeHome };
|
|
9170
9251
|
}
|
|
9171
|
-
const agentSshKey =
|
|
9252
|
+
const agentSshKey = resolve30(runtimeHome, ".ssh", "rig-agent-key");
|
|
9172
9253
|
const sshParts = [
|
|
9173
9254
|
"ssh",
|
|
9174
9255
|
`-o UserKnownHostsFile="${knownHostsPath}"`,
|
|
9175
9256
|
"-o StrictHostKeyChecking=yes",
|
|
9176
9257
|
"-F /dev/null"
|
|
9177
9258
|
];
|
|
9178
|
-
if (
|
|
9259
|
+
if (existsSync29(agentSshKey)) {
|
|
9179
9260
|
sshParts.splice(1, 0, `-i "${agentSshKey}"`, "-o IdentitiesOnly=yes");
|
|
9180
9261
|
}
|
|
9181
9262
|
return {
|
|
@@ -9185,24 +9266,24 @@ function resolveRuntimeGitEnv() {
|
|
|
9185
9266
|
}
|
|
9186
9267
|
function inferRuntimeRootFromWorkspace(cwd) {
|
|
9187
9268
|
const contextPath = findRuntimeContextFile3(cwd);
|
|
9188
|
-
if (!contextPath || !
|
|
9269
|
+
if (!contextPath || !existsSync29(contextPath)) {
|
|
9189
9270
|
return "";
|
|
9190
9271
|
}
|
|
9191
9272
|
try {
|
|
9192
9273
|
loadRuntimeContext(contextPath);
|
|
9193
|
-
return
|
|
9274
|
+
return resolve30(contextPath, "..");
|
|
9194
9275
|
} catch {
|
|
9195
9276
|
return "";
|
|
9196
9277
|
}
|
|
9197
9278
|
}
|
|
9198
9279
|
function findRuntimeContextFile3(startPath) {
|
|
9199
|
-
let current =
|
|
9280
|
+
let current = resolve30(startPath);
|
|
9200
9281
|
while (true) {
|
|
9201
|
-
const candidate =
|
|
9202
|
-
if (
|
|
9282
|
+
const candidate = resolve30(current, "runtime-context.json");
|
|
9283
|
+
if (existsSync29(candidate)) {
|
|
9203
9284
|
return candidate;
|
|
9204
9285
|
}
|
|
9205
|
-
const parent =
|
|
9286
|
+
const parent = resolve30(current, "..");
|
|
9206
9287
|
if (parent === current) {
|
|
9207
9288
|
return "";
|
|
9208
9289
|
}
|
|
@@ -9211,13 +9292,13 @@ function findRuntimeContextFile3(startPath) {
|
|
|
9211
9292
|
}
|
|
9212
9293
|
|
|
9213
9294
|
// packages/runtime/src/control-plane/memory-sync/cli.ts
|
|
9214
|
-
import { existsSync as
|
|
9295
|
+
import { existsSync as existsSync30 } from "fs";
|
|
9215
9296
|
import { randomUUID } from "crypto";
|
|
9216
9297
|
|
|
9217
9298
|
// packages/runtime/src/control-plane/memory-sync/db.ts
|
|
9218
9299
|
import { Database } from "bun:sqlite";
|
|
9219
|
-
import { mkdirSync as
|
|
9220
|
-
import { dirname as
|
|
9300
|
+
import { mkdirSync as mkdirSync18 } from "fs";
|
|
9301
|
+
import { dirname as dirname15 } from "path";
|
|
9221
9302
|
|
|
9222
9303
|
// packages/runtime/src/control-plane/memory-sync/types.ts
|
|
9223
9304
|
var NO_MATCH_RETRIEVAL_CANONICAL_KEY = "__memory_recall__:none";
|
|
@@ -9813,7 +9894,7 @@ async function validateEventTargets(executor, event) {
|
|
|
9813
9894
|
}
|
|
9814
9895
|
}
|
|
9815
9896
|
async function openMemoryDb(dbPath) {
|
|
9816
|
-
|
|
9897
|
+
mkdirSync18(dirname15(dbPath), { recursive: true });
|
|
9817
9898
|
const sqlite = new Database(dbPath, { create: true, strict: true });
|
|
9818
9899
|
const client = createMemoryDbClient(sqlite);
|
|
9819
9900
|
const db = {
|
|
@@ -10232,7 +10313,7 @@ function formatMemoryQueryResults(results) {
|
|
|
10232
10313
|
}
|
|
10233
10314
|
|
|
10234
10315
|
// packages/runtime/src/control-plane/memory-sync/read.ts
|
|
10235
|
-
import { mkdtempSync, rmSync as rmSync8, writeFileSync as
|
|
10316
|
+
import { mkdtempSync, rmSync as rmSync8, writeFileSync as writeFileSync16 } from "fs";
|
|
10236
10317
|
import { tmpdir as tmpdir5 } from "os";
|
|
10237
10318
|
import { join as join5 } from "path";
|
|
10238
10319
|
var CANONICAL_MEMORY_DB_PATH = "rig/memory/project-memory.db";
|
|
@@ -10261,7 +10342,7 @@ async function readCanonicalMemoryDb(projectRoot, deps = {}) {
|
|
|
10261
10342
|
try {
|
|
10262
10343
|
try {
|
|
10263
10344
|
const bytes = readDeps.readBlobBytesAtRef(repoPath2, baseOid, CANONICAL_MEMORY_DB_PATH);
|
|
10264
|
-
|
|
10345
|
+
writeFileSync16(dbPath, bytes);
|
|
10265
10346
|
} catch (error) {
|
|
10266
10347
|
if (!isMissingCanonicalMemoryBlobError(error)) {
|
|
10267
10348
|
throw error;
|
|
@@ -10419,7 +10500,7 @@ function requireRuntimeMemoryContext(runtimeContext) {
|
|
|
10419
10500
|
}
|
|
10420
10501
|
async function ensureRuntimeMemoryUsable(runtimeContext) {
|
|
10421
10502
|
const memory = requireRuntimeMemoryContext(runtimeContext);
|
|
10422
|
-
if (!
|
|
10503
|
+
if (!existsSync30(memory.hydratedPath)) {
|
|
10423
10504
|
throw new Error(`Shared memory database is missing: ${memory.hydratedPath}`);
|
|
10424
10505
|
}
|
|
10425
10506
|
const db = await openMemoryDb(memory.hydratedPath);
|
|
@@ -10720,8 +10801,8 @@ async function executeHarnessCommand(projectRoot, args, eventBus, pluginHostCtx)
|
|
|
10720
10801
|
}
|
|
10721
10802
|
case "completion-verification":
|
|
10722
10803
|
case "completition-verification": {
|
|
10723
|
-
const hookPath =
|
|
10724
|
-
if (!
|
|
10804
|
+
const hookPath = resolve31(projectRoot, ".rig/bin/hooks/completion-verification");
|
|
10805
|
+
if (!existsSync31(hookPath)) {
|
|
10725
10806
|
throw new Error(`completion-verification hook binary not found: ${hookPath}`);
|
|
10726
10807
|
}
|
|
10727
10808
|
const proc = Bun.spawn([hookPath], {
|