@h-rig/runtime 0.0.6-alpha.28 → 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
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// packages/runtime/src/control-plane/hooks/completion-verification.ts
|
|
5
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync21, mkdirSync as
|
|
6
|
-
import { resolve as
|
|
5
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync21, mkdirSync as mkdirSync13, readFileSync as readFileSync13, writeFileSync as writeFileSync13 } from "fs";
|
|
6
|
+
import { resolve as resolve24 } from "path";
|
|
7
7
|
import {
|
|
8
8
|
escapeRegExp as escapeRegExp2,
|
|
9
9
|
resolveBunCli,
|
|
@@ -13,10 +13,15 @@ import {
|
|
|
13
13
|
resolvePolicyContent
|
|
14
14
|
} from "@rig/hook-kit";
|
|
15
15
|
|
|
16
|
-
// packages/runtime/src/control-plane/runtime/
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
16
|
+
// packages/runtime/src/control-plane/runtime/guard.ts
|
|
17
|
+
import { optimizeNextInvocation } from "bun:jsc";
|
|
18
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
|
|
19
|
+
import { resolve as resolve4 } from "path";
|
|
20
|
+
|
|
21
|
+
// packages/runtime/src/control-plane/native/utils.ts
|
|
22
|
+
import { ptr as ptr2 } from "bun:ffi";
|
|
23
|
+
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
24
|
+
import { resolve as resolve3 } from "path";
|
|
20
25
|
|
|
21
26
|
// packages/runtime/src/layout.ts
|
|
22
27
|
import { existsSync } from "fs";
|
|
@@ -127,126 +132,13 @@ function resolveRigLayout(projectRoot) {
|
|
|
127
132
|
};
|
|
128
133
|
}
|
|
129
134
|
|
|
130
|
-
// packages/runtime/src/control-plane/runtime/events.ts
|
|
131
|
-
async function appendEvent(eventsFile, event) {
|
|
132
|
-
await mkdir(dirname2(eventsFile), { recursive: true });
|
|
133
|
-
await appendFile(eventsFile, `${JSON.stringify(event)}
|
|
134
|
-
`, "utf-8");
|
|
135
|
-
}
|
|
136
|
-
function createEvent(runId, type, payload) {
|
|
137
|
-
return {
|
|
138
|
-
id: randomUUID(),
|
|
139
|
-
runId,
|
|
140
|
-
timestamp: new Date().toISOString(),
|
|
141
|
-
type,
|
|
142
|
-
payload
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
class RuntimeEventBus {
|
|
147
|
-
runId;
|
|
148
|
-
eventsFile;
|
|
149
|
-
memoryEvents = [];
|
|
150
|
-
constructor(options) {
|
|
151
|
-
this.runId = options.runId || randomUUID();
|
|
152
|
-
this.eventsFile = options.eventsFile ?? resolveRigLayout(options.projectRoot).controlPlaneEventsFile;
|
|
153
|
-
}
|
|
154
|
-
getRunId() {
|
|
155
|
-
return this.runId;
|
|
156
|
-
}
|
|
157
|
-
getEventsFile() {
|
|
158
|
-
return this.eventsFile;
|
|
159
|
-
}
|
|
160
|
-
getMemoryEvents() {
|
|
161
|
-
return [...this.memoryEvents];
|
|
162
|
-
}
|
|
163
|
-
async attachRuntimeBus(runtimeBus) {
|
|
164
|
-
if (runtimeBus.getEventsFile() === this.eventsFile) {
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
for (const event of this.memoryEvents) {
|
|
168
|
-
await runtimeBus.ingest(event);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
async attachRuntimeWorkspace(projectRoot) {
|
|
172
|
-
const runtimeBus = new RuntimeEventBus({ projectRoot, runId: this.runId });
|
|
173
|
-
await this.attachRuntimeBus(runtimeBus);
|
|
174
|
-
return runtimeBus;
|
|
175
|
-
}
|
|
176
|
-
async ingest(event) {
|
|
177
|
-
this.memoryEvents.push(event);
|
|
178
|
-
await appendEvent(this.eventsFile, event);
|
|
179
|
-
}
|
|
180
|
-
async emit(type, payload) {
|
|
181
|
-
const event = createEvent(this.runId, type, payload);
|
|
182
|
-
await this.ingest(event);
|
|
183
|
-
return event;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
class GeneralCliEventBus {
|
|
188
|
-
runId;
|
|
189
|
-
eventsFile;
|
|
190
|
-
memoryEvents = [];
|
|
191
|
-
runtimeBuses = new Map;
|
|
192
|
-
constructor(options) {
|
|
193
|
-
this.runId = options.runId || randomUUID();
|
|
194
|
-
this.eventsFile = options.eventsFile ?? resolve2(options.projectRoot, ".rig", "logs", "control-plane.events.jsonl");
|
|
195
|
-
}
|
|
196
|
-
getRunId() {
|
|
197
|
-
return this.runId;
|
|
198
|
-
}
|
|
199
|
-
getEventsFile() {
|
|
200
|
-
return this.eventsFile;
|
|
201
|
-
}
|
|
202
|
-
getMemoryEvents() {
|
|
203
|
-
return [...this.memoryEvents];
|
|
204
|
-
}
|
|
205
|
-
async attachRuntimeBus(runtimeBus) {
|
|
206
|
-
const key = runtimeBus.getEventsFile();
|
|
207
|
-
if (this.runtimeBuses.has(key)) {
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
this.runtimeBuses.set(key, runtimeBus);
|
|
211
|
-
for (const event of this.memoryEvents) {
|
|
212
|
-
await runtimeBus.ingest(event);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
async attachRuntimeWorkspace(projectRoot) {
|
|
216
|
-
const runtimeBus = new RuntimeEventBus({ projectRoot, runId: this.runId });
|
|
217
|
-
await this.attachRuntimeBus(runtimeBus);
|
|
218
|
-
return runtimeBus;
|
|
219
|
-
}
|
|
220
|
-
async emit(type, payload) {
|
|
221
|
-
const event = createEvent(this.runId, type, payload);
|
|
222
|
-
this.memoryEvents.push(event);
|
|
223
|
-
await appendEvent(this.eventsFile, event);
|
|
224
|
-
await Promise.all(Array.from(this.runtimeBuses.values()).map((bus) => bus.ingest(event)));
|
|
225
|
-
return event;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// packages/runtime/src/control-plane/runtime/plugins.ts
|
|
230
|
-
import { existsSync as existsSync5, readdirSync } from "fs";
|
|
231
|
-
import { resolve as resolve6, basename as basename2 } from "path";
|
|
232
|
-
|
|
233
|
-
// packages/runtime/src/control-plane/runtime/guard.ts
|
|
234
|
-
import { optimizeNextInvocation } from "bun:jsc";
|
|
235
|
-
import { existsSync as existsSync4, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
|
|
236
|
-
import { resolve as resolve5 } from "path";
|
|
237
|
-
|
|
238
|
-
// packages/runtime/src/control-plane/native/utils.ts
|
|
239
|
-
import { ptr as ptr2 } from "bun:ffi";
|
|
240
|
-
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
241
|
-
import { resolve as resolve4 } from "path";
|
|
242
|
-
|
|
243
135
|
// packages/runtime/src/control-plane/native/runtime-native.ts
|
|
244
136
|
import { dlopen, ptr, suffix, toBuffer } from "bun:ffi";
|
|
245
137
|
import { copyFileSync, existsSync as existsSync2, mkdirSync, renameSync, rmSync, statSync } from "fs";
|
|
246
138
|
import { tmpdir } from "os";
|
|
247
|
-
import { dirname as
|
|
248
|
-
var sharedNativeRuntimeOutputDir =
|
|
249
|
-
var sharedNativeRuntimeOutputPath =
|
|
139
|
+
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
140
|
+
var sharedNativeRuntimeOutputDir = resolve2(tmpdir(), "rig-native");
|
|
141
|
+
var sharedNativeRuntimeOutputPath = resolve2(sharedNativeRuntimeOutputDir, `runtime-native-${process.platform}-${process.arch}.${suffix}`);
|
|
250
142
|
var colocatedNativeRuntimeFileName = `runtime-native.${suffix}`;
|
|
251
143
|
var nativeRuntimeLibrary = await loadNativeRuntimeLibrary();
|
|
252
144
|
function requireNativeRuntimeLibrary(feature) {
|
|
@@ -282,12 +174,12 @@ async function loadNativeRuntimeLibrary() {
|
|
|
282
174
|
}
|
|
283
175
|
function nativePackageLibraryCandidates(fromDir, names) {
|
|
284
176
|
const candidates = [];
|
|
285
|
-
let cursor =
|
|
177
|
+
let cursor = resolve2(fromDir);
|
|
286
178
|
for (let index = 0;index < 8; index += 1) {
|
|
287
179
|
for (const name of names) {
|
|
288
|
-
candidates.push(
|
|
180
|
+
candidates.push(resolve2(cursor, "native", `${process.platform}-${process.arch}`, name), resolve2(cursor, "native", `${process.platform}-${process.arch}`, "lib", name), resolve2(cursor, "native", name), resolve2(cursor, "native", "lib", name));
|
|
289
181
|
}
|
|
290
|
-
const parent =
|
|
182
|
+
const parent = dirname2(cursor);
|
|
291
183
|
if (parent === cursor)
|
|
292
184
|
break;
|
|
293
185
|
cursor = parent;
|
|
@@ -296,17 +188,17 @@ function nativePackageLibraryCandidates(fromDir, names) {
|
|
|
296
188
|
}
|
|
297
189
|
function nativeRuntimeLibraryCandidates() {
|
|
298
190
|
const explicit = process.env.RIG_NATIVE_RUNTIME_LIB?.trim() || "";
|
|
299
|
-
const execDir = process.execPath?.trim() ?
|
|
191
|
+
const execDir = process.execPath?.trim() ? dirname2(process.execPath.trim()) : "";
|
|
300
192
|
const platformSpecific = `runtime-native-${process.platform}-${process.arch}.${suffix}`;
|
|
301
193
|
return [...new Set([
|
|
302
194
|
explicit,
|
|
303
195
|
...nativePackageLibraryCandidates(import.meta.dir, [colocatedNativeRuntimeFileName, platformSpecific]),
|
|
304
|
-
execDir ?
|
|
305
|
-
execDir ?
|
|
306
|
-
execDir ?
|
|
307
|
-
execDir ?
|
|
308
|
-
execDir ?
|
|
309
|
-
execDir ?
|
|
196
|
+
execDir ? resolve2(execDir, colocatedNativeRuntimeFileName) : "",
|
|
197
|
+
execDir ? resolve2(execDir, platformSpecific) : "",
|
|
198
|
+
execDir ? resolve2(execDir, "..", colocatedNativeRuntimeFileName) : "",
|
|
199
|
+
execDir ? resolve2(execDir, "..", platformSpecific) : "",
|
|
200
|
+
execDir ? resolve2(execDir, "lib", colocatedNativeRuntimeFileName) : "",
|
|
201
|
+
execDir ? resolve2(execDir, "..", "lib", colocatedNativeRuntimeFileName) : "",
|
|
310
202
|
sharedNativeRuntimeOutputPath
|
|
311
203
|
].filter(Boolean))];
|
|
312
204
|
}
|
|
@@ -315,7 +207,7 @@ function resolveNativeRuntimeSourcePath() {
|
|
|
315
207
|
if (explicit && existsSync2(explicit)) {
|
|
316
208
|
return explicit;
|
|
317
209
|
}
|
|
318
|
-
const bundled =
|
|
210
|
+
const bundled = resolve2(import.meta.dir, "../../../native/snapshot.zig");
|
|
319
211
|
return existsSync2(bundled) ? bundled : null;
|
|
320
212
|
}
|
|
321
213
|
async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
@@ -329,7 +221,7 @@ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
|
329
221
|
}
|
|
330
222
|
const tempOutputPath = `${outputPath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
331
223
|
try {
|
|
332
|
-
mkdirSync(
|
|
224
|
+
mkdirSync(dirname2(outputPath), { recursive: true });
|
|
333
225
|
const needsBuild = options.force === true || !existsSync2(outputPath) || statSync(sourcePath).mtimeMs > statSync(outputPath).mtimeMs;
|
|
334
226
|
if (!needsBuild) {
|
|
335
227
|
return true;
|
|
@@ -506,31 +398,31 @@ function unique(values) {
|
|
|
506
398
|
function resolveHarnessPaths(projectRoot) {
|
|
507
399
|
const hasRuntimeWorkspace = Boolean(process.env.RIG_TASK_WORKSPACE?.trim());
|
|
508
400
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
509
|
-
const harnessRoot =
|
|
510
|
-
const stateRoot =
|
|
401
|
+
const harnessRoot = resolve3(projectRoot, "rig");
|
|
402
|
+
const stateRoot = resolve3(projectRoot, ".rig");
|
|
511
403
|
const layout = hasRuntimeWorkspace ? resolveRigLayout(projectRoot) : null;
|
|
512
|
-
const stateDir = layout?.stateDir ??
|
|
513
|
-
const logsDir = layout?.logsDir ??
|
|
514
|
-
const artifactsDir = layout?.artifactsRoot ??
|
|
515
|
-
const taskConfigPath = layout?.taskConfigPath ??
|
|
516
|
-
const binDir = layout?.binDir ??
|
|
404
|
+
const stateDir = layout?.stateDir ?? resolve3(stateRoot, "state");
|
|
405
|
+
const logsDir = layout?.logsDir ?? resolve3(stateRoot, "logs");
|
|
406
|
+
const artifactsDir = layout?.artifactsRoot ?? resolve3(monorepoRoot, "artifacts");
|
|
407
|
+
const taskConfigPath = layout?.taskConfigPath ?? resolve3(monorepoRoot, ".rig", "task-config.json");
|
|
408
|
+
const binDir = layout?.binDir ?? resolve3(stateRoot, "bin");
|
|
517
409
|
return {
|
|
518
410
|
harnessRoot,
|
|
519
411
|
stateDir: process.env.RIG_STATE_DIR || stateDir,
|
|
520
412
|
artifactsDir,
|
|
521
413
|
logsDir: process.env.RIG_LOGS_DIR || logsDir,
|
|
522
414
|
binDir,
|
|
523
|
-
hooksDir:
|
|
524
|
-
validationDir:
|
|
415
|
+
hooksDir: resolve3(harnessRoot, "hooks"),
|
|
416
|
+
validationDir: resolve3(harnessRoot, "validation"),
|
|
525
417
|
taskConfigPath,
|
|
526
|
-
sessionPath: process.env.RIG_SESSION_FILE ||
|
|
418
|
+
sessionPath: process.env.RIG_SESSION_FILE || resolve3(stateRoot, "session", "session.json"),
|
|
527
419
|
monorepoRoot,
|
|
528
|
-
tsApiTestsDir: process.env.TS_API_TESTS_DIR ||
|
|
529
|
-
taskRepoCommitsPath:
|
|
530
|
-
baseRepoPinsPath:
|
|
531
|
-
failedApproachesPath:
|
|
532
|
-
agentProfilePath:
|
|
533
|
-
reviewProfilePath:
|
|
420
|
+
tsApiTestsDir: process.env.TS_API_TESTS_DIR || resolve3(monorepoRoot, "TSAPITests"),
|
|
421
|
+
taskRepoCommitsPath: resolve3(stateDir, "task-repo-commits.json"),
|
|
422
|
+
baseRepoPinsPath: resolve3(stateDir, "base-repo-pins.json"),
|
|
423
|
+
failedApproachesPath: resolve3(stateDir, "failed_approaches.md"),
|
|
424
|
+
agentProfilePath: resolve3(stateDir, "agent-profile.json"),
|
|
425
|
+
reviewProfilePath: resolve3(stateDir, "review-profile.json")
|
|
534
426
|
};
|
|
535
427
|
}
|
|
536
428
|
function normalizeRelativeScopePath(inputPath) {
|
|
@@ -658,7 +550,7 @@ function loadPolicy(projectRoot) {
|
|
|
658
550
|
if (seededPolicyConfig) {
|
|
659
551
|
return seededPolicyConfig;
|
|
660
552
|
}
|
|
661
|
-
const configPath =
|
|
553
|
+
const configPath = resolve4(projectRoot, "rig/policy/policy.json");
|
|
662
554
|
if (!existsSync4(configPath)) {
|
|
663
555
|
return defaultPolicy();
|
|
664
556
|
}
|
|
@@ -889,28 +781,28 @@ function resolveAction(mode, matched) {
|
|
|
889
781
|
}
|
|
890
782
|
function resolveAbsolutePath(projectRoot, rawPath) {
|
|
891
783
|
if (rawPath.startsWith("/"))
|
|
892
|
-
return
|
|
893
|
-
return
|
|
784
|
+
return resolve4(rawPath);
|
|
785
|
+
return resolve4(projectRoot, rawPath);
|
|
894
786
|
}
|
|
895
787
|
function isHarnessPath(projectRoot, rawPath) {
|
|
896
788
|
const absPath = resolveAbsolutePath(projectRoot, rawPath);
|
|
897
789
|
const managedRoots = [
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
790
|
+
resolve4(projectRoot, "rig"),
|
|
791
|
+
resolve4(projectRoot, ".rig"),
|
|
792
|
+
resolve4(projectRoot, "artifacts")
|
|
901
793
|
];
|
|
902
794
|
return managedRoots.some((root) => absPath === root || absPath.startsWith(root + "/"));
|
|
903
795
|
}
|
|
904
796
|
function isRuntimePath(projectRoot, rawPath, taskWorkspace) {
|
|
905
797
|
const absPath = resolveAbsolutePath(projectRoot, rawPath);
|
|
906
798
|
if (taskWorkspace) {
|
|
907
|
-
const workspaceRigRoot =
|
|
908
|
-
const workspaceArtifactsRoot =
|
|
799
|
+
const workspaceRigRoot = resolve4(taskWorkspace, ".rig");
|
|
800
|
+
const workspaceArtifactsRoot = resolve4(taskWorkspace, "artifacts");
|
|
909
801
|
if (absPath === workspaceRigRoot || absPath.startsWith(workspaceRigRoot + "/") || absPath === workspaceArtifactsRoot || absPath.startsWith(workspaceArtifactsRoot + "/")) {
|
|
910
802
|
return true;
|
|
911
803
|
}
|
|
912
804
|
}
|
|
913
|
-
const runtimeRoot =
|
|
805
|
+
const runtimeRoot = resolve4(projectRoot, ".rig/runtime/agents");
|
|
914
806
|
return absPath === runtimeRoot || absPath.startsWith(runtimeRoot + "/");
|
|
915
807
|
}
|
|
916
808
|
function isTestFile(path) {
|
|
@@ -958,7 +850,7 @@ function evaluateScope(policy, context, filePath, access) {
|
|
|
958
850
|
return allowed();
|
|
959
851
|
}
|
|
960
852
|
if (context.taskWorkspace && context.taskWorkspace !== context.projectRoot && filePath.startsWith("/")) {
|
|
961
|
-
const absPath =
|
|
853
|
+
const absPath = resolve4(filePath);
|
|
962
854
|
if (!absPath.startsWith(context.taskWorkspace + "/") && !isHarnessPath(context.projectRoot, filePath)) {
|
|
963
855
|
const reason2 = `Absolute path '${filePath}' is outside task runtime boundary. Allowed root: ${context.taskWorkspace}`;
|
|
964
856
|
const matched2 = [{ id: "scope:workspace-boundary", category: "command", reason: reason2 }];
|
|
@@ -1167,12 +1059,6 @@ function extractContentFromToolInput(input) {
|
|
|
1167
1059
|
return input.new_string;
|
|
1168
1060
|
return "";
|
|
1169
1061
|
}
|
|
1170
|
-
function loadRuntimeImageConfig(projectRoot) {
|
|
1171
|
-
return loadPolicy(projectRoot).runtime_image ?? {
|
|
1172
|
-
deps: { ...DEFAULT_RUNTIME_IMAGE.deps },
|
|
1173
|
-
plugins_require_binaries: DEFAULT_RUNTIME_IMAGE.plugins_require_binaries
|
|
1174
|
-
};
|
|
1175
|
-
}
|
|
1176
1062
|
var guardHotPathPrimed = false;
|
|
1177
1063
|
function primeGuardHotPaths() {
|
|
1178
1064
|
if (guardHotPathPrimed) {
|
|
@@ -1186,290 +1072,99 @@ function primeGuardHotPaths() {
|
|
|
1186
1072
|
}
|
|
1187
1073
|
primeGuardHotPaths();
|
|
1188
1074
|
|
|
1189
|
-
// packages/runtime/src/control-plane/
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
1194
|
-
}
|
|
1075
|
+
// packages/runtime/src/control-plane/native/git-ops.ts
|
|
1076
|
+
import { existsSync as existsSync20, lstatSync, mkdirSync as mkdirSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync12 } from "fs";
|
|
1077
|
+
import { dirname as dirname10, isAbsolute as isAbsolute2, resolve as resolve23 } from "path";
|
|
1078
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1195
1079
|
|
|
1196
|
-
// packages/runtime/src/control-plane/runtime/
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
const pluginDir = resolve6(options.projectRoot, "rig/plugins");
|
|
1237
|
-
const runtimeImageConfig = loadRuntimeImageConfig(options.projectRoot);
|
|
1238
|
-
const localBinDir = options.runtimeContext ? resolve6(options.runtimeContext.binDir, "plugins") : resolve6(options.projectRoot, "rig/plugins");
|
|
1239
|
-
const legacyPluginScan = options.legacyPluginScan ?? isLegacyPluginScanEnabled(options.env);
|
|
1240
|
-
const files = legacyPluginScan ? safeReadDir(pluginDir).filter((entry) => /\.(ts|js|mjs|cjs)$/.test(entry)) : [];
|
|
1241
|
-
const pluginNames = files.map((file) => basename2(file).replace(/\.plugin\.(ts|js|mjs|cjs)$/, ""));
|
|
1242
|
-
const validatorProjectRoot = options.runtimeContext?.workspaceDir || options.projectRoot;
|
|
1243
|
-
const context = {
|
|
1244
|
-
projectRoot: validatorProjectRoot,
|
|
1245
|
-
runId: options.runId,
|
|
1246
|
-
eventBus: options.eventBus
|
|
1247
|
-
};
|
|
1248
|
-
return new PluginManager({
|
|
1249
|
-
eventBus: options.eventBus,
|
|
1250
|
-
context,
|
|
1251
|
-
pluginDir,
|
|
1252
|
-
pluginFiles: files,
|
|
1253
|
-
pluginNames,
|
|
1254
|
-
localBinDir,
|
|
1255
|
-
pluginsRequireBinaries: options.pluginsRequireBinaries ?? (runtimeImageConfig.plugins_require_binaries && Boolean(options.runtimeContext))
|
|
1256
|
-
});
|
|
1257
|
-
}
|
|
1258
|
-
list() {
|
|
1259
|
-
if (this.plugins) {
|
|
1260
|
-
return this.plugins.map((plugin) => ({
|
|
1261
|
-
name: plugin.name,
|
|
1262
|
-
validators: plugin.validators?.map((validator) => validator.id) ?? []
|
|
1263
|
-
}));
|
|
1264
|
-
}
|
|
1265
|
-
return this.pluginNames.map((name) => ({
|
|
1266
|
-
name,
|
|
1267
|
-
validators: []
|
|
1268
|
-
}));
|
|
1269
|
-
}
|
|
1270
|
-
async beforeCommand(ctx) {
|
|
1271
|
-
const plugins = await this.ensureLoaded();
|
|
1272
|
-
for (const plugin of plugins) {
|
|
1273
|
-
if (!plugin.beforeCommand) {
|
|
1274
|
-
continue;
|
|
1275
|
-
}
|
|
1276
|
-
await this.safeInvoke(plugin.name, "beforeCommand", () => plugin.beforeCommand?.(ctx, this.context));
|
|
1277
|
-
}
|
|
1278
|
-
}
|
|
1279
|
-
async afterCommand(result) {
|
|
1280
|
-
const plugins = await this.ensureLoaded();
|
|
1281
|
-
for (const plugin of plugins) {
|
|
1282
|
-
if (!plugin.afterCommand) {
|
|
1283
|
-
continue;
|
|
1284
|
-
}
|
|
1285
|
-
await this.safeInvoke(plugin.name, "afterCommand", () => plugin.afterCommand?.(result, this.context));
|
|
1080
|
+
// packages/runtime/src/control-plane/runtime/baked-secrets.ts
|
|
1081
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
1082
|
+
import { resolve as resolve5 } from "path";
|
|
1083
|
+
var BAKED_RUNTIME_SECRETS = {
|
|
1084
|
+
ANTHROPIC_API_KEY: typeof RIG_BAKED_ANTHROPIC_API_KEY !== "undefined" ? RIG_BAKED_ANTHROPIC_API_KEY : "",
|
|
1085
|
+
OPENAI_API_KEY: typeof RIG_BAKED_OPENAI_API_KEY !== "undefined" ? RIG_BAKED_OPENAI_API_KEY : "",
|
|
1086
|
+
OPENROUTER_API_KEY: typeof RIG_BAKED_OPENROUTER_API_KEY !== "undefined" ? RIG_BAKED_OPENROUTER_API_KEY : "",
|
|
1087
|
+
AI_REVIEW_MODE: typeof RIG_BAKED_AI_REVIEW_MODE !== "undefined" ? RIG_BAKED_AI_REVIEW_MODE : "",
|
|
1088
|
+
AI_REVIEW_PROVIDER: typeof RIG_BAKED_AI_REVIEW_PROVIDER !== "undefined" ? RIG_BAKED_AI_REVIEW_PROVIDER : "",
|
|
1089
|
+
GREPTILE_API_BASE: typeof RIG_BAKED_GREPTILE_API_BASE !== "undefined" ? RIG_BAKED_GREPTILE_API_BASE : "",
|
|
1090
|
+
GREPTILE_REMOTE: typeof RIG_BAKED_GREPTILE_REMOTE !== "undefined" ? RIG_BAKED_GREPTILE_REMOTE : "",
|
|
1091
|
+
GREPTILE_REPOSITORY: typeof RIG_BAKED_GREPTILE_REPOSITORY !== "undefined" ? RIG_BAKED_GREPTILE_REPOSITORY : "",
|
|
1092
|
+
GREPTILE_CONTEXT_BRANCH: typeof RIG_BAKED_GREPTILE_CONTEXT_BRANCH !== "undefined" ? RIG_BAKED_GREPTILE_CONTEXT_BRANCH : "",
|
|
1093
|
+
GREPTILE_DEFAULT_BRANCH: typeof RIG_BAKED_GREPTILE_DEFAULT_BRANCH !== "undefined" ? RIG_BAKED_GREPTILE_DEFAULT_BRANCH : "",
|
|
1094
|
+
GREPTILE_API_KEY: typeof RIG_BAKED_GREPTILE_API_KEY !== "undefined" ? RIG_BAKED_GREPTILE_API_KEY : "",
|
|
1095
|
+
GREPTILE_GITHUB_TOKEN: typeof RIG_BAKED_GREPTILE_GITHUB_TOKEN !== "undefined" ? RIG_BAKED_GREPTILE_GITHUB_TOKEN : "",
|
|
1096
|
+
GREPTILE_POLL_ATTEMPTS: typeof RIG_BAKED_GREPTILE_POLL_ATTEMPTS !== "undefined" ? RIG_BAKED_GREPTILE_POLL_ATTEMPTS : "",
|
|
1097
|
+
GREPTILE_POLL_INTERVAL_MS: typeof RIG_BAKED_GREPTILE_POLL_INTERVAL_MS !== "undefined" ? RIG_BAKED_GREPTILE_POLL_INTERVAL_MS : "",
|
|
1098
|
+
GH_TOKEN: typeof RIG_BAKED_GITHUB_TOKEN !== "undefined" ? RIG_BAKED_GITHUB_TOKEN : "",
|
|
1099
|
+
GITHUB_TOKEN: typeof RIG_BAKED_GITHUB_TOKEN !== "undefined" ? RIG_BAKED_GITHUB_TOKEN : "",
|
|
1100
|
+
GITHUB_SSH_KEY: typeof RIG_BAKED_GITHUB_SSH_KEY !== "undefined" ? RIG_BAKED_GITHUB_SSH_KEY : "",
|
|
1101
|
+
AWS_ACCESS_KEY_ID: typeof RIG_BAKED_AWS_ACCESS_KEY_ID !== "undefined" ? RIG_BAKED_AWS_ACCESS_KEY_ID : "",
|
|
1102
|
+
AWS_SECRET_ACCESS_KEY: typeof RIG_BAKED_AWS_SECRET_ACCESS_KEY !== "undefined" ? RIG_BAKED_AWS_SECRET_ACCESS_KEY : "",
|
|
1103
|
+
AWS_REGION: typeof RIG_BAKED_AWS_REGION !== "undefined" ? RIG_BAKED_AWS_REGION : "",
|
|
1104
|
+
LINEAR_API_KEY: typeof RIG_BAKED_LINEAR_API_KEY !== "undefined" ? RIG_BAKED_LINEAR_API_KEY : "",
|
|
1105
|
+
LINEAR_WEBHOOK_SECRET: typeof RIG_BAKED_LINEAR_WEBHOOK_SECRET !== "undefined" ? RIG_BAKED_LINEAR_WEBHOOK_SECRET : ""
|
|
1106
|
+
};
|
|
1107
|
+
function resolveRuntimeSecrets(env, baked = BAKED_RUNTIME_SECRETS) {
|
|
1108
|
+
const resolved = {};
|
|
1109
|
+
const keys = new Set([
|
|
1110
|
+
...Object.keys(BAKED_RUNTIME_SECRETS),
|
|
1111
|
+
...Object.keys(baked)
|
|
1112
|
+
]);
|
|
1113
|
+
for (const key of keys) {
|
|
1114
|
+
const envValue = env[key]?.trim();
|
|
1115
|
+
const bakedValue = baked[key]?.trim();
|
|
1116
|
+
if (envValue) {
|
|
1117
|
+
resolved[key] = envValue;
|
|
1118
|
+
} else if (bakedValue) {
|
|
1119
|
+
resolved[key] = bakedValue;
|
|
1286
1120
|
}
|
|
1287
1121
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
if (!plugin.onEvent) {
|
|
1295
|
-
continue;
|
|
1296
|
-
}
|
|
1297
|
-
await this.safeInvoke(plugin.name, "onEvent", () => plugin.onEvent?.(event, this.context));
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
async runValidators(taskId) {
|
|
1301
|
-
const plugins = await this.ensureLoaded();
|
|
1302
|
-
const results = [];
|
|
1303
|
-
for (const plugin of plugins) {
|
|
1304
|
-
for (const validator of plugin.validators ?? []) {
|
|
1305
|
-
await this.eventBus.emit("validator.started", {
|
|
1306
|
-
plugin: plugin.name,
|
|
1307
|
-
validator: validator.id,
|
|
1308
|
-
taskId
|
|
1309
|
-
});
|
|
1310
|
-
try {
|
|
1311
|
-
const result = await validator.run({ taskId, projectRoot: this.context.projectRoot }, this.context);
|
|
1312
|
-
results.push(result);
|
|
1313
|
-
await this.eventBus.emit("validator.finished", {
|
|
1314
|
-
plugin: plugin.name,
|
|
1315
|
-
validator: validator.id,
|
|
1316
|
-
taskId,
|
|
1317
|
-
passed: result.passed,
|
|
1318
|
-
summary: result.summary
|
|
1319
|
-
});
|
|
1320
|
-
} catch (error) {
|
|
1321
|
-
const failed = {
|
|
1322
|
-
id: validator.id,
|
|
1323
|
-
passed: false,
|
|
1324
|
-
summary: `${plugin.name}/${validator.id} failed unexpectedly`,
|
|
1325
|
-
details: `${error}`
|
|
1326
|
-
};
|
|
1327
|
-
results.push(failed);
|
|
1328
|
-
await this.eventBus.emit("validator.finished", {
|
|
1329
|
-
plugin: plugin.name,
|
|
1330
|
-
validator: validator.id,
|
|
1331
|
-
taskId,
|
|
1332
|
-
passed: false,
|
|
1333
|
-
summary: failed.summary,
|
|
1334
|
-
details: failed.details
|
|
1335
|
-
});
|
|
1336
|
-
}
|
|
1337
|
-
}
|
|
1338
|
-
}
|
|
1339
|
-
return results;
|
|
1122
|
+
return resolved;
|
|
1123
|
+
}
|
|
1124
|
+
function loadDotEnvSecrets(projectRoot, env = process.env) {
|
|
1125
|
+
const dotenvPath = resolve5(projectRoot, ".env");
|
|
1126
|
+
if (!existsSync5(dotenvPath)) {
|
|
1127
|
+
return {};
|
|
1340
1128
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
phase: hook,
|
|
1348
|
-
error: `${error}`
|
|
1349
|
-
});
|
|
1129
|
+
const parsed = {};
|
|
1130
|
+
const lines = readFileSync3(dotenvPath, "utf-8").split(/\r?\n/);
|
|
1131
|
+
for (const rawLine of lines) {
|
|
1132
|
+
const line = rawLine.trim();
|
|
1133
|
+
if (!line || line.startsWith("#")) {
|
|
1134
|
+
continue;
|
|
1350
1135
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
return this.plugins;
|
|
1136
|
+
const exportMatch = line.match(/^(?:export\s+)?([A-Z0-9_]+)\s*=\s*(.*)$/);
|
|
1137
|
+
if (!exportMatch) {
|
|
1138
|
+
continue;
|
|
1355
1139
|
}
|
|
1356
|
-
|
|
1357
|
-
|
|
1140
|
+
const key = exportMatch[1];
|
|
1141
|
+
if (!(key in BAKED_RUNTIME_SECRETS)) {
|
|
1142
|
+
continue;
|
|
1358
1143
|
}
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
return this.plugins;
|
|
1363
|
-
} finally {
|
|
1364
|
-
this.loadPromise = null;
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
resolveBinPath(binName) {
|
|
1368
|
-
const candidates = [this.localBinDir].filter(Boolean).map((dir) => resolve6(dir, binName));
|
|
1369
|
-
return candidates.find((candidate) => existsSync5(candidate));
|
|
1370
|
-
}
|
|
1371
|
-
async loadCompiledPlugins() {
|
|
1372
|
-
const plugins = [];
|
|
1373
|
-
for (const file of this.pluginFiles) {
|
|
1374
|
-
const binName = basename2(file).replace(/\.plugin\.(ts|js|mjs|cjs)$/, "");
|
|
1375
|
-
let binPath = this.resolveBinPath(binName);
|
|
1376
|
-
if (!binPath) {
|
|
1377
|
-
const triedPaths = [this.localBinDir].filter(Boolean).map((dir) => resolve6(dir, binName));
|
|
1378
|
-
const missingError = `Compiled plugin binary not found for '${binName}'. Tried: ${triedPaths.join(", ")}`;
|
|
1379
|
-
await this.eventBus.emit("plugin.error", {
|
|
1380
|
-
file: resolve6(this.pluginDir, file),
|
|
1381
|
-
phase: "load",
|
|
1382
|
-
error: missingError
|
|
1383
|
-
});
|
|
1384
|
-
if (this.pluginsRequireBinaries) {
|
|
1385
|
-
throw new Error(missingError);
|
|
1386
|
-
}
|
|
1387
|
-
plugins.push({
|
|
1388
|
-
name: binName,
|
|
1389
|
-
validators: []
|
|
1390
|
-
});
|
|
1391
|
-
await this.eventBus.emit("plugin.loaded", {
|
|
1392
|
-
plugin: binName,
|
|
1393
|
-
file: resolve6(this.pluginDir, file),
|
|
1394
|
-
source: "metadata-only"
|
|
1395
|
-
});
|
|
1396
|
-
continue;
|
|
1397
|
-
}
|
|
1398
|
-
const wrapper = createBinaryPluginWrapper(binName, binPath, this.context.projectRoot);
|
|
1399
|
-
plugins.push(wrapper);
|
|
1400
|
-
await this.eventBus.emit("plugin.loaded", {
|
|
1401
|
-
plugin: wrapper.name,
|
|
1402
|
-
file: binPath,
|
|
1403
|
-
source: "compiled-binary"
|
|
1404
|
-
});
|
|
1144
|
+
const value = expandShellValue(exportMatch[2] ?? "", { ...env, ...parsed });
|
|
1145
|
+
if (value) {
|
|
1146
|
+
parsed[key] = value;
|
|
1405
1147
|
}
|
|
1406
|
-
return plugins;
|
|
1407
1148
|
}
|
|
1149
|
+
return parsed;
|
|
1408
1150
|
}
|
|
1409
|
-
function
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
{
|
|
1414
|
-
id: `${name}:compiled`,
|
|
1415
|
-
async run(ctx) {
|
|
1416
|
-
const proc = Bun.spawn([binPath, "--validate", ctx.taskId, ctx.projectRoot], {
|
|
1417
|
-
cwd: projectRoot,
|
|
1418
|
-
stdout: "pipe",
|
|
1419
|
-
stderr: "pipe"
|
|
1420
|
-
});
|
|
1421
|
-
const exitCode = await proc.exited;
|
|
1422
|
-
const stdout = await new Response(proc.stdout).text();
|
|
1423
|
-
const stderr = await new Response(proc.stderr).text();
|
|
1424
|
-
if (exitCode !== 0) {
|
|
1425
|
-
return {
|
|
1426
|
-
id: `${name}:compiled`,
|
|
1427
|
-
passed: false,
|
|
1428
|
-
summary: `Plugin binary ${name} exited with code ${exitCode}`,
|
|
1429
|
-
details: stderr || stdout
|
|
1430
|
-
};
|
|
1431
|
-
}
|
|
1432
|
-
try {
|
|
1433
|
-
const results = JSON.parse(stdout.trim());
|
|
1434
|
-
const failed = results.filter((r) => !r.passed);
|
|
1435
|
-
if (failed.length > 0) {
|
|
1436
|
-
return {
|
|
1437
|
-
id: `${name}:compiled`,
|
|
1438
|
-
passed: false,
|
|
1439
|
-
summary: `${failed.length} of ${results.length} validator(s) failed`,
|
|
1440
|
-
details: failed.map((f) => `${f.id}: ${f.summary}`).join(`
|
|
1441
|
-
`)
|
|
1442
|
-
};
|
|
1443
|
-
}
|
|
1444
|
-
return {
|
|
1445
|
-
id: `${name}:compiled`,
|
|
1446
|
-
passed: true,
|
|
1447
|
-
summary: `All ${results.length} validator(s) passed`
|
|
1448
|
-
};
|
|
1449
|
-
} catch {
|
|
1450
|
-
return {
|
|
1451
|
-
id: `${name}:compiled`,
|
|
1452
|
-
passed: false,
|
|
1453
|
-
summary: `Failed to parse output from compiled plugin ${name}`,
|
|
1454
|
-
details: stdout.slice(0, 500)
|
|
1455
|
-
};
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1459
|
-
]
|
|
1460
|
-
};
|
|
1461
|
-
}
|
|
1462
|
-
function safeReadDir(path) {
|
|
1463
|
-
try {
|
|
1464
|
-
return readdirSync(path, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
|
|
1465
|
-
} catch {
|
|
1466
|
-
return [];
|
|
1151
|
+
function expandShellValue(rawValue, env) {
|
|
1152
|
+
let value = rawValue.trim();
|
|
1153
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
1154
|
+
value = value.slice(1, -1);
|
|
1467
1155
|
}
|
|
1156
|
+
return value.replace(/\$\{([A-Z0-9_]+)(:-([^}]*))?\}/g, (_match, name, _defaultGroup, fallback) => {
|
|
1157
|
+
const envValue = env[name]?.trim();
|
|
1158
|
+
if (envValue) {
|
|
1159
|
+
return envValue;
|
|
1160
|
+
}
|
|
1161
|
+
return fallback ?? "";
|
|
1162
|
+
});
|
|
1468
1163
|
}
|
|
1469
1164
|
|
|
1470
1165
|
// packages/runtime/src/control-plane/runtime/context.ts
|
|
1471
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as
|
|
1472
|
-
import { dirname as
|
|
1166
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync } from "fs";
|
|
1167
|
+
import { dirname as dirname3, resolve as resolve6 } from "path";
|
|
1473
1168
|
var RUNTIME_CONTEXT_ENV = "RIG_RUNTIME_CONTEXT_FILE";
|
|
1474
1169
|
var runtimeContextStringFields = [
|
|
1475
1170
|
"runtimeId",
|
|
@@ -1493,13 +1188,13 @@ var runtimeContextOptionalStringFields = [
|
|
|
1493
1188
|
"monorepoBaseCommit"
|
|
1494
1189
|
];
|
|
1495
1190
|
function loadRuntimeContext(path) {
|
|
1496
|
-
const absPath =
|
|
1191
|
+
const absPath = resolve6(path);
|
|
1497
1192
|
if (!existsSync6(absPath)) {
|
|
1498
1193
|
throw new Error(`RuntimeTaskContext file not found: ${absPath}`);
|
|
1499
1194
|
}
|
|
1500
1195
|
let raw;
|
|
1501
1196
|
try {
|
|
1502
|
-
raw = JSON.parse(
|
|
1197
|
+
raw = JSON.parse(readFileSync4(absPath, "utf8"));
|
|
1503
1198
|
} catch (err) {
|
|
1504
1199
|
throw new Error(`Failed to parse RuntimeTaskContext at ${absPath}: ${String(err)}`);
|
|
1505
1200
|
}
|
|
@@ -1622,13 +1317,13 @@ function loadRuntimeContextFromEnv(env = process.env) {
|
|
|
1622
1317
|
return loadRuntimeContext(inferred);
|
|
1623
1318
|
}
|
|
1624
1319
|
function findRuntimeContextFile(startPath) {
|
|
1625
|
-
let current =
|
|
1320
|
+
let current = resolve6(startPath);
|
|
1626
1321
|
while (true) {
|
|
1627
|
-
const candidate =
|
|
1322
|
+
const candidate = resolve6(current, "runtime-context.json");
|
|
1628
1323
|
if (existsSync6(candidate) && isAgentRuntimeContextPath(candidate)) {
|
|
1629
1324
|
return candidate;
|
|
1630
1325
|
}
|
|
1631
|
-
const parent =
|
|
1326
|
+
const parent = dirname3(current);
|
|
1632
1327
|
if (parent === current) {
|
|
1633
1328
|
return "";
|
|
1634
1329
|
}
|
|
@@ -1640,99 +1335,9 @@ function isAgentRuntimeContextPath(path) {
|
|
|
1640
1335
|
return /\/\.rig\/runtime-context\.json$/.test(normalized);
|
|
1641
1336
|
}
|
|
1642
1337
|
|
|
1643
|
-
// packages/runtime/src/control-plane/native/git-ops.ts
|
|
1644
|
-
import { existsSync as existsSync20, lstatSync, mkdirSync as mkdirSync11, readFileSync as readFileSync11, writeFileSync as writeFileSync11 } from "fs";
|
|
1645
|
-
import { dirname as dirname11, isAbsolute as isAbsolute2, resolve as resolve24 } from "path";
|
|
1646
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1647
|
-
|
|
1648
|
-
// packages/runtime/src/control-plane/runtime/baked-secrets.ts
|
|
1649
|
-
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
|
|
1650
|
-
import { resolve as resolve8 } from "path";
|
|
1651
|
-
var BAKED_RUNTIME_SECRETS = {
|
|
1652
|
-
ANTHROPIC_API_KEY: typeof RIG_BAKED_ANTHROPIC_API_KEY !== "undefined" ? RIG_BAKED_ANTHROPIC_API_KEY : "",
|
|
1653
|
-
OPENAI_API_KEY: typeof RIG_BAKED_OPENAI_API_KEY !== "undefined" ? RIG_BAKED_OPENAI_API_KEY : "",
|
|
1654
|
-
OPENROUTER_API_KEY: typeof RIG_BAKED_OPENROUTER_API_KEY !== "undefined" ? RIG_BAKED_OPENROUTER_API_KEY : "",
|
|
1655
|
-
AI_REVIEW_MODE: typeof RIG_BAKED_AI_REVIEW_MODE !== "undefined" ? RIG_BAKED_AI_REVIEW_MODE : "",
|
|
1656
|
-
AI_REVIEW_PROVIDER: typeof RIG_BAKED_AI_REVIEW_PROVIDER !== "undefined" ? RIG_BAKED_AI_REVIEW_PROVIDER : "",
|
|
1657
|
-
GREPTILE_API_BASE: typeof RIG_BAKED_GREPTILE_API_BASE !== "undefined" ? RIG_BAKED_GREPTILE_API_BASE : "",
|
|
1658
|
-
GREPTILE_REMOTE: typeof RIG_BAKED_GREPTILE_REMOTE !== "undefined" ? RIG_BAKED_GREPTILE_REMOTE : "",
|
|
1659
|
-
GREPTILE_REPOSITORY: typeof RIG_BAKED_GREPTILE_REPOSITORY !== "undefined" ? RIG_BAKED_GREPTILE_REPOSITORY : "",
|
|
1660
|
-
GREPTILE_CONTEXT_BRANCH: typeof RIG_BAKED_GREPTILE_CONTEXT_BRANCH !== "undefined" ? RIG_BAKED_GREPTILE_CONTEXT_BRANCH : "",
|
|
1661
|
-
GREPTILE_DEFAULT_BRANCH: typeof RIG_BAKED_GREPTILE_DEFAULT_BRANCH !== "undefined" ? RIG_BAKED_GREPTILE_DEFAULT_BRANCH : "",
|
|
1662
|
-
GREPTILE_API_KEY: typeof RIG_BAKED_GREPTILE_API_KEY !== "undefined" ? RIG_BAKED_GREPTILE_API_KEY : "",
|
|
1663
|
-
GREPTILE_GITHUB_TOKEN: typeof RIG_BAKED_GREPTILE_GITHUB_TOKEN !== "undefined" ? RIG_BAKED_GREPTILE_GITHUB_TOKEN : "",
|
|
1664
|
-
GREPTILE_POLL_ATTEMPTS: typeof RIG_BAKED_GREPTILE_POLL_ATTEMPTS !== "undefined" ? RIG_BAKED_GREPTILE_POLL_ATTEMPTS : "",
|
|
1665
|
-
GREPTILE_POLL_INTERVAL_MS: typeof RIG_BAKED_GREPTILE_POLL_INTERVAL_MS !== "undefined" ? RIG_BAKED_GREPTILE_POLL_INTERVAL_MS : "",
|
|
1666
|
-
GH_TOKEN: typeof RIG_BAKED_GITHUB_TOKEN !== "undefined" ? RIG_BAKED_GITHUB_TOKEN : "",
|
|
1667
|
-
GITHUB_TOKEN: typeof RIG_BAKED_GITHUB_TOKEN !== "undefined" ? RIG_BAKED_GITHUB_TOKEN : "",
|
|
1668
|
-
GITHUB_SSH_KEY: typeof RIG_BAKED_GITHUB_SSH_KEY !== "undefined" ? RIG_BAKED_GITHUB_SSH_KEY : "",
|
|
1669
|
-
AWS_ACCESS_KEY_ID: typeof RIG_BAKED_AWS_ACCESS_KEY_ID !== "undefined" ? RIG_BAKED_AWS_ACCESS_KEY_ID : "",
|
|
1670
|
-
AWS_SECRET_ACCESS_KEY: typeof RIG_BAKED_AWS_SECRET_ACCESS_KEY !== "undefined" ? RIG_BAKED_AWS_SECRET_ACCESS_KEY : "",
|
|
1671
|
-
AWS_REGION: typeof RIG_BAKED_AWS_REGION !== "undefined" ? RIG_BAKED_AWS_REGION : "",
|
|
1672
|
-
LINEAR_API_KEY: typeof RIG_BAKED_LINEAR_API_KEY !== "undefined" ? RIG_BAKED_LINEAR_API_KEY : "",
|
|
1673
|
-
LINEAR_WEBHOOK_SECRET: typeof RIG_BAKED_LINEAR_WEBHOOK_SECRET !== "undefined" ? RIG_BAKED_LINEAR_WEBHOOK_SECRET : ""
|
|
1674
|
-
};
|
|
1675
|
-
function resolveRuntimeSecrets(env, baked = BAKED_RUNTIME_SECRETS) {
|
|
1676
|
-
const resolved = {};
|
|
1677
|
-
const keys = new Set([
|
|
1678
|
-
...Object.keys(BAKED_RUNTIME_SECRETS),
|
|
1679
|
-
...Object.keys(baked)
|
|
1680
|
-
]);
|
|
1681
|
-
for (const key of keys) {
|
|
1682
|
-
const envValue = env[key]?.trim();
|
|
1683
|
-
const bakedValue = baked[key]?.trim();
|
|
1684
|
-
if (envValue) {
|
|
1685
|
-
resolved[key] = envValue;
|
|
1686
|
-
} else if (bakedValue) {
|
|
1687
|
-
resolved[key] = bakedValue;
|
|
1688
|
-
}
|
|
1689
|
-
}
|
|
1690
|
-
return resolved;
|
|
1691
|
-
}
|
|
1692
|
-
function loadDotEnvSecrets(projectRoot, env = process.env) {
|
|
1693
|
-
const dotenvPath = resolve8(projectRoot, ".env");
|
|
1694
|
-
if (!existsSync7(dotenvPath)) {
|
|
1695
|
-
return {};
|
|
1696
|
-
}
|
|
1697
|
-
const parsed = {};
|
|
1698
|
-
const lines = readFileSync4(dotenvPath, "utf-8").split(/\r?\n/);
|
|
1699
|
-
for (const rawLine of lines) {
|
|
1700
|
-
const line = rawLine.trim();
|
|
1701
|
-
if (!line || line.startsWith("#")) {
|
|
1702
|
-
continue;
|
|
1703
|
-
}
|
|
1704
|
-
const exportMatch = line.match(/^(?:export\s+)?([A-Z0-9_]+)\s*=\s*(.*)$/);
|
|
1705
|
-
if (!exportMatch) {
|
|
1706
|
-
continue;
|
|
1707
|
-
}
|
|
1708
|
-
const key = exportMatch[1];
|
|
1709
|
-
if (!(key in BAKED_RUNTIME_SECRETS)) {
|
|
1710
|
-
continue;
|
|
1711
|
-
}
|
|
1712
|
-
const value = expandShellValue(exportMatch[2] ?? "", { ...env, ...parsed });
|
|
1713
|
-
if (value) {
|
|
1714
|
-
parsed[key] = value;
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
return parsed;
|
|
1718
|
-
}
|
|
1719
|
-
function expandShellValue(rawValue, env) {
|
|
1720
|
-
let value = rawValue.trim();
|
|
1721
|
-
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
1722
|
-
value = value.slice(1, -1);
|
|
1723
|
-
}
|
|
1724
|
-
return value.replace(/\$\{([A-Z0-9_]+)(:-([^}]*))?\}/g, (_match, name, _defaultGroup, fallback) => {
|
|
1725
|
-
const envValue = env[name]?.trim();
|
|
1726
|
-
if (envValue) {
|
|
1727
|
-
return envValue;
|
|
1728
|
-
}
|
|
1729
|
-
return fallback ?? "";
|
|
1730
|
-
});
|
|
1731
|
-
}
|
|
1732
|
-
|
|
1733
1338
|
// packages/runtime/src/control-plane/native/task-ops.ts
|
|
1734
|
-
import { appendFileSync, existsSync as existsSync19, mkdirSync as
|
|
1735
|
-
import { resolve as
|
|
1339
|
+
import { appendFileSync, existsSync as existsSync19, mkdirSync as mkdirSync11, readFileSync as readFileSync11, writeFileSync as writeFileSync11 } from "fs";
|
|
1340
|
+
import { resolve as resolve22 } from "path";
|
|
1736
1341
|
|
|
1737
1342
|
// packages/runtime/src/build-time-config.ts
|
|
1738
1343
|
function normalizeBuildConfig(value) {
|
|
@@ -1758,14 +1363,14 @@ function readBuildConfig() {
|
|
|
1758
1363
|
|
|
1759
1364
|
// packages/runtime/src/control-plane/runtime/tooling/shell.ts
|
|
1760
1365
|
import { tmpdir as tmpdir2 } from "os";
|
|
1761
|
-
import { basename as
|
|
1762
|
-
var sharedNativeShellOutputDir =
|
|
1763
|
-
var sharedNativeShellOutputPath =
|
|
1366
|
+
import { basename as basename2, dirname as dirname4, resolve as resolve7 } from "path";
|
|
1367
|
+
var sharedNativeShellOutputDir = resolve7(tmpdir2(), "rig-native");
|
|
1368
|
+
var sharedNativeShellOutputPath = resolve7(sharedNativeShellOutputDir, `rig-shell-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
1764
1369
|
// packages/runtime/src/control-plane/runtime/tooling/file-tools.ts
|
|
1765
1370
|
import { tmpdir as tmpdir3 } from "os";
|
|
1766
|
-
import { basename as
|
|
1767
|
-
var sharedNativeToolsOutputDir =
|
|
1768
|
-
var sharedNativeToolsOutputPath =
|
|
1371
|
+
import { basename as basename3, dirname as dirname5, resolve as resolve8 } from "path";
|
|
1372
|
+
var sharedNativeToolsOutputDir = resolve8(tmpdir3(), "rig-native");
|
|
1373
|
+
var sharedNativeToolsOutputPath = resolve8(sharedNativeToolsOutputDir, `rig-tools-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
1769
1374
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
1770
1375
|
import { createPluginHost } from "@rig/core";
|
|
1771
1376
|
import { loadConfig } from "@rig/core/load-config";
|
|
@@ -1912,7 +1517,7 @@ function createTaskFieldRegistry(extensions) {
|
|
|
1912
1517
|
}
|
|
1913
1518
|
|
|
1914
1519
|
// packages/runtime/src/control-plane/validators/runtime-registration.ts
|
|
1915
|
-
import { existsSync as
|
|
1520
|
+
import { existsSync as existsSync7 } from "fs";
|
|
1916
1521
|
import { join } from "path";
|
|
1917
1522
|
function createValidatorRegistry() {
|
|
1918
1523
|
const map = new Map;
|
|
@@ -1945,7 +1550,7 @@ function registerBuiltInValidators(registry) {
|
|
|
1945
1550
|
}
|
|
1946
1551
|
async function runStdTypecheck(ctx) {
|
|
1947
1552
|
const packageJsonPath = join(ctx.workspaceRoot, "package.json");
|
|
1948
|
-
if (!
|
|
1553
|
+
if (!existsSync7(packageJsonPath)) {
|
|
1949
1554
|
return {
|
|
1950
1555
|
id: "std:typecheck",
|
|
1951
1556
|
passed: false,
|
|
@@ -1973,8 +1578,8 @@ async function runStdTypecheck(ctx) {
|
|
|
1973
1578
|
}
|
|
1974
1579
|
|
|
1975
1580
|
// packages/runtime/src/control-plane/hook-materializer.ts
|
|
1976
|
-
import { existsSync as
|
|
1977
|
-
import { dirname as
|
|
1581
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
|
|
1582
|
+
import { dirname as dirname6, resolve as resolve9 } from "path";
|
|
1978
1583
|
var MARKER_PLUGIN = "_rigPlugin";
|
|
1979
1584
|
var MARKER_HOOK_ID = "_rigHookId";
|
|
1980
1585
|
function matcherToString(matcher) {
|
|
@@ -1988,8 +1593,8 @@ function isPluginOwned(cmd) {
|
|
|
1988
1593
|
return typeof cmd[MARKER_PLUGIN] === "string";
|
|
1989
1594
|
}
|
|
1990
1595
|
function materializeHooks(projectRoot, entries) {
|
|
1991
|
-
const settingsPath =
|
|
1992
|
-
const existing =
|
|
1596
|
+
const settingsPath = resolve9(projectRoot, ".claude", "settings.json");
|
|
1597
|
+
const existing = existsSync8(settingsPath) ? safeReadJson(settingsPath) : {};
|
|
1993
1598
|
const hooks = existing.hooks ?? {};
|
|
1994
1599
|
for (const event of Object.keys(hooks)) {
|
|
1995
1600
|
const groups = hooks[event] ?? [];
|
|
@@ -2031,7 +1636,7 @@ function materializeHooks(projectRoot, entries) {
|
|
|
2031
1636
|
} else {
|
|
2032
1637
|
delete next.hooks;
|
|
2033
1638
|
}
|
|
2034
|
-
mkdirSync3(
|
|
1639
|
+
mkdirSync3(dirname6(settingsPath), { recursive: true });
|
|
2035
1640
|
writeFileSync2(settingsPath, `${JSON.stringify(next, null, 2)}
|
|
2036
1641
|
`, "utf-8");
|
|
2037
1642
|
return settingsPath;
|
|
@@ -2044,6 +1649,49 @@ function safeReadJson(path) {
|
|
|
2044
1649
|
}
|
|
2045
1650
|
}
|
|
2046
1651
|
|
|
1652
|
+
// packages/runtime/src/control-plane/skill-materializer.ts
|
|
1653
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync6, readdirSync, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
1654
|
+
import { resolve as resolve10 } from "path";
|
|
1655
|
+
import { loadSkill } from "@rig/skill-loader";
|
|
1656
|
+
var MARKER_FILENAME = ".rig-plugin";
|
|
1657
|
+
function skillDirName(id) {
|
|
1658
|
+
return id.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
1659
|
+
}
|
|
1660
|
+
async function materializeSkills(projectRoot, entries) {
|
|
1661
|
+
const skillsRoot = resolve10(projectRoot, ".pi", "skills");
|
|
1662
|
+
if (existsSync9(skillsRoot)) {
|
|
1663
|
+
for (const name of readdirSync(skillsRoot)) {
|
|
1664
|
+
const dir = resolve10(skillsRoot, name);
|
|
1665
|
+
if (existsSync9(resolve10(dir, MARKER_FILENAME))) {
|
|
1666
|
+
rmSync2(dir, { recursive: true, force: true });
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
const written = [];
|
|
1671
|
+
for (const { pluginName, skill } of entries) {
|
|
1672
|
+
const sourcePath = resolve10(projectRoot, skill.path);
|
|
1673
|
+
if (!existsSync9(sourcePath)) {
|
|
1674
|
+
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${sourcePath} does not exist`);
|
|
1675
|
+
continue;
|
|
1676
|
+
}
|
|
1677
|
+
let body;
|
|
1678
|
+
try {
|
|
1679
|
+
await loadSkill(sourcePath);
|
|
1680
|
+
body = readFileSync6(sourcePath, "utf-8");
|
|
1681
|
+
} catch (err) {
|
|
1682
|
+
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${err instanceof Error ? err.message : err}`);
|
|
1683
|
+
continue;
|
|
1684
|
+
}
|
|
1685
|
+
const dir = resolve10(skillsRoot, skillDirName(skill.id));
|
|
1686
|
+
mkdirSync4(dir, { recursive: true });
|
|
1687
|
+
writeFileSync3(resolve10(dir, "SKILL.md"), body, "utf-8");
|
|
1688
|
+
writeFileSync3(resolve10(dir, MARKER_FILENAME), `${JSON.stringify({ plugin: pluginName, skillId: skill.id }, null, 2)}
|
|
1689
|
+
`, "utf-8");
|
|
1690
|
+
written.push({ id: skill.id, pluginName, directory: dir });
|
|
1691
|
+
}
|
|
1692
|
+
return written;
|
|
1693
|
+
}
|
|
1694
|
+
|
|
2047
1695
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
2048
1696
|
async function buildPluginHostContext(projectRoot) {
|
|
2049
1697
|
let config;
|
|
@@ -2080,6 +1728,17 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
2080
1728
|
} catch (err) {
|
|
2081
1729
|
console.warn(`[plugin-host] hook materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
2082
1730
|
}
|
|
1731
|
+
try {
|
|
1732
|
+
const skillEntries = config.plugins.flatMap((plugin) => (plugin.contributes?.skills ?? []).map((skill) => ({
|
|
1733
|
+
pluginName: plugin.name,
|
|
1734
|
+
skill
|
|
1735
|
+
})));
|
|
1736
|
+
if (skillEntries.length > 0) {
|
|
1737
|
+
await materializeSkills(projectRoot, skillEntries);
|
|
1738
|
+
}
|
|
1739
|
+
} catch (err) {
|
|
1740
|
+
console.warn(`[plugin-host] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
1741
|
+
}
|
|
2083
1742
|
return {
|
|
2084
1743
|
config,
|
|
2085
1744
|
pluginHost,
|
|
@@ -2093,12 +1752,12 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
2093
1752
|
|
|
2094
1753
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
2095
1754
|
import { spawnSync } from "child_process";
|
|
2096
|
-
import { existsSync as existsSync11, readFileSync as
|
|
2097
|
-
import { basename as
|
|
1755
|
+
import { existsSync as existsSync11, readFileSync as readFileSync8, readdirSync as readdirSync2, statSync as statSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
1756
|
+
import { basename as basename4, join as join2, resolve as resolve12 } from "path";
|
|
2098
1757
|
|
|
2099
1758
|
// packages/runtime/src/control-plane/tasks/legacy-task-config-source.ts
|
|
2100
|
-
import { existsSync as existsSync10, readFileSync as
|
|
2101
|
-
import { resolve as
|
|
1759
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
|
|
1760
|
+
import { resolve as resolve11 } from "path";
|
|
2102
1761
|
|
|
2103
1762
|
// packages/runtime/src/control-plane/tasks/task-record-reader.ts
|
|
2104
1763
|
async function findTaskById(reader, id) {
|
|
@@ -2121,7 +1780,7 @@ class LegacyTaskConfigReadError extends Error {
|
|
|
2121
1780
|
}
|
|
2122
1781
|
}
|
|
2123
1782
|
function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
2124
|
-
const configPath = options.configPath ??
|
|
1783
|
+
const configPath = options.configPath ?? resolve11(projectRoot, ".rig", "task-config.json");
|
|
2125
1784
|
const reader = {
|
|
2126
1785
|
async listTasks() {
|
|
2127
1786
|
return readLegacyTaskRecords(projectRoot, configPath);
|
|
@@ -2132,7 +1791,7 @@ function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
|
2132
1791
|
};
|
|
2133
1792
|
return reader;
|
|
2134
1793
|
}
|
|
2135
|
-
function readLegacyTaskRecords(projectRoot, configPath =
|
|
1794
|
+
function readLegacyTaskRecords(projectRoot, configPath = resolve11(projectRoot, ".rig", "task-config.json")) {
|
|
2136
1795
|
if (!existsSync10(configPath)) {
|
|
2137
1796
|
return [];
|
|
2138
1797
|
}
|
|
@@ -2141,7 +1800,7 @@ function readLegacyTaskRecords(projectRoot, configPath = resolve12(projectRoot,
|
|
|
2141
1800
|
}
|
|
2142
1801
|
function readLegacyTaskConfigJson(projectRoot, configPath) {
|
|
2143
1802
|
try {
|
|
2144
|
-
const parsed = JSON.parse(
|
|
1803
|
+
const parsed = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
2145
1804
|
if (isPlainRecord(parsed)) {
|
|
2146
1805
|
return parsed;
|
|
2147
1806
|
}
|
|
@@ -2225,7 +1884,7 @@ function isPlainRecord(candidate) {
|
|
|
2225
1884
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
2226
1885
|
var FILE_TASK_PATTERN = /\.(task\.)?json$/;
|
|
2227
1886
|
function createSourceAwareTaskConfigRecordReader(projectRoot, options = {}) {
|
|
2228
|
-
const configPath = options.configPath ??
|
|
1887
|
+
const configPath = options.configPath ?? resolve12(projectRoot, ".rig", "task-config.json");
|
|
2229
1888
|
const legacy = createLegacyTaskConfigRecordReader(projectRoot, { configPath });
|
|
2230
1889
|
const spawnFn = options.spawn ?? spawnSync;
|
|
2231
1890
|
const ghBinary = options.ghBinary ?? "gh";
|
|
@@ -2291,7 +1950,7 @@ async function readSourceAwareTaskStatus(projectRoot, taskId, options = {}) {
|
|
|
2291
1950
|
}
|
|
2292
1951
|
}
|
|
2293
1952
|
function updateSourceAwareTaskConfigTask(projectRoot, taskId, update, options = {}) {
|
|
2294
|
-
const configPath = options.configPath ??
|
|
1953
|
+
const configPath = options.configPath ?? resolve12(projectRoot, ".rig", "task-config.json");
|
|
2295
1954
|
const rawEntry = readRawTaskEntry(configPath, taskId);
|
|
2296
1955
|
if (!rawEntry) {
|
|
2297
1956
|
const configuredFilesPath = readConfiguredFilesTaskSourcePath(projectRoot);
|
|
@@ -2344,10 +2003,10 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
2344
2003
|
return metadata;
|
|
2345
2004
|
}
|
|
2346
2005
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
2347
|
-
const jsonPath =
|
|
2006
|
+
const jsonPath = resolve12(projectRoot, "rig.config.json");
|
|
2348
2007
|
if (existsSync11(jsonPath)) {
|
|
2349
2008
|
try {
|
|
2350
|
-
const parsed = JSON.parse(
|
|
2009
|
+
const parsed = JSON.parse(readFileSync8(jsonPath, "utf8"));
|
|
2351
2010
|
if (isPlainRecord2(parsed) && isPlainRecord2(parsed.taskSource)) {
|
|
2352
2011
|
const source = parsed.taskSource;
|
|
2353
2012
|
return source.kind === "files" && typeof source.path === "string" ? source.path : null;
|
|
@@ -2356,12 +2015,12 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
2356
2015
|
return null;
|
|
2357
2016
|
}
|
|
2358
2017
|
}
|
|
2359
|
-
const tsPath =
|
|
2018
|
+
const tsPath = resolve12(projectRoot, "rig.config.ts");
|
|
2360
2019
|
if (!existsSync11(tsPath)) {
|
|
2361
2020
|
return null;
|
|
2362
2021
|
}
|
|
2363
2022
|
try {
|
|
2364
|
-
const source =
|
|
2023
|
+
const source = readFileSync8(tsPath, "utf8");
|
|
2365
2024
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
2366
2025
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
2367
2026
|
if (kind !== "files") {
|
|
@@ -2384,7 +2043,7 @@ function readRawTaskConfig(configPath) {
|
|
|
2384
2043
|
if (!existsSync11(configPath)) {
|
|
2385
2044
|
return null;
|
|
2386
2045
|
}
|
|
2387
|
-
const parsed = JSON.parse(
|
|
2046
|
+
const parsed = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
2388
2047
|
return isPlainRecord2(parsed) ? parsed : null;
|
|
2389
2048
|
}
|
|
2390
2049
|
function stripLegacyTaskConfigMetadata2(raw) {
|
|
@@ -2401,16 +2060,16 @@ function writeLegacyTaskStatus(configPath, taskId, status) {
|
|
|
2401
2060
|
return;
|
|
2402
2061
|
}
|
|
2403
2062
|
entry.status = status;
|
|
2404
|
-
|
|
2063
|
+
writeFileSync4(configPath, `${JSON.stringify(rawConfig, null, 2)}
|
|
2405
2064
|
`, "utf8");
|
|
2406
2065
|
}
|
|
2407
2066
|
function updateFileBackedTask(projectRoot, sourcePath, taskId, update) {
|
|
2408
|
-
const directory =
|
|
2067
|
+
const directory = resolve12(projectRoot, sourcePath);
|
|
2409
2068
|
const file = findFileBackedTaskFile(directory, taskId);
|
|
2410
2069
|
if (!file) {
|
|
2411
2070
|
return false;
|
|
2412
2071
|
}
|
|
2413
|
-
const raw = JSON.parse(
|
|
2072
|
+
const raw = JSON.parse(readFileSync8(file, "utf8"));
|
|
2414
2073
|
if (!isPlainRecord2(raw)) {
|
|
2415
2074
|
return false;
|
|
2416
2075
|
}
|
|
@@ -2427,12 +2086,12 @@ function updateFileBackedTask(projectRoot, sourcePath, taskId, update) {
|
|
|
2427
2086
|
{ body: update.comment, createdAt: new Date().toISOString(), source: "rig" }
|
|
2428
2087
|
];
|
|
2429
2088
|
}
|
|
2430
|
-
|
|
2089
|
+
writeFileSync4(file, `${JSON.stringify(raw, null, 2)}
|
|
2431
2090
|
`, "utf8");
|
|
2432
2091
|
return true;
|
|
2433
2092
|
}
|
|
2434
2093
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
2435
|
-
const directory =
|
|
2094
|
+
const directory = resolve12(projectRoot, sourcePath);
|
|
2436
2095
|
if (!existsSync11(directory)) {
|
|
2437
2096
|
return [];
|
|
2438
2097
|
}
|
|
@@ -2440,7 +2099,7 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
2440
2099
|
for (const name of readdirSync2(directory)) {
|
|
2441
2100
|
if (!FILE_TASK_PATTERN.test(name))
|
|
2442
2101
|
continue;
|
|
2443
|
-
const inferredId =
|
|
2102
|
+
const inferredId = basename4(name).replace(FILE_TASK_PATTERN, "");
|
|
2444
2103
|
const task = readFileBackedTask(projectRoot, sourcePath, inferredId, {});
|
|
2445
2104
|
if (task)
|
|
2446
2105
|
tasks.push(task);
|
|
@@ -2448,11 +2107,11 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
2448
2107
|
return tasks;
|
|
2449
2108
|
}
|
|
2450
2109
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
2451
|
-
const file = findFileBackedTaskFile(
|
|
2110
|
+
const file = findFileBackedTaskFile(resolve12(projectRoot, sourcePath), taskId);
|
|
2452
2111
|
if (!file) {
|
|
2453
2112
|
return null;
|
|
2454
2113
|
}
|
|
2455
|
-
const raw = JSON.parse(
|
|
2114
|
+
const raw = JSON.parse(readFileSync8(file, "utf8"));
|
|
2456
2115
|
if (!isPlainRecord2(raw)) {
|
|
2457
2116
|
return null;
|
|
2458
2117
|
}
|
|
@@ -2475,8 +2134,8 @@ function findFileBackedTaskFile(directory, taskId) {
|
|
|
2475
2134
|
try {
|
|
2476
2135
|
if (!statSync3(file).isFile())
|
|
2477
2136
|
continue;
|
|
2478
|
-
const raw = JSON.parse(
|
|
2479
|
-
const inferredId =
|
|
2137
|
+
const raw = JSON.parse(readFileSync8(file, "utf8"));
|
|
2138
|
+
const inferredId = basename4(file).replace(FILE_TASK_PATTERN, "");
|
|
2480
2139
|
const id = isPlainRecord2(raw) && typeof raw.id === "string" ? raw.id : inferredId;
|
|
2481
2140
|
if (id === taskId) {
|
|
2482
2141
|
return file;
|
|
@@ -2824,8 +2483,8 @@ function buildTaskRunLifecycleComment(input) {
|
|
|
2824
2483
|
}
|
|
2825
2484
|
|
|
2826
2485
|
// packages/runtime/src/control-plane/native/task-state.ts
|
|
2827
|
-
import { existsSync as existsSync13, readFileSync as
|
|
2828
|
-
import { basename as
|
|
2486
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10, readdirSync as readdirSync3, statSync as statSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
2487
|
+
import { basename as basename5, resolve as resolve14 } from "path";
|
|
2829
2488
|
|
|
2830
2489
|
// packages/runtime/src/control-plane/state-sync/types.ts
|
|
2831
2490
|
var CANONICAL_TASK_LIFECYCLE_STATUSES = new Set([
|
|
@@ -2840,23 +2499,23 @@ var CANONICAL_TASK_LIFECYCLE_STATUSES = new Set([
|
|
|
2840
2499
|
"cancelled"
|
|
2841
2500
|
]);
|
|
2842
2501
|
// packages/runtime/src/control-plane/native/git-native.ts
|
|
2843
|
-
import { chmodSync, copyFileSync as copyFileSync2, existsSync as existsSync12, mkdirSync as
|
|
2502
|
+
import { chmodSync, copyFileSync as copyFileSync2, existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync9, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
2844
2503
|
import { tmpdir as tmpdir4 } from "os";
|
|
2845
|
-
import { dirname as
|
|
2504
|
+
import { dirname as dirname7, isAbsolute, resolve as resolve13 } from "path";
|
|
2846
2505
|
import { createHash } from "crypto";
|
|
2847
|
-
var sharedGitNativeOutputDir =
|
|
2848
|
-
var sharedGitNativeOutputPath =
|
|
2506
|
+
var sharedGitNativeOutputDir = resolve13(tmpdir4(), "rig-native");
|
|
2507
|
+
var sharedGitNativeOutputPath = resolve13(sharedGitNativeOutputDir, `rig-git-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
2849
2508
|
var trackerCommandUsageProbe = "usage: rig-git fetch-ref <repo-path> <remote> <branch>";
|
|
2850
2509
|
function temporaryGitBinaryOutputPath(outputPath) {
|
|
2851
2510
|
const suffix2 = process.platform === "win32" ? ".exe" : "";
|
|
2852
|
-
return
|
|
2511
|
+
return resolve13(dirname7(outputPath), `.rig-git-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}${suffix2}`);
|
|
2853
2512
|
}
|
|
2854
2513
|
function publishGitBinary(tempOutputPath, outputPath) {
|
|
2855
2514
|
try {
|
|
2856
2515
|
renameSync2(tempOutputPath, outputPath);
|
|
2857
2516
|
} catch (error) {
|
|
2858
2517
|
if (process.platform === "win32" && existsSync12(outputPath)) {
|
|
2859
|
-
|
|
2518
|
+
rmSync3(outputPath, { force: true });
|
|
2860
2519
|
renameSync2(tempOutputPath, outputPath);
|
|
2861
2520
|
return;
|
|
2862
2521
|
}
|
|
@@ -2867,27 +2526,27 @@ function runtimeRigGitFileName() {
|
|
|
2867
2526
|
return `rig-git${process.platform === "win32" ? ".exe" : ""}`;
|
|
2868
2527
|
}
|
|
2869
2528
|
function rigGitSourceCandidates() {
|
|
2870
|
-
const execDir = process.execPath?.trim() ?
|
|
2529
|
+
const execDir = process.execPath?.trim() ? dirname7(process.execPath.trim()) : "";
|
|
2871
2530
|
const cwd = process.cwd()?.trim() || "";
|
|
2872
2531
|
const projectRoot = process.env.PROJECT_RIG_ROOT?.trim() || "";
|
|
2873
2532
|
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || "";
|
|
2874
|
-
const moduleRelativeSource =
|
|
2533
|
+
const moduleRelativeSource = resolve13(import.meta.dir, "../../../native/rig-git.zig");
|
|
2875
2534
|
return [...new Set([
|
|
2876
2535
|
process.env.RIG_NATIVE_GIT_SOURCE?.trim() || "",
|
|
2877
2536
|
moduleRelativeSource,
|
|
2878
|
-
projectRoot ?
|
|
2879
|
-
hostProjectRoot ?
|
|
2880
|
-
cwd ?
|
|
2881
|
-
execDir ?
|
|
2882
|
-
execDir ?
|
|
2537
|
+
projectRoot ? resolve13(projectRoot, "packages/runtime/native/rig-git.zig") : "",
|
|
2538
|
+
hostProjectRoot ? resolve13(hostProjectRoot, "packages/runtime/native/rig-git.zig") : "",
|
|
2539
|
+
cwd ? resolve13(cwd, "packages/runtime/native/rig-git.zig") : "",
|
|
2540
|
+
execDir ? resolve13(execDir, "..", "..", "packages/runtime/native/rig-git.zig") : "",
|
|
2541
|
+
execDir ? resolve13(execDir, "..", "native", "rig-git.zig") : ""
|
|
2883
2542
|
].filter(Boolean))];
|
|
2884
2543
|
}
|
|
2885
2544
|
function nativePackageBinaryCandidates(fromDir, fileName) {
|
|
2886
2545
|
const candidates = [];
|
|
2887
|
-
let cursor =
|
|
2546
|
+
let cursor = resolve13(fromDir);
|
|
2888
2547
|
for (let index = 0;index < 8; index += 1) {
|
|
2889
|
-
candidates.push(
|
|
2890
|
-
const parent =
|
|
2548
|
+
candidates.push(resolve13(cursor, "native", `${process.platform}-${process.arch}`, fileName), resolve13(cursor, "native", `${process.platform}-${process.arch}`, "bin", fileName), resolve13(cursor, "native", fileName), resolve13(cursor, "native", "bin", fileName));
|
|
2549
|
+
const parent = dirname7(cursor);
|
|
2891
2550
|
if (parent === cursor)
|
|
2892
2551
|
break;
|
|
2893
2552
|
cursor = parent;
|
|
@@ -2895,15 +2554,15 @@ function nativePackageBinaryCandidates(fromDir, fileName) {
|
|
|
2895
2554
|
return candidates;
|
|
2896
2555
|
}
|
|
2897
2556
|
function rigGitBinaryCandidates() {
|
|
2898
|
-
const execDir = process.execPath?.trim() ?
|
|
2557
|
+
const execDir = process.execPath?.trim() ? dirname7(process.execPath.trim()) : "";
|
|
2899
2558
|
const fileName = runtimeRigGitFileName();
|
|
2900
2559
|
const explicit = process.env.RIG_NATIVE_GIT_BIN?.trim() || "";
|
|
2901
2560
|
return [...new Set([
|
|
2902
2561
|
explicit,
|
|
2903
2562
|
...nativePackageBinaryCandidates(import.meta.dir, fileName),
|
|
2904
|
-
execDir ?
|
|
2905
|
-
execDir ?
|
|
2906
|
-
execDir ?
|
|
2563
|
+
execDir ? resolve13(execDir, fileName) : "",
|
|
2564
|
+
execDir ? resolve13(execDir, "..", fileName) : "",
|
|
2565
|
+
execDir ? resolve13(execDir, "..", "bin", fileName) : "",
|
|
2907
2566
|
sharedGitNativeOutputPath
|
|
2908
2567
|
].filter(Boolean))];
|
|
2909
2568
|
}
|
|
@@ -2954,14 +2613,14 @@ function hasMatchingNativeBuildManifestSync(manifestPath, buildKey) {
|
|
|
2954
2613
|
return false;
|
|
2955
2614
|
}
|
|
2956
2615
|
try {
|
|
2957
|
-
const manifest = JSON.parse(
|
|
2616
|
+
const manifest = JSON.parse(readFileSync9(manifestPath, "utf8"));
|
|
2958
2617
|
return manifest.version === 1 && manifest.buildKey === buildKey;
|
|
2959
2618
|
} catch {
|
|
2960
2619
|
return false;
|
|
2961
2620
|
}
|
|
2962
2621
|
}
|
|
2963
2622
|
function sha256FileSync(path) {
|
|
2964
|
-
return createHash("sha256").update(
|
|
2623
|
+
return createHash("sha256").update(readFileSync9(path)).digest("hex");
|
|
2965
2624
|
}
|
|
2966
2625
|
function ensureRigGitBinaryPathSync(outputPath = preferredGitBinaryOutputPath()) {
|
|
2967
2626
|
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
@@ -2979,7 +2638,7 @@ function ensureRigGitBinaryPathSync(outputPath = preferredGitBinaryOutputPath())
|
|
|
2979
2638
|
if (!zigBinary) {
|
|
2980
2639
|
throw new Error("zig is required to build native Rig git tools.");
|
|
2981
2640
|
}
|
|
2982
|
-
|
|
2641
|
+
mkdirSync5(dirname7(outputPath), { recursive: true });
|
|
2983
2642
|
const sourceDigest = sha256FileSync(sourcePath);
|
|
2984
2643
|
const buildKey = JSON.stringify({
|
|
2985
2644
|
version: 1,
|
|
@@ -3004,7 +2663,7 @@ function ensureRigGitBinaryPathSync(outputPath = preferredGitBinaryOutputPath())
|
|
|
3004
2663
|
"ReleaseFast",
|
|
3005
2664
|
`-femit-bin=${tempOutputPath}`
|
|
3006
2665
|
], {
|
|
3007
|
-
cwd:
|
|
2666
|
+
cwd: dirname7(sourcePath),
|
|
3008
2667
|
stdout: "pipe",
|
|
3009
2668
|
stderr: "pipe"
|
|
3010
2669
|
});
|
|
@@ -3017,16 +2676,16 @@ function ensureRigGitBinaryPathSync(outputPath = preferredGitBinaryOutputPath())
|
|
|
3017
2676
|
}
|
|
3018
2677
|
chmodSync(tempOutputPath, 493);
|
|
3019
2678
|
if (existsSync12(outputPath) && hasMatchingNativeBuildManifestSync(manifestPath, buildKey)) {
|
|
3020
|
-
|
|
2679
|
+
rmSync3(tempOutputPath, { force: true });
|
|
3021
2680
|
chmodSync(outputPath, 493);
|
|
3022
2681
|
return outputPath;
|
|
3023
2682
|
}
|
|
3024
2683
|
publishGitBinary(tempOutputPath, outputPath);
|
|
3025
2684
|
if (!binarySupportsTrackerCommandsSync(outputPath)) {
|
|
3026
|
-
|
|
2685
|
+
rmSync3(outputPath, { force: true });
|
|
3027
2686
|
throw new Error("Failed to build native Rig git tools: tracker command probe failed");
|
|
3028
2687
|
}
|
|
3029
|
-
|
|
2688
|
+
writeFileSync5(manifestPath, `${JSON.stringify({ version: 1, buildKey }, null, 2)}
|
|
3030
2689
|
`, "utf8");
|
|
3031
2690
|
return outputPath;
|
|
3032
2691
|
}
|
|
@@ -3135,7 +2794,7 @@ function readValidationDescriptions(projectRoot) {
|
|
|
3135
2794
|
return readValidationDescriptionMap(raw);
|
|
3136
2795
|
}
|
|
3137
2796
|
function readSourceValidationDescriptions(projectRoot) {
|
|
3138
|
-
const rootRaw = readJsonFile(
|
|
2797
|
+
const rootRaw = readJsonFile(resolve14(projectRoot, "rig", "task-config.json"), {});
|
|
3139
2798
|
const sourcePath = findSourceTaskConfigPath(projectRoot);
|
|
3140
2799
|
const sourceRaw = sourcePath ? readJsonFile(sourcePath, {}) : {};
|
|
3141
2800
|
const rootDescriptions = readValidationDescriptionMap(rootRaw);
|
|
@@ -3226,16 +2885,16 @@ function lookupTask(projectRoot, input) {
|
|
|
3226
2885
|
function artifactDirForId(projectRoot, id) {
|
|
3227
2886
|
const workspaceDir = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
3228
2887
|
if (workspaceDir) {
|
|
3229
|
-
const worktreeArtifacts =
|
|
3230
|
-
if (existsSync13(worktreeArtifacts) || existsSync13(
|
|
2888
|
+
const worktreeArtifacts = resolve14(workspaceDir, "artifacts", id);
|
|
2889
|
+
if (existsSync13(worktreeArtifacts) || existsSync13(resolve14(workspaceDir, "artifacts"))) {
|
|
3231
2890
|
return worktreeArtifacts;
|
|
3232
2891
|
}
|
|
3233
2892
|
}
|
|
3234
2893
|
try {
|
|
3235
2894
|
const paths = resolveHarnessPaths(projectRoot);
|
|
3236
|
-
return
|
|
2895
|
+
return resolve14(paths.artifactsDir, id);
|
|
3237
2896
|
} catch {
|
|
3238
|
-
return
|
|
2897
|
+
return resolve14(resolveMonorepoRoot2(projectRoot), "artifacts", id);
|
|
3239
2898
|
}
|
|
3240
2899
|
}
|
|
3241
2900
|
function resolveTaskConfigPath(projectRoot) {
|
|
@@ -3265,7 +2924,7 @@ function readAndSyncSourceTaskConfig(projectRoot) {
|
|
|
3265
2924
|
const synced = synchronizeTaskConfigWithTracker(projectRoot, raw);
|
|
3266
2925
|
if (sourcePath && synced.updated) {
|
|
3267
2926
|
try {
|
|
3268
|
-
|
|
2927
|
+
writeFileSync6(sourcePath, `${JSON.stringify(synced.config, null, 2)}
|
|
3269
2928
|
`, "utf-8");
|
|
3270
2929
|
} catch {}
|
|
3271
2930
|
}
|
|
@@ -3317,12 +2976,12 @@ function shouldRefreshAutoSyncedTaskConfigEntry(entry) {
|
|
|
3317
2976
|
return !candidate.role;
|
|
3318
2977
|
}
|
|
3319
2978
|
function readSourceIssueRecords(projectRoot) {
|
|
3320
|
-
const issuesPath =
|
|
2979
|
+
const issuesPath = resolve14(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
3321
2980
|
if (!existsSync13(issuesPath)) {
|
|
3322
2981
|
return [];
|
|
3323
2982
|
}
|
|
3324
2983
|
const records = [];
|
|
3325
|
-
for (const line of
|
|
2984
|
+
for (const line of readFileSync10(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
3326
2985
|
const trimmed = line.trim();
|
|
3327
2986
|
if (!trimmed) {
|
|
3328
2987
|
continue;
|
|
@@ -3378,7 +3037,7 @@ function readConfiguredFileTaskConfig(projectRoot) {
|
|
|
3378
3037
|
if (!sourcePath) {
|
|
3379
3038
|
return {};
|
|
3380
3039
|
}
|
|
3381
|
-
const directory =
|
|
3040
|
+
const directory = resolve14(projectRoot, sourcePath);
|
|
3382
3041
|
if (!existsSync13(directory)) {
|
|
3383
3042
|
return {};
|
|
3384
3043
|
}
|
|
@@ -3386,15 +3045,15 @@ function readConfiguredFileTaskConfig(projectRoot) {
|
|
|
3386
3045
|
for (const name of readdirSync3(directory)) {
|
|
3387
3046
|
if (!FILE_TASK_PATTERN2.test(name))
|
|
3388
3047
|
continue;
|
|
3389
|
-
const file =
|
|
3048
|
+
const file = resolve14(directory, name);
|
|
3390
3049
|
try {
|
|
3391
3050
|
if (!statSync4(file).isFile())
|
|
3392
3051
|
continue;
|
|
3393
|
-
const raw = JSON.parse(
|
|
3052
|
+
const raw = JSON.parse(readFileSync10(file, "utf8"));
|
|
3394
3053
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
3395
3054
|
continue;
|
|
3396
3055
|
const record = raw;
|
|
3397
|
-
const inferredId =
|
|
3056
|
+
const inferredId = basename5(name).replace(FILE_TASK_PATTERN2, "");
|
|
3398
3057
|
const id = typeof record.id === "string" && record.id.trim().length > 0 ? record.id.trim() : inferredId;
|
|
3399
3058
|
config[id] = fileTaskToConfigEntry(record, { kind: "files", path: sourcePath });
|
|
3400
3059
|
} catch {}
|
|
@@ -3432,10 +3091,10 @@ function firstStringList2(...candidates) {
|
|
|
3432
3091
|
return [];
|
|
3433
3092
|
}
|
|
3434
3093
|
function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
3435
|
-
const jsonPath =
|
|
3094
|
+
const jsonPath = resolve14(projectRoot, "rig.config.json");
|
|
3436
3095
|
if (existsSync13(jsonPath)) {
|
|
3437
3096
|
try {
|
|
3438
|
-
const parsed = JSON.parse(
|
|
3097
|
+
const parsed = JSON.parse(readFileSync10(jsonPath, "utf8"));
|
|
3439
3098
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
3440
3099
|
const taskSource = parsed.taskSource;
|
|
3441
3100
|
if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
|
|
@@ -3447,12 +3106,12 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
3447
3106
|
return null;
|
|
3448
3107
|
}
|
|
3449
3108
|
}
|
|
3450
|
-
const tsPath =
|
|
3109
|
+
const tsPath = resolve14(projectRoot, "rig.config.ts");
|
|
3451
3110
|
if (!existsSync13(tsPath)) {
|
|
3452
3111
|
return null;
|
|
3453
3112
|
}
|
|
3454
3113
|
try {
|
|
3455
|
-
const source =
|
|
3114
|
+
const source = readFileSync10(tsPath, "utf8");
|
|
3456
3115
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
3457
3116
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
3458
3117
|
if (kind !== "files") {
|
|
@@ -3466,23 +3125,23 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
3466
3125
|
function sourceTaskConfigCandidates(projectRoot) {
|
|
3467
3126
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
3468
3127
|
return [
|
|
3469
|
-
runtimeContext?.monorepoMainRoot ?
|
|
3470
|
-
process.env.MONOREPO_MAIN_ROOT?.trim() ?
|
|
3471
|
-
|
|
3128
|
+
runtimeContext?.monorepoMainRoot ? resolve14(runtimeContext.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
3129
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve14(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
3130
|
+
resolve14(resolveMonorepoRoot2(projectRoot), ".rig", "task-config.json")
|
|
3472
3131
|
].filter(Boolean);
|
|
3473
3132
|
}
|
|
3474
3133
|
|
|
3475
3134
|
// packages/runtime/src/control-plane/native/validator.ts
|
|
3476
|
-
import { existsSync as existsSync17, mkdirSync as
|
|
3477
|
-
import { resolve as
|
|
3135
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
3136
|
+
import { resolve as resolve19 } from "path";
|
|
3478
3137
|
|
|
3479
3138
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
3480
|
-
import { existsSync as existsSync16, mkdirSync as
|
|
3481
|
-
import { dirname as
|
|
3139
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync7, rmSync as rmSync5, statSync as statSync5 } from "fs";
|
|
3140
|
+
import { dirname as dirname9, resolve as resolve18 } from "path";
|
|
3482
3141
|
|
|
3483
3142
|
// packages/runtime/src/binary-run.ts
|
|
3484
|
-
import { chmodSync as chmodSync2, cpSync, existsSync as existsSync14, mkdirSync as
|
|
3485
|
-
import { basename as
|
|
3143
|
+
import { chmodSync as chmodSync2, cpSync, existsSync as existsSync14, mkdirSync as mkdirSync6, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
3144
|
+
import { basename as basename6, dirname as dirname8, resolve as resolve15 } from "path";
|
|
3486
3145
|
import { fileURLToPath } from "url";
|
|
3487
3146
|
import { drainMicrotasks, gcAndSweep } from "bun:jsc";
|
|
3488
3147
|
var runtimeBinaryBuildQueue = Promise.resolve();
|
|
@@ -3508,9 +3167,9 @@ async function buildRuntimeBinary(options) {
|
|
|
3508
3167
|
});
|
|
3509
3168
|
}
|
|
3510
3169
|
async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
3511
|
-
const tempBuildDir =
|
|
3512
|
-
const tempOutputPath =
|
|
3513
|
-
|
|
3170
|
+
const tempBuildDir = resolve15(dirname8(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
3171
|
+
const tempOutputPath = resolve15(tempBuildDir, basename6(options.outputPath));
|
|
3172
|
+
mkdirSync6(tempBuildDir, { recursive: true });
|
|
3514
3173
|
await withTemporaryEnv({
|
|
3515
3174
|
...options.env,
|
|
3516
3175
|
...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
|
|
@@ -3550,7 +3209,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
3550
3209
|
});
|
|
3551
3210
|
}
|
|
3552
3211
|
})).finally(() => {
|
|
3553
|
-
|
|
3212
|
+
rmSync4(tempBuildDir, { recursive: true, force: true });
|
|
3554
3213
|
});
|
|
3555
3214
|
}
|
|
3556
3215
|
function runBestEffortBuildGc() {
|
|
@@ -3567,8 +3226,8 @@ function runtimeBinaryCacheManifestPath(outputPath) {
|
|
|
3567
3226
|
function resolveRuntimeBinaryBuildOptions(options) {
|
|
3568
3227
|
return {
|
|
3569
3228
|
...options,
|
|
3570
|
-
entrypoint:
|
|
3571
|
-
outputPath:
|
|
3229
|
+
entrypoint: resolve15(options.cwd, options.sourcePath),
|
|
3230
|
+
outputPath: resolve15(options.outputPath)
|
|
3572
3231
|
};
|
|
3573
3232
|
}
|
|
3574
3233
|
function shouldUseRuntimeBinaryBuildWorker() {
|
|
@@ -3613,13 +3272,13 @@ async function buildRuntimeBinaryViaWorker(options) {
|
|
|
3613
3272
|
new Response(build.stdout).text(),
|
|
3614
3273
|
new Response(build.stderr).text()
|
|
3615
3274
|
]);
|
|
3616
|
-
|
|
3275
|
+
rmSync4(payloadPath, { force: true });
|
|
3617
3276
|
if (exitCode !== 0) {
|
|
3618
3277
|
throw new Error(`Failed to build ${options.entrypoint}: ${(stderr || stdout || `worker exited ${exitCode}`).trim()}`);
|
|
3619
3278
|
}
|
|
3620
3279
|
}
|
|
3621
3280
|
function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
|
|
3622
|
-
return
|
|
3281
|
+
return resolve15(dirname8(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
3623
3282
|
}
|
|
3624
3283
|
function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
3625
3284
|
const envRoots = [
|
|
@@ -3628,12 +3287,12 @@ function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
|
3628
3287
|
process.env.PROJECT_RIG_ROOT?.trim()
|
|
3629
3288
|
].filter(Boolean);
|
|
3630
3289
|
for (const root of envRoots) {
|
|
3631
|
-
const candidate =
|
|
3290
|
+
const candidate = resolve15(root, "packages/runtime/src/binary-build-worker.ts");
|
|
3632
3291
|
if (existsSync14(candidate)) {
|
|
3633
3292
|
return candidate;
|
|
3634
3293
|
}
|
|
3635
3294
|
}
|
|
3636
|
-
const localCandidate =
|
|
3295
|
+
const localCandidate = resolve15(import.meta.dir, "binary-build-worker.ts");
|
|
3637
3296
|
return existsSync14(localCandidate) ? localCandidate : null;
|
|
3638
3297
|
}
|
|
3639
3298
|
function resolveRuntimeBinaryBuildWorkerInvocation() {
|
|
@@ -3719,7 +3378,7 @@ function normalizeBuildInputPath(cwd, inputPath) {
|
|
|
3719
3378
|
if (inputPath.startsWith("<")) {
|
|
3720
3379
|
return null;
|
|
3721
3380
|
}
|
|
3722
|
-
return
|
|
3381
|
+
return resolve15(cwd, inputPath);
|
|
3723
3382
|
}
|
|
3724
3383
|
async function sha256File(path) {
|
|
3725
3384
|
const hasher = new Bun.CryptoHasher("sha256");
|
|
@@ -3735,8 +3394,8 @@ function sortRecord(value) {
|
|
|
3735
3394
|
async function runSerializedRuntimeBinaryBuild(action) {
|
|
3736
3395
|
const previous = runtimeBinaryBuildQueue;
|
|
3737
3396
|
let release;
|
|
3738
|
-
runtimeBinaryBuildQueue = new Promise((
|
|
3739
|
-
release =
|
|
3397
|
+
runtimeBinaryBuildQueue = new Promise((resolve16) => {
|
|
3398
|
+
release = resolve16;
|
|
3740
3399
|
});
|
|
3741
3400
|
await previous;
|
|
3742
3401
|
try {
|
|
@@ -3781,11 +3440,11 @@ async function withTemporaryCwd(cwd, action) {
|
|
|
3781
3440
|
}
|
|
3782
3441
|
|
|
3783
3442
|
// packages/runtime/src/control-plane/runtime/provisioning-env.ts
|
|
3784
|
-
import { delimiter, resolve as
|
|
3443
|
+
import { delimiter, resolve as resolve17 } from "path";
|
|
3785
3444
|
|
|
3786
3445
|
// packages/runtime/src/control-plane/runtime/runtime-paths.ts
|
|
3787
3446
|
import { existsSync as existsSync15, readdirSync as readdirSync4, realpathSync } from "fs";
|
|
3788
|
-
import { resolve as
|
|
3447
|
+
import { resolve as resolve16 } from "path";
|
|
3789
3448
|
|
|
3790
3449
|
// packages/runtime/src/control-plane/runtime/sandbox/utils.ts
|
|
3791
3450
|
function uniq(values) {
|
|
@@ -3803,7 +3462,7 @@ function resolveBunBinaryPath() {
|
|
|
3803
3462
|
}
|
|
3804
3463
|
const home = process.env.HOME?.trim();
|
|
3805
3464
|
const fallbackCandidates = [
|
|
3806
|
-
home ?
|
|
3465
|
+
home ? resolve16(home, ".bun/bin/bun") : "",
|
|
3807
3466
|
"/opt/homebrew/bin/bun",
|
|
3808
3467
|
"/usr/local/bin/bun",
|
|
3809
3468
|
"/usr/bin/bun"
|
|
@@ -3831,8 +3490,8 @@ function resolveClaudeBinaryPath() {
|
|
|
3831
3490
|
}
|
|
3832
3491
|
const home = process.env.HOME?.trim();
|
|
3833
3492
|
const fallbackCandidates = [
|
|
3834
|
-
home ?
|
|
3835
|
-
home ?
|
|
3493
|
+
home ? resolve16(home, ".local/bin/claude") : "",
|
|
3494
|
+
home ? resolve16(home, ".local/share/claude/local/claude") : "",
|
|
3836
3495
|
"/opt/homebrew/bin/claude",
|
|
3837
3496
|
"/usr/local/bin/claude",
|
|
3838
3497
|
"/usr/bin/claude"
|
|
@@ -3846,51 +3505,51 @@ function resolveClaudeBinaryPath() {
|
|
|
3846
3505
|
throw new Error("claude not found in PATH");
|
|
3847
3506
|
}
|
|
3848
3507
|
function resolveBunInstallDir(bunBinaryPath = resolveBunBinaryPath()) {
|
|
3849
|
-
return
|
|
3508
|
+
return resolve16(bunBinaryPath, "../..");
|
|
3850
3509
|
}
|
|
3851
3510
|
function resolveClaudeInstallDir() {
|
|
3852
3511
|
const realPath = resolveClaudeBinaryPath();
|
|
3853
|
-
return
|
|
3512
|
+
return resolve16(realPath, "..");
|
|
3854
3513
|
}
|
|
3855
3514
|
function resolveNodeInstallDir() {
|
|
3856
3515
|
const preferredNode = resolvePreferredNodeBinary();
|
|
3857
3516
|
if (!preferredNode)
|
|
3858
3517
|
return null;
|
|
3859
3518
|
const explicitNode = process.env.RIG_NODE_BIN?.trim();
|
|
3860
|
-
if (explicitNode &&
|
|
3861
|
-
return preferredNode.endsWith("/bin/node") ?
|
|
3519
|
+
if (explicitNode && resolve16(explicitNode) === resolve16(preferredNode)) {
|
|
3520
|
+
return preferredNode.endsWith("/bin/node") ? resolve16(preferredNode, "../..") : resolve16(preferredNode, "..");
|
|
3862
3521
|
}
|
|
3863
3522
|
try {
|
|
3864
3523
|
const realPath = realpathSync(preferredNode);
|
|
3865
3524
|
if (realPath.endsWith("/bin/node")) {
|
|
3866
|
-
return
|
|
3525
|
+
return resolve16(realPath, "../..");
|
|
3867
3526
|
}
|
|
3868
|
-
return
|
|
3527
|
+
return resolve16(realPath, "..");
|
|
3869
3528
|
} catch {
|
|
3870
|
-
return
|
|
3529
|
+
return resolve16(preferredNode, "..");
|
|
3871
3530
|
}
|
|
3872
3531
|
}
|
|
3873
3532
|
function resolvePreferredNodeBinary() {
|
|
3874
3533
|
const candidates = [];
|
|
3875
3534
|
const envNode = process.env.RIG_NODE_BIN?.trim();
|
|
3876
3535
|
if (envNode) {
|
|
3877
|
-
const explicit =
|
|
3536
|
+
const explicit = resolve16(envNode);
|
|
3878
3537
|
if (existsSync15(explicit)) {
|
|
3879
3538
|
return explicit;
|
|
3880
3539
|
}
|
|
3881
3540
|
}
|
|
3882
3541
|
const nvmBin = process.env.NVM_BIN?.trim();
|
|
3883
3542
|
if (nvmBin) {
|
|
3884
|
-
candidates.push(
|
|
3543
|
+
candidates.push(resolve16(nvmBin, "node"));
|
|
3885
3544
|
}
|
|
3886
3545
|
const home = process.env.HOME?.trim();
|
|
3887
3546
|
if (home) {
|
|
3888
|
-
const nvmVersionsDir =
|
|
3547
|
+
const nvmVersionsDir = resolve16(home, ".nvm/versions/node");
|
|
3889
3548
|
if (existsSync15(nvmVersionsDir)) {
|
|
3890
3549
|
try {
|
|
3891
3550
|
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/, "")));
|
|
3892
3551
|
for (const versionDir of versionDirs) {
|
|
3893
|
-
candidates.push(
|
|
3552
|
+
candidates.push(resolve16(nvmVersionsDir, versionDir, "bin/node"));
|
|
3894
3553
|
}
|
|
3895
3554
|
} catch {}
|
|
3896
3555
|
}
|
|
@@ -3899,7 +3558,7 @@ function resolvePreferredNodeBinary() {
|
|
|
3899
3558
|
if (whichNode) {
|
|
3900
3559
|
candidates.push(whichNode);
|
|
3901
3560
|
}
|
|
3902
|
-
const deduped = uniq(candidates.map((candidate) =>
|
|
3561
|
+
const deduped = uniq(candidates.map((candidate) => resolve16(candidate)));
|
|
3903
3562
|
const existing = deduped.filter((candidate) => existsSync15(candidate));
|
|
3904
3563
|
if (existing.length === 0) {
|
|
3905
3564
|
return null;
|
|
@@ -3914,7 +3573,7 @@ function resolvePreferredNodeBinary() {
|
|
|
3914
3573
|
return existing[0] ?? null;
|
|
3915
3574
|
}
|
|
3916
3575
|
function inferNodeMajor(nodeBinaryPath) {
|
|
3917
|
-
const normalized =
|
|
3576
|
+
const normalized = resolve16(nodeBinaryPath).replace(/\\/g, "/");
|
|
3918
3577
|
const match = normalized.match(/(?:^|\/)(?:node-)?v?(\d+)\.\d+\.\d+(?:\/|$)/);
|
|
3919
3578
|
if (!match) {
|
|
3920
3579
|
return null;
|
|
@@ -3926,7 +3585,7 @@ function normalizeExecutablePath(candidate) {
|
|
|
3926
3585
|
if (!candidate) {
|
|
3927
3586
|
return "";
|
|
3928
3587
|
}
|
|
3929
|
-
const normalized =
|
|
3588
|
+
const normalized = resolve16(candidate);
|
|
3930
3589
|
if (!existsSync15(normalized)) {
|
|
3931
3590
|
return "";
|
|
3932
3591
|
}
|
|
@@ -3937,7 +3596,7 @@ function normalizeExecutablePath(candidate) {
|
|
|
3937
3596
|
}
|
|
3938
3597
|
}
|
|
3939
3598
|
function looksLikeRuntimeGateway(candidate) {
|
|
3940
|
-
const normalized =
|
|
3599
|
+
const normalized = resolve16(candidate).replace(/\\/g, "/");
|
|
3941
3600
|
return normalized.includes("/.rig/bin/") || normalized.endsWith("/rig-shell") || normalized.endsWith("/rig-agent");
|
|
3942
3601
|
}
|
|
3943
3602
|
|
|
@@ -3958,7 +3617,7 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
3958
3617
|
try {
|
|
3959
3618
|
return resolveClaudeInstallDir();
|
|
3960
3619
|
} catch {
|
|
3961
|
-
return
|
|
3620
|
+
return resolve17(claudeBinary, "..");
|
|
3962
3621
|
}
|
|
3963
3622
|
})() : "";
|
|
3964
3623
|
const nodeDir = resolveNodeInstallDir();
|
|
@@ -3968,8 +3627,8 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
3968
3627
|
`${bunDir}/bin`,
|
|
3969
3628
|
claudeDir,
|
|
3970
3629
|
nodeDir ? `${nodeDir}/bin` : "",
|
|
3971
|
-
realHome ?
|
|
3972
|
-
realHome ?
|
|
3630
|
+
realHome ? resolve17(realHome, ".local/bin") : "",
|
|
3631
|
+
realHome ? resolve17(realHome, ".cargo/bin") : "",
|
|
3973
3632
|
...inheritedPath,
|
|
3974
3633
|
"/usr/local/bin",
|
|
3975
3634
|
"/usr/local/sbin",
|
|
@@ -4000,9 +3659,9 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
4000
3659
|
// packages/runtime/src/control-plane/native/validator-binaries.ts
|
|
4001
3660
|
function resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext) {
|
|
4002
3661
|
if (runtimeContext) {
|
|
4003
|
-
return
|
|
3662
|
+
return resolve18(runtimeContext.binDir, "validators", binaryName);
|
|
4004
3663
|
}
|
|
4005
|
-
return
|
|
3664
|
+
return resolve18(resolveHarnessPaths(projectRoot).binDir, "validators", binaryName);
|
|
4006
3665
|
}
|
|
4007
3666
|
async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
4008
3667
|
const match = checkId.match(/^([a-z][\w-]*):([a-z][\w-]*)$/);
|
|
@@ -4017,7 +3676,7 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
4017
3676
|
const binaryName = `${category}-${check}`;
|
|
4018
3677
|
const binaryPath = resolveValidatorBinaryPath(projectRoot, binaryName, runtimeContext);
|
|
4019
3678
|
const hostProjectRoot = runtimeContext?.hostProjectRoot?.trim() || projectRoot;
|
|
4020
|
-
const sourcePath =
|
|
3679
|
+
const sourcePath = resolve18(hostProjectRoot, "packages/runtime/src/control-plane/validators", category, `${check}.ts`);
|
|
4021
3680
|
if (!existsSync16(sourcePath)) {
|
|
4022
3681
|
return null;
|
|
4023
3682
|
}
|
|
@@ -4026,10 +3685,10 @@ async function ensureValidatorBinary(projectRoot, checkId, runtimeContext) {
|
|
|
4026
3685
|
const binaryMtime = binaryExists ? statSync5(binaryPath).mtimeMs : 0;
|
|
4027
3686
|
if (!binaryExists || sourceMtime > binaryMtime) {
|
|
4028
3687
|
if (binaryExists) {
|
|
4029
|
-
|
|
4030
|
-
|
|
3688
|
+
rmSync5(binaryPath, { force: true });
|
|
3689
|
+
rmSync5(`${binaryPath}.build-manifest.json`, { force: true });
|
|
4031
3690
|
}
|
|
4032
|
-
|
|
3691
|
+
mkdirSync7(dirname9(binaryPath), { recursive: true });
|
|
4033
3692
|
await buildRuntimeBinary({
|
|
4034
3693
|
sourcePath: `packages/runtime/src/control-plane/validators/${category}/${check}.ts`,
|
|
4035
3694
|
outputPath: binaryPath,
|
|
@@ -4075,14 +3734,14 @@ async function readTaskSourceValidation(projectRoot, taskId) {
|
|
|
4075
3734
|
function resolveValidationPaths(projectRoot, taskId, runtimeContext) {
|
|
4076
3735
|
if (runtimeContext) {
|
|
4077
3736
|
return {
|
|
4078
|
-
taskLogDir:
|
|
4079
|
-
artifactDir:
|
|
3737
|
+
taskLogDir: resolve19(runtimeContext.logsDir, taskId),
|
|
3738
|
+
artifactDir: resolve19(runtimeContext.workspaceDir, "artifacts", taskId)
|
|
4080
3739
|
};
|
|
4081
3740
|
}
|
|
4082
3741
|
const paths = resolveHarnessPaths(projectRoot);
|
|
4083
3742
|
return {
|
|
4084
|
-
taskLogDir:
|
|
4085
|
-
artifactDir:
|
|
3743
|
+
taskLogDir: resolve19(paths.logsDir, taskId),
|
|
3744
|
+
artifactDir: resolve19(paths.artifactsDir, taskId)
|
|
4086
3745
|
};
|
|
4087
3746
|
}
|
|
4088
3747
|
async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext) {
|
|
@@ -4099,7 +3758,7 @@ async function runValidatorBinary(projectRoot, taskId, checkId, runtimeContext)
|
|
|
4099
3758
|
};
|
|
4100
3759
|
}
|
|
4101
3760
|
const validatorCwd = runtimeContext?.workspaceDir || resolveMonorepoRoot(projectRoot);
|
|
4102
|
-
const runtimeShellPath = runtimeContext ?
|
|
3761
|
+
const runtimeShellPath = runtimeContext ? resolve19(runtimeContext.binDir, "rig-shell") : "";
|
|
4103
3762
|
const monorepoMainRoot = runtimeContext?.monorepoMainRoot || process.env.MONOREPO_MAIN_ROOT?.trim() || resolveMonorepoRoot(projectRoot);
|
|
4104
3763
|
const validatorEnv = {
|
|
4105
3764
|
PROJECT_RIG_ROOT: runtimeContext?.hostProjectRoot || projectRoot,
|
|
@@ -4154,8 +3813,8 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
4154
3813
|
const configuredValidation = stringArray(taskConfig[taskId]?.validation);
|
|
4155
3814
|
const commands = resolvedContext?.validation?.length ? resolvedContext.validation : configuredValidation.length > 0 ? configuredValidation : sourceValidation.validation;
|
|
4156
3815
|
const { taskLogDir, artifactDir } = resolveValidationPaths(projectRoot, taskId, resolvedContext);
|
|
4157
|
-
|
|
4158
|
-
|
|
3816
|
+
mkdirSync8(taskLogDir, { recursive: true });
|
|
3817
|
+
mkdirSync8(artifactDir, { recursive: true });
|
|
4159
3818
|
if (commands.length === 0) {
|
|
4160
3819
|
const skipped = {
|
|
4161
3820
|
status: "skipped",
|
|
@@ -4164,7 +3823,7 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
4164
3823
|
failed: 0,
|
|
4165
3824
|
categories: []
|
|
4166
3825
|
};
|
|
4167
|
-
|
|
3826
|
+
writeFileSync8(resolve19(artifactDir, "validation-summary.json"), `${JSON.stringify(skipped, null, 2)}
|
|
4168
3827
|
`, "utf-8");
|
|
4169
3828
|
return skipped;
|
|
4170
3829
|
}
|
|
@@ -4199,18 +3858,18 @@ async function validateTask(projectRoot, taskId, runtimeContext, registry, optio
|
|
|
4199
3858
|
exit_code: 2,
|
|
4200
3859
|
duration_seconds: 0
|
|
4201
3860
|
});
|
|
4202
|
-
const logFile2 =
|
|
4203
|
-
|
|
4204
|
-
|
|
3861
|
+
const logFile2 = resolve19(taskLogDir, `invalid-entry-validation.log`);
|
|
3862
|
+
mkdirSync8(taskLogDir, { recursive: true });
|
|
3863
|
+
writeFileSync8(logFile2, `=== ${nowIso()} :: ${cmd} ===
|
|
4205
3864
|
Invalid validation entry: not a check-ID. All entries must use format "category:check-name".
|
|
4206
3865
|
`, "utf-8");
|
|
4207
3866
|
continue;
|
|
4208
3867
|
}
|
|
4209
3868
|
const { result, exitCode } = await dispatchValidator(cmd, effectiveRegistry, validatorCtx, (id) => runValidatorBinary(projectRoot, taskId, id, resolvedContext));
|
|
4210
3869
|
const durationSeconds = Math.max(0, Math.round((Date.now() - startedAt) / 1000));
|
|
4211
|
-
const logFile =
|
|
4212
|
-
|
|
4213
|
-
|
|
3870
|
+
const logFile = resolve19(taskLogDir, `${cmd.replace(":", "-")}-validation.log`);
|
|
3871
|
+
mkdirSync8(taskLogDir, { recursive: true });
|
|
3872
|
+
writeFileSync8(logFile, `=== ${nowIso()} :: ${cmd} ===
|
|
4214
3873
|
${JSON.stringify(result, null, 2)}
|
|
4215
3874
|
`, "utf-8");
|
|
4216
3875
|
if (result.passed) {
|
|
@@ -4232,19 +3891,19 @@ ${JSON.stringify(result, null, 2)}
|
|
|
4232
3891
|
failed,
|
|
4233
3892
|
categories
|
|
4234
3893
|
};
|
|
4235
|
-
|
|
4236
|
-
|
|
3894
|
+
mkdirSync8(artifactDir, { recursive: true });
|
|
3895
|
+
writeFileSync8(resolve19(artifactDir, "validation-summary.json"), `${JSON.stringify(summary, null, 2)}
|
|
4237
3896
|
`, "utf-8");
|
|
4238
3897
|
return summary;
|
|
4239
3898
|
}
|
|
4240
3899
|
|
|
4241
3900
|
// packages/runtime/src/control-plane/native/verifier.ts
|
|
4242
|
-
import { existsSync as existsSync18, mkdirSync as
|
|
4243
|
-
import { resolve as
|
|
3901
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
|
|
3902
|
+
import { resolve as resolve21 } from "path";
|
|
4244
3903
|
|
|
4245
3904
|
// packages/runtime/src/control-plane/native/pr-review-gate.ts
|
|
4246
|
-
import { mkdirSync as
|
|
4247
|
-
import { resolve as
|
|
3905
|
+
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
3906
|
+
import { resolve as resolve20 } from "path";
|
|
4248
3907
|
function parseJsonObject(value) {
|
|
4249
3908
|
if (!value?.trim())
|
|
4250
3909
|
return { value: {}, error: "empty JSON output" };
|
|
@@ -5568,34 +5227,34 @@ function buildStrictPrGateSteeringPrompt(result) {
|
|
|
5568
5227
|
}
|
|
5569
5228
|
function persistPrReviewCycleArtifacts(input) {
|
|
5570
5229
|
const cycleName = input.final ? `${input.cycle}-final` : String(input.cycle);
|
|
5571
|
-
const taskArtifactRoot = input.artifactRoot?.trim() ? input.artifactRoot :
|
|
5572
|
-
const root =
|
|
5573
|
-
|
|
5574
|
-
const finalMergeGateResultPath = input.final ?
|
|
5230
|
+
const taskArtifactRoot = input.artifactRoot?.trim() ? input.artifactRoot : resolve20(input.projectRoot, "artifacts", input.taskId);
|
|
5231
|
+
const root = resolve20(taskArtifactRoot, "pr-review-cycles", cycleName);
|
|
5232
|
+
mkdirSync9(root, { recursive: true });
|
|
5233
|
+
const finalMergeGateResultPath = input.final ? resolve20(taskArtifactRoot, "merge-gate-final.json") : undefined;
|
|
5575
5234
|
const paths = {
|
|
5576
5235
|
root,
|
|
5577
|
-
prTitlePath:
|
|
5578
|
-
prBodyPath:
|
|
5579
|
-
prCommentsPath:
|
|
5580
|
-
reviewThreadsPath:
|
|
5581
|
-
reviewCommentsPath:
|
|
5582
|
-
checkRollupPath:
|
|
5583
|
-
greptileEvidencePath:
|
|
5584
|
-
mergeGateResultPath:
|
|
5585
|
-
steeringPromptPath:
|
|
5236
|
+
prTitlePath: resolve20(root, "pr-title.md"),
|
|
5237
|
+
prBodyPath: resolve20(root, "pr-body.md"),
|
|
5238
|
+
prCommentsPath: resolve20(root, "pr-comments.json"),
|
|
5239
|
+
reviewThreadsPath: resolve20(root, "review-threads.json"),
|
|
5240
|
+
reviewCommentsPath: resolve20(root, "review-comments.json"),
|
|
5241
|
+
checkRollupPath: resolve20(root, "check-rollup.json"),
|
|
5242
|
+
greptileEvidencePath: resolve20(root, "greptile-evidence.json"),
|
|
5243
|
+
mergeGateResultPath: resolve20(root, "merge-gate-result.json"),
|
|
5244
|
+
steeringPromptPath: resolve20(root, "agent-steering-prompt.md"),
|
|
5586
5245
|
...finalMergeGateResultPath ? { finalMergeGateResultPath } : {}
|
|
5587
5246
|
};
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5247
|
+
writeFileSync9(paths.prTitlePath, input.result.evidence.title || "", "utf8");
|
|
5248
|
+
writeFileSync9(paths.prBodyPath, input.result.evidence.body || "", "utf8");
|
|
5249
|
+
writeFileSync9(paths.prCommentsPath, `${JSON.stringify(input.result.evidence.relevantIssueComments, null, 2)}
|
|
5591
5250
|
`, "utf8");
|
|
5592
|
-
|
|
5251
|
+
writeFileSync9(paths.reviewThreadsPath, `${JSON.stringify(input.result.evidence.reviewThreads, null, 2)}
|
|
5593
5252
|
`, "utf8");
|
|
5594
|
-
|
|
5253
|
+
writeFileSync9(paths.reviewCommentsPath, `${JSON.stringify(input.result.evidence.changedFileReviewComments, null, 2)}
|
|
5595
5254
|
`, "utf8");
|
|
5596
|
-
|
|
5255
|
+
writeFileSync9(paths.checkRollupPath, `${JSON.stringify(input.result.evidence.statusCheckRollup, null, 2)}
|
|
5597
5256
|
`, "utf8");
|
|
5598
|
-
|
|
5257
|
+
writeFileSync9(paths.greptileEvidencePath, `${JSON.stringify(input.result.evidence.greptile, null, 2)}
|
|
5599
5258
|
`, "utf8");
|
|
5600
5259
|
const mergeGatePayload = {
|
|
5601
5260
|
approved: input.result.approved,
|
|
@@ -5612,13 +5271,13 @@ function persistPrReviewCycleArtifacts(input) {
|
|
|
5612
5271
|
evidence: input.result.evidence,
|
|
5613
5272
|
cycleArtifactRoot: root
|
|
5614
5273
|
};
|
|
5615
|
-
|
|
5274
|
+
writeFileSync9(paths.mergeGateResultPath, `${JSON.stringify(mergeGatePayload, null, 2)}
|
|
5616
5275
|
`, "utf8");
|
|
5617
5276
|
if (paths.finalMergeGateResultPath) {
|
|
5618
|
-
|
|
5277
|
+
writeFileSync9(paths.finalMergeGateResultPath, `${JSON.stringify(mergeGatePayload, null, 2)}
|
|
5619
5278
|
`, "utf8");
|
|
5620
5279
|
}
|
|
5621
|
-
|
|
5280
|
+
writeFileSync9(paths.steeringPromptPath, input.steeringPrompt, "utf8");
|
|
5622
5281
|
return paths;
|
|
5623
5282
|
}
|
|
5624
5283
|
async function runStrictPrMergeGate(input) {
|
|
@@ -5635,7 +5294,7 @@ async function runStrictPrMergeGate(input) {
|
|
|
5635
5294
|
final: input.final
|
|
5636
5295
|
});
|
|
5637
5296
|
const steeringPrompt = buildStrictPrGateSteeringPrompt({ ...base, artifacts });
|
|
5638
|
-
|
|
5297
|
+
writeFileSync9(artifacts.steeringPromptPath, steeringPrompt, "utf8");
|
|
5639
5298
|
return { ...base, artifacts, steeringPrompt };
|
|
5640
5299
|
}
|
|
5641
5300
|
|
|
@@ -5645,11 +5304,11 @@ async function verifyTask(options) {
|
|
|
5645
5304
|
const taskId = options.taskId;
|
|
5646
5305
|
const normalizedTaskId = lookupTask(options.projectRoot, taskId);
|
|
5647
5306
|
const artifactDir = artifactDirForId(options.projectRoot, taskId);
|
|
5648
|
-
|
|
5649
|
-
const validationSummaryPath =
|
|
5650
|
-
const reviewFeedbackPath =
|
|
5651
|
-
const reviewStatePath =
|
|
5652
|
-
const greptileRawPath =
|
|
5307
|
+
mkdirSync10(artifactDir, { recursive: true });
|
|
5308
|
+
const validationSummaryPath = resolve21(artifactDir, "validation-summary.json");
|
|
5309
|
+
const reviewFeedbackPath = resolve21(artifactDir, "review-feedback.md");
|
|
5310
|
+
const reviewStatePath = resolve21(artifactDir, "review-state.json");
|
|
5311
|
+
const greptileRawPath = resolve21(artifactDir, "review-greptile-raw.json");
|
|
5653
5312
|
const prStates = readPrMetadata(options.projectRoot, taskId);
|
|
5654
5313
|
const prState = prStates[0] || null;
|
|
5655
5314
|
const localReasons = [];
|
|
@@ -5670,12 +5329,12 @@ async function verifyTask(options) {
|
|
|
5670
5329
|
}
|
|
5671
5330
|
}
|
|
5672
5331
|
for (const file of ["task-result.json", "decision-log.md", "next-actions.md", "changed-files.txt"]) {
|
|
5673
|
-
const requiredPath =
|
|
5332
|
+
const requiredPath = resolve21(artifactDir, file);
|
|
5674
5333
|
if (!existsSync18(requiredPath)) {
|
|
5675
5334
|
localReasons.push(`[Artifact Quality] Missing required artifact file: ${requiredPath}`);
|
|
5676
5335
|
}
|
|
5677
5336
|
}
|
|
5678
|
-
const taskResultPath =
|
|
5337
|
+
const taskResultPath = resolve21(artifactDir, "task-result.json");
|
|
5679
5338
|
if (existsSync18(taskResultPath)) {
|
|
5680
5339
|
const taskResult = await readJsonFile2(taskResultPath);
|
|
5681
5340
|
const artifactStatus = typeof taskResult?.status === "string" ? taskResult.status.trim().toLowerCase() : "";
|
|
@@ -5689,7 +5348,7 @@ async function verifyTask(options) {
|
|
|
5689
5348
|
localReasons.push("[Artifact Quality] task-result.json next actions indicate remaining implementation scope.");
|
|
5690
5349
|
}
|
|
5691
5350
|
}
|
|
5692
|
-
const nextActionsPath =
|
|
5351
|
+
const nextActionsPath = resolve21(artifactDir, "next-actions.md");
|
|
5693
5352
|
if (existsSync18(nextActionsPath)) {
|
|
5694
5353
|
const nextActionsContent = await Bun.file(nextActionsPath).text();
|
|
5695
5354
|
if (nextActionsContent.includes("TODO: Replace this scaffold") || nextActionsContent.includes("bd-<downstream-task-id>")) {
|
|
@@ -5703,12 +5362,6 @@ async function verifyTask(options) {
|
|
|
5703
5362
|
if (sourceCloseoutIssueId) {
|
|
5704
5363
|
localReasons.push(...evaluateGithubSourceIssuePrCloseout(options.projectRoot, prStates, sourceCloseoutIssueId));
|
|
5705
5364
|
}
|
|
5706
|
-
const pluginResults = await options.plugins.runValidators(taskId);
|
|
5707
|
-
for (const result of pluginResults) {
|
|
5708
|
-
if (!result.passed) {
|
|
5709
|
-
localReasons.push(`[Plugin Validator] ${result.id}: ${result.summary}`);
|
|
5710
|
-
}
|
|
5711
|
-
}
|
|
5712
5365
|
const reviewMode = await loadReviewMode(paths.reviewProfilePath, process.env.AI_REVIEW_MODE || "advisory");
|
|
5713
5366
|
const reviewProvider = await loadReviewProvider(paths.reviewProfilePath, process.env.AI_REVIEW_PROVIDER || "greptile");
|
|
5714
5367
|
if (!options.skipAiReview && localReasons.length === 0 && reviewProvider === "greptile" && reviewMode !== "off") {
|
|
@@ -5727,7 +5380,7 @@ async function verifyTask(options) {
|
|
|
5727
5380
|
aiReasons.push(`[AI Review] Required mode needs a completed Greptile approval; current verdict is ${ai.verdict}.`);
|
|
5728
5381
|
}
|
|
5729
5382
|
if (persistArtifacts && ai.rawResponse) {
|
|
5730
|
-
|
|
5383
|
+
writeFileSync10(greptileRawPath, `${ai.rawResponse}
|
|
5731
5384
|
`, "utf-8");
|
|
5732
5385
|
}
|
|
5733
5386
|
} else if (!options.skipAiReview && reviewMode === "off") {
|
|
@@ -6236,7 +5889,7 @@ function writeFeedbackFile(options) {
|
|
|
6236
5889
|
if (options.aiRawFeedback) {
|
|
6237
5890
|
lines.push("## Raw Reviewer Feedback", "", "```text", options.aiRawFeedback, "```", "");
|
|
6238
5891
|
}
|
|
6239
|
-
|
|
5892
|
+
writeFileSync10(options.output, `${lines.join(`
|
|
6240
5893
|
`)}
|
|
6241
5894
|
`, "utf-8");
|
|
6242
5895
|
}
|
|
@@ -6253,7 +5906,7 @@ function writeReviewStateFile(options) {
|
|
|
6253
5906
|
ai_warnings: options.aiWarnings,
|
|
6254
5907
|
updated_at: nowIso()
|
|
6255
5908
|
};
|
|
6256
|
-
|
|
5909
|
+
writeFileSync10(options.output, `${JSON.stringify(payload, null, 2)}
|
|
6257
5910
|
`, "utf-8");
|
|
6258
5911
|
}
|
|
6259
5912
|
async function runGreptileReviewForPr(options) {
|
|
@@ -7040,7 +6693,7 @@ function filterActionableGithubGreptileThreads(threads) {
|
|
|
7040
6693
|
}
|
|
7041
6694
|
function resolvePrRepoRoot(projectRoot, prState) {
|
|
7042
6695
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
7043
|
-
if (prState.target === "monorepo" && runtimeWorkspace && existsSync18(
|
|
6696
|
+
if (prState.target === "monorepo" && runtimeWorkspace && existsSync18(resolve21(runtimeWorkspace, ".git"))) {
|
|
7044
6697
|
return runtimeWorkspace;
|
|
7045
6698
|
}
|
|
7046
6699
|
const paths = resolveHarnessPaths(projectRoot);
|
|
@@ -7108,14 +6761,14 @@ function taskArtifacts(projectRoot, taskId) {
|
|
|
7108
6761
|
throw new Error("No active task.");
|
|
7109
6762
|
}
|
|
7110
6763
|
const paths = resolveHarnessPaths(projectRoot);
|
|
7111
|
-
const artifactDir =
|
|
7112
|
-
|
|
6764
|
+
const artifactDir = resolve22(paths.artifactsDir, activeTask);
|
|
6765
|
+
mkdirSync11(artifactDir, { recursive: true });
|
|
7113
6766
|
const changed = changedFilesForTask(projectRoot, activeTask, true);
|
|
7114
|
-
|
|
6767
|
+
writeFileSync11(resolve22(artifactDir, "changed-files.txt"), `${changed.join(`
|
|
7115
6768
|
`)}
|
|
7116
6769
|
`, "utf-8");
|
|
7117
6770
|
console.log(`changed-files.txt: ${changed.length} files`);
|
|
7118
|
-
const taskResultPath =
|
|
6771
|
+
const taskResultPath = resolve22(artifactDir, "task-result.json");
|
|
7119
6772
|
if (!existsSync19(taskResultPath)) {
|
|
7120
6773
|
const template = {
|
|
7121
6774
|
task_id: activeTask,
|
|
@@ -7123,24 +6776,24 @@ function taskArtifacts(projectRoot, taskId) {
|
|
|
7123
6776
|
summary: "TODO: Write a one-line summary of what you did",
|
|
7124
6777
|
completed_at: nowIso()
|
|
7125
6778
|
};
|
|
7126
|
-
|
|
6779
|
+
writeFileSync11(taskResultPath, `${JSON.stringify(template, null, 2)}
|
|
7127
6780
|
`, "utf-8");
|
|
7128
6781
|
console.log("task-result.json: created (update the summary!)");
|
|
7129
6782
|
} else {
|
|
7130
6783
|
console.log("task-result.json: already exists");
|
|
7131
6784
|
}
|
|
7132
|
-
const decisionLogPath =
|
|
6785
|
+
const decisionLogPath = resolve22(artifactDir, "decision-log.md");
|
|
7133
6786
|
if (!existsSync19(decisionLogPath)) {
|
|
7134
6787
|
const content = `# Decision Log: ${activeTask}
|
|
7135
6788
|
|
|
7136
6789
|
Record key decisions here using: rig-agent record decision "..."
|
|
7137
6790
|
`;
|
|
7138
|
-
|
|
6791
|
+
writeFileSync11(decisionLogPath, content, "utf-8");
|
|
7139
6792
|
console.log("decision-log.md: created (record your decisions!)");
|
|
7140
6793
|
} else {
|
|
7141
6794
|
console.log("decision-log.md: already exists");
|
|
7142
6795
|
}
|
|
7143
|
-
const nextActionsPath =
|
|
6796
|
+
const nextActionsPath = resolve22(artifactDir, "next-actions.md");
|
|
7144
6797
|
if (!existsSync19(nextActionsPath)) {
|
|
7145
6798
|
const content = [
|
|
7146
6799
|
`# Next Actions: ${activeTask}`,
|
|
@@ -7158,12 +6811,12 @@ Record key decisions here using: rig-agent record decision "..."
|
|
|
7158
6811
|
""
|
|
7159
6812
|
].join(`
|
|
7160
6813
|
`);
|
|
7161
|
-
|
|
6814
|
+
writeFileSync11(nextActionsPath, content, "utf-8");
|
|
7162
6815
|
console.log("next-actions.md: created (add recommendations for downstream tasks!)");
|
|
7163
6816
|
} else {
|
|
7164
6817
|
console.log("next-actions.md: already exists");
|
|
7165
6818
|
}
|
|
7166
|
-
const validationSummaryPath =
|
|
6819
|
+
const validationSummaryPath = resolve22(artifactDir, "validation-summary.json");
|
|
7167
6820
|
if (existsSync19(validationSummaryPath)) {
|
|
7168
6821
|
console.log("validation-summary.json: already exists");
|
|
7169
6822
|
} else {
|
|
@@ -7230,7 +6883,7 @@ function collectTaskChangedFiles(projectRoot, taskId, includeCommitted) {
|
|
|
7230
6883
|
[projectRoot, ""],
|
|
7231
6884
|
[monorepoRepoRoot, ""]
|
|
7232
6885
|
]) {
|
|
7233
|
-
if (!existsSync19(
|
|
6886
|
+
if (!existsSync19(resolve22(repo, ".git"))) {
|
|
7234
6887
|
continue;
|
|
7235
6888
|
}
|
|
7236
6889
|
if (includeCommitted && repo === monorepoRepoRoot) {
|
|
@@ -7268,8 +6921,8 @@ function filterTaskChangedFiles(projectRoot, taskId, files, scoped) {
|
|
|
7268
6921
|
}
|
|
7269
6922
|
function resolveTaskMonorepoRoot(projectRoot) {
|
|
7270
6923
|
const runtimeWorkspace = loadRuntimeContextFromEnv()?.workspaceDir || process.env.RIG_TASK_WORKSPACE?.trim();
|
|
7271
|
-
if (runtimeWorkspace && existsSync19(
|
|
7272
|
-
return
|
|
6924
|
+
if (runtimeWorkspace && existsSync19(resolve22(runtimeWorkspace, ".git"))) {
|
|
6925
|
+
return resolve22(runtimeWorkspace);
|
|
7273
6926
|
}
|
|
7274
6927
|
return resolveHarnessPaths(projectRoot).monorepoRoot;
|
|
7275
6928
|
}
|
|
@@ -7297,7 +6950,7 @@ function resolveRuntimeInitialHeadCommit(projectRoot, repo) {
|
|
|
7297
6950
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
7298
6951
|
if (runtimeContext?.initialHeadCommits?.monorepo?.trim()) {
|
|
7299
6952
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
7300
|
-
if (
|
|
6953
|
+
if (resolve22(monorepoRoot) === resolve22(repo)) {
|
|
7301
6954
|
return runtimeContext.initialHeadCommits.monorepo.trim();
|
|
7302
6955
|
}
|
|
7303
6956
|
}
|
|
@@ -7307,7 +6960,7 @@ function resolveMonorepoBaseCommit(projectRoot, repo) {
|
|
|
7307
6960
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
7308
6961
|
if (runtimeContext?.monorepoBaseCommit?.trim()) {
|
|
7309
6962
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
7310
|
-
if (
|
|
6963
|
+
if (resolve22(monorepoRoot) === resolve22(repo)) {
|
|
7311
6964
|
return runtimeContext.monorepoBaseCommit.trim();
|
|
7312
6965
|
}
|
|
7313
6966
|
}
|
|
@@ -7341,7 +6994,7 @@ function resolveRuntimeDirtyBaseline(projectRoot, repo) {
|
|
|
7341
6994
|
return new Set;
|
|
7342
6995
|
}
|
|
7343
6996
|
const monorepoRoot = resolveTaskMonorepoRoot(projectRoot);
|
|
7344
|
-
const selected =
|
|
6997
|
+
const selected = resolve22(repo) === resolve22(monorepoRoot) ? dirtyFiles.monorepo : resolve22(repo) === resolve22(projectRoot) ? dirtyFiles.project : undefined;
|
|
7345
6998
|
return new Set((selected || []).map((file) => normalizeChangedFilePath(file)).filter(Boolean));
|
|
7346
6999
|
}
|
|
7347
7000
|
function normalizeChangedFilePath(file) {
|
|
@@ -7399,8 +7052,8 @@ function isRuntimeGatewayGhPath(candidate) {
|
|
|
7399
7052
|
}
|
|
7400
7053
|
function resolveOptionalMonorepoRoot(projectRoot) {
|
|
7401
7054
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
7402
|
-
if (runtimeWorkspace && existsSync20(
|
|
7403
|
-
return
|
|
7055
|
+
if (runtimeWorkspace && existsSync20(resolve23(runtimeWorkspace, ".git"))) {
|
|
7056
|
+
return resolve23(runtimeWorkspace);
|
|
7404
7057
|
}
|
|
7405
7058
|
try {
|
|
7406
7059
|
return resolveMonorepoRoot2(projectRoot);
|
|
@@ -7452,7 +7105,7 @@ function gitSyncBranch(projectRoot, taskId, targetRepo = "monorepo") {
|
|
|
7452
7105
|
}
|
|
7453
7106
|
const repoRoot = targetRepo === "monorepo" ? resolveOptionalMonorepoRoot(projectRoot) || resolveMonorepoRoot2(projectRoot) : projectRoot;
|
|
7454
7107
|
const repoLabel = targetRepo === "monorepo" ? "Monorepo" : "Project";
|
|
7455
|
-
if (!existsSync20(
|
|
7108
|
+
if (!existsSync20(resolve23(repoRoot, ".git"))) {
|
|
7456
7109
|
throw new Error(`${repoLabel} repo not found at ${repoRoot}`);
|
|
7457
7110
|
}
|
|
7458
7111
|
const branchId = resolveTaskBranchId(projectRoot, resolvedTask);
|
|
@@ -7512,7 +7165,7 @@ function gitOpenPr(options) {
|
|
|
7512
7165
|
} else if (taskId) {
|
|
7513
7166
|
gitSyncBranch(options.projectRoot, taskId, "project");
|
|
7514
7167
|
}
|
|
7515
|
-
if (!existsSync20(
|
|
7168
|
+
if (!existsSync20(resolve23(repoRoot, ".git"))) {
|
|
7516
7169
|
throw new Error(`Repository not available for open-pr target ${target}: ${repoRoot}`);
|
|
7517
7170
|
}
|
|
7518
7171
|
const branch = branchName(options.projectRoot, repoRoot);
|
|
@@ -7745,7 +7398,7 @@ function gitMergePr(options) {
|
|
|
7745
7398
|
}
|
|
7746
7399
|
const repoRoot = resolveRepoRoot(options.projectRoot, options.pr.target);
|
|
7747
7400
|
const repoNameWithOwner = resolveRepoNameWithOwner(options.projectRoot, repoRoot);
|
|
7748
|
-
if (!existsSync20(
|
|
7401
|
+
if (!existsSync20(resolve23(repoRoot, ".git"))) {
|
|
7749
7402
|
throw new Error(`Repository not available for merge-pr target ${options.pr.target}: ${repoRoot}`);
|
|
7750
7403
|
}
|
|
7751
7404
|
const prState = readPrViewState(gh, repoRoot, repoNameWithOwner, options.pr.url);
|
|
@@ -7806,12 +7459,12 @@ function assertPrHasNoGitConflicts(prState, repoLabel, baseRef) {
|
|
|
7806
7459
|
}
|
|
7807
7460
|
function writePrMetadata(projectRoot, taskId, result) {
|
|
7808
7461
|
const dir = artifactDirForId(projectRoot, taskId);
|
|
7809
|
-
|
|
7810
|
-
const path =
|
|
7462
|
+
mkdirSync12(dir, { recursive: true });
|
|
7463
|
+
const path = resolve23(dir, "pr-state.json");
|
|
7811
7464
|
let prs = {};
|
|
7812
7465
|
if (existsSync20(path)) {
|
|
7813
7466
|
try {
|
|
7814
|
-
const parsed = JSON.parse(
|
|
7467
|
+
const parsed = JSON.parse(readFileSync12(path, "utf-8"));
|
|
7815
7468
|
if (parsed && typeof parsed === "object" && parsed.prs && typeof parsed.prs === "object") {
|
|
7816
7469
|
prs = parsed.prs;
|
|
7817
7470
|
}
|
|
@@ -7827,16 +7480,16 @@ function writePrMetadata(projectRoot, taskId, result) {
|
|
|
7827
7480
|
...primary || {},
|
|
7828
7481
|
updated_at: nowIso()
|
|
7829
7482
|
};
|
|
7830
|
-
|
|
7483
|
+
writeFileSync12(path, `${JSON.stringify(artifact, null, 2)}
|
|
7831
7484
|
`, "utf-8");
|
|
7832
7485
|
}
|
|
7833
7486
|
function readPrMetadata(projectRoot, taskId) {
|
|
7834
|
-
const path =
|
|
7487
|
+
const path = resolve23(artifactDirForId(projectRoot, taskId), "pr-state.json");
|
|
7835
7488
|
if (!existsSync20(path)) {
|
|
7836
7489
|
return [];
|
|
7837
7490
|
}
|
|
7838
7491
|
try {
|
|
7839
|
-
const parsed = JSON.parse(
|
|
7492
|
+
const parsed = JSON.parse(readFileSync12(path, "utf-8"));
|
|
7840
7493
|
if (!parsed || typeof parsed !== "object") {
|
|
7841
7494
|
return [];
|
|
7842
7495
|
}
|
|
@@ -7908,7 +7561,7 @@ function resolveGithubCliBinary(projectRoot) {
|
|
|
7908
7561
|
}
|
|
7909
7562
|
const explicitPathEntries = (process.env.PATH || "").split(":").map((entry) => entry.trim()).filter(Boolean);
|
|
7910
7563
|
for (const entry of explicitPathEntries) {
|
|
7911
|
-
candidates.add(
|
|
7564
|
+
candidates.add(resolve23(entry, "gh"));
|
|
7912
7565
|
}
|
|
7913
7566
|
const bunResolved = Bun.which("gh");
|
|
7914
7567
|
if (bunResolved) {
|
|
@@ -7945,7 +7598,7 @@ function resolveRepoNameWithOwner(projectRoot, repoRoot) {
|
|
|
7945
7598
|
return resolveGithubRepoNameWithOwnerFromGitRoot(projectRoot, repoRoot, repoRoot, visited);
|
|
7946
7599
|
}
|
|
7947
7600
|
function resolveGithubRepoNameWithOwnerFromGitRoot(projectRoot, gitRoot, cwd, visited) {
|
|
7948
|
-
const normalizedGitRoot =
|
|
7601
|
+
const normalizedGitRoot = resolve23(gitRoot);
|
|
7949
7602
|
if (visited.has(normalizedGitRoot)) {
|
|
7950
7603
|
return "";
|
|
7951
7604
|
}
|
|
@@ -8017,7 +7670,7 @@ function resolveNetworkRemoteName(projectRoot, repoRoot, repoNameWithOwner) {
|
|
|
8017
7670
|
return remotes.includes("origin") ? "origin" : remotes[0];
|
|
8018
7671
|
}
|
|
8019
7672
|
function gitQuery(projectRoot, gitRoot, cwd, ...args) {
|
|
8020
|
-
const gitArgs = existsSync20(
|
|
7673
|
+
const gitArgs = existsSync20(resolve23(gitRoot, ".git")) ? gitCmd(projectRoot, gitRoot, ...args) : [resolveGitBinary(projectRoot), "--git-dir", gitRoot, ...args];
|
|
8021
7674
|
return runCapture2(gitArgs, cwd, projectRoot);
|
|
8022
7675
|
}
|
|
8023
7676
|
function resolveLocalGitRemoteRoot(remoteUrl, gitRoot) {
|
|
@@ -8035,7 +7688,7 @@ function resolveLocalGitRemoteRoot(remoteUrl, gitRoot) {
|
|
|
8035
7688
|
} else if (/^[a-z][a-z0-9+.-]*:\/\//i.test(normalized) || /^[^@]+@[^:]+:.+$/.test(normalized)) {
|
|
8036
7689
|
return "";
|
|
8037
7690
|
} else if (!isAbsolute2(normalized)) {
|
|
8038
|
-
candidate =
|
|
7691
|
+
candidate = resolve23(gitRoot, normalized);
|
|
8039
7692
|
}
|
|
8040
7693
|
return existsSync20(candidate) ? candidate : "";
|
|
8041
7694
|
}
|
|
@@ -8164,7 +7817,7 @@ function inferReviewerFromChangedFiles(projectRoot, repoRoot, baseRef, branchRef
|
|
|
8164
7817
|
return best;
|
|
8165
7818
|
}
|
|
8166
7819
|
function commitRepo(projectRoot, repo, label, message, allowEmpty, scoped, files, changedFilesManifest) {
|
|
8167
|
-
if (!existsSync20(
|
|
7820
|
+
if (!existsSync20(resolve23(repo, ".git"))) {
|
|
8168
7821
|
console.log(`Skipping ${label}: repo not available (${repo})`);
|
|
8169
7822
|
return;
|
|
8170
7823
|
}
|
|
@@ -8196,18 +7849,18 @@ function commitRepo(projectRoot, repo, label, message, allowEmpty, scoped, files
|
|
|
8196
7849
|
console.log(`Committed ${label}: ${message}`);
|
|
8197
7850
|
}
|
|
8198
7851
|
function readChangedFilesManifest(projectRoot, taskId) {
|
|
8199
|
-
const manifestPath =
|
|
7852
|
+
const manifestPath = resolve23(artifactDirForId(projectRoot, taskId), "changed-files.txt");
|
|
8200
7853
|
if (!existsSync20(manifestPath)) {
|
|
8201
7854
|
return [];
|
|
8202
7855
|
}
|
|
8203
|
-
const files =
|
|
7856
|
+
const files = readFileSync12(manifestPath, "utf-8").split(/\r?\n/).map((line) => normalizeChangedFilePath2(line)).filter(Boolean);
|
|
8204
7857
|
return [...new Set(files)];
|
|
8205
7858
|
}
|
|
8206
7859
|
function refreshChangedFilesManifest(projectRoot, taskId) {
|
|
8207
|
-
const manifestPath =
|
|
8208
|
-
|
|
7860
|
+
const manifestPath = resolve23(artifactDirForId(projectRoot, taskId), "changed-files.txt");
|
|
7861
|
+
mkdirSync12(dirname10(manifestPath), { recursive: true });
|
|
8209
7862
|
const changedFiles = changedFilesForTask(projectRoot, taskId, true);
|
|
8210
|
-
|
|
7863
|
+
writeFileSync12(manifestPath, `${changedFiles.join(`
|
|
8211
7864
|
`)}
|
|
8212
7865
|
`, "utf-8");
|
|
8213
7866
|
return manifestPath;
|
|
@@ -8320,7 +7973,7 @@ function repoHasPathChange(projectRoot, repoRoot, relativePath) {
|
|
|
8320
7973
|
return result.exitCode === 0 && result.stdout.trim().length > 0;
|
|
8321
7974
|
}
|
|
8322
7975
|
function stageExcludePathspecs(repoRoot) {
|
|
8323
|
-
const patterns = existsSync20(
|
|
7976
|
+
const patterns = existsSync20(resolve23(repoRoot, ".rig", "task-config.json")) ? [...TASK_RUNTIME_STAGE_EXCLUDES, ...GENERATED_STAGE_EXCLUDES] : [".rig/**", ...GENERATED_STAGE_EXCLUDES];
|
|
8324
7977
|
return patterns.map((pattern) => `:(glob,exclude)${pattern}`);
|
|
8325
7978
|
}
|
|
8326
7979
|
function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
@@ -8330,7 +7983,7 @@ function pathResolvesBeyondSymlink(repoRoot, relativePath) {
|
|
|
8330
7983
|
}
|
|
8331
7984
|
let current = repoRoot;
|
|
8332
7985
|
for (let index = 0;index < parts.length - 1; index += 1) {
|
|
8333
|
-
current =
|
|
7986
|
+
current = resolve23(current, parts[index]);
|
|
8334
7987
|
try {
|
|
8335
7988
|
if (lstatSync(current).isSymbolicLink()) {
|
|
8336
7989
|
return true;
|
|
@@ -8400,11 +8053,11 @@ function runCapture2(command, cwd, projectRoot = cwd) {
|
|
|
8400
8053
|
}
|
|
8401
8054
|
function runtimeGitEnv(projectRoot) {
|
|
8402
8055
|
const { ctx, runtimeRoot } = resolveRuntimeMetadata(projectRoot);
|
|
8403
|
-
const runtimeHome = runtimeRoot ?
|
|
8404
|
-
const runtimeTmp = runtimeRoot ?
|
|
8405
|
-
const runtimeCache = runtimeRoot ?
|
|
8406
|
-
const runtimeKnownHosts = runtimeHome ?
|
|
8407
|
-
const runtimeKey = runtimeHome ?
|
|
8056
|
+
const runtimeHome = runtimeRoot ? resolve23(runtimeRoot, "home") : "";
|
|
8057
|
+
const runtimeTmp = runtimeRoot ? resolve23(runtimeRoot, "tmp") : "";
|
|
8058
|
+
const runtimeCache = runtimeRoot ? resolve23(runtimeRoot, "cache") : "";
|
|
8059
|
+
const runtimeKnownHosts = runtimeHome ? resolve23(runtimeHome, ".ssh", "known_hosts") : "";
|
|
8060
|
+
const runtimeKey = runtimeHome ? resolve23(runtimeHome, ".ssh", "rig-agent-key") : "";
|
|
8408
8061
|
const env = {};
|
|
8409
8062
|
if (ctx?.workspaceDir) {
|
|
8410
8063
|
env.PROJECT_RIG_ROOT = projectRoot;
|
|
@@ -8496,12 +8149,12 @@ function loadPersistedRuntimeSecrets(runtimeRoot) {
|
|
|
8496
8149
|
if (!runtimeRoot) {
|
|
8497
8150
|
return {};
|
|
8498
8151
|
}
|
|
8499
|
-
const path =
|
|
8152
|
+
const path = resolve23(runtimeRoot, "runtime-secrets.json");
|
|
8500
8153
|
if (!existsSync20(path)) {
|
|
8501
8154
|
return {};
|
|
8502
8155
|
}
|
|
8503
8156
|
try {
|
|
8504
|
-
const parsed = JSON.parse(
|
|
8157
|
+
const parsed = JSON.parse(readFileSync12(path, "utf-8"));
|
|
8505
8158
|
const entries = Object.entries(parsed).filter((entry) => typeof entry[1] === "string");
|
|
8506
8159
|
return Object.fromEntries(entries);
|
|
8507
8160
|
} catch {
|
|
@@ -8509,13 +8162,13 @@ function loadPersistedRuntimeSecrets(runtimeRoot) {
|
|
|
8509
8162
|
}
|
|
8510
8163
|
}
|
|
8511
8164
|
function ensureRuntimeOpenSslConfig(runtimeHome) {
|
|
8512
|
-
const sslDir =
|
|
8513
|
-
const sslConfig =
|
|
8165
|
+
const sslDir = resolve23(runtimeHome, ".ssl");
|
|
8166
|
+
const sslConfig = resolve23(sslDir, "openssl.cnf");
|
|
8514
8167
|
if (!existsSync20(sslDir)) {
|
|
8515
|
-
|
|
8168
|
+
mkdirSync12(sslDir, { recursive: true });
|
|
8516
8169
|
}
|
|
8517
8170
|
if (!existsSync20(sslConfig)) {
|
|
8518
|
-
|
|
8171
|
+
writeFileSync12(sslConfig, `# Rig runtime OpenSSL config placeholder
|
|
8519
8172
|
`);
|
|
8520
8173
|
}
|
|
8521
8174
|
return sslConfig;
|
|
@@ -8533,7 +8186,7 @@ function resolveRuntimeMetadata(projectRoot) {
|
|
|
8533
8186
|
if (contextFile) {
|
|
8534
8187
|
return {
|
|
8535
8188
|
ctx,
|
|
8536
|
-
runtimeRoot:
|
|
8189
|
+
runtimeRoot: dirname10(resolve23(contextFile))
|
|
8537
8190
|
};
|
|
8538
8191
|
}
|
|
8539
8192
|
const inferredContextFile = findRuntimeContextFile2(projectRoot);
|
|
@@ -8543,19 +8196,19 @@ function resolveRuntimeMetadata(projectRoot) {
|
|
|
8543
8196
|
} catch {}
|
|
8544
8197
|
return {
|
|
8545
8198
|
ctx,
|
|
8546
|
-
runtimeRoot:
|
|
8199
|
+
runtimeRoot: dirname10(inferredContextFile)
|
|
8547
8200
|
};
|
|
8548
8201
|
}
|
|
8549
8202
|
return { ctx, runtimeRoot: "" };
|
|
8550
8203
|
}
|
|
8551
8204
|
function findRuntimeContextFile2(startPath) {
|
|
8552
|
-
let current =
|
|
8205
|
+
let current = resolve23(startPath);
|
|
8553
8206
|
while (true) {
|
|
8554
|
-
const candidate =
|
|
8207
|
+
const candidate = resolve23(current, "runtime-context.json");
|
|
8555
8208
|
if (existsSync20(candidate)) {
|
|
8556
8209
|
return candidate;
|
|
8557
8210
|
}
|
|
8558
|
-
const parent =
|
|
8211
|
+
const parent = dirname10(current);
|
|
8559
8212
|
if (parent === current) {
|
|
8560
8213
|
return "";
|
|
8561
8214
|
}
|
|
@@ -8643,21 +8296,12 @@ async function main() {
|
|
|
8643
8296
|
const policy = loadPolicy(projectRoot);
|
|
8644
8297
|
const openPrEnabled = policy.completion.checks.includes("open-pr");
|
|
8645
8298
|
const autoMergeEnabled = policy.completion.checks.includes("auto-merge");
|
|
8646
|
-
const eventBus = new RuntimeEventBus({ projectRoot });
|
|
8647
|
-
const runtimeContext = loadRuntimeContextFromEnv() ?? undefined;
|
|
8648
|
-
const plugins = await PluginManager.load({
|
|
8649
|
-
projectRoot,
|
|
8650
|
-
runId: eventBus.getRunId(),
|
|
8651
|
-
eventBus,
|
|
8652
|
-
runtimeContext
|
|
8653
|
-
});
|
|
8654
8299
|
console.log(`
|
|
8655
8300
|
[2/3] Verifier preflight...`);
|
|
8656
8301
|
if (!failed) {
|
|
8657
8302
|
const localVerifyOutcome = await verifyTask({
|
|
8658
8303
|
projectRoot,
|
|
8659
8304
|
taskId,
|
|
8660
|
-
plugins,
|
|
8661
8305
|
skipAiReview: true,
|
|
8662
8306
|
persistArtifacts: false
|
|
8663
8307
|
});
|
|
@@ -8728,8 +8372,7 @@ async function main() {
|
|
|
8728
8372
|
[3/3] Verifier review...`);
|
|
8729
8373
|
const verifyOutcome = await verifyTask({
|
|
8730
8374
|
projectRoot,
|
|
8731
|
-
taskId
|
|
8732
|
-
plugins
|
|
8375
|
+
taskId
|
|
8733
8376
|
});
|
|
8734
8377
|
if (!verifyOutcome.approved) {
|
|
8735
8378
|
console.log("REJECT:");
|
|
@@ -8801,9 +8444,9 @@ async function main() {
|
|
|
8801
8444
|
console.log(`
|
|
8802
8445
|
[post] Auto-merge: skipped (not in policy completion.checks)`);
|
|
8803
8446
|
}
|
|
8804
|
-
const artifactDir =
|
|
8805
|
-
|
|
8806
|
-
|
|
8447
|
+
const artifactDir = resolve24(paths.artifactsDir, taskId);
|
|
8448
|
+
mkdirSync13(artifactDir, { recursive: true });
|
|
8449
|
+
writeFileSync13(resolve24(artifactDir, "review-status.txt"), failed ? `REJECTED
|
|
8807
8450
|
` : `APPROVED
|
|
8808
8451
|
`, "utf-8");
|
|
8809
8452
|
if (!failed) {
|
|
@@ -8850,7 +8493,7 @@ async function runBunTool(args, cwd) {
|
|
|
8850
8493
|
};
|
|
8851
8494
|
}
|
|
8852
8495
|
async function runProtoQualityGate(monorepoRoot) {
|
|
8853
|
-
const protosDir =
|
|
8496
|
+
const protosDir = resolve24(monorepoRoot, "packages", "protos");
|
|
8854
8497
|
if (!existsSync21(protosDir)) {
|
|
8855
8498
|
console.log(`FAIL: Proto workspace not found at ${protosDir}`);
|
|
8856
8499
|
return false;
|
|
@@ -8899,12 +8542,12 @@ async function runProtoQualityGate(monorepoRoot) {
|
|
|
8899
8542
|
} else {
|
|
8900
8543
|
console.log("OK: Generated TypeScript compiles");
|
|
8901
8544
|
}
|
|
8902
|
-
const workflowPath =
|
|
8545
|
+
const workflowPath = resolve24(monorepoRoot, ".github", "workflows", "pull-request-gate.yml");
|
|
8903
8546
|
if (!existsSync21(workflowPath)) {
|
|
8904
8547
|
console.log(`FAIL: Missing workflow gate file at ${workflowPath}`);
|
|
8905
8548
|
ok = false;
|
|
8906
8549
|
} else {
|
|
8907
|
-
const workflow =
|
|
8550
|
+
const workflow = readFileSync13(workflowPath, "utf-8");
|
|
8908
8551
|
if (workflow.includes("if: false && needs.detect.outputs.protos_changed == 'true'")) {
|
|
8909
8552
|
console.log("FAIL: Proto quality CI gate is disabled in pull-request-gate.yml");
|
|
8910
8553
|
ok = false;
|
|
@@ -8944,9 +8587,9 @@ async function readJsonFileIfPresent(path) {
|
|
|
8944
8587
|
}
|
|
8945
8588
|
async function recordVerifierFailure(projectRoot, taskId, paths) {
|
|
8946
8589
|
const failedApproachesPath = paths.failedApproachesPath;
|
|
8947
|
-
const artifactDir =
|
|
8948
|
-
const reviewStatePath =
|
|
8949
|
-
const reviewFeedbackPath =
|
|
8590
|
+
const artifactDir = resolve24(paths.artifactsDir, taskId);
|
|
8591
|
+
const reviewStatePath = resolve24(artifactDir, "review-state.json");
|
|
8592
|
+
const reviewFeedbackPath = resolve24(artifactDir, "review-feedback.md");
|
|
8950
8593
|
let summary = "Verifier rejected completion. Read review-feedback.md for required fixes.";
|
|
8951
8594
|
const parsedReviewState = await readJsonFileIfPresent(reviewStatePath);
|
|
8952
8595
|
if (parsedReviewState) {
|
|
@@ -8957,11 +8600,11 @@ async function recordVerifierFailure(projectRoot, taskId, paths) {
|
|
|
8957
8600
|
}
|
|
8958
8601
|
let attempts = 1;
|
|
8959
8602
|
if (existsSync21(failedApproachesPath)) {
|
|
8960
|
-
const content =
|
|
8603
|
+
const content = readFileSync13(failedApproachesPath, "utf-8");
|
|
8961
8604
|
attempts = (content.match(new RegExp(`^## ${escapeRegExp2(taskId)}\\b`, "gm")) || []).length + 1;
|
|
8962
8605
|
} else {
|
|
8963
|
-
|
|
8964
|
-
|
|
8606
|
+
mkdirSync13(resolve24(failedApproachesPath, ".."), { recursive: true });
|
|
8607
|
+
writeFileSync13(failedApproachesPath, `# Failed Approaches
|
|
8965
8608
|
|
|
8966
8609
|
`, "utf-8");
|
|
8967
8610
|
}
|
|
@@ -8999,8 +8642,8 @@ async function recordTaskRepoCommits(projectRoot, taskId, paths) {
|
|
|
8999
8642
|
recorded_at: new Date().toISOString(),
|
|
9000
8643
|
repos
|
|
9001
8644
|
};
|
|
9002
|
-
|
|
9003
|
-
|
|
8645
|
+
mkdirSync13(resolve24(statePath, ".."), { recursive: true });
|
|
8646
|
+
writeFileSync13(statePath, `${JSON.stringify(state, null, 2)}
|
|
9004
8647
|
`, "utf-8");
|
|
9005
8648
|
}
|
|
9006
8649
|
}
|