@h-rig/runtime 0.0.6-alpha.27 → 0.0.6-alpha.29
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 +552 -483
- package/dist/bin/rig-agent.js +418 -364
- package/dist/src/control-plane/agent-wrapper.js +557 -488
- package/dist/src/control-plane/harness-main.js +559 -1418
- package/dist/src/control-plane/hooks/completion-verification.js +451 -808
- package/dist/src/control-plane/hooks/inject-context.js +191 -137
- package/dist/src/control-plane/hooks/submodule-branch.js +596 -542
- package/dist/src/control-plane/hooks/task-runtime-start.js +596 -542
- package/dist/src/control-plane/materialize-task-config.js +64 -8
- package/dist/src/control-plane/native/git-ops.js +3 -0
- package/dist/src/control-plane/native/harness-cli.js +544 -496
- package/dist/src/control-plane/native/repo-ops.js +3 -0
- package/dist/src/control-plane/native/run-ops.js +3 -0
- package/dist/src/control-plane/native/task-ops.js +418 -370
- package/dist/src/control-plane/native/validator.js +161 -107
- package/dist/src/control-plane/native/verifier.js +217 -169
- package/dist/src/control-plane/pi-sessiond/launcher.js +12 -2
- package/dist/src/control-plane/plugin-host-context.js +54 -0
- package/dist/src/control-plane/runtime/image/fingerprint-sidecar.js +3 -0
- package/dist/src/control-plane/runtime/image/index.js +3 -0
- package/dist/src/control-plane/runtime/image-fingerprint-sidecar.js +3 -0
- package/dist/src/control-plane/runtime/image.js +3 -0
- package/dist/src/control-plane/runtime/index.js +487 -718
- package/dist/src/control-plane/runtime/isolation/index.js +511 -457
- package/dist/src/control-plane/runtime/isolation.js +511 -457
- package/dist/src/control-plane/runtime/plugin-mode.js +3 -27
- package/dist/src/control-plane/runtime/queue.js +428 -381
- package/dist/src/control-plane/runtime/snapshot/task-run.js +3 -0
- package/dist/src/control-plane/runtime/task-run-snapshot.js +3 -0
- package/dist/src/control-plane/skill-materializer.js +46 -0
- package/dist/src/control-plane/tasks/source-lifecycle.js +84 -30
- package/dist/src/index.js +0 -278
- package/native/darwin-arm64/rig-shell +0 -0
- package/native/darwin-arm64/rig-shell.build-manifest.json +1 -1
- package/native/darwin-arm64/rig-tools +0 -0
- package/native/darwin-arm64/rig-tools.build-manifest.json +1 -1
- package/package.json +8 -7
- package/dist/src/control-plane/runtime/plugins.js +0 -1131
- package/dist/src/plugins.js +0 -329
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 dirname17, resolve as
|
|
5
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync17, readFileSync as readFileSync17, writeFileSync as writeFileSync15 } from "fs";
|
|
6
|
+
import { dirname as dirname17, resolve as resolve32 } 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 dirname14, isAbsolute as isAbsolute2, resolve as
|
|
3619
|
+
import { existsSync as existsSync23, lstatSync, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync11 } from "fs";
|
|
3620
|
+
import { dirname as dirname14, isAbsolute as isAbsolute2, resolve as resolve27 } 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 existsSync22, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync10 } from "fs";
|
|
3625
|
+
import { resolve as resolve26 } from "path";
|
|
3626
3626
|
|
|
3627
3627
|
// packages/runtime/src/control-plane/runtime/tooling/shell.ts
|
|
3628
3628
|
import { tmpdir as tmpdir4 } from "os";
|
|
@@ -3983,6 +3983,49 @@ function safeReadJson(path) {
|
|
|
3983
3983
|
}
|
|
3984
3984
|
}
|
|
3985
3985
|
|
|
3986
|
+
// packages/runtime/src/control-plane/skill-materializer.ts
|
|
3987
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync8, readdirSync, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
3988
|
+
import { resolve as resolve14 } from "path";
|
|
3989
|
+
import { loadSkill } from "@rig/skill-loader";
|
|
3990
|
+
var MARKER_FILENAME = ".rig-plugin";
|
|
3991
|
+
function skillDirName(id) {
|
|
3992
|
+
return id.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
3993
|
+
}
|
|
3994
|
+
async function materializeSkills(projectRoot, entries) {
|
|
3995
|
+
const skillsRoot = resolve14(projectRoot, ".pi", "skills");
|
|
3996
|
+
if (existsSync11(skillsRoot)) {
|
|
3997
|
+
for (const name of readdirSync(skillsRoot)) {
|
|
3998
|
+
const dir = resolve14(skillsRoot, name);
|
|
3999
|
+
if (existsSync11(resolve14(dir, MARKER_FILENAME))) {
|
|
4000
|
+
rmSync4(dir, { recursive: true, force: true });
|
|
4001
|
+
}
|
|
4002
|
+
}
|
|
4003
|
+
}
|
|
4004
|
+
const written = [];
|
|
4005
|
+
for (const { pluginName, skill } of entries) {
|
|
4006
|
+
const sourcePath = resolve14(projectRoot, skill.path);
|
|
4007
|
+
if (!existsSync11(sourcePath)) {
|
|
4008
|
+
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${sourcePath} does not exist`);
|
|
4009
|
+
continue;
|
|
4010
|
+
}
|
|
4011
|
+
let body;
|
|
4012
|
+
try {
|
|
4013
|
+
await loadSkill(sourcePath);
|
|
4014
|
+
body = readFileSync8(sourcePath, "utf-8");
|
|
4015
|
+
} catch (err) {
|
|
4016
|
+
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${err instanceof Error ? err.message : err}`);
|
|
4017
|
+
continue;
|
|
4018
|
+
}
|
|
4019
|
+
const dir = resolve14(skillsRoot, skillDirName(skill.id));
|
|
4020
|
+
mkdirSync6(dir, { recursive: true });
|
|
4021
|
+
writeFileSync5(resolve14(dir, "SKILL.md"), body, "utf-8");
|
|
4022
|
+
writeFileSync5(resolve14(dir, MARKER_FILENAME), `${JSON.stringify({ plugin: pluginName, skillId: skill.id }, null, 2)}
|
|
4023
|
+
`, "utf-8");
|
|
4024
|
+
written.push({ id: skill.id, pluginName, directory: dir });
|
|
4025
|
+
}
|
|
4026
|
+
return written;
|
|
4027
|
+
}
|
|
4028
|
+
|
|
3986
4029
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
3987
4030
|
async function buildPluginHostContext(projectRoot) {
|
|
3988
4031
|
let config;
|
|
@@ -4019,6 +4062,17 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
4019
4062
|
} catch (err) {
|
|
4020
4063
|
console.warn(`[plugin-host] hook materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
4021
4064
|
}
|
|
4065
|
+
try {
|
|
4066
|
+
const skillEntries = config.plugins.flatMap((plugin) => (plugin.contributes?.skills ?? []).map((skill) => ({
|
|
4067
|
+
pluginName: plugin.name,
|
|
4068
|
+
skill
|
|
4069
|
+
})));
|
|
4070
|
+
if (skillEntries.length > 0) {
|
|
4071
|
+
await materializeSkills(projectRoot, skillEntries);
|
|
4072
|
+
}
|
|
4073
|
+
} catch (err) {
|
|
4074
|
+
console.warn(`[plugin-host] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
4075
|
+
}
|
|
4022
4076
|
return {
|
|
4023
4077
|
config,
|
|
4024
4078
|
pluginHost,
|
|
@@ -4032,12 +4086,12 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
4032
4086
|
|
|
4033
4087
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
4034
4088
|
import { spawnSync } from "child_process";
|
|
4035
|
-
import { existsSync as
|
|
4036
|
-
import { basename as basename4, join as join3, resolve as
|
|
4089
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10, readdirSync as readdirSync2, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
4090
|
+
import { basename as basename4, join as join3, resolve as resolve16 } from "path";
|
|
4037
4091
|
|
|
4038
4092
|
// packages/runtime/src/control-plane/tasks/legacy-task-config-source.ts
|
|
4039
|
-
import { existsSync as
|
|
4040
|
-
import { resolve as
|
|
4093
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
|
|
4094
|
+
import { resolve as resolve15 } from "path";
|
|
4041
4095
|
|
|
4042
4096
|
// packages/runtime/src/control-plane/tasks/task-record-reader.ts
|
|
4043
4097
|
async function findTaskById(reader, id) {
|
|
@@ -4060,7 +4114,7 @@ class LegacyTaskConfigReadError extends Error {
|
|
|
4060
4114
|
}
|
|
4061
4115
|
}
|
|
4062
4116
|
function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
4063
|
-
const configPath = options.configPath ??
|
|
4117
|
+
const configPath = options.configPath ?? resolve15(projectRoot, ".rig", "task-config.json");
|
|
4064
4118
|
const reader = {
|
|
4065
4119
|
async listTasks() {
|
|
4066
4120
|
return readLegacyTaskRecords(projectRoot, configPath);
|
|
@@ -4071,8 +4125,8 @@ function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
|
4071
4125
|
};
|
|
4072
4126
|
return reader;
|
|
4073
4127
|
}
|
|
4074
|
-
function readLegacyTaskRecords(projectRoot, configPath =
|
|
4075
|
-
if (!
|
|
4128
|
+
function readLegacyTaskRecords(projectRoot, configPath = resolve15(projectRoot, ".rig", "task-config.json")) {
|
|
4129
|
+
if (!existsSync12(configPath)) {
|
|
4076
4130
|
return [];
|
|
4077
4131
|
}
|
|
4078
4132
|
const rawConfig = readLegacyTaskConfigJson(projectRoot, configPath);
|
|
@@ -4080,7 +4134,7 @@ function readLegacyTaskRecords(projectRoot, configPath = resolve14(projectRoot,
|
|
|
4080
4134
|
}
|
|
4081
4135
|
function readLegacyTaskConfigJson(projectRoot, configPath) {
|
|
4082
4136
|
try {
|
|
4083
|
-
const parsed = JSON.parse(
|
|
4137
|
+
const parsed = JSON.parse(readFileSync9(configPath, "utf8"));
|
|
4084
4138
|
if (isPlainRecord(parsed)) {
|
|
4085
4139
|
return parsed;
|
|
4086
4140
|
}
|
|
@@ -4164,7 +4218,7 @@ function isPlainRecord(candidate) {
|
|
|
4164
4218
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
4165
4219
|
var FILE_TASK_PATTERN = /\.(task\.)?json$/;
|
|
4166
4220
|
function createSourceAwareTaskConfigRecordReader(projectRoot, options = {}) {
|
|
4167
|
-
const configPath = options.configPath ??
|
|
4221
|
+
const configPath = options.configPath ?? resolve16(projectRoot, ".rig", "task-config.json");
|
|
4168
4222
|
const legacy = createLegacyTaskConfigRecordReader(projectRoot, { configPath });
|
|
4169
4223
|
const spawnFn = options.spawn ?? spawnSync;
|
|
4170
4224
|
const ghBinary = options.ghBinary ?? "gh";
|
|
@@ -4247,10 +4301,10 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
4247
4301
|
return metadata;
|
|
4248
4302
|
}
|
|
4249
4303
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
4250
|
-
const jsonPath =
|
|
4251
|
-
if (
|
|
4304
|
+
const jsonPath = resolve16(projectRoot, "rig.config.json");
|
|
4305
|
+
if (existsSync13(jsonPath)) {
|
|
4252
4306
|
try {
|
|
4253
|
-
const parsed = JSON.parse(
|
|
4307
|
+
const parsed = JSON.parse(readFileSync10(jsonPath, "utf8"));
|
|
4254
4308
|
if (isPlainRecord2(parsed) && isPlainRecord2(parsed.taskSource)) {
|
|
4255
4309
|
const source = parsed.taskSource;
|
|
4256
4310
|
return source.kind === "files" && typeof source.path === "string" ? source.path : null;
|
|
@@ -4259,12 +4313,12 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
4259
4313
|
return null;
|
|
4260
4314
|
}
|
|
4261
4315
|
}
|
|
4262
|
-
const tsPath =
|
|
4263
|
-
if (!
|
|
4316
|
+
const tsPath = resolve16(projectRoot, "rig.config.ts");
|
|
4317
|
+
if (!existsSync13(tsPath)) {
|
|
4264
4318
|
return null;
|
|
4265
4319
|
}
|
|
4266
4320
|
try {
|
|
4267
|
-
const source =
|
|
4321
|
+
const source = readFileSync10(tsPath, "utf8");
|
|
4268
4322
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
4269
4323
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
4270
4324
|
if (kind !== "files") {
|
|
@@ -4284,10 +4338,10 @@ function readRawTaskEntry(configPath, taskId) {
|
|
|
4284
4338
|
return isPlainRecord2(entry) ? entry : null;
|
|
4285
4339
|
}
|
|
4286
4340
|
function readRawTaskConfig(configPath) {
|
|
4287
|
-
if (!
|
|
4341
|
+
if (!existsSync13(configPath)) {
|
|
4288
4342
|
return null;
|
|
4289
4343
|
}
|
|
4290
|
-
const parsed = JSON.parse(
|
|
4344
|
+
const parsed = JSON.parse(readFileSync10(configPath, "utf8"));
|
|
4291
4345
|
return isPlainRecord2(parsed) ? parsed : null;
|
|
4292
4346
|
}
|
|
4293
4347
|
function stripLegacyTaskConfigMetadata2(raw) {
|
|
@@ -4295,12 +4349,12 @@ function stripLegacyTaskConfigMetadata2(raw) {
|
|
|
4295
4349
|
return tasks;
|
|
4296
4350
|
}
|
|
4297
4351
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
4298
|
-
const directory =
|
|
4299
|
-
if (!
|
|
4352
|
+
const directory = resolve16(projectRoot, sourcePath);
|
|
4353
|
+
if (!existsSync13(directory)) {
|
|
4300
4354
|
return [];
|
|
4301
4355
|
}
|
|
4302
4356
|
const tasks = [];
|
|
4303
|
-
for (const name of
|
|
4357
|
+
for (const name of readdirSync2(directory)) {
|
|
4304
4358
|
if (!FILE_TASK_PATTERN.test(name))
|
|
4305
4359
|
continue;
|
|
4306
4360
|
const inferredId = basename4(name).replace(FILE_TASK_PATTERN, "");
|
|
@@ -4311,11 +4365,11 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
4311
4365
|
return tasks;
|
|
4312
4366
|
}
|
|
4313
4367
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
4314
|
-
const file = findFileBackedTaskFile(
|
|
4368
|
+
const file = findFileBackedTaskFile(resolve16(projectRoot, sourcePath), taskId);
|
|
4315
4369
|
if (!file) {
|
|
4316
4370
|
return null;
|
|
4317
4371
|
}
|
|
4318
|
-
const raw = JSON.parse(
|
|
4372
|
+
const raw = JSON.parse(readFileSync10(file, "utf8"));
|
|
4319
4373
|
if (!isPlainRecord2(raw)) {
|
|
4320
4374
|
return null;
|
|
4321
4375
|
}
|
|
@@ -4328,17 +4382,17 @@ function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
|
4328
4382
|
};
|
|
4329
4383
|
}
|
|
4330
4384
|
function findFileBackedTaskFile(directory, taskId) {
|
|
4331
|
-
if (!
|
|
4385
|
+
if (!existsSync13(directory)) {
|
|
4332
4386
|
return null;
|
|
4333
4387
|
}
|
|
4334
|
-
for (const name of
|
|
4388
|
+
for (const name of readdirSync2(directory)) {
|
|
4335
4389
|
if (!FILE_TASK_PATTERN.test(name))
|
|
4336
4390
|
continue;
|
|
4337
4391
|
const file = join3(directory, name);
|
|
4338
4392
|
try {
|
|
4339
4393
|
if (!statSync3(file).isFile())
|
|
4340
4394
|
continue;
|
|
4341
|
-
const raw = JSON.parse(
|
|
4395
|
+
const raw = JSON.parse(readFileSync10(file, "utf8"));
|
|
4342
4396
|
const inferredId = basename4(file).replace(FILE_TASK_PATTERN, "");
|
|
4343
4397
|
const id = isPlainRecord2(raw) && typeof raw.id === "string" ? raw.id : inferredId;
|
|
4344
4398
|
if (id === taskId) {
|
|
@@ -4498,8 +4552,8 @@ async function readConfiguredTaskSourceTask(projectRoot, taskId) {
|
|
|
4498
4552
|
}
|
|
4499
4553
|
|
|
4500
4554
|
// packages/runtime/src/control-plane/native/task-state.ts
|
|
4501
|
-
import { existsSync as
|
|
4502
|
-
import { basename as basename6, resolve as
|
|
4555
|
+
import { existsSync as existsSync17, readFileSync as readFileSync12, readdirSync as readdirSync3, statSync as statSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
4556
|
+
import { basename as basename6, resolve as resolve20 } from "path";
|
|
4503
4557
|
|
|
4504
4558
|
// packages/runtime/src/control-plane/state-sync/types.ts
|
|
4505
4559
|
var SUPPORTED_TASK_STATE_SCHEMA_VERSION = 1;
|
|
@@ -4607,38 +4661,38 @@ function readTaskStateMetadataEnvelope(raw) {
|
|
|
4607
4661
|
};
|
|
4608
4662
|
}
|
|
4609
4663
|
// packages/runtime/src/control-plane/state-sync/read.ts
|
|
4610
|
-
import { existsSync as
|
|
4611
|
-
import { resolve as
|
|
4664
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11 } from "fs";
|
|
4665
|
+
import { resolve as resolve19 } from "path";
|
|
4612
4666
|
|
|
4613
4667
|
// packages/runtime/src/control-plane/state-sync/repo.ts
|
|
4614
|
-
import { existsSync as
|
|
4615
|
-
import { resolve as
|
|
4668
|
+
import { existsSync as existsSync15 } from "fs";
|
|
4669
|
+
import { resolve as resolve18 } from "path";
|
|
4616
4670
|
|
|
4617
4671
|
// packages/runtime/src/control-plane/repos/layout.ts
|
|
4618
|
-
import { existsSync as
|
|
4619
|
-
import { basename as basename5, dirname as dirname11, join as join4, resolve as
|
|
4672
|
+
import { existsSync as existsSync14 } from "fs";
|
|
4673
|
+
import { basename as basename5, dirname as dirname11, join as join4, resolve as resolve17 } from "path";
|
|
4620
4674
|
function resolveRepoStateDir(projectRoot) {
|
|
4621
|
-
const normalizedProjectRoot =
|
|
4675
|
+
const normalizedProjectRoot = resolve17(projectRoot);
|
|
4622
4676
|
const projectParent = dirname11(normalizedProjectRoot);
|
|
4623
4677
|
if (basename5(projectParent) === ".worktrees") {
|
|
4624
4678
|
const ownerRoot = dirname11(projectParent);
|
|
4625
|
-
const ownerHasRepoMarkers =
|
|
4679
|
+
const ownerHasRepoMarkers = existsSync14(resolve17(ownerRoot, ".git")) || existsSync14(resolve17(ownerRoot, ".rig", "state"));
|
|
4626
4680
|
if (ownerHasRepoMarkers) {
|
|
4627
|
-
return
|
|
4681
|
+
return resolve17(ownerRoot, ".rig", "state");
|
|
4628
4682
|
}
|
|
4629
4683
|
}
|
|
4630
|
-
return
|
|
4684
|
+
return resolve17(projectRoot, ".rig", "state");
|
|
4631
4685
|
}
|
|
4632
4686
|
function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
4633
|
-
const normalizedProjectRoot =
|
|
4687
|
+
const normalizedProjectRoot = resolve17(projectRoot);
|
|
4634
4688
|
const entry = getManagedRepoEntry(repoId);
|
|
4635
4689
|
const stateDir = resolveRepoStateDir(normalizedProjectRoot);
|
|
4636
4690
|
const metadataRelativePath = join4("repos", entry.id);
|
|
4637
|
-
const metadataRoot =
|
|
4691
|
+
const metadataRoot = resolve17(stateDir, metadataRelativePath);
|
|
4638
4692
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
4639
|
-
const runsInsideTaskWorktree = runtimeWorkspace &&
|
|
4693
|
+
const runsInsideTaskWorktree = runtimeWorkspace && resolve17(runtimeWorkspace) === normalizedProjectRoot || basename5(dirname11(normalizedProjectRoot)) === ".worktrees";
|
|
4640
4694
|
const isPrimaryManagedRepo = listManagedRepoEntries()[0]?.id === repoId;
|
|
4641
|
-
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ?
|
|
4695
|
+
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ? resolve17(process.env[entry.checkoutEnvVar].trim()) : resolve17(normalizedProjectRoot, entry.alias);
|
|
4642
4696
|
return {
|
|
4643
4697
|
projectRoot: normalizedProjectRoot,
|
|
4644
4698
|
repoId: entry.id,
|
|
@@ -4646,12 +4700,12 @@ function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
|
4646
4700
|
defaultBranch: entry.defaultBranch,
|
|
4647
4701
|
remoteUrl: entry.remoteEnvVar && process.env[entry.remoteEnvVar]?.trim() ? process.env[entry.remoteEnvVar].trim() : entry.defaultRemoteUrl,
|
|
4648
4702
|
checkoutRoot,
|
|
4649
|
-
worktreesRoot:
|
|
4703
|
+
worktreesRoot: resolve17(checkoutRoot, ".worktrees"),
|
|
4650
4704
|
stateDir,
|
|
4651
4705
|
metadataRoot,
|
|
4652
4706
|
metadataRelativePath,
|
|
4653
|
-
mirrorRoot:
|
|
4654
|
-
mirrorStatePath:
|
|
4707
|
+
mirrorRoot: resolve17(metadataRoot, "mirror.git"),
|
|
4708
|
+
mirrorStatePath: resolve17(metadataRoot, "mirror-state.json"),
|
|
4655
4709
|
mirrorStateRelativePath: join4(metadataRelativePath, "mirror-state.json")
|
|
4656
4710
|
};
|
|
4657
4711
|
}
|
|
@@ -4673,7 +4727,7 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
4673
4727
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
4674
4728
|
try {
|
|
4675
4729
|
const layout = resolveMonorepoRepoLayout(projectRoot);
|
|
4676
|
-
if (
|
|
4730
|
+
if (existsSync15(resolve18(layout.mirrorRoot, "HEAD"))) {
|
|
4677
4731
|
return layout.mirrorRoot;
|
|
4678
4732
|
}
|
|
4679
4733
|
} catch {}
|
|
@@ -4684,8 +4738,8 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
4684
4738
|
var DEFAULT_READ_DEPS2 = {
|
|
4685
4739
|
fetchRef: nativeFetchRef,
|
|
4686
4740
|
readBlobAtRef: nativeReadBlobAtRef,
|
|
4687
|
-
exists:
|
|
4688
|
-
readFile: (path) =>
|
|
4741
|
+
exists: existsSync16,
|
|
4742
|
+
readFile: (path) => readFileSync11(path, "utf8")
|
|
4689
4743
|
};
|
|
4690
4744
|
function parseIssueStatus(rawStatus) {
|
|
4691
4745
|
const normalized = normalizeTaskLifecycleStatus(rawStatus);
|
|
@@ -4766,12 +4820,12 @@ function shouldPreferLocalTrackerState(options) {
|
|
|
4766
4820
|
if (runtimeContextPath) {
|
|
4767
4821
|
return true;
|
|
4768
4822
|
}
|
|
4769
|
-
return
|
|
4823
|
+
return existsSync16(resolve19(runtimeWorkspace, ".rig", "runtime-context.json"));
|
|
4770
4824
|
}
|
|
4771
4825
|
function readLocalTrackerState(projectRoot, deps) {
|
|
4772
4826
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
4773
|
-
const issuesPath =
|
|
4774
|
-
const taskStatePath =
|
|
4827
|
+
const issuesPath = resolve19(monorepoRoot, ".beads", "issues.jsonl");
|
|
4828
|
+
const taskStatePath = resolve19(monorepoRoot, ".beads", "task-state.json");
|
|
4775
4829
|
return projectSyncedTrackerSnapshot({
|
|
4776
4830
|
source: "local",
|
|
4777
4831
|
issuesBaseOid: null,
|
|
@@ -4833,7 +4887,7 @@ function readValidationDescriptions(projectRoot) {
|
|
|
4833
4887
|
return readValidationDescriptionMap(raw);
|
|
4834
4888
|
}
|
|
4835
4889
|
function readSourceValidationDescriptions(projectRoot) {
|
|
4836
|
-
const rootRaw = readJsonFile(
|
|
4890
|
+
const rootRaw = readJsonFile(resolve20(projectRoot, "rig", "task-config.json"), {});
|
|
4837
4891
|
const sourcePath = findSourceTaskConfigPath(projectRoot);
|
|
4838
4892
|
const sourceRaw = sourcePath ? readJsonFile(sourcePath, {}) : {};
|
|
4839
4893
|
const rootDescriptions = readValidationDescriptionMap(rootRaw);
|
|
@@ -4909,15 +4963,15 @@ function readValidationDescriptionsFromMeta(meta) {
|
|
|
4909
4963
|
return meta.validation_descriptions;
|
|
4910
4964
|
}
|
|
4911
4965
|
function readLocalSourceTaskStateEnvelope(projectRoot) {
|
|
4912
|
-
const taskStatePath =
|
|
4966
|
+
const taskStatePath = resolve20(resolveMonorepoRoot2(projectRoot), ".beads", "task-state.json");
|
|
4913
4967
|
return readTaskStateMetadataEnvelope(readJsonFile(taskStatePath, {}));
|
|
4914
4968
|
}
|
|
4915
4969
|
function readLocalSourceTaskLifecycleStatus(projectRoot, taskId) {
|
|
4916
|
-
const issuesPath =
|
|
4917
|
-
if (!
|
|
4970
|
+
const issuesPath = resolve20(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
4971
|
+
if (!existsSync17(issuesPath)) {
|
|
4918
4972
|
return null;
|
|
4919
4973
|
}
|
|
4920
|
-
for (const line of
|
|
4974
|
+
for (const line of readFileSync12(issuesPath, "utf8").split(/\r?\n/)) {
|
|
4921
4975
|
const trimmed = line.trim();
|
|
4922
4976
|
if (!trimmed) {
|
|
4923
4977
|
continue;
|
|
@@ -4958,25 +5012,25 @@ function lookupTask(projectRoot, input) {
|
|
|
4958
5012
|
function artifactDirForId(projectRoot, id) {
|
|
4959
5013
|
const workspaceDir = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
4960
5014
|
if (workspaceDir) {
|
|
4961
|
-
const worktreeArtifacts =
|
|
4962
|
-
if (
|
|
5015
|
+
const worktreeArtifacts = resolve20(workspaceDir, "artifacts", id);
|
|
5016
|
+
if (existsSync17(worktreeArtifacts) || existsSync17(resolve20(workspaceDir, "artifacts"))) {
|
|
4963
5017
|
return worktreeArtifacts;
|
|
4964
5018
|
}
|
|
4965
5019
|
}
|
|
4966
5020
|
try {
|
|
4967
5021
|
const paths = resolveHarnessPaths(projectRoot);
|
|
4968
|
-
return
|
|
5022
|
+
return resolve20(paths.artifactsDir, id);
|
|
4969
5023
|
} catch {
|
|
4970
|
-
return
|
|
5024
|
+
return resolve20(resolveMonorepoRoot2(projectRoot), "artifacts", id);
|
|
4971
5025
|
}
|
|
4972
5026
|
}
|
|
4973
5027
|
function resolveTaskConfigPath(projectRoot) {
|
|
4974
5028
|
const paths = resolveHarnessPaths(projectRoot);
|
|
4975
|
-
if (
|
|
5029
|
+
if (existsSync17(paths.taskConfigPath)) {
|
|
4976
5030
|
return paths.taskConfigPath;
|
|
4977
5031
|
}
|
|
4978
5032
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
4979
|
-
if (
|
|
5033
|
+
if (existsSync17(candidate)) {
|
|
4980
5034
|
return candidate;
|
|
4981
5035
|
}
|
|
4982
5036
|
}
|
|
@@ -4984,7 +5038,7 @@ function resolveTaskConfigPath(projectRoot) {
|
|
|
4984
5038
|
}
|
|
4985
5039
|
function findSourceTaskConfigPath(projectRoot) {
|
|
4986
5040
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
4987
|
-
if (
|
|
5041
|
+
if (existsSync17(candidate)) {
|
|
4988
5042
|
return candidate;
|
|
4989
5043
|
}
|
|
4990
5044
|
}
|
|
@@ -4997,7 +5051,7 @@ function readAndSyncSourceTaskConfig(projectRoot) {
|
|
|
4997
5051
|
const synced = synchronizeTaskConfigWithTracker(projectRoot, raw);
|
|
4998
5052
|
if (sourcePath && synced.updated) {
|
|
4999
5053
|
try {
|
|
5000
|
-
|
|
5054
|
+
writeFileSync7(sourcePath, `${JSON.stringify(synced.config, null, 2)}
|
|
5001
5055
|
`, "utf-8");
|
|
5002
5056
|
} catch {}
|
|
5003
5057
|
}
|
|
@@ -5049,12 +5103,12 @@ function shouldRefreshAutoSyncedTaskConfigEntry(entry) {
|
|
|
5049
5103
|
return !candidate.role;
|
|
5050
5104
|
}
|
|
5051
5105
|
function readSourceIssueRecords(projectRoot) {
|
|
5052
|
-
const issuesPath =
|
|
5053
|
-
if (!
|
|
5106
|
+
const issuesPath = resolve20(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
5107
|
+
if (!existsSync17(issuesPath)) {
|
|
5054
5108
|
return [];
|
|
5055
5109
|
}
|
|
5056
5110
|
const records = [];
|
|
5057
|
-
for (const line of
|
|
5111
|
+
for (const line of readFileSync12(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
5058
5112
|
const trimmed = line.trim();
|
|
5059
5113
|
if (!trimmed) {
|
|
5060
5114
|
continue;
|
|
@@ -5110,19 +5164,19 @@ function readConfiguredFileTaskConfig(projectRoot) {
|
|
|
5110
5164
|
if (!sourcePath) {
|
|
5111
5165
|
return {};
|
|
5112
5166
|
}
|
|
5113
|
-
const directory =
|
|
5114
|
-
if (!
|
|
5167
|
+
const directory = resolve20(projectRoot, sourcePath);
|
|
5168
|
+
if (!existsSync17(directory)) {
|
|
5115
5169
|
return {};
|
|
5116
5170
|
}
|
|
5117
5171
|
const config = {};
|
|
5118
|
-
for (const name of
|
|
5172
|
+
for (const name of readdirSync3(directory)) {
|
|
5119
5173
|
if (!FILE_TASK_PATTERN2.test(name))
|
|
5120
5174
|
continue;
|
|
5121
|
-
const file =
|
|
5175
|
+
const file = resolve20(directory, name);
|
|
5122
5176
|
try {
|
|
5123
5177
|
if (!statSync4(file).isFile())
|
|
5124
5178
|
continue;
|
|
5125
|
-
const raw = JSON.parse(
|
|
5179
|
+
const raw = JSON.parse(readFileSync12(file, "utf8"));
|
|
5126
5180
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
5127
5181
|
continue;
|
|
5128
5182
|
const record = raw;
|
|
@@ -5164,10 +5218,10 @@ function firstStringList2(...candidates) {
|
|
|
5164
5218
|
return [];
|
|
5165
5219
|
}
|
|
5166
5220
|
function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
5167
|
-
const jsonPath =
|
|
5168
|
-
if (
|
|
5221
|
+
const jsonPath = resolve20(projectRoot, "rig.config.json");
|
|
5222
|
+
if (existsSync17(jsonPath)) {
|
|
5169
5223
|
try {
|
|
5170
|
-
const parsed = JSON.parse(
|
|
5224
|
+
const parsed = JSON.parse(readFileSync12(jsonPath, "utf8"));
|
|
5171
5225
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
5172
5226
|
const taskSource = parsed.taskSource;
|
|
5173
5227
|
if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
|
|
@@ -5179,12 +5233,12 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
5179
5233
|
return null;
|
|
5180
5234
|
}
|
|
5181
5235
|
}
|
|
5182
|
-
const tsPath =
|
|
5183
|
-
if (!
|
|
5236
|
+
const tsPath = resolve20(projectRoot, "rig.config.ts");
|
|
5237
|
+
if (!existsSync17(tsPath)) {
|
|
5184
5238
|
return null;
|
|
5185
5239
|
}
|
|
5186
5240
|
try {
|
|
5187
|
-
const source =
|
|
5241
|
+
const source = readFileSync12(tsPath, "utf8");
|
|
5188
5242
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
5189
5243
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
5190
5244
|
if (kind !== "files") {
|
|
@@ -5198,23 +5252,23 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
5198
5252
|
function sourceTaskConfigCandidates(projectRoot) {
|
|
5199
5253
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
5200
5254
|
return [
|
|
5201
|
-
runtimeContext?.monorepoMainRoot ?
|
|
5202
|
-
process.env.MONOREPO_MAIN_ROOT?.trim() ?
|
|
5203
|
-
|
|
5255
|
+
runtimeContext?.monorepoMainRoot ? resolve20(runtimeContext.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
5256
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve20(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
5257
|
+
resolve20(resolveMonorepoRoot2(projectRoot), ".rig", "task-config.json")
|
|
5204
5258
|
].filter(Boolean);
|
|
5205
5259
|
}
|
|
5206
5260
|
|
|
5207
5261
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
5208
|
-
import { existsSync as
|
|
5209
|
-
import { resolve as
|
|
5262
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
5263
|
+
import { resolve as resolve25 } from "path";
|
|
5210
5264
|
|
|
5211
5265
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
5212
|
-
import { existsSync as
|
|
5213
|
-
import { dirname as dirname13, resolve as
|
|
5266
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync8, rmSync as rmSync6, statSync as statSync5 } from "fs";
|
|
5267
|
+
import { dirname as dirname13, resolve as resolve24 } from "path";
|
|
5214
5268
|
|
|
5215
5269
|
// packages/runtime/src/binary-run.ts
|
|
5216
|
-
import { chmodSync as chmodSync2, cpSync, existsSync as
|
|
5217
|
-
import { basename as basename7, dirname as dirname12, resolve as
|
|
5270
|
+
import { chmodSync as chmodSync2, cpSync, existsSync as existsSync18, mkdirSync as mkdirSync7, renameSync as renameSync3, rmSync as rmSync5, writeFileSync as writeFileSync8 } from "fs";
|
|
5271
|
+
import { basename as basename7, dirname as dirname12, resolve as resolve21 } from "path";
|
|
5218
5272
|
import { fileURLToPath } from "url";
|
|
5219
5273
|
import { drainMicrotasks, gcAndSweep } from "bun:jsc";
|
|
5220
5274
|
var runtimeBinaryBuildQueue = Promise.resolve();
|
|
@@ -5240,9 +5294,9 @@ async function buildRuntimeBinary(options) {
|
|
|
5240
5294
|
});
|
|
5241
5295
|
}
|
|
5242
5296
|
async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
5243
|
-
const tempBuildDir =
|
|
5244
|
-
const tempOutputPath =
|
|
5245
|
-
|
|
5297
|
+
const tempBuildDir = resolve21(dirname12(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
5298
|
+
const tempOutputPath = resolve21(tempBuildDir, basename7(options.outputPath));
|
|
5299
|
+
mkdirSync7(tempBuildDir, { recursive: true });
|
|
5246
5300
|
await withTemporaryEnv({
|
|
5247
5301
|
...options.env,
|
|
5248
5302
|
...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
|
|
@@ -5267,7 +5321,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
5267
5321
|
`);
|
|
5268
5322
|
throw new Error(`Failed to build ${options.entrypoint}: ${details || "Bun.build() returned errors"}`);
|
|
5269
5323
|
}
|
|
5270
|
-
if (!
|
|
5324
|
+
if (!existsSync18(tempOutputPath)) {
|
|
5271
5325
|
const emitted = buildResult.outputs.map((output) => output.path).join(", ") || "(none)";
|
|
5272
5326
|
throw new Error(`Failed to build ${options.entrypoint}: Bun.build() did not emit ${tempOutputPath}. Emitted: ${emitted}`);
|
|
5273
5327
|
}
|
|
@@ -5282,7 +5336,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
5282
5336
|
});
|
|
5283
5337
|
}
|
|
5284
5338
|
})).finally(() => {
|
|
5285
|
-
|
|
5339
|
+
rmSync5(tempBuildDir, { recursive: true, force: true });
|
|
5286
5340
|
});
|
|
5287
5341
|
}
|
|
5288
5342
|
function runBestEffortBuildGc() {
|
|
@@ -5299,8 +5353,8 @@ function runtimeBinaryCacheManifestPath(outputPath) {
|
|
|
5299
5353
|
function resolveRuntimeBinaryBuildOptions(options) {
|
|
5300
5354
|
return {
|
|
5301
5355
|
...options,
|
|
5302
|
-
entrypoint:
|
|
5303
|
-
outputPath:
|
|
5356
|
+
entrypoint: resolve21(options.cwd, options.sourcePath),
|
|
5357
|
+
outputPath: resolve21(options.outputPath)
|
|
5304
5358
|
};
|
|
5305
5359
|
}
|
|
5306
5360
|
function shouldUseRuntimeBinaryBuildWorker() {
|
|
@@ -5314,7 +5368,7 @@ function shouldUseRuntimeBinaryBuildWorker() {
|
|
|
5314
5368
|
}
|
|
5315
5369
|
async function buildRuntimeBinaryViaWorker(options) {
|
|
5316
5370
|
const workerSourcePath = resolveRuntimeBinaryBuildWorkerSourcePath(options);
|
|
5317
|
-
if (!workerSourcePath || !
|
|
5371
|
+
if (!workerSourcePath || !existsSync18(workerSourcePath)) {
|
|
5318
5372
|
await buildRuntimeBinaryInProcess(options, {
|
|
5319
5373
|
manifestPath: runtimeBinaryCacheManifestPath(options.outputPath),
|
|
5320
5374
|
buildKey: createRuntimeBinaryBuildKey({
|
|
@@ -5345,13 +5399,13 @@ async function buildRuntimeBinaryViaWorker(options) {
|
|
|
5345
5399
|
new Response(build.stdout).text(),
|
|
5346
5400
|
new Response(build.stderr).text()
|
|
5347
5401
|
]);
|
|
5348
|
-
|
|
5402
|
+
rmSync5(payloadPath, { force: true });
|
|
5349
5403
|
if (exitCode !== 0) {
|
|
5350
5404
|
throw new Error(`Failed to build ${options.entrypoint}: ${(stderr || stdout || `worker exited ${exitCode}`).trim()}`);
|
|
5351
5405
|
}
|
|
5352
5406
|
}
|
|
5353
5407
|
function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
|
|
5354
|
-
return
|
|
5408
|
+
return resolve21(dirname12(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
5355
5409
|
}
|
|
5356
5410
|
function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
5357
5411
|
const envRoots = [
|
|
@@ -5360,13 +5414,13 @@ function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
|
5360
5414
|
process.env.PROJECT_RIG_ROOT?.trim()
|
|
5361
5415
|
].filter(Boolean);
|
|
5362
5416
|
for (const root of envRoots) {
|
|
5363
|
-
const candidate =
|
|
5364
|
-
if (
|
|
5417
|
+
const candidate = resolve21(root, "packages/runtime/src/binary-build-worker.ts");
|
|
5418
|
+
if (existsSync18(candidate)) {
|
|
5365
5419
|
return candidate;
|
|
5366
5420
|
}
|
|
5367
5421
|
}
|
|
5368
|
-
const localCandidate =
|
|
5369
|
-
return
|
|
5422
|
+
const localCandidate = resolve21(import.meta.dir, "binary-build-worker.ts");
|
|
5423
|
+
return existsSync18(localCandidate) ? localCandidate : null;
|
|
5370
5424
|
}
|
|
5371
5425
|
function resolveRuntimeBinaryBuildWorkerInvocation() {
|
|
5372
5426
|
const bunPath = Bun.which("bun");
|
|
@@ -5402,7 +5456,7 @@ function createRuntimeBinaryBuildKey(input) {
|
|
|
5402
5456
|
});
|
|
5403
5457
|
}
|
|
5404
5458
|
async function isRuntimeBinaryBuildFresh(input) {
|
|
5405
|
-
if (!
|
|
5459
|
+
if (!existsSync18(input.outputPath) || !existsSync18(input.manifestPath)) {
|
|
5406
5460
|
return false;
|
|
5407
5461
|
}
|
|
5408
5462
|
let manifest = null;
|
|
@@ -5415,7 +5469,7 @@ async function isRuntimeBinaryBuildFresh(input) {
|
|
|
5415
5469
|
return false;
|
|
5416
5470
|
}
|
|
5417
5471
|
for (const [filePath, expectedDigest] of Object.entries(manifest.inputs || {})) {
|
|
5418
|
-
if (!
|
|
5472
|
+
if (!existsSync18(filePath)) {
|
|
5419
5473
|
return false;
|
|
5420
5474
|
}
|
|
5421
5475
|
if (await sha256File(filePath) !== expectedDigest) {
|
|
@@ -5428,7 +5482,7 @@ async function writeRuntimeBinaryCacheManifest(input) {
|
|
|
5428
5482
|
const inputs = {};
|
|
5429
5483
|
for (const inputPath of Object.keys(input.metafile?.inputs || {}).sort()) {
|
|
5430
5484
|
const normalized = normalizeBuildInputPath(input.cwd, inputPath);
|
|
5431
|
-
if (!normalized || !
|
|
5485
|
+
if (!normalized || !existsSync18(normalized)) {
|
|
5432
5486
|
continue;
|
|
5433
5487
|
}
|
|
5434
5488
|
inputs[normalized] = await sha256File(normalized);
|
|
@@ -5451,7 +5505,7 @@ function normalizeBuildInputPath(cwd, inputPath) {
|
|
|
5451
5505
|
if (inputPath.startsWith("<")) {
|
|
5452
5506
|
return null;
|
|
5453
5507
|
}
|
|
5454
|
-
return
|
|
5508
|
+
return resolve21(cwd, inputPath);
|
|
5455
5509
|
}
|
|
5456
5510
|
async function sha256File(path) {
|
|
5457
5511
|
const hasher = new Bun.CryptoHasher("sha256");
|
|
@@ -5467,8 +5521,8 @@ function sortRecord(value) {
|
|
|
5467
5521
|
async function runSerializedRuntimeBinaryBuild(action) {
|
|
5468
5522
|
const previous = runtimeBinaryBuildQueue;
|
|
5469
5523
|
let release;
|
|
5470
|
-
runtimeBinaryBuildQueue = new Promise((
|
|
5471
|
-
release =
|
|
5524
|
+
runtimeBinaryBuildQueue = new Promise((resolve22) => {
|
|
5525
|
+
release = resolve22;
|
|
5472
5526
|
});
|
|
5473
5527
|
await previous;
|
|
5474
5528
|
try {
|
|
@@ -5513,11 +5567,11 @@ async function withTemporaryCwd(cwd, action) {
|
|
|
5513
5567
|
}
|
|
5514
5568
|
|
|
5515
5569
|
// packages/runtime/src/control-plane/runtime/provisioning-env.ts
|
|
5516
|
-
import { delimiter, resolve as
|
|
5570
|
+
import { delimiter, resolve as resolve23 } from "path";
|
|
5517
5571
|
|
|
5518
5572
|
// packages/runtime/src/control-plane/runtime/runtime-paths.ts
|
|
5519
|
-
import { existsSync as
|
|
5520
|
-
import { resolve as
|
|
5573
|
+
import { existsSync as existsSync19, readdirSync as readdirSync4, realpathSync } from "fs";
|
|
5574
|
+
import { resolve as resolve22 } from "path";
|
|
5521
5575
|
|
|
5522
5576
|
// packages/runtime/src/control-plane/runtime/sandbox/utils.ts
|
|
5523
5577
|
function uniq(values) {
|
|
@@ -5535,7 +5589,7 @@ function resolveBunBinaryPath() {
|
|
|
5535
5589
|
}
|
|
5536
5590
|
const home = process.env.HOME?.trim();
|
|
5537
5591
|
const fallbackCandidates = [
|
|
5538
|
-
home ?
|
|
5592
|
+
home ? resolve22(home, ".bun/bin/bun") : "",
|
|
5539
5593
|
"/opt/homebrew/bin/bun",
|
|
5540
5594
|
"/usr/local/bin/bun",
|
|
5541
5595
|
"/usr/bin/bun"
|
|
@@ -5563,8 +5617,8 @@ function resolveClaudeBinaryPath() {
|
|
|
5563
5617
|
}
|
|
5564
5618
|
const home = process.env.HOME?.trim();
|
|
5565
5619
|
const fallbackCandidates = [
|
|
5566
|
-
home ?
|
|
5567
|
-
home ?
|
|
5620
|
+
home ? resolve22(home, ".local/bin/claude") : "",
|
|
5621
|
+
home ? resolve22(home, ".local/share/claude/local/claude") : "",
|
|
5568
5622
|
"/opt/homebrew/bin/claude",
|
|
5569
5623
|
"/usr/local/bin/claude",
|
|
5570
5624
|
"/usr/bin/claude"
|
|
@@ -5578,51 +5632,51 @@ function resolveClaudeBinaryPath() {
|
|
|
5578
5632
|
throw new Error("claude not found in PATH");
|
|
5579
5633
|
}
|
|
5580
5634
|
function resolveBunInstallDir(bunBinaryPath = resolveBunBinaryPath()) {
|
|
5581
|
-
return
|
|
5635
|
+
return resolve22(bunBinaryPath, "../..");
|
|
5582
5636
|
}
|
|
5583
5637
|
function resolveClaudeInstallDir() {
|
|
5584
5638
|
const realPath = resolveClaudeBinaryPath();
|
|
5585
|
-
return
|
|
5639
|
+
return resolve22(realPath, "..");
|
|
5586
5640
|
}
|
|
5587
5641
|
function resolveNodeInstallDir() {
|
|
5588
5642
|
const preferredNode = resolvePreferredNodeBinary();
|
|
5589
5643
|
if (!preferredNode)
|
|
5590
5644
|
return null;
|
|
5591
5645
|
const explicitNode = process.env.RIG_NODE_BIN?.trim();
|
|
5592
|
-
if (explicitNode &&
|
|
5593
|
-
return preferredNode.endsWith("/bin/node") ?
|
|
5646
|
+
if (explicitNode && resolve22(explicitNode) === resolve22(preferredNode)) {
|
|
5647
|
+
return preferredNode.endsWith("/bin/node") ? resolve22(preferredNode, "../..") : resolve22(preferredNode, "..");
|
|
5594
5648
|
}
|
|
5595
5649
|
try {
|
|
5596
5650
|
const realPath = realpathSync(preferredNode);
|
|
5597
5651
|
if (realPath.endsWith("/bin/node")) {
|
|
5598
|
-
return
|
|
5652
|
+
return resolve22(realPath, "../..");
|
|
5599
5653
|
}
|
|
5600
|
-
return
|
|
5654
|
+
return resolve22(realPath, "..");
|
|
5601
5655
|
} catch {
|
|
5602
|
-
return
|
|
5656
|
+
return resolve22(preferredNode, "..");
|
|
5603
5657
|
}
|
|
5604
5658
|
}
|
|
5605
5659
|
function resolvePreferredNodeBinary() {
|
|
5606
5660
|
const candidates = [];
|
|
5607
5661
|
const envNode = process.env.RIG_NODE_BIN?.trim();
|
|
5608
5662
|
if (envNode) {
|
|
5609
|
-
const explicit =
|
|
5610
|
-
if (
|
|
5663
|
+
const explicit = resolve22(envNode);
|
|
5664
|
+
if (existsSync19(explicit)) {
|
|
5611
5665
|
return explicit;
|
|
5612
5666
|
}
|
|
5613
5667
|
}
|
|
5614
5668
|
const nvmBin = process.env.NVM_BIN?.trim();
|
|
5615
5669
|
if (nvmBin) {
|
|
5616
|
-
candidates.push(
|
|
5670
|
+
candidates.push(resolve22(nvmBin, "node"));
|
|
5617
5671
|
}
|
|
5618
5672
|
const home = process.env.HOME?.trim();
|
|
5619
5673
|
if (home) {
|
|
5620
|
-
const nvmVersionsDir =
|
|
5621
|
-
if (
|
|
5674
|
+
const nvmVersionsDir = resolve22(home, ".nvm/versions/node");
|
|
5675
|
+
if (existsSync19(nvmVersionsDir)) {
|
|
5622
5676
|
try {
|
|
5623
|
-
const versionDirs =
|
|
5677
|
+
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/, "")));
|
|
5624
5678
|
for (const versionDir of versionDirs) {
|
|
5625
|
-
candidates.push(
|
|
5679
|
+
candidates.push(resolve22(nvmVersionsDir, versionDir, "bin/node"));
|
|
5626
5680
|
}
|
|
5627
5681
|
} catch {}
|
|
5628
5682
|
}
|
|
@@ -5631,8 +5685,8 @@ function resolvePreferredNodeBinary() {
|
|
|
5631
5685
|
if (whichNode) {
|
|
5632
5686
|
candidates.push(whichNode);
|
|
5633
5687
|
}
|
|
5634
|
-
const deduped = uniq(candidates.map((candidate) =>
|
|
5635
|
-
const existing = deduped.filter((candidate) =>
|
|
5688
|
+
const deduped = uniq(candidates.map((candidate) => resolve22(candidate)));
|
|
5689
|
+
const existing = deduped.filter((candidate) => existsSync19(candidate));
|
|
5636
5690
|
if (existing.length === 0) {
|
|
5637
5691
|
return null;
|
|
5638
5692
|
}
|
|
@@ -5646,7 +5700,7 @@ function resolvePreferredNodeBinary() {
|
|
|
5646
5700
|
return existing[0] ?? null;
|
|
5647
5701
|
}
|
|
5648
5702
|
function inferNodeMajor(nodeBinaryPath) {
|
|
5649
|
-
const normalized =
|
|
5703
|
+
const normalized = resolve22(nodeBinaryPath).replace(/\\/g, "/");
|
|
5650
5704
|
const match = normalized.match(/(?:^|\/)(?:node-)?v?(\d+)\.\d+\.\d+(?:\/|$)/);
|
|
5651
5705
|
if (!match) {
|
|
5652
5706
|
return null;
|
|
@@ -5658,8 +5712,8 @@ function normalizeExecutablePath(candidate) {
|
|
|
5658
5712
|
if (!candidate) {
|
|
5659
5713
|
return "";
|
|
5660
5714
|
}
|
|
5661
|
-
const normalized =
|
|
5662
|
-
if (!
|
|
5715
|
+
const normalized = resolve22(candidate);
|
|
5716
|
+
if (!existsSync19(normalized)) {
|
|
5663
5717
|
return "";
|
|
5664
5718
|
}
|
|
5665
5719
|
try {
|
|
@@ -5669,7 +5723,7 @@ function normalizeExecutablePath(candidate) {
|
|
|
5669
5723
|
}
|
|
5670
5724
|
}
|
|
5671
5725
|
function looksLikeRuntimeGateway(candidate) {
|
|
5672
|
-
const normalized =
|
|
5726
|
+
const normalized = resolve22(candidate).replace(/\\/g, "/");
|
|
5673
5727
|
return normalized.includes("/.rig/bin/") || normalized.endsWith("/rig-shell") || normalized.endsWith("/rig-agent");
|
|
5674
5728
|
}
|
|
5675
5729
|
|
|
@@ -5690,7 +5744,7 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
5690
5744
|
try {
|
|
5691
5745
|
return resolveClaudeInstallDir();
|
|
5692
5746
|
} catch {
|
|
5693
|
-
return
|
|
5747
|
+
return resolve23(claudeBinary, "..");
|
|
5694
5748
|
}
|
|
5695
5749
|
})() : "";
|
|
5696
5750
|
const nodeDir = resolveNodeInstallDir();
|
|
@@ -5700,8 +5754,8 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
5700
5754
|
`${bunDir}/bin`,
|
|
5701
5755
|
claudeDir,
|
|
5702
5756
|
nodeDir ? `${nodeDir}/bin` : "",
|
|
5703
|
-
realHome ?
|
|
5704
|
-
realHome ?
|
|
5757
|
+
realHome ? resolve23(realHome, ".local/bin") : "",
|
|
5758
|
+
realHome ? resolve23(realHome, ".cargo/bin") : "",
|
|
5705
5759
|
...inheritedPath,
|
|
5706
5760
|
"/usr/local/bin",
|
|
5707
5761
|
"/usr/local/sbin",
|
|
@@ -5732,9 +5786,9 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
5732
5786
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
5733
5787
|
function resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext) {
|
|
5734
5788
|
if (runtimeContext) {
|
|
5735
|
-
return
|
|
5789
|
+
return resolve24(runtimeContext.binDir, "validators", binaryName);
|
|
5736
5790
|
}
|
|
5737
|
-
return
|
|
5791
|
+
return resolve24(resolveHarnessPaths(projectRoot).binDir, "validators", binaryName);
|
|
5738
5792
|
}
|
|
5739
5793
|
async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
5740
5794
|
const match = checkId.match(/^([a-z][\w-]*):([a-z][\w-]*)$/);
|
|
@@ -5749,19 +5803,19 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
5749
5803
|
const binaryName = `${category}-${check}`;
|
|
5750
5804
|
const binaryPath = resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
5751
5805
|
const hostProjectRoot = runtimeContext?.hostProjectRoot?.trim() || projectRoot;
|
|
5752
|
-
const sourcePath =
|
|
5753
|
-
if (!
|
|
5806
|
+
const sourcePath = resolve24(hostProjectRoot, "packages/runtime/src/control-plane/validators", category, `${check}.ts`);
|
|
5807
|
+
if (!existsSync20(sourcePath)) {
|
|
5754
5808
|
return null;
|
|
5755
5809
|
}
|
|
5756
5810
|
const sourceMtime = statSync5(sourcePath).mtimeMs;
|
|
5757
|
-
const binaryExists =
|
|
5811
|
+
const binaryExists = existsSync20(binaryPath);
|
|
5758
5812
|
const binaryMtime = binaryExists ? statSync5(binaryPath).mtimeMs : 0;
|
|
5759
5813
|
if (!binaryExists || sourceMtime > binaryMtime) {
|
|
5760
5814
|
if (binaryExists) {
|
|
5761
|
-
|
|
5762
|
-
|
|
5815
|
+
rmSync6(binaryPath, { force: true });
|
|
5816
|
+
rmSync6(`${binaryPath}.build-manifest.json`, { force: true });
|
|
5763
5817
|
}
|
|
5764
|
-
|
|
5818
|
+
mkdirSync8(dirname13(binaryPath), { recursive: true });
|
|
5765
5819
|
await buildRuntimeBinary({
|
|
5766
5820
|
sourcePath: `packages/runtime/src/control-plane/validators/${category}/${check}.ts`,
|
|
5767
5821
|
outputPath: binaryPath,
|
|
@@ -5770,7 +5824,7 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
5770
5824
|
env: runtimeProvisioningEnv()
|
|
5771
5825
|
});
|
|
5772
5826
|
}
|
|
5773
|
-
return
|
|
5827
|
+
return existsSync20(binaryPath) ? binaryPath : null;
|
|
5774
5828
|
}
|
|
5775
5829
|
|
|
5776
5830
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
@@ -5807,20 +5861,20 @@ async function readTaskSourceValidation(projectRoot, taskId) {
|
|
|
5807
5861
|
function resolveValidationPaths(projectRoot, taskId, runtimeContext) {
|
|
5808
5862
|
if (runtimeContext) {
|
|
5809
5863
|
return {
|
|
5810
|
-
taskLogDir:
|
|
5811
|
-
artifactDir:
|
|
5864
|
+
taskLogDir: resolve25(runtimeContext.logsDir, taskId),
|
|
5865
|
+
artifactDir: resolve25(runtimeContext.workspaceDir, "artifacts", taskId)
|
|
5812
5866
|
};
|
|
5813
5867
|
}
|
|
5814
5868
|
const paths = resolveHarnessPaths(projectRoot);
|
|
5815
5869
|
return {
|
|
5816
|
-
taskLogDir:
|
|
5817
|
-
artifactDir:
|
|
5870
|
+
taskLogDir: resolve25(paths.logsDir, taskId),
|
|
5871
|
+
artifactDir: resolve25(paths.artifactsDir, taskId)
|
|
5818
5872
|
};
|
|
5819
5873
|
}
|
|
5820
5874
|
async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext) {
|
|
5821
5875
|
const binaryName = checkId.replace(":", "-");
|
|
5822
5876
|
const binaryPath = await ensureValidatorBinary(projectRoot, checkId, runtimeContext) ?? resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
5823
|
-
if (!
|
|
5877
|
+
if (!existsSync21(binaryPath)) {
|
|
5824
5878
|
return {
|
|
5825
5879
|
result: {
|
|
5826
5880
|
id: checkId,
|
|
@@ -5831,7 +5885,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
5831
5885
|
};
|
|
5832
5886
|
}
|
|
5833
5887
|
const validatorCwd = runtimeContext?.workspaceDir || resolveMonorepoRoot(projectRoot);
|
|
5834
|
-
const runtimeShellPath = runtimeContext ?
|
|
5888
|
+
const runtimeShellPath = runtimeContext ? resolve25(runtimeContext.binDir, "rig-shell") : "";
|
|
5835
5889
|
const monorepoMainRoot = runtimeContext?.monorepoMainRoot || process.env.MONOREPO_MAIN_ROOT?.trim() || resolveMonorepoRoot(projectRoot);
|
|
5836
5890
|
const validatorEnv = {
|
|
5837
5891
|
PROJECT_RIG_ROOT: runtimeContext?.hostProjectRoot || projectRoot,
|
|
@@ -5846,7 +5900,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
5846
5900
|
validatorEnv.RIG_LOGS_DIR = runtimeContext.logsDir;
|
|
5847
5901
|
validatorEnv.RIG_RUNTIME_BIN_DIR = runtimeContext.binDir;
|
|
5848
5902
|
}
|
|
5849
|
-
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath &&
|
|
5903
|
+
const { exitCode, stdout, stderr } = await runCaptureAsync(runtimeShellPath && existsSync21(runtimeShellPath) ? [runtimeShellPath, "run-binary", binaryPath] : [binaryPath], validatorCwd, validatorEnv);
|
|
5850
5904
|
try {
|
|
5851
5905
|
const result = JSON.parse(stdout.trim());
|
|
5852
5906
|
return { result, exitCode };
|
|
@@ -5886,8 +5940,8 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
5886
5940
|
const configuredValidation = stringArray(taskConfig[taskId]?.validation);
|
|
5887
5941
|
const commands = resolvedContext?.validation?.length ? resolvedContext.validation : configuredValidation.length > 0 ? configuredValidation : sourceValidation.validation;
|
|
5888
5942
|
const { taskLogDir, artifactDir } = resolveValidationPaths(projectRoot, taskId, resolvedContext);
|
|
5889
|
-
|
|
5890
|
-
|
|
5943
|
+
mkdirSync9(taskLogDir, { recursive: true });
|
|
5944
|
+
mkdirSync9(artifactDir, { recursive: true });
|
|
5891
5945
|
if (commands.length === 0) {
|
|
5892
5946
|
const skipped = {
|
|
5893
5947
|
status: "skipped",
|
|
@@ -5896,7 +5950,7 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
5896
5950
|
failed: 0,
|
|
5897
5951
|
categories: []
|
|
5898
5952
|
};
|
|
5899
|
-
|
|
5953
|
+
writeFileSync9(resolve25(artifactDir, "validation-summary.json"), `${JSON.stringify(skipped, null, 2)}
|
|
5900
5954
|
`, "utf-8");
|
|
5901
5955
|
return skipped;
|
|
5902
5956
|
}
|
|
@@ -5931,18 +5985,18 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
5931
5985
|
exit_code: 2,
|
|
5932
5986
|
duration_seconds: 0
|
|
5933
5987
|
});
|
|
5934
|
-
const logFile2 =
|
|
5935
|
-
|
|
5936
|
-
|
|
5988
|
+
const logFile2 = resolve25(taskLogDir, `invalid-entry-validation.log`);
|
|
5989
|
+
mkdirSync9(taskLogDir, { recursive: true });
|
|
5990
|
+
writeFileSync9(logFile2, `=== ${nowIso()} :: ${cmd} ===
|
|
5937
5991
|
Invalid validation entry: not a check-ID. All entries must use format "category:check-name".
|
|
5938
5992
|
`, "utf-8");
|
|
5939
5993
|
continue;
|
|
5940
5994
|
}
|
|
5941
5995
|
const { result, exitCode } = await dispatchValidator(cmd, effectiveRegistry, validatorCtx, (id) => runValidatorBinary(projectRoot, taskId, id, resolvedContext));
|
|
5942
5996
|
const durationSeconds = Math.max(0, Math.round((Date.now() - startedAt) / 1000));
|
|
5943
|
-
const logFile =
|
|
5944
|
-
|
|
5945
|
-
|
|
5997
|
+
const logFile = resolve25(taskLogDir, `${cmd.replace(":", "-")}-validation.log`);
|
|
5998
|
+
mkdirSync9(taskLogDir, { recursive: true });
|
|
5999
|
+
writeFileSync9(logFile, `=== ${nowIso()} :: ${cmd} ===
|
|
5946
6000
|
${JSON.stringify(result, null, 2)}
|
|
5947
6001
|
`, "utf-8");
|
|
5948
6002
|
if (result.passed) {
|
|
@@ -5964,8 +6018,8 @@ ${JSON.stringify(result, null, 2)}
|
|
|
5964
6018
|
failed,
|
|
5965
6019
|
categories
|
|
5966
6020
|
};
|
|
5967
|
-
|
|
5968
|
-
|
|
6021
|
+
mkdirSync9(artifactDir, { recursive: true });
|
|
6022
|
+
writeFileSync9(resolve25(artifactDir, "validation-summary.json"), `${JSON.stringify(summary, null, 2)}
|
|
5969
6023
|
`, "utf-8");
|
|
5970
6024
|
return summary;
|
|
5971
6025
|
}
|
|
@@ -6312,16 +6366,16 @@ async function taskDeps(projectRoot, taskId) {
|
|
|
6312
6366
|
for (const dep of deps) {
|
|
6313
6367
|
const artifactDir = artifactDirForId(projectRoot, dep);
|
|
6314
6368
|
console.log(`=== ${dep} ===`);
|
|
6315
|
-
if (!
|
|
6369
|
+
if (!existsSync22(artifactDir)) {
|
|
6316
6370
|
console.log(` (no artifacts yet)
|
|
6317
6371
|
`);
|
|
6318
6372
|
continue;
|
|
6319
6373
|
}
|
|
6320
|
-
printArtifactSection(
|
|
6321
|
-
printArtifactSection(
|
|
6322
|
-
const changedFiles =
|
|
6323
|
-
if (
|
|
6324
|
-
const lines =
|
|
6374
|
+
printArtifactSection(resolve26(artifactDir, "decision-log.md"), "--- Decisions ---");
|
|
6375
|
+
printArtifactSection(resolve26(artifactDir, "next-actions.md"), "--- Next Actions (for you) ---");
|
|
6376
|
+
const changedFiles = resolve26(artifactDir, "changed-files.txt");
|
|
6377
|
+
if (existsSync22(changedFiles)) {
|
|
6378
|
+
const lines = readFileSync13(changedFiles, "utf-8").split(/\r?\n/).filter(Boolean);
|
|
6325
6379
|
console.log(`--- Changed Files (${lines.length}) ---`);
|
|
6326
6380
|
for (const line of lines) {
|
|
6327
6381
|
console.log(line);
|
|
@@ -6366,12 +6420,12 @@ function taskRecord(projectRoot, type, text, taskId) {
|
|
|
6366
6420
|
throw new Error("No active task.");
|
|
6367
6421
|
}
|
|
6368
6422
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6369
|
-
|
|
6423
|
+
mkdirSync10(paths.stateDir, { recursive: true });
|
|
6370
6424
|
if (type === "decision") {
|
|
6371
|
-
const artifactDir =
|
|
6372
|
-
|
|
6425
|
+
const artifactDir = resolve26(paths.artifactsDir, activeTask);
|
|
6426
|
+
mkdirSync10(artifactDir, { recursive: true });
|
|
6373
6427
|
const timestamp = nowIso();
|
|
6374
|
-
appendFileSync(
|
|
6428
|
+
appendFileSync(resolve26(artifactDir, "decision-log.md"), `
|
|
6375
6429
|
### ${timestamp}
|
|
6376
6430
|
|
|
6377
6431
|
${text}
|
|
@@ -6381,14 +6435,14 @@ ${text}
|
|
|
6381
6435
|
return;
|
|
6382
6436
|
}
|
|
6383
6437
|
const failedPath = paths.failedApproachesPath;
|
|
6384
|
-
if (!
|
|
6385
|
-
|
|
6438
|
+
if (!existsSync22(failedPath)) {
|
|
6439
|
+
writeFileSync10(failedPath, `# Failed Approaches Log
|
|
6386
6440
|
|
|
6387
6441
|
This file records approaches that did not work.
|
|
6388
6442
|
|
|
6389
6443
|
`, "utf-8");
|
|
6390
6444
|
}
|
|
6391
|
-
const content =
|
|
6445
|
+
const content = readFileSync13(failedPath, "utf-8");
|
|
6392
6446
|
const attempts = (content.match(new RegExp(`^## ${escapeRegExp(activeTask)}\\b`, "gm")) || []).length + 1;
|
|
6393
6447
|
appendFileSync(failedPath, `
|
|
6394
6448
|
## ${activeTask} - Attempt ${attempts} (${nowIso()})
|
|
@@ -6405,40 +6459,40 @@ function taskArtifacts(projectRoot, taskId) {
|
|
|
6405
6459
|
throw new Error("No active task.");
|
|
6406
6460
|
}
|
|
6407
6461
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6408
|
-
const artifactDir =
|
|
6409
|
-
|
|
6462
|
+
const artifactDir = resolve26(paths.artifactsDir, activeTask);
|
|
6463
|
+
mkdirSync10(artifactDir, { recursive: true });
|
|
6410
6464
|
const changed = changedFilesForTask(projectRoot, activeTask, true);
|
|
6411
|
-
|
|
6465
|
+
writeFileSync10(resolve26(artifactDir, "changed-files.txt"), `${changed.join(`
|
|
6412
6466
|
`)}
|
|
6413
6467
|
`, "utf-8");
|
|
6414
6468
|
console.log(`changed-files.txt: ${changed.length} files`);
|
|
6415
|
-
const taskResultPath =
|
|
6416
|
-
if (!
|
|
6469
|
+
const taskResultPath = resolve26(artifactDir, "task-result.json");
|
|
6470
|
+
if (!existsSync22(taskResultPath)) {
|
|
6417
6471
|
const template = {
|
|
6418
6472
|
task_id: activeTask,
|
|
6419
6473
|
status: "completed",
|
|
6420
6474
|
summary: "TODO: Write a one-line summary of what you did",
|
|
6421
6475
|
completed_at: nowIso()
|
|
6422
6476
|
};
|
|
6423
|
-
|
|
6477
|
+
writeFileSync10(taskResultPath, `${JSON.stringify(template, null, 2)}
|
|
6424
6478
|
`, "utf-8");
|
|
6425
6479
|
console.log("task-result.json: created (update the summary!)");
|
|
6426
6480
|
} else {
|
|
6427
6481
|
console.log("task-result.json: already exists");
|
|
6428
6482
|
}
|
|
6429
|
-
const decisionLogPath =
|
|
6430
|
-
if (!
|
|
6483
|
+
const decisionLogPath = resolve26(artifactDir, "decision-log.md");
|
|
6484
|
+
if (!existsSync22(decisionLogPath)) {
|
|
6431
6485
|
const content = `# Decision Log: ${activeTask}
|
|
6432
6486
|
|
|
6433
6487
|
Record key decisions here using: rig-agent record decision "..."
|
|
6434
6488
|
`;
|
|
6435
|
-
|
|
6489
|
+
writeFileSync10(decisionLogPath, content, "utf-8");
|
|
6436
6490
|
console.log("decision-log.md: created (record your decisions!)");
|
|
6437
6491
|
} else {
|
|
6438
6492
|
console.log("decision-log.md: already exists");
|
|
6439
6493
|
}
|
|
6440
|
-
const nextActionsPath =
|
|
6441
|
-
if (!
|
|
6494
|
+
const nextActionsPath = resolve26(artifactDir, "next-actions.md");
|
|
6495
|
+
if (!existsSync22(nextActionsPath)) {
|
|
6442
6496
|
const content = [
|
|
6443
6497
|
`# Next Actions: ${activeTask}`,
|
|
6444
6498
|
"",
|
|
@@ -6455,13 +6509,13 @@ Record key decisions here using: rig-agent record decision "..."
|
|
|
6455
6509
|
""
|
|
6456
6510
|
].join(`
|
|
6457
6511
|
`);
|
|
6458
|
-
|
|
6512
|
+
writeFileSync10(nextActionsPath, content, "utf-8");
|
|
6459
6513
|
console.log("next-actions.md: created (add recommendations for downstream tasks!)");
|
|
6460
6514
|
} else {
|
|
6461
6515
|
console.log("next-actions.md: already exists");
|
|
6462
6516
|
}
|
|
6463
|
-
const validationSummaryPath =
|
|
6464
|
-
if (
|
|
6517
|
+
const validationSummaryPath = resolve26(artifactDir, "validation-summary.json");
|
|
6518
|
+
if (existsSync22(validationSummaryPath)) {
|
|
6465
6519
|
console.log("validation-summary.json: already exists");
|
|
6466
6520
|
} else {
|
|
6467
6521
|
console.log("validation-summary.json: not yet created (run: rig-agent validate)");
|
|
@@ -6475,8 +6529,8 @@ function taskArtifactDir(projectRoot, taskId) {
|
|
|
6475
6529
|
throw new Error("No active task.");
|
|
6476
6530
|
}
|
|
6477
6531
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6478
|
-
const artifactDir =
|
|
6479
|
-
|
|
6532
|
+
const artifactDir = resolve26(paths.artifactsDir, activeTask);
|
|
6533
|
+
mkdirSync10(artifactDir, { recursive: true });
|
|
6480
6534
|
return artifactDir;
|
|
6481
6535
|
}
|
|
6482
6536
|
function taskArtifactWrite(projectRoot, filename, content, taskId) {
|
|
@@ -6485,10 +6539,10 @@ function taskArtifactWrite(projectRoot, filename, content, taskId) {
|
|
|
6485
6539
|
throw new Error("No active task.");
|
|
6486
6540
|
}
|
|
6487
6541
|
const paths = resolveHarnessPaths(projectRoot);
|
|
6488
|
-
const artifactDir =
|
|
6489
|
-
|
|
6490
|
-
const targetPath =
|
|
6491
|
-
|
|
6542
|
+
const artifactDir = resolve26(paths.artifactsDir, activeTask);
|
|
6543
|
+
mkdirSync10(artifactDir, { recursive: true });
|
|
6544
|
+
const targetPath = resolve26(artifactDir, filename);
|
|
6545
|
+
writeFileSync10(targetPath, content, "utf-8");
|
|
6492
6546
|
console.log(`Wrote: ${targetPath}`);
|
|
6493
6547
|
}
|
|
6494
6548
|
async function taskValidate(projectRoot, taskId, validatorRegistry) {
|
|
@@ -6549,7 +6603,7 @@ function collectTaskChangedFiles(projectRoot, taskId, includeCommitted) {
|
|
|
6549
6603
|
[projectRoot, ""],
|
|
6550
6604
|
[monorepoRepoRoot, ""]
|
|
6551
6605
|
]) {
|
|
6552
|
-
if (!
|
|
6606
|
+
if (!existsSync22(resolve26(repo, ".git"))) {
|
|
6553
6607
|
continue;
|
|
6554
6608
|
}
|
|
6555
6609
|
if (includeCommitted && repo === monorepoRepoRoot) {
|
|
@@ -6587,8 +6641,8 @@ function filterTaskChangedFiles(projectRoot, taskId, files, scoped) {
|
|
|
6587
6641
|
}
|
|
6588
6642
|
function resolveTaskMonorepoRoot(projectRoot) {
|
|
6589
6643
|
const runtimeWorkspace = loadRuntimeContextFromEnv()?.workspaceDir || process.env.RIG_TASK_WORKSPACE?.trim();
|
|
6590
|
-
if (runtimeWorkspace &&
|
|
6591
|
-
return
|
|
6644
|
+
if (runtimeWorkspace && existsSync22(resolve26(runtimeWorkspace, ".git"))) {
|
|
6645
|
+
return resolve26(runtimeWorkspace);
|
|
6592
6646
|
}
|
|
6593
6647
|
return resolveHarnessPaths(projectRoot).monorepoRoot;
|
|
6594
6648
|
}
|
|
@@ -6616,7 +6670,7 @@ function resolveRuntimeInitialHeadCommit(projectRoot, repo) {
|
|
|
6616
6670
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
6617
6671
|
if (runtimeContext?.initialHeadCommits?.monorepo?.trim()) {
|
|
6618
6672
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6619
|
-
if (
|
|
6673
|
+
if (resolve26(monorepoRoot) === resolve26(repo)) {
|
|
6620
6674
|
return runtimeContext.initialHeadCommits.monorepo.trim();
|
|
6621
6675
|
}
|
|
6622
6676
|
}
|
|
@@ -6626,7 +6680,7 @@ function resolveMonorepoBaseCommit(projectRoot, repo) {
|
|
|
6626
6680
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
6627
6681
|
if (runtimeContext?.monorepoBaseCommit?.trim()) {
|
|
6628
6682
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6629
|
-
if (
|
|
6683
|
+
if (resolve26(monorepoRoot) === resolve26(repo)) {
|
|
6630
6684
|
return runtimeContext.monorepoBaseCommit.trim();
|
|
6631
6685
|
}
|
|
6632
6686
|
}
|
|
@@ -6660,7 +6714,7 @@ function resolveRuntimeDirtyBaseline(projectRoot, repo) {
|
|
|
6660
6714
|
return new Set;
|
|
6661
6715
|
}
|
|
6662
6716
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
6663
|
-
const selected =
|
|
6717
|
+
const selected = resolve26(repo) === resolve26(monorepoRoot) ? dirtyFiles.monorepo : resolve26(repo) === resolve26(projectRoot) ? dirtyFiles.project : undefined;
|
|
6664
6718
|
return new Set((selected || []).map((file) => normalizeChangedFilePath(file)).filter(Boolean));
|
|
6665
6719
|
}
|
|
6666
6720
|
function normalizeChangedFilePath(file) {
|
|
@@ -6760,12 +6814,12 @@ function printIndented(text) {
|
|
|
6760
6814
|
}
|
|
6761
6815
|
}
|
|
6762
6816
|
function readLocalBeadsTasks(projectRoot) {
|
|
6763
|
-
const issuesPath =
|
|
6764
|
-
if (!
|
|
6817
|
+
const issuesPath = resolve26(resolveMonorepoRoot2(projectRoot), ".beads/issues.jsonl");
|
|
6818
|
+
if (!existsSync22(issuesPath)) {
|
|
6765
6819
|
return [];
|
|
6766
6820
|
}
|
|
6767
6821
|
const tasks = [];
|
|
6768
|
-
for (const line of
|
|
6822
|
+
for (const line of readFileSync13(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
6769
6823
|
const trimmed = line.trim();
|
|
6770
6824
|
if (!trimmed) {
|
|
6771
6825
|
continue;
|
|
@@ -6878,11 +6932,11 @@ function taskDependencies(projectRoot, taskId, tracker) {
|
|
|
6878
6932
|
return [...ids].sort();
|
|
6879
6933
|
}
|
|
6880
6934
|
function printArtifactSection(path, header) {
|
|
6881
|
-
if (!
|
|
6935
|
+
if (!existsSync22(path)) {
|
|
6882
6936
|
return;
|
|
6883
6937
|
}
|
|
6884
6938
|
console.log(header);
|
|
6885
|
-
process.stdout.write(
|
|
6939
|
+
process.stdout.write(readFileSync13(path, "utf-8"));
|
|
6886
6940
|
console.log("");
|
|
6887
6941
|
}
|
|
6888
6942
|
function escapeRegExp(value) {
|
|
@@ -6922,8 +6976,8 @@ function isRuntimeGatewayGhPath(candidate) {
|
|
|
6922
6976
|
}
|
|
6923
6977
|
function resolveOptionalMonorepoRoot(projectRoot) {
|
|
6924
6978
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
6925
|
-
if (runtimeWorkspace &&
|
|
6926
|
-
return
|
|
6979
|
+
if (runtimeWorkspace && existsSync23(resolve27(runtimeWorkspace, ".git"))) {
|
|
6980
|
+
return resolve27(runtimeWorkspace);
|
|
6927
6981
|
}
|
|
6928
6982
|
try {
|
|
6929
6983
|
return resolveMonorepoRoot2(projectRoot);
|
|
@@ -6948,7 +7002,7 @@ function resolveGitBinary(projectRoot) {
|
|
|
6948
7002
|
if (!candidate || isRuntimeGatewayGitPath(candidate)) {
|
|
6949
7003
|
continue;
|
|
6950
7004
|
}
|
|
6951
|
-
if (
|
|
7005
|
+
if (existsSync23(candidate)) {
|
|
6952
7006
|
return candidate;
|
|
6953
7007
|
}
|
|
6954
7008
|
}
|
|
@@ -7008,11 +7062,11 @@ function gitPreflight(projectRoot, taskId, strict) {
|
|
|
7008
7062
|
const expected = resolvedTask ? `rig/${resolveTaskBranchId(projectRoot, resolvedTask)}` : "";
|
|
7009
7063
|
console.log("=== Git Flow Preflight ===");
|
|
7010
7064
|
let issues = 0;
|
|
7011
|
-
if (!
|
|
7065
|
+
if (!existsSync23(resolve27(projectRoot, ".git"))) {
|
|
7012
7066
|
console.log(`ERROR: project root is not a git repo (${projectRoot})`);
|
|
7013
7067
|
issues += 1;
|
|
7014
7068
|
}
|
|
7015
|
-
if (monorepoRoot &&
|
|
7069
|
+
if (monorepoRoot && existsSync23(resolve27(monorepoRoot, ".git"))) {
|
|
7016
7070
|
const monoBranch = branchName(projectRoot, monorepoRoot);
|
|
7017
7071
|
if (expected && monoBranch !== expected) {
|
|
7018
7072
|
console.log(`WARN: monorepo branch is ${monoBranch}, expected ${expected} for task ${resolvedTask}`);
|
|
@@ -7046,7 +7100,7 @@ function gitSyncBranch(projectRoot, taskId, targetRepo = "monorepo") {
|
|
|
7046
7100
|
}
|
|
7047
7101
|
const repoRoot = targetRepo === "monorepo" ? resolveOptionalMonorepoRoot(projectRoot) || resolveMonorepoRoot2(projectRoot) : projectRoot;
|
|
7048
7102
|
const repoLabel = targetRepo === "monorepo" ? "Monorepo" : "Project";
|
|
7049
|
-
if (!
|
|
7103
|
+
if (!existsSync23(resolve27(repoRoot, ".git"))) {
|
|
7050
7104
|
throw new Error(`${repoLabel} repo not found at ${repoRoot}`);
|
|
7051
7105
|
}
|
|
7052
7106
|
const branchId = resolveTaskBranchId(projectRoot, resolvedTask);
|
|
@@ -7090,8 +7144,8 @@ function gitCommit(options) {
|
|
|
7090
7144
|
function gitSnapshot(projectRoot, taskId, outputPath) {
|
|
7091
7145
|
const monorepoRoot = resolveOptionalMonorepoRoot(projectRoot);
|
|
7092
7146
|
const resolvedTask = taskId || safeCurrentTaskId(projectRoot);
|
|
7093
|
-
const output = outputPath || (resolvedTask ? resolveArtifactSnapshot(projectRoot, resolvedTask) :
|
|
7094
|
-
|
|
7147
|
+
const output = outputPath || (resolvedTask ? resolveArtifactSnapshot(projectRoot, resolvedTask) : resolve27(resolve27(projectRoot, ".rig", "state"), "git-state.txt"));
|
|
7148
|
+
mkdirSync11(dirname14(output), { recursive: true });
|
|
7095
7149
|
const lines = ["# Git Snapshot", `timestamp: ${nowIso()}`];
|
|
7096
7150
|
if (resolvedTask) {
|
|
7097
7151
|
lines.push(`task: ${resolvedTask}`);
|
|
@@ -7101,7 +7155,7 @@ function gitSnapshot(projectRoot, taskId, outputPath) {
|
|
|
7101
7155
|
if (monorepoRoot && monorepoRoot !== projectRoot) {
|
|
7102
7156
|
lines.push(...snapshotRepo(projectRoot, "monorepo", monorepoRoot));
|
|
7103
7157
|
}
|
|
7104
|
-
|
|
7158
|
+
writeFileSync11(output, `${lines.join(`
|
|
7105
7159
|
`)}
|
|
7106
7160
|
`, "utf-8");
|
|
7107
7161
|
return output;
|
|
@@ -7125,7 +7179,7 @@ function gitOpenPr(options) {
|
|
|
7125
7179
|
} else if (taskId) {
|
|
7126
7180
|
gitSyncBranch(options.projectRoot, taskId, "project");
|
|
7127
7181
|
}
|
|
7128
|
-
if (!
|
|
7182
|
+
if (!existsSync23(resolve27(repoRoot, ".git"))) {
|
|
7129
7183
|
throw new Error(`Repository not available for open-pr target ${target}: ${repoRoot}`);
|
|
7130
7184
|
}
|
|
7131
7185
|
const branch = branchName(options.projectRoot, repoRoot);
|
|
@@ -7338,12 +7392,12 @@ function assertPrHasNoGitConflicts(prState, repoLabel, baseRef) {
|
|
|
7338
7392
|
}
|
|
7339
7393
|
function writePrMetadata(projectRoot, taskId, result) {
|
|
7340
7394
|
const dir = artifactDirForId(projectRoot, taskId);
|
|
7341
|
-
|
|
7342
|
-
const path =
|
|
7395
|
+
mkdirSync11(dir, { recursive: true });
|
|
7396
|
+
const path = resolve27(dir, "pr-state.json");
|
|
7343
7397
|
let prs = {};
|
|
7344
|
-
if (
|
|
7398
|
+
if (existsSync23(path)) {
|
|
7345
7399
|
try {
|
|
7346
|
-
const parsed = JSON.parse(
|
|
7400
|
+
const parsed = JSON.parse(readFileSync14(path, "utf-8"));
|
|
7347
7401
|
if (parsed && typeof parsed === "object" && parsed.prs && typeof parsed.prs === "object") {
|
|
7348
7402
|
prs = parsed.prs;
|
|
7349
7403
|
}
|
|
@@ -7359,12 +7413,12 @@ function writePrMetadata(projectRoot, taskId, result) {
|
|
|
7359
7413
|
...primary || {},
|
|
7360
7414
|
updated_at: nowIso()
|
|
7361
7415
|
};
|
|
7362
|
-
|
|
7416
|
+
writeFileSync11(path, `${JSON.stringify(artifact, null, 2)}
|
|
7363
7417
|
`, "utf-8");
|
|
7364
7418
|
}
|
|
7365
7419
|
function resolveArtifactSnapshot(projectRoot, taskId) {
|
|
7366
|
-
const artifactDir =
|
|
7367
|
-
return
|
|
7420
|
+
const artifactDir = resolve27(resolveHarnessPaths(projectRoot).artifactsDir, taskId);
|
|
7421
|
+
return resolve27(artifactDir, "git-state.txt");
|
|
7368
7422
|
}
|
|
7369
7423
|
function ensureFullGitHistory(projectRoot, repoRoot, remoteName = "origin") {
|
|
7370
7424
|
const shallow = runCapture2(gitCmd(projectRoot, repoRoot, "rev-parse", "--is-shallow-repository"), projectRoot);
|
|
@@ -7416,14 +7470,14 @@ function resolveGithubCliBinary(projectRoot) {
|
|
|
7416
7470
|
}
|
|
7417
7471
|
const explicitPathEntries = (process.env.PATH || "").split(":").map((entry) => entry.trim()).filter(Boolean);
|
|
7418
7472
|
for (const entry of explicitPathEntries) {
|
|
7419
|
-
candidates.add(
|
|
7473
|
+
candidates.add(resolve27(entry, "gh"));
|
|
7420
7474
|
}
|
|
7421
7475
|
const bunResolved = Bun.which("gh");
|
|
7422
7476
|
if (bunResolved) {
|
|
7423
7477
|
candidates.add(bunResolved);
|
|
7424
7478
|
}
|
|
7425
7479
|
for (const candidate of candidates) {
|
|
7426
|
-
if (candidate &&
|
|
7480
|
+
if (candidate && existsSync23(candidate) && !isRuntimeGatewayGhPath(candidate)) {
|
|
7427
7481
|
return candidate;
|
|
7428
7482
|
}
|
|
7429
7483
|
}
|
|
@@ -7453,7 +7507,7 @@ function resolveRepoNameWithOwner(projectRoot, repoRoot) {
|
|
|
7453
7507
|
return resolveGithubRepoNameWithOwnerFromGitRoot(projectRoot, repoRoot, repoRoot, visited);
|
|
7454
7508
|
}
|
|
7455
7509
|
function resolveGithubRepoNameWithOwnerFromGitRoot(projectRoot, gitRoot, cwd, visited) {
|
|
7456
|
-
const normalizedGitRoot =
|
|
7510
|
+
const normalizedGitRoot = resolve27(gitRoot);
|
|
7457
7511
|
if (visited.has(normalizedGitRoot)) {
|
|
7458
7512
|
return "";
|
|
7459
7513
|
}
|
|
@@ -7525,7 +7579,7 @@ function resolveNetworkRemoteName(projectRoot, repoRoot, repoNameWithOwner) {
|
|
|
7525
7579
|
return remotes.includes("origin") ? "origin" : remotes[0];
|
|
7526
7580
|
}
|
|
7527
7581
|
function gitQuery(projectRoot, gitRoot, cwd, ...args) {
|
|
7528
|
-
const gitArgs =
|
|
7582
|
+
const gitArgs = existsSync23(resolve27(gitRoot, ".git")) ? gitCmd(projectRoot, gitRoot, ...args) : [resolveGitBinary(projectRoot), "--git-dir", gitRoot, ...args];
|
|
7529
7583
|
return runCapture2(gitArgs, cwd, projectRoot);
|
|
7530
7584
|
}
|
|
7531
7585
|
function resolveLocalGitRemoteRoot(remoteUrl, gitRoot) {
|
|
@@ -7543,9 +7597,9 @@ function resolveLocalGitRemoteRoot(remoteUrl, gitRoot) {
|
|
|
7543
7597
|
} else if (/^[a-z][a-z0-9+.-]*:\/\//i.test(normalized) || /^[^@]+@[^:]+:.+$/.test(normalized)) {
|
|
7544
7598
|
return "";
|
|
7545
7599
|
} else if (!isAbsolute2(normalized)) {
|
|
7546
|
-
candidate =
|
|
7600
|
+
candidate = resolve27(gitRoot, normalized);
|
|
7547
7601
|
}
|
|
7548
|
-
return
|
|
7602
|
+
return existsSync23(candidate) ? candidate : "";
|
|
7549
7603
|
}
|
|
7550
7604
|
function normalizeGithubRepoNameWithOwner(value) {
|
|
7551
7605
|
const normalized = value.trim();
|
|
@@ -7672,7 +7726,7 @@ function inferReviewerFromChangedFiles(projectRoot, repoRoot, baseRef, branchRef
|
|
|
7672
7726
|
return best;
|
|
7673
7727
|
}
|
|
7674
7728
|
function snapshotRepo(projectRoot, label, repo) {
|
|
7675
|
-
if (!
|
|
7729
|
+
if (!existsSync23(resolve27(repo, ".git"))) {
|
|
7676
7730
|
return [`## ${label}`, `repo: ${repo}`, "status: unavailable", ""];
|
|
7677
7731
|
}
|
|
7678
7732
|
const status = runCapture2(gitCmd(projectRoot, repo, "status", "--short"), projectRoot).stdout.trim();
|
|
@@ -7695,7 +7749,7 @@ function snapshotRepo(projectRoot, label, repo) {
|
|
|
7695
7749
|
];
|
|
7696
7750
|
}
|
|
7697
7751
|
function commitRepo(projectRoot, repo, label, message, allowEmpty, scoped, files, changedFilesManifest) {
|
|
7698
|
-
if (!
|
|
7752
|
+
if (!existsSync23(resolve27(repo, ".git"))) {
|
|
7699
7753
|
console.log(`Skipping ${label}: repo not available (${repo})`);
|
|
7700
7754
|
return;
|
|
7701
7755
|
}
|
|
@@ -7727,18 +7781,18 @@ function commitRepo(projectRoot, repo, label, message, allowEmpty, scoped, files
|
|
|
7727
7781
|
console.log(`Committed ${label}: ${message}`);
|
|
7728
7782
|
}
|
|
7729
7783
|
function readChangedFilesManifest(projectRoot, taskId) {
|
|
7730
|
-
const manifestPath =
|
|
7731
|
-
if (!
|
|
7784
|
+
const manifestPath = resolve27(artifactDirForId(projectRoot, taskId), "changed-files.txt");
|
|
7785
|
+
if (!existsSync23(manifestPath)) {
|
|
7732
7786
|
return [];
|
|
7733
7787
|
}
|
|
7734
|
-
const files =
|
|
7788
|
+
const files = readFileSync14(manifestPath, "utf-8").split(/\r?\n/).map((line) => normalizeChangedFilePath2(line)).filter(Boolean);
|
|
7735
7789
|
return [...new Set(files)];
|
|
7736
7790
|
}
|
|
7737
7791
|
function refreshChangedFilesManifest(projectRoot, taskId) {
|
|
7738
|
-
const manifestPath =
|
|
7739
|
-
|
|
7792
|
+
const manifestPath = resolve27(artifactDirForId(projectRoot, taskId), "changed-files.txt");
|
|
7793
|
+
mkdirSync11(dirname14(manifestPath), { recursive: true });
|
|
7740
7794
|
const changedFiles = changedFilesForTask(projectRoot, taskId, true);
|
|
7741
|
-
|
|
7795
|
+
writeFileSync11(manifestPath, `${changedFiles.join(`
|
|
7742
7796
|
`)}
|
|
7743
7797
|
`, "utf-8");
|
|
7744
7798
|
return manifestPath;
|
|
@@ -7851,7 +7905,7 @@ function repoHasPathChange(projectRoot, repoRoot, relativePath) {
|
|
|
7851
7905
|
return result.exitCode === 0 && result.stdout.trim().length > 0;
|
|
7852
7906
|
}
|
|
7853
7907
|
function stageExcludePathspecs(repoRoot) {
|
|
7854
|
-
const patterns =
|
|
7908
|
+
const patterns = existsSync23(resolve27(repoRoot, ".rig", "task-config.json")) ? [...TASK_RUNTIME_STAGE_EXCLUDES, ...GENERATED_STAGE_EXCLUDES] : [".rig/**", ...GENERATED_STAGE_EXCLUDES];
|
|
7855
7909
|
return patterns.map((pattern) => `:(glob,exclude)${pattern}`);
|
|
7856
7910
|
}
|
|
7857
7911
|
function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
@@ -7861,7 +7915,7 @@ function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
|
7861
7915
|
}
|
|
7862
7916
|
let current = repoRoot;
|
|
7863
7917
|
for (let index = 0;index < parts.length - 1; index += 1) {
|
|
7864
|
-
current =
|
|
7918
|
+
current = resolve27(current, parts[index]);
|
|
7865
7919
|
try {
|
|
7866
7920
|
if (lstatSync(current).isSymbolicLink()) {
|
|
7867
7921
|
return true;
|
|
@@ -7873,7 +7927,7 @@ function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
|
7873
7927
|
return false;
|
|
7874
7928
|
}
|
|
7875
7929
|
function printRepoStatus(projectRoot, label, repo, expectedBranch) {
|
|
7876
|
-
if (!
|
|
7930
|
+
if (!existsSync23(resolve27(repo, ".git"))) {
|
|
7877
7931
|
console.log(`${label}: unavailable (${repo})`);
|
|
7878
7932
|
return;
|
|
7879
7933
|
}
|
|
@@ -7909,7 +7963,7 @@ function resolveTaskBranchId(projectRoot, taskId) {
|
|
|
7909
7963
|
}
|
|
7910
7964
|
} catch {}
|
|
7911
7965
|
const artifactDir = artifactDirForId(projectRoot, taskId);
|
|
7912
|
-
if (
|
|
7966
|
+
if (existsSync23(artifactDir)) {
|
|
7913
7967
|
return taskId;
|
|
7914
7968
|
}
|
|
7915
7969
|
throw new Error(`Unknown task id: ${taskId}`);
|
|
@@ -7945,11 +7999,11 @@ function runCapture2(command, cwd, projectRoot = cwd) {
|
|
|
7945
7999
|
}
|
|
7946
8000
|
function runtimeGitEnv(projectRoot) {
|
|
7947
8001
|
const { ctx, runtimeRoot } = resolveRuntimeMetadata(projectRoot);
|
|
7948
|
-
const runtimeHome = runtimeRoot ?
|
|
7949
|
-
const runtimeTmp = runtimeRoot ?
|
|
7950
|
-
const runtimeCache = runtimeRoot ?
|
|
7951
|
-
const runtimeKnownHosts = runtimeHome ?
|
|
7952
|
-
const runtimeKey = runtimeHome ?
|
|
8002
|
+
const runtimeHome = runtimeRoot ? resolve27(runtimeRoot, "home") : "";
|
|
8003
|
+
const runtimeTmp = runtimeRoot ? resolve27(runtimeRoot, "tmp") : "";
|
|
8004
|
+
const runtimeCache = runtimeRoot ? resolve27(runtimeRoot, "cache") : "";
|
|
8005
|
+
const runtimeKnownHosts = runtimeHome ? resolve27(runtimeHome, ".ssh", "known_hosts") : "";
|
|
8006
|
+
const runtimeKey = runtimeHome ? resolve27(runtimeHome, ".ssh", "rig-agent-key") : "";
|
|
7953
8007
|
const env = {};
|
|
7954
8008
|
if (ctx?.workspaceDir) {
|
|
7955
8009
|
env.PROJECT_RIG_ROOT = projectRoot;
|
|
@@ -7962,14 +8016,14 @@ function runtimeGitEnv(projectRoot) {
|
|
|
7962
8016
|
if (runtimeRoot) {
|
|
7963
8017
|
env.RIG_RUNTIME_HOME = runtimeRoot;
|
|
7964
8018
|
}
|
|
7965
|
-
if (runtimeHome &&
|
|
8019
|
+
if (runtimeHome && existsSync23(runtimeHome)) {
|
|
7966
8020
|
env.HOME = runtimeHome;
|
|
7967
8021
|
env.OPENSSL_CONF = ensureRuntimeOpenSslConfig(runtimeHome);
|
|
7968
8022
|
}
|
|
7969
|
-
if (runtimeTmp &&
|
|
8023
|
+
if (runtimeTmp && existsSync23(runtimeTmp)) {
|
|
7970
8024
|
env.TMPDIR = runtimeTmp;
|
|
7971
8025
|
}
|
|
7972
|
-
if (runtimeCache &&
|
|
8026
|
+
if (runtimeCache && existsSync23(runtimeCache)) {
|
|
7973
8027
|
env.XDG_CACHE_HOME = runtimeCache;
|
|
7974
8028
|
}
|
|
7975
8029
|
const workspaceSecrets = loadDotEnvSecrets(ctx?.workspaceDir || projectRoot, process.env);
|
|
@@ -8013,14 +8067,14 @@ function runtimeGitEnv(projectRoot) {
|
|
|
8013
8067
|
env.GH_TOKEN = env.GH_TOKEN || gitHubToken;
|
|
8014
8068
|
applyGitHubCredentialHelperEnv(env);
|
|
8015
8069
|
}
|
|
8016
|
-
if (runtimeKnownHosts &&
|
|
8070
|
+
if (runtimeKnownHosts && existsSync23(runtimeKnownHosts)) {
|
|
8017
8071
|
const sshParts = [
|
|
8018
8072
|
"ssh",
|
|
8019
8073
|
`-o UserKnownHostsFile="${runtimeKnownHosts}"`,
|
|
8020
8074
|
"-o StrictHostKeyChecking=yes",
|
|
8021
8075
|
"-F /dev/null"
|
|
8022
8076
|
];
|
|
8023
|
-
if (runtimeKey &&
|
|
8077
|
+
if (runtimeKey && existsSync23(runtimeKey)) {
|
|
8024
8078
|
sshParts.splice(1, 0, `-i "${runtimeKey}"`, "-o IdentitiesOnly=yes");
|
|
8025
8079
|
}
|
|
8026
8080
|
env.GIT_SSH_COMMAND = sshParts.join(" ");
|
|
@@ -8041,12 +8095,12 @@ function loadPersistedRuntimeSecrets(runtimeRoot) {
|
|
|
8041
8095
|
if (!runtimeRoot) {
|
|
8042
8096
|
return {};
|
|
8043
8097
|
}
|
|
8044
|
-
const path =
|
|
8045
|
-
if (!
|
|
8098
|
+
const path = resolve27(runtimeRoot, "runtime-secrets.json");
|
|
8099
|
+
if (!existsSync23(path)) {
|
|
8046
8100
|
return {};
|
|
8047
8101
|
}
|
|
8048
8102
|
try {
|
|
8049
|
-
const parsed = JSON.parse(
|
|
8103
|
+
const parsed = JSON.parse(readFileSync14(path, "utf-8"));
|
|
8050
8104
|
const entries = Object.entries(parsed).filter((entry) => typeof entry[1] === "string");
|
|
8051
8105
|
return Object.fromEntries(entries);
|
|
8052
8106
|
} catch {
|
|
@@ -8054,13 +8108,13 @@ function loadPersistedRuntimeSecrets(runtimeRoot) {
|
|
|
8054
8108
|
}
|
|
8055
8109
|
}
|
|
8056
8110
|
function ensureRuntimeOpenSslConfig(runtimeHome) {
|
|
8057
|
-
const sslDir =
|
|
8058
|
-
const sslConfig =
|
|
8059
|
-
if (!
|
|
8060
|
-
|
|
8111
|
+
const sslDir = resolve27(runtimeHome, ".ssl");
|
|
8112
|
+
const sslConfig = resolve27(sslDir, "openssl.cnf");
|
|
8113
|
+
if (!existsSync23(sslDir)) {
|
|
8114
|
+
mkdirSync11(sslDir, { recursive: true });
|
|
8061
8115
|
}
|
|
8062
|
-
if (!
|
|
8063
|
-
|
|
8116
|
+
if (!existsSync23(sslConfig)) {
|
|
8117
|
+
writeFileSync11(sslConfig, `# Rig runtime OpenSSL config placeholder
|
|
8064
8118
|
`);
|
|
8065
8119
|
}
|
|
8066
8120
|
return sslConfig;
|
|
@@ -8078,11 +8132,11 @@ function resolveRuntimeMetadata(projectRoot) {
|
|
|
8078
8132
|
if (contextFile) {
|
|
8079
8133
|
return {
|
|
8080
8134
|
ctx,
|
|
8081
|
-
runtimeRoot: dirname14(
|
|
8135
|
+
runtimeRoot: dirname14(resolve27(contextFile))
|
|
8082
8136
|
};
|
|
8083
8137
|
}
|
|
8084
8138
|
const inferredContextFile = findRuntimeContextFile2(projectRoot);
|
|
8085
|
-
if (
|
|
8139
|
+
if (existsSync23(inferredContextFile)) {
|
|
8086
8140
|
try {
|
|
8087
8141
|
ctx = loadRuntimeContext(inferredContextFile);
|
|
8088
8142
|
} catch {}
|
|
@@ -8094,10 +8148,10 @@ function resolveRuntimeMetadata(projectRoot) {
|
|
|
8094
8148
|
return { ctx, runtimeRoot: "" };
|
|
8095
8149
|
}
|
|
8096
8150
|
function findRuntimeContextFile2(startPath) {
|
|
8097
|
-
let current =
|
|
8151
|
+
let current = resolve27(startPath);
|
|
8098
8152
|
while (true) {
|
|
8099
|
-
const candidate =
|
|
8100
|
-
if (
|
|
8153
|
+
const candidate = resolve27(current, "runtime-context.json");
|
|
8154
|
+
if (existsSync23(candidate)) {
|
|
8101
8155
|
return candidate;
|
|
8102
8156
|
}
|
|
8103
8157
|
const parent = dirname14(current);
|
|
@@ -8109,7 +8163,7 @@ function findRuntimeContextFile2(startPath) {
|
|
|
8109
8163
|
}
|
|
8110
8164
|
|
|
8111
8165
|
// packages/runtime/src/control-plane/native/profile-ops.ts
|
|
8112
|
-
import { existsSync as
|
|
8166
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "fs";
|
|
8113
8167
|
var DEFAULTS = {
|
|
8114
8168
|
model: parseEnvOrDefault(process.env.DEFAULT_AGENT_MODEL, ["claude", "gpt-codex", "pi"], "pi"),
|
|
8115
8169
|
runtime: parseEnvOrDefault(process.env.DEFAULT_AGENT_RUNTIME, ["claude-code", "codex-app-server", "pi"], "pi"),
|
|
@@ -8124,7 +8178,7 @@ function parseEnvOrDefault(value, allowed, fallback) {
|
|
|
8124
8178
|
return allowed.includes(value) ? value : fallback;
|
|
8125
8179
|
}
|
|
8126
8180
|
async function readProfileFile(path) {
|
|
8127
|
-
if (!
|
|
8181
|
+
if (!existsSync24(path)) {
|
|
8128
8182
|
return null;
|
|
8129
8183
|
}
|
|
8130
8184
|
try {
|
|
@@ -8177,14 +8231,14 @@ async function setProfile(projectRoot, options) {
|
|
|
8177
8231
|
plugin = model === "gpt-codex" ? "codex" : model === "pi" ? "pi" : "claude";
|
|
8178
8232
|
}
|
|
8179
8233
|
const paths = resolveHarnessPaths(projectRoot);
|
|
8180
|
-
|
|
8234
|
+
mkdirSync12(paths.stateDir, { recursive: true });
|
|
8181
8235
|
const next = {
|
|
8182
8236
|
model,
|
|
8183
8237
|
runtime,
|
|
8184
8238
|
agent_plugin: plugin,
|
|
8185
8239
|
updated_at: new Date().toISOString()
|
|
8186
8240
|
};
|
|
8187
|
-
|
|
8241
|
+
writeFileSync12(paths.agentProfilePath, `${JSON.stringify(next, null, 2)}
|
|
8188
8242
|
`, "utf-8");
|
|
8189
8243
|
await showProfile(projectRoot, false);
|
|
8190
8244
|
}
|
|
@@ -8220,13 +8274,13 @@ async function setReviewProfile(projectRoot, mode, provider) {
|
|
|
8220
8274
|
throw new Error(`Invalid provider: ${resolvedProvider}. Supported: greptile.`);
|
|
8221
8275
|
}
|
|
8222
8276
|
const paths = resolveHarnessPaths(projectRoot);
|
|
8223
|
-
|
|
8277
|
+
mkdirSync12(paths.stateDir, { recursive: true });
|
|
8224
8278
|
const next = {
|
|
8225
8279
|
mode,
|
|
8226
8280
|
provider: resolvedProvider,
|
|
8227
8281
|
updated_at: new Date().toISOString()
|
|
8228
8282
|
};
|
|
8229
|
-
|
|
8283
|
+
writeFileSync12(paths.reviewProfilePath, `${JSON.stringify(next, null, 2)}
|
|
8230
8284
|
`, "utf-8");
|
|
8231
8285
|
await showReviewProfile(projectRoot);
|
|
8232
8286
|
}
|
|
@@ -8264,44 +8318,44 @@ async function loadReviewProfile(path) {
|
|
|
8264
8318
|
}
|
|
8265
8319
|
|
|
8266
8320
|
// packages/runtime/src/control-plane/native/repo-ops.ts
|
|
8267
|
-
import { existsSync as
|
|
8268
|
-
import { basename as basename8, dirname as dirname16, resolve as
|
|
8321
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync16, readFileSync as readFileSync16, readdirSync as readdirSync6, rmSync as rmSync8, writeFileSync as writeFileSync14 } from "fs";
|
|
8322
|
+
import { basename as basename8, dirname as dirname16, resolve as resolve31 } from "path";
|
|
8269
8323
|
// packages/runtime/src/control-plane/repos/mirror/bootstrap.ts
|
|
8270
|
-
import { existsSync as
|
|
8271
|
-
import { resolve as
|
|
8324
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync14, realpathSync as realpathSync2 } from "fs";
|
|
8325
|
+
import { resolve as resolve29 } from "path";
|
|
8272
8326
|
|
|
8273
8327
|
// packages/runtime/src/control-plane/authority-files.ts
|
|
8274
|
-
import { existsSync as
|
|
8275
|
-
import { dirname as dirname15, join as join5, relative, resolve as
|
|
8328
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync13, readFileSync as readFileSync15, writeFileSync as writeFileSync13, appendFileSync as appendFileSync2, copyFileSync as copyFileSync3, statSync as statSync6, readdirSync as readdirSync5, chmodSync as chmodSync3 } from "fs";
|
|
8329
|
+
import { dirname as dirname15, join as join5, relative, resolve as resolve28 } from "path";
|
|
8276
8330
|
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
8277
8331
|
function resolveAuthorityProjectStateDir(projectRoot) {
|
|
8278
8332
|
const explicit = process.env.RIG_STATE_DIR?.trim();
|
|
8279
8333
|
if (explicit) {
|
|
8280
|
-
return
|
|
8334
|
+
return resolve28(explicit);
|
|
8281
8335
|
}
|
|
8282
|
-
return
|
|
8336
|
+
return resolve28(resolve28(projectRoot), ".rig", "state");
|
|
8283
8337
|
}
|
|
8284
8338
|
function readJsonAtPath(path, fallback) {
|
|
8285
|
-
if (!
|
|
8339
|
+
if (!existsSync25(path)) {
|
|
8286
8340
|
return fallback;
|
|
8287
8341
|
}
|
|
8288
8342
|
try {
|
|
8289
|
-
return JSON.parse(
|
|
8343
|
+
return JSON.parse(readFileSync15(path, "utf-8"));
|
|
8290
8344
|
} catch {
|
|
8291
8345
|
return fallback;
|
|
8292
8346
|
}
|
|
8293
8347
|
}
|
|
8294
8348
|
function writeJsonAtPath(path, value) {
|
|
8295
|
-
|
|
8296
|
-
|
|
8349
|
+
mkdirSync13(dirname15(path), { recursive: true });
|
|
8350
|
+
writeFileSync13(path, `${JSON.stringify(value, null, 2)}
|
|
8297
8351
|
`, "utf8");
|
|
8298
8352
|
return path;
|
|
8299
8353
|
}
|
|
8300
8354
|
function readAuthorityProjectStateJson(projectRoot, relativePath, fallback) {
|
|
8301
|
-
return readJsonAtPath(
|
|
8355
|
+
return readJsonAtPath(resolve28(resolveAuthorityProjectStateDir(projectRoot), relativePath), fallback);
|
|
8302
8356
|
}
|
|
8303
8357
|
function writeAuthorityProjectStateJson(projectRoot, relativePath, value) {
|
|
8304
|
-
return writeJsonAtPath(
|
|
8358
|
+
return writeJsonAtPath(resolve28(resolveAuthorityProjectStateDir(projectRoot), relativePath), value);
|
|
8305
8359
|
}
|
|
8306
8360
|
|
|
8307
8361
|
// packages/runtime/src/control-plane/repos/mirror/state.ts
|
|
@@ -8361,7 +8415,7 @@ function sameExistingPath(left, right) {
|
|
|
8361
8415
|
try {
|
|
8362
8416
|
return realpathSync2(left) === realpathSync2(right);
|
|
8363
8417
|
} catch {
|
|
8364
|
-
return
|
|
8418
|
+
return resolve29(left) === resolve29(right);
|
|
8365
8419
|
}
|
|
8366
8420
|
}
|
|
8367
8421
|
function repoLooksUsable(repoRoot, projectRoot) {
|
|
@@ -8397,7 +8451,7 @@ function resolveMirrorRemoteUrl(layout) {
|
|
|
8397
8451
|
}
|
|
8398
8452
|
}
|
|
8399
8453
|
}
|
|
8400
|
-
if (
|
|
8454
|
+
if (existsSync26(resolve29(layout.checkoutRoot, ".git")) && checkoutLooksUsable(layout)) {
|
|
8401
8455
|
const checkoutOrigin = runGit(["git", "-C", layout.checkoutRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
8402
8456
|
if (checkoutOrigin.exitCode === 0) {
|
|
8403
8457
|
const currentOrigin = checkoutOrigin.stdout.trim();
|
|
@@ -8410,9 +8464,9 @@ function resolveMirrorRemoteUrl(layout) {
|
|
|
8410
8464
|
}
|
|
8411
8465
|
function ensureManagedRepoMirror(projectRoot, repoId) {
|
|
8412
8466
|
const layout = resolveManagedRepoLayout(projectRoot, repoId);
|
|
8413
|
-
|
|
8467
|
+
mkdirSync14(layout.metadataRoot, { recursive: true });
|
|
8414
8468
|
const remoteUrl = resolveMirrorRemoteUrl(layout);
|
|
8415
|
-
if (!
|
|
8469
|
+
if (!existsSync26(resolve29(layout.mirrorRoot, "HEAD"))) {
|
|
8416
8470
|
ensureGitSuccess(runGit(["git", "init", "--bare", layout.mirrorRoot], layout.projectRoot), ["git", "init", "--bare", layout.mirrorRoot]);
|
|
8417
8471
|
}
|
|
8418
8472
|
const getOrigin = runGit(["git", "--git-dir", layout.mirrorRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
@@ -8432,8 +8486,8 @@ function ensureManagedRepoMirror(projectRoot, repoId) {
|
|
|
8432
8486
|
return layout;
|
|
8433
8487
|
}
|
|
8434
8488
|
// packages/runtime/src/control-plane/repos/mirror/refresh.ts
|
|
8435
|
-
import { existsSync as
|
|
8436
|
-
import { resolve as
|
|
8489
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync15, realpathSync as realpathSync3, rmSync as rmSync7 } from "fs";
|
|
8490
|
+
import { resolve as resolve30 } from "path";
|
|
8437
8491
|
function nowIso3() {
|
|
8438
8492
|
return new Date().toISOString();
|
|
8439
8493
|
}
|
|
@@ -8460,7 +8514,7 @@ function sameExistingPath2(left, right) {
|
|
|
8460
8514
|
try {
|
|
8461
8515
|
return realpathSync3(left) === realpathSync3(right);
|
|
8462
8516
|
} catch {
|
|
8463
|
-
return
|
|
8517
|
+
return resolve30(left) === resolve30(right);
|
|
8464
8518
|
}
|
|
8465
8519
|
}
|
|
8466
8520
|
function ensureMirrorHead(layout) {
|
|
@@ -8506,12 +8560,12 @@ function checkoutLooksUsable2(layout) {
|
|
|
8506
8560
|
return probe.exitCode === 0 && sameExistingPath2(probe.stdout.trim(), layout.checkoutRoot);
|
|
8507
8561
|
}
|
|
8508
8562
|
function ensureCheckoutFromMirror(layout) {
|
|
8509
|
-
|
|
8510
|
-
const gitPath =
|
|
8511
|
-
if (
|
|
8512
|
-
|
|
8563
|
+
mkdirSync15(resolve30(layout.checkoutRoot, ".."), { recursive: true });
|
|
8564
|
+
const gitPath = resolve30(layout.checkoutRoot, ".git");
|
|
8565
|
+
if (existsSync27(layout.checkoutRoot) && (!existsSync27(gitPath) || !checkoutLooksUsable2(layout))) {
|
|
8566
|
+
rmSync7(layout.checkoutRoot, { recursive: true, force: true });
|
|
8513
8567
|
}
|
|
8514
|
-
if (!
|
|
8568
|
+
if (!existsSync27(gitPath)) {
|
|
8515
8569
|
ensureGitSuccess2(runGit2(["git", "clone", layout.mirrorRoot, layout.checkoutRoot], layout.projectRoot), ["git", "clone", layout.mirrorRoot, layout.checkoutRoot]);
|
|
8516
8570
|
}
|
|
8517
8571
|
const getOrigin = runGit2(["git", "-C", layout.checkoutRoot, "remote", "get-url", "origin"], layout.projectRoot);
|
|
@@ -8612,7 +8666,7 @@ function repoDiscover(projectRoot, taskId) {
|
|
|
8612
8666
|
}
|
|
8613
8667
|
function repoBaseline(projectRoot, refresh = false) {
|
|
8614
8668
|
const paths = resolveRepoDiscoveryPaths(projectRoot);
|
|
8615
|
-
if (!refresh &&
|
|
8669
|
+
if (!refresh && existsSync28(paths.baseRepoPinsPath)) {
|
|
8616
8670
|
const baseline = readJsonFile(paths.baseRepoPinsPath, { recorded_at: nowIso(), repos: {} });
|
|
8617
8671
|
return baseline.repos || {};
|
|
8618
8672
|
}
|
|
@@ -8636,8 +8690,8 @@ function ensureMonorepoReady(projectRoot) {
|
|
|
8636
8690
|
}
|
|
8637
8691
|
function persistBaselinePins(projectRoot, repos) {
|
|
8638
8692
|
const paths = resolveRepoDiscoveryPaths(projectRoot);
|
|
8639
|
-
|
|
8640
|
-
|
|
8693
|
+
mkdirSync16(resolve31(paths.baseRepoPinsPath, ".."), { recursive: true });
|
|
8694
|
+
writeFileSync14(paths.baseRepoPinsPath, `${JSON.stringify({ recorded_at: nowIso(), repos }, null, 2)}
|
|
8641
8695
|
`, "utf-8");
|
|
8642
8696
|
return repos;
|
|
8643
8697
|
}
|
|
@@ -8716,28 +8770,28 @@ function readRepoDiscoveryTaskConfig(projectRoot) {
|
|
|
8716
8770
|
function resolveRepoDiscoveryPaths(projectRoot) {
|
|
8717
8771
|
const monorepoRoot = resolveMonorepoRepoLayout(projectRoot).checkoutRoot;
|
|
8718
8772
|
const explicitHostProjectRoot = (process.env.RIG_HOST_PROJECT_ROOT || "").trim();
|
|
8719
|
-
const normalizedProjectRoot =
|
|
8773
|
+
const normalizedProjectRoot = resolve31(projectRoot);
|
|
8720
8774
|
const hostProjectRoot = explicitHostProjectRoot && shouldUseHostProjectStateRoot(normalizedProjectRoot) ? explicitHostProjectRoot : normalizedProjectRoot;
|
|
8721
|
-
const stateDir =
|
|
8775
|
+
const stateDir = resolve31(hostProjectRoot, ".rig", "state");
|
|
8722
8776
|
return {
|
|
8723
8777
|
monorepoRoot,
|
|
8724
|
-
taskRepoCommitsPath:
|
|
8725
|
-
baseRepoPinsPath:
|
|
8778
|
+
taskRepoCommitsPath: resolve31(stateDir, "task-repo-commits.json"),
|
|
8779
|
+
baseRepoPinsPath: resolve31(stateDir, "base-repo-pins.json")
|
|
8726
8780
|
};
|
|
8727
8781
|
}
|
|
8728
8782
|
function shouldUseHostProjectStateRoot(projectRoot) {
|
|
8729
8783
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
8730
|
-
if (runtimeWorkspace &&
|
|
8784
|
+
if (runtimeWorkspace && resolve31(runtimeWorkspace) === projectRoot) {
|
|
8731
8785
|
return true;
|
|
8732
8786
|
}
|
|
8733
8787
|
return basename8(dirname16(projectRoot)) === ".worktrees";
|
|
8734
8788
|
}
|
|
8735
8789
|
function readPinFromArtifact(projectRoot, depTask, repoKey) {
|
|
8736
|
-
const snapshot =
|
|
8737
|
-
if (!
|
|
8790
|
+
const snapshot = resolve31(artifactDirForId(projectRoot, depTask), "git-state.txt");
|
|
8791
|
+
if (!existsSync28(snapshot)) {
|
|
8738
8792
|
return "";
|
|
8739
8793
|
}
|
|
8740
|
-
const content =
|
|
8794
|
+
const content = readFileSync16(snapshot, "utf-8");
|
|
8741
8795
|
const chunk = content.split(/\r?\n/);
|
|
8742
8796
|
let inSection = false;
|
|
8743
8797
|
for (const line of chunk) {
|
|
@@ -8759,12 +8813,12 @@ function repoPath(projectRoot, key) {
|
|
|
8759
8813
|
if (managed) {
|
|
8760
8814
|
return managed.checkoutRoot;
|
|
8761
8815
|
}
|
|
8762
|
-
return key.startsWith("/") ? key :
|
|
8816
|
+
return key.startsWith("/") ? key : resolve31(projectRoot, key);
|
|
8763
8817
|
}
|
|
8764
8818
|
function applyPins(projectRoot, pins) {
|
|
8765
8819
|
for (const [key, commit] of Object.entries(pins)) {
|
|
8766
8820
|
const path = repoPath(projectRoot, key);
|
|
8767
|
-
if (!
|
|
8821
|
+
if (!existsSync28(resolve31(path, ".git"))) {
|
|
8768
8822
|
throw new Error(`Repo for pin not available: ${key} (${path})`);
|
|
8769
8823
|
}
|
|
8770
8824
|
let hasCommit = runGitCapture(["git", "-C", path, "cat-file", "-e", `${commit}^{commit}`], projectRoot).exitCode === 0;
|
|
@@ -8793,7 +8847,7 @@ function verifyPins(projectRoot, pins) {
|
|
|
8793
8847
|
let ok = true;
|
|
8794
8848
|
for (const [key, expected] of Object.entries(pins)) {
|
|
8795
8849
|
const path = repoPath(projectRoot, key);
|
|
8796
|
-
if (!
|
|
8850
|
+
if (!existsSync28(resolve31(path, ".git"))) {
|
|
8797
8851
|
console.error(`ERROR: repo missing during pin verification: ${key}`);
|
|
8798
8852
|
ok = false;
|
|
8799
8853
|
continue;
|
|
@@ -8818,23 +8872,23 @@ function resolveRuntimeGitEnv() {
|
|
|
8818
8872
|
GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND
|
|
8819
8873
|
};
|
|
8820
8874
|
}
|
|
8821
|
-
const runtimeRoot = process.env.RIG_RUNTIME_HOME?.trim() || (process.env.RIG_RUNTIME_CONTEXT_FILE?.trim() ?
|
|
8822
|
-
const runtimeHome = runtimeRoot ?
|
|
8875
|
+
const runtimeRoot = process.env.RIG_RUNTIME_HOME?.trim() || (process.env.RIG_RUNTIME_CONTEXT_FILE?.trim() ? resolve31(process.env.RIG_RUNTIME_CONTEXT_FILE, "..") : inferRuntimeRootFromWorkspace(process.cwd()));
|
|
8876
|
+
const runtimeHome = runtimeRoot ? resolve31(runtimeRoot, "home") : process.env.HOME?.trim() || "";
|
|
8823
8877
|
if (!runtimeHome) {
|
|
8824
8878
|
return;
|
|
8825
8879
|
}
|
|
8826
|
-
const knownHostsPath =
|
|
8827
|
-
if (!
|
|
8880
|
+
const knownHostsPath = resolve31(runtimeHome, ".ssh", "known_hosts");
|
|
8881
|
+
if (!existsSync28(knownHostsPath)) {
|
|
8828
8882
|
return { HOME: runtimeHome };
|
|
8829
8883
|
}
|
|
8830
|
-
const agentSshKey =
|
|
8884
|
+
const agentSshKey = resolve31(runtimeHome, ".ssh", "rig-agent-key");
|
|
8831
8885
|
const sshParts = [
|
|
8832
8886
|
"ssh",
|
|
8833
8887
|
`-o UserKnownHostsFile="${knownHostsPath}"`,
|
|
8834
8888
|
"-o StrictHostKeyChecking=yes",
|
|
8835
8889
|
"-F /dev/null"
|
|
8836
8890
|
];
|
|
8837
|
-
if (
|
|
8891
|
+
if (existsSync28(agentSshKey)) {
|
|
8838
8892
|
sshParts.splice(1, 0, `-i "${agentSshKey}"`, "-o IdentitiesOnly=yes");
|
|
8839
8893
|
}
|
|
8840
8894
|
return {
|
|
@@ -8844,24 +8898,24 @@ function resolveRuntimeGitEnv() {
|
|
|
8844
8898
|
}
|
|
8845
8899
|
function inferRuntimeRootFromWorkspace(cwd) {
|
|
8846
8900
|
const contextPath = findRuntimeContextFile3(cwd);
|
|
8847
|
-
if (!contextPath || !
|
|
8901
|
+
if (!contextPath || !existsSync28(contextPath)) {
|
|
8848
8902
|
return "";
|
|
8849
8903
|
}
|
|
8850
8904
|
try {
|
|
8851
8905
|
loadRuntimeContext(contextPath);
|
|
8852
|
-
return
|
|
8906
|
+
return resolve31(contextPath, "..");
|
|
8853
8907
|
} catch {
|
|
8854
8908
|
return "";
|
|
8855
8909
|
}
|
|
8856
8910
|
}
|
|
8857
8911
|
function findRuntimeContextFile3(startPath) {
|
|
8858
|
-
let current =
|
|
8912
|
+
let current = resolve31(startPath);
|
|
8859
8913
|
while (true) {
|
|
8860
|
-
const candidate =
|
|
8861
|
-
if (
|
|
8914
|
+
const candidate = resolve31(current, "runtime-context.json");
|
|
8915
|
+
if (existsSync28(candidate)) {
|
|
8862
8916
|
return candidate;
|
|
8863
8917
|
}
|
|
8864
|
-
const parent =
|
|
8918
|
+
const parent = resolve31(current, "..");
|
|
8865
8919
|
if (parent === current) {
|
|
8866
8920
|
return "";
|
|
8867
8921
|
}
|
|
@@ -8915,7 +8969,7 @@ function getEventBus() {
|
|
|
8915
8969
|
}
|
|
8916
8970
|
function inferRuntimeContext() {
|
|
8917
8971
|
for (const candidate of runtimeContextCandidates()) {
|
|
8918
|
-
if (!candidate || !
|
|
8972
|
+
if (!candidate || !existsSync29(candidate)) {
|
|
8919
8973
|
continue;
|
|
8920
8974
|
}
|
|
8921
8975
|
try {
|
|
@@ -8928,15 +8982,15 @@ function inferRuntimeContext() {
|
|
|
8928
8982
|
function runtimeContextCandidates() {
|
|
8929
8983
|
const cwd = process.cwd();
|
|
8930
8984
|
const candidates = [
|
|
8931
|
-
|
|
8932
|
-
|
|
8985
|
+
resolve32(cwd, "..", "runtime-context.json"),
|
|
8986
|
+
resolve32(cwd, ".rig", "runtime-context.json")
|
|
8933
8987
|
];
|
|
8934
8988
|
const argv1 = process.argv[1]?.trim();
|
|
8935
8989
|
if (argv1) {
|
|
8936
|
-
candidates.push(
|
|
8990
|
+
candidates.push(resolve32(argv1, "..", "..", "runtime-context.json"));
|
|
8937
8991
|
}
|
|
8938
8992
|
if (BAKED_BINARY_PATH) {
|
|
8939
|
-
candidates.push(
|
|
8993
|
+
candidates.push(resolve32(BAKED_BINARY_PATH, "..", "..", "runtime-context.json"));
|
|
8940
8994
|
}
|
|
8941
8995
|
return Array.from(new Set(candidates));
|
|
8942
8996
|
}
|
|
@@ -8951,12 +9005,12 @@ var GITHUB_KNOWN_HOSTS = [
|
|
|
8951
9005
|
"github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk="
|
|
8952
9006
|
];
|
|
8953
9007
|
function ensureRuntimeKnownHosts(runtimeHome) {
|
|
8954
|
-
const sshDir =
|
|
8955
|
-
const knownHostsPath =
|
|
8956
|
-
if (!
|
|
8957
|
-
|
|
9008
|
+
const sshDir = resolve32(runtimeHome, ".ssh");
|
|
9009
|
+
const knownHostsPath = resolve32(sshDir, "known_hosts");
|
|
9010
|
+
if (!existsSync29(sshDir)) {
|
|
9011
|
+
mkdirSync17(sshDir, { recursive: true });
|
|
8958
9012
|
}
|
|
8959
|
-
const existing =
|
|
9013
|
+
const existing = existsSync29(knownHostsPath) ? readFileSync17(knownHostsPath, "utf-8") : "";
|
|
8960
9014
|
const existingLines = new Set(existing.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
|
|
8961
9015
|
const missing = GITHUB_KNOWN_HOSTS.filter((line) => !existingLines.has(line));
|
|
8962
9016
|
if (missing.length === 0) {
|
|
@@ -8966,11 +9020,11 @@ function ensureRuntimeKnownHosts(runtimeHome) {
|
|
|
8966
9020
|
for (const line of missing) {
|
|
8967
9021
|
existingLines.add(line);
|
|
8968
9022
|
}
|
|
8969
|
-
|
|
9023
|
+
writeFileSync15(knownHostsPath, `${Array.from(existingLines).join(`
|
|
8970
9024
|
`)}
|
|
8971
9025
|
`, { mode: 420 });
|
|
8972
9026
|
} catch (err) {
|
|
8973
|
-
const hint =
|
|
9027
|
+
const hint = existsSync29(knownHostsPath) ? "" : " \u2014 known_hosts is missing; git SSH operations may fail";
|
|
8974
9028
|
console.warn(`[rig-agent] Could not update ${knownHostsPath}: ${err instanceof Error ? err.message : String(err)}${hint}`);
|
|
8975
9029
|
}
|
|
8976
9030
|
return knownHostsPath;
|
|
@@ -8984,13 +9038,13 @@ function hydrateRuntimeProcessEnv(ctx) {
|
|
|
8984
9038
|
return;
|
|
8985
9039
|
}
|
|
8986
9040
|
process.env.RIG_RUNTIME_CONTEXT_FILE = contextFile;
|
|
8987
|
-
const runtimeRoot = dirname17(
|
|
8988
|
-
const runtimeHome =
|
|
8989
|
-
const runtimeTmp =
|
|
8990
|
-
const runtimeCache =
|
|
8991
|
-
const runtimeBin =
|
|
8992
|
-
const runtimeWorkspaceBin =
|
|
8993
|
-
const runtimeTools =
|
|
9041
|
+
const runtimeRoot = dirname17(resolve32(contextFile));
|
|
9042
|
+
const runtimeHome = resolve32(runtimeRoot, "home");
|
|
9043
|
+
const runtimeTmp = resolve32(runtimeRoot, "tmp");
|
|
9044
|
+
const runtimeCache = resolve32(runtimeRoot, "cache");
|
|
9045
|
+
const runtimeBin = resolve32(runtimeRoot, "bin");
|
|
9046
|
+
const runtimeWorkspaceBin = resolve32(ctx.workspaceDir, ".rig", "bin");
|
|
9047
|
+
const runtimeTools = resolve32(ctx.workspaceDir, "rig", "tools");
|
|
8994
9048
|
if (ctx.hostProjectRoot) {
|
|
8995
9049
|
process.env.PROJECT_RIG_ROOT = ctx.hostProjectRoot;
|
|
8996
9050
|
}
|
|
@@ -9006,13 +9060,13 @@ function hydrateRuntimeProcessEnv(ctx) {
|
|
|
9006
9060
|
for (const [key, value] of Object.entries(browserEnvFromContext(ctx.browser))) {
|
|
9007
9061
|
process.env[key] = value;
|
|
9008
9062
|
}
|
|
9009
|
-
if (
|
|
9063
|
+
if (existsSync29(runtimeHome)) {
|
|
9010
9064
|
process.env.HOME = runtimeHome;
|
|
9011
9065
|
}
|
|
9012
|
-
if (
|
|
9066
|
+
if (existsSync29(runtimeTmp)) {
|
|
9013
9067
|
process.env.TMPDIR = runtimeTmp;
|
|
9014
9068
|
}
|
|
9015
|
-
if (
|
|
9069
|
+
if (existsSync29(runtimeCache)) {
|
|
9016
9070
|
process.env.XDG_CACHE_HOME = runtimeCache;
|
|
9017
9071
|
}
|
|
9018
9072
|
const workspaceSecrets = loadDotEnvSecrets(ctx.workspaceDir, process.env);
|
|
@@ -9038,31 +9092,31 @@ function hydrateRuntimeProcessEnv(ctx) {
|
|
|
9038
9092
|
const currentPath = process.env.PATH || "";
|
|
9039
9093
|
const pathEntries = currentPath.split(":").filter(Boolean);
|
|
9040
9094
|
for (const entry of [runtimeBin, runtimeWorkspaceBin, runtimeTools, "/usr/bin", "/bin", "/usr/sbin", "/sbin"]) {
|
|
9041
|
-
if (
|
|
9095
|
+
if (existsSync29(entry) && !pathEntries.includes(entry)) {
|
|
9042
9096
|
pathEntries.unshift(entry);
|
|
9043
9097
|
}
|
|
9044
9098
|
}
|
|
9045
9099
|
process.env.PATH = pathEntries.join(":");
|
|
9046
9100
|
if (!process.env.RIG_GIT_BIN) {
|
|
9047
|
-
const runtimeGit =
|
|
9048
|
-
process.env.RIG_GIT_BIN =
|
|
9101
|
+
const runtimeGit = resolve32(runtimeBin, "git");
|
|
9102
|
+
process.env.RIG_GIT_BIN = existsSync29(runtimeGit) ? runtimeGit : Bun.which("git") || "/usr/bin/git";
|
|
9049
9103
|
}
|
|
9050
9104
|
const knownHosts = ensureRuntimeKnownHosts(runtimeHome);
|
|
9051
|
-
const agentKey =
|
|
9105
|
+
const agentKey = resolve32(runtimeHome, ".ssh", "rig-agent-key");
|
|
9052
9106
|
const sshParts = [
|
|
9053
9107
|
"ssh",
|
|
9054
9108
|
`-o UserKnownHostsFile="${knownHosts}"`,
|
|
9055
9109
|
"-o StrictHostKeyChecking=yes",
|
|
9056
9110
|
"-F /dev/null"
|
|
9057
9111
|
];
|
|
9058
|
-
if (
|
|
9112
|
+
if (existsSync29(agentKey)) {
|
|
9059
9113
|
sshParts.splice(1, 0, `-i "${agentKey}"`, "-o IdentitiesOnly=yes");
|
|
9060
9114
|
}
|
|
9061
9115
|
process.env.GIT_SSH_COMMAND = sshParts.join(" ");
|
|
9062
9116
|
}
|
|
9063
9117
|
function inferRuntimeContextFileFromWorkspace(workspaceDir) {
|
|
9064
|
-
const candidate =
|
|
9065
|
-
return
|
|
9118
|
+
const candidate = resolve32(workspaceDir, "..", "runtime-context.json");
|
|
9119
|
+
return existsSync29(candidate) ? candidate : "";
|
|
9066
9120
|
}
|
|
9067
9121
|
async function main() {
|
|
9068
9122
|
const args = process.argv.slice(2);
|
|
@@ -9187,7 +9241,7 @@ async function runAgentCommand(args) {
|
|
|
9187
9241
|
const fileIdx = rest.indexOf("--file");
|
|
9188
9242
|
const inputFile = fileIdx !== -1 ? rest[fileIdx + 1] : undefined;
|
|
9189
9243
|
if (inputFile) {
|
|
9190
|
-
content =
|
|
9244
|
+
content = readFileSync17(resolve32(projectRoot, inputFile), "utf-8");
|
|
9191
9245
|
} else {
|
|
9192
9246
|
const chunks = [];
|
|
9193
9247
|
for await (const chunk of process.stdin) {
|
|
@@ -9490,8 +9544,8 @@ WORKFLOW:
|
|
|
9490
9544
|
`);
|
|
9491
9545
|
}
|
|
9492
9546
|
async function runCompletionVerification(projectRoot) {
|
|
9493
|
-
const hookPath =
|
|
9494
|
-
if (!
|
|
9547
|
+
const hookPath = resolve32(projectRoot, ".rig/bin/hooks/completion-verification");
|
|
9548
|
+
if (!existsSync29(hookPath)) {
|
|
9495
9549
|
console.error(`[rig-agent] completion-verification hook binary not found: ${hookPath}`);
|
|
9496
9550
|
return 1;
|
|
9497
9551
|
}
|
|
@@ -9525,7 +9579,7 @@ async function verifyRuntimeManifest() {
|
|
|
9525
9579
|
if (!manifestPath) {
|
|
9526
9580
|
return;
|
|
9527
9581
|
}
|
|
9528
|
-
if (!
|
|
9582
|
+
if (!existsSync29(manifestPath)) {
|
|
9529
9583
|
throw new Error(`[rig-agent] Runtime manifest missing: ${manifestPath}`);
|
|
9530
9584
|
}
|
|
9531
9585
|
let manifest;
|
|
@@ -9542,10 +9596,10 @@ async function verifyRuntimeManifest() {
|
|
|
9542
9596
|
if (!manifestBinaryPath || !expectedHash) {
|
|
9543
9597
|
throw new Error(`[rig-agent] Runtime manifest is missing binary hash data (${manifestPath}).`);
|
|
9544
9598
|
}
|
|
9545
|
-
if (!
|
|
9599
|
+
if (!existsSync29(manifestBinaryPath)) {
|
|
9546
9600
|
throw new Error(`[rig-agent] Runtime binary not found at ${manifestBinaryPath}.`);
|
|
9547
9601
|
}
|
|
9548
|
-
const actualHash = sha256Hex(
|
|
9602
|
+
const actualHash = sha256Hex(readFileSync17(resolve32(manifestBinaryPath)));
|
|
9549
9603
|
if (actualHash !== expectedHash) {
|
|
9550
9604
|
throw new Error(`[rig-agent] Runtime manifest mismatch for binary hash.
|
|
9551
9605
|
` + `expected=${expectedHash}
|