@h-rig/runtime 0.0.6-alpha.3 → 0.0.6-alpha.31
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 +1165 -785
- package/dist/bin/rig-agent.js +458 -389
- package/dist/src/control-plane/agent-wrapper.js +1191 -504
- package/dist/src/control-plane/authority-files.js +12 -6
- package/dist/src/control-plane/harness-main.js +2186 -1786
- package/dist/src/control-plane/hooks/completion-verification.js +2084 -1019
- package/dist/src/control-plane/hooks/inject-context.js +193 -139
- package/dist/src/control-plane/hooks/submodule-branch.js +603 -545
- package/dist/src/control-plane/hooks/task-runtime-start.js +603 -545
- package/dist/src/control-plane/materialize-task-config.js +64 -8
- package/dist/src/control-plane/native/git-ops.js +90 -64
- package/dist/src/control-plane/native/harness-cli.js +1989 -682
- package/dist/src/control-plane/native/pr-automation.js +1657 -54
- package/dist/src/control-plane/native/pr-review-gate.js +1455 -0
- package/dist/src/control-plane/native/repo-ops.js +3 -0
- package/dist/src/control-plane/native/run-ops.js +39 -13
- package/dist/src/control-plane/native/task-ops.js +1819 -527
- package/dist/src/control-plane/native/validator.js +163 -109
- package/dist/src/control-plane/native/verifier.js +1616 -323
- package/dist/src/control-plane/native/workspace-ops.js +12 -6
- package/dist/src/control-plane/pi-sessiond/bin.js +793 -0
- package/dist/src/control-plane/pi-sessiond/client.js +41 -0
- package/dist/src/control-plane/pi-sessiond/event-hub.js +59 -0
- package/dist/src/control-plane/pi-sessiond/extension-ui-context.js +198 -0
- package/dist/src/control-plane/pi-sessiond/launcher.js +173 -0
- package/dist/src/control-plane/pi-sessiond/server.js +802 -0
- package/dist/src/control-plane/pi-sessiond/session-service.js +540 -0
- package/dist/src/control-plane/pi-sessiond/types.js +1 -0
- 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 +517 -722
- package/dist/src/control-plane/runtime/isolation/home.js +28 -6
- package/dist/src/control-plane/runtime/isolation/index.js +541 -461
- package/dist/src/control-plane/runtime/isolation/runner.js +28 -6
- package/dist/src/control-plane/runtime/isolation/shared.js +9 -6
- package/dist/src/control-plane/runtime/isolation.js +541 -461
- package/dist/src/control-plane/runtime/plugin-mode.js +3 -27
- package/dist/src/control-plane/runtime/queue.js +458 -385
- 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-aware-task-config-source.js +14 -2
- package/dist/src/control-plane/tasks/source-lifecycle.js +86 -32
- package/dist/src/index.js +27 -298
- package/dist/src/layout.js +12 -7
- package/dist/src/local-server.js +20 -14
- package/native/darwin-arm64/rig-git +0 -0
- package/native/darwin-arm64/rig-git.build-manifest.json +1 -1
- 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/native/darwin-arm64/runtime-native.dylib +0 -0
- package/package.json +8 -6
- package/dist/src/control-plane/runtime/plugins.js +0 -1131
- package/dist/src/plugins.js +0 -329
|
@@ -150,32 +150,32 @@ var RIG_DEFINITION_DIRNAME = "rig", RIG_ARTIFACTS_DIRNAME = "artifacts";
|
|
|
150
150
|
var init_layout = () => {};
|
|
151
151
|
|
|
152
152
|
// packages/runtime/src/control-plane/runtime/sandbox/utils.ts
|
|
153
|
-
import { existsSync as
|
|
154
|
-
import { resolve as
|
|
153
|
+
import { existsSync as existsSync20, readdirSync as readdirSync4, realpathSync } from "fs";
|
|
154
|
+
import { resolve as resolve20 } from "path";
|
|
155
155
|
function toRealPath(path) {
|
|
156
|
-
if (!
|
|
157
|
-
return
|
|
156
|
+
if (!existsSync20(path)) {
|
|
157
|
+
return resolve20(path);
|
|
158
158
|
}
|
|
159
159
|
try {
|
|
160
160
|
return realpathSync.native(path);
|
|
161
161
|
} catch {
|
|
162
|
-
return
|
|
162
|
+
return resolve20(path);
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
function resolveHostGitMetadataPaths(projectRoot, workspaceDir) {
|
|
166
166
|
const candidates = new Set;
|
|
167
167
|
const addPath = (candidate) => {
|
|
168
|
-
if (
|
|
168
|
+
if (existsSync20(candidate)) {
|
|
169
169
|
candidates.add(toRealPath(candidate));
|
|
170
170
|
}
|
|
171
171
|
};
|
|
172
|
-
addPath(
|
|
173
|
-
addPath(
|
|
172
|
+
addPath(resolve20(projectRoot, ".git"));
|
|
173
|
+
addPath(resolve20(workspaceDir, "..", "..", ".git"));
|
|
174
174
|
for (const repoRoot of resolveHostRepoRootPaths(projectRoot)) {
|
|
175
|
-
addPath(
|
|
175
|
+
addPath(resolve20(repoRoot, ".git"));
|
|
176
176
|
}
|
|
177
|
-
const workspaceGit =
|
|
178
|
-
if (
|
|
177
|
+
const workspaceGit = resolve20(workspaceDir, ".git");
|
|
178
|
+
if (existsSync20(workspaceGit)) {
|
|
179
179
|
addPath(workspaceGit);
|
|
180
180
|
}
|
|
181
181
|
return [...candidates];
|
|
@@ -183,7 +183,7 @@ function resolveHostGitMetadataPaths(projectRoot, workspaceDir) {
|
|
|
183
183
|
function resolveHostRepoRootPaths(projectRoot) {
|
|
184
184
|
const candidates = new Set;
|
|
185
185
|
const addPath = (candidate) => {
|
|
186
|
-
if (
|
|
186
|
+
if (existsSync20(candidate)) {
|
|
187
187
|
candidates.add(toRealPath(candidate));
|
|
188
188
|
}
|
|
189
189
|
};
|
|
@@ -193,11 +193,11 @@ function resolveHostRepoRootPaths(projectRoot) {
|
|
|
193
193
|
addPath(monorepoRoot);
|
|
194
194
|
}
|
|
195
195
|
} catch {}
|
|
196
|
-
const reposDir =
|
|
197
|
-
if (
|
|
198
|
-
for (const entry of
|
|
196
|
+
const reposDir = resolve20(projectRoot, "repos");
|
|
197
|
+
if (existsSync20(reposDir)) {
|
|
198
|
+
for (const entry of readdirSync4(reposDir, { withFileTypes: true })) {
|
|
199
199
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
200
|
-
addPath(
|
|
200
|
+
addPath(resolve20(reposDir, entry.name));
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
203
|
}
|
|
@@ -241,8 +241,8 @@ var exports_backend_seatbelt = {};
|
|
|
241
241
|
__export(exports_backend_seatbelt, {
|
|
242
242
|
SeatbeltBackend: () => SeatbeltBackend
|
|
243
243
|
});
|
|
244
|
-
import { mkdirSync as
|
|
245
|
-
import { resolve as
|
|
244
|
+
import { mkdirSync as mkdirSync17, writeFileSync as writeFileSync12 } from "fs";
|
|
245
|
+
import { resolve as resolve32 } from "path";
|
|
246
246
|
|
|
247
247
|
class SeatbeltBackend {
|
|
248
248
|
kind = "macos-seatbelt";
|
|
@@ -266,11 +266,11 @@ class SeatbeltBackend {
|
|
|
266
266
|
};
|
|
267
267
|
}
|
|
268
268
|
writeSeatbeltProfile(options) {
|
|
269
|
-
const sandboxDir =
|
|
270
|
-
|
|
271
|
-
const profilePath =
|
|
269
|
+
const sandboxDir = resolve32(options.runtime.rootDir, "sandbox");
|
|
270
|
+
mkdirSync17(sandboxDir, { recursive: true });
|
|
271
|
+
const profilePath = resolve32(sandboxDir, "seatbelt.sb");
|
|
272
272
|
const profile = this.renderProfile(options);
|
|
273
|
-
|
|
273
|
+
writeFileSync12(profilePath, `${profile}
|
|
274
274
|
`, "utf-8");
|
|
275
275
|
return profilePath;
|
|
276
276
|
}
|
|
@@ -355,7 +355,7 @@ class SeatbeltBackend {
|
|
|
355
355
|
const realHome = process.env.HOME?.trim();
|
|
356
356
|
if (realHome) {
|
|
357
357
|
for (const binSubdir of [".local/bin", ".cargo/bin"]) {
|
|
358
|
-
const binPath =
|
|
358
|
+
const binPath = resolve32(realHome, binSubdir);
|
|
359
359
|
if (ctx.pathExists(binPath)) {
|
|
360
360
|
lines.push(`(allow file-read* (subpath ${seatbeltString(ctx.realPath(binPath))}))`);
|
|
361
361
|
}
|
|
@@ -384,8 +384,8 @@ var exports_backend_bwrap = {};
|
|
|
384
384
|
__export(exports_backend_bwrap, {
|
|
385
385
|
BwrapBackend: () => BwrapBackend
|
|
386
386
|
});
|
|
387
|
-
import { mkdirSync as
|
|
388
|
-
import { resolve as
|
|
387
|
+
import { mkdirSync as mkdirSync18 } from "fs";
|
|
388
|
+
import { resolve as resolve33 } from "path";
|
|
389
389
|
|
|
390
390
|
class BwrapBackend {
|
|
391
391
|
kind = "linux-bwrap";
|
|
@@ -514,18 +514,18 @@ class BwrapBackend {
|
|
|
514
514
|
const realHome = process.env.HOME?.trim();
|
|
515
515
|
if (realHome) {
|
|
516
516
|
for (const binSubdir of [".local/bin", ".local/lib", ".cargo/bin"]) {
|
|
517
|
-
const binPath = ctx.realPath(
|
|
517
|
+
const binPath = ctx.realPath(resolve33(realHome, binSubdir));
|
|
518
518
|
if (ctx.pathExists(binPath)) {
|
|
519
519
|
args.push("--ro-bind", binPath, binPath);
|
|
520
520
|
}
|
|
521
521
|
}
|
|
522
|
-
const agentSshDir =
|
|
522
|
+
const agentSshDir = resolve33(homeReal, ".ssh");
|
|
523
523
|
if (ctx.pathExists(agentSshDir)) {
|
|
524
524
|
args.push("--ro-bind", agentSshDir, agentSshDir);
|
|
525
525
|
} else {
|
|
526
|
-
const hostSshDir =
|
|
526
|
+
const hostSshDir = resolve33(realHome, ".ssh");
|
|
527
527
|
if (ctx.pathExists(hostSshDir)) {
|
|
528
|
-
|
|
528
|
+
mkdirSync18(agentSshDir, { recursive: true });
|
|
529
529
|
args.push("--ro-bind", hostSshDir, agentSshDir);
|
|
530
530
|
args.push("--ro-bind", hostSshDir, hostSshDir);
|
|
531
531
|
}
|
|
@@ -567,8 +567,9 @@ var init_backend_bwrap = __esm(() => {
|
|
|
567
567
|
});
|
|
568
568
|
|
|
569
569
|
// packages/runtime/src/control-plane/agent-wrapper.ts
|
|
570
|
-
import {
|
|
571
|
-
import {
|
|
570
|
+
import { createRequire } from "module";
|
|
571
|
+
import { resolve as resolve37 } from "path";
|
|
572
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync21, writeFileSync as writeFileSync14 } from "fs";
|
|
572
573
|
|
|
573
574
|
// packages/runtime/src/control-plane/runtime/context.ts
|
|
574
575
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -776,9 +777,9 @@ function isAgentRuntimeContextPath(path) {
|
|
|
776
777
|
}
|
|
777
778
|
|
|
778
779
|
// packages/runtime/src/control-plane/runtime/isolation/index.ts
|
|
779
|
-
import { existsSync as
|
|
780
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync19, readFileSync as readFileSync16, rmSync as rmSync13 } from "fs";
|
|
780
781
|
import { copyFile, mkdir as mkdir3, writeFile as writeFile2 } from "fs/promises";
|
|
781
|
-
import { resolve as
|
|
782
|
+
import { resolve as resolve35 } from "path";
|
|
782
783
|
|
|
783
784
|
// packages/runtime/src/control-plane/native/git-native.ts
|
|
784
785
|
import { chmodSync, copyFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
@@ -1853,8 +1854,8 @@ async function readCanonicalMemoryDb(projectRoot, deps = {}) {
|
|
|
1853
1854
|
var DEFAULT_RESULT_LIMIT = DEFAULT_RUNTIME_MEMORY_RETRIEVAL.topK;
|
|
1854
1855
|
var DAY_MS = 24 * 60 * 60 * 1000;
|
|
1855
1856
|
// packages/runtime/src/control-plane/native/task-ops.ts
|
|
1856
|
-
import { appendFileSync, existsSync as
|
|
1857
|
-
import { resolve as
|
|
1857
|
+
import { appendFileSync, existsSync as existsSync23, mkdirSync as mkdirSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
|
|
1858
|
+
import { resolve as resolve24 } from "path";
|
|
1858
1859
|
|
|
1859
1860
|
// packages/runtime/src/build-time-config.ts
|
|
1860
1861
|
function normalizeBuildConfig(value) {
|
|
@@ -2705,6 +2706,49 @@ function safeReadJson(path) {
|
|
|
2705
2706
|
}
|
|
2706
2707
|
}
|
|
2707
2708
|
|
|
2709
|
+
// packages/runtime/src/control-plane/skill-materializer.ts
|
|
2710
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync5, readdirSync, rmSync as rmSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
2711
|
+
import { resolve as resolve12 } from "path";
|
|
2712
|
+
import { loadSkill } from "@rig/skill-loader";
|
|
2713
|
+
var MARKER_FILENAME = ".rig-plugin";
|
|
2714
|
+
function skillDirName(id) {
|
|
2715
|
+
return id.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
2716
|
+
}
|
|
2717
|
+
async function materializeSkills(projectRoot, entries) {
|
|
2718
|
+
const skillsRoot = resolve12(projectRoot, ".pi", "skills");
|
|
2719
|
+
if (existsSync12(skillsRoot)) {
|
|
2720
|
+
for (const name of readdirSync(skillsRoot)) {
|
|
2721
|
+
const dir = resolve12(skillsRoot, name);
|
|
2722
|
+
if (existsSync12(resolve12(dir, MARKER_FILENAME))) {
|
|
2723
|
+
rmSync7(dir, { recursive: true, force: true });
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
const written = [];
|
|
2728
|
+
for (const { pluginName, skill } of entries) {
|
|
2729
|
+
const sourcePath = resolve12(projectRoot, skill.path);
|
|
2730
|
+
if (!existsSync12(sourcePath)) {
|
|
2731
|
+
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${sourcePath} does not exist`);
|
|
2732
|
+
continue;
|
|
2733
|
+
}
|
|
2734
|
+
let body;
|
|
2735
|
+
try {
|
|
2736
|
+
await loadSkill(sourcePath);
|
|
2737
|
+
body = readFileSync5(sourcePath, "utf-8");
|
|
2738
|
+
} catch (err) {
|
|
2739
|
+
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${err instanceof Error ? err.message : err}`);
|
|
2740
|
+
continue;
|
|
2741
|
+
}
|
|
2742
|
+
const dir = resolve12(skillsRoot, skillDirName(skill.id));
|
|
2743
|
+
mkdirSync8(dir, { recursive: true });
|
|
2744
|
+
writeFileSync5(resolve12(dir, "SKILL.md"), body, "utf-8");
|
|
2745
|
+
writeFileSync5(resolve12(dir, MARKER_FILENAME), `${JSON.stringify({ plugin: pluginName, skillId: skill.id }, null, 2)}
|
|
2746
|
+
`, "utf-8");
|
|
2747
|
+
written.push({ id: skill.id, pluginName, directory: dir });
|
|
2748
|
+
}
|
|
2749
|
+
return written;
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2708
2752
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
2709
2753
|
async function buildPluginHostContext(projectRoot) {
|
|
2710
2754
|
let config;
|
|
@@ -2741,6 +2785,17 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
2741
2785
|
} catch (err) {
|
|
2742
2786
|
console.warn(`[plugin-host] hook materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
2743
2787
|
}
|
|
2788
|
+
try {
|
|
2789
|
+
const skillEntries = config.plugins.flatMap((plugin) => (plugin.contributes?.skills ?? []).map((skill) => ({
|
|
2790
|
+
pluginName: plugin.name,
|
|
2791
|
+
skill
|
|
2792
|
+
})));
|
|
2793
|
+
if (skillEntries.length > 0) {
|
|
2794
|
+
await materializeSkills(projectRoot, skillEntries);
|
|
2795
|
+
}
|
|
2796
|
+
} catch (err) {
|
|
2797
|
+
console.warn(`[plugin-host] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
2798
|
+
}
|
|
2744
2799
|
return {
|
|
2745
2800
|
config,
|
|
2746
2801
|
pluginHost,
|
|
@@ -2754,12 +2809,12 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
2754
2809
|
|
|
2755
2810
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
2756
2811
|
import { spawnSync } from "child_process";
|
|
2757
|
-
import { existsSync as
|
|
2758
|
-
import { basename as basename4, join as join3, resolve as
|
|
2812
|
+
import { existsSync as existsSync14, readFileSync as readFileSync7, readdirSync as readdirSync2, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
2813
|
+
import { basename as basename4, join as join3, resolve as resolve14 } from "path";
|
|
2759
2814
|
|
|
2760
2815
|
// packages/runtime/src/control-plane/tasks/legacy-task-config-source.ts
|
|
2761
|
-
import { existsSync as
|
|
2762
|
-
import { resolve as
|
|
2816
|
+
import { existsSync as existsSync13, readFileSync as readFileSync6 } from "fs";
|
|
2817
|
+
import { resolve as resolve13 } from "path";
|
|
2763
2818
|
|
|
2764
2819
|
// packages/runtime/src/control-plane/tasks/task-record-reader.ts
|
|
2765
2820
|
async function findTaskById(reader, id) {
|
|
@@ -2782,7 +2837,7 @@ class LegacyTaskConfigReadError extends Error {
|
|
|
2782
2837
|
}
|
|
2783
2838
|
}
|
|
2784
2839
|
function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
2785
|
-
const configPath = options.configPath ??
|
|
2840
|
+
const configPath = options.configPath ?? resolve13(projectRoot, ".rig", "task-config.json");
|
|
2786
2841
|
const reader = {
|
|
2787
2842
|
async listTasks() {
|
|
2788
2843
|
return readLegacyTaskRecords(projectRoot, configPath);
|
|
@@ -2793,8 +2848,8 @@ function createLegacyTaskConfigRecordReader(projectRoot, options = {}) {
|
|
|
2793
2848
|
};
|
|
2794
2849
|
return reader;
|
|
2795
2850
|
}
|
|
2796
|
-
function readLegacyTaskRecords(projectRoot, configPath =
|
|
2797
|
-
if (!
|
|
2851
|
+
function readLegacyTaskRecords(projectRoot, configPath = resolve13(projectRoot, ".rig", "task-config.json")) {
|
|
2852
|
+
if (!existsSync13(configPath)) {
|
|
2798
2853
|
return [];
|
|
2799
2854
|
}
|
|
2800
2855
|
const rawConfig = readLegacyTaskConfigJson(projectRoot, configPath);
|
|
@@ -2802,7 +2857,7 @@ function readLegacyTaskRecords(projectRoot, configPath = resolve12(projectRoot,
|
|
|
2802
2857
|
}
|
|
2803
2858
|
function readLegacyTaskConfigJson(projectRoot, configPath) {
|
|
2804
2859
|
try {
|
|
2805
|
-
const parsed = JSON.parse(
|
|
2860
|
+
const parsed = JSON.parse(readFileSync6(configPath, "utf8"));
|
|
2806
2861
|
if (isPlainRecord(parsed)) {
|
|
2807
2862
|
return parsed;
|
|
2808
2863
|
}
|
|
@@ -2886,7 +2941,7 @@ function isPlainRecord(candidate) {
|
|
|
2886
2941
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
2887
2942
|
var FILE_TASK_PATTERN = /\.(task\.)?json$/;
|
|
2888
2943
|
function createSourceAwareTaskConfigRecordReader(projectRoot, options = {}) {
|
|
2889
|
-
const configPath = options.configPath ??
|
|
2944
|
+
const configPath = options.configPath ?? resolve14(projectRoot, ".rig", "task-config.json");
|
|
2890
2945
|
const legacy = createLegacyTaskConfigRecordReader(projectRoot, { configPath });
|
|
2891
2946
|
const spawnFn = options.spawn ?? spawnSync;
|
|
2892
2947
|
const ghBinary = options.ghBinary ?? "gh";
|
|
@@ -2951,8 +3006,19 @@ async function readSourceAwareTaskStatus(projectRoot, taskId, options = {}) {
|
|
|
2951
3006
|
return null;
|
|
2952
3007
|
}
|
|
2953
3008
|
}
|
|
3009
|
+
function updateGithubIssueTaskBySourceIssueId(sourceIssueId, taskId, update, options = {}) {
|
|
3010
|
+
const parsed = sourceIssueId?.trim().match(/^([^/]+)\/([^#]+)#(\d+)$/);
|
|
3011
|
+
if (!parsed || parsed[3] !== taskId) {
|
|
3012
|
+
return false;
|
|
3013
|
+
}
|
|
3014
|
+
applyGithubIssueUpdate(options.ghBinary ?? "gh", options.spawn ?? spawnSync, parsed[3], {
|
|
3015
|
+
sourceIssueId: sourceIssueId.trim(),
|
|
3016
|
+
taskSource: { kind: "github-issues", owner: parsed[1], repo: parsed[2] }
|
|
3017
|
+
}, update);
|
|
3018
|
+
return true;
|
|
3019
|
+
}
|
|
2954
3020
|
function updateSourceAwareTaskConfigTask(projectRoot, taskId, update, options = {}) {
|
|
2955
|
-
const configPath = options.configPath ??
|
|
3021
|
+
const configPath = options.configPath ?? resolve14(projectRoot, ".rig", "task-config.json");
|
|
2956
3022
|
const rawEntry = readRawTaskEntry(configPath, taskId);
|
|
2957
3023
|
if (!rawEntry) {
|
|
2958
3024
|
const configuredFilesPath = readConfiguredFilesTaskSourcePath(projectRoot);
|
|
@@ -3005,10 +3071,10 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
3005
3071
|
return metadata;
|
|
3006
3072
|
}
|
|
3007
3073
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
3008
|
-
const jsonPath =
|
|
3009
|
-
if (
|
|
3074
|
+
const jsonPath = resolve14(projectRoot, "rig.config.json");
|
|
3075
|
+
if (existsSync14(jsonPath)) {
|
|
3010
3076
|
try {
|
|
3011
|
-
const parsed = JSON.parse(
|
|
3077
|
+
const parsed = JSON.parse(readFileSync7(jsonPath, "utf8"));
|
|
3012
3078
|
if (isPlainRecord2(parsed) && isPlainRecord2(parsed.taskSource)) {
|
|
3013
3079
|
const source = parsed.taskSource;
|
|
3014
3080
|
return source.kind === "files" && typeof source.path === "string" ? source.path : null;
|
|
@@ -3017,12 +3083,12 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
3017
3083
|
return null;
|
|
3018
3084
|
}
|
|
3019
3085
|
}
|
|
3020
|
-
const tsPath =
|
|
3021
|
-
if (!
|
|
3086
|
+
const tsPath = resolve14(projectRoot, "rig.config.ts");
|
|
3087
|
+
if (!existsSync14(tsPath)) {
|
|
3022
3088
|
return null;
|
|
3023
3089
|
}
|
|
3024
3090
|
try {
|
|
3025
|
-
const source =
|
|
3091
|
+
const source = readFileSync7(tsPath, "utf8");
|
|
3026
3092
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
3027
3093
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
3028
3094
|
if (kind !== "files") {
|
|
@@ -3042,10 +3108,10 @@ function readRawTaskEntry(configPath, taskId) {
|
|
|
3042
3108
|
return isPlainRecord2(entry) ? entry : null;
|
|
3043
3109
|
}
|
|
3044
3110
|
function readRawTaskConfig(configPath) {
|
|
3045
|
-
if (!
|
|
3111
|
+
if (!existsSync14(configPath)) {
|
|
3046
3112
|
return null;
|
|
3047
3113
|
}
|
|
3048
|
-
const parsed = JSON.parse(
|
|
3114
|
+
const parsed = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
3049
3115
|
return isPlainRecord2(parsed) ? parsed : null;
|
|
3050
3116
|
}
|
|
3051
3117
|
function stripLegacyTaskConfigMetadata2(raw) {
|
|
@@ -3062,16 +3128,16 @@ function writeLegacyTaskStatus(configPath, taskId, status) {
|
|
|
3062
3128
|
return;
|
|
3063
3129
|
}
|
|
3064
3130
|
entry.status = status;
|
|
3065
|
-
|
|
3131
|
+
writeFileSync6(configPath, `${JSON.stringify(rawConfig, null, 2)}
|
|
3066
3132
|
`, "utf8");
|
|
3067
3133
|
}
|
|
3068
3134
|
function updateFileBackedTask(projectRoot, sourcePath, taskId, update) {
|
|
3069
|
-
const directory =
|
|
3135
|
+
const directory = resolve14(projectRoot, sourcePath);
|
|
3070
3136
|
const file = findFileBackedTaskFile(directory, taskId);
|
|
3071
3137
|
if (!file) {
|
|
3072
3138
|
return false;
|
|
3073
3139
|
}
|
|
3074
|
-
const raw = JSON.parse(
|
|
3140
|
+
const raw = JSON.parse(readFileSync7(file, "utf8"));
|
|
3075
3141
|
if (!isPlainRecord2(raw)) {
|
|
3076
3142
|
return false;
|
|
3077
3143
|
}
|
|
@@ -3088,17 +3154,17 @@ function updateFileBackedTask(projectRoot, sourcePath, taskId, update) {
|
|
|
3088
3154
|
{ body: update.comment, createdAt: new Date().toISOString(), source: "rig" }
|
|
3089
3155
|
];
|
|
3090
3156
|
}
|
|
3091
|
-
|
|
3157
|
+
writeFileSync6(file, `${JSON.stringify(raw, null, 2)}
|
|
3092
3158
|
`, "utf8");
|
|
3093
3159
|
return true;
|
|
3094
3160
|
}
|
|
3095
3161
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
3096
|
-
const directory =
|
|
3097
|
-
if (!
|
|
3162
|
+
const directory = resolve14(projectRoot, sourcePath);
|
|
3163
|
+
if (!existsSync14(directory)) {
|
|
3098
3164
|
return [];
|
|
3099
3165
|
}
|
|
3100
3166
|
const tasks = [];
|
|
3101
|
-
for (const name of
|
|
3167
|
+
for (const name of readdirSync2(directory)) {
|
|
3102
3168
|
if (!FILE_TASK_PATTERN.test(name))
|
|
3103
3169
|
continue;
|
|
3104
3170
|
const inferredId = basename4(name).replace(FILE_TASK_PATTERN, "");
|
|
@@ -3109,11 +3175,11 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
3109
3175
|
return tasks;
|
|
3110
3176
|
}
|
|
3111
3177
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
3112
|
-
const file = findFileBackedTaskFile(
|
|
3178
|
+
const file = findFileBackedTaskFile(resolve14(projectRoot, sourcePath), taskId);
|
|
3113
3179
|
if (!file) {
|
|
3114
3180
|
return null;
|
|
3115
3181
|
}
|
|
3116
|
-
const raw = JSON.parse(
|
|
3182
|
+
const raw = JSON.parse(readFileSync7(file, "utf8"));
|
|
3117
3183
|
if (!isPlainRecord2(raw)) {
|
|
3118
3184
|
return null;
|
|
3119
3185
|
}
|
|
@@ -3126,17 +3192,17 @@ function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
|
3126
3192
|
};
|
|
3127
3193
|
}
|
|
3128
3194
|
function findFileBackedTaskFile(directory, taskId) {
|
|
3129
|
-
if (!
|
|
3195
|
+
if (!existsSync14(directory)) {
|
|
3130
3196
|
return null;
|
|
3131
3197
|
}
|
|
3132
|
-
for (const name of
|
|
3198
|
+
for (const name of readdirSync2(directory)) {
|
|
3133
3199
|
if (!FILE_TASK_PATTERN.test(name))
|
|
3134
3200
|
continue;
|
|
3135
3201
|
const file = join3(directory, name);
|
|
3136
3202
|
try {
|
|
3137
3203
|
if (!statSync3(file).isFile())
|
|
3138
3204
|
continue;
|
|
3139
|
-
const raw = JSON.parse(
|
|
3205
|
+
const raw = JSON.parse(readFileSync7(file, "utf8"));
|
|
3140
3206
|
const inferredId = basename4(file).replace(FILE_TASK_PATTERN, "");
|
|
3141
3207
|
const id = isPlainRecord2(raw) && typeof raw.id === "string" ? raw.id : inferredId;
|
|
3142
3208
|
if (id === taskId) {
|
|
@@ -3306,8 +3372,8 @@ function ensureStatusLabel(bin, repo, spawnFn, label) {
|
|
|
3306
3372
|
}
|
|
3307
3373
|
}
|
|
3308
3374
|
function selectedGitHubEnv() {
|
|
3309
|
-
const token = process.env.RIG_GITHUB_SELECTED_TOKEN?.trim()
|
|
3310
|
-
return { GH_TOKEN: token, GITHUB_TOKEN: token };
|
|
3375
|
+
const token = process.env.RIG_GITHUB_SELECTED_TOKEN?.trim() || process.env.RIG_GITHUB_TOKEN?.trim() || "";
|
|
3376
|
+
return { GH_TOKEN: token, GITHUB_TOKEN: token, RIG_GITHUB_TOKEN: token };
|
|
3311
3377
|
}
|
|
3312
3378
|
function ghSpawnOptions() {
|
|
3313
3379
|
return { encoding: "utf-8", env: { ...process.env, ...selectedGitHubEnv() } };
|
|
@@ -3485,8 +3551,8 @@ function buildTaskRunLifecycleComment(input) {
|
|
|
3485
3551
|
}
|
|
3486
3552
|
|
|
3487
3553
|
// packages/runtime/src/control-plane/native/task-state.ts
|
|
3488
|
-
import { existsSync as
|
|
3489
|
-
import { basename as basename6, resolve as
|
|
3554
|
+
import { existsSync as existsSync18, readFileSync as readFileSync9, readdirSync as readdirSync3, statSync as statSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
3555
|
+
import { basename as basename6, resolve as resolve18 } from "path";
|
|
3490
3556
|
|
|
3491
3557
|
// packages/runtime/src/control-plane/state-sync/types.ts
|
|
3492
3558
|
var SUPPORTED_TASK_STATE_SCHEMA_VERSION = 1;
|
|
@@ -3594,39 +3660,39 @@ function readTaskStateMetadataEnvelope(raw) {
|
|
|
3594
3660
|
};
|
|
3595
3661
|
}
|
|
3596
3662
|
// packages/runtime/src/control-plane/state-sync/read.ts
|
|
3597
|
-
import { existsSync as
|
|
3598
|
-
import { resolve as
|
|
3663
|
+
import { existsSync as existsSync17, readFileSync as readFileSync8 } from "fs";
|
|
3664
|
+
import { resolve as resolve17 } from "path";
|
|
3599
3665
|
|
|
3600
3666
|
// packages/runtime/src/control-plane/state-sync/repo.ts
|
|
3601
|
-
import { existsSync as
|
|
3602
|
-
import { resolve as
|
|
3667
|
+
import { existsSync as existsSync16 } from "fs";
|
|
3668
|
+
import { resolve as resolve16 } from "path";
|
|
3603
3669
|
|
|
3604
3670
|
// packages/runtime/src/control-plane/repos/layout.ts
|
|
3605
3671
|
init_layout();
|
|
3606
|
-
import { existsSync as
|
|
3607
|
-
import { basename as basename5, dirname as dirname9, join as join4, resolve as
|
|
3672
|
+
import { existsSync as existsSync15 } from "fs";
|
|
3673
|
+
import { basename as basename5, dirname as dirname9, join as join4, resolve as resolve15 } from "path";
|
|
3608
3674
|
function resolveRepoStateDir(projectRoot) {
|
|
3609
|
-
const normalizedProjectRoot =
|
|
3675
|
+
const normalizedProjectRoot = resolve15(projectRoot);
|
|
3610
3676
|
const projectParent = dirname9(normalizedProjectRoot);
|
|
3611
3677
|
if (basename5(projectParent) === ".worktrees") {
|
|
3612
3678
|
const ownerRoot = dirname9(projectParent);
|
|
3613
|
-
const ownerHasRepoMarkers =
|
|
3679
|
+
const ownerHasRepoMarkers = existsSync15(resolve15(ownerRoot, ".git")) || existsSync15(resolve15(ownerRoot, ".rig", "state"));
|
|
3614
3680
|
if (ownerHasRepoMarkers) {
|
|
3615
|
-
return
|
|
3681
|
+
return resolve15(ownerRoot, ".rig", "state");
|
|
3616
3682
|
}
|
|
3617
3683
|
}
|
|
3618
|
-
return
|
|
3684
|
+
return resolve15(projectRoot, ".rig", "state");
|
|
3619
3685
|
}
|
|
3620
3686
|
function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
3621
|
-
const normalizedProjectRoot =
|
|
3687
|
+
const normalizedProjectRoot = resolve15(projectRoot);
|
|
3622
3688
|
const entry = getManagedRepoEntry(repoId);
|
|
3623
3689
|
const stateDir = resolveRepoStateDir(normalizedProjectRoot);
|
|
3624
3690
|
const metadataRelativePath = join4("repos", entry.id);
|
|
3625
|
-
const metadataRoot =
|
|
3691
|
+
const metadataRoot = resolve15(stateDir, metadataRelativePath);
|
|
3626
3692
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
3627
|
-
const runsInsideTaskWorktree = runtimeWorkspace &&
|
|
3693
|
+
const runsInsideTaskWorktree = runtimeWorkspace && resolve15(runtimeWorkspace) === normalizedProjectRoot || basename5(dirname9(normalizedProjectRoot)) === ".worktrees";
|
|
3628
3694
|
const isPrimaryManagedRepo = listManagedRepoEntries()[0]?.id === repoId;
|
|
3629
|
-
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ?
|
|
3695
|
+
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ? resolve15(process.env[entry.checkoutEnvVar].trim()) : resolve15(normalizedProjectRoot, entry.alias);
|
|
3630
3696
|
return {
|
|
3631
3697
|
projectRoot: normalizedProjectRoot,
|
|
3632
3698
|
repoId: entry.id,
|
|
@@ -3634,12 +3700,12 @@ function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
|
3634
3700
|
defaultBranch: entry.defaultBranch,
|
|
3635
3701
|
remoteUrl: entry.remoteEnvVar && process.env[entry.remoteEnvVar]?.trim() ? process.env[entry.remoteEnvVar].trim() : entry.defaultRemoteUrl,
|
|
3636
3702
|
checkoutRoot,
|
|
3637
|
-
worktreesRoot:
|
|
3703
|
+
worktreesRoot: resolve15(checkoutRoot, ".worktrees"),
|
|
3638
3704
|
stateDir,
|
|
3639
3705
|
metadataRoot,
|
|
3640
3706
|
metadataRelativePath,
|
|
3641
|
-
mirrorRoot:
|
|
3642
|
-
mirrorStatePath:
|
|
3707
|
+
mirrorRoot: resolve15(metadataRoot, "mirror.git"),
|
|
3708
|
+
mirrorStatePath: resolve15(metadataRoot, "mirror-state.json"),
|
|
3643
3709
|
mirrorStateRelativePath: join4(metadataRelativePath, "mirror-state.json")
|
|
3644
3710
|
};
|
|
3645
3711
|
}
|
|
@@ -3657,7 +3723,7 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
3657
3723
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
3658
3724
|
try {
|
|
3659
3725
|
const layout = resolveMonorepoRepoLayout(projectRoot);
|
|
3660
|
-
if (
|
|
3726
|
+
if (existsSync16(resolve16(layout.mirrorRoot, "HEAD"))) {
|
|
3661
3727
|
return layout.mirrorRoot;
|
|
3662
3728
|
}
|
|
3663
3729
|
} catch {}
|
|
@@ -3668,8 +3734,8 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
3668
3734
|
var DEFAULT_READ_DEPS2 = {
|
|
3669
3735
|
fetchRef: nativeFetchRef,
|
|
3670
3736
|
readBlobAtRef: nativeReadBlobAtRef,
|
|
3671
|
-
exists:
|
|
3672
|
-
readFile: (path) =>
|
|
3737
|
+
exists: existsSync17,
|
|
3738
|
+
readFile: (path) => readFileSync8(path, "utf8")
|
|
3673
3739
|
};
|
|
3674
3740
|
function parseIssueStatus(rawStatus) {
|
|
3675
3741
|
const normalized = normalizeTaskLifecycleStatus(rawStatus);
|
|
@@ -3750,12 +3816,12 @@ function shouldPreferLocalTrackerState(options) {
|
|
|
3750
3816
|
if (runtimeContextPath) {
|
|
3751
3817
|
return true;
|
|
3752
3818
|
}
|
|
3753
|
-
return
|
|
3819
|
+
return existsSync17(resolve17(runtimeWorkspace, ".rig", "runtime-context.json"));
|
|
3754
3820
|
}
|
|
3755
3821
|
function readLocalTrackerState(projectRoot, deps) {
|
|
3756
3822
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
3757
|
-
const issuesPath =
|
|
3758
|
-
const taskStatePath =
|
|
3823
|
+
const issuesPath = resolve17(monorepoRoot, ".beads", "issues.jsonl");
|
|
3824
|
+
const taskStatePath = resolve17(monorepoRoot, ".beads", "task-state.json");
|
|
3759
3825
|
return projectSyncedTrackerSnapshot({
|
|
3760
3826
|
source: "local",
|
|
3761
3827
|
issuesBaseOid: null,
|
|
@@ -3817,7 +3883,7 @@ function readValidationDescriptions(projectRoot) {
|
|
|
3817
3883
|
return readValidationDescriptionMap(raw);
|
|
3818
3884
|
}
|
|
3819
3885
|
function readSourceValidationDescriptions(projectRoot) {
|
|
3820
|
-
const rootRaw = readJsonFile(
|
|
3886
|
+
const rootRaw = readJsonFile(resolve18(projectRoot, "rig", "task-config.json"), {});
|
|
3821
3887
|
const sourcePath = findSourceTaskConfigPath(projectRoot);
|
|
3822
3888
|
const sourceRaw = sourcePath ? readJsonFile(sourcePath, {}) : {};
|
|
3823
3889
|
const rootDescriptions = readValidationDescriptionMap(rootRaw);
|
|
@@ -3893,15 +3959,15 @@ function readValidationDescriptionsFromMeta(meta) {
|
|
|
3893
3959
|
return meta.validation_descriptions;
|
|
3894
3960
|
}
|
|
3895
3961
|
function readLocalSourceTaskStateEnvelope(projectRoot) {
|
|
3896
|
-
const taskStatePath =
|
|
3962
|
+
const taskStatePath = resolve18(resolveMonorepoRoot2(projectRoot), ".beads", "task-state.json");
|
|
3897
3963
|
return readTaskStateMetadataEnvelope(readJsonFile(taskStatePath, {}));
|
|
3898
3964
|
}
|
|
3899
3965
|
function readLocalSourceTaskLifecycleStatus(projectRoot, taskId) {
|
|
3900
|
-
const issuesPath =
|
|
3901
|
-
if (!
|
|
3966
|
+
const issuesPath = resolve18(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
3967
|
+
if (!existsSync18(issuesPath)) {
|
|
3902
3968
|
return null;
|
|
3903
3969
|
}
|
|
3904
|
-
for (const line of
|
|
3970
|
+
for (const line of readFileSync9(issuesPath, "utf8").split(/\r?\n/)) {
|
|
3905
3971
|
const trimmed = line.trim();
|
|
3906
3972
|
if (!trimmed) {
|
|
3907
3973
|
continue;
|
|
@@ -3926,25 +3992,25 @@ function inferTaskIdFromRuntimePath(path) {
|
|
|
3926
3992
|
function artifactDirForId(projectRoot, id) {
|
|
3927
3993
|
const workspaceDir = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
3928
3994
|
if (workspaceDir) {
|
|
3929
|
-
const worktreeArtifacts =
|
|
3930
|
-
if (
|
|
3995
|
+
const worktreeArtifacts = resolve18(workspaceDir, "artifacts", id);
|
|
3996
|
+
if (existsSync18(worktreeArtifacts) || existsSync18(resolve18(workspaceDir, "artifacts"))) {
|
|
3931
3997
|
return worktreeArtifacts;
|
|
3932
3998
|
}
|
|
3933
3999
|
}
|
|
3934
4000
|
try {
|
|
3935
4001
|
const paths = resolveHarnessPaths(projectRoot);
|
|
3936
|
-
return
|
|
4002
|
+
return resolve18(paths.artifactsDir, id);
|
|
3937
4003
|
} catch {
|
|
3938
|
-
return
|
|
4004
|
+
return resolve18(resolveMonorepoRoot2(projectRoot), "artifacts", id);
|
|
3939
4005
|
}
|
|
3940
4006
|
}
|
|
3941
4007
|
function resolveTaskConfigPath(projectRoot) {
|
|
3942
4008
|
const paths = resolveHarnessPaths(projectRoot);
|
|
3943
|
-
if (
|
|
4009
|
+
if (existsSync18(paths.taskConfigPath)) {
|
|
3944
4010
|
return paths.taskConfigPath;
|
|
3945
4011
|
}
|
|
3946
4012
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
3947
|
-
if (
|
|
4013
|
+
if (existsSync18(candidate)) {
|
|
3948
4014
|
return candidate;
|
|
3949
4015
|
}
|
|
3950
4016
|
}
|
|
@@ -3952,7 +4018,7 @@ function resolveTaskConfigPath(projectRoot) {
|
|
|
3952
4018
|
}
|
|
3953
4019
|
function findSourceTaskConfigPath(projectRoot) {
|
|
3954
4020
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
3955
|
-
if (
|
|
4021
|
+
if (existsSync18(candidate)) {
|
|
3956
4022
|
return candidate;
|
|
3957
4023
|
}
|
|
3958
4024
|
}
|
|
@@ -3965,7 +4031,7 @@ function readAndSyncSourceTaskConfig(projectRoot) {
|
|
|
3965
4031
|
const synced = synchronizeTaskConfigWithTracker(projectRoot, raw);
|
|
3966
4032
|
if (sourcePath && synced.updated) {
|
|
3967
4033
|
try {
|
|
3968
|
-
|
|
4034
|
+
writeFileSync7(sourcePath, `${JSON.stringify(synced.config, null, 2)}
|
|
3969
4035
|
`, "utf-8");
|
|
3970
4036
|
} catch {}
|
|
3971
4037
|
}
|
|
@@ -4017,12 +4083,12 @@ function shouldRefreshAutoSyncedTaskConfigEntry(entry) {
|
|
|
4017
4083
|
return !candidate.role;
|
|
4018
4084
|
}
|
|
4019
4085
|
function readSourceIssueRecords(projectRoot) {
|
|
4020
|
-
const issuesPath =
|
|
4021
|
-
if (!
|
|
4086
|
+
const issuesPath = resolve18(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
4087
|
+
if (!existsSync18(issuesPath)) {
|
|
4022
4088
|
return [];
|
|
4023
4089
|
}
|
|
4024
4090
|
const records = [];
|
|
4025
|
-
for (const line of
|
|
4091
|
+
for (const line of readFileSync9(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
4026
4092
|
const trimmed = line.trim();
|
|
4027
4093
|
if (!trimmed) {
|
|
4028
4094
|
continue;
|
|
@@ -4078,19 +4144,19 @@ function readConfiguredFileTaskConfig(projectRoot) {
|
|
|
4078
4144
|
if (!sourcePath) {
|
|
4079
4145
|
return {};
|
|
4080
4146
|
}
|
|
4081
|
-
const directory =
|
|
4082
|
-
if (!
|
|
4147
|
+
const directory = resolve18(projectRoot, sourcePath);
|
|
4148
|
+
if (!existsSync18(directory)) {
|
|
4083
4149
|
return {};
|
|
4084
4150
|
}
|
|
4085
4151
|
const config = {};
|
|
4086
|
-
for (const name of
|
|
4152
|
+
for (const name of readdirSync3(directory)) {
|
|
4087
4153
|
if (!FILE_TASK_PATTERN2.test(name))
|
|
4088
4154
|
continue;
|
|
4089
|
-
const file =
|
|
4155
|
+
const file = resolve18(directory, name);
|
|
4090
4156
|
try {
|
|
4091
4157
|
if (!statSync4(file).isFile())
|
|
4092
4158
|
continue;
|
|
4093
|
-
const raw = JSON.parse(
|
|
4159
|
+
const raw = JSON.parse(readFileSync9(file, "utf8"));
|
|
4094
4160
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
4095
4161
|
continue;
|
|
4096
4162
|
const record = raw;
|
|
@@ -4132,10 +4198,10 @@ function firstStringList2(...candidates) {
|
|
|
4132
4198
|
return [];
|
|
4133
4199
|
}
|
|
4134
4200
|
function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
4135
|
-
const jsonPath =
|
|
4136
|
-
if (
|
|
4201
|
+
const jsonPath = resolve18(projectRoot, "rig.config.json");
|
|
4202
|
+
if (existsSync18(jsonPath)) {
|
|
4137
4203
|
try {
|
|
4138
|
-
const parsed = JSON.parse(
|
|
4204
|
+
const parsed = JSON.parse(readFileSync9(jsonPath, "utf8"));
|
|
4139
4205
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
4140
4206
|
const taskSource = parsed.taskSource;
|
|
4141
4207
|
if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
|
|
@@ -4147,12 +4213,12 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
4147
4213
|
return null;
|
|
4148
4214
|
}
|
|
4149
4215
|
}
|
|
4150
|
-
const tsPath =
|
|
4151
|
-
if (!
|
|
4216
|
+
const tsPath = resolve18(projectRoot, "rig.config.ts");
|
|
4217
|
+
if (!existsSync18(tsPath)) {
|
|
4152
4218
|
return null;
|
|
4153
4219
|
}
|
|
4154
4220
|
try {
|
|
4155
|
-
const source =
|
|
4221
|
+
const source = readFileSync9(tsPath, "utf8");
|
|
4156
4222
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
4157
4223
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
4158
4224
|
if (kind !== "files") {
|
|
@@ -4166,9 +4232,9 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
4166
4232
|
function sourceTaskConfigCandidates(projectRoot) {
|
|
4167
4233
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
4168
4234
|
return [
|
|
4169
|
-
runtimeContext?.monorepoMainRoot ?
|
|
4170
|
-
process.env.MONOREPO_MAIN_ROOT?.trim() ?
|
|
4171
|
-
|
|
4235
|
+
runtimeContext?.monorepoMainRoot ? resolve18(runtimeContext.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
4236
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve18(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
4237
|
+
resolve18(resolveMonorepoRoot2(projectRoot), ".rig", "task-config.json")
|
|
4172
4238
|
].filter(Boolean);
|
|
4173
4239
|
}
|
|
4174
4240
|
|
|
@@ -4177,8 +4243,8 @@ init_layout();
|
|
|
4177
4243
|
|
|
4178
4244
|
// packages/runtime/src/binary-run.ts
|
|
4179
4245
|
init_layout();
|
|
4180
|
-
import { chmodSync as chmodSync4, cpSync, existsSync as
|
|
4181
|
-
import { basename as basename7, dirname as dirname10, resolve as
|
|
4246
|
+
import { chmodSync as chmodSync4, cpSync, existsSync as existsSync19, mkdirSync as mkdirSync9, renameSync as renameSync3, rmSync as rmSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
4247
|
+
import { basename as basename7, dirname as dirname10, resolve as resolve19 } from "path";
|
|
4182
4248
|
import { fileURLToPath } from "url";
|
|
4183
4249
|
import { drainMicrotasks, gcAndSweep } from "bun:jsc";
|
|
4184
4250
|
var runtimeBinaryBuildQueue = Promise.resolve();
|
|
@@ -4204,9 +4270,9 @@ async function buildRuntimeBinary(options) {
|
|
|
4204
4270
|
});
|
|
4205
4271
|
}
|
|
4206
4272
|
async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
4207
|
-
const tempBuildDir =
|
|
4208
|
-
const tempOutputPath =
|
|
4209
|
-
|
|
4273
|
+
const tempBuildDir = resolve19(dirname10(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
4274
|
+
const tempOutputPath = resolve19(tempBuildDir, basename7(options.outputPath));
|
|
4275
|
+
mkdirSync9(tempBuildDir, { recursive: true });
|
|
4210
4276
|
await withTemporaryEnv({
|
|
4211
4277
|
...options.env,
|
|
4212
4278
|
...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
|
|
@@ -4231,7 +4297,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
4231
4297
|
`);
|
|
4232
4298
|
throw new Error(`Failed to build ${options.entrypoint}: ${details || "Bun.build() returned errors"}`);
|
|
4233
4299
|
}
|
|
4234
|
-
if (!
|
|
4300
|
+
if (!existsSync19(tempOutputPath)) {
|
|
4235
4301
|
const emitted = buildResult.outputs.map((output) => output.path).join(", ") || "(none)";
|
|
4236
4302
|
throw new Error(`Failed to build ${options.entrypoint}: Bun.build() did not emit ${tempOutputPath}. Emitted: ${emitted}`);
|
|
4237
4303
|
}
|
|
@@ -4246,7 +4312,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
4246
4312
|
});
|
|
4247
4313
|
}
|
|
4248
4314
|
})).finally(() => {
|
|
4249
|
-
|
|
4315
|
+
rmSync8(tempBuildDir, { recursive: true, force: true });
|
|
4250
4316
|
});
|
|
4251
4317
|
}
|
|
4252
4318
|
function runBestEffortBuildGc() {
|
|
@@ -4263,8 +4329,8 @@ function runtimeBinaryCacheManifestPath(outputPath) {
|
|
|
4263
4329
|
function resolveRuntimeBinaryBuildOptions(options) {
|
|
4264
4330
|
return {
|
|
4265
4331
|
...options,
|
|
4266
|
-
entrypoint:
|
|
4267
|
-
outputPath:
|
|
4332
|
+
entrypoint: resolve19(options.cwd, options.sourcePath),
|
|
4333
|
+
outputPath: resolve19(options.outputPath)
|
|
4268
4334
|
};
|
|
4269
4335
|
}
|
|
4270
4336
|
function shouldUseRuntimeBinaryBuildWorker() {
|
|
@@ -4278,7 +4344,7 @@ function shouldUseRuntimeBinaryBuildWorker() {
|
|
|
4278
4344
|
}
|
|
4279
4345
|
async function buildRuntimeBinaryViaWorker(options) {
|
|
4280
4346
|
const workerSourcePath = resolveRuntimeBinaryBuildWorkerSourcePath(options);
|
|
4281
|
-
if (!workerSourcePath || !
|
|
4347
|
+
if (!workerSourcePath || !existsSync19(workerSourcePath)) {
|
|
4282
4348
|
await buildRuntimeBinaryInProcess(options, {
|
|
4283
4349
|
manifestPath: runtimeBinaryCacheManifestPath(options.outputPath),
|
|
4284
4350
|
buildKey: createRuntimeBinaryBuildKey({
|
|
@@ -4309,13 +4375,13 @@ async function buildRuntimeBinaryViaWorker(options) {
|
|
|
4309
4375
|
new Response(build.stdout).text(),
|
|
4310
4376
|
new Response(build.stderr).text()
|
|
4311
4377
|
]);
|
|
4312
|
-
|
|
4378
|
+
rmSync8(payloadPath, { force: true });
|
|
4313
4379
|
if (exitCode !== 0) {
|
|
4314
4380
|
throw new Error(`Failed to build ${options.entrypoint}: ${(stderr || stdout || `worker exited ${exitCode}`).trim()}`);
|
|
4315
4381
|
}
|
|
4316
4382
|
}
|
|
4317
4383
|
function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
|
|
4318
|
-
return
|
|
4384
|
+
return resolve19(dirname10(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
4319
4385
|
}
|
|
4320
4386
|
function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
4321
4387
|
const envRoots = [
|
|
@@ -4324,13 +4390,13 @@ function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
|
4324
4390
|
process.env.PROJECT_RIG_ROOT?.trim()
|
|
4325
4391
|
].filter(Boolean);
|
|
4326
4392
|
for (const root of envRoots) {
|
|
4327
|
-
const candidate =
|
|
4328
|
-
if (
|
|
4393
|
+
const candidate = resolve19(root, "packages/runtime/src/binary-build-worker.ts");
|
|
4394
|
+
if (existsSync19(candidate)) {
|
|
4329
4395
|
return candidate;
|
|
4330
4396
|
}
|
|
4331
4397
|
}
|
|
4332
|
-
const localCandidate =
|
|
4333
|
-
return
|
|
4398
|
+
const localCandidate = resolve19(import.meta.dir, "binary-build-worker.ts");
|
|
4399
|
+
return existsSync19(localCandidate) ? localCandidate : null;
|
|
4334
4400
|
}
|
|
4335
4401
|
function resolveRuntimeBinaryBuildWorkerInvocation() {
|
|
4336
4402
|
const bunPath = Bun.which("bun");
|
|
@@ -4366,7 +4432,7 @@ function createRuntimeBinaryBuildKey(input) {
|
|
|
4366
4432
|
});
|
|
4367
4433
|
}
|
|
4368
4434
|
async function isRuntimeBinaryBuildFresh(input) {
|
|
4369
|
-
if (!
|
|
4435
|
+
if (!existsSync19(input.outputPath) || !existsSync19(input.manifestPath)) {
|
|
4370
4436
|
return false;
|
|
4371
4437
|
}
|
|
4372
4438
|
let manifest = null;
|
|
@@ -4379,7 +4445,7 @@ async function isRuntimeBinaryBuildFresh(input) {
|
|
|
4379
4445
|
return false;
|
|
4380
4446
|
}
|
|
4381
4447
|
for (const [filePath, expectedDigest] of Object.entries(manifest.inputs || {})) {
|
|
4382
|
-
if (!
|
|
4448
|
+
if (!existsSync19(filePath)) {
|
|
4383
4449
|
return false;
|
|
4384
4450
|
}
|
|
4385
4451
|
if (await sha256File4(filePath) !== expectedDigest) {
|
|
@@ -4392,7 +4458,7 @@ async function writeRuntimeBinaryCacheManifest(input) {
|
|
|
4392
4458
|
const inputs = {};
|
|
4393
4459
|
for (const inputPath of Object.keys(input.metafile?.inputs || {}).sort()) {
|
|
4394
4460
|
const normalized = normalizeBuildInputPath(input.cwd, inputPath);
|
|
4395
|
-
if (!normalized || !
|
|
4461
|
+
if (!normalized || !existsSync19(normalized)) {
|
|
4396
4462
|
continue;
|
|
4397
4463
|
}
|
|
4398
4464
|
inputs[normalized] = await sha256File4(normalized);
|
|
@@ -4415,7 +4481,7 @@ function normalizeBuildInputPath(cwd, inputPath) {
|
|
|
4415
4481
|
if (inputPath.startsWith("<")) {
|
|
4416
4482
|
return null;
|
|
4417
4483
|
}
|
|
4418
|
-
return
|
|
4484
|
+
return resolve19(cwd, inputPath);
|
|
4419
4485
|
}
|
|
4420
4486
|
async function sha256File4(path) {
|
|
4421
4487
|
const hasher = new Bun.CryptoHasher("sha256");
|
|
@@ -4431,8 +4497,8 @@ function sortRecord(value) {
|
|
|
4431
4497
|
async function runSerializedRuntimeBinaryBuild(action) {
|
|
4432
4498
|
const previous = runtimeBinaryBuildQueue;
|
|
4433
4499
|
let release;
|
|
4434
|
-
runtimeBinaryBuildQueue = new Promise((
|
|
4435
|
-
release =
|
|
4500
|
+
runtimeBinaryBuildQueue = new Promise((resolve20) => {
|
|
4501
|
+
release = resolve20;
|
|
4436
4502
|
});
|
|
4437
4503
|
await previous;
|
|
4438
4504
|
try {
|
|
@@ -4477,11 +4543,11 @@ async function withTemporaryCwd(cwd, action) {
|
|
|
4477
4543
|
}
|
|
4478
4544
|
|
|
4479
4545
|
// packages/runtime/src/control-plane/runtime/provisioning-env.ts
|
|
4480
|
-
import { delimiter, resolve as
|
|
4546
|
+
import { delimiter, resolve as resolve22 } from "path";
|
|
4481
4547
|
|
|
4482
4548
|
// packages/runtime/src/control-plane/runtime/runtime-paths.ts
|
|
4483
|
-
import { existsSync as
|
|
4484
|
-
import { resolve as
|
|
4549
|
+
import { existsSync as existsSync21, readdirSync as readdirSync5, realpathSync as realpathSync2 } from "fs";
|
|
4550
|
+
import { resolve as resolve21 } from "path";
|
|
4485
4551
|
|
|
4486
4552
|
// packages/runtime/src/control-plane/runtime/sandbox-utils.ts
|
|
4487
4553
|
init_utils();
|
|
@@ -4498,7 +4564,7 @@ function resolveBunBinaryPath() {
|
|
|
4498
4564
|
}
|
|
4499
4565
|
const home = process.env.HOME?.trim();
|
|
4500
4566
|
const fallbackCandidates = [
|
|
4501
|
-
home ?
|
|
4567
|
+
home ? resolve21(home, ".bun/bin/bun") : "",
|
|
4502
4568
|
"/opt/homebrew/bin/bun",
|
|
4503
4569
|
"/usr/local/bin/bun",
|
|
4504
4570
|
"/usr/bin/bun"
|
|
@@ -4526,8 +4592,8 @@ function resolveClaudeBinaryPath() {
|
|
|
4526
4592
|
}
|
|
4527
4593
|
const home = process.env.HOME?.trim();
|
|
4528
4594
|
const fallbackCandidates = [
|
|
4529
|
-
home ?
|
|
4530
|
-
home ?
|
|
4595
|
+
home ? resolve21(home, ".local/bin/claude") : "",
|
|
4596
|
+
home ? resolve21(home, ".local/share/claude/local/claude") : "",
|
|
4531
4597
|
"/opt/homebrew/bin/claude",
|
|
4532
4598
|
"/usr/local/bin/claude",
|
|
4533
4599
|
"/usr/bin/claude"
|
|
@@ -4541,35 +4607,35 @@ function resolveClaudeBinaryPath() {
|
|
|
4541
4607
|
throw new Error("claude not found in PATH");
|
|
4542
4608
|
}
|
|
4543
4609
|
function resolveBunInstallDir(bunBinaryPath = resolveBunBinaryPath()) {
|
|
4544
|
-
return
|
|
4610
|
+
return resolve21(bunBinaryPath, "../..");
|
|
4545
4611
|
}
|
|
4546
4612
|
function resolveClaudeInstallDir() {
|
|
4547
4613
|
const realPath = resolveClaudeBinaryPath();
|
|
4548
|
-
return
|
|
4614
|
+
return resolve21(realPath, "..");
|
|
4549
4615
|
}
|
|
4550
4616
|
function resolveNodeInstallDir() {
|
|
4551
4617
|
const preferredNode = resolvePreferredNodeBinary();
|
|
4552
4618
|
if (!preferredNode)
|
|
4553
4619
|
return null;
|
|
4554
4620
|
const explicitNode = process.env.RIG_NODE_BIN?.trim();
|
|
4555
|
-
if (explicitNode &&
|
|
4556
|
-
return preferredNode.endsWith("/bin/node") ?
|
|
4621
|
+
if (explicitNode && resolve21(explicitNode) === resolve21(preferredNode)) {
|
|
4622
|
+
return preferredNode.endsWith("/bin/node") ? resolve21(preferredNode, "../..") : resolve21(preferredNode, "..");
|
|
4557
4623
|
}
|
|
4558
4624
|
try {
|
|
4559
4625
|
const realPath = realpathSync2(preferredNode);
|
|
4560
4626
|
if (realPath.endsWith("/bin/node")) {
|
|
4561
|
-
return
|
|
4627
|
+
return resolve21(realPath, "../..");
|
|
4562
4628
|
}
|
|
4563
|
-
return
|
|
4629
|
+
return resolve21(realPath, "..");
|
|
4564
4630
|
} catch {
|
|
4565
|
-
return
|
|
4631
|
+
return resolve21(preferredNode, "..");
|
|
4566
4632
|
}
|
|
4567
4633
|
}
|
|
4568
4634
|
function resolveRuntimeDependencyRoots(runtimeDirs) {
|
|
4569
4635
|
const roots = [];
|
|
4570
4636
|
if (process.platform === "darwin") {
|
|
4571
4637
|
for (const macPath of ["/opt/homebrew", "/opt/homebrew/opt"]) {
|
|
4572
|
-
if (
|
|
4638
|
+
if (existsSync21(macPath)) {
|
|
4573
4639
|
roots.push(macPath);
|
|
4574
4640
|
}
|
|
4575
4641
|
}
|
|
@@ -4587,23 +4653,23 @@ function resolvePreferredNodeBinary() {
|
|
|
4587
4653
|
const candidates = [];
|
|
4588
4654
|
const envNode = process.env.RIG_NODE_BIN?.trim();
|
|
4589
4655
|
if (envNode) {
|
|
4590
|
-
const explicit =
|
|
4591
|
-
if (
|
|
4656
|
+
const explicit = resolve21(envNode);
|
|
4657
|
+
if (existsSync21(explicit)) {
|
|
4592
4658
|
return explicit;
|
|
4593
4659
|
}
|
|
4594
4660
|
}
|
|
4595
4661
|
const nvmBin = process.env.NVM_BIN?.trim();
|
|
4596
4662
|
if (nvmBin) {
|
|
4597
|
-
candidates.push(
|
|
4663
|
+
candidates.push(resolve21(nvmBin, "node"));
|
|
4598
4664
|
}
|
|
4599
4665
|
const home = process.env.HOME?.trim();
|
|
4600
4666
|
if (home) {
|
|
4601
|
-
const nvmVersionsDir =
|
|
4602
|
-
if (
|
|
4667
|
+
const nvmVersionsDir = resolve21(home, ".nvm/versions/node");
|
|
4668
|
+
if (existsSync21(nvmVersionsDir)) {
|
|
4603
4669
|
try {
|
|
4604
|
-
const versionDirs =
|
|
4670
|
+
const versionDirs = readdirSync5(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/, "")));
|
|
4605
4671
|
for (const versionDir of versionDirs) {
|
|
4606
|
-
candidates.push(
|
|
4672
|
+
candidates.push(resolve21(nvmVersionsDir, versionDir, "bin/node"));
|
|
4607
4673
|
}
|
|
4608
4674
|
} catch {}
|
|
4609
4675
|
}
|
|
@@ -4612,8 +4678,8 @@ function resolvePreferredNodeBinary() {
|
|
|
4612
4678
|
if (whichNode) {
|
|
4613
4679
|
candidates.push(whichNode);
|
|
4614
4680
|
}
|
|
4615
|
-
const deduped = uniq(candidates.map((candidate) =>
|
|
4616
|
-
const existing = deduped.filter((candidate) =>
|
|
4681
|
+
const deduped = uniq(candidates.map((candidate) => resolve21(candidate)));
|
|
4682
|
+
const existing = deduped.filter((candidate) => existsSync21(candidate));
|
|
4617
4683
|
if (existing.length === 0) {
|
|
4618
4684
|
return null;
|
|
4619
4685
|
}
|
|
@@ -4627,7 +4693,7 @@ function resolvePreferredNodeBinary() {
|
|
|
4627
4693
|
return existing[0] ?? null;
|
|
4628
4694
|
}
|
|
4629
4695
|
function inferNodeMajor(nodeBinaryPath) {
|
|
4630
|
-
const normalized =
|
|
4696
|
+
const normalized = resolve21(nodeBinaryPath).replace(/\\/g, "/");
|
|
4631
4697
|
const match = normalized.match(/(?:^|\/)(?:node-)?v?(\d+)\.\d+\.\d+(?:\/|$)/);
|
|
4632
4698
|
if (!match) {
|
|
4633
4699
|
return null;
|
|
@@ -4639,8 +4705,8 @@ function normalizeExecutablePath(candidate) {
|
|
|
4639
4705
|
if (!candidate) {
|
|
4640
4706
|
return "";
|
|
4641
4707
|
}
|
|
4642
|
-
const normalized =
|
|
4643
|
-
if (!
|
|
4708
|
+
const normalized = resolve21(candidate);
|
|
4709
|
+
if (!existsSync21(normalized)) {
|
|
4644
4710
|
return "";
|
|
4645
4711
|
}
|
|
4646
4712
|
try {
|
|
@@ -4650,7 +4716,7 @@ function normalizeExecutablePath(candidate) {
|
|
|
4650
4716
|
}
|
|
4651
4717
|
}
|
|
4652
4718
|
function looksLikeRuntimeGateway(candidate) {
|
|
4653
|
-
const normalized =
|
|
4719
|
+
const normalized = resolve21(candidate).replace(/\\/g, "/");
|
|
4654
4720
|
return normalized.includes("/.rig/bin/") || normalized.endsWith("/rig-shell") || normalized.endsWith("/rig-agent");
|
|
4655
4721
|
}
|
|
4656
4722
|
|
|
@@ -4671,7 +4737,7 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
4671
4737
|
try {
|
|
4672
4738
|
return resolveClaudeInstallDir();
|
|
4673
4739
|
} catch {
|
|
4674
|
-
return
|
|
4740
|
+
return resolve22(claudeBinary, "..");
|
|
4675
4741
|
}
|
|
4676
4742
|
})() : "";
|
|
4677
4743
|
const nodeDir = resolveNodeInstallDir();
|
|
@@ -4681,8 +4747,8 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
4681
4747
|
`${bunDir}/bin`,
|
|
4682
4748
|
claudeDir,
|
|
4683
4749
|
nodeDir ? `${nodeDir}/bin` : "",
|
|
4684
|
-
realHome ?
|
|
4685
|
-
realHome ?
|
|
4750
|
+
realHome ? resolve22(realHome, ".local/bin") : "",
|
|
4751
|
+
realHome ? resolve22(realHome, ".cargo/bin") : "",
|
|
4686
4752
|
...inheritedPath,
|
|
4687
4753
|
"/usr/local/bin",
|
|
4688
4754
|
"/usr/local/sbin",
|
|
@@ -4711,8 +4777,8 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
4711
4777
|
}
|
|
4712
4778
|
|
|
4713
4779
|
// packages/runtime/src/control-plane/runtime/baked-secrets.ts
|
|
4714
|
-
import { existsSync as
|
|
4715
|
-
import { resolve as
|
|
4780
|
+
import { existsSync as existsSync22, readFileSync as readFileSync10 } from "fs";
|
|
4781
|
+
import { resolve as resolve23 } from "path";
|
|
4716
4782
|
var BAKED_RUNTIME_SECRETS = {
|
|
4717
4783
|
ANTHROPIC_API_KEY: typeof RIG_BAKED_ANTHROPIC_API_KEY !== "undefined" ? RIG_BAKED_ANTHROPIC_API_KEY : "",
|
|
4718
4784
|
OPENAI_API_KEY: typeof RIG_BAKED_OPENAI_API_KEY !== "undefined" ? RIG_BAKED_OPENAI_API_KEY : "",
|
|
@@ -4755,12 +4821,12 @@ function resolveRuntimeSecrets(env, baked = BAKED_RUNTIME_SECRETS) {
|
|
|
4755
4821
|
return resolved;
|
|
4756
4822
|
}
|
|
4757
4823
|
function loadDotEnvSecrets(projectRoot, env = process.env) {
|
|
4758
|
-
const dotenvPath =
|
|
4759
|
-
if (!
|
|
4824
|
+
const dotenvPath = resolve23(projectRoot, ".env");
|
|
4825
|
+
if (!existsSync22(dotenvPath)) {
|
|
4760
4826
|
return {};
|
|
4761
4827
|
}
|
|
4762
4828
|
const parsed = {};
|
|
4763
|
-
const lines =
|
|
4829
|
+
const lines = readFileSync10(dotenvPath, "utf-8").split(/\r?\n/);
|
|
4764
4830
|
for (const rawLine of lines) {
|
|
4765
4831
|
const line = rawLine.trim();
|
|
4766
4832
|
if (!line || line.startsWith("#")) {
|
|
@@ -5117,16 +5183,16 @@ async function taskDeps(projectRoot, taskId) {
|
|
|
5117
5183
|
for (const dep of deps) {
|
|
5118
5184
|
const artifactDir = artifactDirForId(projectRoot, dep);
|
|
5119
5185
|
console.log(`=== ${dep} ===`);
|
|
5120
|
-
if (!
|
|
5186
|
+
if (!existsSync23(artifactDir)) {
|
|
5121
5187
|
console.log(` (no artifacts yet)
|
|
5122
5188
|
`);
|
|
5123
5189
|
continue;
|
|
5124
5190
|
}
|
|
5125
|
-
printArtifactSection(
|
|
5126
|
-
printArtifactSection(
|
|
5127
|
-
const changedFiles =
|
|
5128
|
-
if (
|
|
5129
|
-
const lines =
|
|
5191
|
+
printArtifactSection(resolve24(artifactDir, "decision-log.md"), "--- Decisions ---");
|
|
5192
|
+
printArtifactSection(resolve24(artifactDir, "next-actions.md"), "--- Next Actions (for you) ---");
|
|
5193
|
+
const changedFiles = resolve24(artifactDir, "changed-files.txt");
|
|
5194
|
+
if (existsSync23(changedFiles)) {
|
|
5195
|
+
const lines = readFileSync11(changedFiles, "utf-8").split(/\r?\n/).filter(Boolean);
|
|
5130
5196
|
console.log(`--- Changed Files (${lines.length}) ---`);
|
|
5131
5197
|
for (const line of lines) {
|
|
5132
5198
|
console.log(line);
|
|
@@ -5250,12 +5316,12 @@ function printIndented(text) {
|
|
|
5250
5316
|
}
|
|
5251
5317
|
}
|
|
5252
5318
|
function readLocalBeadsTasks(projectRoot) {
|
|
5253
|
-
const issuesPath =
|
|
5254
|
-
if (!
|
|
5319
|
+
const issuesPath = resolve24(resolveMonorepoRoot2(projectRoot), ".beads/issues.jsonl");
|
|
5320
|
+
if (!existsSync23(issuesPath)) {
|
|
5255
5321
|
return [];
|
|
5256
5322
|
}
|
|
5257
5323
|
const tasks = [];
|
|
5258
|
-
for (const line of
|
|
5324
|
+
for (const line of readFileSync11(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
5259
5325
|
const trimmed = line.trim();
|
|
5260
5326
|
if (!trimmed) {
|
|
5261
5327
|
continue;
|
|
@@ -5368,11 +5434,11 @@ function taskDependencies(projectRoot, taskId, tracker) {
|
|
|
5368
5434
|
return [...ids].sort();
|
|
5369
5435
|
}
|
|
5370
5436
|
function printArtifactSection(path, header) {
|
|
5371
|
-
if (!
|
|
5437
|
+
if (!existsSync23(path)) {
|
|
5372
5438
|
return;
|
|
5373
5439
|
}
|
|
5374
5440
|
console.log(header);
|
|
5375
|
-
process.stdout.write(
|
|
5441
|
+
process.stdout.write(readFileSync11(path, "utf-8"));
|
|
5376
5442
|
console.log("");
|
|
5377
5443
|
}
|
|
5378
5444
|
|
|
@@ -5474,7 +5540,7 @@ init_layout();
|
|
|
5474
5540
|
|
|
5475
5541
|
// packages/runtime/src/control-plane/runtime/overlay.ts
|
|
5476
5542
|
init_layout();
|
|
5477
|
-
import { mkdirSync as
|
|
5543
|
+
import { mkdirSync as mkdirSync11 } from "fs";
|
|
5478
5544
|
function ensureRuntimeOverlay(projectRoot, runtimeId, workspaceDir) {
|
|
5479
5545
|
const layout = resolveRuntimeWorkspaceLayout(workspaceDir ?? projectRoot);
|
|
5480
5546
|
const rootDir = layout.rigRoot;
|
|
@@ -5486,14 +5552,14 @@ function ensureRuntimeOverlay(projectRoot, runtimeId, workspaceDir) {
|
|
|
5486
5552
|
const sessionDir = layout.sessionDir;
|
|
5487
5553
|
const runtimeDir = layout.runtimeDir;
|
|
5488
5554
|
const contextPath = layout.contextPath;
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5555
|
+
mkdirSync11(rootDir, { recursive: true });
|
|
5556
|
+
mkdirSync11(homeDir, { recursive: true });
|
|
5557
|
+
mkdirSync11(tmpDir, { recursive: true });
|
|
5558
|
+
mkdirSync11(cacheDir, { recursive: true });
|
|
5559
|
+
mkdirSync11(logsDir, { recursive: true });
|
|
5560
|
+
mkdirSync11(stateDir, { recursive: true });
|
|
5561
|
+
mkdirSync11(sessionDir, { recursive: true });
|
|
5562
|
+
mkdirSync11(runtimeDir, { recursive: true });
|
|
5497
5563
|
return {
|
|
5498
5564
|
rootDir,
|
|
5499
5565
|
homeDir,
|
|
@@ -5511,17 +5577,17 @@ import {
|
|
|
5511
5577
|
chmodSync as chmodSync5,
|
|
5512
5578
|
copyFileSync as copyFileSync5,
|
|
5513
5579
|
cpSync as cpSync2,
|
|
5514
|
-
existsSync as
|
|
5515
|
-
mkdirSync as
|
|
5580
|
+
existsSync as existsSync25,
|
|
5581
|
+
mkdirSync as mkdirSync12,
|
|
5516
5582
|
statSync as statSync5,
|
|
5517
|
-
writeFileSync as
|
|
5583
|
+
writeFileSync as writeFileSync10
|
|
5518
5584
|
} from "fs";
|
|
5519
5585
|
import { mkdir } from "fs/promises";
|
|
5520
|
-
import { basename as basename8, delimiter as delimiter2, resolve as
|
|
5586
|
+
import { basename as basename8, delimiter as delimiter2, resolve as resolve26 } from "path";
|
|
5521
5587
|
|
|
5522
5588
|
// packages/runtime/src/control-plane/runtime/isolation/shared.ts
|
|
5523
|
-
import { existsSync as
|
|
5524
|
-
import { resolve as
|
|
5589
|
+
import { existsSync as existsSync24, readFileSync as readFileSync12, rmSync as rmSync9 } from "fs";
|
|
5590
|
+
import { resolve as resolve25 } from "path";
|
|
5525
5591
|
var generatedCredentialFiles = new Set;
|
|
5526
5592
|
var credentialCleanupRegistered = false;
|
|
5527
5593
|
function resolveMonorepoRoot3(projectRoot) {
|
|
@@ -5545,7 +5611,7 @@ function resolveHostGitBinary() {
|
|
|
5545
5611
|
if (!candidate || isRuntimeGatewayGitPath(candidate)) {
|
|
5546
5612
|
continue;
|
|
5547
5613
|
}
|
|
5548
|
-
if (
|
|
5614
|
+
if (existsSync24(candidate)) {
|
|
5549
5615
|
return candidate;
|
|
5550
5616
|
}
|
|
5551
5617
|
}
|
|
@@ -5611,7 +5677,7 @@ async function refreshRemoteBranch(repoRoot, remote, branch) {
|
|
|
5611
5677
|
}
|
|
5612
5678
|
}
|
|
5613
5679
|
async function tryReadGitHead(repoRoot) {
|
|
5614
|
-
if (!
|
|
5680
|
+
if (!existsSync24(resolve25(repoRoot, ".git"))) {
|
|
5615
5681
|
return;
|
|
5616
5682
|
}
|
|
5617
5683
|
const result = await runGitCommand(repoRoot, ["rev-parse", "HEAD"]);
|
|
@@ -5622,7 +5688,7 @@ async function tryReadGitHead(repoRoot) {
|
|
|
5622
5688
|
return value || undefined;
|
|
5623
5689
|
}
|
|
5624
5690
|
async function captureRepoDirtyFiles(repoRoot) {
|
|
5625
|
-
if (!
|
|
5691
|
+
if (!existsSync24(resolve25(repoRoot, ".git"))) {
|
|
5626
5692
|
return [];
|
|
5627
5693
|
}
|
|
5628
5694
|
const files = new Set;
|
|
@@ -5658,7 +5724,7 @@ function registerCredentialCleanup(path) {
|
|
|
5658
5724
|
const cleanup = () => {
|
|
5659
5725
|
for (const filePath of generatedCredentialFiles) {
|
|
5660
5726
|
try {
|
|
5661
|
-
|
|
5727
|
+
rmSync9(filePath, { force: true });
|
|
5662
5728
|
} catch {}
|
|
5663
5729
|
}
|
|
5664
5730
|
generatedCredentialFiles.clear();
|
|
@@ -5710,20 +5776,23 @@ function hashProjectPath(workspaceDir) {
|
|
|
5710
5776
|
}
|
|
5711
5777
|
function resolveGithubCliBinaryPath() {
|
|
5712
5778
|
const explicit = process.env.RIG_GH_BIN?.trim();
|
|
5713
|
-
if (explicit &&
|
|
5779
|
+
if (explicit && existsSync24(explicit) && !isRuntimeGatewayGhPath(explicit)) {
|
|
5714
5780
|
return explicit;
|
|
5715
5781
|
}
|
|
5716
|
-
const
|
|
5717
|
-
|
|
5718
|
-
return bunResolved;
|
|
5719
|
-
}
|
|
5720
|
-
for (const candidate of ["/opt/homebrew/bin/gh", "/usr/local/bin/gh", "/usr/bin/gh"]) {
|
|
5721
|
-
if (existsSync23(candidate)) {
|
|
5782
|
+
for (const candidate of ["/usr/bin/gh", "/opt/homebrew/bin/gh", "/usr/local/bin/gh"]) {
|
|
5783
|
+
if (existsSync24(candidate)) {
|
|
5722
5784
|
return candidate;
|
|
5723
5785
|
}
|
|
5724
5786
|
}
|
|
5787
|
+
const bunResolved = Bun.which("gh");
|
|
5788
|
+
if (bunResolved && existsSync24(bunResolved) && !isRuntimeGatewayGhPath(bunResolved)) {
|
|
5789
|
+
return bunResolved;
|
|
5790
|
+
}
|
|
5725
5791
|
return "";
|
|
5726
5792
|
}
|
|
5793
|
+
function isRuntimeGatewayGhPath(candidate) {
|
|
5794
|
+
return /\/\.rig\/bin\/gh$/.test(candidate.replace(/\\/g, "/"));
|
|
5795
|
+
}
|
|
5727
5796
|
async function resolveGithubCliAuthToken(ghBinary = "") {
|
|
5728
5797
|
const gh = ghBinary || resolveGithubCliBinaryPath();
|
|
5729
5798
|
if (!gh) {
|
|
@@ -5750,17 +5819,17 @@ function resolveSystemCertBundlePath() {
|
|
|
5750
5819
|
"/opt/homebrew/etc/openssl@3/cert.pem"
|
|
5751
5820
|
];
|
|
5752
5821
|
for (const candidate of candidates) {
|
|
5753
|
-
if (candidate &&
|
|
5754
|
-
return
|
|
5822
|
+
if (candidate && existsSync24(candidate)) {
|
|
5823
|
+
return resolve25(candidate);
|
|
5755
5824
|
}
|
|
5756
5825
|
}
|
|
5757
5826
|
return "";
|
|
5758
5827
|
}
|
|
5759
5828
|
function readKnownHosts(path) {
|
|
5760
|
-
if (!
|
|
5829
|
+
if (!existsSync24(path)) {
|
|
5761
5830
|
return new Set;
|
|
5762
5831
|
}
|
|
5763
|
-
return new Set(
|
|
5832
|
+
return new Set(readFileSync12(path, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
|
|
5764
5833
|
}
|
|
5765
5834
|
|
|
5766
5835
|
// packages/runtime/src/control-plane/runtime/isolation/home.ts
|
|
@@ -5771,6 +5840,21 @@ var GITHUB_KNOWN_HOSTS = [
|
|
|
5771
5840
|
"github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk="
|
|
5772
5841
|
].join(`
|
|
5773
5842
|
`);
|
|
5843
|
+
function resolveControlPlaneSourceRoot(projectRoot) {
|
|
5844
|
+
const candidates = [
|
|
5845
|
+
process.env.RIG_CONTROL_PLANE_SOURCE_ROOT?.trim(),
|
|
5846
|
+
process.env.RIG_HOST_PROJECT_ROOT?.trim(),
|
|
5847
|
+
resolve26(import.meta.dir, "../../../../.."),
|
|
5848
|
+
projectRoot
|
|
5849
|
+
].filter((value) => Boolean(value));
|
|
5850
|
+
for (const candidate of candidates) {
|
|
5851
|
+
const root = resolve26(candidate);
|
|
5852
|
+
if (existsSync25(resolve26(root, "packages/runtime/src/control-plane/pi-sessiond/bin.ts"))) {
|
|
5853
|
+
return root;
|
|
5854
|
+
}
|
|
5855
|
+
}
|
|
5856
|
+
return "";
|
|
5857
|
+
}
|
|
5774
5858
|
async function runtimeEnv(projectRoot, runtime) {
|
|
5775
5859
|
const bunBinaryPath = resolveBunBinaryPath();
|
|
5776
5860
|
const bunDir = resolveBunInstallDir(bunBinaryPath);
|
|
@@ -5785,7 +5869,7 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5785
5869
|
try {
|
|
5786
5870
|
return resolveClaudeInstallDir();
|
|
5787
5871
|
} catch {
|
|
5788
|
-
return
|
|
5872
|
+
return resolve26(claudeBinaryPath, "..");
|
|
5789
5873
|
}
|
|
5790
5874
|
})() : "";
|
|
5791
5875
|
const nodeDir = resolveNodeInstallDir();
|
|
@@ -5800,8 +5884,8 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5800
5884
|
`${bunDir}/bin`,
|
|
5801
5885
|
claudeDir,
|
|
5802
5886
|
nodeDir ? `${nodeDir}/bin` : "",
|
|
5803
|
-
realHome ?
|
|
5804
|
-
realHome ?
|
|
5887
|
+
realHome ? resolve26(realHome, ".local/bin") : "",
|
|
5888
|
+
realHome ? resolve26(realHome, ".cargo/bin") : "",
|
|
5805
5889
|
...inheritedPath,
|
|
5806
5890
|
"/usr/local/bin",
|
|
5807
5891
|
"/usr/local/sbin",
|
|
@@ -5812,18 +5896,22 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5812
5896
|
"/usr/sbin",
|
|
5813
5897
|
"/sbin"
|
|
5814
5898
|
].filter(Boolean);
|
|
5815
|
-
const runtimeBash =
|
|
5816
|
-
const runtimeRigGit =
|
|
5817
|
-
const preferredShell =
|
|
5899
|
+
const runtimeBash = resolve26(runtime.binDir, "bash");
|
|
5900
|
+
const runtimeRigGit = resolve26(runtime.binDir, runtimeRigGitFileName());
|
|
5901
|
+
const preferredShell = existsSync25(runtimeBash) ? runtimeBash : "/bin/bash";
|
|
5818
5902
|
const nativeRuntimeLibraryPath = await materializeNativeRuntimeLibrary(runtime.binDir);
|
|
5903
|
+
const controlPlaneSourceRoot = resolveControlPlaneSourceRoot(projectRoot);
|
|
5819
5904
|
const env = {
|
|
5820
5905
|
PROJECT_RIG_ROOT: projectRoot,
|
|
5821
5906
|
RIG_HOST_PROJECT_ROOT: projectRoot,
|
|
5907
|
+
...controlPlaneSourceRoot ? { RIG_CONTROL_PLANE_SOURCE_ROOT: controlPlaneSourceRoot } : {},
|
|
5822
5908
|
HOME: runtime.homeDir,
|
|
5823
5909
|
TMPDIR: runtime.tmpDir,
|
|
5824
5910
|
XDG_CACHE_HOME: runtime.cacheDir,
|
|
5825
5911
|
XDG_STATE_HOME: runtime.stateDir,
|
|
5826
5912
|
RIG_AGENT_ID: runtime.id,
|
|
5913
|
+
...process.env.RIG_RUN_ID?.trim() ? { RIG_RUN_ID: process.env.RIG_RUN_ID.trim() } : {},
|
|
5914
|
+
...process.env.RIG_SERVER_RUN_ID?.trim() ? { RIG_SERVER_RUN_ID: process.env.RIG_SERVER_RUN_ID.trim() } : {},
|
|
5827
5915
|
RIG_TASK_ID: runtime.taskId,
|
|
5828
5916
|
RIG_TASK_RUNTIME_ID: runtime.id,
|
|
5829
5917
|
RIG_TASK_WORKSPACE: runtime.workspaceDir,
|
|
@@ -5831,30 +5919,30 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5831
5919
|
RIG_RUNTIME_MODE: runtime.mode,
|
|
5832
5920
|
RIG_RUNTIME_HOME: runtime.rootDir,
|
|
5833
5921
|
RIG_RUNTIME_BIN_DIR: runtime.binDir,
|
|
5834
|
-
...
|
|
5922
|
+
...existsSync25(runtimeRigGit) ? { RIG_NATIVE_GIT_BIN: runtimeRigGit } : {},
|
|
5835
5923
|
RIG_BUN_PATH: bunBinaryPath,
|
|
5836
5924
|
...claudeBinaryPath ? { RIG_CLAUDE_PATH: claudeBinaryPath } : {},
|
|
5837
|
-
RIG_AGENT_BIN:
|
|
5925
|
+
RIG_AGENT_BIN: resolve26(runtime.binDir, "rig-agent"),
|
|
5838
5926
|
RIG_HOOKS_ACTIVE: "1",
|
|
5839
5927
|
RIG_AUTO_PR_ON_COMPLETE: "1",
|
|
5840
|
-
RIG_POLICY_FILE:
|
|
5928
|
+
RIG_POLICY_FILE: resolve26(projectRoot, "rig/policy/policy.json"),
|
|
5841
5929
|
RIG_STATE_DIR: runtime.stateDir,
|
|
5842
5930
|
RIG_LOGS_DIR: runtime.logsDir,
|
|
5843
|
-
RIG_SESSION_FILE:
|
|
5931
|
+
RIG_SESSION_FILE: resolve26(runtime.sessionDir, "session.json"),
|
|
5844
5932
|
MONOREPO_ROOT: runtime.workspaceDir,
|
|
5845
5933
|
MONOREPO_MAIN_ROOT: monorepoMainRoot,
|
|
5846
|
-
TS_API_TESTS_DIR:
|
|
5934
|
+
TS_API_TESTS_DIR: resolve26(runtime.workspaceDir, "TSAPITests"),
|
|
5847
5935
|
BASH: preferredShell,
|
|
5848
5936
|
SHELL: preferredShell,
|
|
5849
5937
|
PATH: [...new Set(pathEntries)].join(delimiter2),
|
|
5850
5938
|
LANG: process.env.LANG ?? "en_US.UTF-8",
|
|
5851
5939
|
TERM: process.env.TERM ?? "xterm-256color",
|
|
5852
5940
|
PYTHONDONTWRITEBYTECODE: "1",
|
|
5853
|
-
PYTHONPYCACHEPREFIX:
|
|
5941
|
+
PYTHONPYCACHEPREFIX: resolve26(runtime.cacheDir, "python"),
|
|
5854
5942
|
...process.env.RIG_PR_BASE_PROJECT && { RIG_PR_BASE_PROJECT: process.env.RIG_PR_BASE_PROJECT },
|
|
5855
5943
|
...process.env.RIG_PR_BASE_MONOREPO && { RIG_PR_BASE_MONOREPO: process.env.RIG_PR_BASE_MONOREPO },
|
|
5856
5944
|
CLAUDE_HOME: runtime.claudeHomeDir,
|
|
5857
|
-
PI_CODING_AGENT_DIR:
|
|
5945
|
+
PI_CODING_AGENT_DIR: resolve26(runtime.homeDir, ".pi", "agent"),
|
|
5858
5946
|
[RUNTIME_CONTEXT_ENV]: runtime.contextFile,
|
|
5859
5947
|
...nativeRuntimeLibraryPath ? { RIG_NATIVE_RUNTIME_LIB: nativeRuntimeLibraryPath } : {},
|
|
5860
5948
|
...hostGhBinary ? { RIG_GH_BIN: hostGhBinary } : {},
|
|
@@ -5865,16 +5953,16 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5865
5953
|
NODE_EXTRA_CA_CERTS: runtimeCertBundlePath
|
|
5866
5954
|
} : {}
|
|
5867
5955
|
};
|
|
5868
|
-
const knownHostsPath =
|
|
5869
|
-
if (
|
|
5870
|
-
const agentSshKey =
|
|
5956
|
+
const knownHostsPath = resolve26(runtime.homeDir, ".ssh", "known_hosts");
|
|
5957
|
+
if (existsSync25(knownHostsPath)) {
|
|
5958
|
+
const agentSshKey = resolve26(runtime.homeDir, ".ssh", "rig-agent-key");
|
|
5871
5959
|
const sshParts = [
|
|
5872
5960
|
"ssh",
|
|
5873
5961
|
`-o UserKnownHostsFile="${knownHostsPath}"`,
|
|
5874
5962
|
"-o StrictHostKeyChecking=yes",
|
|
5875
5963
|
"-F /dev/null"
|
|
5876
5964
|
];
|
|
5877
|
-
if (
|
|
5965
|
+
if (existsSync25(agentSshKey)) {
|
|
5878
5966
|
sshParts.splice(1, 0, `-i "${agentSshKey}"`, "-o IdentitiesOnly=yes");
|
|
5879
5967
|
}
|
|
5880
5968
|
env.GIT_SSH_COMMAND = sshParts.join(" ");
|
|
@@ -5911,7 +5999,7 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5911
5999
|
if (!env.GREPTILE_GITHUB_TOKEN && env.GITHUB_TOKEN) {
|
|
5912
6000
|
env.GREPTILE_GITHUB_TOKEN = env.GITHUB_TOKEN;
|
|
5913
6001
|
}
|
|
5914
|
-
if (
|
|
6002
|
+
if (existsSync25(runtime.contextFile)) {
|
|
5915
6003
|
const runtimeContext = loadRuntimeContext(runtime.contextFile);
|
|
5916
6004
|
Object.assign(env, runtimeMemoryEnvFromContext(runtimeContext));
|
|
5917
6005
|
Object.assign(env, browserEnvFromContext(runtimeContext.browser));
|
|
@@ -5925,30 +6013,30 @@ async function provisionRuntimeHome(runtime, options = {}) {
|
|
|
5925
6013
|
await mkdir(runtime.cacheDir, { recursive: true });
|
|
5926
6014
|
await provisionAgentSshKey(runtime.homeDir);
|
|
5927
6015
|
if (options.provider === "codex") {
|
|
5928
|
-
const hasCodexAuth = await injectCodexAuth(
|
|
6016
|
+
const hasCodexAuth = await injectCodexAuth(resolve26(runtime.homeDir, ".codex"));
|
|
5929
6017
|
if (!hasCodexAuth) {
|
|
5930
6018
|
console.warn("[rig] No Codex auth.json found for isolated runtime. " + "Run `codex login` in your host shell, then retry the agent run.");
|
|
5931
6019
|
}
|
|
5932
6020
|
}
|
|
5933
6021
|
if (options.provider === "pi") {
|
|
5934
|
-
const hasPiAuth = await injectPiAgentConfig(
|
|
6022
|
+
const hasPiAuth = await injectPiAgentConfig(resolve26(runtime.homeDir, ".pi", "agent"));
|
|
5935
6023
|
if (!hasPiAuth) {
|
|
5936
6024
|
console.warn("[rig] No Pi auth.json found for isolated runtime. " + "Run `pi /login` in your host shell, then retry the agent run.");
|
|
5937
6025
|
}
|
|
5938
6026
|
}
|
|
5939
6027
|
}
|
|
5940
6028
|
async function provisionClaudeHome(config) {
|
|
5941
|
-
|
|
5942
|
-
const workspaceSettings =
|
|
5943
|
-
const hostSettings =
|
|
5944
|
-
const projectSettings =
|
|
6029
|
+
mkdirSync12(config.claudeHomeDir, { recursive: true });
|
|
6030
|
+
const workspaceSettings = resolve26(config.workspaceDir, ".claude/settings.json");
|
|
6031
|
+
const hostSettings = resolve26(config.hostProjectRoot, ".claude/settings.json");
|
|
6032
|
+
const projectSettings = existsSync25(workspaceSettings) ? workspaceSettings : hostSettings;
|
|
5945
6033
|
const runtimeSettings = await loadRuntimeClaudeSettings(projectSettings);
|
|
5946
|
-
if (
|
|
5947
|
-
|
|
6034
|
+
if (existsSync25(projectSettings)) {
|
|
6035
|
+
writeFileSync10(resolve26(config.claudeHomeDir, "settings.local.json"), `${JSON.stringify(runtimeSettings, null, 2)}
|
|
5948
6036
|
`, "utf-8");
|
|
5949
6037
|
}
|
|
5950
6038
|
writeClaudeProjectSettings(config.claudeHomeDir, config.workspaceDir, runtimeSettings);
|
|
5951
|
-
|
|
6039
|
+
writeFileSync10(resolve26(config.claudeHomeDir, "settings.json"), JSON.stringify({
|
|
5952
6040
|
permissions: { defaultMode: "bypassPermissions" },
|
|
5953
6041
|
autoMemoryEnabled: false
|
|
5954
6042
|
}, null, 2));
|
|
@@ -5956,12 +6044,12 @@ async function provisionClaudeHome(config) {
|
|
|
5956
6044
|
if (!hasCredentials) {
|
|
5957
6045
|
console.warn("[rig] No Claude credentials found for isolated runtime. " + "Run `claude /login` in your host shell, then retry the agent run.");
|
|
5958
6046
|
}
|
|
5959
|
-
const realClaudeHome =
|
|
5960
|
-
if (process.env.HOME &&
|
|
5961
|
-
cpSync2(
|
|
6047
|
+
const realClaudeHome = resolve26(process.env.HOME ?? "", ".claude");
|
|
6048
|
+
if (process.env.HOME && existsSync25(resolve26(realClaudeHome, "CLAUDE.md"))) {
|
|
6049
|
+
cpSync2(resolve26(realClaudeHome, "CLAUDE.md"), resolve26(config.claudeHomeDir, "CLAUDE.md"));
|
|
5962
6050
|
}
|
|
5963
|
-
if (process.env.HOME &&
|
|
5964
|
-
cpSync2(
|
|
6051
|
+
if (process.env.HOME && existsSync25(resolve26(realClaudeHome, "agents"))) {
|
|
6052
|
+
cpSync2(resolve26(realClaudeHome, "agents"), resolve26(config.claudeHomeDir, "agents"), { recursive: true });
|
|
5965
6053
|
}
|
|
5966
6054
|
if (process.platform === "darwin" && process.env.HOME) {
|
|
5967
6055
|
writeClaudeProjectSettings(realClaudeHome, config.workspaceDir, runtimeSettings);
|
|
@@ -5972,10 +6060,10 @@ async function materializeRuntimeCertBundle(runtime) {
|
|
|
5972
6060
|
if (!sourcePath) {
|
|
5973
6061
|
return "";
|
|
5974
6062
|
}
|
|
5975
|
-
const certsDir =
|
|
5976
|
-
const targetPath =
|
|
6063
|
+
const certsDir = resolve26(runtime.rootDir, "certs");
|
|
6064
|
+
const targetPath = resolve26(certsDir, "ca-certificates.pem");
|
|
5977
6065
|
await mkdir(certsDir, { recursive: true });
|
|
5978
|
-
let shouldCopy = !
|
|
6066
|
+
let shouldCopy = !existsSync25(targetPath);
|
|
5979
6067
|
if (!shouldCopy) {
|
|
5980
6068
|
try {
|
|
5981
6069
|
shouldCopy = statSync5(sourcePath).mtimeMs > statSync5(targetPath).mtimeMs;
|
|
@@ -5997,7 +6085,7 @@ function applyGitHubCredentialHelperEnv(env) {
|
|
|
5997
6085
|
env.GIT_CONFIG_VALUE_1 = '!f() { test "$1" = get || exit 0; token="${GITHUB_TOKEN:-${GH_TOKEN:-${RIG_GITHUB_TOKEN:-}}}"; test -n "$token" || exit 0; echo username=x-access-token; echo password="$token"; }; f';
|
|
5998
6086
|
}
|
|
5999
6087
|
function persistRuntimeSecrets(runtimeRoot, env) {
|
|
6000
|
-
const secretsPath =
|
|
6088
|
+
const secretsPath = resolve26(runtimeRoot, "runtime-secrets.json");
|
|
6001
6089
|
const persisted = {};
|
|
6002
6090
|
for (const key of [
|
|
6003
6091
|
"GITHUB_TOKEN",
|
|
@@ -6016,12 +6104,12 @@ function persistRuntimeSecrets(runtimeRoot, env) {
|
|
|
6016
6104
|
if (Object.keys(persisted).length === 0) {
|
|
6017
6105
|
return;
|
|
6018
6106
|
}
|
|
6019
|
-
|
|
6107
|
+
writeFileSync10(secretsPath, `${JSON.stringify(persisted, null, 2)}
|
|
6020
6108
|
`, "utf-8");
|
|
6021
6109
|
}
|
|
6022
6110
|
async function provisionAgentSshKey(homeDir) {
|
|
6023
|
-
const sshDir =
|
|
6024
|
-
if (!
|
|
6111
|
+
const sshDir = resolve26(homeDir, ".ssh");
|
|
6112
|
+
if (!existsSync25(sshDir)) {
|
|
6025
6113
|
await mkdir(sshDir, { recursive: true });
|
|
6026
6114
|
}
|
|
6027
6115
|
seedKnownHosts(sshDir);
|
|
@@ -6029,27 +6117,27 @@ async function provisionAgentSshKey(homeDir) {
|
|
|
6029
6117
|
const privateKey = decodeProvisionedSshKey(secrets.GITHUB_SSH_KEY);
|
|
6030
6118
|
if (!privateKey) {
|
|
6031
6119
|
const hostKeyPath = resolveHostSshKeyPath(process.env.HOME ?? "");
|
|
6032
|
-
if (!process.env.HOME || !
|
|
6120
|
+
if (!process.env.HOME || !existsSync25(hostKeyPath)) {
|
|
6033
6121
|
return;
|
|
6034
6122
|
}
|
|
6035
|
-
const agentKeyPath2 =
|
|
6036
|
-
if (!
|
|
6123
|
+
const agentKeyPath2 = resolve26(sshDir, "rig-agent-key");
|
|
6124
|
+
if (!existsSync25(agentKeyPath2)) {
|
|
6037
6125
|
copyFileSync5(hostKeyPath, agentKeyPath2);
|
|
6038
6126
|
chmodSync5(agentKeyPath2, 384);
|
|
6039
6127
|
}
|
|
6040
6128
|
const hostPubPath = `${hostKeyPath}.pub`;
|
|
6041
|
-
if (
|
|
6129
|
+
if (existsSync25(hostPubPath)) {
|
|
6042
6130
|
const agentPubPath = `${agentKeyPath2}.pub`;
|
|
6043
|
-
if (!
|
|
6131
|
+
if (!existsSync25(agentPubPath)) {
|
|
6044
6132
|
copyFileSync5(hostPubPath, agentPubPath);
|
|
6045
6133
|
}
|
|
6046
6134
|
}
|
|
6047
6135
|
writeSshConfig(sshDir, agentKeyPath2);
|
|
6048
6136
|
return;
|
|
6049
6137
|
}
|
|
6050
|
-
const agentKeyPath =
|
|
6051
|
-
if (!
|
|
6052
|
-
|
|
6138
|
+
const agentKeyPath = resolve26(sshDir, "rig-agent-key");
|
|
6139
|
+
if (!existsSync25(agentKeyPath)) {
|
|
6140
|
+
writeFileSync10(agentKeyPath, privateKey, { mode: 384 });
|
|
6053
6141
|
}
|
|
6054
6142
|
writeSshConfig(sshDir, agentKeyPath);
|
|
6055
6143
|
}
|
|
@@ -6066,21 +6154,21 @@ function decodeProvisionedSshKey(encodedKey) {
|
|
|
6066
6154
|
`;
|
|
6067
6155
|
}
|
|
6068
6156
|
function resolveHostSshKeyPath(homeDir) {
|
|
6069
|
-
const sshDir =
|
|
6157
|
+
const sshDir = resolve26(homeDir, ".ssh");
|
|
6070
6158
|
const candidates = [
|
|
6071
6159
|
"rig-agent-key",
|
|
6072
6160
|
"id_ed25519",
|
|
6073
6161
|
"id_ecdsa",
|
|
6074
6162
|
"id_rsa"
|
|
6075
|
-
].map((name) =>
|
|
6076
|
-
return candidates.find((candidate) =>
|
|
6163
|
+
].map((name) => resolve26(sshDir, name));
|
|
6164
|
+
return candidates.find((candidate) => existsSync25(candidate)) ?? resolve26(sshDir, "rig-agent-key");
|
|
6077
6165
|
}
|
|
6078
6166
|
function writeSshConfig(sshDir, keyPath) {
|
|
6079
|
-
const configPath =
|
|
6080
|
-
if (
|
|
6167
|
+
const configPath = resolve26(sshDir, "config");
|
|
6168
|
+
if (existsSync25(configPath)) {
|
|
6081
6169
|
return;
|
|
6082
6170
|
}
|
|
6083
|
-
const knownHostsPath =
|
|
6171
|
+
const knownHostsPath = resolve26(sshDir, "known_hosts");
|
|
6084
6172
|
const config = [
|
|
6085
6173
|
"Host github.com",
|
|
6086
6174
|
` IdentityFile ${keyPath}`,
|
|
@@ -6090,10 +6178,10 @@ function writeSshConfig(sshDir, keyPath) {
|
|
|
6090
6178
|
""
|
|
6091
6179
|
].join(`
|
|
6092
6180
|
`);
|
|
6093
|
-
|
|
6181
|
+
writeFileSync10(configPath, config, { mode: 420 });
|
|
6094
6182
|
}
|
|
6095
6183
|
function seedKnownHosts(sshDir) {
|
|
6096
|
-
const knownHostsPath =
|
|
6184
|
+
const knownHostsPath = resolve26(sshDir, "known_hosts");
|
|
6097
6185
|
const existingLines = readKnownHosts(knownHostsPath);
|
|
6098
6186
|
const requiredLines = GITHUB_KNOWN_HOSTS.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
6099
6187
|
const missing = requiredLines.filter((line) => !existingLines.has(line));
|
|
@@ -6104,23 +6192,23 @@ function seedKnownHosts(sshDir) {
|
|
|
6104
6192
|
for (const line of missing) {
|
|
6105
6193
|
existingLines.add(line);
|
|
6106
6194
|
}
|
|
6107
|
-
|
|
6195
|
+
writeFileSync10(knownHostsPath, `${Array.from(existingLines).join(`
|
|
6108
6196
|
`)}
|
|
6109
6197
|
`, { mode: 420 });
|
|
6110
6198
|
} catch (err) {
|
|
6111
|
-
const hint =
|
|
6199
|
+
const hint = existsSync25(knownHostsPath) ? "" : " \u2014 known_hosts is missing; git SSH operations may fail";
|
|
6112
6200
|
console.warn(`[rig] Could not update ${knownHostsPath}: ${err instanceof Error ? err.message : String(err)}${hint}`);
|
|
6113
6201
|
}
|
|
6114
6202
|
}
|
|
6115
6203
|
function writeClaudeProjectSettings(claudeHomeDir, workspaceDir, runtimeSettings) {
|
|
6116
6204
|
const projectHash = hashProjectPath(workspaceDir);
|
|
6117
|
-
const projectDir =
|
|
6118
|
-
|
|
6119
|
-
|
|
6205
|
+
const projectDir = resolve26(claudeHomeDir, "projects", projectHash);
|
|
6206
|
+
mkdirSync12(projectDir, { recursive: true });
|
|
6207
|
+
writeFileSync10(resolve26(projectDir, "settings.json"), `${JSON.stringify(runtimeSettings, null, 2)}
|
|
6120
6208
|
`, "utf-8");
|
|
6121
6209
|
}
|
|
6122
6210
|
async function loadRuntimeClaudeSettings(projectSettingsPath) {
|
|
6123
|
-
if (!
|
|
6211
|
+
if (!existsSync25(projectSettingsPath)) {
|
|
6124
6212
|
return {};
|
|
6125
6213
|
}
|
|
6126
6214
|
let parsed;
|
|
@@ -6166,7 +6254,7 @@ async function loadRuntimeClaudeSettings(projectSettingsPath) {
|
|
|
6166
6254
|
return clone;
|
|
6167
6255
|
}
|
|
6168
6256
|
async function injectClaudeCredentials(claudeHomeDir, options = {}) {
|
|
6169
|
-
const credentialsPath =
|
|
6257
|
+
const credentialsPath = resolve26(claudeHomeDir, ".credentials.json");
|
|
6170
6258
|
const platform = options.platform ?? process.platform;
|
|
6171
6259
|
if (platform === "darwin") {
|
|
6172
6260
|
const raw = options.loadKeychainCredentials ? await options.loadKeychainCredentials() : await (async () => {
|
|
@@ -6176,16 +6264,16 @@ async function injectClaudeCredentials(claudeHomeDir, options = {}) {
|
|
|
6176
6264
|
if (raw) {
|
|
6177
6265
|
try {
|
|
6178
6266
|
JSON.parse(raw);
|
|
6179
|
-
|
|
6267
|
+
writeFileSync10(credentialsPath, raw, { mode: 384 });
|
|
6180
6268
|
registerCredentialCleanup(credentialsPath);
|
|
6181
6269
|
return true;
|
|
6182
6270
|
} catch {}
|
|
6183
6271
|
}
|
|
6184
6272
|
}
|
|
6185
|
-
const hostClaudeHome = options.hostClaudeHome ?
|
|
6273
|
+
const hostClaudeHome = options.hostClaudeHome ? resolve26(options.hostClaudeHome) : process.env.CLAUDE_HOME?.trim() ? resolve26(process.env.CLAUDE_HOME) : process.env.HOME ? resolve26(process.env.HOME, ".claude") : "";
|
|
6186
6274
|
if (hostClaudeHome) {
|
|
6187
|
-
const realCredentials =
|
|
6188
|
-
if (
|
|
6275
|
+
const realCredentials = resolve26(hostClaudeHome, ".credentials.json");
|
|
6276
|
+
if (existsSync25(realCredentials)) {
|
|
6189
6277
|
cpSync2(realCredentials, credentialsPath);
|
|
6190
6278
|
return true;
|
|
6191
6279
|
}
|
|
@@ -6193,36 +6281,36 @@ async function injectClaudeCredentials(claudeHomeDir, options = {}) {
|
|
|
6193
6281
|
return false;
|
|
6194
6282
|
}
|
|
6195
6283
|
async function injectCodexAuth(codexHomeDir) {
|
|
6196
|
-
|
|
6197
|
-
const hostCodexHome = process.env.CODEX_HOME?.trim() ?
|
|
6284
|
+
mkdirSync12(codexHomeDir, { recursive: true });
|
|
6285
|
+
const hostCodexHome = process.env.CODEX_HOME?.trim() ? resolve26(process.env.CODEX_HOME) : process.env.HOME ? resolve26(process.env.HOME, ".codex") : "";
|
|
6198
6286
|
if (!hostCodexHome) {
|
|
6199
6287
|
return false;
|
|
6200
6288
|
}
|
|
6201
|
-
const hostAuthPath =
|
|
6202
|
-
if (!
|
|
6289
|
+
const hostAuthPath = resolve26(hostCodexHome, "auth.json");
|
|
6290
|
+
if (!existsSync25(hostAuthPath)) {
|
|
6203
6291
|
return false;
|
|
6204
6292
|
}
|
|
6205
|
-
const runtimeAuthPath =
|
|
6293
|
+
const runtimeAuthPath = resolve26(codexHomeDir, "auth.json");
|
|
6206
6294
|
copyFileSync5(hostAuthPath, runtimeAuthPath);
|
|
6207
6295
|
chmodSync5(runtimeAuthPath, 384);
|
|
6208
6296
|
return true;
|
|
6209
6297
|
}
|
|
6210
6298
|
async function injectPiAgentConfig(piAgentDir) {
|
|
6211
|
-
|
|
6212
|
-
const hostPiAgentDir = process.env.PI_CODING_AGENT_DIR?.trim() ?
|
|
6299
|
+
mkdirSync12(piAgentDir, { recursive: true });
|
|
6300
|
+
const hostPiAgentDir = process.env.PI_CODING_AGENT_DIR?.trim() ? resolve26(process.env.PI_CODING_AGENT_DIR) : process.env.HOME ? resolve26(process.env.HOME, ".pi", "agent") : "";
|
|
6213
6301
|
if (!hostPiAgentDir) {
|
|
6214
6302
|
return false;
|
|
6215
6303
|
}
|
|
6216
|
-
const hostAuthPath =
|
|
6217
|
-
if (!
|
|
6304
|
+
const hostAuthPath = resolve26(hostPiAgentDir, "auth.json");
|
|
6305
|
+
if (!existsSync25(hostAuthPath)) {
|
|
6218
6306
|
return false;
|
|
6219
6307
|
}
|
|
6220
|
-
const runtimeAuthPath =
|
|
6308
|
+
const runtimeAuthPath = resolve26(piAgentDir, "auth.json");
|
|
6221
6309
|
copyFileSync5(hostAuthPath, runtimeAuthPath);
|
|
6222
6310
|
chmodSync5(runtimeAuthPath, 384);
|
|
6223
|
-
const hostSettingsPath =
|
|
6224
|
-
if (
|
|
6225
|
-
const runtimeSettingsPath =
|
|
6311
|
+
const hostSettingsPath = resolve26(hostPiAgentDir, "settings.json");
|
|
6312
|
+
if (existsSync25(hostSettingsPath)) {
|
|
6313
|
+
const runtimeSettingsPath = resolve26(piAgentDir, "settings.json");
|
|
6226
6314
|
copyFileSync5(hostSettingsPath, runtimeSettingsPath);
|
|
6227
6315
|
chmodSync5(runtimeSettingsPath, 384);
|
|
6228
6316
|
}
|
|
@@ -6230,8 +6318,8 @@ async function injectPiAgentConfig(piAgentDir) {
|
|
|
6230
6318
|
}
|
|
6231
6319
|
|
|
6232
6320
|
// packages/runtime/src/control-plane/runtime/tooling/claude-router.ts
|
|
6233
|
-
import { existsSync as
|
|
6234
|
-
import { resolve as
|
|
6321
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync13, statSync as statSync6, writeFileSync as writeFileSync11 } from "fs";
|
|
6322
|
+
import { resolve as resolve27 } from "path";
|
|
6235
6323
|
var CLAUDE_ROUTER_SERVER_NAME = "rig_runtime_tools";
|
|
6236
6324
|
var CLAUDE_DISABLED_FILE_TOOLS = [
|
|
6237
6325
|
"Read",
|
|
@@ -6329,7 +6417,7 @@ function claudeRuntimeToolCliArgs(configPath) {
|
|
|
6329
6417
|
function buildRuntimeToolRouterServerConfig(options) {
|
|
6330
6418
|
return {
|
|
6331
6419
|
type: "stdio",
|
|
6332
|
-
command:
|
|
6420
|
+
command: resolve27(options.binDir, "rig-tool-router"),
|
|
6333
6421
|
args: [],
|
|
6334
6422
|
env: {
|
|
6335
6423
|
RIG_RUNTIME_CONTEXT_FILE: options.contextFile,
|
|
@@ -6363,14 +6451,14 @@ function codexRuntimeToolCliArgs(options) {
|
|
|
6363
6451
|
];
|
|
6364
6452
|
}
|
|
6365
6453
|
function writeClaudeRuntimeToolRouterConfig(options) {
|
|
6366
|
-
const configPath =
|
|
6367
|
-
|
|
6454
|
+
const configPath = resolve27(options.stateDir, "claude-runtime-tools.mcp.json");
|
|
6455
|
+
mkdirSync13(options.stateDir, { recursive: true });
|
|
6368
6456
|
const payload = {
|
|
6369
6457
|
mcpServers: {
|
|
6370
6458
|
[CLAUDE_ROUTER_SERVER_NAME]: buildRuntimeToolRouterServerConfig(options)
|
|
6371
6459
|
}
|
|
6372
6460
|
};
|
|
6373
|
-
|
|
6461
|
+
writeFileSync11(configPath, `${JSON.stringify(payload, null, 2)}
|
|
6374
6462
|
`, "utf-8");
|
|
6375
6463
|
return configPath;
|
|
6376
6464
|
}
|
|
@@ -6457,7 +6545,7 @@ function resolveRuntimeToolBinary(toolName, env) {
|
|
|
6457
6545
|
grep: "rig-grep"
|
|
6458
6546
|
};
|
|
6459
6547
|
const executable = mapping[toolName];
|
|
6460
|
-
return executable ?
|
|
6548
|
+
return executable ? resolve27(binDir, executable) : "";
|
|
6461
6549
|
}
|
|
6462
6550
|
function renderToolText(toolName, payload) {
|
|
6463
6551
|
if (toolName === "shell") {
|
|
@@ -6522,10 +6610,10 @@ async function invokeRuntimeShellTool(args, options = {}) {
|
|
|
6522
6610
|
isError: true
|
|
6523
6611
|
};
|
|
6524
6612
|
}
|
|
6525
|
-
const workspaceRoot =
|
|
6613
|
+
const workspaceRoot = resolve27(invocationEnv.RIG_TASK_WORKSPACE?.trim() || process.cwd());
|
|
6526
6614
|
const requestedWorkdir = typeof args.workdir === "string" ? args.workdir.trim() : "";
|
|
6527
6615
|
const workdir = requestedWorkdir ? resolveWithinWorkspace(workspaceRoot, requestedWorkdir) : workspaceRoot;
|
|
6528
|
-
if (!
|
|
6616
|
+
if (!existsSync26(workdir)) {
|
|
6529
6617
|
return {
|
|
6530
6618
|
content: [{
|
|
6531
6619
|
type: "text",
|
|
@@ -6592,10 +6680,10 @@ async function invokeRuntimeShellTool(args, options = {}) {
|
|
|
6592
6680
|
}
|
|
6593
6681
|
function resolveRuntimeShellBinary(shellName, env) {
|
|
6594
6682
|
const binDir = env.RIG_RUNTIME_BIN_DIR?.trim() || "";
|
|
6595
|
-
return binDir ?
|
|
6683
|
+
return binDir ? resolve27(binDir, shellName) : "";
|
|
6596
6684
|
}
|
|
6597
6685
|
function resolveWithinWorkspace(workspaceRoot, target) {
|
|
6598
|
-
const resolvedTarget =
|
|
6686
|
+
const resolvedTarget = resolve27(workspaceRoot, normalizeWorkspaceRelativeTarget(target));
|
|
6599
6687
|
const normalizedWorkspace = workspaceRoot.endsWith("/") ? workspaceRoot : `${workspaceRoot}/`;
|
|
6600
6688
|
const normalizedTarget = resolvedTarget.endsWith("/") ? resolvedTarget : `${resolvedTarget}/`;
|
|
6601
6689
|
if (resolvedTarget === workspaceRoot || normalizedTarget.startsWith(normalizedWorkspace)) {
|
|
@@ -6633,8 +6721,8 @@ if (false) {}
|
|
|
6633
6721
|
init_layout();
|
|
6634
6722
|
|
|
6635
6723
|
// packages/runtime/src/control-plane/runtime/isolation/worktree.ts
|
|
6636
|
-
import { existsSync as
|
|
6637
|
-
import { dirname as dirname11, resolve as
|
|
6724
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync14, rmSync as rmSync10 } from "fs";
|
|
6725
|
+
import { dirname as dirname11, resolve as resolve28 } from "path";
|
|
6638
6726
|
async function resolveMonorepoBaseRef(monorepoRoot) {
|
|
6639
6727
|
const explicit = process.env.RIG_RUNTIME_BASE_REF?.trim();
|
|
6640
6728
|
if (explicit) {
|
|
@@ -6670,12 +6758,12 @@ function ensureProvisioningHostProjectRootEnv(projectRoot) {
|
|
|
6670
6758
|
}
|
|
6671
6759
|
async function provisionRuntimeWorktree(config) {
|
|
6672
6760
|
const branch = runtimeBranchName(config.taskId, config.runtimeId);
|
|
6673
|
-
let hasValidWorktree =
|
|
6674
|
-
if (
|
|
6675
|
-
|
|
6761
|
+
let hasValidWorktree = existsSync27(resolve28(config.workspaceDir, ".git")) && (await runGitCommand(config.workspaceDir, ["rev-parse", "--show-toplevel"])).exitCode === 0;
|
|
6762
|
+
if (existsSync27(config.workspaceDir) && !hasValidWorktree) {
|
|
6763
|
+
rmSync10(config.workspaceDir, { recursive: true, force: true });
|
|
6676
6764
|
}
|
|
6677
6765
|
if (!hasValidWorktree) {
|
|
6678
|
-
|
|
6766
|
+
mkdirSync14(dirname11(config.workspaceDir), { recursive: true });
|
|
6679
6767
|
const branchExists = await runGitCommand(config.monorepoRoot, ["show-ref", "--verify", "--quiet", `refs/heads/${branch}`]);
|
|
6680
6768
|
const add = branchExists.exitCode === 0 ? await runGitCommand(config.monorepoRoot, ["worktree", "add", "--force", config.workspaceDir, branch]) : await runGitCommand(config.monorepoRoot, ["worktree", "add", "--force", "-b", branch, config.workspaceDir, config.baseRef]);
|
|
6681
6769
|
if (add.exitCode !== 0) {
|
|
@@ -6851,31 +6939,31 @@ async function preferredBaseRemotes(repoRoot) {
|
|
|
6851
6939
|
|
|
6852
6940
|
// packages/runtime/src/control-plane/runtime/isolation/toolchain.ts
|
|
6853
6941
|
import {
|
|
6854
|
-
existsSync as
|
|
6942
|
+
existsSync as existsSync29,
|
|
6855
6943
|
lstatSync,
|
|
6856
|
-
mkdirSync as
|
|
6857
|
-
readdirSync as
|
|
6858
|
-
readFileSync as
|
|
6859
|
-
rmSync as
|
|
6944
|
+
mkdirSync as mkdirSync16,
|
|
6945
|
+
readdirSync as readdirSync6,
|
|
6946
|
+
readFileSync as readFileSync14,
|
|
6947
|
+
rmSync as rmSync11,
|
|
6860
6948
|
statSync as statSync8,
|
|
6861
6949
|
symlinkSync as symlinkSync4
|
|
6862
6950
|
} from "fs";
|
|
6863
6951
|
import { mkdir as mkdir2, writeFile } from "fs/promises";
|
|
6864
|
-
import { dirname as dirname13, resolve as
|
|
6952
|
+
import { dirname as dirname13, resolve as resolve30 } from "path";
|
|
6865
6953
|
|
|
6866
6954
|
// packages/runtime/src/control-plane/runtime/tooling/claude-router-binary.ts
|
|
6867
|
-
import { chmodSync as chmodSync6, copyFileSync as copyFileSync6, existsSync as
|
|
6955
|
+
import { chmodSync as chmodSync6, copyFileSync as copyFileSync6, existsSync as existsSync28, mkdirSync as mkdirSync15, statSync as statSync7 } from "fs";
|
|
6868
6956
|
import { tmpdir as tmpdir6 } from "os";
|
|
6869
|
-
import { dirname as dirname12, resolve as
|
|
6870
|
-
var sharedRouterOutputDir =
|
|
6871
|
-
var sharedRouterOutputPath =
|
|
6957
|
+
import { dirname as dirname12, resolve as resolve29 } from "path";
|
|
6958
|
+
var sharedRouterOutputDir = resolve29(tmpdir6(), "rig-native");
|
|
6959
|
+
var sharedRouterOutputPath = resolve29(sharedRouterOutputDir, `rig-tool-router-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
6872
6960
|
function runtimeClaudeToolRouterFileName() {
|
|
6873
6961
|
return `rig-tool-router${process.platform === "win32" ? ".exe" : ""}`;
|
|
6874
6962
|
}
|
|
6875
6963
|
async function ensureClaudeToolRouterBinaryPath(projectRoot, outputPath = sharedRouterOutputPath) {
|
|
6876
|
-
const sourcePath =
|
|
6877
|
-
|
|
6878
|
-
const needsBuild = !
|
|
6964
|
+
const sourcePath = resolve29(projectRoot, "packages/runtime/src/control-plane/runtime/tooling/claude-router.ts");
|
|
6965
|
+
mkdirSync15(dirname12(outputPath), { recursive: true });
|
|
6966
|
+
const needsBuild = !existsSync28(outputPath) || statSync7(sourcePath).mtimeMs > statSync7(outputPath).mtimeMs;
|
|
6879
6967
|
if (!needsBuild) {
|
|
6880
6968
|
return outputPath;
|
|
6881
6969
|
}
|
|
@@ -6889,9 +6977,9 @@ async function ensureClaudeToolRouterBinaryPath(projectRoot, outputPath = shared
|
|
|
6889
6977
|
}
|
|
6890
6978
|
async function materializeClaudeToolRouterBinary(projectRoot, targetDir) {
|
|
6891
6979
|
const sourcePath = await ensureClaudeToolRouterBinaryPath(projectRoot);
|
|
6892
|
-
const targetPath =
|
|
6893
|
-
|
|
6894
|
-
const needsCopy = !
|
|
6980
|
+
const targetPath = resolve29(targetDir, runtimeClaudeToolRouterFileName());
|
|
6981
|
+
mkdirSync15(targetDir, { recursive: true });
|
|
6982
|
+
const needsCopy = !existsSync28(targetPath) || statSync7(sourcePath).mtimeMs > statSync7(targetPath).mtimeMs;
|
|
6895
6983
|
if (needsCopy) {
|
|
6896
6984
|
copyFileSync6(sourcePath, targetPath);
|
|
6897
6985
|
chmodSync6(targetPath, 493);
|
|
@@ -6904,48 +6992,48 @@ var GIT_INDEX_LOCK_RETRY_DELAY_MS = 250;
|
|
|
6904
6992
|
var GIT_INDEX_LOCK_STALE_AFTER_MS = 5000;
|
|
6905
6993
|
function resolveRigSourceRoot(projectRoot) {
|
|
6906
6994
|
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim();
|
|
6907
|
-
if (hostProjectRoot &&
|
|
6995
|
+
if (hostProjectRoot && existsSync29(resolve30(hostProjectRoot, "packages/runtime/bin/rig-agent.ts"))) {
|
|
6908
6996
|
return hostProjectRoot;
|
|
6909
6997
|
}
|
|
6910
|
-
const fromModule =
|
|
6911
|
-
if (
|
|
6998
|
+
const fromModule = resolve30(import.meta.dir, "../../../../../..");
|
|
6999
|
+
if (existsSync29(resolve30(fromModule, "packages/runtime/bin/rig-agent.ts"))) {
|
|
6912
7000
|
return fromModule;
|
|
6913
7001
|
}
|
|
6914
7002
|
return projectRoot;
|
|
6915
7003
|
}
|
|
6916
7004
|
function prepareTrackedRuntimePaths(logsDir, stateDir, sessionDir) {
|
|
6917
|
-
for (const path of [logsDir, stateDir, sessionDir,
|
|
7005
|
+
for (const path of [logsDir, stateDir, sessionDir, resolve30(sessionDir, "session.json")]) {
|
|
6918
7006
|
removeSymbolicLink(path);
|
|
6919
7007
|
}
|
|
6920
7008
|
runtimePrepareTrackedPathsNative({
|
|
6921
7009
|
logsDir,
|
|
6922
7010
|
stateDir,
|
|
6923
7011
|
sessionDir,
|
|
6924
|
-
controlledBashLogFile:
|
|
6925
|
-
eventsFile:
|
|
7012
|
+
controlledBashLogFile: resolve30(logsDir, "controlled-bash.jsonl"),
|
|
7013
|
+
eventsFile: resolve30(logsDir, "control-plane.events.jsonl")
|
|
6926
7014
|
});
|
|
6927
7015
|
}
|
|
6928
7016
|
async function initializeRuntimeStateFiles(stateDir, sessionDir, taskId) {
|
|
6929
7017
|
await mkdir2(stateDir, { recursive: true });
|
|
6930
7018
|
await mkdir2(sessionDir, { recursive: true });
|
|
6931
|
-
const failedApproachesPath =
|
|
6932
|
-
if (!
|
|
7019
|
+
const failedApproachesPath = resolve30(stateDir, "failed_approaches.md");
|
|
7020
|
+
if (!existsSync29(failedApproachesPath)) {
|
|
6933
7021
|
await writeFile(failedApproachesPath, `# Failed Approaches
|
|
6934
7022
|
|
|
6935
7023
|
`);
|
|
6936
7024
|
}
|
|
6937
|
-
const hookTripsPath =
|
|
6938
|
-
if (!
|
|
7025
|
+
const hookTripsPath = resolve30(stateDir, "hook_trips.log");
|
|
7026
|
+
if (!existsSync29(hookTripsPath)) {
|
|
6939
7027
|
await writeFile(hookTripsPath, "");
|
|
6940
7028
|
}
|
|
6941
|
-
const sessionFile =
|
|
7029
|
+
const sessionFile = resolve30(sessionDir, "session.json");
|
|
6942
7030
|
if (taskId) {
|
|
6943
7031
|
await writeFile(sessionFile, JSON.stringify({ activeTaskIds: [taskId] }));
|
|
6944
7032
|
}
|
|
6945
7033
|
}
|
|
6946
7034
|
async function resetEphemeralTaskArtifacts(workspaceDir, taskId) {
|
|
6947
|
-
const artifactDir =
|
|
6948
|
-
const runtimeSnapshotDir =
|
|
7035
|
+
const artifactDir = resolve30(workspaceDir, "artifacts", taskId);
|
|
7036
|
+
const runtimeSnapshotDir = resolve30(artifactDir, "runtime-snapshots");
|
|
6949
7037
|
let preservedTrackedFiles = false;
|
|
6950
7038
|
for (const file of [
|
|
6951
7039
|
"changed-files.txt",
|
|
@@ -6961,13 +7049,13 @@ async function resetEphemeralTaskArtifacts(workspaceDir, taskId) {
|
|
|
6961
7049
|
preservedTrackedFiles = true;
|
|
6962
7050
|
continue;
|
|
6963
7051
|
}
|
|
6964
|
-
|
|
7052
|
+
rmSync11(resolve30(artifactDir, file), { force: true });
|
|
6965
7053
|
}
|
|
6966
7054
|
const runtimeSnapshotRelativePath = `artifacts/${taskId}/runtime-snapshots`;
|
|
6967
7055
|
if (await resetTrackedArtifactPath(workspaceDir, runtimeSnapshotRelativePath)) {
|
|
6968
7056
|
preservedTrackedFiles = true;
|
|
6969
7057
|
} else {
|
|
6970
|
-
|
|
7058
|
+
rmSync11(runtimeSnapshotDir, { recursive: true, force: true });
|
|
6971
7059
|
}
|
|
6972
7060
|
if (preservedTrackedFiles) {
|
|
6973
7061
|
console.log(`[rig-agent] Preserved tracked runtime artifact files in ${taskId}; skipped ephemeral cleanup for committed paths.`);
|
|
@@ -7000,28 +7088,28 @@ async function buildRuntimeToolchain(options) {
|
|
|
7000
7088
|
throw new Error("Failed to provision the native Zig runtime library.");
|
|
7001
7089
|
}
|
|
7002
7090
|
const rigSourceRoot = resolveRigSourceRoot(options.projectRoot);
|
|
7003
|
-
await buildBinary("packages/cli/bin/rig.ts",
|
|
7004
|
-
await buildBinary("packages/runtime/bin/rig-agent.ts",
|
|
7091
|
+
await buildBinary("packages/cli/bin/rig.ts", resolve30(options.binDir, "rig"), rigSourceRoot);
|
|
7092
|
+
await buildBinary("packages/runtime/bin/rig-agent.ts", resolve30(options.binDir, "rig-agent"), rigSourceRoot, {
|
|
7005
7093
|
...options.runtimeSecretDefines,
|
|
7006
7094
|
AGENT_TASK_ID: options.taskId,
|
|
7007
7095
|
AGENT_PROJECT_ROOT: options.projectRoot,
|
|
7008
7096
|
AGENT_RUNTIME_ID: options.runtimeId,
|
|
7009
7097
|
AGENT_SCOPE_HASH: options.bakedScopeHash,
|
|
7010
7098
|
AGENT_MANIFEST_PATH: options.manifestPath,
|
|
7011
|
-
AGENT_BINARY_PATH:
|
|
7099
|
+
AGENT_BINARY_PATH: resolve30(options.binDir, "rig-agent"),
|
|
7012
7100
|
AGENT_INFO_OUTPUT: options.bakedInfoOutput,
|
|
7013
7101
|
AGENT_DEPS_OUTPUT: options.bakedDepsOutput,
|
|
7014
7102
|
AGENT_STATUS_OUTPUT: options.bakedStatusOutput
|
|
7015
7103
|
});
|
|
7016
|
-
await buildBinary("packages/runtime/src/control-plane/controlled-bash.ts",
|
|
7104
|
+
await buildBinary("packages/runtime/src/control-plane/controlled-bash.ts", resolve30(options.binDir, "controlled-bash"), rigSourceRoot, {
|
|
7017
7105
|
AGENT_PROJECT_ROOT: options.projectRoot,
|
|
7018
7106
|
AGENT_LOGS_DIR: options.logsDir,
|
|
7019
7107
|
AGENT_MONOREPO_ROOT: resolveMonorepoRoot3(options.projectRoot),
|
|
7020
|
-
AGENT_TS_API_TESTS_DIR:
|
|
7021
|
-
AGENT_RIG_AGENT_BIN:
|
|
7108
|
+
AGENT_TS_API_TESTS_DIR: resolve30(options.workspaceDir, "TSAPITests"),
|
|
7109
|
+
AGENT_RIG_AGENT_BIN: resolve30(options.binDir, "rig-agent")
|
|
7022
7110
|
});
|
|
7023
|
-
await buildBinary("packages/runtime/bin/rig-browser-tool.ts",
|
|
7024
|
-
await buildBinary("packages/runtime/src/control-plane/runtime/snapshot/sidecar.ts",
|
|
7111
|
+
await buildBinary("packages/runtime/bin/rig-browser-tool.ts", resolve30(options.binDir, runtimeBrowserToolBinaryName()), rigSourceRoot);
|
|
7112
|
+
await buildBinary("packages/runtime/src/control-plane/runtime/snapshot/sidecar.ts", resolve30(options.binDir, "snapshot-sidecar"), rigSourceRoot, {
|
|
7025
7113
|
AGENT_PROJECT_ROOT: options.projectRoot,
|
|
7026
7114
|
AGENT_BUN_PATH: resolveBunBinaryPath()
|
|
7027
7115
|
});
|
|
@@ -7030,15 +7118,15 @@ async function buildRuntimeToolchain(options) {
|
|
|
7030
7118
|
AGENT_BUN_PATH: resolveBunBinaryPath()
|
|
7031
7119
|
};
|
|
7032
7120
|
for (const hookName of hookNames) {
|
|
7033
|
-
await buildBinary(`packages/runtime/src/control-plane/hooks/${hookName}.ts`,
|
|
7121
|
+
await buildBinary(`packages/runtime/src/control-plane/hooks/${hookName}.ts`, resolve30(runtimeBins.hooksDir, hookName), rigSourceRoot, hookDefines);
|
|
7034
7122
|
}
|
|
7035
|
-
const pluginsDir =
|
|
7036
|
-
if (
|
|
7037
|
-
for (const entry of
|
|
7123
|
+
const pluginsDir = resolve30(options.projectRoot, "rig/plugins");
|
|
7124
|
+
if (existsSync29(pluginsDir)) {
|
|
7125
|
+
for (const entry of readdirSync6(pluginsDir, { withFileTypes: true })) {
|
|
7038
7126
|
const match = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
7039
7127
|
if (!match)
|
|
7040
7128
|
continue;
|
|
7041
|
-
await buildBinary(`rig/plugins/${entry.name}`,
|
|
7129
|
+
await buildBinary(`rig/plugins/${entry.name}`, resolve30(runtimeBins.pluginsDir, match[1]), options.projectRoot);
|
|
7042
7130
|
}
|
|
7043
7131
|
}
|
|
7044
7132
|
await materializeRigGitBinary(options.binDir);
|
|
@@ -7048,8 +7136,8 @@ async function buildRuntimeToolchain(options) {
|
|
|
7048
7136
|
}
|
|
7049
7137
|
async function writeRuntimeManifest(config) {
|
|
7050
7138
|
const scopeHash = sha256Hex(JSON.stringify(config.scopes));
|
|
7051
|
-
const binarySha256 = sha256Hex(
|
|
7052
|
-
const manifestPath =
|
|
7139
|
+
const binarySha256 = sha256Hex(readFileSync14(config.binaryPath));
|
|
7140
|
+
const manifestPath = resolve30(config.runtimeRoot, "manifest.json");
|
|
7053
7141
|
const manifest = {
|
|
7054
7142
|
runtimeId: config.runtimeId,
|
|
7055
7143
|
taskId: config.taskId,
|
|
@@ -7083,7 +7171,7 @@ function removeSymbolicLink(path) {
|
|
|
7083
7171
|
} catch {
|
|
7084
7172
|
return;
|
|
7085
7173
|
}
|
|
7086
|
-
|
|
7174
|
+
rmSync11(path, { force: true, recursive: true });
|
|
7087
7175
|
}
|
|
7088
7176
|
async function resetTrackedArtifactPath(workspaceDir, relativePath) {
|
|
7089
7177
|
const tracked = await runGitLsFiles(workspaceDir, relativePath);
|
|
@@ -7109,7 +7197,7 @@ async function restoreTrackedArtifactPathWithRetry(workspaceDir, relativePath, r
|
|
|
7109
7197
|
const retryDelayMs = options.retryDelayMs ?? GIT_INDEX_LOCK_RETRY_DELAY_MS;
|
|
7110
7198
|
const now = options.now ?? Date.now;
|
|
7111
7199
|
const statMtimeMs = options.statMtimeMs ?? readFileMtimeMs;
|
|
7112
|
-
const removeFile = options.removeFile ?? ((path) =>
|
|
7200
|
+
const removeFile = options.removeFile ?? ((path) => rmSync11(path, { force: true }));
|
|
7113
7201
|
const log = options.log ?? console.warn;
|
|
7114
7202
|
let lastOutput = "";
|
|
7115
7203
|
for (let attempt = 0;attempt <= maxRetries; attempt += 1) {
|
|
@@ -7169,31 +7257,31 @@ function readFileMtimeMs(path) {
|
|
|
7169
7257
|
}
|
|
7170
7258
|
function linkRuntimeDependencyLayers(monorepoRoot, workspaceDir) {
|
|
7171
7259
|
linkGenericNodeModulesLayers(monorepoRoot, workspaceDir);
|
|
7172
|
-
const sourceNodeModules =
|
|
7173
|
-
if (!
|
|
7174
|
-
const runtimeHumoongate =
|
|
7175
|
-
if (
|
|
7176
|
-
const targetNodeModules =
|
|
7260
|
+
const sourceNodeModules = resolve30(monorepoRoot, "humoongate", "node_modules");
|
|
7261
|
+
if (!existsSync29(sourceNodeModules)) {} else {
|
|
7262
|
+
const runtimeHumoongate = resolve30(workspaceDir, "humoongate");
|
|
7263
|
+
if (existsSync29(resolve30(runtimeHumoongate, "package.json"))) {
|
|
7264
|
+
const targetNodeModules = resolve30(runtimeHumoongate, "node_modules");
|
|
7177
7265
|
runtimeLinkDependencyLayerNative(sourceNodeModules, targetNodeModules);
|
|
7178
7266
|
}
|
|
7179
7267
|
}
|
|
7180
|
-
const runtimeHpNext =
|
|
7181
|
-
if (!
|
|
7268
|
+
const runtimeHpNext = resolve30(workspaceDir, "microservices", "hp-next-frontend", "app");
|
|
7269
|
+
if (!existsSync29(resolve30(runtimeHpNext, "package.json"))) {
|
|
7182
7270
|
return;
|
|
7183
7271
|
}
|
|
7184
|
-
const sourceHpNextNodeModules =
|
|
7185
|
-
const sourceMonorepoNodeModules =
|
|
7186
|
-
const targetHpNextNodeModules =
|
|
7187
|
-
if (
|
|
7272
|
+
const sourceHpNextNodeModules = resolve30(monorepoRoot, "microservices", "hp-next-frontend", "app", "node_modules");
|
|
7273
|
+
const sourceMonorepoNodeModules = resolve30(monorepoRoot, "node_modules");
|
|
7274
|
+
const targetHpNextNodeModules = resolve30(runtimeHpNext, "node_modules");
|
|
7275
|
+
if (existsSync29(sourceHpNextNodeModules)) {
|
|
7188
7276
|
runtimeLinkDependencyLayerNative(sourceHpNextNodeModules, targetHpNextNodeModules);
|
|
7189
7277
|
return;
|
|
7190
7278
|
}
|
|
7191
|
-
if (
|
|
7279
|
+
if (existsSync29(sourceMonorepoNodeModules)) {
|
|
7192
7280
|
runtimeLinkDependencyLayerNative(sourceMonorepoNodeModules, targetHpNextNodeModules);
|
|
7193
7281
|
}
|
|
7194
7282
|
}
|
|
7195
7283
|
function linkGenericNodeModulesLayers(monorepoRoot, workspaceDir) {
|
|
7196
|
-
linkNodeModulesLayer(
|
|
7284
|
+
linkNodeModulesLayer(resolve30(monorepoRoot, "node_modules"), resolve30(workspaceDir, "node_modules"));
|
|
7197
7285
|
for (const relativePackageDir of [
|
|
7198
7286
|
"apps/native-app/apps/marketing",
|
|
7199
7287
|
"apps/native-app/apps/web",
|
|
@@ -7215,15 +7303,15 @@ function linkGenericNodeModulesLayers(monorepoRoot, workspaceDir) {
|
|
|
7215
7303
|
"packages/standard-plugin",
|
|
7216
7304
|
"packages/validator-kit"
|
|
7217
7305
|
]) {
|
|
7218
|
-
const workspacePackageDir =
|
|
7219
|
-
if (!
|
|
7306
|
+
const workspacePackageDir = resolve30(workspaceDir, relativePackageDir);
|
|
7307
|
+
if (!existsSync29(resolve30(workspacePackageDir, "package.json"))) {
|
|
7220
7308
|
continue;
|
|
7221
7309
|
}
|
|
7222
|
-
linkNodeModulesLayer(
|
|
7310
|
+
linkNodeModulesLayer(resolve30(monorepoRoot, relativePackageDir, "node_modules"), resolve30(workspacePackageDir, "node_modules"));
|
|
7223
7311
|
}
|
|
7224
7312
|
}
|
|
7225
7313
|
function linkNodeModulesLayer(sourceDir, targetDir) {
|
|
7226
|
-
if (!
|
|
7314
|
+
if (!existsSync29(sourceDir) || existsSync29(targetDir)) {
|
|
7227
7315
|
return;
|
|
7228
7316
|
}
|
|
7229
7317
|
try {
|
|
@@ -7232,30 +7320,30 @@ function linkNodeModulesLayer(sourceDir, targetDir) {
|
|
|
7232
7320
|
} catch (error) {
|
|
7233
7321
|
console.warn(`[rig-agent] Native dependency-layer linking failed for ${targetDir}; using symlink fallback: ${error instanceof Error ? error.message : String(error)}`);
|
|
7234
7322
|
}
|
|
7235
|
-
|
|
7323
|
+
mkdirSync16(dirname13(targetDir), { recursive: true });
|
|
7236
7324
|
symlinkSync4(sourceDir, targetDir, "dir");
|
|
7237
7325
|
}
|
|
7238
7326
|
function ensureRuntimeBinTrees(runtimeBinDir) {
|
|
7239
|
-
const hooksDir =
|
|
7240
|
-
const pluginsDir =
|
|
7241
|
-
const validatorsDir =
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7327
|
+
const hooksDir = resolve30(runtimeBinDir, "hooks");
|
|
7328
|
+
const pluginsDir = resolve30(runtimeBinDir, "plugins");
|
|
7329
|
+
const validatorsDir = resolve30(runtimeBinDir, "validators");
|
|
7330
|
+
mkdirSync16(hooksDir, { recursive: true });
|
|
7331
|
+
mkdirSync16(pluginsDir, { recursive: true });
|
|
7332
|
+
mkdirSync16(validatorsDir, { recursive: true });
|
|
7245
7333
|
return { hooksDir, pluginsDir, validatorsDir };
|
|
7246
7334
|
}
|
|
7247
7335
|
|
|
7248
7336
|
// packages/runtime/src/control-plane/runtime/isolation/runner.ts
|
|
7249
|
-
import { existsSync as
|
|
7250
|
-
import { basename as basename9, resolve as
|
|
7337
|
+
import { existsSync as existsSync32, rmSync as rmSync12, writeFileSync as writeFileSync13 } from "fs";
|
|
7338
|
+
import { basename as basename9, resolve as resolve34 } from "path";
|
|
7251
7339
|
|
|
7252
7340
|
// packages/runtime/src/control-plane/runtime/sandbox/backend.ts
|
|
7253
|
-
import { existsSync as
|
|
7341
|
+
import { existsSync as existsSync31 } from "fs";
|
|
7254
7342
|
|
|
7255
7343
|
// packages/runtime/src/control-plane/runtime/guard.ts
|
|
7256
7344
|
import { optimizeNextInvocation } from "bun:jsc";
|
|
7257
|
-
import { existsSync as
|
|
7258
|
-
import { resolve as
|
|
7345
|
+
import { existsSync as existsSync30, readFileSync as readFileSync15, statSync as statSync9 } from "fs";
|
|
7346
|
+
import { resolve as resolve31 } from "path";
|
|
7259
7347
|
|
|
7260
7348
|
// packages/runtime/src/control-plane/runtime/guard-types.ts
|
|
7261
7349
|
var POLICY_VERSION = 1;
|
|
@@ -7318,8 +7406,8 @@ function loadPolicy(projectRoot) {
|
|
|
7318
7406
|
if (seededPolicyConfig) {
|
|
7319
7407
|
return seededPolicyConfig;
|
|
7320
7408
|
}
|
|
7321
|
-
const configPath =
|
|
7322
|
-
if (!
|
|
7409
|
+
const configPath = resolve31(projectRoot, "rig/policy/policy.json");
|
|
7410
|
+
if (!existsSync30(configPath)) {
|
|
7323
7411
|
return defaultPolicy();
|
|
7324
7412
|
}
|
|
7325
7413
|
let mtimeMs;
|
|
@@ -7333,7 +7421,7 @@ function loadPolicy(projectRoot) {
|
|
|
7333
7421
|
}
|
|
7334
7422
|
let parsed;
|
|
7335
7423
|
try {
|
|
7336
|
-
parsed = JSON.parse(
|
|
7424
|
+
parsed = JSON.parse(readFileSync15(configPath, "utf-8"));
|
|
7337
7425
|
} catch {
|
|
7338
7426
|
return defaultPolicy();
|
|
7339
7427
|
}
|
|
@@ -7549,28 +7637,28 @@ function resolveAction(mode, matched) {
|
|
|
7549
7637
|
}
|
|
7550
7638
|
function resolveAbsolutePath(projectRoot, rawPath) {
|
|
7551
7639
|
if (rawPath.startsWith("/"))
|
|
7552
|
-
return
|
|
7553
|
-
return
|
|
7640
|
+
return resolve31(rawPath);
|
|
7641
|
+
return resolve31(projectRoot, rawPath);
|
|
7554
7642
|
}
|
|
7555
7643
|
function isHarnessPath(projectRoot, rawPath) {
|
|
7556
7644
|
const absPath = resolveAbsolutePath(projectRoot, rawPath);
|
|
7557
7645
|
const managedRoots = [
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7646
|
+
resolve31(projectRoot, "rig"),
|
|
7647
|
+
resolve31(projectRoot, ".rig"),
|
|
7648
|
+
resolve31(projectRoot, "artifacts")
|
|
7561
7649
|
];
|
|
7562
7650
|
return managedRoots.some((root) => absPath === root || absPath.startsWith(root + "/"));
|
|
7563
7651
|
}
|
|
7564
7652
|
function isRuntimePath(projectRoot, rawPath, taskWorkspace) {
|
|
7565
7653
|
const absPath = resolveAbsolutePath(projectRoot, rawPath);
|
|
7566
7654
|
if (taskWorkspace) {
|
|
7567
|
-
const workspaceRigRoot =
|
|
7568
|
-
const workspaceArtifactsRoot =
|
|
7655
|
+
const workspaceRigRoot = resolve31(taskWorkspace, ".rig");
|
|
7656
|
+
const workspaceArtifactsRoot = resolve31(taskWorkspace, "artifacts");
|
|
7569
7657
|
if (absPath === workspaceRigRoot || absPath.startsWith(workspaceRigRoot + "/") || absPath === workspaceArtifactsRoot || absPath.startsWith(workspaceArtifactsRoot + "/")) {
|
|
7570
7658
|
return true;
|
|
7571
7659
|
}
|
|
7572
7660
|
}
|
|
7573
|
-
const runtimeRoot =
|
|
7661
|
+
const runtimeRoot = resolve31(projectRoot, ".rig/runtime/agents");
|
|
7574
7662
|
return absPath === runtimeRoot || absPath.startsWith(runtimeRoot + "/");
|
|
7575
7663
|
}
|
|
7576
7664
|
function isTestFile(path) {
|
|
@@ -7618,7 +7706,7 @@ function evaluateScope(policy, context, filePath, access) {
|
|
|
7618
7706
|
return allowed();
|
|
7619
7707
|
}
|
|
7620
7708
|
if (context.taskWorkspace && context.taskWorkspace !== context.projectRoot && filePath.startsWith("/")) {
|
|
7621
|
-
const absPath =
|
|
7709
|
+
const absPath = resolve31(filePath);
|
|
7622
7710
|
if (!absPath.startsWith(context.taskWorkspace + "/") && !isHarnessPath(context.projectRoot, filePath)) {
|
|
7623
7711
|
const reason2 = `Absolute path '${filePath}' is outside task runtime boundary. Allowed root: ${context.taskWorkspace}`;
|
|
7624
7712
|
const matched2 = [{ id: "scope:workspace-boundary", category: "command", reason: reason2 }];
|
|
@@ -7946,13 +8034,13 @@ async function resolveBackend(projectRoot, options) {
|
|
|
7946
8034
|
depRoots
|
|
7947
8035
|
};
|
|
7948
8036
|
const fsContext = {
|
|
7949
|
-
pathExists: (p) =>
|
|
8037
|
+
pathExists: (p) => existsSync31(p),
|
|
7950
8038
|
realPath: toRealPath
|
|
7951
8039
|
};
|
|
7952
8040
|
if (process.platform === "darwin" && (!requestedBackend || requestedBackend === "macos-seatbelt")) {
|
|
7953
8041
|
const seatbelt = Bun.which("sandbox-exec");
|
|
7954
8042
|
probed.push("sandbox-exec");
|
|
7955
|
-
if (seatbelt &&
|
|
8043
|
+
if (seatbelt && existsSync31(seatbelt)) {
|
|
7956
8044
|
const SeatbeltBackendClass = loadSeatbeltBackend();
|
|
7957
8045
|
if (SeatbeltBackendClass) {
|
|
7958
8046
|
return {
|
|
@@ -8073,10 +8161,10 @@ init_layout();
|
|
|
8073
8161
|
var SNAPSHOT_SIDECAR_READY_TIMEOUT_MS = 1e4;
|
|
8074
8162
|
async function startRuntimeSnapshotSidecar(runtime, options = {}) {
|
|
8075
8163
|
const instanceId = sanitizeRuntimeRefSegment(options.instanceId?.trim() || runtime.id);
|
|
8076
|
-
const readyFile =
|
|
8077
|
-
const requestFile =
|
|
8078
|
-
|
|
8079
|
-
|
|
8164
|
+
const readyFile = resolve34(runtime.stateDir, `runtime-snapshot-sidecar-${instanceId}.ready`);
|
|
8165
|
+
const requestFile = resolve34(runtime.stateDir, `runtime-snapshot-sidecar-${instanceId}.request.json`);
|
|
8166
|
+
rmSync12(readyFile, { force: true });
|
|
8167
|
+
rmSync12(requestFile, { force: true });
|
|
8080
8168
|
const sidecarBinary = resolveSnapshotSidecarBinaryPath(runtime.binDir);
|
|
8081
8169
|
const useCompiledSidecar = shouldUseCompiledSnapshotSidecar(sidecarBinary);
|
|
8082
8170
|
const bunCli = useCompiledSidecar ? null : resolveBunCliInvocation();
|
|
@@ -8114,19 +8202,19 @@ async function startRuntimeSnapshotSidecar(runtime, options = {}) {
|
|
|
8114
8202
|
proc.kill("SIGTERM");
|
|
8115
8203
|
} catch {}
|
|
8116
8204
|
await proc.exited;
|
|
8117
|
-
|
|
8118
|
-
|
|
8205
|
+
rmSync12(readyFile, { force: true });
|
|
8206
|
+
rmSync12(requestFile, { force: true });
|
|
8119
8207
|
},
|
|
8120
8208
|
finalize: async (commandParts, exitCode) => {
|
|
8121
|
-
|
|
8209
|
+
writeFileSync13(requestFile, `${JSON.stringify({ command: commandParts, exitCode })}
|
|
8122
8210
|
`, "utf-8");
|
|
8123
8211
|
const [sidecarExitCode, stdout, stderr] = await Promise.all([
|
|
8124
8212
|
proc.exited,
|
|
8125
8213
|
stdoutTextPromise,
|
|
8126
8214
|
stderrTextPromise
|
|
8127
8215
|
]);
|
|
8128
|
-
|
|
8129
|
-
|
|
8216
|
+
rmSync12(readyFile, { force: true });
|
|
8217
|
+
rmSync12(requestFile, { force: true });
|
|
8130
8218
|
if (sidecarExitCode !== 0) {
|
|
8131
8219
|
throw new Error(`snapshot sidecar failed (${sidecarExitCode}): ${stderr || stdout}`);
|
|
8132
8220
|
}
|
|
@@ -8146,10 +8234,10 @@ function resolveSnapshotSidecarScriptPath() {
|
|
|
8146
8234
|
return resolveRuntimeSourceScriptPath("snapshot-sidecar.ts");
|
|
8147
8235
|
}
|
|
8148
8236
|
function resolveSnapshotSidecarBinaryPath(binDir) {
|
|
8149
|
-
return
|
|
8237
|
+
return resolve34(binDir, "snapshot-sidecar");
|
|
8150
8238
|
}
|
|
8151
8239
|
function shouldUseCompiledSnapshotSidecar(binaryPath) {
|
|
8152
|
-
if (!
|
|
8240
|
+
if (!existsSync32(binaryPath)) {
|
|
8153
8241
|
return false;
|
|
8154
8242
|
}
|
|
8155
8243
|
const preference = process.env.RIG_USE_COMPILED_SNAPSHOT_SIDECAR?.trim().toLowerCase();
|
|
@@ -8164,12 +8252,12 @@ function resolveRuntimeSourceScriptPath(fileName) {
|
|
|
8164
8252
|
process.env.PROJECT_RIG_ROOT?.trim()
|
|
8165
8253
|
].filter((value) => Boolean(value));
|
|
8166
8254
|
for (const root of hostRoots) {
|
|
8167
|
-
const candidate =
|
|
8168
|
-
if (
|
|
8255
|
+
const candidate = resolve34(root, "packages/runtime/src/control-plane/runtime", fileName);
|
|
8256
|
+
if (existsSync32(candidate)) {
|
|
8169
8257
|
return candidate;
|
|
8170
8258
|
}
|
|
8171
8259
|
}
|
|
8172
|
-
return
|
|
8260
|
+
return resolve34(import.meta.dir, "..", fileName);
|
|
8173
8261
|
}
|
|
8174
8262
|
function resolveBunCliInvocation() {
|
|
8175
8263
|
if (process.env.RIG_BUN_PATH?.trim()) {
|
|
@@ -8196,7 +8284,7 @@ function resolveBunCliInvocation() {
|
|
|
8196
8284
|
async function waitForSnapshotSidecarReady(readyFile, proc, stdoutTextPromise, stderrTextPromise) {
|
|
8197
8285
|
const deadline = Date.now() + SNAPSHOT_SIDECAR_READY_TIMEOUT_MS;
|
|
8198
8286
|
while (Date.now() < deadline) {
|
|
8199
|
-
if (
|
|
8287
|
+
if (existsSync32(readyFile)) {
|
|
8200
8288
|
return;
|
|
8201
8289
|
}
|
|
8202
8290
|
const exitCode = proc.exitCode;
|
|
@@ -8214,9 +8302,9 @@ var CANONICAL_MEMORY_DB_PATH2 = "rig/memory/project-memory.db";
|
|
|
8214
8302
|
async function hydrateRuntimeMemory(options) {
|
|
8215
8303
|
const snapshot = await readCanonicalMemoryDb(options.projectRoot);
|
|
8216
8304
|
const workspaceLayout = resolveRuntimeWorkspaceLayout(options.workspaceDir);
|
|
8217
|
-
const hydratedPath =
|
|
8305
|
+
const hydratedPath = resolve35(workspaceLayout.stateDir, "memory", "project-memory.db");
|
|
8218
8306
|
try {
|
|
8219
|
-
await mkdir3(
|
|
8307
|
+
await mkdir3(resolve35(workspaceLayout.stateDir, "memory"), { recursive: true });
|
|
8220
8308
|
await copyFile(snapshot.dbPath, hydratedPath);
|
|
8221
8309
|
return {
|
|
8222
8310
|
canonicalPath: CANONICAL_MEMORY_DB_PATH2,
|
|
@@ -8231,12 +8319,12 @@ async function hydrateRuntimeMemory(options) {
|
|
|
8231
8319
|
}
|
|
8232
8320
|
}
|
|
8233
8321
|
async function createRuntimeTaskRecordReader(options) {
|
|
8234
|
-
const legacyConfigPath =
|
|
8322
|
+
const legacyConfigPath = resolve35(options.projectRoot, ".rig", "task-config.json");
|
|
8235
8323
|
let pluginHostContext = null;
|
|
8236
8324
|
try {
|
|
8237
8325
|
pluginHostContext = await buildPluginHostContext(options.projectRoot);
|
|
8238
8326
|
} catch (error) {
|
|
8239
|
-
if (!
|
|
8327
|
+
if (!existsSync33(legacyConfigPath)) {
|
|
8240
8328
|
throw error;
|
|
8241
8329
|
}
|
|
8242
8330
|
const message = `Plugin task source unavailable; using source-aware .rig/task-config.json compatibility path: ${error instanceof Error ? error.message : String(error)}`;
|
|
@@ -8256,7 +8344,7 @@ async function createRuntimeTaskRecordReader(options) {
|
|
|
8256
8344
|
source: "plugin"
|
|
8257
8345
|
};
|
|
8258
8346
|
}
|
|
8259
|
-
if (
|
|
8347
|
+
if (existsSync33(legacyConfigPath)) {
|
|
8260
8348
|
const message = "Using source-aware .rig/task-config.json task source compatibility path";
|
|
8261
8349
|
options.diagnostics?.(message);
|
|
8262
8350
|
console.warn(message);
|
|
@@ -8273,10 +8361,10 @@ async function createRuntimeTaskRecordReader(options) {
|
|
|
8273
8361
|
};
|
|
8274
8362
|
}
|
|
8275
8363
|
function readConfiguredTaskSourceKindHint(projectRoot) {
|
|
8276
|
-
const jsonPath =
|
|
8277
|
-
if (
|
|
8364
|
+
const jsonPath = resolve35(projectRoot, "rig.config.json");
|
|
8365
|
+
if (existsSync33(jsonPath)) {
|
|
8278
8366
|
try {
|
|
8279
|
-
const parsed = JSON.parse(
|
|
8367
|
+
const parsed = JSON.parse(readFileSync16(jsonPath, "utf8"));
|
|
8280
8368
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
8281
8369
|
const taskSource = parsed.taskSource;
|
|
8282
8370
|
if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
|
|
@@ -8288,12 +8376,12 @@ function readConfiguredTaskSourceKindHint(projectRoot) {
|
|
|
8288
8376
|
return null;
|
|
8289
8377
|
}
|
|
8290
8378
|
}
|
|
8291
|
-
const tsPath =
|
|
8292
|
-
if (!
|
|
8379
|
+
const tsPath = resolve35(projectRoot, "rig.config.ts");
|
|
8380
|
+
if (!existsSync33(tsPath)) {
|
|
8293
8381
|
return null;
|
|
8294
8382
|
}
|
|
8295
8383
|
try {
|
|
8296
|
-
const source =
|
|
8384
|
+
const source = readFileSync16(tsPath, "utf8");
|
|
8297
8385
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
8298
8386
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
8299
8387
|
return kind ?? null;
|
|
@@ -8363,8 +8451,8 @@ async function writeRuntimeTaskConfigProjection(options) {
|
|
|
8363
8451
|
...options.taskEntry.validation && options.taskEntry.validation.length > 0 ? { validation: options.taskEntry.validation } : {},
|
|
8364
8452
|
...options.taskEntry.browser ? { browser: options.taskEntry.browser } : {}
|
|
8365
8453
|
};
|
|
8366
|
-
const configPath =
|
|
8367
|
-
await mkdir3(
|
|
8454
|
+
const configPath = resolve35(options.workspaceDir, ".rig", "task-config.json");
|
|
8455
|
+
await mkdir3(resolve35(options.workspaceDir, ".rig"), { recursive: true });
|
|
8368
8456
|
await writeFile2(configPath, `${JSON.stringify({ [options.task.id]: entry }, null, 2)}
|
|
8369
8457
|
`, "utf-8");
|
|
8370
8458
|
}
|
|
@@ -8428,9 +8516,9 @@ async function ensureAgentRuntime(options) {
|
|
|
8428
8516
|
}
|
|
8429
8517
|
ensureProvisioningHostProjectRootEnv(options.projectRoot);
|
|
8430
8518
|
const monorepoRoot = resolveMonorepoRoot3(options.projectRoot);
|
|
8431
|
-
const workspaceDir =
|
|
8519
|
+
const workspaceDir = resolve35(monorepoRoot, ".worktrees", runtimeWorktreeName(options.taskId, options.id));
|
|
8432
8520
|
const createdAt = new Date().toISOString();
|
|
8433
|
-
if (!
|
|
8521
|
+
if (!existsSync33(resolve35(monorepoRoot, ".git"))) {
|
|
8434
8522
|
throw new Error(`Monorepo root is not a git checkout: ${monorepoRoot}`);
|
|
8435
8523
|
}
|
|
8436
8524
|
const taskResolution = await resolveRuntimeTaskRecord({
|
|
@@ -8465,7 +8553,7 @@ async function ensureAgentRuntime(options) {
|
|
|
8465
8553
|
logsDir: overlay.logsDir,
|
|
8466
8554
|
stateDir: overlay.stateDir,
|
|
8467
8555
|
sessionDir: overlay.sessionDir,
|
|
8468
|
-
claudeHomeDir:
|
|
8556
|
+
claudeHomeDir: resolve35(workspaceLayout.homeDir, ".claude"),
|
|
8469
8557
|
contextFile: overlay.contextPath,
|
|
8470
8558
|
binDir: workspaceLayout.binDir,
|
|
8471
8559
|
createdAt
|
|
@@ -8478,10 +8566,14 @@ async function ensureAgentRuntime(options) {
|
|
|
8478
8566
|
projectRoot: options.projectRoot,
|
|
8479
8567
|
workspaceDir
|
|
8480
8568
|
});
|
|
8481
|
-
|
|
8482
|
-
|
|
8569
|
+
mkdirSync19(runtime.binDir, { recursive: true });
|
|
8570
|
+
mkdirSync19(workspaceLayout.distDir, { recursive: true });
|
|
8483
8571
|
prepareRuntimeWorkspace(options.projectRoot, workspaceDir);
|
|
8484
|
-
|
|
8572
|
+
if (options.preserveTaskArtifacts) {
|
|
8573
|
+
console.log(`[rig-agent] Preserving runtime task artifacts for resume of ${options.taskId}.`);
|
|
8574
|
+
} else {
|
|
8575
|
+
await resetEphemeralTaskArtifacts(workspaceDir, options.taskId);
|
|
8576
|
+
}
|
|
8485
8577
|
const ctx = {
|
|
8486
8578
|
runtimeId: options.id,
|
|
8487
8579
|
taskId: options.taskId,
|
|
@@ -8494,7 +8586,7 @@ async function ensureAgentRuntime(options) {
|
|
|
8494
8586
|
runtimeId: options.id
|
|
8495
8587
|
}),
|
|
8496
8588
|
workspaceDir,
|
|
8497
|
-
artifactRoot:
|
|
8589
|
+
artifactRoot: resolve35(workspaceDir, "artifacts", options.taskId),
|
|
8498
8590
|
hostProjectRoot: options.projectRoot,
|
|
8499
8591
|
monorepoMainRoot: monorepoRoot,
|
|
8500
8592
|
monorepoBaseRef: baseRef,
|
|
@@ -8510,8 +8602,8 @@ async function ensureAgentRuntime(options) {
|
|
|
8510
8602
|
stateDir: overlay.stateDir,
|
|
8511
8603
|
logsDir: overlay.logsDir,
|
|
8512
8604
|
sessionDir: overlay.sessionDir,
|
|
8513
|
-
sessionFile:
|
|
8514
|
-
policyFile:
|
|
8605
|
+
sessionFile: resolve35(overlay.sessionDir, "session.json"),
|
|
8606
|
+
policyFile: resolve35(options.projectRoot, "rig/policy/policy.json"),
|
|
8515
8607
|
binDir: runtime.binDir,
|
|
8516
8608
|
createdAt,
|
|
8517
8609
|
memory
|
|
@@ -8522,9 +8614,9 @@ async function ensureAgentRuntime(options) {
|
|
|
8522
8614
|
task: taskResolution.task,
|
|
8523
8615
|
taskEntry
|
|
8524
8616
|
});
|
|
8525
|
-
const manifestPath =
|
|
8617
|
+
const manifestPath = resolve35(runtimeRoot, "manifest.json");
|
|
8526
8618
|
const bakedScopeHash = sha256Hex(JSON.stringify(taskEntry.scope || []));
|
|
8527
|
-
const runtimeAgentBinary =
|
|
8619
|
+
const runtimeAgentBinary = resolve35(runtime.binDir, "rig-agent");
|
|
8528
8620
|
await ensureRigGitBinaryPath();
|
|
8529
8621
|
const bakedInfoOutput = await captureTaskInfoOutput({
|
|
8530
8622
|
projectRoot: options.projectRoot,
|
|
@@ -8539,10 +8631,10 @@ async function ensureAgentRuntime(options) {
|
|
|
8539
8631
|
const bakedStatusOutput = await captureStdout(async () => {
|
|
8540
8632
|
taskStatus(options.projectRoot);
|
|
8541
8633
|
});
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8634
|
+
rmSync13(runtime.binDir, { recursive: true, force: true });
|
|
8635
|
+
rmSync13(workspaceLayout.distDir, { recursive: true, force: true });
|
|
8636
|
+
mkdirSync19(runtime.binDir, { recursive: true });
|
|
8637
|
+
mkdirSync19(workspaceLayout.distDir, { recursive: true });
|
|
8546
8638
|
await buildRuntimeToolchain({
|
|
8547
8639
|
projectRoot: options.projectRoot,
|
|
8548
8640
|
workspaceDir,
|
|
@@ -8579,9 +8671,9 @@ async function ensureAgentRuntime(options) {
|
|
|
8579
8671
|
workspaceDir,
|
|
8580
8672
|
taskEntry
|
|
8581
8673
|
});
|
|
8582
|
-
const sandboxDir =
|
|
8674
|
+
const sandboxDir = resolve35(runtimeRoot, "sandbox");
|
|
8583
8675
|
await mkdir3(sandboxDir, { recursive: true });
|
|
8584
|
-
await writeFile2(
|
|
8676
|
+
await writeFile2(resolve35(runtimeRoot, "runtime.json"), JSON.stringify({
|
|
8585
8677
|
id: options.id,
|
|
8586
8678
|
taskId: options.taskId,
|
|
8587
8679
|
mode: "worktree",
|
|
@@ -8688,8 +8780,8 @@ async function runCodexAppServerTaskRun(options) {
|
|
|
8688
8780
|
const sendRequest = async (method, params) => {
|
|
8689
8781
|
const id = nextRequestId;
|
|
8690
8782
|
nextRequestId += 1;
|
|
8691
|
-
const resultPromise = new Promise((
|
|
8692
|
-
pendingResponses.set(id, { resolve:
|
|
8783
|
+
const resultPromise = new Promise((resolve36, reject) => {
|
|
8784
|
+
pendingResponses.set(id, { resolve: resolve36, reject });
|
|
8693
8785
|
});
|
|
8694
8786
|
await sendMessage({ id, method, params });
|
|
8695
8787
|
return resultPromise;
|
|
@@ -8888,8 +8980,8 @@ async function runCodexAppServerTaskRun(options) {
|
|
|
8888
8980
|
console.error(line);
|
|
8889
8981
|
}
|
|
8890
8982
|
});
|
|
8891
|
-
const exitPromise = new Promise((
|
|
8892
|
-
child.once("close", (code, signal) =>
|
|
8983
|
+
const exitPromise = new Promise((resolve36) => {
|
|
8984
|
+
child.once("close", (code, signal) => resolve36({ code, signal }));
|
|
8893
8985
|
});
|
|
8894
8986
|
await sendRequest("initialize", {
|
|
8895
8987
|
clientInfo: DEFAULT_CLIENT_INFO,
|
|
@@ -8930,7 +9022,7 @@ async function runCodexAppServerTaskRun(options) {
|
|
|
8930
9022
|
while (!completionState.current) {
|
|
8931
9023
|
exitResult = await Promise.race([
|
|
8932
9024
|
exitPromise,
|
|
8933
|
-
new Promise((
|
|
9025
|
+
new Promise((resolve36) => setTimeout(() => resolve36(null), 100))
|
|
8934
9026
|
]);
|
|
8935
9027
|
if (exitResult) {
|
|
8936
9028
|
break;
|
|
@@ -9079,13 +9171,13 @@ function sanitizeEnv(env) {
|
|
|
9079
9171
|
return next;
|
|
9080
9172
|
}
|
|
9081
9173
|
function writeChildLine(child, line) {
|
|
9082
|
-
return new Promise((
|
|
9174
|
+
return new Promise((resolve36, reject) => {
|
|
9083
9175
|
child.stdin.write(line, (error) => {
|
|
9084
9176
|
if (error) {
|
|
9085
9177
|
reject(error);
|
|
9086
9178
|
return;
|
|
9087
9179
|
}
|
|
9088
|
-
|
|
9180
|
+
resolve36();
|
|
9089
9181
|
});
|
|
9090
9182
|
});
|
|
9091
9183
|
}
|
|
@@ -9131,7 +9223,175 @@ function formatJsonRpcError(error) {
|
|
|
9131
9223
|
return parts.join(" ");
|
|
9132
9224
|
}
|
|
9133
9225
|
|
|
9226
|
+
// packages/runtime/src/control-plane/pi-sessiond/launcher.ts
|
|
9227
|
+
import { randomBytes } from "crypto";
|
|
9228
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync20, readFileSync as readFileSync17, rmSync as rmSync14 } from "fs";
|
|
9229
|
+
import { dirname as dirname14, resolve as resolve36 } from "path";
|
|
9230
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9231
|
+
|
|
9232
|
+
// packages/runtime/src/control-plane/pi-sessiond/client.ts
|
|
9233
|
+
class RigPiSessionDaemonClient {
|
|
9234
|
+
baseUrl;
|
|
9235
|
+
token;
|
|
9236
|
+
constructor(options) {
|
|
9237
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
9238
|
+
this.token = options.token;
|
|
9239
|
+
}
|
|
9240
|
+
static fromConnection(connection, token) {
|
|
9241
|
+
if (connection.mode === "http")
|
|
9242
|
+
return new RigPiSessionDaemonClient({ baseUrl: connection.baseUrl, token });
|
|
9243
|
+
throw new Error("Unix-socket Rig Pi daemon connections are not implemented in this build; use loopback HTTP.");
|
|
9244
|
+
}
|
|
9245
|
+
async request(method, path, body) {
|
|
9246
|
+
const response = await fetch(`${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`, {
|
|
9247
|
+
method,
|
|
9248
|
+
headers: {
|
|
9249
|
+
authorization: `Bearer ${this.token}`,
|
|
9250
|
+
...body === undefined ? {} : { "content-type": "application/json" }
|
|
9251
|
+
},
|
|
9252
|
+
body: body === undefined ? undefined : JSON.stringify(body)
|
|
9253
|
+
});
|
|
9254
|
+
const text = await response.text();
|
|
9255
|
+
const payload = text.trim() ? JSON.parse(text) : undefined;
|
|
9256
|
+
if (!response.ok) {
|
|
9257
|
+
const message = payload && typeof payload === "object" && !Array.isArray(payload) && typeof payload.error === "string" ? payload.error : text || response.statusText;
|
|
9258
|
+
throw new Error(`Rig Pi session daemon request failed (${response.status}): ${message}`);
|
|
9259
|
+
}
|
|
9260
|
+
return payload;
|
|
9261
|
+
}
|
|
9262
|
+
webSocketUrl(path) {
|
|
9263
|
+
const url = new URL(`${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`);
|
|
9264
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
9265
|
+
url.searchParams.set("token", this.token);
|
|
9266
|
+
return url.toString();
|
|
9267
|
+
}
|
|
9268
|
+
}
|
|
9269
|
+
|
|
9270
|
+
// packages/runtime/src/control-plane/pi-sessiond/launcher.ts
|
|
9271
|
+
var BUILD_CONFIG2 = {};
|
|
9272
|
+
var BAKED_RIG_SOURCE_ROOT = BUILD_CONFIG2.RIG_SOURCE_ROOT ?? "";
|
|
9273
|
+
async function ensureRigPiSessionDaemon(input) {
|
|
9274
|
+
const rootDir = resolve36(input.rootDir);
|
|
9275
|
+
mkdirSync20(rootDir, { recursive: true });
|
|
9276
|
+
const readyFile = resolve36(rootDir, "ready.json");
|
|
9277
|
+
const existing = readDaemonReadyFile(readyFile);
|
|
9278
|
+
const existingHandle = existing ? await tryReady(existing) : null;
|
|
9279
|
+
if (existingHandle)
|
|
9280
|
+
return existingHandle;
|
|
9281
|
+
try {
|
|
9282
|
+
rmSync14(readyFile, { force: true });
|
|
9283
|
+
} catch {}
|
|
9284
|
+
const token = randomBytes(32).toString("hex");
|
|
9285
|
+
const binPath = resolveRigPiSessionDaemonBinPath(input.env);
|
|
9286
|
+
const bunPath = input.env.RIG_BUN_PATH || process.execPath;
|
|
9287
|
+
const proc = Bun.spawn([bunPath, binPath], {
|
|
9288
|
+
cwd: rootDir,
|
|
9289
|
+
env: {
|
|
9290
|
+
...input.env,
|
|
9291
|
+
RIG_PI_SESSIOND_ROOT: rootDir,
|
|
9292
|
+
RIG_PI_SESSIOND_TOKEN: token,
|
|
9293
|
+
RIG_PI_SESSIOND_READY_FILE: readyFile,
|
|
9294
|
+
RIG_PI_SESSIOND_HOST: "127.0.0.1",
|
|
9295
|
+
RIG_PI_SESSIOND_PORT: "0",
|
|
9296
|
+
...input.version ? { RIG_VERSION: input.version } : {},
|
|
9297
|
+
...input.commit ? { RIG_GIT_COMMIT: input.commit } : {}
|
|
9298
|
+
},
|
|
9299
|
+
stdin: "ignore",
|
|
9300
|
+
stdout: "ignore",
|
|
9301
|
+
stderr: "inherit"
|
|
9302
|
+
});
|
|
9303
|
+
proc.unref();
|
|
9304
|
+
const deadline = Date.now() + (input.timeoutMs ?? 15000);
|
|
9305
|
+
while (Date.now() < deadline) {
|
|
9306
|
+
const ready = readDaemonReadyFile(readyFile);
|
|
9307
|
+
const handle = ready ? await tryReady(ready) : null;
|
|
9308
|
+
if (handle)
|
|
9309
|
+
return handle;
|
|
9310
|
+
await sleep(100);
|
|
9311
|
+
}
|
|
9312
|
+
throw new Error([
|
|
9313
|
+
`Rig Pi session daemon did not become ready at ${readyFile}.`,
|
|
9314
|
+
"Usual causes: the bundled Pi runtime is missing or broken. Run `rig doctor` to check Pi wiring,",
|
|
9315
|
+
"set RIG_PI_BINARY to a working Pi build, or run without Pi via RIG_RUNTIME_ADAPTER=claude-code."
|
|
9316
|
+
].join(`
|
|
9317
|
+
`));
|
|
9318
|
+
}
|
|
9319
|
+
function privateMetadataForDaemon(input) {
|
|
9320
|
+
return { public: input.publicMetadata, daemonConnection: input.connection };
|
|
9321
|
+
}
|
|
9322
|
+
async function tryReady(ready) {
|
|
9323
|
+
const host = typeof ready.host === "string" ? ready.host : "127.0.0.1";
|
|
9324
|
+
const port = typeof ready.port === "number" ? ready.port : Number(ready.port);
|
|
9325
|
+
const token = typeof ready.token === "string" ? ready.token : "";
|
|
9326
|
+
if (!Number.isFinite(port) || port <= 0 || !token)
|
|
9327
|
+
return null;
|
|
9328
|
+
const baseUrl = `http://${host}:${port}`;
|
|
9329
|
+
const client = new RigPiSessionDaemonClient({ baseUrl, token });
|
|
9330
|
+
try {
|
|
9331
|
+
await client.request("GET", "/health");
|
|
9332
|
+
} catch {
|
|
9333
|
+
return null;
|
|
9334
|
+
}
|
|
9335
|
+
return {
|
|
9336
|
+
client,
|
|
9337
|
+
connection: { mode: "http", baseUrl, tokenRef: tokenRefFromReady(ready) },
|
|
9338
|
+
token,
|
|
9339
|
+
ready
|
|
9340
|
+
};
|
|
9341
|
+
}
|
|
9342
|
+
function tokenRefFromReady(ready) {
|
|
9343
|
+
const token = typeof ready.token === "string" ? ready.token : "";
|
|
9344
|
+
return token ? `inline:${token}` : "missing";
|
|
9345
|
+
}
|
|
9346
|
+
function resolveRigPiSessionDaemonBinPath(env) {
|
|
9347
|
+
const explicit = env.RIG_PI_SESSIOND_BIN?.trim();
|
|
9348
|
+
if (explicit)
|
|
9349
|
+
return explicit;
|
|
9350
|
+
const roots = [
|
|
9351
|
+
env.RIG_CONTROL_PLANE_SOURCE_ROOT?.trim(),
|
|
9352
|
+
BAKED_RIG_SOURCE_ROOT.trim(),
|
|
9353
|
+
process.env.RIG_CONTROL_PLANE_SOURCE_ROOT?.trim(),
|
|
9354
|
+
process.env.RIG_HOST_PROJECT_ROOT?.trim(),
|
|
9355
|
+
process.env.PROJECT_RIG_ROOT?.trim()
|
|
9356
|
+
].filter((value) => Boolean(value));
|
|
9357
|
+
for (const root of roots) {
|
|
9358
|
+
const candidate = resolve36(root, "packages/runtime/src/control-plane/pi-sessiond/bin.ts");
|
|
9359
|
+
if (existsSync34(candidate))
|
|
9360
|
+
return candidate;
|
|
9361
|
+
}
|
|
9362
|
+
const moduleCandidate = fileURLToPath2(new URL("./bin.ts", import.meta.url));
|
|
9363
|
+
if (existsSync34(moduleCandidate))
|
|
9364
|
+
return moduleCandidate;
|
|
9365
|
+
throw new Error([
|
|
9366
|
+
"Unable to locate rig-pi-sessiond entrypoint.",
|
|
9367
|
+
"Set RIG_PI_SESSIOND_BIN or RIG_CONTROL_PLANE_SOURCE_ROOT to the Rig source checkout,",
|
|
9368
|
+
"or run without the Pi daemon via RIG_RUNTIME_ADAPTER=claude-code."
|
|
9369
|
+
].join(`
|
|
9370
|
+
`));
|
|
9371
|
+
}
|
|
9372
|
+
function readDaemonReadyFile(path) {
|
|
9373
|
+
if (!existsSync34(path))
|
|
9374
|
+
return null;
|
|
9375
|
+
try {
|
|
9376
|
+
const parsed = JSON.parse(readFileSync17(path, "utf8"));
|
|
9377
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
9378
|
+
} catch {
|
|
9379
|
+
return null;
|
|
9380
|
+
}
|
|
9381
|
+
}
|
|
9382
|
+
function sleep(ms) {
|
|
9383
|
+
return new Promise((resolveSleep) => setTimeout(resolveSleep, ms));
|
|
9384
|
+
}
|
|
9385
|
+
function resolveRigPiSessionDaemonRoot(stateDir) {
|
|
9386
|
+
const root = resolve36(stateDir, "pi-sessiond");
|
|
9387
|
+
mkdirSync20(dirname14(root), { recursive: true });
|
|
9388
|
+
if (!existsSync34(root))
|
|
9389
|
+
mkdirSync20(root, { recursive: true });
|
|
9390
|
+
return root;
|
|
9391
|
+
}
|
|
9392
|
+
|
|
9134
9393
|
// packages/runtime/src/control-plane/agent-wrapper.ts
|
|
9394
|
+
var requireFromRuntime = createRequire(import.meta.url);
|
|
9135
9395
|
async function finalizeRuntimeSnapshot(snapshotSidecar, providerCommand, exitCode, context) {
|
|
9136
9396
|
try {
|
|
9137
9397
|
await snapshotSidecar.finalize(providerCommand, exitCode);
|
|
@@ -9164,7 +9424,7 @@ async function startOptionalRuntimeSnapshotSidecar(runtime, startSidecar = start
|
|
|
9164
9424
|
}
|
|
9165
9425
|
}
|
|
9166
9426
|
async function runAgentWrapper(options = {}) {
|
|
9167
|
-
const projectRoot =
|
|
9427
|
+
const projectRoot = resolve37(options.projectRoot || process.env.PROJECT_RIG_ROOT || process.cwd());
|
|
9168
9428
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
9169
9429
|
const argv = options.argv || process.argv.slice(2);
|
|
9170
9430
|
if (argv.length === 0 || argv[0] === "--version" || argv[0] === "--help" || argv[0] === "help") {
|
|
@@ -9193,7 +9453,8 @@ async function runAgentWrapper(options = {}) {
|
|
|
9193
9453
|
taskId,
|
|
9194
9454
|
mode: "worktree",
|
|
9195
9455
|
provider,
|
|
9196
|
-
taskRecordReader: taskRecordReaderFromEnv(taskId)
|
|
9456
|
+
taskRecordReader: taskRecordReaderFromEnv(taskId),
|
|
9457
|
+
preserveTaskArtifacts: process.env.RIG_RUN_RESUME === "1" || process.env.RIG_RUNTIME_ARTIFACT_CLEANUP === "preserve"
|
|
9197
9458
|
});
|
|
9198
9459
|
emitWrapperEvent("runtime.provision.completed", {
|
|
9199
9460
|
runtimeId: runtime.id,
|
|
@@ -9226,7 +9487,8 @@ async function runAgentWrapper(options = {}) {
|
|
|
9226
9487
|
return 1;
|
|
9227
9488
|
}
|
|
9228
9489
|
const providerArgs = buildProviderArgs(provider, runtime, argv);
|
|
9229
|
-
const
|
|
9490
|
+
const normalPiDaemonPath = provider === "pi" && process.env.RIG_PI_RPC_FALLBACK !== "1";
|
|
9491
|
+
const providerCommand = normalPiDaemonPath ? ["rig-pi-sessiond", ...providerArgs] : [providerBinary(provider), ...providerArgs];
|
|
9230
9492
|
emitWrapperEvent("provider.launch", {
|
|
9231
9493
|
provider,
|
|
9232
9494
|
runtimeId: runtime.id,
|
|
@@ -9238,11 +9500,11 @@ async function runAgentWrapper(options = {}) {
|
|
|
9238
9500
|
const bypassOuterRuntimeSandbox = shouldBypassProviderSandboxOnPlatform(provider, process.platform);
|
|
9239
9501
|
const runClaudeCompatUnsandboxed = provider === "claude-code" && bypassOuterRuntimeSandbox;
|
|
9240
9502
|
if (runClaudeCompatUnsandboxed && process.env.HOME?.trim()) {
|
|
9241
|
-
env.CLAUDE_HOME =
|
|
9503
|
+
env.CLAUDE_HOME = resolve37(process.env.HOME.trim(), ".claude");
|
|
9242
9504
|
env.RIG_CLAUDE_RUNTIME_HOME = runtime.claudeHomeDir;
|
|
9243
9505
|
}
|
|
9244
9506
|
if (provider === "pi") {
|
|
9245
|
-
env.PI_CODING_AGENT_DIR =
|
|
9507
|
+
env.PI_CODING_AGENT_DIR = resolve37(runtime.homeDir, ".pi", "agent");
|
|
9246
9508
|
env.PI_CODING_AGENT_SESSION_DIR = runtime.sessionDir;
|
|
9247
9509
|
}
|
|
9248
9510
|
env.RIG_RUNTIME_SANDBOX = "enforce";
|
|
@@ -9276,14 +9538,36 @@ async function runAgentWrapper(options = {}) {
|
|
|
9276
9538
|
},
|
|
9277
9539
|
command: providerCommand
|
|
9278
9540
|
})).command;
|
|
9279
|
-
|
|
9280
|
-
|
|
9281
|
-
|
|
9282
|
-
|
|
9283
|
-
|
|
9284
|
-
|
|
9285
|
-
|
|
9286
|
-
|
|
9541
|
+
if (provider === "pi" && process.env.RIG_PI_RPC_FALLBACK !== "1") {
|
|
9542
|
+
const prompt = await readProcessStdin();
|
|
9543
|
+
exitCode = await runPiSessionDaemonProvider({
|
|
9544
|
+
projectRoot,
|
|
9545
|
+
runtime,
|
|
9546
|
+
env,
|
|
9547
|
+
prompt,
|
|
9548
|
+
runId: process.env.RIG_SERVER_RUN_ID?.trim() || process.env.RIG_RUN_ID?.trim() || undefined,
|
|
9549
|
+
sessionName: process.env.RIG_SERVER_RUN_ID?.trim() ? `Rig ${process.env.RIG_SERVER_RUN_ID.trim()}` : `Rig ${runtime.taskId}`
|
|
9550
|
+
});
|
|
9551
|
+
} else if (provider === "pi" && isPiRpcArgs(providerArgs)) {
|
|
9552
|
+
const prompt = await readProcessStdin();
|
|
9553
|
+
exitCode = await runPiRpcProviderFallback({
|
|
9554
|
+
command,
|
|
9555
|
+
cwd: runtime.workspaceDir,
|
|
9556
|
+
env,
|
|
9557
|
+
prompt,
|
|
9558
|
+
runId: process.env.RIG_SERVER_RUN_ID?.trim() || undefined,
|
|
9559
|
+
sessionName: process.env.RIG_SERVER_RUN_ID?.trim() ? `Rig ${process.env.RIG_SERVER_RUN_ID.trim()}` : `Rig ${runtime.taskId}`
|
|
9560
|
+
});
|
|
9561
|
+
} else {
|
|
9562
|
+
const proc = Bun.spawn(command, {
|
|
9563
|
+
cwd: runtime.workspaceDir,
|
|
9564
|
+
env,
|
|
9565
|
+
stdin: "inherit",
|
|
9566
|
+
stdout: "inherit",
|
|
9567
|
+
stderr: "inherit"
|
|
9568
|
+
});
|
|
9569
|
+
exitCode = await proc.exited;
|
|
9570
|
+
}
|
|
9287
9571
|
}
|
|
9288
9572
|
if (snapshotSidecar) {
|
|
9289
9573
|
await finalizeRuntimeSnapshot(snapshotSidecar, providerCommand, exitCode, {
|
|
@@ -9298,15 +9582,13 @@ async function runAgentWrapper(options = {}) {
|
|
|
9298
9582
|
throw error;
|
|
9299
9583
|
}
|
|
9300
9584
|
const serverManagedRun = Boolean(process.env.RIG_SERVER_RUN_ID?.trim());
|
|
9301
|
-
if (exitCode === 0 && serverManagedRun) {
|
|
9302
|
-
await updateTaskSourceAfterRun(monorepoRoot, taskId, runtime);
|
|
9303
|
-
}
|
|
9304
9585
|
const taskClosed = await isTaskClosed(monorepoRoot, taskId);
|
|
9305
9586
|
const finalExitCode = resolveFinalProviderExitCode({
|
|
9306
9587
|
providerExitCode: exitCode,
|
|
9307
9588
|
taskClosed,
|
|
9308
9589
|
serverManagedRun
|
|
9309
9590
|
});
|
|
9591
|
+
const handoffRequired = exitCode !== 0 || !taskClosed && !serverManagedRun;
|
|
9310
9592
|
emitWrapperEvent("provider.completed", {
|
|
9311
9593
|
provider,
|
|
9312
9594
|
runtimeId: runtime.id,
|
|
@@ -9315,24 +9597,353 @@ async function runAgentWrapper(options = {}) {
|
|
|
9315
9597
|
providerExitCode: exitCode,
|
|
9316
9598
|
taskClosed,
|
|
9317
9599
|
serverManagedRun,
|
|
9318
|
-
handoffRequired
|
|
9600
|
+
handoffRequired
|
|
9319
9601
|
});
|
|
9320
|
-
if (
|
|
9602
|
+
if (handoffRequired) {
|
|
9321
9603
|
recordRuntimeHandoff(projectRoot, runtime, taskId, exitCode);
|
|
9322
9604
|
}
|
|
9323
|
-
if (exitCode === 0 && !taskClosed && serverManagedRun) {
|
|
9324
|
-
console.error(`[rig-agent] Server-managed task run cannot finish successfully while ${taskId} is still open.`);
|
|
9325
|
-
}
|
|
9326
9605
|
return finalExitCode;
|
|
9327
9606
|
}
|
|
9607
|
+
function parseJsonRecord(line) {
|
|
9608
|
+
try {
|
|
9609
|
+
const parsed = JSON.parse(line);
|
|
9610
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
9611
|
+
} catch {
|
|
9612
|
+
return null;
|
|
9613
|
+
}
|
|
9614
|
+
}
|
|
9615
|
+
async function readProcessStdin() {
|
|
9616
|
+
if (process.stdin.isTTY)
|
|
9617
|
+
return "";
|
|
9618
|
+
return await new Promise((resolveRead) => {
|
|
9619
|
+
let data = "";
|
|
9620
|
+
process.stdin.setEncoding("utf8");
|
|
9621
|
+
process.stdin.on("data", (chunk) => {
|
|
9622
|
+
data += String(chunk);
|
|
9623
|
+
});
|
|
9624
|
+
process.stdin.on("end", () => resolveRead(data));
|
|
9625
|
+
process.stdin.resume();
|
|
9626
|
+
});
|
|
9627
|
+
}
|
|
9628
|
+
async function pumpReadableLines(stream, onLine) {
|
|
9629
|
+
if (!stream)
|
|
9630
|
+
return;
|
|
9631
|
+
const reader = stream.getReader();
|
|
9632
|
+
const decoder = new TextDecoder;
|
|
9633
|
+
let buffer = "";
|
|
9634
|
+
try {
|
|
9635
|
+
while (true) {
|
|
9636
|
+
const { done, value } = await reader.read();
|
|
9637
|
+
if (done)
|
|
9638
|
+
break;
|
|
9639
|
+
buffer += decoder.decode(value, { stream: true });
|
|
9640
|
+
const parts = buffer.split(/\r?\n/);
|
|
9641
|
+
buffer = parts.pop() ?? "";
|
|
9642
|
+
for (const part of parts)
|
|
9643
|
+
onLine(part);
|
|
9644
|
+
}
|
|
9645
|
+
buffer += decoder.decode();
|
|
9646
|
+
if (buffer)
|
|
9647
|
+
onLine(buffer);
|
|
9648
|
+
} finally {
|
|
9649
|
+
reader.releaseLock();
|
|
9650
|
+
}
|
|
9651
|
+
}
|
|
9652
|
+
function isBlockingPiRpcUiRequest(record) {
|
|
9653
|
+
if (record.type !== "extension_ui_request")
|
|
9654
|
+
return false;
|
|
9655
|
+
return record.method === "select" || record.method === "confirm" || record.method === "input" || record.method === "editor";
|
|
9656
|
+
}
|
|
9657
|
+
function writeRpcCommand(stdin, command) {
|
|
9658
|
+
stdin.write(`${JSON.stringify(command)}
|
|
9659
|
+
`);
|
|
9660
|
+
}
|
|
9661
|
+
function joinUrl(baseUrl, pathname) {
|
|
9662
|
+
return `${baseUrl.replace(/\/+$/, "")}${pathname.startsWith("/") ? pathname : `/${pathname}`}`;
|
|
9663
|
+
}
|
|
9664
|
+
async function readQueuedSteeringFromServer(input) {
|
|
9665
|
+
if (!input.serverUrl || !input.runId)
|
|
9666
|
+
return [];
|
|
9667
|
+
const headers = {};
|
|
9668
|
+
if (input.authToken)
|
|
9669
|
+
headers.authorization = `Bearer ${input.authToken}`;
|
|
9670
|
+
const response = await fetch(joinUrl(input.serverUrl, `/api/runs/${encodeURIComponent(input.runId)}/steering?ack=1`), { headers });
|
|
9671
|
+
if (!response.ok)
|
|
9672
|
+
return [];
|
|
9673
|
+
const payload = await response.json().catch(() => null);
|
|
9674
|
+
const messages = payload && typeof payload === "object" && !Array.isArray(payload) ? payload.messages : null;
|
|
9675
|
+
return Array.isArray(messages) ? messages.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
|
|
9676
|
+
}
|
|
9677
|
+
function steeringMessageText(entry) {
|
|
9678
|
+
const message = typeof entry.message === "string" ? entry.message.trim() : "";
|
|
9679
|
+
return message || null;
|
|
9680
|
+
}
|
|
9681
|
+
function isPiRpcArgs(args) {
|
|
9682
|
+
return cliOptionValue(args, "--mode") === "rpc";
|
|
9683
|
+
}
|
|
9684
|
+
async function runPiSessionDaemonProvider(input) {
|
|
9685
|
+
const stdout = input.stdout ?? process.stdout;
|
|
9686
|
+
const stderr = input.stderr ?? process.stderr;
|
|
9687
|
+
const runId = input.runId ?? input.runtime.taskId;
|
|
9688
|
+
emitWrapperEvent("pi.sessiond.starting", {
|
|
9689
|
+
runId,
|
|
9690
|
+
runtimeId: input.runtime.id,
|
|
9691
|
+
workspaceDir: input.runtime.workspaceDir
|
|
9692
|
+
});
|
|
9693
|
+
const daemon = await ensureRigPiSessionDaemon({
|
|
9694
|
+
rootDir: resolveRigPiSessionDaemonRoot(input.runtime.stateDir),
|
|
9695
|
+
env: input.env,
|
|
9696
|
+
version: process.env.RIG_VERSION?.trim() || "dev",
|
|
9697
|
+
commit: process.env.RIG_GIT_COMMIT?.trim() || undefined
|
|
9698
|
+
});
|
|
9699
|
+
emitWrapperEvent("pi.sessiond.ready", {
|
|
9700
|
+
runId,
|
|
9701
|
+
runtimeId: input.runtime.id,
|
|
9702
|
+
connection: daemon.connection,
|
|
9703
|
+
ready: daemon.ready
|
|
9704
|
+
});
|
|
9705
|
+
const start = await daemon.client.request("POST", "/sessions", {
|
|
9706
|
+
runId,
|
|
9707
|
+
cwd: input.runtime.workspaceDir,
|
|
9708
|
+
agentDir: input.env.PI_CODING_AGENT_DIR || resolve37(input.runtime.homeDir, ".pi", "agent"),
|
|
9709
|
+
sessionDir: input.runtime.sessionDir,
|
|
9710
|
+
sessionName: input.sessionName
|
|
9711
|
+
});
|
|
9712
|
+
const privateMetadata = privateMetadataForDaemon({ publicMetadata: start.metadata, connection: daemon.connection });
|
|
9713
|
+
emitWrapperEvent("pi.session.ready", {
|
|
9714
|
+
runId,
|
|
9715
|
+
runtimeId: input.runtime.id,
|
|
9716
|
+
metadata: start.metadata,
|
|
9717
|
+
privateMetadata
|
|
9718
|
+
});
|
|
9719
|
+
const eventStream = waitForPiSessionEvents({
|
|
9720
|
+
url: daemon.client.webSocketUrl(`/sessions/${encodeURIComponent(start.metadata.sessionId)}/events`),
|
|
9721
|
+
stdout,
|
|
9722
|
+
stderr,
|
|
9723
|
+
runId
|
|
9724
|
+
});
|
|
9725
|
+
emitWrapperEvent("pi.session.event_stream.connected", { runId, sessionId: start.metadata.sessionId });
|
|
9726
|
+
const forwardSigterm = () => {
|
|
9727
|
+
daemon.client.request("POST", `/sessions/${encodeURIComponent(start.metadata.sessionId)}/abort`).catch(() => {
|
|
9728
|
+
return;
|
|
9729
|
+
});
|
|
9730
|
+
eventStream.close();
|
|
9731
|
+
};
|
|
9732
|
+
process.once("SIGTERM", forwardSigterm);
|
|
9733
|
+
try {
|
|
9734
|
+
if (input.prompt.trim()) {
|
|
9735
|
+
await daemon.client.request("POST", `/sessions/${encodeURIComponent(start.metadata.sessionId)}/prompt`, { text: input.prompt });
|
|
9736
|
+
emitWrapperEvent("pi.prompt.sent", { runId, sessionId: start.metadata.sessionId, bytes: Buffer.byteLength(input.prompt) });
|
|
9737
|
+
} else {
|
|
9738
|
+
emitWrapperEvent("pi.prompt.waiting", { runId, sessionId: start.metadata.sessionId, reason: "empty-initial-prompt" });
|
|
9739
|
+
}
|
|
9740
|
+
const result = await eventStream.done;
|
|
9741
|
+
if (result.error) {
|
|
9742
|
+
stderr.write(`[rig-agent] Pi session daemon stream failed: ${result.error}
|
|
9743
|
+
`);
|
|
9744
|
+
return 1;
|
|
9745
|
+
}
|
|
9746
|
+
return 0;
|
|
9747
|
+
} finally {
|
|
9748
|
+
process.off("SIGTERM", forwardSigterm);
|
|
9749
|
+
eventStream.close();
|
|
9750
|
+
}
|
|
9751
|
+
}
|
|
9752
|
+
function waitForPiSessionEvents(input) {
|
|
9753
|
+
let closed = false;
|
|
9754
|
+
let resolved = false;
|
|
9755
|
+
let socket = null;
|
|
9756
|
+
let resolveDone = () => {
|
|
9757
|
+
return;
|
|
9758
|
+
};
|
|
9759
|
+
const done = new Promise((resolveDoneInner) => {
|
|
9760
|
+
resolveDone = resolveDoneInner;
|
|
9761
|
+
});
|
|
9762
|
+
const finish = (value) => {
|
|
9763
|
+
if (resolved)
|
|
9764
|
+
return;
|
|
9765
|
+
resolved = true;
|
|
9766
|
+
resolveDone(value);
|
|
9767
|
+
};
|
|
9768
|
+
socket = new WebSocket(input.url);
|
|
9769
|
+
socket.addEventListener("message", (message) => {
|
|
9770
|
+
const text = typeof message.data === "string" ? message.data : Buffer.from(message.data).toString("utf8");
|
|
9771
|
+
input.stdout.write(`${text}
|
|
9772
|
+
`);
|
|
9773
|
+
const envelope = parseJsonRecord(text);
|
|
9774
|
+
if (!envelope)
|
|
9775
|
+
return;
|
|
9776
|
+
if (envelope.type === "pi.event") {
|
|
9777
|
+
const event = envelope.event && typeof envelope.event === "object" && !Array.isArray(envelope.event) ? envelope.event : null;
|
|
9778
|
+
if (event?.type === "agent_end") {
|
|
9779
|
+
emitWrapperEvent("pi.session.agent_end", { runId: input.runId, sessionId: envelope.sessionId });
|
|
9780
|
+
finish({});
|
|
9781
|
+
}
|
|
9782
|
+
}
|
|
9783
|
+
if (envelope.type === "error") {
|
|
9784
|
+
emitWrapperEvent("pi.session.error", { runId: input.runId, message: envelope.message, detail: envelope.detail ?? null });
|
|
9785
|
+
finish({ error: envelope.message });
|
|
9786
|
+
}
|
|
9787
|
+
});
|
|
9788
|
+
socket.addEventListener("error", () => {
|
|
9789
|
+
if (!closed)
|
|
9790
|
+
finish({ error: "WebSocket error" });
|
|
9791
|
+
});
|
|
9792
|
+
socket.addEventListener("close", () => {
|
|
9793
|
+
if (!closed && !resolved)
|
|
9794
|
+
finish({ error: "WebSocket closed before agent_end" });
|
|
9795
|
+
});
|
|
9796
|
+
return {
|
|
9797
|
+
done,
|
|
9798
|
+
close: () => {
|
|
9799
|
+
closed = true;
|
|
9800
|
+
try {
|
|
9801
|
+
socket?.close();
|
|
9802
|
+
} catch {}
|
|
9803
|
+
}
|
|
9804
|
+
};
|
|
9805
|
+
}
|
|
9806
|
+
async function runPiRpcProviderFallback(input) {
|
|
9807
|
+
const stdout = input.stdout ?? process.stdout;
|
|
9808
|
+
const stderr = input.stderr ?? process.stderr;
|
|
9809
|
+
const proc = Bun.spawn(input.command, {
|
|
9810
|
+
cwd: input.cwd,
|
|
9811
|
+
env: input.env,
|
|
9812
|
+
stdin: "pipe",
|
|
9813
|
+
stdout: "pipe",
|
|
9814
|
+
stderr: "pipe"
|
|
9815
|
+
});
|
|
9816
|
+
let sawAgentEnd = false;
|
|
9817
|
+
let promptError = null;
|
|
9818
|
+
let stdinOpen = true;
|
|
9819
|
+
let steeringPollStopped = false;
|
|
9820
|
+
const closeStdin = () => {
|
|
9821
|
+
if (!stdinOpen)
|
|
9822
|
+
return;
|
|
9823
|
+
stdinOpen = false;
|
|
9824
|
+
try {
|
|
9825
|
+
steeringPollStopped = true;
|
|
9826
|
+
proc.stdin.end();
|
|
9827
|
+
} catch {}
|
|
9828
|
+
};
|
|
9829
|
+
const send = (command) => {
|
|
9830
|
+
if (!stdinOpen)
|
|
9831
|
+
return;
|
|
9832
|
+
try {
|
|
9833
|
+
writeRpcCommand(proc.stdin, command);
|
|
9834
|
+
} catch (error) {
|
|
9835
|
+
promptError ??= error instanceof Error ? error.message : String(error);
|
|
9836
|
+
}
|
|
9837
|
+
};
|
|
9838
|
+
const forwardSigterm = () => {
|
|
9839
|
+
try {
|
|
9840
|
+
proc.kill("SIGTERM");
|
|
9841
|
+
} catch {}
|
|
9842
|
+
};
|
|
9843
|
+
process.once("SIGTERM", forwardSigterm);
|
|
9844
|
+
const pollSteering = async () => {
|
|
9845
|
+
const serverUrl = input.env.RIG_SERVER_URL || input.env.RIG_SERVER_BASE_URL;
|
|
9846
|
+
const authToken = input.env.RIG_AUTH_TOKEN || input.env.RIG_SERVER_AUTH_TOKEN;
|
|
9847
|
+
while (!steeringPollStopped && stdinOpen) {
|
|
9848
|
+
try {
|
|
9849
|
+
const messages = await readQueuedSteeringFromServer({ serverUrl, authToken, runId: input.runId });
|
|
9850
|
+
for (const message of messages) {
|
|
9851
|
+
const text = steeringMessageText(message);
|
|
9852
|
+
if (!text || !stdinOpen)
|
|
9853
|
+
continue;
|
|
9854
|
+
send({
|
|
9855
|
+
id: typeof message.id === "string" ? `rig_steer_${message.id}` : `rig_steer_${Date.now()}`,
|
|
9856
|
+
type: "prompt",
|
|
9857
|
+
message: text,
|
|
9858
|
+
streamingBehavior: "steer"
|
|
9859
|
+
});
|
|
9860
|
+
emitWrapperEvent("pi.rpc.steering.delivered", {
|
|
9861
|
+
runId: input.runId ?? null,
|
|
9862
|
+
steeringId: typeof message.id === "string" ? message.id : null,
|
|
9863
|
+
actor: typeof message.actor === "string" ? message.actor : "operator",
|
|
9864
|
+
message: text
|
|
9865
|
+
});
|
|
9866
|
+
}
|
|
9867
|
+
} catch (error) {
|
|
9868
|
+
emitWrapperEvent("pi.rpc.steering.poll.failed", {
|
|
9869
|
+
runId: input.runId ?? null,
|
|
9870
|
+
error: error instanceof Error ? error.message : String(error)
|
|
9871
|
+
});
|
|
9872
|
+
}
|
|
9873
|
+
await sleep2(1000);
|
|
9874
|
+
}
|
|
9875
|
+
};
|
|
9876
|
+
const stdoutPump = pumpReadableLines(proc.stdout, (line) => {
|
|
9877
|
+
stdout.write(`${line}
|
|
9878
|
+
`);
|
|
9879
|
+
const record = parseJsonRecord(line.trim());
|
|
9880
|
+
if (!record)
|
|
9881
|
+
return;
|
|
9882
|
+
if (record.type === "agent_end") {
|
|
9883
|
+
sawAgentEnd = true;
|
|
9884
|
+
closeStdin();
|
|
9885
|
+
return;
|
|
9886
|
+
}
|
|
9887
|
+
if (record.type === "response" && record.command === "prompt" && record.success === false) {
|
|
9888
|
+
promptError = typeof record.error === "string" ? record.error : "Pi RPC prompt failed.";
|
|
9889
|
+
closeStdin();
|
|
9890
|
+
return;
|
|
9891
|
+
}
|
|
9892
|
+
if (isBlockingPiRpcUiRequest(record)) {
|
|
9893
|
+
const id = typeof record.id === "string" ? record.id : "";
|
|
9894
|
+
if (id) {
|
|
9895
|
+
send({ type: "extension_ui_response", id, cancelled: true });
|
|
9896
|
+
emitWrapperEvent("pi.rpc.extension_ui.cancelled", {
|
|
9897
|
+
id,
|
|
9898
|
+
method: record.method,
|
|
9899
|
+
reason: "noninteractive Rig worker RPC session"
|
|
9900
|
+
});
|
|
9901
|
+
}
|
|
9902
|
+
}
|
|
9903
|
+
});
|
|
9904
|
+
const stderrPump = pumpReadableLines(proc.stderr, (line) => {
|
|
9905
|
+
stderr.write(`${line}
|
|
9906
|
+
`);
|
|
9907
|
+
});
|
|
9908
|
+
if (input.sessionName?.trim()) {
|
|
9909
|
+
send({ id: "rig_set_session_name", type: "set_session_name", name: input.sessionName.trim() });
|
|
9910
|
+
}
|
|
9911
|
+
const steeringPollPromise = pollSteering();
|
|
9912
|
+
if (input.prompt.trim()) {
|
|
9913
|
+
send({ id: "rig_initial_prompt", type: "prompt", message: input.prompt });
|
|
9914
|
+
emitWrapperEvent("pi.rpc.prompt.sent", {
|
|
9915
|
+
runId: input.runId ?? null,
|
|
9916
|
+
kind: "initial",
|
|
9917
|
+
bytes: Buffer.byteLength(input.prompt)
|
|
9918
|
+
});
|
|
9919
|
+
} else {
|
|
9920
|
+
closeStdin();
|
|
9921
|
+
}
|
|
9922
|
+
const exitCode = await proc.exited;
|
|
9923
|
+
process.off("SIGTERM", forwardSigterm);
|
|
9924
|
+
steeringPollStopped = true;
|
|
9925
|
+
await Promise.all([stdoutPump, stderrPump, steeringPollPromise]);
|
|
9926
|
+
if (promptError) {
|
|
9927
|
+
stderr.write(`[rig-agent] Pi RPC prompt failed: ${promptError}
|
|
9928
|
+
`);
|
|
9929
|
+
return exitCode === 0 ? 1 : exitCode;
|
|
9930
|
+
}
|
|
9931
|
+
if (input.prompt.trim() && !sawAgentEnd && exitCode === 0) {
|
|
9932
|
+
stderr.write(`[rig-agent] Pi RPC exited before emitting agent_end.
|
|
9933
|
+
`);
|
|
9934
|
+
return 1;
|
|
9935
|
+
}
|
|
9936
|
+
return exitCode;
|
|
9937
|
+
}
|
|
9938
|
+
var runPiRpcProvider = runPiRpcProviderFallback;
|
|
9328
9939
|
function resolveFinalProviderExitCode(input) {
|
|
9329
9940
|
if (input.providerExitCode !== 0) {
|
|
9330
9941
|
return input.providerExitCode;
|
|
9331
9942
|
}
|
|
9332
|
-
if (input.taskClosed) {
|
|
9943
|
+
if (input.taskClosed || input.serverManagedRun) {
|
|
9333
9944
|
return 0;
|
|
9334
9945
|
}
|
|
9335
|
-
return
|
|
9946
|
+
return 0;
|
|
9336
9947
|
}
|
|
9337
9948
|
function shouldBypassProviderSandboxOnPlatform(provider, platform) {
|
|
9338
9949
|
if (platform !== "darwin") {
|
|
@@ -9356,14 +9967,27 @@ function buildProviderArgs(provider, runtime, argv) {
|
|
|
9356
9967
|
}
|
|
9357
9968
|
if (provider === "pi") {
|
|
9358
9969
|
const piArgs = [...argv];
|
|
9970
|
+
if (piArgs.includes("__rig_pi_session_daemon__")) {
|
|
9971
|
+
return piArgs.filter((arg) => arg !== "__rig_pi_session_daemon__");
|
|
9972
|
+
}
|
|
9973
|
+
const piProvider = cliOptionValue(piArgs, "--provider") || process.env.RIG_PI_PROVIDER?.trim() || "openai-codex";
|
|
9359
9974
|
if (!hasCliOption(piArgs, "--provider")) {
|
|
9360
|
-
piArgs.unshift(
|
|
9975
|
+
piArgs.unshift(piProvider);
|
|
9361
9976
|
piArgs.unshift("--provider");
|
|
9362
9977
|
}
|
|
9363
|
-
|
|
9364
|
-
|
|
9978
|
+
const model = cliOptionValue(piArgs, "--model") || process.env.RIG_PI_MODEL?.trim() || "gpt-5.5";
|
|
9979
|
+
if (hasCliOption(piArgs, "--model")) {
|
|
9980
|
+
rewriteCliOptionValue(piArgs, "--model", normalizePiModelForProvider(model, piProvider));
|
|
9981
|
+
} else {
|
|
9982
|
+
piArgs.unshift(normalizePiModelForProvider(model, piProvider));
|
|
9365
9983
|
piArgs.unshift("--model");
|
|
9366
9984
|
}
|
|
9985
|
+
if (!hasCliOption(piArgs, "--mode")) {
|
|
9986
|
+
piArgs.push("--mode", process.env.RIG_PI_TRANSPORT?.trim() === "print" ? "json" : "rpc");
|
|
9987
|
+
if (process.env.RIG_PI_TRANSPORT?.trim() === "print" && !hasCliOption(piArgs, "--print")) {
|
|
9988
|
+
piArgs.push("--print");
|
|
9989
|
+
}
|
|
9990
|
+
}
|
|
9367
9991
|
return piArgs;
|
|
9368
9992
|
}
|
|
9369
9993
|
return [
|
|
@@ -9413,6 +10037,7 @@ async function runBeadsJson(projectRoot, args) {
|
|
|
9413
10037
|
return null;
|
|
9414
10038
|
}
|
|
9415
10039
|
}
|
|
10040
|
+
var warnedUnknownRuntimeAdapter = false;
|
|
9416
10041
|
function resolveProvider() {
|
|
9417
10042
|
const value = process.env.RIG_RUNTIME_ADAPTER?.trim().toLowerCase();
|
|
9418
10043
|
if (!value) {
|
|
@@ -9424,28 +10049,85 @@ function resolveProvider() {
|
|
|
9424
10049
|
if (value === "pi" || value === "rig-pi" || value === "@rig/pi") {
|
|
9425
10050
|
return "pi";
|
|
9426
10051
|
}
|
|
10052
|
+
if (value !== "claude-code" && value !== "claude" && !warnedUnknownRuntimeAdapter) {
|
|
10053
|
+
warnedUnknownRuntimeAdapter = true;
|
|
10054
|
+
console.warn(`[rig-agent] Unknown RIG_RUNTIME_ADAPTER value "${value}"; falling back to claude-code. Use pi|claude-code|codex.`);
|
|
10055
|
+
}
|
|
9427
10056
|
return "claude-code";
|
|
9428
10057
|
}
|
|
9429
10058
|
function hasCliOption(argv, option) {
|
|
9430
10059
|
return argv.some((arg) => arg === option || arg.startsWith(`${option}=`));
|
|
9431
10060
|
}
|
|
10061
|
+
function cliOptionValue(argv, option) {
|
|
10062
|
+
for (let index = 0;index < argv.length; index += 1) {
|
|
10063
|
+
const arg = argv[index];
|
|
10064
|
+
if (arg === option) {
|
|
10065
|
+
const next = argv[index + 1];
|
|
10066
|
+
return next && !next.startsWith("--") ? next : undefined;
|
|
10067
|
+
}
|
|
10068
|
+
if (arg?.startsWith(`${option}=`)) {
|
|
10069
|
+
return arg.slice(option.length + 1);
|
|
10070
|
+
}
|
|
10071
|
+
}
|
|
10072
|
+
return;
|
|
10073
|
+
}
|
|
10074
|
+
function rewriteCliOptionValue(argv, option, value) {
|
|
10075
|
+
for (let index = 0;index < argv.length; index += 1) {
|
|
10076
|
+
const arg = argv[index];
|
|
10077
|
+
if (arg === option && argv[index + 1] && !argv[index + 1].startsWith("--")) {
|
|
10078
|
+
argv[index + 1] = value;
|
|
10079
|
+
return;
|
|
10080
|
+
}
|
|
10081
|
+
if (arg?.startsWith(`${option}=`)) {
|
|
10082
|
+
argv[index] = `${option}=${value}`;
|
|
10083
|
+
return;
|
|
10084
|
+
}
|
|
10085
|
+
}
|
|
10086
|
+
}
|
|
10087
|
+
function normalizePiModelForProvider(model, provider) {
|
|
10088
|
+
if (provider === "openrouter" && model === "openai-codex/gpt-5.5") {
|
|
10089
|
+
return "openai/gpt-5.5";
|
|
10090
|
+
}
|
|
10091
|
+
return model;
|
|
10092
|
+
}
|
|
10093
|
+
function resolveFromShellPath(binary) {
|
|
10094
|
+
const resolved = Bun.spawnSync(["sh", "-lc", `command -v ${binary}`], {
|
|
10095
|
+
stdout: "pipe",
|
|
10096
|
+
stderr: "ignore",
|
|
10097
|
+
stdin: "ignore",
|
|
10098
|
+
env: process.env
|
|
10099
|
+
});
|
|
10100
|
+
if (resolved.exitCode !== 0)
|
|
10101
|
+
return null;
|
|
10102
|
+
const path = resolved.stdout.toString().trim().split(/\r?\n/)[0]?.trim();
|
|
10103
|
+
return path || null;
|
|
10104
|
+
}
|
|
10105
|
+
function resolveBundledPiBinary() {
|
|
10106
|
+
try {
|
|
10107
|
+
const packageJson = requireFromRuntime.resolve("@earendil-works/pi-coding-agent/package.json");
|
|
10108
|
+
const binaryPath = resolve37(packageJson, "..", "dist", "cli.js");
|
|
10109
|
+
return existsSync35(binaryPath) ? binaryPath : null;
|
|
10110
|
+
} catch {
|
|
10111
|
+
return null;
|
|
10112
|
+
}
|
|
10113
|
+
}
|
|
9432
10114
|
function providerBinary(provider) {
|
|
9433
10115
|
if (provider === "codex") {
|
|
9434
|
-
return Bun.which("codex") || "codex";
|
|
10116
|
+
return resolveFromShellPath("codex") || Bun.which("codex") || "codex";
|
|
9435
10117
|
}
|
|
9436
10118
|
if (provider === "pi") {
|
|
9437
|
-
return Bun.which("pi") || "pi";
|
|
10119
|
+
return process.env.RIG_PI_BINARY?.trim() || resolveBundledPiBinary() || resolveFromShellPath("pi") || Bun.which("pi") || "pi";
|
|
9438
10120
|
}
|
|
9439
10121
|
try {
|
|
9440
10122
|
return resolveClaudeBinaryPath();
|
|
9441
10123
|
} catch {
|
|
9442
|
-
return Bun.which("claude") || "claude";
|
|
10124
|
+
return resolveFromShellPath("claude") || Bun.which("claude") || "claude";
|
|
9443
10125
|
}
|
|
9444
10126
|
}
|
|
9445
10127
|
function emitWrapperEvent(type, payload) {
|
|
9446
10128
|
console.log(`__RIG_WRAPPER_EVENT__${JSON.stringify({ type, payload, at: new Date().toISOString() })}`);
|
|
9447
10129
|
}
|
|
9448
|
-
function
|
|
10130
|
+
function sleep2(ms) {
|
|
9449
10131
|
return new Promise((resolveSleep) => setTimeout(resolveSleep, ms));
|
|
9450
10132
|
}
|
|
9451
10133
|
async function waitForDirtyBaselineReady(runtime, taskId) {
|
|
@@ -9460,11 +10142,11 @@ async function waitForDirtyBaselineReady(runtime, taskId) {
|
|
|
9460
10142
|
workspaceDir: runtime.workspaceDir,
|
|
9461
10143
|
readyFile
|
|
9462
10144
|
});
|
|
9463
|
-
while (!
|
|
10145
|
+
while (!existsSync35(readyFile)) {
|
|
9464
10146
|
if (Date.now() >= deadline) {
|
|
9465
10147
|
throw new Error(`Timed out waiting for dirty baseline ready file: ${readyFile}`);
|
|
9466
10148
|
}
|
|
9467
|
-
await
|
|
10149
|
+
await sleep2(50);
|
|
9468
10150
|
}
|
|
9469
10151
|
emitWrapperEvent("runtime.baseline.completed", {
|
|
9470
10152
|
runtimeId: runtime.id,
|
|
@@ -9530,8 +10212,8 @@ async function readPluginTaskStatus(projectRoot, taskId) {
|
|
|
9530
10212
|
async function updateTaskSourceAfterRun(projectRoot, taskId, runtime) {
|
|
9531
10213
|
const comment = buildTaskRunLifecycleComment({
|
|
9532
10214
|
runId: process.env.RIG_SERVER_RUN_ID || "(unknown)",
|
|
9533
|
-
status: "
|
|
9534
|
-
summary: "Rig task run completed
|
|
10215
|
+
status: "completed",
|
|
10216
|
+
summary: "Rig task run completed; source closeout waits for approved PR merge.",
|
|
9535
10217
|
runtimeWorkspace: runtime.workspaceDir,
|
|
9536
10218
|
logsDir: runtime.logsDir,
|
|
9537
10219
|
sessionDir: runtime.sessionDir
|
|
@@ -9539,7 +10221,7 @@ async function updateTaskSourceAfterRun(projectRoot, taskId, runtime) {
|
|
|
9539
10221
|
try {
|
|
9540
10222
|
const result = await updateConfiguredTaskSourceTask(projectRoot, {
|
|
9541
10223
|
taskId,
|
|
9542
|
-
update: { status: "
|
|
10224
|
+
update: { status: "completed", comment }
|
|
9543
10225
|
});
|
|
9544
10226
|
if (result.updated) {
|
|
9545
10227
|
return;
|
|
@@ -9548,7 +10230,9 @@ async function updateTaskSourceAfterRun(projectRoot, taskId, runtime) {
|
|
|
9548
10230
|
} catch (error) {
|
|
9549
10231
|
let fallbackUpdated = false;
|
|
9550
10232
|
try {
|
|
9551
|
-
|
|
10233
|
+
const sourceIssueId = loadRuntimeContextFromEnv()?.sourceTask?.sourceIssueId;
|
|
10234
|
+
fallbackUpdated = updateGithubIssueTaskBySourceIssueId(sourceIssueId, taskId, { status: "completed", comment });
|
|
10235
|
+
fallbackUpdated = updateSourceAwareTaskConfigTask(projectRoot, taskId, { status: "completed", comment }) || fallbackUpdated;
|
|
9552
10236
|
} catch (fallbackError) {
|
|
9553
10237
|
console.error(`[rig-agent] Source-aware compatibility update also failed for ${taskId}: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`);
|
|
9554
10238
|
}
|
|
@@ -9561,9 +10245,9 @@ async function updateTaskSourceAfterRun(projectRoot, taskId, runtime) {
|
|
|
9561
10245
|
}
|
|
9562
10246
|
}
|
|
9563
10247
|
function recordRuntimeHandoff(hostProjectRoot, runtime, taskId, exitCode) {
|
|
9564
|
-
const handoffDir =
|
|
9565
|
-
|
|
9566
|
-
const handoffPath =
|
|
10248
|
+
const handoffDir = resolve37(hostProjectRoot, ".rig/runtime/handoffs");
|
|
10249
|
+
mkdirSync21(handoffDir, { recursive: true });
|
|
10250
|
+
const handoffPath = resolve37(handoffDir, `${taskId}-${Date.now()}.json`);
|
|
9567
10251
|
const handoff = {
|
|
9568
10252
|
taskId,
|
|
9569
10253
|
runtimeId: runtime.id,
|
|
@@ -9579,7 +10263,7 @@ function recordRuntimeHandoff(hostProjectRoot, runtime, taskId, exitCode) {
|
|
|
9579
10263
|
`rig git open-pr --task ${taskId}`
|
|
9580
10264
|
]
|
|
9581
10265
|
};
|
|
9582
|
-
|
|
10266
|
+
writeFileSync14(handoffPath, `${JSON.stringify(handoff, null, 2)}
|
|
9583
10267
|
`, "utf-8");
|
|
9584
10268
|
console.log(`[rig-agent] Completion verification paused for ${taskId}.`);
|
|
9585
10269
|
console.log(`[rig-agent] Runtime handoff saved: ${handoffPath}`);
|
|
@@ -9629,13 +10313,13 @@ async function readTaskMetadata2(taskRoot, taskId) {
|
|
|
9629
10313
|
async function readTaskConfigHints(taskRoot, taskId) {
|
|
9630
10314
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
9631
10315
|
const candidates = [
|
|
9632
|
-
runtimeContext?.monorepoMainRoot ?
|
|
9633
|
-
process.env.MONOREPO_MAIN_ROOT?.trim() ?
|
|
9634
|
-
|
|
9635
|
-
|
|
10316
|
+
runtimeContext?.monorepoMainRoot ? resolve37(runtimeContext.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
10317
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve37(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
10318
|
+
resolve37(taskRoot, ".rig", "task-config.json"),
|
|
10319
|
+
resolve37(taskRoot, "rig", "task-config.json")
|
|
9636
10320
|
].filter(Boolean);
|
|
9637
10321
|
for (const configPath of candidates) {
|
|
9638
|
-
if (!
|
|
10322
|
+
if (!existsSync35(configPath)) {
|
|
9639
10323
|
continue;
|
|
9640
10324
|
}
|
|
9641
10325
|
try {
|
|
@@ -9672,6 +10356,9 @@ export {
|
|
|
9672
10356
|
updateTaskSourceAfterRun,
|
|
9673
10357
|
startOptionalRuntimeSnapshotSidecar,
|
|
9674
10358
|
shouldBypassProviderSandboxOnPlatform,
|
|
10359
|
+
runPiSessionDaemonProvider,
|
|
10360
|
+
runPiRpcProviderFallback,
|
|
10361
|
+
runPiRpcProvider,
|
|
9675
10362
|
runAgentWrapper,
|
|
9676
10363
|
resolveTaskFromBeads,
|
|
9677
10364
|
resolveFinalProviderExitCode,
|