@h-rig/runtime 0.0.6-alpha.34 → 0.0.6-alpha.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/rig-agent-dispatch.js +518 -459
- package/dist/bin/rig-agent.js +430 -361
- package/dist/src/control-plane/agent-wrapper.js +523 -464
- package/dist/src/control-plane/harness-main.js +528 -458
- package/dist/src/control-plane/hooks/completion-verification.js +353 -283
- package/dist/src/control-plane/hooks/inject-context.js +158 -99
- package/dist/src/control-plane/hooks/submodule-branch.js +538 -479
- package/dist/src/control-plane/hooks/task-runtime-start.js +538 -479
- package/dist/src/control-plane/materialize-task-config.js +68 -8
- package/dist/src/control-plane/native/git-ops.js +10 -0
- package/dist/src/control-plane/native/harness-cli.js +513 -443
- package/dist/src/control-plane/native/task-ops.js +392 -322
- package/dist/src/control-plane/native/validator.js +159 -100
- package/dist/src/control-plane/native/verifier.js +227 -166
- package/dist/src/control-plane/pi-settings-materializer.js +52 -0
- package/dist/src/control-plane/plugin-host-context.js +59 -0
- package/dist/src/control-plane/runtime/index.js +469 -410
- package/dist/src/control-plane/runtime/isolation/index.js +493 -434
- package/dist/src/control-plane/runtime/isolation.js +493 -434
- package/dist/src/control-plane/runtime/queue.js +411 -352
- package/dist/src/control-plane/tasks/source-lifecycle.js +87 -28
- package/package.json +8 -8
package/dist/bin/rig-agent.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// packages/runtime/bin/rig-agent.ts
|
|
5
|
-
import { existsSync as
|
|
6
|
-
import { dirname as
|
|
5
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync18, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "fs";
|
|
6
|
+
import { dirname as dirname18, resolve as resolve33 } from "path";
|
|
7
7
|
|
|
8
8
|
// packages/runtime/src/control-plane/controlled-bash.ts
|
|
9
9
|
import { readFileSync as readFileSync3 } from "fs";
|
|
@@ -3616,13 +3616,13 @@ class GeneralCliEventBus {
|
|
|
3616
3616
|
}
|
|
3617
3617
|
|
|
3618
3618
|
// packages/runtime/src/control-plane/native/git-ops.ts
|
|
3619
|
-
import { existsSync as
|
|
3620
|
-
import { dirname as
|
|
3619
|
+
import { existsSync as existsSync25, lstatSync, mkdirSync as mkdirSync12, readFileSync as readFileSync15, writeFileSync as writeFileSync12 } from "fs";
|
|
3620
|
+
import { dirname as dirname15, isAbsolute as isAbsolute2, resolve as resolve28 } from "path";
|
|
3621
3621
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3622
3622
|
|
|
3623
3623
|
// packages/runtime/src/control-plane/native/task-ops.ts
|
|
3624
|
-
import { appendFileSync, existsSync as
|
|
3625
|
-
import { resolve as
|
|
3624
|
+
import { appendFileSync, existsSync as existsSync24, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync11 } from "fs";
|
|
3625
|
+
import { resolve as resolve27 } from "path";
|
|
3626
3626
|
|
|
3627
3627
|
// packages/runtime/src/control-plane/runtime/tooling/shell.ts
|
|
3628
3628
|
import { tmpdir as tmpdir4 } from "os";
|
|
@@ -3688,6 +3688,8 @@ function runtimeGatewayToolNames() {
|
|
|
3688
3688
|
return runtimeToolGatewayNames();
|
|
3689
3689
|
}
|
|
3690
3690
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
3691
|
+
import { existsSync as existsSync13 } from "fs";
|
|
3692
|
+
import { resolve as resolvePath } from "path";
|
|
3691
3693
|
import { createPluginHost } from "@rig/core";
|
|
3692
3694
|
import { loadConfig } from "@rig/core/load-config";
|
|
3693
3695
|
|
|
@@ -4026,6 +4028,55 @@ async function materializeSkills(projectRoot, entries) {
|
|
|
4026
4028
|
return written;
|
|
4027
4029
|
}
|
|
4028
4030
|
|
|
4031
|
+
// packages/runtime/src/control-plane/pi-settings-materializer.ts
|
|
4032
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
|
|
4033
|
+
import { dirname as dirname11, resolve as resolve15 } from "path";
|
|
4034
|
+
var SETTINGS_RELATIVE_PATH = ".pi/settings.json";
|
|
4035
|
+
var MANAGED_RECORD_RELATIVE_PATH = ".rig/state/pi-managed-packages.json";
|
|
4036
|
+
function readJson(path, fallback) {
|
|
4037
|
+
if (!existsSync12(path))
|
|
4038
|
+
return fallback;
|
|
4039
|
+
try {
|
|
4040
|
+
return JSON.parse(readFileSync9(path, "utf-8"));
|
|
4041
|
+
} catch {
|
|
4042
|
+
return fallback;
|
|
4043
|
+
}
|
|
4044
|
+
}
|
|
4045
|
+
function packageKey(entry) {
|
|
4046
|
+
if (typeof entry === "string")
|
|
4047
|
+
return entry;
|
|
4048
|
+
if (entry && typeof entry === "object" && typeof entry.source === "string") {
|
|
4049
|
+
return entry.source;
|
|
4050
|
+
}
|
|
4051
|
+
return JSON.stringify(entry);
|
|
4052
|
+
}
|
|
4053
|
+
function materializePiPackages(projectRoot, declaredPackages) {
|
|
4054
|
+
const settingsPath = resolve15(projectRoot, SETTINGS_RELATIVE_PATH);
|
|
4055
|
+
const managedRecordPath = resolve15(projectRoot, MANAGED_RECORD_RELATIVE_PATH);
|
|
4056
|
+
const settings = readJson(settingsPath, {});
|
|
4057
|
+
const previouslyManaged = new Set(readJson(managedRecordPath, []));
|
|
4058
|
+
const existing = Array.isArray(settings.packages) ? settings.packages : [];
|
|
4059
|
+
const operatorEntries = existing.filter((entry) => !previouslyManaged.has(packageKey(entry)));
|
|
4060
|
+
const operatorKeys = new Set(operatorEntries.map(packageKey));
|
|
4061
|
+
const managedToAdd = declaredPackages.filter((pkg) => !operatorKeys.has(pkg));
|
|
4062
|
+
const nextPackages = [...operatorEntries, ...managedToAdd];
|
|
4063
|
+
if (nextPackages.length > 0 || existsSync12(settingsPath)) {
|
|
4064
|
+
const nextSettings = { ...settings };
|
|
4065
|
+
if (nextPackages.length > 0) {
|
|
4066
|
+
nextSettings.packages = nextPackages;
|
|
4067
|
+
} else {
|
|
4068
|
+
delete nextSettings.packages;
|
|
4069
|
+
}
|
|
4070
|
+
mkdirSync7(dirname11(settingsPath), { recursive: true });
|
|
4071
|
+
writeFileSync6(settingsPath, `${JSON.stringify(nextSettings, null, 2)}
|
|
4072
|
+
`, "utf-8");
|
|
4073
|
+
}
|
|
4074
|
+
mkdirSync7(dirname11(managedRecordPath), { recursive: true });
|
|
4075
|
+
writeFileSync6(managedRecordPath, `${JSON.stringify(managedToAdd, null, 2)}
|
|
4076
|
+
`, "utf-8");
|
|
4077
|
+
return { settingsPath, packages: managedToAdd };
|
|
4078
|
+
}
|
|
4079
|
+
|
|
4029
4080
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
4030
4081
|
async function buildPluginHostContext(projectRoot) {
|
|
4031
4082
|
let config;
|
|
@@ -4073,6 +4124,14 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
4073
4124
|
} catch (err) {
|
|
4074
4125
|
console.warn(`[plugin-host] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
4075
4126
|
}
|
|
4127
|
+
try {
|
|
4128
|
+
const piPackages = config.runtime?.pi?.packages ?? [];
|
|
4129
|
+
if (piPackages.length > 0 || existsSync13(resolvePath(projectRoot, ".rig/state/pi-managed-packages.json"))) {
|
|
4130
|
+
materializePiPackages(projectRoot, piPackages);
|
|
4131
|
+
}
|
|
4132
|
+
} catch (err) {
|
|
4133
|
+
console.warn(`[plugin-host] Pi package materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
4134
|
+
}
|
|
4076
4135
|
return {
|
|
4077
4136
|
config,
|
|
4078
4137
|
pluginHost,
|
|
@@ -4086,12 +4145,12 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
4086
4145
|
|
|
4087
4146
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
4088
4147
|
import { spawnSync } from "child_process";
|
|
4089
|
-
import { existsSync as
|
|
4090
|
-
import { basename as basename4, join as join3, resolve as
|
|
4148
|
+
import { existsSync as existsSync15, readFileSync as readFileSync11, readdirSync as readdirSync2, statSync as statSync3, writeFileSync as writeFileSync7 } from "fs";
|
|
4149
|
+
import { basename as basename4, join as join3, resolve as resolve17 } from "path";
|
|
4091
4150
|
|
|
4092
4151
|
// packages/runtime/src/control-plane/tasks/legacy-task-config-source.ts
|
|
4093
|
-
import { existsSync as
|
|
4094
|
-
import { resolve as
|
|
4152
|
+
import { existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
|
|
4153
|
+
import { resolve as resolve16 } from "path";
|
|
4095
4154
|
|
|
4096
4155
|
// packages/runtime/src/control-plane/tasks/task-record-reader.ts
|
|
4097
4156
|
async function findTaskById(reader, id) {
|
|
@@ -4114,7 +4173,7 @@ class LegacyTaskConfigReadError extends Error {
|
|
|
4114
4173
|
}
|
|
4115
4174
|
}
|
|
4116
4175
|
function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
4117
|
-
const configPath = options.configPath ??
|
|
4176
|
+
const configPath = options.configPath ?? resolve16(projectRoot, ".rig", "task-config.json");
|
|
4118
4177
|
const reader = {
|
|
4119
4178
|
async listTasks() {
|
|
4120
4179
|
return readLegacyTaskRecords(projectRoot, configPath);
|
|
@@ -4125,8 +4184,8 @@ function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
|
4125
4184
|
};
|
|
4126
4185
|
return reader;
|
|
4127
4186
|
}
|
|
4128
|
-
function readLegacyTaskRecords(projectRoot, configPath =
|
|
4129
|
-
if (!
|
|
4187
|
+
function readLegacyTaskRecords(projectRoot, configPath = resolve16(projectRoot, ".rig", "task-config.json")) {
|
|
4188
|
+
if (!existsSync14(configPath)) {
|
|
4130
4189
|
return [];
|
|
4131
4190
|
}
|
|
4132
4191
|
const rawConfig = readLegacyTaskConfigJson(projectRoot, configPath);
|
|
@@ -4134,7 +4193,7 @@ function readLegacyTaskRecords(projectRoot, configPath = resolve15(projectRoot,
|
|
|
4134
4193
|
}
|
|
4135
4194
|
function readLegacyTaskConfigJson(projectRoot, configPath) {
|
|
4136
4195
|
try {
|
|
4137
|
-
const parsed = JSON.parse(
|
|
4196
|
+
const parsed = JSON.parse(readFileSync10(configPath, "utf8"));
|
|
4138
4197
|
if (isPlainRecord(parsed)) {
|
|
4139
4198
|
return parsed;
|
|
4140
4199
|
}
|
|
@@ -4218,7 +4277,7 @@ function isPlainRecord(candidate) {
|
|
|
4218
4277
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
4219
4278
|
var FILE_TASK_PATTERN = /\.(task\.)?json$/;
|
|
4220
4279
|
function createSourceAwareTaskConfigRecordReader(projectRoot, options = {}) {
|
|
4221
|
-
const configPath = options.configPath ??
|
|
4280
|
+
const configPath = options.configPath ?? resolve17(projectRoot, ".rig", "task-config.json");
|
|
4222
4281
|
const legacy = createLegacyTaskConfigRecordReader(projectRoot, { configPath });
|
|
4223
4282
|
const spawnFn = options.spawn ?? spawnSync;
|
|
4224
4283
|
const ghBinary = options.ghBinary ?? "gh";
|
|
@@ -4301,10 +4360,10 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
4301
4360
|
return metadata;
|
|
4302
4361
|
}
|
|
4303
4362
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
4304
|
-
const jsonPath =
|
|
4305
|
-
if (
|
|
4363
|
+
const jsonPath = resolve17(projectRoot, "rig.config.json");
|
|
4364
|
+
if (existsSync15(jsonPath)) {
|
|
4306
4365
|
try {
|
|
4307
|
-
const parsed = JSON.parse(
|
|
4366
|
+
const parsed = JSON.parse(readFileSync11(jsonPath, "utf8"));
|
|
4308
4367
|
if (isPlainRecord2(parsed) && isPlainRecord2(parsed.taskSource)) {
|
|
4309
4368
|
const source = parsed.taskSource;
|
|
4310
4369
|
return source.kind === "files" && typeof source.path === "string" ? source.path : null;
|
|
@@ -4313,12 +4372,12 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
4313
4372
|
return null;
|
|
4314
4373
|
}
|
|
4315
4374
|
}
|
|
4316
|
-
const tsPath =
|
|
4317
|
-
if (!
|
|
4375
|
+
const tsPath = resolve17(projectRoot, "rig.config.ts");
|
|
4376
|
+
if (!existsSync15(tsPath)) {
|
|
4318
4377
|
return null;
|
|
4319
4378
|
}
|
|
4320
4379
|
try {
|
|
4321
|
-
const source =
|
|
4380
|
+
const source = readFileSync11(tsPath, "utf8");
|
|
4322
4381
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
4323
4382
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
4324
4383
|
if (kind !== "files") {
|
|
@@ -4338,10 +4397,10 @@ function readRawTaskEntry(configPath, taskId) {
|
|
|
4338
4397
|
return isPlainRecord2(entry) ? entry : null;
|
|
4339
4398
|
}
|
|
4340
4399
|
function readRawTaskConfig(configPath) {
|
|
4341
|
-
if (!
|
|
4400
|
+
if (!existsSync15(configPath)) {
|
|
4342
4401
|
return null;
|
|
4343
4402
|
}
|
|
4344
|
-
const parsed = JSON.parse(
|
|
4403
|
+
const parsed = JSON.parse(readFileSync11(configPath, "utf8"));
|
|
4345
4404
|
return isPlainRecord2(parsed) ? parsed : null;
|
|
4346
4405
|
}
|
|
4347
4406
|
function stripLegacyTaskConfigMetadata2(raw) {
|
|
@@ -4349,8 +4408,8 @@ function stripLegacyTaskConfigMetadata2(raw) {
|
|
|
4349
4408
|
return tasks;
|
|
4350
4409
|
}
|
|
4351
4410
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
4352
|
-
const directory =
|
|
4353
|
-
if (!
|
|
4411
|
+
const directory = resolve17(projectRoot, sourcePath);
|
|
4412
|
+
if (!existsSync15(directory)) {
|
|
4354
4413
|
return [];
|
|
4355
4414
|
}
|
|
4356
4415
|
const tasks = [];
|
|
@@ -4365,11 +4424,11 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
4365
4424
|
return tasks;
|
|
4366
4425
|
}
|
|
4367
4426
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
4368
|
-
const file = findFileBackedTaskFile(
|
|
4427
|
+
const file = findFileBackedTaskFile(resolve17(projectRoot, sourcePath), taskId);
|
|
4369
4428
|
if (!file) {
|
|
4370
4429
|
return null;
|
|
4371
4430
|
}
|
|
4372
|
-
const raw = JSON.parse(
|
|
4431
|
+
const raw = JSON.parse(readFileSync11(file, "utf8"));
|
|
4373
4432
|
if (!isPlainRecord2(raw)) {
|
|
4374
4433
|
return null;
|
|
4375
4434
|
}
|
|
@@ -4382,7 +4441,7 @@ function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
|
4382
4441
|
};
|
|
4383
4442
|
}
|
|
4384
4443
|
function findFileBackedTaskFile(directory, taskId) {
|
|
4385
|
-
if (!
|
|
4444
|
+
if (!existsSync15(directory)) {
|
|
4386
4445
|
return null;
|
|
4387
4446
|
}
|
|
4388
4447
|
for (const name of readdirSync2(directory)) {
|
|
@@ -4392,7 +4451,7 @@ function findFileBackedTaskFile(directory, taskId) {
|
|
|
4392
4451
|
try {
|
|
4393
4452
|
if (!statSync3(file).isFile())
|
|
4394
4453
|
continue;
|
|
4395
|
-
const raw = JSON.parse(
|
|
4454
|
+
const raw = JSON.parse(readFileSync11(file, "utf8"));
|
|
4396
4455
|
const inferredId = basename4(file).replace(FILE_TASK_PATTERN, "");
|
|
4397
4456
|
const id = isPlainRecord2(raw) && typeof raw.id === "string" ? raw.id : inferredId;
|
|
4398
4457
|
if (id === taskId) {
|
|
@@ -4552,8 +4611,8 @@ async function readConfiguredTaskSourceTask(projectRoot, taskId) {
|
|
|
4552
4611
|
}
|
|
4553
4612
|
|
|
4554
4613
|
// packages/runtime/src/control-plane/native/task-state.ts
|
|
4555
|
-
import { existsSync as
|
|
4556
|
-
import { basename as basename6, resolve as
|
|
4614
|
+
import { existsSync as existsSync19, readFileSync as readFileSync13, readdirSync as readdirSync3, statSync as statSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
4615
|
+
import { basename as basename6, resolve as resolve21 } from "path";
|
|
4557
4616
|
|
|
4558
4617
|
// packages/runtime/src/control-plane/state-sync/types.ts
|
|
4559
4618
|
var SUPPORTED_TASK_STATE_SCHEMA_VERSION = 1;
|
|
@@ -4661,38 +4720,38 @@ function readTaskStateMetadataEnvelope(raw) {
|
|
|
4661
4720
|
};
|
|
4662
4721
|
}
|
|
4663
4722
|
// packages/runtime/src/control-plane/state-sync/read.ts
|
|
4664
|
-
import { existsSync as
|
|
4665
|
-
import { resolve as
|
|
4723
|
+
import { existsSync as existsSync18, readFileSync as readFileSync12 } from "fs";
|
|
4724
|
+
import { resolve as resolve20 } from "path";
|
|
4666
4725
|
|
|
4667
4726
|
// packages/runtime/src/control-plane/state-sync/repo.ts
|
|
4668
|
-
import { existsSync as
|
|
4669
|
-
import { resolve as
|
|
4727
|
+
import { existsSync as existsSync17 } from "fs";
|
|
4728
|
+
import { resolve as resolve19 } from "path";
|
|
4670
4729
|
|
|
4671
4730
|
// packages/runtime/src/control-plane/repos/layout.ts
|
|
4672
|
-
import { existsSync as
|
|
4673
|
-
import { basename as basename5, dirname as
|
|
4731
|
+
import { existsSync as existsSync16 } from "fs";
|
|
4732
|
+
import { basename as basename5, dirname as dirname12, join as join4, resolve as resolve18 } from "path";
|
|
4674
4733
|
function resolveRepoStateDir(projectRoot) {
|
|
4675
|
-
const normalizedProjectRoot =
|
|
4676
|
-
const projectParent =
|
|
4734
|
+
const normalizedProjectRoot = resolve18(projectRoot);
|
|
4735
|
+
const projectParent = dirname12(normalizedProjectRoot);
|
|
4677
4736
|
if (basename5(projectParent) === ".worktrees") {
|
|
4678
|
-
const ownerRoot =
|
|
4679
|
-
const ownerHasRepoMarkers =
|
|
4737
|
+
const ownerRoot = dirname12(projectParent);
|
|
4738
|
+
const ownerHasRepoMarkers = existsSync16(resolve18(ownerRoot, ".git")) || existsSync16(resolve18(ownerRoot, ".rig", "state"));
|
|
4680
4739
|
if (ownerHasRepoMarkers) {
|
|
4681
|
-
return
|
|
4740
|
+
return resolve18(ownerRoot, ".rig", "state");
|
|
4682
4741
|
}
|
|
4683
4742
|
}
|
|
4684
|
-
return
|
|
4743
|
+
return resolve18(projectRoot, ".rig", "state");
|
|
4685
4744
|
}
|
|
4686
4745
|
function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
4687
|
-
const normalizedProjectRoot =
|
|
4746
|
+
const normalizedProjectRoot = resolve18(projectRoot);
|
|
4688
4747
|
const entry = getManagedRepoEntry(repoId);
|
|
4689
4748
|
const stateDir = resolveRepoStateDir(normalizedProjectRoot);
|
|
4690
4749
|
const metadataRelativePath = join4("repos", entry.id);
|
|
4691
|
-
const metadataRoot =
|
|
4750
|
+
const metadataRoot = resolve18(stateDir, metadataRelativePath);
|
|
4692
4751
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
4693
|
-
const runsInsideTaskWorktree = runtimeWorkspace &&
|
|
4752
|
+
const runsInsideTaskWorktree = runtimeWorkspace && resolve18(runtimeWorkspace) === normalizedProjectRoot || basename5(dirname12(normalizedProjectRoot)) === ".worktrees";
|
|
4694
4753
|
const isPrimaryManagedRepo = listManagedRepoEntries()[0]?.id === repoId;
|
|
4695
|
-
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ?
|
|
4754
|
+
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ? resolve18(process.env[entry.checkoutEnvVar].trim()) : resolve18(normalizedProjectRoot, entry.alias);
|
|
4696
4755
|
return {
|
|
4697
4756
|
projectRoot: normalizedProjectRoot,
|
|
4698
4757
|
repoId: entry.id,
|
|
@@ -4700,12 +4759,12 @@ function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
|
4700
4759
|
defaultBranch: entry.defaultBranch,
|
|
4701
4760
|
remoteUrl: entry.remoteEnvVar && process.env[entry.remoteEnvVar]?.trim() ? process.env[entry.remoteEnvVar].trim() : entry.defaultRemoteUrl,
|
|
4702
4761
|
checkoutRoot,
|
|
4703
|
-
worktreesRoot:
|
|
4762
|
+
worktreesRoot: resolve18(checkoutRoot, ".worktrees"),
|
|
4704
4763
|
stateDir,
|
|
4705
4764
|
metadataRoot,
|
|
4706
4765
|
metadataRelativePath,
|
|
4707
|
-
mirrorRoot:
|
|
4708
|
-
mirrorStatePath:
|
|
4766
|
+
mirrorRoot: resolve18(metadataRoot, "mirror.git"),
|
|
4767
|
+
mirrorStatePath: resolve18(metadataRoot, "mirror-state.json"),
|
|
4709
4768
|
mirrorStateRelativePath: join4(metadataRelativePath, "mirror-state.json")
|
|
4710
4769
|
};
|
|
4711
4770
|
}
|
|
@@ -4727,7 +4786,7 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
4727
4786
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
4728
4787
|
try {
|
|
4729
4788
|
const layout = resolveMonorepoRepoLayout(projectRoot);
|
|
4730
|
-
if (
|
|
4789
|
+
if (existsSync17(resolve19(layout.mirrorRoot, "HEAD"))) {
|
|
4731
4790
|
return layout.mirrorRoot;
|
|
4732
4791
|
}
|
|
4733
4792
|
} catch {}
|
|
@@ -4738,8 +4797,8 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
4738
4797
|
var DEFAULT_READ_DEPS2 = {
|
|
4739
4798
|
fetchRef: nativeFetchRef,
|
|
4740
4799
|
readBlobAtRef: nativeReadBlobAtRef,
|
|
4741
|
-
exists:
|
|
4742
|
-
readFile: (path) =>
|
|
4800
|
+
exists: existsSync18,
|
|
4801
|
+
readFile: (path) => readFileSync12(path, "utf8")
|
|
4743
4802
|
};
|
|
4744
4803
|
function parseIssueStatus(rawStatus) {
|
|
4745
4804
|
const normalized = normalizeTaskLifecycleStatus(rawStatus);
|
|
@@ -4820,12 +4879,12 @@ function shouldPreferLocalTrackerState(options) {
|
|
|
4820
4879
|
if (runtimeContextPath) {
|
|
4821
4880
|
return true;
|
|
4822
4881
|
}
|
|
4823
|
-
return
|
|
4882
|
+
return existsSync18(resolve20(runtimeWorkspace, ".rig", "runtime-context.json"));
|
|
4824
4883
|
}
|
|
4825
4884
|
function readLocalTrackerState(projectRoot, deps) {
|
|
4826
4885
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
4827
|
-
const issuesPath =
|
|
4828
|
-
const taskStatePath =
|
|
4886
|
+
const issuesPath = resolve20(monorepoRoot, ".beads", "issues.jsonl");
|
|
4887
|
+
const taskStatePath = resolve20(monorepoRoot, ".beads", "task-state.json");
|
|
4829
4888
|
return projectSyncedTrackerSnapshot({
|
|
4830
4889
|
source: "local",
|
|
4831
4890
|
issuesBaseOid: null,
|
|
@@ -4887,7 +4946,7 @@ function readValidationDescriptions(projectRoot) {
|
|
|
4887
4946
|
return readValidationDescriptionMap(raw);
|
|
4888
4947
|
}
|
|
4889
4948
|
function readSourceValidationDescriptions(projectRoot) {
|
|
4890
|
-
const rootRaw = readJsonFile(
|
|
4949
|
+
const rootRaw = readJsonFile(resolve21(projectRoot, "rig", "task-config.json"), {});
|
|
4891
4950
|
const sourcePath = findSourceTaskConfigPath(projectRoot);
|
|
4892
4951
|
const sourceRaw = sourcePath ? readJsonFile(sourcePath, {}) : {};
|
|
4893
4952
|
const rootDescriptions = readValidationDescriptionMap(rootRaw);
|
|
@@ -4963,15 +5022,15 @@ function readValidationDescriptionsFromMeta(meta) {
|
|
|
4963
5022
|
return meta.validation_descriptions;
|
|
4964
5023
|
}
|
|
4965
5024
|
function readLocalSourceTaskStateEnvelope(projectRoot) {
|
|
4966
|
-
const taskStatePath =
|
|
5025
|
+
const taskStatePath = resolve21(resolveMonorepoRoot2(projectRoot), ".beads", "task-state.json");
|
|
4967
5026
|
return readTaskStateMetadataEnvelope(readJsonFile(taskStatePath, {}));
|
|
4968
5027
|
}
|
|
4969
5028
|
function readLocalSourceTaskLifecycleStatus(projectRoot, taskId) {
|
|
4970
|
-
const issuesPath =
|
|
4971
|
-
if (!
|
|
5029
|
+
const issuesPath = resolve21(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
5030
|
+
if (!existsSync19(issuesPath)) {
|
|
4972
5031
|
return null;
|
|
4973
5032
|
}
|
|
4974
|
-
for (const line of
|
|
5033
|
+
for (const line of readFileSync13(issuesPath, "utf8").split(/\r?\n/)) {
|
|
4975
5034
|
const trimmed = line.trim();
|
|
4976
5035
|
if (!trimmed) {
|
|
4977
5036
|
continue;
|
|
@@ -5012,25 +5071,25 @@ function lookupTask(projectRoot, input) {
|
|
|
5012
5071
|
function artifactDirForId(projectRoot, id) {
|
|
5013
5072
|
const workspaceDir = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
5014
5073
|
if (workspaceDir) {
|
|
5015
|
-
const worktreeArtifacts =
|
|
5016
|
-
if (
|
|
5074
|
+
const worktreeArtifacts = resolve21(workspaceDir, "artifacts", id);
|
|
5075
|
+
if (existsSync19(worktreeArtifacts) || existsSync19(resolve21(workspaceDir, "artifacts"))) {
|
|
5017
5076
|
return worktreeArtifacts;
|
|
5018
5077
|
}
|
|
5019
5078
|
}
|
|
5020
5079
|
try {
|
|
5021
5080
|
const paths = resolveHarnessPaths(projectRoot);
|
|
5022
|
-
return
|
|
5081
|
+
return resolve21(paths.artifactsDir, id);
|
|
5023
5082
|
} catch {
|
|
5024
|
-
return
|
|
5083
|
+
return resolve21(resolveMonorepoRoot2(projectRoot), "artifacts", id);
|
|
5025
5084
|
}
|
|
5026
5085
|
}
|
|
5027
5086
|
function resolveTaskConfigPath(projectRoot) {
|
|
5028
5087
|
const paths = resolveHarnessPaths(projectRoot);
|
|
5029
|
-
if (
|
|
5088
|
+
if (existsSync19(paths.taskConfigPath)) {
|
|
5030
5089
|
return paths.taskConfigPath;
|
|
5031
5090
|
}
|
|
5032
5091
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
5033
|
-
if (
|
|
5092
|
+
if (existsSync19(candidate)) {
|
|
5034
5093
|
return candidate;
|
|
5035
5094
|
}
|
|
5036
5095
|
}
|
|
@@ -5038,7 +5097,7 @@ function resolveTaskConfigPath(projectRoot) {
|
|
|
5038
5097
|
}
|
|
5039
5098
|
function findSourceTaskConfigPath(projectRoot) {
|
|
5040
5099
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
5041
|
-
if (
|
|
5100
|
+
if (existsSync19(candidate)) {
|
|
5042
5101
|
return candidate;
|
|
5043
5102
|
}
|
|
5044
5103
|
}
|
|
@@ -5051,7 +5110,7 @@ function readAndSyncSourceTaskConfig(projectRoot) {
|
|
|
5051
5110
|
const synced = synchronizeTaskConfigWithTracker(projectRoot, raw);
|
|
5052
5111
|
if (sourcePath && synced.updated) {
|
|
5053
5112
|
try {
|
|
5054
|
-
|
|
5113
|
+
writeFileSync8(sourcePath, `${JSON.stringify(synced.config, null, 2)}
|
|
5055
5114
|
`, "utf-8");
|
|
5056
5115
|
} catch {}
|
|
5057
5116
|
}
|
|
@@ -5103,12 +5162,12 @@ function shouldRefreshAutoSyncedTaskConfigEntry(entry) {
|
|
|
5103
5162
|
return !candidate.role;
|
|
5104
5163
|
}
|
|
5105
5164
|
function readSourceIssueRecords(projectRoot) {
|
|
5106
|
-
const issuesPath =
|
|
5107
|
-
if (!
|
|
5165
|
+
const issuesPath = resolve21(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
5166
|
+
if (!existsSync19(issuesPath)) {
|
|
5108
5167
|
return [];
|
|
5109
5168
|
}
|
|
5110
5169
|
const records = [];
|
|
5111
|
-
for (const line of
|
|
5170
|
+
for (const line of readFileSync13(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
5112
5171
|
const trimmed = line.trim();
|
|
5113
5172
|
if (!trimmed) {
|
|
5114
5173
|
continue;
|
|
@@ -5164,19 +5223,19 @@ function readConfiguredFileTaskConfig(projectRoot) {
|
|
|
5164
5223
|
if (!sourcePath) {
|
|
5165
5224
|
return {};
|
|
5166
5225
|
}
|
|
5167
|
-
const directory =
|
|
5168
|
-
if (!
|
|
5226
|
+
const directory = resolve21(projectRoot, sourcePath);
|
|
5227
|
+
if (!existsSync19(directory)) {
|
|
5169
5228
|
return {};
|
|
5170
5229
|
}
|
|
5171
5230
|
const config = {};
|
|
5172
5231
|
for (const name of readdirSync3(directory)) {
|
|
5173
5232
|
if (!FILE_TASK_PATTERN2.test(name))
|
|
5174
5233
|
continue;
|
|
5175
|
-
const file =
|
|
5234
|
+
const file = resolve21(directory, name);
|
|
5176
5235
|
try {
|
|
5177
5236
|
if (!statSync4(file).isFile())
|
|
5178
5237
|
continue;
|
|
5179
|
-
const raw = JSON.parse(
|
|
5238
|
+
const raw = JSON.parse(readFileSync13(file, "utf8"));
|
|
5180
5239
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
5181
5240
|
continue;
|
|
5182
5241
|
const record = raw;
|
|
@@ -5218,10 +5277,10 @@ function firstStringList2(...candidates) {
|
|
|
5218
5277
|
return [];
|
|
5219
5278
|
}
|
|
5220
5279
|
function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
5221
|
-
const jsonPath =
|
|
5222
|
-
if (
|
|
5280
|
+
const jsonPath = resolve21(projectRoot, "rig.config.json");
|
|
5281
|
+
if (existsSync19(jsonPath)) {
|
|
5223
5282
|
try {
|
|
5224
|
-
const parsed = JSON.parse(
|
|
5283
|
+
const parsed = JSON.parse(readFileSync13(jsonPath, "utf8"));
|
|
5225
5284
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
5226
5285
|
const taskSource = parsed.taskSource;
|
|
5227
5286
|
if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
|
|
@@ -5233,12 +5292,12 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
5233
5292
|
return null;
|
|
5234
5293
|
}
|
|
5235
5294
|
}
|
|
5236
|
-
const tsPath =
|
|
5237
|
-
if (!
|
|
5295
|
+
const tsPath = resolve21(projectRoot, "rig.config.ts");
|
|
5296
|
+
if (!existsSync19(tsPath)) {
|
|
5238
5297
|
return null;
|
|
5239
5298
|
}
|
|
5240
5299
|
try {
|
|
5241
|
-
const source =
|
|
5300
|
+
const source = readFileSync13(tsPath, "utf8");
|
|
5242
5301
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
5243
5302
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
5244
5303
|
if (kind !== "files") {
|
|
@@ -5252,23 +5311,23 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
5252
5311
|
function sourceTaskConfigCandidates(projectRoot) {
|
|
5253
5312
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
5254
5313
|
return [
|
|
5255
|
-
runtimeContext?.monorepoMainRoot ?
|
|
5256
|
-
process.env.MONOREPO_MAIN_ROOT?.trim() ?
|
|
5257
|
-
|
|
5314
|
+
runtimeContext?.monorepoMainRoot ? resolve21(runtimeContext.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
5315
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve21(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
5316
|
+
resolve21(resolveMonorepoRoot2(projectRoot), ".rig", "task-config.json")
|
|
5258
5317
|
].filter(Boolean);
|
|
5259
5318
|
}
|
|
5260
5319
|
|
|
5261
5320
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
5262
|
-
import { existsSync as
|
|
5263
|
-
import { resolve as
|
|
5321
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
|
|
5322
|
+
import { resolve as resolve26 } from "path";
|
|
5264
5323
|
|
|
5265
5324
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
5266
|
-
import { existsSync as
|
|
5267
|
-
import { dirname as
|
|
5325
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync9, rmSync as rmSync6, statSync as statSync5 } from "fs";
|
|
5326
|
+
import { dirname as dirname14, resolve as resolve25 } from "path";
|
|
5268
5327
|
|
|
5269
5328
|
// packages/runtime/src/binary-run.ts
|
|
5270
|
-
import { chmodSync as chmodSync2, cpSync, existsSync as
|
|
5271
|
-
import { basename as basename7, dirname as
|
|
5329
|
+
import { chmodSync as chmodSync2, cpSync, existsSync as existsSync20, mkdirSync as mkdirSync8, renameSync as renameSync3, rmSync as rmSync5, writeFileSync as writeFileSync9 } from "fs";
|
|
5330
|
+
import { basename as basename7, dirname as dirname13, resolve as resolve22 } from "path";
|
|
5272
5331
|
import { fileURLToPath } from "url";
|
|
5273
5332
|
import { drainMicrotasks, gcAndSweep } from "bun:jsc";
|
|
5274
5333
|
var runtimeBinaryBuildQueue = Promise.resolve();
|
|
@@ -5294,9 +5353,9 @@ async function buildRuntimeBinary(options) {
|
|
|
5294
5353
|
});
|
|
5295
5354
|
}
|
|
5296
5355
|
async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
5297
|
-
const tempBuildDir =
|
|
5298
|
-
const tempOutputPath =
|
|
5299
|
-
|
|
5356
|
+
const tempBuildDir = resolve22(dirname13(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
5357
|
+
const tempOutputPath = resolve22(tempBuildDir, basename7(options.outputPath));
|
|
5358
|
+
mkdirSync8(tempBuildDir, { recursive: true });
|
|
5300
5359
|
await withTemporaryEnv({
|
|
5301
5360
|
...options.env,
|
|
5302
5361
|
...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
|
|
@@ -5321,7 +5380,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
5321
5380
|
`);
|
|
5322
5381
|
throw new Error(`Failed to build ${options.entrypoint}: ${details || "Bun.build() returned errors"}`);
|
|
5323
5382
|
}
|
|
5324
|
-
if (!
|
|
5383
|
+
if (!existsSync20(tempOutputPath)) {
|
|
5325
5384
|
const emitted = buildResult.outputs.map((output) => output.path).join(", ") || "(none)";
|
|
5326
5385
|
throw new Error(`Failed to build ${options.entrypoint}: Bun.build() did not emit ${tempOutputPath}. Emitted: ${emitted}`);
|
|
5327
5386
|
}
|
|
@@ -5353,8 +5412,8 @@ function runtimeBinaryCacheManifestPath(outputPath) {
|
|
|
5353
5412
|
function resolveRuntimeBinaryBuildOptions(options) {
|
|
5354
5413
|
return {
|
|
5355
5414
|
...options,
|
|
5356
|
-
entrypoint:
|
|
5357
|
-
outputPath:
|
|
5415
|
+
entrypoint: resolve22(options.cwd, options.sourcePath),
|
|
5416
|
+
outputPath: resolve22(options.outputPath)
|
|
5358
5417
|
};
|
|
5359
5418
|
}
|
|
5360
5419
|
function shouldUseRuntimeBinaryBuildWorker() {
|
|
@@ -5368,7 +5427,7 @@ function shouldUseRuntimeBinaryBuildWorker() {
|
|
|
5368
5427
|
}
|
|
5369
5428
|
async function buildRuntimeBinaryViaWorker(options) {
|
|
5370
5429
|
const workerSourcePath = resolveRuntimeBinaryBuildWorkerSourcePath(options);
|
|
5371
|
-
if (!workerSourcePath || !
|
|
5430
|
+
if (!workerSourcePath || !existsSync20(workerSourcePath)) {
|
|
5372
5431
|
await buildRuntimeBinaryInProcess(options, {
|
|
5373
5432
|
manifestPath: runtimeBinaryCacheManifestPath(options.outputPath),
|
|
5374
5433
|
buildKey: createRuntimeBinaryBuildKey({
|
|
@@ -5405,7 +5464,7 @@ async function buildRuntimeBinaryViaWorker(options) {
|
|
|
5405
5464
|
}
|
|
5406
5465
|
}
|
|
5407
5466
|
function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
|
|
5408
|
-
return
|
|
5467
|
+
return resolve22(dirname13(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
5409
5468
|
}
|
|
5410
5469
|
function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
5411
5470
|
const envRoots = [
|
|
@@ -5414,13 +5473,13 @@ function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
|
5414
5473
|
process.env.PROJECT_RIG_ROOT?.trim()
|
|
5415
5474
|
].filter(Boolean);
|
|
5416
5475
|
for (const root of envRoots) {
|
|
5417
|
-
const candidate =
|
|
5418
|
-
if (
|
|
5476
|
+
const candidate = resolve22(root, "packages/runtime/src/binary-build-worker.ts");
|
|
5477
|
+
if (existsSync20(candidate)) {
|
|
5419
5478
|
return candidate;
|
|
5420
5479
|
}
|
|
5421
5480
|
}
|
|
5422
|
-
const localCandidate =
|
|
5423
|
-
return
|
|
5481
|
+
const localCandidate = resolve22(import.meta.dir, "binary-build-worker.ts");
|
|
5482
|
+
return existsSync20(localCandidate) ? localCandidate : null;
|
|
5424
5483
|
}
|
|
5425
5484
|
function resolveRuntimeBinaryBuildWorkerInvocation() {
|
|
5426
5485
|
const bunPath = Bun.which("bun");
|
|
@@ -5456,7 +5515,7 @@ function createRuntimeBinaryBuildKey(input) {
|
|
|
5456
5515
|
});
|
|
5457
5516
|
}
|
|
5458
5517
|
async function isRuntimeBinaryBuildFresh(input) {
|
|
5459
|
-
if (!
|
|
5518
|
+
if (!existsSync20(input.outputPath) || !existsSync20(input.manifestPath)) {
|
|
5460
5519
|
return false;
|
|
5461
5520
|
}
|
|
5462
5521
|
let manifest = null;
|
|
@@ -5469,7 +5528,7 @@ async function isRuntimeBinaryBuildFresh(input) {
|
|
|
5469
5528
|
return false;
|
|
5470
5529
|
}
|
|
5471
5530
|
for (const [filePath, expectedDigest] of Object.entries(manifest.inputs || {})) {
|
|
5472
|
-
if (!
|
|
5531
|
+
if (!existsSync20(filePath)) {
|
|
5473
5532
|
return false;
|
|
5474
5533
|
}
|
|
5475
5534
|
if (await sha256File(filePath) !== expectedDigest) {
|
|
@@ -5482,7 +5541,7 @@ async function writeRuntimeBinaryCacheManifest(input) {
|
|
|
5482
5541
|
const inputs = {};
|
|
5483
5542
|
for (const inputPath of Object.keys(input.metafile?.inputs || {}).sort()) {
|
|
5484
5543
|
const normalized = normalizeBuildInputPath(input.cwd, inputPath);
|
|
5485
|
-
if (!normalized || !
|
|
5544
|
+
if (!normalized || !existsSync20(normalized)) {
|
|
5486
5545
|
continue;
|
|
5487
5546
|
}
|
|
5488
5547
|
inputs[normalized] = await sha256File(normalized);
|
|
@@ -5505,7 +5564,7 @@ function normalizeBuildInputPath(cwd, inputPath) {
|
|
|
5505
5564
|
if (inputPath.startsWith("<")) {
|
|
5506
5565
|
return null;
|
|
5507
5566
|
}
|
|
5508
|
-
return
|
|
5567
|
+
return resolve22(cwd, inputPath);
|
|
5509
5568
|
}
|
|
5510
5569
|
async function sha256File(path) {
|
|
5511
5570
|
const hasher = new Bun.CryptoHasher("sha256");
|
|
@@ -5521,8 +5580,8 @@ function sortRecord(value) {
|
|
|
5521
5580
|
async function runSerializedRuntimeBinaryBuild(action) {
|
|
5522
5581
|
const previous = runtimeBinaryBuildQueue;
|
|
5523
5582
|
let release;
|
|
5524
|
-
runtimeBinaryBuildQueue = new Promise((
|
|
5525
|
-
release =
|
|
5583
|
+
runtimeBinaryBuildQueue = new Promise((resolve23) => {
|
|
5584
|
+
release = resolve23;
|
|
5526
5585
|
});
|
|
5527
5586
|
await previous;
|
|
5528
5587
|
try {
|
|
@@ -5567,11 +5626,11 @@ async function withTemporaryCwd(cwd, action) {
|
|
|
5567
5626
|
}
|
|
5568
5627
|
|
|
5569
5628
|
// packages/runtime/src/control-plane/runtime/provisioning-env.ts
|
|
5570
|
-
import { delimiter, resolve as
|
|
5629
|
+
import { delimiter, resolve as resolve24 } from "path";
|
|
5571
5630
|
|
|
5572
5631
|
// packages/runtime/src/control-plane/runtime/runtime-paths.ts
|
|
5573
|
-
import { existsSync as
|
|
5574
|
-
import { resolve as
|
|
5632
|
+
import { existsSync as existsSync21, readdirSync as readdirSync4, realpathSync } from "fs";
|
|
5633
|
+
import { resolve as resolve23 } from "path";
|
|
5575
5634
|
|
|
5576
5635
|
// packages/runtime/src/control-plane/runtime/sandbox/utils.ts
|
|
5577
5636
|
function uniq(values) {
|
|
@@ -5589,7 +5648,7 @@ function resolveBunBinaryPath() {
|
|
|
5589
5648
|
}
|
|
5590
5649
|
const home = process.env.HOME?.trim();
|
|
5591
5650
|
const fallbackCandidates = [
|
|
5592
|
-
home ?
|
|
5651
|
+
home ? resolve23(home, ".bun/bin/bun") : "",
|
|
5593
5652
|
"/opt/homebrew/bin/bun",
|
|
5594
5653
|
"/usr/local/bin/bun",
|
|
5595
5654
|
"/usr/bin/bun"
|
|
@@ -5617,8 +5676,8 @@ function resolveClaudeBinaryPath() {
|
|
|
5617
5676
|
}
|
|
5618
5677
|
const home = process.env.HOME?.trim();
|
|
5619
5678
|
const fallbackCandidates = [
|
|
5620
|
-
home ?
|
|
5621
|
-
home ?
|
|
5679
|
+
home ? resolve23(home, ".local/bin/claude") : "",
|
|
5680
|
+
home ? resolve23(home, ".local/share/claude/local/claude") : "",
|
|
5622
5681
|
"/opt/homebrew/bin/claude",
|
|
5623
5682
|
"/usr/local/bin/claude",
|
|
5624
5683
|
"/usr/bin/claude"
|
|
@@ -5632,51 +5691,51 @@ function resolveClaudeBinaryPath() {
|
|
|
5632
5691
|
throw new Error("claude not found in PATH");
|
|
5633
5692
|
}
|
|
5634
5693
|
function resolveBunInstallDir(bunBinaryPath = resolveBunBinaryPath()) {
|
|
5635
|
-
return
|
|
5694
|
+
return resolve23(bunBinaryPath, "../..");
|
|
5636
5695
|
}
|
|
5637
5696
|
function resolveClaudeInstallDir() {
|
|
5638
5697
|
const realPath = resolveClaudeBinaryPath();
|
|
5639
|
-
return
|
|
5698
|
+
return resolve23(realPath, "..");
|
|
5640
5699
|
}
|
|
5641
5700
|
function resolveNodeInstallDir() {
|
|
5642
5701
|
const preferredNode = resolvePreferredNodeBinary();
|
|
5643
5702
|
if (!preferredNode)
|
|
5644
5703
|
return null;
|
|
5645
5704
|
const explicitNode = process.env.RIG_NODE_BIN?.trim();
|
|
5646
|
-
if (explicitNode &&
|
|
5647
|
-
return preferredNode.endsWith("/bin/node") ?
|
|
5705
|
+
if (explicitNode && resolve23(explicitNode) === resolve23(preferredNode)) {
|
|
5706
|
+
return preferredNode.endsWith("/bin/node") ? resolve23(preferredNode, "../..") : resolve23(preferredNode, "..");
|
|
5648
5707
|
}
|
|
5649
5708
|
try {
|
|
5650
5709
|
const realPath = realpathSync(preferredNode);
|
|
5651
5710
|
if (realPath.endsWith("/bin/node")) {
|
|
5652
|
-
return
|
|
5711
|
+
return resolve23(realPath, "../..");
|
|
5653
5712
|
}
|
|
5654
|
-
return
|
|
5713
|
+
return resolve23(realPath, "..");
|
|
5655
5714
|
} catch {
|
|
5656
|
-
return
|
|
5715
|
+
return resolve23(preferredNode, "..");
|
|
5657
5716
|
}
|
|
5658
5717
|
}
|
|
5659
5718
|
function resolvePreferredNodeBinary() {
|
|
5660
5719
|
const candidates = [];
|
|
5661
5720
|
const envNode = process.env.RIG_NODE_BIN?.trim();
|
|
5662
5721
|
if (envNode) {
|
|
5663
|
-
const explicit =
|
|
5664
|
-
if (
|
|
5722
|
+
const explicit = resolve23(envNode);
|
|
5723
|
+
if (existsSync21(explicit)) {
|
|
5665
5724
|
return explicit;
|
|
5666
5725
|
}
|
|
5667
5726
|
}
|
|
5668
5727
|
const nvmBin = process.env.NVM_BIN?.trim();
|
|
5669
5728
|
if (nvmBin) {
|
|
5670
|
-
candidates.push(
|
|
5729
|
+
candidates.push(resolve23(nvmBin, "node"));
|
|
5671
5730
|
}
|
|
5672
5731
|
const home = process.env.HOME?.trim();
|
|
5673
5732
|
if (home) {
|
|
5674
|
-
const nvmVersionsDir =
|
|
5675
|
-
if (
|
|
5733
|
+
const nvmVersionsDir = resolve23(home, ".nvm/versions/node");
|
|
5734
|
+
if (existsSync21(nvmVersionsDir)) {
|
|
5676
5735
|
try {
|
|
5677
5736
|
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/, "")));
|
|
5678
5737
|
for (const versionDir of versionDirs) {
|
|
5679
|
-
candidates.push(
|
|
5738
|
+
candidates.push(resolve23(nvmVersionsDir, versionDir, "bin/node"));
|
|
5680
5739
|
}
|
|
5681
5740
|
} catch {}
|
|
5682
5741
|
}
|
|
@@ -5685,8 +5744,8 @@ function resolvePreferredNodeBinary() {
|
|
|
5685
5744
|
if (whichNode) {
|
|
5686
5745
|
candidates.push(whichNode);
|
|
5687
5746
|
}
|
|
5688
|
-
const deduped = uniq(candidates.map((candidate) =>
|
|
5689
|
-
const existing = deduped.filter((candidate) =>
|
|
5747
|
+
const deduped = uniq(candidates.map((candidate) => resolve23(candidate)));
|
|
5748
|
+
const existing = deduped.filter((candidate) => existsSync21(candidate));
|
|
5690
5749
|
if (existing.length === 0) {
|
|
5691
5750
|
return null;
|
|
5692
5751
|
}
|
|
@@ -5700,7 +5759,7 @@ function resolvePreferredNodeBinary() {
|
|
|
5700
5759
|
return existing[0] ?? null;
|
|
5701
5760
|
}
|
|
5702
5761
|
function inferNodeMajor(nodeBinaryPath) {
|
|
5703
|
-
const normalized =
|
|
5762
|
+
const normalized = resolve23(nodeBinaryPath).replace(/\\/g, "/");
|
|
5704
5763
|
const match = normalized.match(/(?:^|\/)(?:node-)?v?(\d+)\.\d+\.\d+(?:\/|$)/);
|
|
5705
5764
|
if (!match) {
|
|
5706
5765
|
return null;
|
|
@@ -5712,8 +5771,8 @@ function normalizeExecutablePath(candidate) {
|
|
|
5712
5771
|
if (!candidate) {
|
|
5713
5772
|
return "";
|
|
5714
5773
|
}
|
|
5715
|
-
const normalized =
|
|
5716
|
-
if (!
|
|
5774
|
+
const normalized = resolve23(candidate);
|
|
5775
|
+
if (!existsSync21(normalized)) {
|
|
5717
5776
|
return "";
|
|
5718
5777
|
}
|
|
5719
5778
|
try {
|
|
@@ -5723,7 +5782,7 @@ function normalizeExecutablePath(candidate) {
|
|
|
5723
5782
|
}
|
|
5724
5783
|
}
|
|
5725
5784
|
function looksLikeRuntimeGateway(candidate) {
|
|
5726
|
-
const normalized =
|
|
5785
|
+
const normalized = resolve23(candidate).replace(/\\/g, "/");
|
|
5727
5786
|
return normalized.includes("/.rig/bin/") || normalized.endsWith("/rig-shell") || normalized.endsWith("/rig-agent");
|
|
5728
5787
|
}
|
|
5729
5788
|
|
|
@@ -5744,7 +5803,7 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
5744
5803
|
try {
|
|
5745
5804
|
return resolveClaudeInstallDir();
|
|
5746
5805
|
} catch {
|
|
5747
|
-
return
|
|
5806
|
+
return resolve24(claudeBinary, "..");
|
|
5748
5807
|
}
|
|
5749
5808
|
})() : "";
|
|
5750
5809
|
const nodeDir = resolveNodeInstallDir();
|
|
@@ -5754,8 +5813,8 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
5754
5813
|
`${bunDir}/bin`,
|
|
5755
5814
|
claudeDir,
|
|
5756
5815
|
nodeDir ? `${nodeDir}/bin` : "",
|
|
5757
|
-
realHome ?
|
|
5758
|
-
realHome ?
|
|
5816
|
+
realHome ? resolve24(realHome, ".local/bin") : "",
|
|
5817
|
+
realHome ? resolve24(realHome, ".cargo/bin") : "",
|
|
5759
5818
|
...inheritedPath,
|
|
5760
5819
|
"/usr/local/bin",
|
|
5761
5820
|
"/usr/local/sbin",
|
|
@@ -5786,9 +5845,9 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
5786
5845
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
5787
5846
|
function resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext) {
|
|
5788
5847
|
if (runtimeContext) {
|
|
5789
|
-
return
|
|
5848
|
+
return resolve25(runtimeContext.binDir, "validators", binaryName);
|
|
5790
5849
|
}
|
|
5791
|
-
return
|
|
5850
|
+
return resolve25(resolveHarnessPaths(projectRoot).binDir, "validators", binaryName);
|
|
5792
5851
|
}
|
|
5793
5852
|
async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
5794
5853
|
const match = checkId.match(/^([a-z][\w-]*):([a-z][\w-]*)$/);
|
|
@@ -5803,19 +5862,19 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
5803
5862
|
const binaryName = `${category}-${check}`;
|
|
5804
5863
|
const binaryPath = resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
5805
5864
|
const hostProjectRoot = runtimeContext?.hostProjectRoot?.trim() || projectRoot;
|
|
5806
|
-
const sourcePath =
|
|
5807
|
-
if (!
|
|
5865
|
+
const sourcePath = resolve25(hostProjectRoot, "packages/runtime/src/control-plane/validators", category, `${check}.ts`);
|
|
5866
|
+
if (!existsSync22(sourcePath)) {
|
|
5808
5867
|
return null;
|
|
5809
5868
|
}
|
|
5810
5869
|
const sourceMtime = statSync5(sourcePath).mtimeMs;
|
|
5811
|
-
const binaryExists =
|
|
5870
|
+
const binaryExists = existsSync22(binaryPath);
|
|
5812
5871
|
const binaryMtime = binaryExists ? statSync5(binaryPath).mtimeMs : 0;
|
|
5813
5872
|
if (!binaryExists || sourceMtime > binaryMtime) {
|
|
5814
5873
|
if (binaryExists) {
|
|
5815
5874
|
rmSync6(binaryPath, { force: true });
|
|
5816
5875
|
rmSync6(`${binaryPath}.build-manifest.json`, { force: true });
|
|
5817
5876
|
}
|
|
5818
|
-
|
|
5877
|
+
mkdirSync9(dirname14(binaryPath), { recursive: true });
|
|
5819
5878
|
await buildRuntimeBinary({
|
|
5820
5879
|
sourcePath: `packages/runtime/src/control-plane/validators/${category}/${check}.ts`,
|
|
5821
5880
|
outputPath: binaryPath,
|
|
@@ -5824,7 +5883,7 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
5824
5883
|
env: runtimeProvisioningEnv()
|
|
5825
5884
|
});
|
|
5826
5885
|
}
|
|
5827
|
-
return
|
|
5886
|
+
return existsSync22(binaryPath) ? binaryPath : null;
|
|
5828
5887
|
}
|
|
5829
5888
|
|
|
5830
5889
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
@@ -5861,20 +5920,20 @@ async function readTaskSourceValidation(projectRoot, taskId) {
|
|
|
5861
5920
|
function resolveValidationPaths(projectRoot, taskId, runtimeContext) {
|
|
5862
5921
|
if (runtimeContext) {
|
|
5863
5922
|
return {
|
|
5864
|
-
taskLogDir:
|
|
5865
|
-
artifactDir:
|
|
5923
|
+
taskLogDir: resolve26(runtimeContext.logsDir, taskId),
|
|
5924
|
+
artifactDir: resolve26(runtimeContext.workspaceDir, "artifacts", taskId)
|
|
5866
5925
|
};
|
|
5867
5926
|
}
|
|
5868
5927
|
const paths = resolveHarnessPaths(projectRoot);
|
|
5869
5928
|
return {
|
|
5870
|
-
taskLogDir:
|
|
5871
|
-
artifactDir:
|
|
5929
|
+
taskLogDir: resolve26(paths.logsDir, taskId),
|
|
5930
|
+
artifactDir: resolve26(paths.artifactsDir, taskId)
|
|
5872
5931
|
};
|
|
5873
5932
|
}
|
|
5874
5933
|
async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext) {
|
|
5875
5934
|
const binaryName = checkId.replace(":", "-");
|
|
5876
5935
|
const binaryPath = await ensureValidatorBinary(projectRoot, checkId, runtimeContext) ?? resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
5877
|
-
if (!
|
|
5936
|
+
if (!existsSync23(binaryPath)) {
|
|
5878
5937
|
return {
|
|
5879
5938
|
result: {
|
|
5880
5939
|
id: checkId,
|
|
@@ -5885,7 +5944,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
5885
5944
|
};
|
|
5886
5945
|
}
|
|
5887
5946
|
const validatorCwd = runtimeContext?.workspaceDir || resolveMonorepoRoot(projectRoot);
|
|
5888
|
-
const runtimeShellPath = runtimeContext ?
|
|
5947
|
+
const runtimeShellPath = runtimeContext ? resolve26(runtimeContext.binDir, "rig-shell") : "";
|
|
5889
5948
|
const monorepoMainRoot = runtimeContext?.monorepoMainRoot || process.env.MONOREPO_MAIN_ROOT?.trim() || resolveMonorepoRoot(projectRoot);
|
|
5890
5949
|
const validatorEnv = {
|
|
5891
5950
|
PROJECT_RIG_ROOT: runtimeContext?.hostProjectRoot || projectRoot,
|
|
@@ -5900,7 +5959,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
5900
5959
|
validatorEnv.RIG_LOGS_DIR = runtimeContext.logsDir;
|
|
5901
5960
|
validatorEnv.RIG_RUNTIME_BIN_DIR = runtimeContext.binDir;
|
|
5902
5961
|
}
|
|
5903
|
-
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath &&
|
|
5962
|
+
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath && existsSync23(runtimeShellPath) ? [runtimeShellPath, "run-binary", binaryPath] : [binaryPath], validatorCwd, validatorEnv);
|
|
5904
5963
|
try {
|
|
5905
5964
|
const result = JSON.parse(stdout.trim());
|
|
5906
5965
|
return { result, exitCode };
|
|
@@ -5940,8 +5999,8 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
5940
5999
|
const configuredValidation = stringArray(taskConfig[taskId]?.validation);
|
|
5941
6000
|
const commands = resolvedContext?.validation?.length ? resolvedContext.validation : configuredValidation.length > 0 ? configuredValidation : sourceValidation.validation;
|
|
5942
6001
|
const { taskLogDir, artifactDir } = resolveValidationPaths(projectRoot, taskId, resolvedContext);
|
|
5943
|
-
|
|
5944
|
-
|
|
6002
|
+
mkdirSync10(taskLogDir, { recursive: true });
|
|
6003
|
+
mkdirSync10(artifactDir, { recursive: true });
|
|
5945
6004
|
if (commands.length === 0) {
|
|
5946
6005
|
const skipped = {
|
|
5947
6006
|
status: "skipped",
|
|
@@ -5950,7 +6009,7 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
5950
6009
|
failed: 0,
|
|
5951
6010
|
categories: []
|
|
5952
6011
|
};
|
|
5953
|
-
|
|
6012
|
+
writeFileSync10(resolve26(artifactDir, "validation-summary.json"), `${JSON.stringify(skipped, null, 2)}
|
|
5954
6013
|
`, "utf-8");
|
|
5955
6014
|
return skipped;
|
|
5956
6015
|
}
|
|
@@ -5985,18 +6044,18 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
5985
6044
|
exit_code: 2,
|
|
5986
6045
|
duration_seconds: 0
|
|
5987
6046
|
});
|
|
5988
|
-
const logFile2 =
|
|
5989
|
-
|
|
5990
|
-
|
|
6047
|
+
const logFile2 = resolve26(taskLogDir, `invalid-entry-validation.log`);
|
|
6048
|
+
mkdirSync10(taskLogDir, { recursive: true });
|
|
6049
|
+
writeFileSync10(logFile2, `=== ${nowIso()} :: ${cmd} ===
|
|
5991
6050
|
Invalid validation entry: not a check-ID. All entries must use format "category:check-name".
|
|
5992
6051
|
`, "utf-8");
|
|
5993
6052
|
continue;
|
|
5994
6053
|
}
|
|
5995
6054
|
const { result, exitCode } = await dispatchValidator(cmd, effectiveRegistry, validatorCtx, (id) => runValidatorBinary(projectRoot, taskId, id, resolvedContext));
|
|
5996
6055
|
const durationSeconds = Math.max(0, Math.round((Date.now() - startedAt) / 1000));
|
|
5997
|
-
const logFile =
|
|
5998
|
-
|
|
5999
|
-
|
|
6056
|
+
const logFile = resolve26(taskLogDir, `${cmd.replace(":", "-")}-validation.log`);
|
|
6057
|
+
mkdirSync10(taskLogDir, { recursive: true });
|
|
6058
|
+
writeFileSync10(logFile, `=== ${nowIso()} :: ${cmd} ===
|
|
6000
6059
|
${JSON.stringify(result, null, 2)}
|
|
6001
6060
|
`, "utf-8");
|
|
6002
6061
|
if (result.passed) {
|
|
@@ -6018,8 +6077,8 @@ ${JSON.stringify(result, null, 2)}
|
|
|
6018
6077
|
failed,
|
|
6019
6078
|
categories
|
|
6020
6079
|
};
|
|
6021
|
-
|
|
6022
|
-
|
|
6080
|
+
mkdirSync10(artifactDir, { recursive: true });
|
|
6081
|
+
writeFileSync10(resolve26(artifactDir, "validation-summary.json"), `${JSON.stringify(summary, null, 2)}
|
|
6023
6082
|
`, "utf-8");
|
|
6024
6083
|
return summary;
|
|
6025
6084
|
}
|
|
@@ -6366,16 +6425,16 @@ async function taskDeps(projectRoot, taskId) {
|
|
|
6366
6425
|
for (const dep of deps) {
|
|
6367
6426
|
const artifactDir = artifactDirForId(projectRoot, dep);
|
|
6368
6427
|
console.log(`=== ${dep} ===`);
|
|
6369
|
-
if (!
|
|
6428
|
+
if (!existsSync24(artifactDir)) {
|
|
6370
6429
|
console.log(` (no artifacts yet)
|
|
6371
6430
|
`);
|
|
6372
6431
|
continue;
|
|
6373
6432
|
}
|
|
6374
|
-
printArtifactSection(
|
|
6375
|
-
printArtifactSection(
|
|
6376
|
-
const changedFiles =
|
|
6377
|
-
if (
|
|
6378
|
-
const lines =
|
|
6433
|
+
printArtifactSection(resolve27(artifactDir, "decision-log.md"), "--- Decisions ---");
|
|
6434
|
+
printArtifactSection(resolve27(artifactDir, "next-actions.md"), "--- Next Actions (for you) ---");
|
|
6435
|
+
const changedFiles = resolve27(artifactDir, "changed-files.txt");
|
|
6436
|
+
if (existsSync24(changedFiles)) {
|
|
6437
|
+
const lines = readFileSync14(changedFiles, "utf-8").split(/\r?\n/).filter(Boolean);
|
|
6379
6438
|
console.log(`--- Changed Files (${lines.length}) ---`);
|
|
6380
6439
|
for (const line of lines) {
|
|
6381
6440
|
console.log(line);
|
|
@@ -6420,12 +6479,12 @@ function taskRecord(projectRoot, type, text, taskId) {
|
|
|
6420
6479
|
throw new Error("No active task.");
|
|
6421
6480
|
}
|
|
6422
6481
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6423
|
-
|
|
6482
|
+
mkdirSync11(paths.stateDir, { recursive: true });
|
|
6424
6483
|
if (type === "decision") {
|
|
6425
|
-
const artifactDir =
|
|
6426
|
-
|
|
6484
|
+
const artifactDir = resolve27(paths.artifactsDir, activeTask);
|
|
6485
|
+
mkdirSync11(artifactDir, { recursive: true });
|
|
6427
6486
|
const timestamp = nowIso();
|
|
6428
|
-
appendFileSync(
|
|
6487
|
+
appendFileSync(resolve27(artifactDir, "decision-log.md"), `
|
|
6429
6488
|
### ${timestamp}
|
|
6430
6489
|
|
|
6431
6490
|
${text}
|
|
@@ -6435,14 +6494,14 @@ ${text}
|
|
|
6435
6494
|
return;
|
|
6436
6495
|
}
|
|
6437
6496
|
const failedPath = paths.failedApproachesPath;
|
|
6438
|
-
if (!
|
|
6439
|
-
|
|
6497
|
+
if (!existsSync24(failedPath)) {
|
|
6498
|
+
writeFileSync11(failedPath, `# Failed Approaches Log
|
|
6440
6499
|
|
|
6441
6500
|
This file records approaches that did not work.
|
|
6442
6501
|
|
|
6443
6502
|
`, "utf-8");
|
|
6444
6503
|
}
|
|
6445
|
-
const content =
|
|
6504
|
+
const content = readFileSync14(failedPath, "utf-8");
|
|
6446
6505
|
const attempts = (content.match(new RegExp(`^## ${escapeRegExp(activeTask)}\\b`, "gm")) || []).length + 1;
|
|
6447
6506
|
appendFileSync(failedPath, `
|
|
6448
6507
|
## ${activeTask} - Attempt ${attempts} (${nowIso()})
|
|
@@ -6459,40 +6518,40 @@ function taskArtifacts(projectRoot, taskId) {
|
|
|
6459
6518
|
throw new Error("No active task.");
|
|
6460
6519
|
}
|
|
6461
6520
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6462
|
-
const artifactDir =
|
|
6463
|
-
|
|
6521
|
+
const artifactDir = resolve27(paths.artifactsDir, activeTask);
|
|
6522
|
+
mkdirSync11(artifactDir, { recursive: true });
|
|
6464
6523
|
const changed = changedFilesForTask(projectRoot, activeTask, true);
|
|
6465
|
-
|
|
6524
|
+
writeFileSync11(resolve27(artifactDir, "changed-files.txt"), `${changed.join(`
|
|
6466
6525
|
`)}
|
|
6467
6526
|
`, "utf-8");
|
|
6468
6527
|
console.log(`changed-files.txt: ${changed.length} files`);
|
|
6469
|
-
const taskResultPath =
|
|
6470
|
-
if (!
|
|
6528
|
+
const taskResultPath = resolve27(artifactDir, "task-result.json");
|
|
6529
|
+
if (!existsSync24(taskResultPath)) {
|
|
6471
6530
|
const template = {
|
|
6472
6531
|
task_id: activeTask,
|
|
6473
6532
|
status: "completed",
|
|
6474
6533
|
summary: "TODO: Write a one-line summary of what you did",
|
|
6475
6534
|
completed_at: nowIso()
|
|
6476
6535
|
};
|
|
6477
|
-
|
|
6536
|
+
writeFileSync11(taskResultPath, `${JSON.stringify(template, null, 2)}
|
|
6478
6537
|
`, "utf-8");
|
|
6479
6538
|
console.log("task-result.json: created (update the summary!)");
|
|
6480
6539
|
} else {
|
|
6481
6540
|
console.log("task-result.json: already exists");
|
|
6482
6541
|
}
|
|
6483
|
-
const decisionLogPath =
|
|
6484
|
-
if (!
|
|
6542
|
+
const decisionLogPath = resolve27(artifactDir, "decision-log.md");
|
|
6543
|
+
if (!existsSync24(decisionLogPath)) {
|
|
6485
6544
|
const content = `# Decision Log: ${activeTask}
|
|
6486
6545
|
|
|
6487
6546
|
Record key decisions here using: rig-agent record decision "..."
|
|
6488
6547
|
`;
|
|
6489
|
-
|
|
6548
|
+
writeFileSync11(decisionLogPath, content, "utf-8");
|
|
6490
6549
|
console.log("decision-log.md: created (record your decisions!)");
|
|
6491
6550
|
} else {
|
|
6492
6551
|
console.log("decision-log.md: already exists");
|
|
6493
6552
|
}
|
|
6494
|
-
const nextActionsPath =
|
|
6495
|
-
if (!
|
|
6553
|
+
const nextActionsPath = resolve27(artifactDir, "next-actions.md");
|
|
6554
|
+
if (!existsSync24(nextActionsPath)) {
|
|
6496
6555
|
const content = [
|
|
6497
6556
|
`# Next Actions: ${activeTask}`,
|
|
6498
6557
|
"",
|
|
@@ -6509,13 +6568,13 @@ Record key decisions here using: rig-agent record decision "..."
|
|
|
6509
6568
|
""
|
|
6510
6569
|
].join(`
|
|
6511
6570
|
`);
|
|
6512
|
-
|
|
6571
|
+
writeFileSync11(nextActionsPath, content, "utf-8");
|
|
6513
6572
|
console.log("next-actions.md: created (add recommendations for downstream tasks!)");
|
|
6514
6573
|
} else {
|
|
6515
6574
|
console.log("next-actions.md: already exists");
|
|
6516
6575
|
}
|
|
6517
|
-
const validationSummaryPath =
|
|
6518
|
-
if (
|
|
6576
|
+
const validationSummaryPath = resolve27(artifactDir, "validation-summary.json");
|
|
6577
|
+
if (existsSync24(validationSummaryPath)) {
|
|
6519
6578
|
console.log("validation-summary.json: already exists");
|
|
6520
6579
|
} else {
|
|
6521
6580
|
console.log("validation-summary.json: not yet created (run: rig-agent validate)");
|
|
@@ -6529,8 +6588,8 @@ function taskArtifactDir(projectRoot, taskId) {
|
|
|
6529
6588
|
throw new Error("No active task.");
|
|
6530
6589
|
}
|
|
6531
6590
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6532
|
-
const artifactDir =
|
|
6533
|
-
|
|
6591
|
+
const artifactDir = resolve27(paths.artifactsDir, activeTask);
|
|
6592
|
+
mkdirSync11(artifactDir, { recursive: true });
|
|
6534
6593
|
return artifactDir;
|
|
6535
6594
|
}
|
|
6536
6595
|
function taskArtifactWrite(projectRoot, filename, content, taskId) {
|
|
@@ -6539,10 +6598,10 @@ function taskArtifactWrite(projectRoot, filename, content, taskId) {
|
|
|
6539
6598
|
throw new Error("No active task.");
|
|
6540
6599
|
}
|
|
6541
6600
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6542
|
-
const artifactDir =
|
|
6543
|
-
|
|
6544
|
-
const targetPath =
|
|
6545
|
-
|
|
6601
|
+
const artifactDir = resolve27(paths.artifactsDir, activeTask);
|
|
6602
|
+
mkdirSync11(artifactDir, { recursive: true });
|
|
6603
|
+
const targetPath = resolve27(artifactDir, filename);
|
|
6604
|
+
writeFileSync11(targetPath, content, "utf-8");
|
|
6546
6605
|
console.log(`Wrote: ${targetPath}`);
|
|
6547
6606
|
}
|
|
6548
6607
|
async function taskValidate(projectRoot, taskId, validatorRegistry) {
|
|
@@ -6603,7 +6662,7 @@ function collectTaskChangedFiles(projectRoot, taskId, includeCommitted) {
|
|
|
6603
6662
|
[projectRoot, ""],
|
|
6604
6663
|
[monorepoRepoRoot, ""]
|
|
6605
6664
|
]) {
|
|
6606
|
-
if (!
|
|
6665
|
+
if (!existsSync24(resolve27(repo, ".git"))) {
|
|
6607
6666
|
continue;
|
|
6608
6667
|
}
|
|
6609
6668
|
if (includeCommitted && repo === monorepoRepoRoot) {
|
|
@@ -6628,12 +6687,22 @@ function filterTaskChangedFiles(projectRoot, taskId, files, scoped) {
|
|
|
6628
6687
|
}
|
|
6629
6688
|
function resolveTaskMonorepoRoot(projectRoot) {
|
|
6630
6689
|
const runtimeWorkspace = loadRuntimeContextFromEnv()?.workspaceDir || process.env.RIG_TASK_WORKSPACE?.trim();
|
|
6631
|
-
if (runtimeWorkspace &&
|
|
6632
|
-
return
|
|
6690
|
+
if (runtimeWorkspace && existsSync24(resolve27(runtimeWorkspace, ".git"))) {
|
|
6691
|
+
return resolve27(runtimeWorkspace);
|
|
6633
6692
|
}
|
|
6634
6693
|
return resolveHarnessPaths(projectRoot).monorepoRoot;
|
|
6635
6694
|
}
|
|
6636
6695
|
function collectCommittedMonorepoFiles(projectRoot, repo) {
|
|
6696
|
+
const defaultRef = runCapture(["git", "-C", repo, "rev-parse", "--abbrev-ref", "origin/HEAD"], projectRoot);
|
|
6697
|
+
if (defaultRef.exitCode === 0 && defaultRef.stdout.trim()) {
|
|
6698
|
+
const mergeBase = runCapture(["git", "-C", repo, "merge-base", "HEAD", defaultRef.stdout.trim()], projectRoot);
|
|
6699
|
+
if (mergeBase.exitCode === 0 && mergeBase.stdout.trim()) {
|
|
6700
|
+
const result = runCapture(["git", "-C", repo, "diff", "--name-only", `${mergeBase.stdout.trim()}..HEAD`], projectRoot);
|
|
6701
|
+
if (result.exitCode === 0) {
|
|
6702
|
+
return result.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
6703
|
+
}
|
|
6704
|
+
}
|
|
6705
|
+
}
|
|
6637
6706
|
const initialHeadCommit = resolveRuntimeInitialHeadCommit(projectRoot, repo);
|
|
6638
6707
|
if (initialHeadCommit) {
|
|
6639
6708
|
const result = runCapture(["git", "-C", repo, "diff", "--name-only", `${initialHeadCommit}..HEAD`], projectRoot);
|
|
@@ -6657,7 +6726,7 @@ function resolveRuntimeInitialHeadCommit(projectRoot, repo) {
|
|
|
6657
6726
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
6658
6727
|
if (runtimeContext?.initialHeadCommits?.monorepo?.trim()) {
|
|
6659
6728
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6660
|
-
if (
|
|
6729
|
+
if (resolve27(monorepoRoot) === resolve27(repo)) {
|
|
6661
6730
|
return runtimeContext.initialHeadCommits.monorepo.trim();
|
|
6662
6731
|
}
|
|
6663
6732
|
}
|
|
@@ -6667,7 +6736,7 @@ function resolveMonorepoBaseCommit(projectRoot, repo) {
|
|
|
6667
6736
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
6668
6737
|
if (runtimeContext?.monorepoBaseCommit?.trim()) {
|
|
6669
6738
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6670
|
-
if (
|
|
6739
|
+
if (resolve27(monorepoRoot) === resolve27(repo)) {
|
|
6671
6740
|
return runtimeContext.monorepoBaseCommit.trim();
|
|
6672
6741
|
}
|
|
6673
6742
|
}
|
|
@@ -6712,7 +6781,7 @@ function resolveRuntimeDirtyBaseline(projectRoot, repo) {
|
|
|
6712
6781
|
return new Set;
|
|
6713
6782
|
}
|
|
6714
6783
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6715
|
-
const selected =
|
|
6784
|
+
const selected = resolve27(repo) === resolve27(monorepoRoot) ? dirtyFiles.monorepo : resolve27(repo) === resolve27(projectRoot) ? dirtyFiles.project : undefined;
|
|
6716
6785
|
return new Set((selected || []).map((file) => normalizeChangedFilePath(file)).filter(Boolean));
|
|
6717
6786
|
}
|
|
6718
6787
|
function normalizeChangedFilePath(file) {
|
|
@@ -6812,12 +6881,12 @@ function printIndented(text) {
|
|
|
6812
6881
|
}
|
|
6813
6882
|
}
|
|
6814
6883
|
function readLocalBeadsTasks(projectRoot) {
|
|
6815
|
-
const issuesPath =
|
|
6816
|
-
if (!
|
|
6884
|
+
const issuesPath = resolve27(resolveMonorepoRoot2(projectRoot), ".beads/issues.jsonl");
|
|
6885
|
+
if (!existsSync24(issuesPath)) {
|
|
6817
6886
|
return [];
|
|
6818
6887
|
}
|
|
6819
6888
|
const tasks = [];
|
|
6820
|
-
for (const line of
|
|
6889
|
+
for (const line of readFileSync14(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
6821
6890
|
const trimmed = line.trim();
|
|
6822
6891
|
if (!trimmed) {
|
|
6823
6892
|
continue;
|
|
@@ -6930,11 +6999,11 @@ function taskDependencies(projectRoot, taskId, tracker) {
|
|
|
6930
6999
|
return [...ids].sort();
|
|
6931
7000
|
}
|
|
6932
7001
|
function printArtifactSection(path, header) {
|
|
6933
|
-
if (!
|
|
7002
|
+
if (!existsSync24(path)) {
|
|
6934
7003
|
return;
|
|
6935
7004
|
}
|
|
6936
7005
|
console.log(header);
|
|
6937
|
-
process.stdout.write(
|
|
7006
|
+
process.stdout.write(readFileSync14(path, "utf-8"));
|
|
6938
7007
|
console.log("");
|
|
6939
7008
|
}
|
|
6940
7009
|
function escapeRegExp(value) {
|
|
@@ -6974,8 +7043,8 @@ function isRuntimeGatewayGhPath(candidate) {
|
|
|
6974
7043
|
}
|
|
6975
7044
|
function resolveOptionalMonorepoRoot(projectRoot) {
|
|
6976
7045
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
6977
|
-
if (runtimeWorkspace &&
|
|
6978
|
-
return
|
|
7046
|
+
if (runtimeWorkspace && existsSync25(resolve28(runtimeWorkspace, ".git"))) {
|
|
7047
|
+
return resolve28(runtimeWorkspace);
|
|
6979
7048
|
}
|
|
6980
7049
|
try {
|
|
6981
7050
|
return resolveMonorepoRoot2(projectRoot);
|
|
@@ -7000,7 +7069,7 @@ function resolveGitBinary(projectRoot) {
|
|
|
7000
7069
|
if (!candidate || isRuntimeGatewayGitPath(candidate)) {
|
|
7001
7070
|
continue;
|
|
7002
7071
|
}
|
|
7003
|
-
if (
|
|
7072
|
+
if (existsSync25(candidate)) {
|
|
7004
7073
|
return candidate;
|
|
7005
7074
|
}
|
|
7006
7075
|
}
|
|
@@ -7060,11 +7129,11 @@ function gitPreflight(projectRoot, taskId, strict) {
|
|
|
7060
7129
|
const expected = resolvedTask ? `rig/${resolveTaskBranchId(projectRoot, resolvedTask)}` : "";
|
|
7061
7130
|
console.log("=== Git Flow Preflight ===");
|
|
7062
7131
|
let issues = 0;
|
|
7063
|
-
if (!
|
|
7132
|
+
if (!existsSync25(resolve28(projectRoot, ".git"))) {
|
|
7064
7133
|
console.log(`ERROR: project root is not a git repo (${projectRoot})`);
|
|
7065
7134
|
issues += 1;
|
|
7066
7135
|
}
|
|
7067
|
-
if (monorepoRoot &&
|
|
7136
|
+
if (monorepoRoot && existsSync25(resolve28(monorepoRoot, ".git"))) {
|
|
7068
7137
|
const monoBranch = branchName(projectRoot, monorepoRoot);
|
|
7069
7138
|
if (expected && monoBranch !== expected) {
|
|
7070
7139
|
console.log(`WARN: monorepo branch is ${monoBranch}, expected ${expected} for task ${resolvedTask}`);
|
|
@@ -7098,7 +7167,7 @@ function gitSyncBranch(projectRoot, taskId, targetRepo = "monorepo") {
|
|
|
7098
7167
|
}
|
|
7099
7168
|
const repoRoot = targetRepo === "monorepo" ? resolveOptionalMonorepoRoot(projectRoot) || resolveMonorepoRoot2(projectRoot) : projectRoot;
|
|
7100
7169
|
const repoLabel = targetRepo === "monorepo" ? "Monorepo" : "Project";
|
|
7101
|
-
if (!
|
|
7170
|
+
if (!existsSync25(resolve28(repoRoot, ".git"))) {
|
|
7102
7171
|
throw new Error(`${repoLabel} repo not found at ${repoRoot}`);
|
|
7103
7172
|
}
|
|
7104
7173
|
const branchId = resolveTaskBranchId(projectRoot, resolvedTask);
|
|
@@ -7142,8 +7211,8 @@ function gitCommit(options) {
|
|
|
7142
7211
|
function gitSnapshot(projectRoot, taskId, outputPath) {
|
|
7143
7212
|
const monorepoRoot = resolveOptionalMonorepoRoot(projectRoot);
|
|
7144
7213
|
const resolvedTask = taskId || safeCurrentTaskId(projectRoot);
|
|
7145
|
-
const output = outputPath || (resolvedTask ? resolveArtifactSnapshot(projectRoot, resolvedTask) :
|
|
7146
|
-
|
|
7214
|
+
const output = outputPath || (resolvedTask ? resolveArtifactSnapshot(projectRoot, resolvedTask) : resolve28(resolve28(projectRoot, ".rig", "state"), "git-state.txt"));
|
|
7215
|
+
mkdirSync12(dirname15(output), { recursive: true });
|
|
7147
7216
|
const lines = ["# Git Snapshot", `timestamp: ${nowIso()}`];
|
|
7148
7217
|
if (resolvedTask) {
|
|
7149
7218
|
lines.push(`task: ${resolvedTask}`);
|
|
@@ -7153,7 +7222,7 @@ function gitSnapshot(projectRoot, taskId, outputPath) {
|
|
|
7153
7222
|
if (monorepoRoot && monorepoRoot !== projectRoot) {
|
|
7154
7223
|
lines.push(...snapshotRepo(projectRoot, "monorepo", monorepoRoot));
|
|
7155
7224
|
}
|
|
7156
|
-
|
|
7225
|
+
writeFileSync12(output, `${lines.join(`
|
|
7157
7226
|
`)}
|
|
7158
7227
|
`, "utf-8");
|
|
7159
7228
|
return output;
|
|
@@ -7177,7 +7246,7 @@ function gitOpenPr(options) {
|
|
|
7177
7246
|
} else if (taskId) {
|
|
7178
7247
|
gitSyncBranch(options.projectRoot, taskId, "project");
|
|
7179
7248
|
}
|
|
7180
|
-
if (!
|
|
7249
|
+
if (!existsSync25(resolve28(repoRoot, ".git"))) {
|
|
7181
7250
|
throw new Error(`Repository not available for open-pr target ${target}: ${repoRoot}`);
|
|
7182
7251
|
}
|
|
7183
7252
|
const branch = branchName(options.projectRoot, repoRoot);
|
|
@@ -7390,12 +7459,12 @@ function assertPrHasNoGitConflicts(prState, repoLabel, baseRef) {
|
|
|
7390
7459
|
}
|
|
7391
7460
|
function writePrMetadata(projectRoot, taskId, result) {
|
|
7392
7461
|
const dir = artifactDirForId(projectRoot, taskId);
|
|
7393
|
-
|
|
7394
|
-
const path =
|
|
7462
|
+
mkdirSync12(dir, { recursive: true });
|
|
7463
|
+
const path = resolve28(dir, "pr-state.json");
|
|
7395
7464
|
let prs = {};
|
|
7396
|
-
if (
|
|
7465
|
+
if (existsSync25(path)) {
|
|
7397
7466
|
try {
|
|
7398
|
-
const parsed = JSON.parse(
|
|
7467
|
+
const parsed = JSON.parse(readFileSync15(path, "utf-8"));
|
|
7399
7468
|
if (parsed && typeof parsed === "object" && parsed.prs && typeof parsed.prs === "object") {
|
|
7400
7469
|
prs = parsed.prs;
|
|
7401
7470
|
}
|
|
@@ -7411,12 +7480,12 @@ function writePrMetadata(projectRoot, taskId, result) {
|
|
|
7411
7480
|
...primary || {},
|
|
7412
7481
|
updated_at: nowIso()
|
|
7413
7482
|
};
|
|
7414
|
-
|
|
7483
|
+
writeFileSync12(path, `${JSON.stringify(artifact, null, 2)}
|
|
7415
7484
|
`, "utf-8");
|
|
7416
7485
|
}
|
|
7417
7486
|
function resolveArtifactSnapshot(projectRoot, taskId) {
|
|
7418
|
-
const artifactDir =
|
|
7419
|
-
return
|
|
7487
|
+
const artifactDir = resolve28(resolveHarnessPaths(projectRoot).artifactsDir, taskId);
|
|
7488
|
+
return resolve28(artifactDir, "git-state.txt");
|
|
7420
7489
|
}
|
|
7421
7490
|
function ensureFullGitHistory(projectRoot, repoRoot, remoteName = "origin") {
|
|
7422
7491
|
const shallow = runCapture2(gitCmd(projectRoot, repoRoot, "rev-parse", "--is-shallow-repository"), projectRoot);
|
|
@@ -7468,14 +7537,14 @@ function resolveGithubCliBinary(projectRoot) {
|
|
|
7468
7537
|
}
|
|
7469
7538
|
const explicitPathEntries = (process.env.PATH || "").split(":").map((entry) => entry.trim()).filter(Boolean);
|
|
7470
7539
|
for (const entry of explicitPathEntries) {
|
|
7471
|
-
candidates.add(
|
|
7540
|
+
candidates.add(resolve28(entry, "gh"));
|
|
7472
7541
|
}
|
|
7473
7542
|
const bunResolved = Bun.which("gh");
|
|
7474
7543
|
if (bunResolved) {
|
|
7475
7544
|
candidates.add(bunResolved);
|
|
7476
7545
|
}
|
|
7477
7546
|
for (const candidate of candidates) {
|
|
7478
|
-
if (candidate &&
|
|
7547
|
+
if (candidate && existsSync25(candidate) && !isRuntimeGatewayGhPath(candidate)) {
|
|
7479
7548
|
return candidate;
|
|
7480
7549
|
}
|
|
7481
7550
|
}
|
|
@@ -7505,7 +7574,7 @@ function resolveRepoNameWithOwner(projectRoot, repoRoot) {
|
|
|
7505
7574
|
return resolveGithubRepoNameWithOwnerFromGitRoot(projectRoot, repoRoot, repoRoot, visited);
|
|
7506
7575
|
}
|
|
7507
7576
|
function resolveGithubRepoNameWithOwnerFromGitRoot(projectRoot, gitRoot, cwd, visited) {
|
|
7508
|
-
const normalizedGitRoot =
|
|
7577
|
+
const normalizedGitRoot = resolve28(gitRoot);
|
|
7509
7578
|
if (visited.has(normalizedGitRoot)) {
|
|
7510
7579
|
return "";
|
|
7511
7580
|
}
|
|
@@ -7577,7 +7646,7 @@ function resolveNetworkRemoteName(projectRoot, repoRoot, repoNameWithOwner) {
|
|
|
7577
7646
|
return remotes.includes("origin") ? "origin" : remotes[0];
|
|
7578
7647
|
}
|
|
7579
7648
|
function gitQuery(projectRoot, gitRoot, cwd, ...args) {
|
|
7580
|
-
const gitArgs =
|
|
7649
|
+
const gitArgs = existsSync25(resolve28(gitRoot, ".git")) ? gitCmd(projectRoot, gitRoot, ...args) : [resolveGitBinary(projectRoot), "--git-dir", gitRoot, ...args];
|
|
7581
7650
|
return runCapture2(gitArgs, cwd, projectRoot);
|
|
7582
7651
|
}
|
|
7583
7652
|
function resolveLocalGitRemoteRoot(remoteUrl, gitRoot) {
|
|
@@ -7595,9 +7664,9 @@ function resolveLocalGitRemoteRoot(remoteUrl, gitRoot) {
|
|
|
7595
7664
|
} else if (/^[a-z][a-z0-9+.-]*:\/\//i.test(normalized) || /^[^@]+@[^:]+:.+$/.test(normalized)) {
|
|
7596
7665
|
return "";
|
|
7597
7666
|
} else if (!isAbsolute2(normalized)) {
|
|
7598
|
-
candidate =
|
|
7667
|
+
candidate = resolve28(gitRoot, normalized);
|
|
7599
7668
|
}
|
|
7600
|
-
return
|
|
7669
|
+
return existsSync25(candidate) ? candidate : "";
|
|
7601
7670
|
}
|
|
7602
7671
|
function normalizeGithubRepoNameWithOwner(value) {
|
|
7603
7672
|
const normalized = value.trim();
|
|
@@ -7724,7 +7793,7 @@ function inferReviewerFromChangedFiles(projectRoot, repoRoot, baseRef, branchRef
|
|
|
7724
7793
|
return best;
|
|
7725
7794
|
}
|
|
7726
7795
|
function snapshotRepo(projectRoot, label, repo) {
|
|
7727
|
-
if (!
|
|
7796
|
+
if (!existsSync25(resolve28(repo, ".git"))) {
|
|
7728
7797
|
return [`## ${label}`, `repo: ${repo}`, "status: unavailable", ""];
|
|
7729
7798
|
}
|
|
7730
7799
|
const status = runCapture2(gitCmd(projectRoot, repo, "status", "--short"), projectRoot).stdout.trim();
|
|
@@ -7747,7 +7816,7 @@ function snapshotRepo(projectRoot, label, repo) {
|
|
|
7747
7816
|
];
|
|
7748
7817
|
}
|
|
7749
7818
|
function commitRepo(projectRoot, repo, label, message, allowEmpty, scoped, files, changedFilesManifest) {
|
|
7750
|
-
if (!
|
|
7819
|
+
if (!existsSync25(resolve28(repo, ".git"))) {
|
|
7751
7820
|
console.log(`Skipping ${label}: repo not available (${repo})`);
|
|
7752
7821
|
return;
|
|
7753
7822
|
}
|
|
@@ -7779,18 +7848,18 @@ function commitRepo(projectRoot, repo, label, message, allowEmpty, scoped, files
|
|
|
7779
7848
|
console.log(`Committed ${label}: ${message}`);
|
|
7780
7849
|
}
|
|
7781
7850
|
function readChangedFilesManifest(projectRoot, taskId) {
|
|
7782
|
-
const manifestPath =
|
|
7783
|
-
if (!
|
|
7851
|
+
const manifestPath = resolve28(artifactDirForId(projectRoot, taskId), "changed-files.txt");
|
|
7852
|
+
if (!existsSync25(manifestPath)) {
|
|
7784
7853
|
return [];
|
|
7785
7854
|
}
|
|
7786
|
-
const files =
|
|
7855
|
+
const files = readFileSync15(manifestPath, "utf-8").split(/\r?\n/).map((line) => normalizeChangedFilePath2(line)).filter(Boolean);
|
|
7787
7856
|
return [...new Set(files)];
|
|
7788
7857
|
}
|
|
7789
7858
|
function refreshChangedFilesManifest(projectRoot, taskId) {
|
|
7790
|
-
const manifestPath =
|
|
7791
|
-
|
|
7859
|
+
const manifestPath = resolve28(artifactDirForId(projectRoot, taskId), "changed-files.txt");
|
|
7860
|
+
mkdirSync12(dirname15(manifestPath), { recursive: true });
|
|
7792
7861
|
const changedFiles = changedFilesForTask(projectRoot, taskId, true);
|
|
7793
|
-
|
|
7862
|
+
writeFileSync12(manifestPath, `${changedFiles.join(`
|
|
7794
7863
|
`)}
|
|
7795
7864
|
`, "utf-8");
|
|
7796
7865
|
return manifestPath;
|
|
@@ -7903,7 +7972,7 @@ function repoHasPathChange(projectRoot, repoRoot, relativePath) {
|
|
|
7903
7972
|
return result.exitCode === 0 && result.stdout.trim().length > 0;
|
|
7904
7973
|
}
|
|
7905
7974
|
function stageExcludePathspecs(repoRoot) {
|
|
7906
|
-
const patterns =
|
|
7975
|
+
const patterns = existsSync25(resolve28(repoRoot, ".rig", "task-config.json")) ? [...TASK_RUNTIME_STAGE_EXCLUDES, ...GENERATED_STAGE_EXCLUDES] : [".rig/**", ...GENERATED_STAGE_EXCLUDES];
|
|
7907
7976
|
return patterns.map((pattern) => `:(glob,exclude)${pattern}`);
|
|
7908
7977
|
}
|
|
7909
7978
|
function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
@@ -7913,7 +7982,7 @@ function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
|
7913
7982
|
}
|
|
7914
7983
|
let current = repoRoot;
|
|
7915
7984
|
for (let index = 0;index < parts.length - 1; index += 1) {
|
|
7916
|
-
current =
|
|
7985
|
+
current = resolve28(current, parts[index]);
|
|
7917
7986
|
try {
|
|
7918
7987
|
if (lstatSync(current).isSymbolicLink()) {
|
|
7919
7988
|
return true;
|
|
@@ -7925,7 +7994,7 @@ function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
|
7925
7994
|
return false;
|
|
7926
7995
|
}
|
|
7927
7996
|
function printRepoStatus(projectRoot, label, repo, expectedBranch) {
|
|
7928
|
-
if (!
|
|
7997
|
+
if (!existsSync25(resolve28(repo, ".git"))) {
|
|
7929
7998
|
console.log(`${label}: unavailable (${repo})`);
|
|
7930
7999
|
return;
|
|
7931
8000
|
}
|
|
@@ -7961,7 +8030,7 @@ function resolveTaskBranchId(projectRoot, taskId) {
|
|
|
7961
8030
|
}
|
|
7962
8031
|
} catch {}
|
|
7963
8032
|
const artifactDir = artifactDirForId(projectRoot, taskId);
|
|
7964
|
-
if (
|
|
8033
|
+
if (existsSync25(artifactDir)) {
|
|
7965
8034
|
return taskId;
|
|
7966
8035
|
}
|
|
7967
8036
|
throw new Error(`Unknown task id: ${taskId}`);
|
|
@@ -7997,11 +8066,11 @@ function runCapture2(command, cwd, projectRoot = cwd) {
|
|
|
7997
8066
|
}
|
|
7998
8067
|
function runtimeGitEnv(projectRoot) {
|
|
7999
8068
|
const { ctx, runtimeRoot } = resolveRuntimeMetadata(projectRoot);
|
|
8000
|
-
const runtimeHome = runtimeRoot ?
|
|
8001
|
-
const runtimeTmp = runtimeRoot ?
|
|
8002
|
-
const runtimeCache = runtimeRoot ?
|
|
8003
|
-
const runtimeKnownHosts = runtimeHome ?
|
|
8004
|
-
const runtimeKey = runtimeHome ?
|
|
8069
|
+
const runtimeHome = runtimeRoot ? resolve28(runtimeRoot, "home") : "";
|
|
8070
|
+
const runtimeTmp = runtimeRoot ? resolve28(runtimeRoot, "tmp") : "";
|
|
8071
|
+
const runtimeCache = runtimeRoot ? resolve28(runtimeRoot, "cache") : "";
|
|
8072
|
+
const runtimeKnownHosts = runtimeHome ? resolve28(runtimeHome, ".ssh", "known_hosts") : "";
|
|
8073
|
+
const runtimeKey = runtimeHome ? resolve28(runtimeHome, ".ssh", "rig-agent-key") : "";
|
|
8005
8074
|
const env = {};
|
|
8006
8075
|
if (ctx?.workspaceDir) {
|
|
8007
8076
|
env.PROJECT_RIG_ROOT = projectRoot;
|
|
@@ -8014,14 +8083,14 @@ function runtimeGitEnv(projectRoot) {
|
|
|
8014
8083
|
if (runtimeRoot) {
|
|
8015
8084
|
env.RIG_RUNTIME_HOME = runtimeRoot;
|
|
8016
8085
|
}
|
|
8017
|
-
if (runtimeHome &&
|
|
8086
|
+
if (runtimeHome && existsSync25(runtimeHome)) {
|
|
8018
8087
|
env.HOME = runtimeHome;
|
|
8019
8088
|
env.OPENSSL_CONF = ensureRuntimeOpenSslConfig(runtimeHome);
|
|
8020
8089
|
}
|
|
8021
|
-
if (runtimeTmp &&
|
|
8090
|
+
if (runtimeTmp && existsSync25(runtimeTmp)) {
|
|
8022
8091
|
env.TMPDIR = runtimeTmp;
|
|
8023
8092
|
}
|
|
8024
|
-
if (runtimeCache &&
|
|
8093
|
+
if (runtimeCache && existsSync25(runtimeCache)) {
|
|
8025
8094
|
env.XDG_CACHE_HOME = runtimeCache;
|
|
8026
8095
|
}
|
|
8027
8096
|
const workspaceSecrets = loadDotEnvSecrets(ctx?.workspaceDir || projectRoot, process.env);
|
|
@@ -8065,14 +8134,14 @@ function runtimeGitEnv(projectRoot) {
|
|
|
8065
8134
|
env.GH_TOKEN = env.GH_TOKEN || gitHubToken;
|
|
8066
8135
|
applyGitHubCredentialHelperEnv(env);
|
|
8067
8136
|
}
|
|
8068
|
-
if (runtimeKnownHosts &&
|
|
8137
|
+
if (runtimeKnownHosts && existsSync25(runtimeKnownHosts)) {
|
|
8069
8138
|
const sshParts = [
|
|
8070
8139
|
"ssh",
|
|
8071
8140
|
`-o UserKnownHostsFile="${runtimeKnownHosts}"`,
|
|
8072
8141
|
"-o StrictHostKeyChecking=yes",
|
|
8073
8142
|
"-F /dev/null"
|
|
8074
8143
|
];
|
|
8075
|
-
if (runtimeKey &&
|
|
8144
|
+
if (runtimeKey && existsSync25(runtimeKey)) {
|
|
8076
8145
|
sshParts.splice(1, 0, `-i "${runtimeKey}"`, "-o IdentitiesOnly=yes");
|
|
8077
8146
|
}
|
|
8078
8147
|
env.GIT_SSH_COMMAND = sshParts.join(" ");
|
|
@@ -8093,12 +8162,12 @@ function loadPersistedRuntimeSecrets(runtimeRoot) {
|
|
|
8093
8162
|
if (!runtimeRoot) {
|
|
8094
8163
|
return {};
|
|
8095
8164
|
}
|
|
8096
|
-
const path =
|
|
8097
|
-
if (!
|
|
8165
|
+
const path = resolve28(runtimeRoot, "runtime-secrets.json");
|
|
8166
|
+
if (!existsSync25(path)) {
|
|
8098
8167
|
return {};
|
|
8099
8168
|
}
|
|
8100
8169
|
try {
|
|
8101
|
-
const parsed = JSON.parse(
|
|
8170
|
+
const parsed = JSON.parse(readFileSync15(path, "utf-8"));
|
|
8102
8171
|
const entries = Object.entries(parsed).filter((entry) => typeof entry[1] === "string");
|
|
8103
8172
|
return Object.fromEntries(entries);
|
|
8104
8173
|
} catch {
|
|
@@ -8106,13 +8175,13 @@ function loadPersistedRuntimeSecrets(runtimeRoot) {
|
|
|
8106
8175
|
}
|
|
8107
8176
|
}
|
|
8108
8177
|
function ensureRuntimeOpenSslConfig(runtimeHome) {
|
|
8109
|
-
const sslDir =
|
|
8110
|
-
const sslConfig =
|
|
8111
|
-
if (!
|
|
8112
|
-
|
|
8178
|
+
const sslDir = resolve28(runtimeHome, ".ssl");
|
|
8179
|
+
const sslConfig = resolve28(sslDir, "openssl.cnf");
|
|
8180
|
+
if (!existsSync25(sslDir)) {
|
|
8181
|
+
mkdirSync12(sslDir, { recursive: true });
|
|
8113
8182
|
}
|
|
8114
|
-
if (!
|
|
8115
|
-
|
|
8183
|
+
if (!existsSync25(sslConfig)) {
|
|
8184
|
+
writeFileSync12(sslConfig, `# Rig runtime OpenSSL config placeholder
|
|
8116
8185
|
`);
|
|
8117
8186
|
}
|
|
8118
8187
|
return sslConfig;
|
|
@@ -8130,29 +8199,29 @@ function resolveRuntimeMetadata(projectRoot) {
|
|
|
8130
8199
|
if (contextFile) {
|
|
8131
8200
|
return {
|
|
8132
8201
|
ctx,
|
|
8133
|
-
runtimeRoot:
|
|
8202
|
+
runtimeRoot: dirname15(resolve28(contextFile))
|
|
8134
8203
|
};
|
|
8135
8204
|
}
|
|
8136
8205
|
const inferredContextFile = findRuntimeContextFile2(projectRoot);
|
|
8137
|
-
if (
|
|
8206
|
+
if (existsSync25(inferredContextFile)) {
|
|
8138
8207
|
try {
|
|
8139
8208
|
ctx = loadRuntimeContext(inferredContextFile);
|
|
8140
8209
|
} catch {}
|
|
8141
8210
|
return {
|
|
8142
8211
|
ctx,
|
|
8143
|
-
runtimeRoot:
|
|
8212
|
+
runtimeRoot: dirname15(inferredContextFile)
|
|
8144
8213
|
};
|
|
8145
8214
|
}
|
|
8146
8215
|
return { ctx, runtimeRoot: "" };
|
|
8147
8216
|
}
|
|
8148
8217
|
function findRuntimeContextFile2(startPath) {
|
|
8149
|
-
let current =
|
|
8218
|
+
let current = resolve28(startPath);
|
|
8150
8219
|
while (true) {
|
|
8151
|
-
const candidate =
|
|
8152
|
-
if (
|
|
8220
|
+
const candidate = resolve28(current, "runtime-context.json");
|
|
8221
|
+
if (existsSync25(candidate)) {
|
|
8153
8222
|
return candidate;
|
|
8154
8223
|
}
|
|
8155
|
-
const parent =
|
|
8224
|
+
const parent = dirname15(current);
|
|
8156
8225
|
if (parent === current) {
|
|
8157
8226
|
return "";
|
|
8158
8227
|
}
|
|
@@ -8161,7 +8230,7 @@ function findRuntimeContextFile2(startPath) {
|
|
|
8161
8230
|
}
|
|
8162
8231
|
|
|
8163
8232
|
// packages/runtime/src/control-plane/native/profile-ops.ts
|
|
8164
|
-
import { existsSync as
|
|
8233
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync13, writeFileSync as writeFileSync13 } from "fs";
|
|
8165
8234
|
var DEFAULTS = {
|
|
8166
8235
|
model: parseEnvOrDefault(process.env.DEFAULT_AGENT_MODEL, ["claude", "gpt-codex", "pi"], "pi"),
|
|
8167
8236
|
runtime: parseEnvOrDefault(process.env.DEFAULT_AGENT_RUNTIME, ["claude-code", "codex-app-server", "pi"], "pi"),
|
|
@@ -8176,7 +8245,7 @@ function parseEnvOrDefault(value, allowed, fallback) {
|
|
|
8176
8245
|
return allowed.includes(value) ? value : fallback;
|
|
8177
8246
|
}
|
|
8178
8247
|
async function readProfileFile(path) {
|
|
8179
|
-
if (!
|
|
8248
|
+
if (!existsSync26(path)) {
|
|
8180
8249
|
return null;
|
|
8181
8250
|
}
|
|
8182
8251
|
try {
|
|
@@ -8229,14 +8298,14 @@ async function setProfile(projectRoot, options) {
|
|
|
8229
8298
|
plugin = model === "gpt-codex" ? "codex" : model === "pi" ? "pi" : "claude";
|
|
8230
8299
|
}
|
|
8231
8300
|
const paths = resolveHarnessPaths(projectRoot);
|
|
8232
|
-
|
|
8301
|
+
mkdirSync13(paths.stateDir, { recursive: true });
|
|
8233
8302
|
const next = {
|
|
8234
8303
|
model,
|
|
8235
8304
|
runtime,
|
|
8236
8305
|
agent_plugin: plugin,
|
|
8237
8306
|
updated_at: new Date().toISOString()
|
|
8238
8307
|
};
|
|
8239
|
-
|
|
8308
|
+
writeFileSync13(paths.agentProfilePath, `${JSON.stringify(next, null, 2)}
|
|
8240
8309
|
`, "utf-8");
|
|
8241
8310
|
await showProfile(projectRoot, false);
|
|
8242
8311
|
}
|
|
@@ -8272,13 +8341,13 @@ async function setReviewProfile(projectRoot, mode, provider) {
|
|
|
8272
8341
|
throw new Error(`Invalid provider: ${resolvedProvider}. Supported: greptile.`);
|
|
8273
8342
|
}
|
|
8274
8343
|
const paths = resolveHarnessPaths(projectRoot);
|
|
8275
|
-
|
|
8344
|
+
mkdirSync13(paths.stateDir, { recursive: true });
|
|
8276
8345
|
const next = {
|
|
8277
8346
|
mode,
|
|
8278
8347
|
provider: resolvedProvider,
|
|
8279
8348
|
updated_at: new Date().toISOString()
|
|
8280
8349
|
};
|
|
8281
|
-
|
|
8350
|
+
writeFileSync13(paths.reviewProfilePath, `${JSON.stringify(next, null, 2)}
|
|
8282
8351
|
`, "utf-8");
|
|
8283
8352
|
await showReviewProfile(projectRoot);
|
|
8284
8353
|
}
|
|
@@ -8316,44 +8385,44 @@ async function loadReviewProfile(path) {
|
|
|
8316
8385
|
}
|
|
8317
8386
|
|
|
8318
8387
|
// packages/runtime/src/control-plane/native/repo-ops.ts
|
|
8319
|
-
import { existsSync as
|
|
8320
|
-
import { basename as basename8, dirname as
|
|
8388
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync17, readFileSync as readFileSync17, readdirSync as readdirSync6, rmSync as rmSync8, writeFileSync as writeFileSync15 } from "fs";
|
|
8389
|
+
import { basename as basename8, dirname as dirname17, resolve as resolve32 } from "path";
|
|
8321
8390
|
// packages/runtime/src/control-plane/repos/mirror/bootstrap.ts
|
|
8322
|
-
import { existsSync as
|
|
8323
|
-
import { resolve as
|
|
8391
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync15, realpathSync as realpathSync2 } from "fs";
|
|
8392
|
+
import { resolve as resolve30 } from "path";
|
|
8324
8393
|
|
|
8325
8394
|
// packages/runtime/src/control-plane/authority-files.ts
|
|
8326
|
-
import { existsSync as
|
|
8327
|
-
import { dirname as
|
|
8395
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync14, readFileSync as readFileSync16, writeFileSync as writeFileSync14, appendFileSync as appendFileSync2, copyFileSync as copyFileSync3, statSync as statSync6, readdirSync as readdirSync5, chmodSync as chmodSync3 } from "fs";
|
|
8396
|
+
import { dirname as dirname16, join as join5, relative, resolve as resolve29 } from "path";
|
|
8328
8397
|
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
8329
8398
|
function resolveAuthorityProjectStateDir(projectRoot) {
|
|
8330
8399
|
const explicit = process.env.RIG_STATE_DIR?.trim();
|
|
8331
8400
|
if (explicit) {
|
|
8332
|
-
return
|
|
8401
|
+
return resolve29(explicit);
|
|
8333
8402
|
}
|
|
8334
|
-
return
|
|
8403
|
+
return resolve29(resolve29(projectRoot), ".rig", "state");
|
|
8335
8404
|
}
|
|
8336
8405
|
function readJsonAtPath(path, fallback) {
|
|
8337
|
-
if (!
|
|
8406
|
+
if (!existsSync27(path)) {
|
|
8338
8407
|
return fallback;
|
|
8339
8408
|
}
|
|
8340
8409
|
try {
|
|
8341
|
-
return JSON.parse(
|
|
8410
|
+
return JSON.parse(readFileSync16(path, "utf-8"));
|
|
8342
8411
|
} catch {
|
|
8343
8412
|
return fallback;
|
|
8344
8413
|
}
|
|
8345
8414
|
}
|
|
8346
8415
|
function writeJsonAtPath(path, value) {
|
|
8347
|
-
|
|
8348
|
-
|
|
8416
|
+
mkdirSync14(dirname16(path), { recursive: true });
|
|
8417
|
+
writeFileSync14(path, `${JSON.stringify(value, null, 2)}
|
|
8349
8418
|
`, "utf8");
|
|
8350
8419
|
return path;
|
|
8351
8420
|
}
|
|
8352
8421
|
function readAuthorityProjectStateJson(projectRoot, relativePath, fallback) {
|
|
8353
|
-
return readJsonAtPath(
|
|
8422
|
+
return readJsonAtPath(resolve29(resolveAuthorityProjectStateDir(projectRoot), relativePath), fallback);
|
|
8354
8423
|
}
|
|
8355
8424
|
function writeAuthorityProjectStateJson(projectRoot, relativePath, value) {
|
|
8356
|
-
return writeJsonAtPath(
|
|
8425
|
+
return writeJsonAtPath(resolve29(resolveAuthorityProjectStateDir(projectRoot), relativePath), value);
|
|
8357
8426
|
}
|
|
8358
8427
|
|
|
8359
8428
|
// packages/runtime/src/control-plane/repos/mirror/state.ts
|
|
@@ -8413,7 +8482,7 @@ function sameExistingPath(left, right) {
|
|
|
8413
8482
|
try {
|
|
8414
8483
|
return realpathSync2(left) === realpathSync2(right);
|
|
8415
8484
|
} catch {
|
|
8416
|
-
return
|
|
8485
|
+
return resolve30(left) === resolve30(right);
|
|
8417
8486
|
}
|
|
8418
8487
|
}
|
|
8419
8488
|
function repoLooksUsable(repoRoot, projectRoot) {
|
|
@@ -8449,7 +8518,7 @@ function resolveMirrorRemoteUrl(layout) {
|
|
|
8449
8518
|
}
|
|
8450
8519
|
}
|
|
8451
8520
|
}
|
|
8452
|
-
if (
|
|
8521
|
+
if (existsSync28(resolve30(layout.checkoutRoot, ".git")) && checkoutLooksUsable(layout)) {
|
|
8453
8522
|
const checkoutOrigin = runGit(["git", "-C", layout.checkoutRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
8454
8523
|
if (checkoutOrigin.exitCode === 0) {
|
|
8455
8524
|
const currentOrigin = checkoutOrigin.stdout.trim();
|
|
@@ -8462,9 +8531,9 @@ function resolveMirrorRemoteUrl(layout) {
|
|
|
8462
8531
|
}
|
|
8463
8532
|
function ensureManagedRepoMirror(projectRoot, repoId) {
|
|
8464
8533
|
const layout = resolveManagedRepoLayout(projectRoot, repoId);
|
|
8465
|
-
|
|
8534
|
+
mkdirSync15(layout.metadataRoot, { recursive: true });
|
|
8466
8535
|
const remoteUrl = resolveMirrorRemoteUrl(layout);
|
|
8467
|
-
if (!
|
|
8536
|
+
if (!existsSync28(resolve30(layout.mirrorRoot, "HEAD"))) {
|
|
8468
8537
|
ensureGitSuccess(runGit(["git", "init", "--bare", layout.mirrorRoot], layout.projectRoot), ["git", "init", "--bare", layout.mirrorRoot]);
|
|
8469
8538
|
}
|
|
8470
8539
|
const getOrigin = runGit(["git", "--git-dir", layout.mirrorRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
@@ -8484,8 +8553,8 @@ function ensureManagedRepoMirror(projectRoot, repoId) {
|
|
|
8484
8553
|
return layout;
|
|
8485
8554
|
}
|
|
8486
8555
|
// packages/runtime/src/control-plane/repos/mirror/refresh.ts
|
|
8487
|
-
import { existsSync as
|
|
8488
|
-
import { resolve as
|
|
8556
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync16, realpathSync as realpathSync3, rmSync as rmSync7 } from "fs";
|
|
8557
|
+
import { resolve as resolve31 } from "path";
|
|
8489
8558
|
function nowIso3() {
|
|
8490
8559
|
return new Date().toISOString();
|
|
8491
8560
|
}
|
|
@@ -8512,7 +8581,7 @@ function sameExistingPath2(left, right) {
|
|
|
8512
8581
|
try {
|
|
8513
8582
|
return realpathSync3(left) === realpathSync3(right);
|
|
8514
8583
|
} catch {
|
|
8515
|
-
return
|
|
8584
|
+
return resolve31(left) === resolve31(right);
|
|
8516
8585
|
}
|
|
8517
8586
|
}
|
|
8518
8587
|
function ensureMirrorHead(layout) {
|
|
@@ -8558,12 +8627,12 @@ function checkoutLooksUsable2(layout) {
|
|
|
8558
8627
|
return probe.exitCode === 0 && sameExistingPath2(probe.stdout.trim(), layout.checkoutRoot);
|
|
8559
8628
|
}
|
|
8560
8629
|
function ensureCheckoutFromMirror(layout) {
|
|
8561
|
-
|
|
8562
|
-
const gitPath =
|
|
8563
|
-
if (
|
|
8630
|
+
mkdirSync16(resolve31(layout.checkoutRoot, ".."), { recursive: true });
|
|
8631
|
+
const gitPath = resolve31(layout.checkoutRoot, ".git");
|
|
8632
|
+
if (existsSync29(layout.checkoutRoot) && (!existsSync29(gitPath) || !checkoutLooksUsable2(layout))) {
|
|
8564
8633
|
rmSync7(layout.checkoutRoot, { recursive: true, force: true });
|
|
8565
8634
|
}
|
|
8566
|
-
if (!
|
|
8635
|
+
if (!existsSync29(gitPath)) {
|
|
8567
8636
|
ensureGitSuccess2(runGit2(["git", "clone", layout.mirrorRoot, layout.checkoutRoot], layout.projectRoot), ["git", "clone", layout.mirrorRoot, layout.checkoutRoot]);
|
|
8568
8637
|
}
|
|
8569
8638
|
const getOrigin = runGit2(["git", "-C", layout.checkoutRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
@@ -8664,7 +8733,7 @@ function repoDiscover(projectRoot, taskId) {
|
|
|
8664
8733
|
}
|
|
8665
8734
|
function repoBaseline(projectRoot, refresh = false) {
|
|
8666
8735
|
const paths = resolveRepoDiscoveryPaths(projectRoot);
|
|
8667
|
-
if (!refresh &&
|
|
8736
|
+
if (!refresh && existsSync30(paths.baseRepoPinsPath)) {
|
|
8668
8737
|
const baseline = readJsonFile(paths.baseRepoPinsPath, { recorded_at: nowIso(), repos: {} });
|
|
8669
8738
|
return baseline.repos || {};
|
|
8670
8739
|
}
|
|
@@ -8688,8 +8757,8 @@ function ensureMonorepoReady(projectRoot) {
|
|
|
8688
8757
|
}
|
|
8689
8758
|
function persistBaselinePins(projectRoot, repos) {
|
|
8690
8759
|
const paths = resolveRepoDiscoveryPaths(projectRoot);
|
|
8691
|
-
|
|
8692
|
-
|
|
8760
|
+
mkdirSync17(resolve32(paths.baseRepoPinsPath, ".."), { recursive: true });
|
|
8761
|
+
writeFileSync15(paths.baseRepoPinsPath, `${JSON.stringify({ recorded_at: nowIso(), repos }, null, 2)}
|
|
8693
8762
|
`, "utf-8");
|
|
8694
8763
|
return repos;
|
|
8695
8764
|
}
|
|
@@ -8768,28 +8837,28 @@ function readRepoDiscoveryTaskConfig(projectRoot) {
|
|
|
8768
8837
|
function resolveRepoDiscoveryPaths(projectRoot) {
|
|
8769
8838
|
const monorepoRoot = resolveMonorepoRepoLayout(projectRoot).checkoutRoot;
|
|
8770
8839
|
const explicitHostProjectRoot = (process.env.RIG_HOST_PROJECT_ROOT || "").trim();
|
|
8771
|
-
const normalizedProjectRoot =
|
|
8840
|
+
const normalizedProjectRoot = resolve32(projectRoot);
|
|
8772
8841
|
const hostProjectRoot = explicitHostProjectRoot && shouldUseHostProjectStateRoot(normalizedProjectRoot) ? explicitHostProjectRoot : normalizedProjectRoot;
|
|
8773
|
-
const stateDir =
|
|
8842
|
+
const stateDir = resolve32(hostProjectRoot, ".rig", "state");
|
|
8774
8843
|
return {
|
|
8775
8844
|
monorepoRoot,
|
|
8776
|
-
taskRepoCommitsPath:
|
|
8777
|
-
baseRepoPinsPath:
|
|
8845
|
+
taskRepoCommitsPath: resolve32(stateDir, "task-repo-commits.json"),
|
|
8846
|
+
baseRepoPinsPath: resolve32(stateDir, "base-repo-pins.json")
|
|
8778
8847
|
};
|
|
8779
8848
|
}
|
|
8780
8849
|
function shouldUseHostProjectStateRoot(projectRoot) {
|
|
8781
8850
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
8782
|
-
if (runtimeWorkspace &&
|
|
8851
|
+
if (runtimeWorkspace && resolve32(runtimeWorkspace) === projectRoot) {
|
|
8783
8852
|
return true;
|
|
8784
8853
|
}
|
|
8785
|
-
return basename8(
|
|
8854
|
+
return basename8(dirname17(projectRoot)) === ".worktrees";
|
|
8786
8855
|
}
|
|
8787
8856
|
function readPinFromArtifact(projectRoot, depTask, repoKey) {
|
|
8788
|
-
const snapshot =
|
|
8789
|
-
if (!
|
|
8857
|
+
const snapshot = resolve32(artifactDirForId(projectRoot, depTask), "git-state.txt");
|
|
8858
|
+
if (!existsSync30(snapshot)) {
|
|
8790
8859
|
return "";
|
|
8791
8860
|
}
|
|
8792
|
-
const content =
|
|
8861
|
+
const content = readFileSync17(snapshot, "utf-8");
|
|
8793
8862
|
const chunk = content.split(/\r?\n/);
|
|
8794
8863
|
let inSection = false;
|
|
8795
8864
|
for (const line of chunk) {
|
|
@@ -8811,12 +8880,12 @@ function repoPath(projectRoot, key) {
|
|
|
8811
8880
|
if (managed) {
|
|
8812
8881
|
return managed.checkoutRoot;
|
|
8813
8882
|
}
|
|
8814
|
-
return key.startsWith("/") ? key :
|
|
8883
|
+
return key.startsWith("/") ? key : resolve32(projectRoot, key);
|
|
8815
8884
|
}
|
|
8816
8885
|
function applyPins(projectRoot, pins) {
|
|
8817
8886
|
for (const [key, commit] of Object.entries(pins)) {
|
|
8818
8887
|
const path = repoPath(projectRoot, key);
|
|
8819
|
-
if (!
|
|
8888
|
+
if (!existsSync30(resolve32(path, ".git"))) {
|
|
8820
8889
|
throw new Error(`Repo for pin not available: ${key} (${path})`);
|
|
8821
8890
|
}
|
|
8822
8891
|
let hasCommit = runGitCapture(["git", "-C", path, "cat-file", "-e", `${commit}^{commit}`], projectRoot).exitCode === 0;
|
|
@@ -8845,7 +8914,7 @@ function verifyPins(projectRoot, pins) {
|
|
|
8845
8914
|
let ok = true;
|
|
8846
8915
|
for (const [key, expected] of Object.entries(pins)) {
|
|
8847
8916
|
const path = repoPath(projectRoot, key);
|
|
8848
|
-
if (!
|
|
8917
|
+
if (!existsSync30(resolve32(path, ".git"))) {
|
|
8849
8918
|
console.error(`ERROR: repo missing during pin verification: ${key}`);
|
|
8850
8919
|
ok = false;
|
|
8851
8920
|
continue;
|
|
@@ -8870,23 +8939,23 @@ function resolveRuntimeGitEnv() {
|
|
|
8870
8939
|
GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND
|
|
8871
8940
|
};
|
|
8872
8941
|
}
|
|
8873
|
-
const runtimeRoot = process.env.RIG_RUNTIME_HOME?.trim() || (process.env.RIG_RUNTIME_CONTEXT_FILE?.trim() ?
|
|
8874
|
-
const runtimeHome = runtimeRoot ?
|
|
8942
|
+
const runtimeRoot = process.env.RIG_RUNTIME_HOME?.trim() || (process.env.RIG_RUNTIME_CONTEXT_FILE?.trim() ? resolve32(process.env.RIG_RUNTIME_CONTEXT_FILE, "..") : inferRuntimeRootFromWorkspace(process.cwd()));
|
|
8943
|
+
const runtimeHome = runtimeRoot ? resolve32(runtimeRoot, "home") : process.env.HOME?.trim() || "";
|
|
8875
8944
|
if (!runtimeHome) {
|
|
8876
8945
|
return;
|
|
8877
8946
|
}
|
|
8878
|
-
const knownHostsPath =
|
|
8879
|
-
if (!
|
|
8947
|
+
const knownHostsPath = resolve32(runtimeHome, ".ssh", "known_hosts");
|
|
8948
|
+
if (!existsSync30(knownHostsPath)) {
|
|
8880
8949
|
return { HOME: runtimeHome };
|
|
8881
8950
|
}
|
|
8882
|
-
const agentSshKey =
|
|
8951
|
+
const agentSshKey = resolve32(runtimeHome, ".ssh", "rig-agent-key");
|
|
8883
8952
|
const sshParts = [
|
|
8884
8953
|
"ssh",
|
|
8885
8954
|
`-o UserKnownHostsFile="${knownHostsPath}"`,
|
|
8886
8955
|
"-o StrictHostKeyChecking=yes",
|
|
8887
8956
|
"-F /dev/null"
|
|
8888
8957
|
];
|
|
8889
|
-
if (
|
|
8958
|
+
if (existsSync30(agentSshKey)) {
|
|
8890
8959
|
sshParts.splice(1, 0, `-i "${agentSshKey}"`, "-o IdentitiesOnly=yes");
|
|
8891
8960
|
}
|
|
8892
8961
|
return {
|
|
@@ -8896,24 +8965,24 @@ function resolveRuntimeGitEnv() {
|
|
|
8896
8965
|
}
|
|
8897
8966
|
function inferRuntimeRootFromWorkspace(cwd) {
|
|
8898
8967
|
const contextPath = findRuntimeContextFile3(cwd);
|
|
8899
|
-
if (!contextPath || !
|
|
8968
|
+
if (!contextPath || !existsSync30(contextPath)) {
|
|
8900
8969
|
return "";
|
|
8901
8970
|
}
|
|
8902
8971
|
try {
|
|
8903
8972
|
loadRuntimeContext(contextPath);
|
|
8904
|
-
return
|
|
8973
|
+
return resolve32(contextPath, "..");
|
|
8905
8974
|
} catch {
|
|
8906
8975
|
return "";
|
|
8907
8976
|
}
|
|
8908
8977
|
}
|
|
8909
8978
|
function findRuntimeContextFile3(startPath) {
|
|
8910
|
-
let current =
|
|
8979
|
+
let current = resolve32(startPath);
|
|
8911
8980
|
while (true) {
|
|
8912
|
-
const candidate =
|
|
8913
|
-
if (
|
|
8981
|
+
const candidate = resolve32(current, "runtime-context.json");
|
|
8982
|
+
if (existsSync30(candidate)) {
|
|
8914
8983
|
return candidate;
|
|
8915
8984
|
}
|
|
8916
|
-
const parent =
|
|
8985
|
+
const parent = resolve32(current, "..");
|
|
8917
8986
|
if (parent === current) {
|
|
8918
8987
|
return "";
|
|
8919
8988
|
}
|
|
@@ -8935,7 +9004,7 @@ var BAKED_STATUS_OUTPUT2 = BUILD_CONFIG3.AGENT_STATUS_OUTPUT ?? "";
|
|
|
8935
9004
|
var BAKED_GIT_BRANCH = BUILD_CONFIG3.AGENT_GIT_BRANCH ?? "";
|
|
8936
9005
|
var BAKED_BASE_COMMIT = BUILD_CONFIG3.AGENT_BASE_COMMIT ?? "";
|
|
8937
9006
|
if (BAKED_BINARY_PATH) {
|
|
8938
|
-
const binaryDir =
|
|
9007
|
+
const binaryDir = dirname18(BAKED_BINARY_PATH);
|
|
8939
9008
|
const currentPath = process.env.PATH || "";
|
|
8940
9009
|
const pathEntries = currentPath.split(":").filter(Boolean);
|
|
8941
9010
|
if (!pathEntries.includes(binaryDir)) {
|
|
@@ -8967,7 +9036,7 @@ function getEventBus() {
|
|
|
8967
9036
|
}
|
|
8968
9037
|
function inferRuntimeContext() {
|
|
8969
9038
|
for (const candidate of runtimeContextCandidates()) {
|
|
8970
|
-
if (!candidate || !
|
|
9039
|
+
if (!candidate || !existsSync31(candidate)) {
|
|
8971
9040
|
continue;
|
|
8972
9041
|
}
|
|
8973
9042
|
try {
|
|
@@ -8980,15 +9049,15 @@ function inferRuntimeContext() {
|
|
|
8980
9049
|
function runtimeContextCandidates() {
|
|
8981
9050
|
const cwd = process.cwd();
|
|
8982
9051
|
const candidates = [
|
|
8983
|
-
|
|
8984
|
-
|
|
9052
|
+
resolve33(cwd, "..", "runtime-context.json"),
|
|
9053
|
+
resolve33(cwd, ".rig", "runtime-context.json")
|
|
8985
9054
|
];
|
|
8986
9055
|
const argv1 = process.argv[1]?.trim();
|
|
8987
9056
|
if (argv1) {
|
|
8988
|
-
candidates.push(
|
|
9057
|
+
candidates.push(resolve33(argv1, "..", "..", "runtime-context.json"));
|
|
8989
9058
|
}
|
|
8990
9059
|
if (BAKED_BINARY_PATH) {
|
|
8991
|
-
candidates.push(
|
|
9060
|
+
candidates.push(resolve33(BAKED_BINARY_PATH, "..", "..", "runtime-context.json"));
|
|
8992
9061
|
}
|
|
8993
9062
|
return Array.from(new Set(candidates));
|
|
8994
9063
|
}
|
|
@@ -9003,12 +9072,12 @@ var GITHUB_KNOWN_HOSTS = [
|
|
|
9003
9072
|
"github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk="
|
|
9004
9073
|
];
|
|
9005
9074
|
function ensureRuntimeKnownHosts(runtimeHome) {
|
|
9006
|
-
const sshDir =
|
|
9007
|
-
const knownHostsPath =
|
|
9008
|
-
if (!
|
|
9009
|
-
|
|
9075
|
+
const sshDir = resolve33(runtimeHome, ".ssh");
|
|
9076
|
+
const knownHostsPath = resolve33(sshDir, "known_hosts");
|
|
9077
|
+
if (!existsSync31(sshDir)) {
|
|
9078
|
+
mkdirSync18(sshDir, { recursive: true });
|
|
9010
9079
|
}
|
|
9011
|
-
const existing =
|
|
9080
|
+
const existing = existsSync31(knownHostsPath) ? readFileSync18(knownHostsPath, "utf-8") : "";
|
|
9012
9081
|
const existingLines = new Set(existing.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
|
|
9013
9082
|
const missing = GITHUB_KNOWN_HOSTS.filter((line) => !existingLines.has(line));
|
|
9014
9083
|
if (missing.length === 0) {
|
|
@@ -9018,11 +9087,11 @@ function ensureRuntimeKnownHosts(runtimeHome) {
|
|
|
9018
9087
|
for (const line of missing) {
|
|
9019
9088
|
existingLines.add(line);
|
|
9020
9089
|
}
|
|
9021
|
-
|
|
9090
|
+
writeFileSync16(knownHostsPath, `${Array.from(existingLines).join(`
|
|
9022
9091
|
`)}
|
|
9023
9092
|
`, { mode: 420 });
|
|
9024
9093
|
} catch (err) {
|
|
9025
|
-
const hint =
|
|
9094
|
+
const hint = existsSync31(knownHostsPath) ? "" : " \u2014 known_hosts is missing; git SSH operations may fail";
|
|
9026
9095
|
console.warn(`[rig-agent] Could not update ${knownHostsPath}: ${err instanceof Error ? err.message : String(err)}${hint}`);
|
|
9027
9096
|
}
|
|
9028
9097
|
return knownHostsPath;
|
|
@@ -9036,13 +9105,13 @@ function hydrateRuntimeProcessEnv(ctx) {
|
|
|
9036
9105
|
return;
|
|
9037
9106
|
}
|
|
9038
9107
|
process.env.RIG_RUNTIME_CONTEXT_FILE = contextFile;
|
|
9039
|
-
const runtimeRoot =
|
|
9040
|
-
const runtimeHome =
|
|
9041
|
-
const runtimeTmp =
|
|
9042
|
-
const runtimeCache =
|
|
9043
|
-
const runtimeBin =
|
|
9044
|
-
const runtimeWorkspaceBin =
|
|
9045
|
-
const runtimeTools =
|
|
9108
|
+
const runtimeRoot = dirname18(resolve33(contextFile));
|
|
9109
|
+
const runtimeHome = resolve33(runtimeRoot, "home");
|
|
9110
|
+
const runtimeTmp = resolve33(runtimeRoot, "tmp");
|
|
9111
|
+
const runtimeCache = resolve33(runtimeRoot, "cache");
|
|
9112
|
+
const runtimeBin = resolve33(runtimeRoot, "bin");
|
|
9113
|
+
const runtimeWorkspaceBin = resolve33(ctx.workspaceDir, ".rig", "bin");
|
|
9114
|
+
const runtimeTools = resolve33(ctx.workspaceDir, "rig", "tools");
|
|
9046
9115
|
if (ctx.hostProjectRoot) {
|
|
9047
9116
|
process.env.PROJECT_RIG_ROOT = ctx.hostProjectRoot;
|
|
9048
9117
|
}
|
|
@@ -9058,13 +9127,13 @@ function hydrateRuntimeProcessEnv(ctx) {
|
|
|
9058
9127
|
for (const [key, value] of Object.entries(browserEnvFromContext(ctx.browser))) {
|
|
9059
9128
|
process.env[key] = value;
|
|
9060
9129
|
}
|
|
9061
|
-
if (
|
|
9130
|
+
if (existsSync31(runtimeHome)) {
|
|
9062
9131
|
process.env.HOME = runtimeHome;
|
|
9063
9132
|
}
|
|
9064
|
-
if (
|
|
9133
|
+
if (existsSync31(runtimeTmp)) {
|
|
9065
9134
|
process.env.TMPDIR = runtimeTmp;
|
|
9066
9135
|
}
|
|
9067
|
-
if (
|
|
9136
|
+
if (existsSync31(runtimeCache)) {
|
|
9068
9137
|
process.env.XDG_CACHE_HOME = runtimeCache;
|
|
9069
9138
|
}
|
|
9070
9139
|
const workspaceSecrets = loadDotEnvSecrets(ctx.workspaceDir, process.env);
|
|
@@ -9090,31 +9159,31 @@ function hydrateRuntimeProcessEnv(ctx) {
|
|
|
9090
9159
|
const currentPath = process.env.PATH || "";
|
|
9091
9160
|
const pathEntries = currentPath.split(":").filter(Boolean);
|
|
9092
9161
|
for (const entry of [runtimeBin, runtimeWorkspaceBin, runtimeTools, "/usr/bin", "/bin", "/usr/sbin", "/sbin"]) {
|
|
9093
|
-
if (
|
|
9162
|
+
if (existsSync31(entry) && !pathEntries.includes(entry)) {
|
|
9094
9163
|
pathEntries.unshift(entry);
|
|
9095
9164
|
}
|
|
9096
9165
|
}
|
|
9097
9166
|
process.env.PATH = pathEntries.join(":");
|
|
9098
9167
|
if (!process.env.RIG_GIT_BIN) {
|
|
9099
|
-
const runtimeGit =
|
|
9100
|
-
process.env.RIG_GIT_BIN =
|
|
9168
|
+
const runtimeGit = resolve33(runtimeBin, "git");
|
|
9169
|
+
process.env.RIG_GIT_BIN = existsSync31(runtimeGit) ? runtimeGit : Bun.which("git") || "/usr/bin/git";
|
|
9101
9170
|
}
|
|
9102
9171
|
const knownHosts = ensureRuntimeKnownHosts(runtimeHome);
|
|
9103
|
-
const agentKey =
|
|
9172
|
+
const agentKey = resolve33(runtimeHome, ".ssh", "rig-agent-key");
|
|
9104
9173
|
const sshParts = [
|
|
9105
9174
|
"ssh",
|
|
9106
9175
|
`-o UserKnownHostsFile="${knownHosts}"`,
|
|
9107
9176
|
"-o StrictHostKeyChecking=yes",
|
|
9108
9177
|
"-F /dev/null"
|
|
9109
9178
|
];
|
|
9110
|
-
if (
|
|
9179
|
+
if (existsSync31(agentKey)) {
|
|
9111
9180
|
sshParts.splice(1, 0, `-i "${agentKey}"`, "-o IdentitiesOnly=yes");
|
|
9112
9181
|
}
|
|
9113
9182
|
process.env.GIT_SSH_COMMAND = sshParts.join(" ");
|
|
9114
9183
|
}
|
|
9115
9184
|
function inferRuntimeContextFileFromWorkspace(workspaceDir) {
|
|
9116
|
-
const candidate =
|
|
9117
|
-
return
|
|
9185
|
+
const candidate = resolve33(workspaceDir, "..", "runtime-context.json");
|
|
9186
|
+
return existsSync31(candidate) ? candidate : "";
|
|
9118
9187
|
}
|
|
9119
9188
|
async function main() {
|
|
9120
9189
|
const args = process.argv.slice(2);
|
|
@@ -9239,7 +9308,7 @@ async function runAgentCommand(args) {
|
|
|
9239
9308
|
const fileIdx = rest.indexOf("--file");
|
|
9240
9309
|
const inputFile = fileIdx !== -1 ? rest[fileIdx + 1] : undefined;
|
|
9241
9310
|
if (inputFile) {
|
|
9242
|
-
content =
|
|
9311
|
+
content = readFileSync18(resolve33(projectRoot, inputFile), "utf-8");
|
|
9243
9312
|
} else {
|
|
9244
9313
|
const chunks = [];
|
|
9245
9314
|
for await (const chunk of process.stdin) {
|
|
@@ -9542,8 +9611,8 @@ WORKFLOW:
|
|
|
9542
9611
|
`);
|
|
9543
9612
|
}
|
|
9544
9613
|
async function runCompletionVerification(projectRoot) {
|
|
9545
|
-
const hookPath =
|
|
9546
|
-
if (!
|
|
9614
|
+
const hookPath = resolve33(projectRoot, ".rig/bin/hooks/completion-verification");
|
|
9615
|
+
if (!existsSync31(hookPath)) {
|
|
9547
9616
|
console.error(`[rig-agent] completion-verification hook binary not found: ${hookPath}`);
|
|
9548
9617
|
return 1;
|
|
9549
9618
|
}
|
|
@@ -9577,7 +9646,7 @@ async function verifyRuntimeManifest() {
|
|
|
9577
9646
|
if (!manifestPath) {
|
|
9578
9647
|
return;
|
|
9579
9648
|
}
|
|
9580
|
-
if (!
|
|
9649
|
+
if (!existsSync31(manifestPath)) {
|
|
9581
9650
|
throw new Error(`[rig-agent] Runtime manifest missing: ${manifestPath}`);
|
|
9582
9651
|
}
|
|
9583
9652
|
let manifest;
|
|
@@ -9594,10 +9663,10 @@ async function verifyRuntimeManifest() {
|
|
|
9594
9663
|
if (!manifestBinaryPath || !expectedHash) {
|
|
9595
9664
|
throw new Error(`[rig-agent] Runtime manifest is missing binary hash data (${manifestPath}).`);
|
|
9596
9665
|
}
|
|
9597
|
-
if (!
|
|
9666
|
+
if (!existsSync31(manifestBinaryPath)) {
|
|
9598
9667
|
throw new Error(`[rig-agent] Runtime binary not found at ${manifestBinaryPath}.`);
|
|
9599
9668
|
}
|
|
9600
|
-
const actualHash = sha256Hex(
|
|
9669
|
+
const actualHash = sha256Hex(readFileSync18(resolve33(manifestBinaryPath)));
|
|
9601
9670
|
if (actualHash !== expectedHash) {
|
|
9602
9671
|
throw new Error(`[rig-agent] Runtime manifest mismatch for binary hash.
|
|
9603
9672
|
` + `expected=${expectedHash}
|