@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,34 +3006,6 @@ async function readSourceAwareTaskStatus(projectRoot, taskId, options = {}) {
|
|
|
2951
3006
|
return null;
|
|
2952
3007
|
}
|
|
2953
3008
|
}
|
|
2954
|
-
function updateSourceAwareTaskConfigTask(projectRoot, taskId, update, options = {}) {
|
|
2955
|
-
const configPath = options.configPath ?? resolve13(projectRoot, ".rig", "task-config.json");
|
|
2956
|
-
const rawEntry = readRawTaskEntry(configPath, taskId);
|
|
2957
|
-
if (!rawEntry) {
|
|
2958
|
-
const configuredFilesPath = readConfiguredFilesTaskSourcePath(projectRoot);
|
|
2959
|
-
return configuredFilesPath ? updateFileBackedTask(projectRoot, configuredFilesPath, taskId, update) : false;
|
|
2960
|
-
}
|
|
2961
|
-
const metadata = readMaterializedTaskMetadata(rawEntry);
|
|
2962
|
-
const source = metadata.taskSource;
|
|
2963
|
-
if (source?.kind === "github-issues") {
|
|
2964
|
-
applyGithubIssueUpdate(options.ghBinary ?? "gh", options.spawn ?? spawnSync, taskId, metadata, update);
|
|
2965
|
-
return true;
|
|
2966
|
-
}
|
|
2967
|
-
if (source?.kind === "files" && source.path) {
|
|
2968
|
-
return updateFileBackedTask(projectRoot, source.path, taskId, update);
|
|
2969
|
-
}
|
|
2970
|
-
if (source?.kind && source.kind !== "files" && source.kind !== "legacy-task-config") {
|
|
2971
|
-
return false;
|
|
2972
|
-
}
|
|
2973
|
-
if (!source && options.allowLocalTaskConfigStatusFallback === false) {
|
|
2974
|
-
return false;
|
|
2975
|
-
}
|
|
2976
|
-
if (typeof update.status !== "string" || update.status.trim().length === 0) {
|
|
2977
|
-
return false;
|
|
2978
|
-
}
|
|
2979
|
-
writeLegacyTaskStatus(configPath, taskId, update.status);
|
|
2980
|
-
return true;
|
|
2981
|
-
}
|
|
2982
3009
|
function readMaterializedTaskMetadata(entry) {
|
|
2983
3010
|
const rawRig = entry._rig;
|
|
2984
3011
|
if (!isPlainRecord2(rawRig)) {
|
|
@@ -3005,10 +3032,10 @@ function readMaterializedTaskMetadata(entry) {
|
|
|
3005
3032
|
return metadata;
|
|
3006
3033
|
}
|
|
3007
3034
|
function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
3008
|
-
const jsonPath =
|
|
3009
|
-
if (
|
|
3035
|
+
const jsonPath = resolve14(projectRoot, "rig.config.json");
|
|
3036
|
+
if (existsSync14(jsonPath)) {
|
|
3010
3037
|
try {
|
|
3011
|
-
const parsed = JSON.parse(
|
|
3038
|
+
const parsed = JSON.parse(readFileSync7(jsonPath, "utf8"));
|
|
3012
3039
|
if (isPlainRecord2(parsed) && isPlainRecord2(parsed.taskSource)) {
|
|
3013
3040
|
const source = parsed.taskSource;
|
|
3014
3041
|
return source.kind === "files" && typeof source.path === "string" ? source.path : null;
|
|
@@ -3017,12 +3044,12 @@ function readConfiguredFilesTaskSourcePath(projectRoot) {
|
|
|
3017
3044
|
return null;
|
|
3018
3045
|
}
|
|
3019
3046
|
}
|
|
3020
|
-
const tsPath =
|
|
3021
|
-
if (!
|
|
3047
|
+
const tsPath = resolve14(projectRoot, "rig.config.ts");
|
|
3048
|
+
if (!existsSync14(tsPath)) {
|
|
3022
3049
|
return null;
|
|
3023
3050
|
}
|
|
3024
3051
|
try {
|
|
3025
|
-
const source =
|
|
3052
|
+
const source = readFileSync7(tsPath, "utf8");
|
|
3026
3053
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
3027
3054
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
3028
3055
|
if (kind !== "files") {
|
|
@@ -3042,63 +3069,23 @@ function readRawTaskEntry(configPath, taskId) {
|
|
|
3042
3069
|
return isPlainRecord2(entry) ? entry : null;
|
|
3043
3070
|
}
|
|
3044
3071
|
function readRawTaskConfig(configPath) {
|
|
3045
|
-
if (!
|
|
3072
|
+
if (!existsSync14(configPath)) {
|
|
3046
3073
|
return null;
|
|
3047
3074
|
}
|
|
3048
|
-
const parsed = JSON.parse(
|
|
3075
|
+
const parsed = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
3049
3076
|
return isPlainRecord2(parsed) ? parsed : null;
|
|
3050
3077
|
}
|
|
3051
3078
|
function stripLegacyTaskConfigMetadata2(raw) {
|
|
3052
3079
|
const { validation_descriptions: _legacyDescriptions, _meta, ...tasks } = raw;
|
|
3053
3080
|
return tasks;
|
|
3054
3081
|
}
|
|
3055
|
-
function writeLegacyTaskStatus(configPath, taskId, status) {
|
|
3056
|
-
const rawConfig = readRawTaskConfig(configPath);
|
|
3057
|
-
if (!rawConfig) {
|
|
3058
|
-
return;
|
|
3059
|
-
}
|
|
3060
|
-
const entry = rawConfig[taskId];
|
|
3061
|
-
if (!isPlainRecord2(entry)) {
|
|
3062
|
-
return;
|
|
3063
|
-
}
|
|
3064
|
-
entry.status = status;
|
|
3065
|
-
writeFileSync5(configPath, `${JSON.stringify(rawConfig, null, 2)}
|
|
3066
|
-
`, "utf8");
|
|
3067
|
-
}
|
|
3068
|
-
function updateFileBackedTask(projectRoot, sourcePath, taskId, update) {
|
|
3069
|
-
const directory = resolve13(projectRoot, sourcePath);
|
|
3070
|
-
const file = findFileBackedTaskFile(directory, taskId);
|
|
3071
|
-
if (!file) {
|
|
3072
|
-
return false;
|
|
3073
|
-
}
|
|
3074
|
-
const raw = JSON.parse(readFileSync6(file, "utf8"));
|
|
3075
|
-
if (!isPlainRecord2(raw)) {
|
|
3076
|
-
return false;
|
|
3077
|
-
}
|
|
3078
|
-
if (update.status)
|
|
3079
|
-
raw.status = update.status;
|
|
3080
|
-
if (update.title !== undefined)
|
|
3081
|
-
raw.title = update.title;
|
|
3082
|
-
if (update.body !== undefined)
|
|
3083
|
-
raw.body = update.body;
|
|
3084
|
-
if (update.comment?.trim()) {
|
|
3085
|
-
const existing = Array.isArray(raw.comments) ? raw.comments : [];
|
|
3086
|
-
raw.comments = [
|
|
3087
|
-
...existing,
|
|
3088
|
-
{ body: update.comment, createdAt: new Date().toISOString(), source: "rig" }
|
|
3089
|
-
];
|
|
3090
|
-
}
|
|
3091
|
-
writeFileSync5(file, `${JSON.stringify(raw, null, 2)}
|
|
3092
|
-
`, "utf8");
|
|
3093
|
-
return true;
|
|
3094
|
-
}
|
|
3095
3082
|
function listFileBackedTasks(projectRoot, sourcePath) {
|
|
3096
|
-
const directory =
|
|
3097
|
-
if (!
|
|
3083
|
+
const directory = resolve14(projectRoot, sourcePath);
|
|
3084
|
+
if (!existsSync14(directory)) {
|
|
3098
3085
|
return [];
|
|
3099
3086
|
}
|
|
3100
3087
|
const tasks = [];
|
|
3101
|
-
for (const name of
|
|
3088
|
+
for (const name of readdirSync2(directory)) {
|
|
3102
3089
|
if (!FILE_TASK_PATTERN.test(name))
|
|
3103
3090
|
continue;
|
|
3104
3091
|
const inferredId = basename4(name).replace(FILE_TASK_PATTERN, "");
|
|
@@ -3109,11 +3096,11 @@ function listFileBackedTasks(projectRoot, sourcePath) {
|
|
|
3109
3096
|
return tasks;
|
|
3110
3097
|
}
|
|
3111
3098
|
function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
3112
|
-
const file = findFileBackedTaskFile(
|
|
3099
|
+
const file = findFileBackedTaskFile(resolve14(projectRoot, sourcePath), taskId);
|
|
3113
3100
|
if (!file) {
|
|
3114
3101
|
return null;
|
|
3115
3102
|
}
|
|
3116
|
-
const raw = JSON.parse(
|
|
3103
|
+
const raw = JSON.parse(readFileSync7(file, "utf8"));
|
|
3117
3104
|
if (!isPlainRecord2(raw)) {
|
|
3118
3105
|
return null;
|
|
3119
3106
|
}
|
|
@@ -3126,17 +3113,17 @@ function readFileBackedTask(projectRoot, sourcePath, taskId, rawEntry) {
|
|
|
3126
3113
|
};
|
|
3127
3114
|
}
|
|
3128
3115
|
function findFileBackedTaskFile(directory, taskId) {
|
|
3129
|
-
if (!
|
|
3116
|
+
if (!existsSync14(directory)) {
|
|
3130
3117
|
return null;
|
|
3131
3118
|
}
|
|
3132
|
-
for (const name of
|
|
3119
|
+
for (const name of readdirSync2(directory)) {
|
|
3133
3120
|
if (!FILE_TASK_PATTERN.test(name))
|
|
3134
3121
|
continue;
|
|
3135
3122
|
const file = join3(directory, name);
|
|
3136
3123
|
try {
|
|
3137
3124
|
if (!statSync3(file).isFile())
|
|
3138
3125
|
continue;
|
|
3139
|
-
const raw = JSON.parse(
|
|
3126
|
+
const raw = JSON.parse(readFileSync7(file, "utf8"));
|
|
3140
3127
|
const inferredId = basename4(file).replace(FILE_TASK_PATTERN, "");
|
|
3141
3128
|
const id = isPlainRecord2(raw) && typeof raw.id === "string" ? raw.id : inferredId;
|
|
3142
3129
|
if (id === taskId) {
|
|
@@ -3159,26 +3146,6 @@ function readGithubIssueTask(bin, spawnFn, id, metadata, rawEntry) {
|
|
|
3159
3146
|
], spawnFn);
|
|
3160
3147
|
return githubIssueToTask(issue, source, rawEntry);
|
|
3161
3148
|
}
|
|
3162
|
-
function applyGithubIssueUpdate(bin, spawnFn, id, metadata, update) {
|
|
3163
|
-
const source = requireGithubIssueSource(metadata, id);
|
|
3164
|
-
const repo = `${source.owner}/${source.repo}`;
|
|
3165
|
-
if (update.status) {
|
|
3166
|
-
applyGithubIssueStatus(bin, repo, spawnFn, id, update.status);
|
|
3167
|
-
}
|
|
3168
|
-
if (typeof update.comment === "string" && update.comment.trim().length > 0) {
|
|
3169
|
-
runGhVoid(bin, ["issue", "comment", String(id), "--repo", repo, "--body", update.comment], spawnFn);
|
|
3170
|
-
}
|
|
3171
|
-
const editArgs = ["issue", "edit", String(id), "--repo", repo];
|
|
3172
|
-
if (typeof update.title === "string" && update.title.trim().length > 0) {
|
|
3173
|
-
editArgs.push("--title", update.title.trim());
|
|
3174
|
-
}
|
|
3175
|
-
if (typeof update.body === "string") {
|
|
3176
|
-
editArgs.push("--body", update.body);
|
|
3177
|
-
}
|
|
3178
|
-
if (editArgs.length > 5) {
|
|
3179
|
-
runGhVoid(bin, editArgs, spawnFn);
|
|
3180
|
-
}
|
|
3181
|
-
}
|
|
3182
3149
|
function requireGithubIssueSource(metadata, id) {
|
|
3183
3150
|
const source = metadata.taskSource;
|
|
3184
3151
|
if (source?.kind === "github-issues" && source.owner && source.repo) {
|
|
@@ -3238,76 +3205,9 @@ function githubStatusFor(issue) {
|
|
|
3238
3205
|
return "cancelled";
|
|
3239
3206
|
return "open";
|
|
3240
3207
|
}
|
|
3241
|
-
function applyGithubIssueStatus(bin, repo, spawnFn, id, status) {
|
|
3242
|
-
if (status === "closed") {
|
|
3243
|
-
runGhVoid(bin, ["issue", "close", String(id), "--repo", repo], spawnFn);
|
|
3244
|
-
return;
|
|
3245
|
-
}
|
|
3246
|
-
const targetLabel = statusLabelFor(status);
|
|
3247
|
-
for (const label of STATUS_LABELS) {
|
|
3248
|
-
if (targetLabel !== null && label === targetLabel) {
|
|
3249
|
-
continue;
|
|
3250
|
-
}
|
|
3251
|
-
try {
|
|
3252
|
-
runGhVoid(bin, ["issue", "edit", String(id), "--repo", repo, "--remove-label", label], spawnFn);
|
|
3253
|
-
} catch {}
|
|
3254
|
-
}
|
|
3255
|
-
if (targetLabel !== null) {
|
|
3256
|
-
try {
|
|
3257
|
-
runGhVoid(bin, ["issue", "edit", String(id), "--repo", repo, "--add-label", targetLabel], spawnFn);
|
|
3258
|
-
} catch (error) {
|
|
3259
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
3260
|
-
if (!/not found/i.test(message)) {
|
|
3261
|
-
throw error;
|
|
3262
|
-
}
|
|
3263
|
-
ensureStatusLabel(bin, repo, spawnFn, targetLabel);
|
|
3264
|
-
runGhVoid(bin, ["issue", "edit", String(id), "--repo", repo, "--add-label", targetLabel], spawnFn);
|
|
3265
|
-
}
|
|
3266
|
-
}
|
|
3267
|
-
}
|
|
3268
|
-
function statusLabelFor(status) {
|
|
3269
|
-
switch (status) {
|
|
3270
|
-
case "in_progress":
|
|
3271
|
-
return "in-progress";
|
|
3272
|
-
case "blocked":
|
|
3273
|
-
return "blocked";
|
|
3274
|
-
case "ready":
|
|
3275
|
-
return "ready";
|
|
3276
|
-
case "under_review":
|
|
3277
|
-
return "under-review";
|
|
3278
|
-
case "failed":
|
|
3279
|
-
return "failed";
|
|
3280
|
-
case "cancelled":
|
|
3281
|
-
return "cancelled";
|
|
3282
|
-
case "open":
|
|
3283
|
-
return null;
|
|
3284
|
-
default:
|
|
3285
|
-
throw new Error(`unsupported status: ${status}`);
|
|
3286
|
-
}
|
|
3287
|
-
}
|
|
3288
|
-
function ensureStatusLabel(bin, repo, spawnFn, label) {
|
|
3289
|
-
try {
|
|
3290
|
-
runGhVoid(bin, [
|
|
3291
|
-
"label",
|
|
3292
|
-
"create",
|
|
3293
|
-
label,
|
|
3294
|
-
"--repo",
|
|
3295
|
-
repo,
|
|
3296
|
-
"--color",
|
|
3297
|
-
"6f42c1",
|
|
3298
|
-
"--description",
|
|
3299
|
-
"Task status managed by Rig"
|
|
3300
|
-
], spawnFn);
|
|
3301
|
-
} catch (error) {
|
|
3302
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
3303
|
-
if (!/already exists/i.test(message)) {
|
|
3304
|
-
throw error;
|
|
3305
|
-
}
|
|
3306
|
-
}
|
|
3307
|
-
}
|
|
3308
3208
|
function selectedGitHubEnv() {
|
|
3309
|
-
const token = process.env.RIG_GITHUB_SELECTED_TOKEN?.trim()
|
|
3310
|
-
return { GH_TOKEN: token, GITHUB_TOKEN: token };
|
|
3209
|
+
const token = process.env.RIG_GITHUB_SELECTED_TOKEN?.trim() || process.env.RIG_GITHUB_TOKEN?.trim() || "";
|
|
3210
|
+
return { GH_TOKEN: token, GITHUB_TOKEN: token, RIG_GITHUB_TOKEN: token };
|
|
3311
3211
|
}
|
|
3312
3212
|
function ghSpawnOptions() {
|
|
3313
3213
|
return { encoding: "utf-8", env: { ...process.env, ...selectedGitHubEnv() } };
|
|
@@ -3320,10 +3220,6 @@ function runGh(bin, args, spawnFn) {
|
|
|
3320
3220
|
}
|
|
3321
3221
|
return JSON.parse(res.stdout);
|
|
3322
3222
|
}
|
|
3323
|
-
function runGhVoid(bin, args, spawnFn) {
|
|
3324
|
-
const res = spawnFn(bin, [...args], ghSpawnOptions());
|
|
3325
|
-
assertGhSuccess(args, res);
|
|
3326
|
-
}
|
|
3327
3223
|
function assertGhSuccess(args, res) {
|
|
3328
3224
|
if (res.error) {
|
|
3329
3225
|
const msg = res.error.message ?? String(res.error);
|
|
@@ -3361,19 +3257,6 @@ function isPlainRecord2(candidate) {
|
|
|
3361
3257
|
function hasRunnableTaskSource(source) {
|
|
3362
3258
|
return Boolean(source && typeof source === "object" && !Array.isArray(source));
|
|
3363
3259
|
}
|
|
3364
|
-
function cleanString(value) {
|
|
3365
|
-
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
3366
|
-
}
|
|
3367
|
-
function taskIdFromSourceIssueId(value) {
|
|
3368
|
-
const raw = cleanString(value);
|
|
3369
|
-
if (!raw)
|
|
3370
|
-
return null;
|
|
3371
|
-
const issueNumber = raw.match(/#([^#\s]+)$/)?.[1];
|
|
3372
|
-
return issueNumber ?? raw;
|
|
3373
|
-
}
|
|
3374
|
-
function resolveSourceTaskId(taskId, sourceTask) {
|
|
3375
|
-
return cleanString(sourceTask?.id) ?? taskIdFromSourceIssueId(sourceTask?.sourceIssueId) ?? taskIdFromSourceIssueId(sourceTask?.source_issue_id) ?? taskId;
|
|
3376
|
-
}
|
|
3377
3260
|
async function getPluginTask(projectRoot, taskId) {
|
|
3378
3261
|
const ctx = await buildPluginHostContext(projectRoot);
|
|
3379
3262
|
const [source] = ctx?.taskSourceRegistry.list() ?? [];
|
|
@@ -3398,95 +3281,10 @@ async function readConfiguredTaskSourceTask(projectRoot, taskId) {
|
|
|
3398
3281
|
task
|
|
3399
3282
|
};
|
|
3400
3283
|
}
|
|
3401
|
-
async function updatePluginTaskSourceTask(projectRoot, taskId, update) {
|
|
3402
|
-
const ctx = await buildPluginHostContext(projectRoot);
|
|
3403
|
-
const [source] = ctx?.taskSourceRegistry.list() ?? [];
|
|
3404
|
-
if (!hasRunnableTaskSource(source)) {
|
|
3405
|
-
return ctx ? { taskId, updated: false, source: "none", sourceKind: null, status: null } : null;
|
|
3406
|
-
}
|
|
3407
|
-
if (source.updateTask) {
|
|
3408
|
-
await source.updateTask(taskId, update);
|
|
3409
|
-
} else if (update.status && source.updateStatus) {
|
|
3410
|
-
await source.updateStatus(taskId, update.status);
|
|
3411
|
-
} else {
|
|
3412
|
-
return {
|
|
3413
|
-
taskId,
|
|
3414
|
-
updated: false,
|
|
3415
|
-
source: "plugin",
|
|
3416
|
-
sourceKind: source.kind,
|
|
3417
|
-
status: null
|
|
3418
|
-
};
|
|
3419
|
-
}
|
|
3420
|
-
const status = source.get ? (await source.get(taskId))?.status ?? update.status ?? null : update.status ?? null;
|
|
3421
|
-
return {
|
|
3422
|
-
taskId,
|
|
3423
|
-
updated: true,
|
|
3424
|
-
source: "plugin",
|
|
3425
|
-
sourceKind: source.kind,
|
|
3426
|
-
status
|
|
3427
|
-
};
|
|
3428
|
-
}
|
|
3429
|
-
async function updateConfiguredTaskSourceTask(projectRoot, input) {
|
|
3430
|
-
const taskId = resolveSourceTaskId(input.taskId, input.sourceTask);
|
|
3431
|
-
let pluginResult = null;
|
|
3432
|
-
try {
|
|
3433
|
-
pluginResult = await updatePluginTaskSourceTask(projectRoot, taskId, input.update);
|
|
3434
|
-
} catch (error) {
|
|
3435
|
-
const fallbackUpdated = updateSourceAwareTaskConfigTask(projectRoot, taskId, input.update, {
|
|
3436
|
-
allowLocalTaskConfigStatusFallback: false
|
|
3437
|
-
});
|
|
3438
|
-
if (!fallbackUpdated) {
|
|
3439
|
-
throw error;
|
|
3440
|
-
}
|
|
3441
|
-
return {
|
|
3442
|
-
taskId,
|
|
3443
|
-
updated: true,
|
|
3444
|
-
source: "compat",
|
|
3445
|
-
sourceKind: null,
|
|
3446
|
-
status: await readSourceAwareTaskStatus(projectRoot, taskId)
|
|
3447
|
-
};
|
|
3448
|
-
}
|
|
3449
|
-
if (pluginResult) {
|
|
3450
|
-
return pluginResult;
|
|
3451
|
-
}
|
|
3452
|
-
const updated = updateSourceAwareTaskConfigTask(projectRoot, taskId, input.update);
|
|
3453
|
-
return {
|
|
3454
|
-
taskId,
|
|
3455
|
-
updated,
|
|
3456
|
-
source: updated ? "compat" : "none",
|
|
3457
|
-
sourceKind: null,
|
|
3458
|
-
status: await readSourceAwareTaskStatus(projectRoot, taskId)
|
|
3459
|
-
};
|
|
3460
|
-
}
|
|
3461
|
-
function buildTaskRunLifecycleComment(input) {
|
|
3462
|
-
const lines = [
|
|
3463
|
-
"<!-- rig:status-comment -->",
|
|
3464
|
-
`### Rig status: ${input.status}`,
|
|
3465
|
-
"",
|
|
3466
|
-
input.summary,
|
|
3467
|
-
"",
|
|
3468
|
-
`- Run: ${input.runId}`,
|
|
3469
|
-
`- Status: ${input.status}`
|
|
3470
|
-
];
|
|
3471
|
-
if (input.errorText?.trim()) {
|
|
3472
|
-
lines.push(`- Error: ${input.errorText.trim()}`);
|
|
3473
|
-
}
|
|
3474
|
-
if (input.runtimeWorkspace?.trim()) {
|
|
3475
|
-
lines.push(`- Runtime workspace: ${input.runtimeWorkspace.trim()}`);
|
|
3476
|
-
}
|
|
3477
|
-
if (input.logsDir?.trim()) {
|
|
3478
|
-
lines.push(`- Logs: ${input.logsDir.trim()}`);
|
|
3479
|
-
}
|
|
3480
|
-
if (input.sessionDir?.trim()) {
|
|
3481
|
-
lines.push(`- Session: ${input.sessionDir.trim()}`);
|
|
3482
|
-
}
|
|
3483
|
-
return lines.join(`
|
|
3484
|
-
`);
|
|
3485
|
-
}
|
|
3486
3284
|
|
|
3487
3285
|
// packages/runtime/src/control-plane/native/task-state.ts
|
|
3488
|
-
import { existsSync as
|
|
3489
|
-
import { basename as basename6, resolve as
|
|
3286
|
+
import { existsSync as existsSync18, readFileSync as readFileSync9, readdirSync as readdirSync3, statSync as statSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
3287
|
+
import { basename as basename6, resolve as resolve18 } from "path";
|
|
3490
3288
|
|
|
3491
3289
|
// packages/runtime/src/control-plane/state-sync/types.ts
|
|
3492
3290
|
var SUPPORTED_TASK_STATE_SCHEMA_VERSION = 1;
|
|
@@ -3594,39 +3392,39 @@ function readTaskStateMetadataEnvelope(raw) {
|
|
|
3594
3392
|
};
|
|
3595
3393
|
}
|
|
3596
3394
|
// packages/runtime/src/control-plane/state-sync/read.ts
|
|
3597
|
-
import { existsSync as
|
|
3598
|
-
import { resolve as
|
|
3395
|
+
import { existsSync as existsSync17, readFileSync as readFileSync8 } from "fs";
|
|
3396
|
+
import { resolve as resolve17 } from "path";
|
|
3599
3397
|
|
|
3600
3398
|
// packages/runtime/src/control-plane/state-sync/repo.ts
|
|
3601
|
-
import { existsSync as
|
|
3602
|
-
import { resolve as
|
|
3399
|
+
import { existsSync as existsSync16 } from "fs";
|
|
3400
|
+
import { resolve as resolve16 } from "path";
|
|
3603
3401
|
|
|
3604
3402
|
// packages/runtime/src/control-plane/repos/layout.ts
|
|
3605
3403
|
init_layout();
|
|
3606
|
-
import { existsSync as
|
|
3607
|
-
import { basename as basename5, dirname as dirname9, join as join4, resolve as
|
|
3404
|
+
import { existsSync as existsSync15 } from "fs";
|
|
3405
|
+
import { basename as basename5, dirname as dirname9, join as join4, resolve as resolve15 } from "path";
|
|
3608
3406
|
function resolveRepoStateDir(projectRoot) {
|
|
3609
|
-
const normalizedProjectRoot =
|
|
3407
|
+
const normalizedProjectRoot = resolve15(projectRoot);
|
|
3610
3408
|
const projectParent = dirname9(normalizedProjectRoot);
|
|
3611
3409
|
if (basename5(projectParent) === ".worktrees") {
|
|
3612
3410
|
const ownerRoot = dirname9(projectParent);
|
|
3613
|
-
const ownerHasRepoMarkers =
|
|
3411
|
+
const ownerHasRepoMarkers = existsSync15(resolve15(ownerRoot, ".git")) || existsSync15(resolve15(ownerRoot, ".rig", "state"));
|
|
3614
3412
|
if (ownerHasRepoMarkers) {
|
|
3615
|
-
return
|
|
3413
|
+
return resolve15(ownerRoot, ".rig", "state");
|
|
3616
3414
|
}
|
|
3617
3415
|
}
|
|
3618
|
-
return
|
|
3416
|
+
return resolve15(projectRoot, ".rig", "state");
|
|
3619
3417
|
}
|
|
3620
3418
|
function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
3621
|
-
const normalizedProjectRoot =
|
|
3419
|
+
const normalizedProjectRoot = resolve15(projectRoot);
|
|
3622
3420
|
const entry = getManagedRepoEntry(repoId);
|
|
3623
3421
|
const stateDir = resolveRepoStateDir(normalizedProjectRoot);
|
|
3624
3422
|
const metadataRelativePath = join4("repos", entry.id);
|
|
3625
|
-
const metadataRoot =
|
|
3423
|
+
const metadataRoot = resolve15(stateDir, metadataRelativePath);
|
|
3626
3424
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
3627
|
-
const runsInsideTaskWorktree = runtimeWorkspace &&
|
|
3425
|
+
const runsInsideTaskWorktree = runtimeWorkspace && resolve15(runtimeWorkspace) === normalizedProjectRoot || basename5(dirname9(normalizedProjectRoot)) === ".worktrees";
|
|
3628
3426
|
const isPrimaryManagedRepo = listManagedRepoEntries()[0]?.id === repoId;
|
|
3629
|
-
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ?
|
|
3427
|
+
const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ? resolve15(process.env[entry.checkoutEnvVar].trim()) : resolve15(normalizedProjectRoot, entry.alias);
|
|
3630
3428
|
return {
|
|
3631
3429
|
projectRoot: normalizedProjectRoot,
|
|
3632
3430
|
repoId: entry.id,
|
|
@@ -3634,12 +3432,12 @@ function resolveManagedRepoLayout(projectRoot, repoId) {
|
|
|
3634
3432
|
defaultBranch: entry.defaultBranch,
|
|
3635
3433
|
remoteUrl: entry.remoteEnvVar && process.env[entry.remoteEnvVar]?.trim() ? process.env[entry.remoteEnvVar].trim() : entry.defaultRemoteUrl,
|
|
3636
3434
|
checkoutRoot,
|
|
3637
|
-
worktreesRoot:
|
|
3435
|
+
worktreesRoot: resolve15(checkoutRoot, ".worktrees"),
|
|
3638
3436
|
stateDir,
|
|
3639
3437
|
metadataRoot,
|
|
3640
3438
|
metadataRelativePath,
|
|
3641
|
-
mirrorRoot:
|
|
3642
|
-
mirrorStatePath:
|
|
3439
|
+
mirrorRoot: resolve15(metadataRoot, "mirror.git"),
|
|
3440
|
+
mirrorStatePath: resolve15(metadataRoot, "mirror-state.json"),
|
|
3643
3441
|
mirrorStateRelativePath: join4(metadataRelativePath, "mirror-state.json")
|
|
3644
3442
|
};
|
|
3645
3443
|
}
|
|
@@ -3657,7 +3455,7 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
3657
3455
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
3658
3456
|
try {
|
|
3659
3457
|
const layout = resolveMonorepoRepoLayout(projectRoot);
|
|
3660
|
-
if (
|
|
3458
|
+
if (existsSync16(resolve16(layout.mirrorRoot, "HEAD"))) {
|
|
3661
3459
|
return layout.mirrorRoot;
|
|
3662
3460
|
}
|
|
3663
3461
|
} catch {}
|
|
@@ -3668,8 +3466,8 @@ function resolveTrackerRepoPath(projectRoot) {
|
|
|
3668
3466
|
var DEFAULT_READ_DEPS2 = {
|
|
3669
3467
|
fetchRef: nativeFetchRef,
|
|
3670
3468
|
readBlobAtRef: nativeReadBlobAtRef,
|
|
3671
|
-
exists:
|
|
3672
|
-
readFile: (path) =>
|
|
3469
|
+
exists: existsSync17,
|
|
3470
|
+
readFile: (path) => readFileSync8(path, "utf8")
|
|
3673
3471
|
};
|
|
3674
3472
|
function parseIssueStatus(rawStatus) {
|
|
3675
3473
|
const normalized = normalizeTaskLifecycleStatus(rawStatus);
|
|
@@ -3750,12 +3548,12 @@ function shouldPreferLocalTrackerState(options) {
|
|
|
3750
3548
|
if (runtimeContextPath) {
|
|
3751
3549
|
return true;
|
|
3752
3550
|
}
|
|
3753
|
-
return
|
|
3551
|
+
return existsSync17(resolve17(runtimeWorkspace, ".rig", "runtime-context.json"));
|
|
3754
3552
|
}
|
|
3755
3553
|
function readLocalTrackerState(projectRoot, deps) {
|
|
3756
3554
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
3757
|
-
const issuesPath =
|
|
3758
|
-
const taskStatePath =
|
|
3555
|
+
const issuesPath = resolve17(monorepoRoot, ".beads", "issues.jsonl");
|
|
3556
|
+
const taskStatePath = resolve17(monorepoRoot, ".beads", "task-state.json");
|
|
3759
3557
|
return projectSyncedTrackerSnapshot({
|
|
3760
3558
|
source: "local",
|
|
3761
3559
|
issuesBaseOid: null,
|
|
@@ -3817,7 +3615,7 @@ function readValidationDescriptions(projectRoot) {
|
|
|
3817
3615
|
return readValidationDescriptionMap(raw);
|
|
3818
3616
|
}
|
|
3819
3617
|
function readSourceValidationDescriptions(projectRoot) {
|
|
3820
|
-
const rootRaw = readJsonFile(
|
|
3618
|
+
const rootRaw = readJsonFile(resolve18(projectRoot, "rig", "task-config.json"), {});
|
|
3821
3619
|
const sourcePath = findSourceTaskConfigPath(projectRoot);
|
|
3822
3620
|
const sourceRaw = sourcePath ? readJsonFile(sourcePath, {}) : {};
|
|
3823
3621
|
const rootDescriptions = readValidationDescriptionMap(rootRaw);
|
|
@@ -3893,15 +3691,15 @@ function readValidationDescriptionsFromMeta(meta) {
|
|
|
3893
3691
|
return meta.validation_descriptions;
|
|
3894
3692
|
}
|
|
3895
3693
|
function readLocalSourceTaskStateEnvelope(projectRoot) {
|
|
3896
|
-
const taskStatePath =
|
|
3694
|
+
const taskStatePath = resolve18(resolveMonorepoRoot2(projectRoot), ".beads", "task-state.json");
|
|
3897
3695
|
return readTaskStateMetadataEnvelope(readJsonFile(taskStatePath, {}));
|
|
3898
3696
|
}
|
|
3899
3697
|
function readLocalSourceTaskLifecycleStatus(projectRoot, taskId) {
|
|
3900
|
-
const issuesPath =
|
|
3901
|
-
if (!
|
|
3698
|
+
const issuesPath = resolve18(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
3699
|
+
if (!existsSync18(issuesPath)) {
|
|
3902
3700
|
return null;
|
|
3903
3701
|
}
|
|
3904
|
-
for (const line of
|
|
3702
|
+
for (const line of readFileSync9(issuesPath, "utf8").split(/\r?\n/)) {
|
|
3905
3703
|
const trimmed = line.trim();
|
|
3906
3704
|
if (!trimmed) {
|
|
3907
3705
|
continue;
|
|
@@ -3926,25 +3724,25 @@ function inferTaskIdFromRuntimePath(path) {
|
|
|
3926
3724
|
function artifactDirForId(projectRoot, id) {
|
|
3927
3725
|
const workspaceDir = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
3928
3726
|
if (workspaceDir) {
|
|
3929
|
-
const worktreeArtifacts =
|
|
3930
|
-
if (
|
|
3727
|
+
const worktreeArtifacts = resolve18(workspaceDir, "artifacts", id);
|
|
3728
|
+
if (existsSync18(worktreeArtifacts) || existsSync18(resolve18(workspaceDir, "artifacts"))) {
|
|
3931
3729
|
return worktreeArtifacts;
|
|
3932
3730
|
}
|
|
3933
3731
|
}
|
|
3934
3732
|
try {
|
|
3935
3733
|
const paths = resolveHarnessPaths(projectRoot);
|
|
3936
|
-
return
|
|
3734
|
+
return resolve18(paths.artifactsDir, id);
|
|
3937
3735
|
} catch {
|
|
3938
|
-
return
|
|
3736
|
+
return resolve18(resolveMonorepoRoot2(projectRoot), "artifacts", id);
|
|
3939
3737
|
}
|
|
3940
3738
|
}
|
|
3941
3739
|
function resolveTaskConfigPath(projectRoot) {
|
|
3942
3740
|
const paths = resolveHarnessPaths(projectRoot);
|
|
3943
|
-
if (
|
|
3741
|
+
if (existsSync18(paths.taskConfigPath)) {
|
|
3944
3742
|
return paths.taskConfigPath;
|
|
3945
3743
|
}
|
|
3946
3744
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
3947
|
-
if (
|
|
3745
|
+
if (existsSync18(candidate)) {
|
|
3948
3746
|
return candidate;
|
|
3949
3747
|
}
|
|
3950
3748
|
}
|
|
@@ -3952,7 +3750,7 @@ function resolveTaskConfigPath(projectRoot) {
|
|
|
3952
3750
|
}
|
|
3953
3751
|
function findSourceTaskConfigPath(projectRoot) {
|
|
3954
3752
|
for (const candidate of sourceTaskConfigCandidates(projectRoot)) {
|
|
3955
|
-
if (
|
|
3753
|
+
if (existsSync18(candidate)) {
|
|
3956
3754
|
return candidate;
|
|
3957
3755
|
}
|
|
3958
3756
|
}
|
|
@@ -3965,7 +3763,7 @@ function readAndSyncSourceTaskConfig(projectRoot) {
|
|
|
3965
3763
|
const synced = synchronizeTaskConfigWithTracker(projectRoot, raw);
|
|
3966
3764
|
if (sourcePath && synced.updated) {
|
|
3967
3765
|
try {
|
|
3968
|
-
|
|
3766
|
+
writeFileSync7(sourcePath, `${JSON.stringify(synced.config, null, 2)}
|
|
3969
3767
|
`, "utf-8");
|
|
3970
3768
|
} catch {}
|
|
3971
3769
|
}
|
|
@@ -4017,12 +3815,12 @@ function shouldRefreshAutoSyncedTaskConfigEntry(entry) {
|
|
|
4017
3815
|
return !candidate.role;
|
|
4018
3816
|
}
|
|
4019
3817
|
function readSourceIssueRecords(projectRoot) {
|
|
4020
|
-
const issuesPath =
|
|
4021
|
-
if (!
|
|
3818
|
+
const issuesPath = resolve18(resolveMonorepoRoot2(projectRoot), ".beads", "issues.jsonl");
|
|
3819
|
+
if (!existsSync18(issuesPath)) {
|
|
4022
3820
|
return [];
|
|
4023
3821
|
}
|
|
4024
3822
|
const records = [];
|
|
4025
|
-
for (const line of
|
|
3823
|
+
for (const line of readFileSync9(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
4026
3824
|
const trimmed = line.trim();
|
|
4027
3825
|
if (!trimmed) {
|
|
4028
3826
|
continue;
|
|
@@ -4078,19 +3876,19 @@ function readConfiguredFileTaskConfig(projectRoot) {
|
|
|
4078
3876
|
if (!sourcePath) {
|
|
4079
3877
|
return {};
|
|
4080
3878
|
}
|
|
4081
|
-
const directory =
|
|
4082
|
-
if (!
|
|
3879
|
+
const directory = resolve18(projectRoot, sourcePath);
|
|
3880
|
+
if (!existsSync18(directory)) {
|
|
4083
3881
|
return {};
|
|
4084
3882
|
}
|
|
4085
3883
|
const config = {};
|
|
4086
|
-
for (const name of
|
|
3884
|
+
for (const name of readdirSync3(directory)) {
|
|
4087
3885
|
if (!FILE_TASK_PATTERN2.test(name))
|
|
4088
3886
|
continue;
|
|
4089
|
-
const file =
|
|
3887
|
+
const file = resolve18(directory, name);
|
|
4090
3888
|
try {
|
|
4091
3889
|
if (!statSync4(file).isFile())
|
|
4092
3890
|
continue;
|
|
4093
|
-
const raw = JSON.parse(
|
|
3891
|
+
const raw = JSON.parse(readFileSync9(file, "utf8"));
|
|
4094
3892
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
4095
3893
|
continue;
|
|
4096
3894
|
const record = raw;
|
|
@@ -4132,10 +3930,10 @@ function firstStringList2(...candidates) {
|
|
|
4132
3930
|
return [];
|
|
4133
3931
|
}
|
|
4134
3932
|
function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
4135
|
-
const jsonPath =
|
|
4136
|
-
if (
|
|
3933
|
+
const jsonPath = resolve18(projectRoot, "rig.config.json");
|
|
3934
|
+
if (existsSync18(jsonPath)) {
|
|
4137
3935
|
try {
|
|
4138
|
-
const parsed = JSON.parse(
|
|
3936
|
+
const parsed = JSON.parse(readFileSync9(jsonPath, "utf8"));
|
|
4139
3937
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
4140
3938
|
const taskSource = parsed.taskSource;
|
|
4141
3939
|
if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
|
|
@@ -4147,12 +3945,12 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
4147
3945
|
return null;
|
|
4148
3946
|
}
|
|
4149
3947
|
}
|
|
4150
|
-
const tsPath =
|
|
4151
|
-
if (!
|
|
3948
|
+
const tsPath = resolve18(projectRoot, "rig.config.ts");
|
|
3949
|
+
if (!existsSync18(tsPath)) {
|
|
4152
3950
|
return null;
|
|
4153
3951
|
}
|
|
4154
3952
|
try {
|
|
4155
|
-
const source =
|
|
3953
|
+
const source = readFileSync9(tsPath, "utf8");
|
|
4156
3954
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
4157
3955
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
4158
3956
|
if (kind !== "files") {
|
|
@@ -4166,9 +3964,9 @@ function readConfiguredFilesTaskSourcePath2(projectRoot) {
|
|
|
4166
3964
|
function sourceTaskConfigCandidates(projectRoot) {
|
|
4167
3965
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
4168
3966
|
return [
|
|
4169
|
-
runtimeContext?.monorepoMainRoot ?
|
|
4170
|
-
process.env.MONOREPO_MAIN_ROOT?.trim() ?
|
|
4171
|
-
|
|
3967
|
+
runtimeContext?.monorepoMainRoot ? resolve18(runtimeContext.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
3968
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve18(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
3969
|
+
resolve18(resolveMonorepoRoot2(projectRoot), ".rig", "task-config.json")
|
|
4172
3970
|
].filter(Boolean);
|
|
4173
3971
|
}
|
|
4174
3972
|
|
|
@@ -4177,8 +3975,8 @@ init_layout();
|
|
|
4177
3975
|
|
|
4178
3976
|
// packages/runtime/src/binary-run.ts
|
|
4179
3977
|
init_layout();
|
|
4180
|
-
import { chmodSync as chmodSync4, cpSync, existsSync as
|
|
4181
|
-
import { basename as basename7, dirname as dirname10, resolve as
|
|
3978
|
+
import { chmodSync as chmodSync4, cpSync, existsSync as existsSync19, mkdirSync as mkdirSync9, renameSync as renameSync3, rmSync as rmSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
3979
|
+
import { basename as basename7, dirname as dirname10, resolve as resolve19 } from "path";
|
|
4182
3980
|
import { fileURLToPath } from "url";
|
|
4183
3981
|
import { drainMicrotasks, gcAndSweep } from "bun:jsc";
|
|
4184
3982
|
var runtimeBinaryBuildQueue = Promise.resolve();
|
|
@@ -4204,9 +4002,9 @@ async function buildRuntimeBinary(options) {
|
|
|
4204
4002
|
});
|
|
4205
4003
|
}
|
|
4206
4004
|
async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
4207
|
-
const tempBuildDir =
|
|
4208
|
-
const tempOutputPath =
|
|
4209
|
-
|
|
4005
|
+
const tempBuildDir = resolve19(dirname10(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
4006
|
+
const tempOutputPath = resolve19(tempBuildDir, basename7(options.outputPath));
|
|
4007
|
+
mkdirSync9(tempBuildDir, { recursive: true });
|
|
4210
4008
|
await withTemporaryEnv({
|
|
4211
4009
|
...options.env,
|
|
4212
4010
|
...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
|
|
@@ -4231,7 +4029,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
4231
4029
|
`);
|
|
4232
4030
|
throw new Error(`Failed to build ${options.entrypoint}: ${details || "Bun.build() returned errors"}`);
|
|
4233
4031
|
}
|
|
4234
|
-
if (!
|
|
4032
|
+
if (!existsSync19(tempOutputPath)) {
|
|
4235
4033
|
const emitted = buildResult.outputs.map((output) => output.path).join(", ") || "(none)";
|
|
4236
4034
|
throw new Error(`Failed to build ${options.entrypoint}: Bun.build() did not emit ${tempOutputPath}. Emitted: ${emitted}`);
|
|
4237
4035
|
}
|
|
@@ -4246,7 +4044,7 @@ async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
|
4246
4044
|
});
|
|
4247
4045
|
}
|
|
4248
4046
|
})).finally(() => {
|
|
4249
|
-
|
|
4047
|
+
rmSync8(tempBuildDir, { recursive: true, force: true });
|
|
4250
4048
|
});
|
|
4251
4049
|
}
|
|
4252
4050
|
function runBestEffortBuildGc() {
|
|
@@ -4263,8 +4061,8 @@ function runtimeBinaryCacheManifestPath(outputPath) {
|
|
|
4263
4061
|
function resolveRuntimeBinaryBuildOptions(options) {
|
|
4264
4062
|
return {
|
|
4265
4063
|
...options,
|
|
4266
|
-
entrypoint:
|
|
4267
|
-
outputPath:
|
|
4064
|
+
entrypoint: resolve19(options.cwd, options.sourcePath),
|
|
4065
|
+
outputPath: resolve19(options.outputPath)
|
|
4268
4066
|
};
|
|
4269
4067
|
}
|
|
4270
4068
|
function shouldUseRuntimeBinaryBuildWorker() {
|
|
@@ -4278,7 +4076,7 @@ function shouldUseRuntimeBinaryBuildWorker() {
|
|
|
4278
4076
|
}
|
|
4279
4077
|
async function buildRuntimeBinaryViaWorker(options) {
|
|
4280
4078
|
const workerSourcePath = resolveRuntimeBinaryBuildWorkerSourcePath(options);
|
|
4281
|
-
if (!workerSourcePath || !
|
|
4079
|
+
if (!workerSourcePath || !existsSync19(workerSourcePath)) {
|
|
4282
4080
|
await buildRuntimeBinaryInProcess(options, {
|
|
4283
4081
|
manifestPath: runtimeBinaryCacheManifestPath(options.outputPath),
|
|
4284
4082
|
buildKey: createRuntimeBinaryBuildKey({
|
|
@@ -4309,13 +4107,13 @@ async function buildRuntimeBinaryViaWorker(options) {
|
|
|
4309
4107
|
new Response(build.stdout).text(),
|
|
4310
4108
|
new Response(build.stderr).text()
|
|
4311
4109
|
]);
|
|
4312
|
-
|
|
4110
|
+
rmSync8(payloadPath, { force: true });
|
|
4313
4111
|
if (exitCode !== 0) {
|
|
4314
4112
|
throw new Error(`Failed to build ${options.entrypoint}: ${(stderr || stdout || `worker exited ${exitCode}`).trim()}`);
|
|
4315
4113
|
}
|
|
4316
4114
|
}
|
|
4317
4115
|
function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
|
|
4318
|
-
return
|
|
4116
|
+
return resolve19(dirname10(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
4319
4117
|
}
|
|
4320
4118
|
function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
4321
4119
|
const envRoots = [
|
|
@@ -4324,13 +4122,13 @@ function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
|
4324
4122
|
process.env.PROJECT_RIG_ROOT?.trim()
|
|
4325
4123
|
].filter(Boolean);
|
|
4326
4124
|
for (const root of envRoots) {
|
|
4327
|
-
const candidate =
|
|
4328
|
-
if (
|
|
4125
|
+
const candidate = resolve19(root, "packages/runtime/src/binary-build-worker.ts");
|
|
4126
|
+
if (existsSync19(candidate)) {
|
|
4329
4127
|
return candidate;
|
|
4330
4128
|
}
|
|
4331
4129
|
}
|
|
4332
|
-
const localCandidate =
|
|
4333
|
-
return
|
|
4130
|
+
const localCandidate = resolve19(import.meta.dir, "binary-build-worker.ts");
|
|
4131
|
+
return existsSync19(localCandidate) ? localCandidate : null;
|
|
4334
4132
|
}
|
|
4335
4133
|
function resolveRuntimeBinaryBuildWorkerInvocation() {
|
|
4336
4134
|
const bunPath = Bun.which("bun");
|
|
@@ -4366,7 +4164,7 @@ function createRuntimeBinaryBuildKey(input) {
|
|
|
4366
4164
|
});
|
|
4367
4165
|
}
|
|
4368
4166
|
async function isRuntimeBinaryBuildFresh(input) {
|
|
4369
|
-
if (!
|
|
4167
|
+
if (!existsSync19(input.outputPath) || !existsSync19(input.manifestPath)) {
|
|
4370
4168
|
return false;
|
|
4371
4169
|
}
|
|
4372
4170
|
let manifest = null;
|
|
@@ -4379,7 +4177,7 @@ async function isRuntimeBinaryBuildFresh(input) {
|
|
|
4379
4177
|
return false;
|
|
4380
4178
|
}
|
|
4381
4179
|
for (const [filePath, expectedDigest] of Object.entries(manifest.inputs || {})) {
|
|
4382
|
-
if (!
|
|
4180
|
+
if (!existsSync19(filePath)) {
|
|
4383
4181
|
return false;
|
|
4384
4182
|
}
|
|
4385
4183
|
if (await sha256File4(filePath) !== expectedDigest) {
|
|
@@ -4392,7 +4190,7 @@ async function writeRuntimeBinaryCacheManifest(input) {
|
|
|
4392
4190
|
const inputs = {};
|
|
4393
4191
|
for (const inputPath of Object.keys(input.metafile?.inputs || {}).sort()) {
|
|
4394
4192
|
const normalized = normalizeBuildInputPath(input.cwd, inputPath);
|
|
4395
|
-
if (!normalized || !
|
|
4193
|
+
if (!normalized || !existsSync19(normalized)) {
|
|
4396
4194
|
continue;
|
|
4397
4195
|
}
|
|
4398
4196
|
inputs[normalized] = await sha256File4(normalized);
|
|
@@ -4415,7 +4213,7 @@ function normalizeBuildInputPath(cwd, inputPath) {
|
|
|
4415
4213
|
if (inputPath.startsWith("<")) {
|
|
4416
4214
|
return null;
|
|
4417
4215
|
}
|
|
4418
|
-
return
|
|
4216
|
+
return resolve19(cwd, inputPath);
|
|
4419
4217
|
}
|
|
4420
4218
|
async function sha256File4(path) {
|
|
4421
4219
|
const hasher = new Bun.CryptoHasher("sha256");
|
|
@@ -4431,8 +4229,8 @@ function sortRecord(value) {
|
|
|
4431
4229
|
async function runSerializedRuntimeBinaryBuild(action) {
|
|
4432
4230
|
const previous = runtimeBinaryBuildQueue;
|
|
4433
4231
|
let release;
|
|
4434
|
-
runtimeBinaryBuildQueue = new Promise((
|
|
4435
|
-
release =
|
|
4232
|
+
runtimeBinaryBuildQueue = new Promise((resolve20) => {
|
|
4233
|
+
release = resolve20;
|
|
4436
4234
|
});
|
|
4437
4235
|
await previous;
|
|
4438
4236
|
try {
|
|
@@ -4477,11 +4275,11 @@ async function withTemporaryCwd(cwd, action) {
|
|
|
4477
4275
|
}
|
|
4478
4276
|
|
|
4479
4277
|
// packages/runtime/src/control-plane/runtime/provisioning-env.ts
|
|
4480
|
-
import { delimiter, resolve as
|
|
4278
|
+
import { delimiter, resolve as resolve22 } from "path";
|
|
4481
4279
|
|
|
4482
4280
|
// packages/runtime/src/control-plane/runtime/runtime-paths.ts
|
|
4483
|
-
import { existsSync as
|
|
4484
|
-
import { resolve as
|
|
4281
|
+
import { existsSync as existsSync21, readdirSync as readdirSync5, realpathSync as realpathSync2 } from "fs";
|
|
4282
|
+
import { resolve as resolve21 } from "path";
|
|
4485
4283
|
|
|
4486
4284
|
// packages/runtime/src/control-plane/runtime/sandbox-utils.ts
|
|
4487
4285
|
init_utils();
|
|
@@ -4498,7 +4296,7 @@ function resolveBunBinaryPath() {
|
|
|
4498
4296
|
}
|
|
4499
4297
|
const home = process.env.HOME?.trim();
|
|
4500
4298
|
const fallbackCandidates = [
|
|
4501
|
-
home ?
|
|
4299
|
+
home ? resolve21(home, ".bun/bin/bun") : "",
|
|
4502
4300
|
"/opt/homebrew/bin/bun",
|
|
4503
4301
|
"/usr/local/bin/bun",
|
|
4504
4302
|
"/usr/bin/bun"
|
|
@@ -4526,8 +4324,8 @@ function resolveClaudeBinaryPath() {
|
|
|
4526
4324
|
}
|
|
4527
4325
|
const home = process.env.HOME?.trim();
|
|
4528
4326
|
const fallbackCandidates = [
|
|
4529
|
-
home ?
|
|
4530
|
-
home ?
|
|
4327
|
+
home ? resolve21(home, ".local/bin/claude") : "",
|
|
4328
|
+
home ? resolve21(home, ".local/share/claude/local/claude") : "",
|
|
4531
4329
|
"/opt/homebrew/bin/claude",
|
|
4532
4330
|
"/usr/local/bin/claude",
|
|
4533
4331
|
"/usr/bin/claude"
|
|
@@ -4541,35 +4339,35 @@ function resolveClaudeBinaryPath() {
|
|
|
4541
4339
|
throw new Error("claude not found in PATH");
|
|
4542
4340
|
}
|
|
4543
4341
|
function resolveBunInstallDir(bunBinaryPath = resolveBunBinaryPath()) {
|
|
4544
|
-
return
|
|
4342
|
+
return resolve21(bunBinaryPath, "../..");
|
|
4545
4343
|
}
|
|
4546
4344
|
function resolveClaudeInstallDir() {
|
|
4547
4345
|
const realPath = resolveClaudeBinaryPath();
|
|
4548
|
-
return
|
|
4346
|
+
return resolve21(realPath, "..");
|
|
4549
4347
|
}
|
|
4550
4348
|
function resolveNodeInstallDir() {
|
|
4551
4349
|
const preferredNode = resolvePreferredNodeBinary();
|
|
4552
4350
|
if (!preferredNode)
|
|
4553
4351
|
return null;
|
|
4554
4352
|
const explicitNode = process.env.RIG_NODE_BIN?.trim();
|
|
4555
|
-
if (explicitNode &&
|
|
4556
|
-
return preferredNode.endsWith("/bin/node") ?
|
|
4353
|
+
if (explicitNode && resolve21(explicitNode) === resolve21(preferredNode)) {
|
|
4354
|
+
return preferredNode.endsWith("/bin/node") ? resolve21(preferredNode, "../..") : resolve21(preferredNode, "..");
|
|
4557
4355
|
}
|
|
4558
4356
|
try {
|
|
4559
4357
|
const realPath = realpathSync2(preferredNode);
|
|
4560
4358
|
if (realPath.endsWith("/bin/node")) {
|
|
4561
|
-
return
|
|
4359
|
+
return resolve21(realPath, "../..");
|
|
4562
4360
|
}
|
|
4563
|
-
return
|
|
4361
|
+
return resolve21(realPath, "..");
|
|
4564
4362
|
} catch {
|
|
4565
|
-
return
|
|
4363
|
+
return resolve21(preferredNode, "..");
|
|
4566
4364
|
}
|
|
4567
4365
|
}
|
|
4568
4366
|
function resolveRuntimeDependencyRoots(runtimeDirs) {
|
|
4569
4367
|
const roots = [];
|
|
4570
4368
|
if (process.platform === "darwin") {
|
|
4571
4369
|
for (const macPath of ["/opt/homebrew", "/opt/homebrew/opt"]) {
|
|
4572
|
-
if (
|
|
4370
|
+
if (existsSync21(macPath)) {
|
|
4573
4371
|
roots.push(macPath);
|
|
4574
4372
|
}
|
|
4575
4373
|
}
|
|
@@ -4587,23 +4385,23 @@ function resolvePreferredNodeBinary() {
|
|
|
4587
4385
|
const candidates = [];
|
|
4588
4386
|
const envNode = process.env.RIG_NODE_BIN?.trim();
|
|
4589
4387
|
if (envNode) {
|
|
4590
|
-
const explicit =
|
|
4591
|
-
if (
|
|
4388
|
+
const explicit = resolve21(envNode);
|
|
4389
|
+
if (existsSync21(explicit)) {
|
|
4592
4390
|
return explicit;
|
|
4593
4391
|
}
|
|
4594
4392
|
}
|
|
4595
4393
|
const nvmBin = process.env.NVM_BIN?.trim();
|
|
4596
4394
|
if (nvmBin) {
|
|
4597
|
-
candidates.push(
|
|
4395
|
+
candidates.push(resolve21(nvmBin, "node"));
|
|
4598
4396
|
}
|
|
4599
4397
|
const home = process.env.HOME?.trim();
|
|
4600
4398
|
if (home) {
|
|
4601
|
-
const nvmVersionsDir =
|
|
4602
|
-
if (
|
|
4399
|
+
const nvmVersionsDir = resolve21(home, ".nvm/versions/node");
|
|
4400
|
+
if (existsSync21(nvmVersionsDir)) {
|
|
4603
4401
|
try {
|
|
4604
|
-
const versionDirs =
|
|
4402
|
+
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
4403
|
for (const versionDir of versionDirs) {
|
|
4606
|
-
candidates.push(
|
|
4404
|
+
candidates.push(resolve21(nvmVersionsDir, versionDir, "bin/node"));
|
|
4607
4405
|
}
|
|
4608
4406
|
} catch {}
|
|
4609
4407
|
}
|
|
@@ -4612,8 +4410,8 @@ function resolvePreferredNodeBinary() {
|
|
|
4612
4410
|
if (whichNode) {
|
|
4613
4411
|
candidates.push(whichNode);
|
|
4614
4412
|
}
|
|
4615
|
-
const deduped = uniq(candidates.map((candidate) =>
|
|
4616
|
-
const existing = deduped.filter((candidate) =>
|
|
4413
|
+
const deduped = uniq(candidates.map((candidate) => resolve21(candidate)));
|
|
4414
|
+
const existing = deduped.filter((candidate) => existsSync21(candidate));
|
|
4617
4415
|
if (existing.length === 0) {
|
|
4618
4416
|
return null;
|
|
4619
4417
|
}
|
|
@@ -4627,7 +4425,7 @@ function resolvePreferredNodeBinary() {
|
|
|
4627
4425
|
return existing[0] ?? null;
|
|
4628
4426
|
}
|
|
4629
4427
|
function inferNodeMajor(nodeBinaryPath) {
|
|
4630
|
-
const normalized =
|
|
4428
|
+
const normalized = resolve21(nodeBinaryPath).replace(/\\/g, "/");
|
|
4631
4429
|
const match = normalized.match(/(?:^|\/)(?:node-)?v?(\d+)\.\d+\.\d+(?:\/|$)/);
|
|
4632
4430
|
if (!match) {
|
|
4633
4431
|
return null;
|
|
@@ -4639,8 +4437,8 @@ function normalizeExecutablePath(candidate) {
|
|
|
4639
4437
|
if (!candidate) {
|
|
4640
4438
|
return "";
|
|
4641
4439
|
}
|
|
4642
|
-
const normalized =
|
|
4643
|
-
if (!
|
|
4440
|
+
const normalized = resolve21(candidate);
|
|
4441
|
+
if (!existsSync21(normalized)) {
|
|
4644
4442
|
return "";
|
|
4645
4443
|
}
|
|
4646
4444
|
try {
|
|
@@ -4650,7 +4448,7 @@ function normalizeExecutablePath(candidate) {
|
|
|
4650
4448
|
}
|
|
4651
4449
|
}
|
|
4652
4450
|
function looksLikeRuntimeGateway(candidate) {
|
|
4653
|
-
const normalized =
|
|
4451
|
+
const normalized = resolve21(candidate).replace(/\\/g, "/");
|
|
4654
4452
|
return normalized.includes("/.rig/bin/") || normalized.endsWith("/rig-shell") || normalized.endsWith("/rig-agent");
|
|
4655
4453
|
}
|
|
4656
4454
|
|
|
@@ -4671,7 +4469,7 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
4671
4469
|
try {
|
|
4672
4470
|
return resolveClaudeInstallDir();
|
|
4673
4471
|
} catch {
|
|
4674
|
-
return
|
|
4472
|
+
return resolve22(claudeBinary, "..");
|
|
4675
4473
|
}
|
|
4676
4474
|
})() : "";
|
|
4677
4475
|
const nodeDir = resolveNodeInstallDir();
|
|
@@ -4681,8 +4479,8 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
4681
4479
|
`${bunDir}/bin`,
|
|
4682
4480
|
claudeDir,
|
|
4683
4481
|
nodeDir ? `${nodeDir}/bin` : "",
|
|
4684
|
-
realHome ?
|
|
4685
|
-
realHome ?
|
|
4482
|
+
realHome ? resolve22(realHome, ".local/bin") : "",
|
|
4483
|
+
realHome ? resolve22(realHome, ".cargo/bin") : "",
|
|
4686
4484
|
...inheritedPath,
|
|
4687
4485
|
"/usr/local/bin",
|
|
4688
4486
|
"/usr/local/sbin",
|
|
@@ -4711,8 +4509,8 @@ function runtimeProvisioningEnv(baseEnv = process.env) {
|
|
|
4711
4509
|
}
|
|
4712
4510
|
|
|
4713
4511
|
// packages/runtime/src/control-plane/runtime/baked-secrets.ts
|
|
4714
|
-
import { existsSync as
|
|
4715
|
-
import { resolve as
|
|
4512
|
+
import { existsSync as existsSync22, readFileSync as readFileSync10 } from "fs";
|
|
4513
|
+
import { resolve as resolve23 } from "path";
|
|
4716
4514
|
var BAKED_RUNTIME_SECRETS = {
|
|
4717
4515
|
ANTHROPIC_API_KEY: typeof RIG_BAKED_ANTHROPIC_API_KEY !== "undefined" ? RIG_BAKED_ANTHROPIC_API_KEY : "",
|
|
4718
4516
|
OPENAI_API_KEY: typeof RIG_BAKED_OPENAI_API_KEY !== "undefined" ? RIG_BAKED_OPENAI_API_KEY : "",
|
|
@@ -4755,12 +4553,12 @@ function resolveRuntimeSecrets(env, baked = BAKED_RUNTIME_SECRETS) {
|
|
|
4755
4553
|
return resolved;
|
|
4756
4554
|
}
|
|
4757
4555
|
function loadDotEnvSecrets(projectRoot, env = process.env) {
|
|
4758
|
-
const dotenvPath =
|
|
4759
|
-
if (!
|
|
4556
|
+
const dotenvPath = resolve23(projectRoot, ".env");
|
|
4557
|
+
if (!existsSync22(dotenvPath)) {
|
|
4760
4558
|
return {};
|
|
4761
4559
|
}
|
|
4762
4560
|
const parsed = {};
|
|
4763
|
-
const lines =
|
|
4561
|
+
const lines = readFileSync10(dotenvPath, "utf-8").split(/\r?\n/);
|
|
4764
4562
|
for (const rawLine of lines) {
|
|
4765
4563
|
const line = rawLine.trim();
|
|
4766
4564
|
if (!line || line.startsWith("#")) {
|
|
@@ -5117,16 +4915,16 @@ async function taskDeps(projectRoot, taskId) {
|
|
|
5117
4915
|
for (const dep of deps) {
|
|
5118
4916
|
const artifactDir = artifactDirForId(projectRoot, dep);
|
|
5119
4917
|
console.log(`=== ${dep} ===`);
|
|
5120
|
-
if (!
|
|
4918
|
+
if (!existsSync23(artifactDir)) {
|
|
5121
4919
|
console.log(` (no artifacts yet)
|
|
5122
4920
|
`);
|
|
5123
4921
|
continue;
|
|
5124
4922
|
}
|
|
5125
|
-
printArtifactSection(
|
|
5126
|
-
printArtifactSection(
|
|
5127
|
-
const changedFiles =
|
|
5128
|
-
if (
|
|
5129
|
-
const lines =
|
|
4923
|
+
printArtifactSection(resolve24(artifactDir, "decision-log.md"), "--- Decisions ---");
|
|
4924
|
+
printArtifactSection(resolve24(artifactDir, "next-actions.md"), "--- Next Actions (for you) ---");
|
|
4925
|
+
const changedFiles = resolve24(artifactDir, "changed-files.txt");
|
|
4926
|
+
if (existsSync23(changedFiles)) {
|
|
4927
|
+
const lines = readFileSync11(changedFiles, "utf-8").split(/\r?\n/).filter(Boolean);
|
|
5130
4928
|
console.log(`--- Changed Files (${lines.length}) ---`);
|
|
5131
4929
|
for (const line of lines) {
|
|
5132
4930
|
console.log(line);
|
|
@@ -5250,12 +5048,12 @@ function printIndented(text) {
|
|
|
5250
5048
|
}
|
|
5251
5049
|
}
|
|
5252
5050
|
function readLocalBeadsTasks(projectRoot) {
|
|
5253
|
-
const issuesPath =
|
|
5254
|
-
if (!
|
|
5051
|
+
const issuesPath = resolve24(resolveMonorepoRoot2(projectRoot), ".beads/issues.jsonl");
|
|
5052
|
+
if (!existsSync23(issuesPath)) {
|
|
5255
5053
|
return [];
|
|
5256
5054
|
}
|
|
5257
5055
|
const tasks = [];
|
|
5258
|
-
for (const line of
|
|
5056
|
+
for (const line of readFileSync11(issuesPath, "utf-8").split(/\r?\n/)) {
|
|
5259
5057
|
const trimmed = line.trim();
|
|
5260
5058
|
if (!trimmed) {
|
|
5261
5059
|
continue;
|
|
@@ -5368,11 +5166,11 @@ function taskDependencies(projectRoot, taskId, tracker) {
|
|
|
5368
5166
|
return [...ids].sort();
|
|
5369
5167
|
}
|
|
5370
5168
|
function printArtifactSection(path, header) {
|
|
5371
|
-
if (!
|
|
5169
|
+
if (!existsSync23(path)) {
|
|
5372
5170
|
return;
|
|
5373
5171
|
}
|
|
5374
5172
|
console.log(header);
|
|
5375
|
-
process.stdout.write(
|
|
5173
|
+
process.stdout.write(readFileSync11(path, "utf-8"));
|
|
5376
5174
|
console.log("");
|
|
5377
5175
|
}
|
|
5378
5176
|
|
|
@@ -5474,7 +5272,7 @@ init_layout();
|
|
|
5474
5272
|
|
|
5475
5273
|
// packages/runtime/src/control-plane/runtime/overlay.ts
|
|
5476
5274
|
init_layout();
|
|
5477
|
-
import { mkdirSync as
|
|
5275
|
+
import { mkdirSync as mkdirSync11 } from "fs";
|
|
5478
5276
|
function ensureRuntimeOverlay(projectRoot, runtimeId, workspaceDir) {
|
|
5479
5277
|
const layout = resolveRuntimeWorkspaceLayout(workspaceDir ?? projectRoot);
|
|
5480
5278
|
const rootDir = layout.rigRoot;
|
|
@@ -5486,14 +5284,14 @@ function ensureRuntimeOverlay(projectRoot, runtimeId, workspaceDir) {
|
|
|
5486
5284
|
const sessionDir = layout.sessionDir;
|
|
5487
5285
|
const runtimeDir = layout.runtimeDir;
|
|
5488
5286
|
const contextPath = layout.contextPath;
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5287
|
+
mkdirSync11(rootDir, { recursive: true });
|
|
5288
|
+
mkdirSync11(homeDir, { recursive: true });
|
|
5289
|
+
mkdirSync11(tmpDir, { recursive: true });
|
|
5290
|
+
mkdirSync11(cacheDir, { recursive: true });
|
|
5291
|
+
mkdirSync11(logsDir, { recursive: true });
|
|
5292
|
+
mkdirSync11(stateDir, { recursive: true });
|
|
5293
|
+
mkdirSync11(sessionDir, { recursive: true });
|
|
5294
|
+
mkdirSync11(runtimeDir, { recursive: true });
|
|
5497
5295
|
return {
|
|
5498
5296
|
rootDir,
|
|
5499
5297
|
homeDir,
|
|
@@ -5511,17 +5309,17 @@ import {
|
|
|
5511
5309
|
chmodSync as chmodSync5,
|
|
5512
5310
|
copyFileSync as copyFileSync5,
|
|
5513
5311
|
cpSync as cpSync2,
|
|
5514
|
-
existsSync as
|
|
5515
|
-
mkdirSync as
|
|
5312
|
+
existsSync as existsSync25,
|
|
5313
|
+
mkdirSync as mkdirSync12,
|
|
5516
5314
|
statSync as statSync5,
|
|
5517
|
-
writeFileSync as
|
|
5315
|
+
writeFileSync as writeFileSync10
|
|
5518
5316
|
} from "fs";
|
|
5519
5317
|
import { mkdir } from "fs/promises";
|
|
5520
|
-
import { basename as basename8, delimiter as delimiter2, resolve as
|
|
5318
|
+
import { basename as basename8, delimiter as delimiter2, resolve as resolve26 } from "path";
|
|
5521
5319
|
|
|
5522
5320
|
// packages/runtime/src/control-plane/runtime/isolation/shared.ts
|
|
5523
|
-
import { existsSync as
|
|
5524
|
-
import { resolve as
|
|
5321
|
+
import { existsSync as existsSync24, readFileSync as readFileSync12, rmSync as rmSync9 } from "fs";
|
|
5322
|
+
import { resolve as resolve25 } from "path";
|
|
5525
5323
|
var generatedCredentialFiles = new Set;
|
|
5526
5324
|
var credentialCleanupRegistered = false;
|
|
5527
5325
|
function resolveMonorepoRoot3(projectRoot) {
|
|
@@ -5545,7 +5343,7 @@ function resolveHostGitBinary() {
|
|
|
5545
5343
|
if (!candidate || isRuntimeGatewayGitPath(candidate)) {
|
|
5546
5344
|
continue;
|
|
5547
5345
|
}
|
|
5548
|
-
if (
|
|
5346
|
+
if (existsSync24(candidate)) {
|
|
5549
5347
|
return candidate;
|
|
5550
5348
|
}
|
|
5551
5349
|
}
|
|
@@ -5611,7 +5409,7 @@ async function refreshRemoteBranch(repoRoot, remote, branch) {
|
|
|
5611
5409
|
}
|
|
5612
5410
|
}
|
|
5613
5411
|
async function tryReadGitHead(repoRoot) {
|
|
5614
|
-
if (!
|
|
5412
|
+
if (!existsSync24(resolve25(repoRoot, ".git"))) {
|
|
5615
5413
|
return;
|
|
5616
5414
|
}
|
|
5617
5415
|
const result = await runGitCommand(repoRoot, ["rev-parse", "HEAD"]);
|
|
@@ -5622,7 +5420,7 @@ async function tryReadGitHead(repoRoot) {
|
|
|
5622
5420
|
return value || undefined;
|
|
5623
5421
|
}
|
|
5624
5422
|
async function captureRepoDirtyFiles(repoRoot) {
|
|
5625
|
-
if (!
|
|
5423
|
+
if (!existsSync24(resolve25(repoRoot, ".git"))) {
|
|
5626
5424
|
return [];
|
|
5627
5425
|
}
|
|
5628
5426
|
const files = new Set;
|
|
@@ -5658,7 +5456,7 @@ function registerCredentialCleanup(path) {
|
|
|
5658
5456
|
const cleanup = () => {
|
|
5659
5457
|
for (const filePath of generatedCredentialFiles) {
|
|
5660
5458
|
try {
|
|
5661
|
-
|
|
5459
|
+
rmSync9(filePath, { force: true });
|
|
5662
5460
|
} catch {}
|
|
5663
5461
|
}
|
|
5664
5462
|
generatedCredentialFiles.clear();
|
|
@@ -5710,20 +5508,23 @@ function hashProjectPath(workspaceDir) {
|
|
|
5710
5508
|
}
|
|
5711
5509
|
function resolveGithubCliBinaryPath() {
|
|
5712
5510
|
const explicit = process.env.RIG_GH_BIN?.trim();
|
|
5713
|
-
if (explicit &&
|
|
5511
|
+
if (explicit && existsSync24(explicit) && !isRuntimeGatewayGhPath(explicit)) {
|
|
5714
5512
|
return explicit;
|
|
5715
5513
|
}
|
|
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)) {
|
|
5514
|
+
for (const candidate of ["/usr/bin/gh", "/opt/homebrew/bin/gh", "/usr/local/bin/gh"]) {
|
|
5515
|
+
if (existsSync24(candidate)) {
|
|
5722
5516
|
return candidate;
|
|
5723
5517
|
}
|
|
5724
5518
|
}
|
|
5519
|
+
const bunResolved = Bun.which("gh");
|
|
5520
|
+
if (bunResolved && existsSync24(bunResolved) && !isRuntimeGatewayGhPath(bunResolved)) {
|
|
5521
|
+
return bunResolved;
|
|
5522
|
+
}
|
|
5725
5523
|
return "";
|
|
5726
5524
|
}
|
|
5525
|
+
function isRuntimeGatewayGhPath(candidate) {
|
|
5526
|
+
return /\/\.rig\/bin\/gh$/.test(candidate.replace(/\\/g, "/"));
|
|
5527
|
+
}
|
|
5727
5528
|
async function resolveGithubCliAuthToken(ghBinary = "") {
|
|
5728
5529
|
const gh = ghBinary || resolveGithubCliBinaryPath();
|
|
5729
5530
|
if (!gh) {
|
|
@@ -5750,17 +5551,17 @@ function resolveSystemCertBundlePath() {
|
|
|
5750
5551
|
"/opt/homebrew/etc/openssl@3/cert.pem"
|
|
5751
5552
|
];
|
|
5752
5553
|
for (const candidate of candidates) {
|
|
5753
|
-
if (candidate &&
|
|
5754
|
-
return
|
|
5554
|
+
if (candidate && existsSync24(candidate)) {
|
|
5555
|
+
return resolve25(candidate);
|
|
5755
5556
|
}
|
|
5756
5557
|
}
|
|
5757
5558
|
return "";
|
|
5758
5559
|
}
|
|
5759
5560
|
function readKnownHosts(path) {
|
|
5760
|
-
if (!
|
|
5561
|
+
if (!existsSync24(path)) {
|
|
5761
5562
|
return new Set;
|
|
5762
5563
|
}
|
|
5763
|
-
return new Set(
|
|
5564
|
+
return new Set(readFileSync12(path, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
|
|
5764
5565
|
}
|
|
5765
5566
|
|
|
5766
5567
|
// packages/runtime/src/control-plane/runtime/isolation/home.ts
|
|
@@ -5771,6 +5572,21 @@ var GITHUB_KNOWN_HOSTS = [
|
|
|
5771
5572
|
"github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk="
|
|
5772
5573
|
].join(`
|
|
5773
5574
|
`);
|
|
5575
|
+
function resolveControlPlaneSourceRoot(projectRoot) {
|
|
5576
|
+
const candidates = [
|
|
5577
|
+
process.env.RIG_CONTROL_PLANE_SOURCE_ROOT?.trim(),
|
|
5578
|
+
process.env.RIG_HOST_PROJECT_ROOT?.trim(),
|
|
5579
|
+
resolve26(import.meta.dir, "../../../../.."),
|
|
5580
|
+
projectRoot
|
|
5581
|
+
].filter((value) => Boolean(value));
|
|
5582
|
+
for (const candidate of candidates) {
|
|
5583
|
+
const root = resolve26(candidate);
|
|
5584
|
+
if (existsSync25(resolve26(root, "packages/runtime/src/control-plane/pi-sessiond/bin.ts"))) {
|
|
5585
|
+
return root;
|
|
5586
|
+
}
|
|
5587
|
+
}
|
|
5588
|
+
return "";
|
|
5589
|
+
}
|
|
5774
5590
|
async function runtimeEnv(projectRoot, runtime) {
|
|
5775
5591
|
const bunBinaryPath = resolveBunBinaryPath();
|
|
5776
5592
|
const bunDir = resolveBunInstallDir(bunBinaryPath);
|
|
@@ -5785,7 +5601,7 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5785
5601
|
try {
|
|
5786
5602
|
return resolveClaudeInstallDir();
|
|
5787
5603
|
} catch {
|
|
5788
|
-
return
|
|
5604
|
+
return resolve26(claudeBinaryPath, "..");
|
|
5789
5605
|
}
|
|
5790
5606
|
})() : "";
|
|
5791
5607
|
const nodeDir = resolveNodeInstallDir();
|
|
@@ -5800,8 +5616,8 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5800
5616
|
`${bunDir}/bin`,
|
|
5801
5617
|
claudeDir,
|
|
5802
5618
|
nodeDir ? `${nodeDir}/bin` : "",
|
|
5803
|
-
realHome ?
|
|
5804
|
-
realHome ?
|
|
5619
|
+
realHome ? resolve26(realHome, ".local/bin") : "",
|
|
5620
|
+
realHome ? resolve26(realHome, ".cargo/bin") : "",
|
|
5805
5621
|
...inheritedPath,
|
|
5806
5622
|
"/usr/local/bin",
|
|
5807
5623
|
"/usr/local/sbin",
|
|
@@ -5812,18 +5628,22 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5812
5628
|
"/usr/sbin",
|
|
5813
5629
|
"/sbin"
|
|
5814
5630
|
].filter(Boolean);
|
|
5815
|
-
const runtimeBash =
|
|
5816
|
-
const runtimeRigGit =
|
|
5817
|
-
const preferredShell =
|
|
5631
|
+
const runtimeBash = resolve26(runtime.binDir, "bash");
|
|
5632
|
+
const runtimeRigGit = resolve26(runtime.binDir, runtimeRigGitFileName());
|
|
5633
|
+
const preferredShell = existsSync25(runtimeBash) ? runtimeBash : "/bin/bash";
|
|
5818
5634
|
const nativeRuntimeLibraryPath = await materializeNativeRuntimeLibrary(runtime.binDir);
|
|
5635
|
+
const controlPlaneSourceRoot = resolveControlPlaneSourceRoot(projectRoot);
|
|
5819
5636
|
const env = {
|
|
5820
5637
|
PROJECT_RIG_ROOT: projectRoot,
|
|
5821
5638
|
RIG_HOST_PROJECT_ROOT: projectRoot,
|
|
5639
|
+
...controlPlaneSourceRoot ? { RIG_CONTROL_PLANE_SOURCE_ROOT: controlPlaneSourceRoot } : {},
|
|
5822
5640
|
HOME: runtime.homeDir,
|
|
5823
5641
|
TMPDIR: runtime.tmpDir,
|
|
5824
5642
|
XDG_CACHE_HOME: runtime.cacheDir,
|
|
5825
5643
|
XDG_STATE_HOME: runtime.stateDir,
|
|
5826
5644
|
RIG_AGENT_ID: runtime.id,
|
|
5645
|
+
...process.env.RIG_RUN_ID?.trim() ? { RIG_RUN_ID: process.env.RIG_RUN_ID.trim() } : {},
|
|
5646
|
+
...process.env.RIG_SERVER_RUN_ID?.trim() ? { RIG_SERVER_RUN_ID: process.env.RIG_SERVER_RUN_ID.trim() } : {},
|
|
5827
5647
|
RIG_TASK_ID: runtime.taskId,
|
|
5828
5648
|
RIG_TASK_RUNTIME_ID: runtime.id,
|
|
5829
5649
|
RIG_TASK_WORKSPACE: runtime.workspaceDir,
|
|
@@ -5831,30 +5651,30 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5831
5651
|
RIG_RUNTIME_MODE: runtime.mode,
|
|
5832
5652
|
RIG_RUNTIME_HOME: runtime.rootDir,
|
|
5833
5653
|
RIG_RUNTIME_BIN_DIR: runtime.binDir,
|
|
5834
|
-
...
|
|
5654
|
+
...existsSync25(runtimeRigGit) ? { RIG_NATIVE_GIT_BIN: runtimeRigGit } : {},
|
|
5835
5655
|
RIG_BUN_PATH: bunBinaryPath,
|
|
5836
5656
|
...claudeBinaryPath ? { RIG_CLAUDE_PATH: claudeBinaryPath } : {},
|
|
5837
|
-
RIG_AGENT_BIN:
|
|
5657
|
+
RIG_AGENT_BIN: resolve26(runtime.binDir, "rig-agent"),
|
|
5838
5658
|
RIG_HOOKS_ACTIVE: "1",
|
|
5839
5659
|
RIG_AUTO_PR_ON_COMPLETE: "1",
|
|
5840
|
-
RIG_POLICY_FILE:
|
|
5660
|
+
RIG_POLICY_FILE: resolve26(projectRoot, "rig/policy/policy.json"),
|
|
5841
5661
|
RIG_STATE_DIR: runtime.stateDir,
|
|
5842
5662
|
RIG_LOGS_DIR: runtime.logsDir,
|
|
5843
|
-
RIG_SESSION_FILE:
|
|
5663
|
+
RIG_SESSION_FILE: resolve26(runtime.sessionDir, "session.json"),
|
|
5844
5664
|
MONOREPO_ROOT: runtime.workspaceDir,
|
|
5845
5665
|
MONOREPO_MAIN_ROOT: monorepoMainRoot,
|
|
5846
|
-
TS_API_TESTS_DIR:
|
|
5666
|
+
TS_API_TESTS_DIR: resolve26(runtime.workspaceDir, "TSAPITests"),
|
|
5847
5667
|
BASH: preferredShell,
|
|
5848
5668
|
SHELL: preferredShell,
|
|
5849
5669
|
PATH: [...new Set(pathEntries)].join(delimiter2),
|
|
5850
5670
|
LANG: process.env.LANG ?? "en_US.UTF-8",
|
|
5851
5671
|
TERM: process.env.TERM ?? "xterm-256color",
|
|
5852
5672
|
PYTHONDONTWRITEBYTECODE: "1",
|
|
5853
|
-
PYTHONPYCACHEPREFIX:
|
|
5673
|
+
PYTHONPYCACHEPREFIX: resolve26(runtime.cacheDir, "python"),
|
|
5854
5674
|
...process.env.RIG_PR_BASE_PROJECT && { RIG_PR_BASE_PROJECT: process.env.RIG_PR_BASE_PROJECT },
|
|
5855
5675
|
...process.env.RIG_PR_BASE_MONOREPO && { RIG_PR_BASE_MONOREPO: process.env.RIG_PR_BASE_MONOREPO },
|
|
5856
5676
|
CLAUDE_HOME: runtime.claudeHomeDir,
|
|
5857
|
-
PI_CODING_AGENT_DIR:
|
|
5677
|
+
PI_CODING_AGENT_DIR: resolve26(runtime.homeDir, ".pi", "agent"),
|
|
5858
5678
|
[RUNTIME_CONTEXT_ENV]: runtime.contextFile,
|
|
5859
5679
|
...nativeRuntimeLibraryPath ? { RIG_NATIVE_RUNTIME_LIB: nativeRuntimeLibraryPath } : {},
|
|
5860
5680
|
...hostGhBinary ? { RIG_GH_BIN: hostGhBinary } : {},
|
|
@@ -5865,16 +5685,16 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5865
5685
|
NODE_EXTRA_CA_CERTS: runtimeCertBundlePath
|
|
5866
5686
|
} : {}
|
|
5867
5687
|
};
|
|
5868
|
-
const knownHostsPath =
|
|
5869
|
-
if (
|
|
5870
|
-
const agentSshKey =
|
|
5688
|
+
const knownHostsPath = resolve26(runtime.homeDir, ".ssh", "known_hosts");
|
|
5689
|
+
if (existsSync25(knownHostsPath)) {
|
|
5690
|
+
const agentSshKey = resolve26(runtime.homeDir, ".ssh", "rig-agent-key");
|
|
5871
5691
|
const sshParts = [
|
|
5872
5692
|
"ssh",
|
|
5873
5693
|
`-o UserKnownHostsFile="${knownHostsPath}"`,
|
|
5874
5694
|
"-o StrictHostKeyChecking=yes",
|
|
5875
5695
|
"-F /dev/null"
|
|
5876
5696
|
];
|
|
5877
|
-
if (
|
|
5697
|
+
if (existsSync25(agentSshKey)) {
|
|
5878
5698
|
sshParts.splice(1, 0, `-i "${agentSshKey}"`, "-o IdentitiesOnly=yes");
|
|
5879
5699
|
}
|
|
5880
5700
|
env.GIT_SSH_COMMAND = sshParts.join(" ");
|
|
@@ -5911,7 +5731,7 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5911
5731
|
if (!env.GREPTILE_GITHUB_TOKEN && env.GITHUB_TOKEN) {
|
|
5912
5732
|
env.GREPTILE_GITHUB_TOKEN = env.GITHUB_TOKEN;
|
|
5913
5733
|
}
|
|
5914
|
-
if (
|
|
5734
|
+
if (existsSync25(runtime.contextFile)) {
|
|
5915
5735
|
const runtimeContext = loadRuntimeContext(runtime.contextFile);
|
|
5916
5736
|
Object.assign(env, runtimeMemoryEnvFromContext(runtimeContext));
|
|
5917
5737
|
Object.assign(env, browserEnvFromContext(runtimeContext.browser));
|
|
@@ -5925,30 +5745,30 @@ async function provisionRuntimeHome(runtime, options = {}) {
|
|
|
5925
5745
|
await mkdir(runtime.cacheDir, { recursive: true });
|
|
5926
5746
|
await provisionAgentSshKey(runtime.homeDir);
|
|
5927
5747
|
if (options.provider === "codex") {
|
|
5928
|
-
const hasCodexAuth = await injectCodexAuth(
|
|
5748
|
+
const hasCodexAuth = await injectCodexAuth(resolve26(runtime.homeDir, ".codex"));
|
|
5929
5749
|
if (!hasCodexAuth) {
|
|
5930
5750
|
console.warn("[rig] No Codex auth.json found for isolated runtime. " + "Run `codex login` in your host shell, then retry the agent run.");
|
|
5931
5751
|
}
|
|
5932
5752
|
}
|
|
5933
5753
|
if (options.provider === "pi") {
|
|
5934
|
-
const hasPiAuth = await injectPiAgentConfig(
|
|
5754
|
+
const hasPiAuth = await injectPiAgentConfig(resolve26(runtime.homeDir, ".pi", "agent"));
|
|
5935
5755
|
if (!hasPiAuth) {
|
|
5936
5756
|
console.warn("[rig] No Pi auth.json found for isolated runtime. " + "Run `pi /login` in your host shell, then retry the agent run.");
|
|
5937
5757
|
}
|
|
5938
5758
|
}
|
|
5939
5759
|
}
|
|
5940
5760
|
async function provisionClaudeHome(config) {
|
|
5941
|
-
|
|
5942
|
-
const workspaceSettings =
|
|
5943
|
-
const hostSettings =
|
|
5944
|
-
const projectSettings =
|
|
5761
|
+
mkdirSync12(config.claudeHomeDir, { recursive: true });
|
|
5762
|
+
const workspaceSettings = resolve26(config.workspaceDir, ".claude/settings.json");
|
|
5763
|
+
const hostSettings = resolve26(config.hostProjectRoot, ".claude/settings.json");
|
|
5764
|
+
const projectSettings = existsSync25(workspaceSettings) ? workspaceSettings : hostSettings;
|
|
5945
5765
|
const runtimeSettings = await loadRuntimeClaudeSettings(projectSettings);
|
|
5946
|
-
if (
|
|
5947
|
-
|
|
5766
|
+
if (existsSync25(projectSettings)) {
|
|
5767
|
+
writeFileSync10(resolve26(config.claudeHomeDir, "settings.local.json"), `${JSON.stringify(runtimeSettings, null, 2)}
|
|
5948
5768
|
`, "utf-8");
|
|
5949
5769
|
}
|
|
5950
5770
|
writeClaudeProjectSettings(config.claudeHomeDir, config.workspaceDir, runtimeSettings);
|
|
5951
|
-
|
|
5771
|
+
writeFileSync10(resolve26(config.claudeHomeDir, "settings.json"), JSON.stringify({
|
|
5952
5772
|
permissions: { defaultMode: "bypassPermissions" },
|
|
5953
5773
|
autoMemoryEnabled: false
|
|
5954
5774
|
}, null, 2));
|
|
@@ -5956,12 +5776,12 @@ async function provisionClaudeHome(config) {
|
|
|
5956
5776
|
if (!hasCredentials) {
|
|
5957
5777
|
console.warn("[rig] No Claude credentials found for isolated runtime. " + "Run `claude /login` in your host shell, then retry the agent run.");
|
|
5958
5778
|
}
|
|
5959
|
-
const realClaudeHome =
|
|
5960
|
-
if (process.env.HOME &&
|
|
5961
|
-
cpSync2(
|
|
5779
|
+
const realClaudeHome = resolve26(process.env.HOME ?? "", ".claude");
|
|
5780
|
+
if (process.env.HOME && existsSync25(resolve26(realClaudeHome, "CLAUDE.md"))) {
|
|
5781
|
+
cpSync2(resolve26(realClaudeHome, "CLAUDE.md"), resolve26(config.claudeHomeDir, "CLAUDE.md"));
|
|
5962
5782
|
}
|
|
5963
|
-
if (process.env.HOME &&
|
|
5964
|
-
cpSync2(
|
|
5783
|
+
if (process.env.HOME && existsSync25(resolve26(realClaudeHome, "agents"))) {
|
|
5784
|
+
cpSync2(resolve26(realClaudeHome, "agents"), resolve26(config.claudeHomeDir, "agents"), { recursive: true });
|
|
5965
5785
|
}
|
|
5966
5786
|
if (process.platform === "darwin" && process.env.HOME) {
|
|
5967
5787
|
writeClaudeProjectSettings(realClaudeHome, config.workspaceDir, runtimeSettings);
|
|
@@ -5972,10 +5792,10 @@ async function materializeRuntimeCertBundle(runtime) {
|
|
|
5972
5792
|
if (!sourcePath) {
|
|
5973
5793
|
return "";
|
|
5974
5794
|
}
|
|
5975
|
-
const certsDir =
|
|
5976
|
-
const targetPath =
|
|
5795
|
+
const certsDir = resolve26(runtime.rootDir, "certs");
|
|
5796
|
+
const targetPath = resolve26(certsDir, "ca-certificates.pem");
|
|
5977
5797
|
await mkdir(certsDir, { recursive: true });
|
|
5978
|
-
let shouldCopy = !
|
|
5798
|
+
let shouldCopy = !existsSync25(targetPath);
|
|
5979
5799
|
if (!shouldCopy) {
|
|
5980
5800
|
try {
|
|
5981
5801
|
shouldCopy = statSync5(sourcePath).mtimeMs > statSync5(targetPath).mtimeMs;
|
|
@@ -5997,7 +5817,7 @@ function applyGitHubCredentialHelperEnv(env) {
|
|
|
5997
5817
|
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
5818
|
}
|
|
5999
5819
|
function persistRuntimeSecrets(runtimeRoot, env) {
|
|
6000
|
-
const secretsPath =
|
|
5820
|
+
const secretsPath = resolve26(runtimeRoot, "runtime-secrets.json");
|
|
6001
5821
|
const persisted = {};
|
|
6002
5822
|
for (const key of [
|
|
6003
5823
|
"GITHUB_TOKEN",
|
|
@@ -6016,12 +5836,12 @@ function persistRuntimeSecrets(runtimeRoot, env) {
|
|
|
6016
5836
|
if (Object.keys(persisted).length === 0) {
|
|
6017
5837
|
return;
|
|
6018
5838
|
}
|
|
6019
|
-
|
|
5839
|
+
writeFileSync10(secretsPath, `${JSON.stringify(persisted, null, 2)}
|
|
6020
5840
|
`, "utf-8");
|
|
6021
5841
|
}
|
|
6022
5842
|
async function provisionAgentSshKey(homeDir) {
|
|
6023
|
-
const sshDir =
|
|
6024
|
-
if (!
|
|
5843
|
+
const sshDir = resolve26(homeDir, ".ssh");
|
|
5844
|
+
if (!existsSync25(sshDir)) {
|
|
6025
5845
|
await mkdir(sshDir, { recursive: true });
|
|
6026
5846
|
}
|
|
6027
5847
|
seedKnownHosts(sshDir);
|
|
@@ -6029,27 +5849,27 @@ async function provisionAgentSshKey(homeDir) {
|
|
|
6029
5849
|
const privateKey = decodeProvisionedSshKey(secrets.GITHUB_SSH_KEY);
|
|
6030
5850
|
if (!privateKey) {
|
|
6031
5851
|
const hostKeyPath = resolveHostSshKeyPath(process.env.HOME ?? "");
|
|
6032
|
-
if (!process.env.HOME || !
|
|
5852
|
+
if (!process.env.HOME || !existsSync25(hostKeyPath)) {
|
|
6033
5853
|
return;
|
|
6034
5854
|
}
|
|
6035
|
-
const agentKeyPath2 =
|
|
6036
|
-
if (!
|
|
5855
|
+
const agentKeyPath2 = resolve26(sshDir, "rig-agent-key");
|
|
5856
|
+
if (!existsSync25(agentKeyPath2)) {
|
|
6037
5857
|
copyFileSync5(hostKeyPath, agentKeyPath2);
|
|
6038
5858
|
chmodSync5(agentKeyPath2, 384);
|
|
6039
5859
|
}
|
|
6040
5860
|
const hostPubPath = `${hostKeyPath}.pub`;
|
|
6041
|
-
if (
|
|
5861
|
+
if (existsSync25(hostPubPath)) {
|
|
6042
5862
|
const agentPubPath = `${agentKeyPath2}.pub`;
|
|
6043
|
-
if (!
|
|
5863
|
+
if (!existsSync25(agentPubPath)) {
|
|
6044
5864
|
copyFileSync5(hostPubPath, agentPubPath);
|
|
6045
5865
|
}
|
|
6046
5866
|
}
|
|
6047
5867
|
writeSshConfig(sshDir, agentKeyPath2);
|
|
6048
5868
|
return;
|
|
6049
5869
|
}
|
|
6050
|
-
const agentKeyPath =
|
|
6051
|
-
if (!
|
|
6052
|
-
|
|
5870
|
+
const agentKeyPath = resolve26(sshDir, "rig-agent-key");
|
|
5871
|
+
if (!existsSync25(agentKeyPath)) {
|
|
5872
|
+
writeFileSync10(agentKeyPath, privateKey, { mode: 384 });
|
|
6053
5873
|
}
|
|
6054
5874
|
writeSshConfig(sshDir, agentKeyPath);
|
|
6055
5875
|
}
|
|
@@ -6066,21 +5886,21 @@ function decodeProvisionedSshKey(encodedKey) {
|
|
|
6066
5886
|
`;
|
|
6067
5887
|
}
|
|
6068
5888
|
function resolveHostSshKeyPath(homeDir) {
|
|
6069
|
-
const sshDir =
|
|
5889
|
+
const sshDir = resolve26(homeDir, ".ssh");
|
|
6070
5890
|
const candidates = [
|
|
6071
5891
|
"rig-agent-key",
|
|
6072
5892
|
"id_ed25519",
|
|
6073
5893
|
"id_ecdsa",
|
|
6074
5894
|
"id_rsa"
|
|
6075
|
-
].map((name) =>
|
|
6076
|
-
return candidates.find((candidate) =>
|
|
5895
|
+
].map((name) => resolve26(sshDir, name));
|
|
5896
|
+
return candidates.find((candidate) => existsSync25(candidate)) ?? resolve26(sshDir, "rig-agent-key");
|
|
6077
5897
|
}
|
|
6078
5898
|
function writeSshConfig(sshDir, keyPath) {
|
|
6079
|
-
const configPath =
|
|
6080
|
-
if (
|
|
5899
|
+
const configPath = resolve26(sshDir, "config");
|
|
5900
|
+
if (existsSync25(configPath)) {
|
|
6081
5901
|
return;
|
|
6082
5902
|
}
|
|
6083
|
-
const knownHostsPath =
|
|
5903
|
+
const knownHostsPath = resolve26(sshDir, "known_hosts");
|
|
6084
5904
|
const config = [
|
|
6085
5905
|
"Host github.com",
|
|
6086
5906
|
` IdentityFile ${keyPath}`,
|
|
@@ -6090,10 +5910,10 @@ function writeSshConfig(sshDir, keyPath) {
|
|
|
6090
5910
|
""
|
|
6091
5911
|
].join(`
|
|
6092
5912
|
`);
|
|
6093
|
-
|
|
5913
|
+
writeFileSync10(configPath, config, { mode: 420 });
|
|
6094
5914
|
}
|
|
6095
5915
|
function seedKnownHosts(sshDir) {
|
|
6096
|
-
const knownHostsPath =
|
|
5916
|
+
const knownHostsPath = resolve26(sshDir, "known_hosts");
|
|
6097
5917
|
const existingLines = readKnownHosts(knownHostsPath);
|
|
6098
5918
|
const requiredLines = GITHUB_KNOWN_HOSTS.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
6099
5919
|
const missing = requiredLines.filter((line) => !existingLines.has(line));
|
|
@@ -6104,23 +5924,23 @@ function seedKnownHosts(sshDir) {
|
|
|
6104
5924
|
for (const line of missing) {
|
|
6105
5925
|
existingLines.add(line);
|
|
6106
5926
|
}
|
|
6107
|
-
|
|
5927
|
+
writeFileSync10(knownHostsPath, `${Array.from(existingLines).join(`
|
|
6108
5928
|
`)}
|
|
6109
5929
|
`, { mode: 420 });
|
|
6110
5930
|
} catch (err) {
|
|
6111
|
-
const hint =
|
|
5931
|
+
const hint = existsSync25(knownHostsPath) ? "" : " \u2014 known_hosts is missing; git SSH operations may fail";
|
|
6112
5932
|
console.warn(`[rig] Could not update ${knownHostsPath}: ${err instanceof Error ? err.message : String(err)}${hint}`);
|
|
6113
5933
|
}
|
|
6114
5934
|
}
|
|
6115
5935
|
function writeClaudeProjectSettings(claudeHomeDir, workspaceDir, runtimeSettings) {
|
|
6116
5936
|
const projectHash = hashProjectPath(workspaceDir);
|
|
6117
|
-
const projectDir =
|
|
6118
|
-
|
|
6119
|
-
|
|
5937
|
+
const projectDir = resolve26(claudeHomeDir, "projects", projectHash);
|
|
5938
|
+
mkdirSync12(projectDir, { recursive: true });
|
|
5939
|
+
writeFileSync10(resolve26(projectDir, "settings.json"), `${JSON.stringify(runtimeSettings, null, 2)}
|
|
6120
5940
|
`, "utf-8");
|
|
6121
5941
|
}
|
|
6122
5942
|
async function loadRuntimeClaudeSettings(projectSettingsPath) {
|
|
6123
|
-
if (!
|
|
5943
|
+
if (!existsSync25(projectSettingsPath)) {
|
|
6124
5944
|
return {};
|
|
6125
5945
|
}
|
|
6126
5946
|
let parsed;
|
|
@@ -6166,7 +5986,7 @@ async function loadRuntimeClaudeSettings(projectSettingsPath) {
|
|
|
6166
5986
|
return clone;
|
|
6167
5987
|
}
|
|
6168
5988
|
async function injectClaudeCredentials(claudeHomeDir, options = {}) {
|
|
6169
|
-
const credentialsPath =
|
|
5989
|
+
const credentialsPath = resolve26(claudeHomeDir, ".credentials.json");
|
|
6170
5990
|
const platform = options.platform ?? process.platform;
|
|
6171
5991
|
if (platform === "darwin") {
|
|
6172
5992
|
const raw = options.loadKeychainCredentials ? await options.loadKeychainCredentials() : await (async () => {
|
|
@@ -6176,16 +5996,16 @@ async function injectClaudeCredentials(claudeHomeDir, options = {}) {
|
|
|
6176
5996
|
if (raw) {
|
|
6177
5997
|
try {
|
|
6178
5998
|
JSON.parse(raw);
|
|
6179
|
-
|
|
5999
|
+
writeFileSync10(credentialsPath, raw, { mode: 384 });
|
|
6180
6000
|
registerCredentialCleanup(credentialsPath);
|
|
6181
6001
|
return true;
|
|
6182
6002
|
} catch {}
|
|
6183
6003
|
}
|
|
6184
6004
|
}
|
|
6185
|
-
const hostClaudeHome = options.hostClaudeHome ?
|
|
6005
|
+
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
6006
|
if (hostClaudeHome) {
|
|
6187
|
-
const realCredentials =
|
|
6188
|
-
if (
|
|
6007
|
+
const realCredentials = resolve26(hostClaudeHome, ".credentials.json");
|
|
6008
|
+
if (existsSync25(realCredentials)) {
|
|
6189
6009
|
cpSync2(realCredentials, credentialsPath);
|
|
6190
6010
|
return true;
|
|
6191
6011
|
}
|
|
@@ -6193,36 +6013,36 @@ async function injectClaudeCredentials(claudeHomeDir, options = {}) {
|
|
|
6193
6013
|
return false;
|
|
6194
6014
|
}
|
|
6195
6015
|
async function injectCodexAuth(codexHomeDir) {
|
|
6196
|
-
|
|
6197
|
-
const hostCodexHome = process.env.CODEX_HOME?.trim() ?
|
|
6016
|
+
mkdirSync12(codexHomeDir, { recursive: true });
|
|
6017
|
+
const hostCodexHome = process.env.CODEX_HOME?.trim() ? resolve26(process.env.CODEX_HOME) : process.env.HOME ? resolve26(process.env.HOME, ".codex") : "";
|
|
6198
6018
|
if (!hostCodexHome) {
|
|
6199
6019
|
return false;
|
|
6200
6020
|
}
|
|
6201
|
-
const hostAuthPath =
|
|
6202
|
-
if (!
|
|
6021
|
+
const hostAuthPath = resolve26(hostCodexHome, "auth.json");
|
|
6022
|
+
if (!existsSync25(hostAuthPath)) {
|
|
6203
6023
|
return false;
|
|
6204
6024
|
}
|
|
6205
|
-
const runtimeAuthPath =
|
|
6025
|
+
const runtimeAuthPath = resolve26(codexHomeDir, "auth.json");
|
|
6206
6026
|
copyFileSync5(hostAuthPath, runtimeAuthPath);
|
|
6207
6027
|
chmodSync5(runtimeAuthPath, 384);
|
|
6208
6028
|
return true;
|
|
6209
6029
|
}
|
|
6210
6030
|
async function injectPiAgentConfig(piAgentDir) {
|
|
6211
|
-
|
|
6212
|
-
const hostPiAgentDir = process.env.PI_CODING_AGENT_DIR?.trim() ?
|
|
6031
|
+
mkdirSync12(piAgentDir, { recursive: true });
|
|
6032
|
+
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
6033
|
if (!hostPiAgentDir) {
|
|
6214
6034
|
return false;
|
|
6215
6035
|
}
|
|
6216
|
-
const hostAuthPath =
|
|
6217
|
-
if (!
|
|
6036
|
+
const hostAuthPath = resolve26(hostPiAgentDir, "auth.json");
|
|
6037
|
+
if (!existsSync25(hostAuthPath)) {
|
|
6218
6038
|
return false;
|
|
6219
6039
|
}
|
|
6220
|
-
const runtimeAuthPath =
|
|
6040
|
+
const runtimeAuthPath = resolve26(piAgentDir, "auth.json");
|
|
6221
6041
|
copyFileSync5(hostAuthPath, runtimeAuthPath);
|
|
6222
6042
|
chmodSync5(runtimeAuthPath, 384);
|
|
6223
|
-
const hostSettingsPath =
|
|
6224
|
-
if (
|
|
6225
|
-
const runtimeSettingsPath =
|
|
6043
|
+
const hostSettingsPath = resolve26(hostPiAgentDir, "settings.json");
|
|
6044
|
+
if (existsSync25(hostSettingsPath)) {
|
|
6045
|
+
const runtimeSettingsPath = resolve26(piAgentDir, "settings.json");
|
|
6226
6046
|
copyFileSync5(hostSettingsPath, runtimeSettingsPath);
|
|
6227
6047
|
chmodSync5(runtimeSettingsPath, 384);
|
|
6228
6048
|
}
|
|
@@ -6230,8 +6050,8 @@ async function injectPiAgentConfig(piAgentDir) {
|
|
|
6230
6050
|
}
|
|
6231
6051
|
|
|
6232
6052
|
// packages/runtime/src/control-plane/runtime/tooling/claude-router.ts
|
|
6233
|
-
import { existsSync as
|
|
6234
|
-
import { resolve as
|
|
6053
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync13, statSync as statSync6, writeFileSync as writeFileSync11 } from "fs";
|
|
6054
|
+
import { resolve as resolve27 } from "path";
|
|
6235
6055
|
var CLAUDE_ROUTER_SERVER_NAME = "rig_runtime_tools";
|
|
6236
6056
|
var CLAUDE_DISABLED_FILE_TOOLS = [
|
|
6237
6057
|
"Read",
|
|
@@ -6329,7 +6149,7 @@ function claudeRuntimeToolCliArgs(configPath) {
|
|
|
6329
6149
|
function buildRuntimeToolRouterServerConfig(options) {
|
|
6330
6150
|
return {
|
|
6331
6151
|
type: "stdio",
|
|
6332
|
-
command:
|
|
6152
|
+
command: resolve27(options.binDir, "rig-tool-router"),
|
|
6333
6153
|
args: [],
|
|
6334
6154
|
env: {
|
|
6335
6155
|
RIG_RUNTIME_CONTEXT_FILE: options.contextFile,
|
|
@@ -6363,14 +6183,14 @@ function codexRuntimeToolCliArgs(options) {
|
|
|
6363
6183
|
];
|
|
6364
6184
|
}
|
|
6365
6185
|
function writeClaudeRuntimeToolRouterConfig(options) {
|
|
6366
|
-
const configPath =
|
|
6367
|
-
|
|
6186
|
+
const configPath = resolve27(options.stateDir, "claude-runtime-tools.mcp.json");
|
|
6187
|
+
mkdirSync13(options.stateDir, { recursive: true });
|
|
6368
6188
|
const payload = {
|
|
6369
6189
|
mcpServers: {
|
|
6370
6190
|
[CLAUDE_ROUTER_SERVER_NAME]: buildRuntimeToolRouterServerConfig(options)
|
|
6371
6191
|
}
|
|
6372
6192
|
};
|
|
6373
|
-
|
|
6193
|
+
writeFileSync11(configPath, `${JSON.stringify(payload, null, 2)}
|
|
6374
6194
|
`, "utf-8");
|
|
6375
6195
|
return configPath;
|
|
6376
6196
|
}
|
|
@@ -6457,7 +6277,7 @@ function resolveRuntimeToolBinary(toolName, env) {
|
|
|
6457
6277
|
grep: "rig-grep"
|
|
6458
6278
|
};
|
|
6459
6279
|
const executable = mapping[toolName];
|
|
6460
|
-
return executable ?
|
|
6280
|
+
return executable ? resolve27(binDir, executable) : "";
|
|
6461
6281
|
}
|
|
6462
6282
|
function renderToolText(toolName, payload) {
|
|
6463
6283
|
if (toolName === "shell") {
|
|
@@ -6522,10 +6342,10 @@ async function invokeRuntimeShellTool(args, options = {}) {
|
|
|
6522
6342
|
isError: true
|
|
6523
6343
|
};
|
|
6524
6344
|
}
|
|
6525
|
-
const workspaceRoot =
|
|
6345
|
+
const workspaceRoot = resolve27(invocationEnv.RIG_TASK_WORKSPACE?.trim() || process.cwd());
|
|
6526
6346
|
const requestedWorkdir = typeof args.workdir === "string" ? args.workdir.trim() : "";
|
|
6527
6347
|
const workdir = requestedWorkdir ? resolveWithinWorkspace(workspaceRoot, requestedWorkdir) : workspaceRoot;
|
|
6528
|
-
if (!
|
|
6348
|
+
if (!existsSync26(workdir)) {
|
|
6529
6349
|
return {
|
|
6530
6350
|
content: [{
|
|
6531
6351
|
type: "text",
|
|
@@ -6592,10 +6412,10 @@ async function invokeRuntimeShellTool(args, options = {}) {
|
|
|
6592
6412
|
}
|
|
6593
6413
|
function resolveRuntimeShellBinary(shellName, env) {
|
|
6594
6414
|
const binDir = env.RIG_RUNTIME_BIN_DIR?.trim() || "";
|
|
6595
|
-
return binDir ?
|
|
6415
|
+
return binDir ? resolve27(binDir, shellName) : "";
|
|
6596
6416
|
}
|
|
6597
6417
|
function resolveWithinWorkspace(workspaceRoot, target) {
|
|
6598
|
-
const resolvedTarget =
|
|
6418
|
+
const resolvedTarget = resolve27(workspaceRoot, normalizeWorkspaceRelativeTarget(target));
|
|
6599
6419
|
const normalizedWorkspace = workspaceRoot.endsWith("/") ? workspaceRoot : `${workspaceRoot}/`;
|
|
6600
6420
|
const normalizedTarget = resolvedTarget.endsWith("/") ? resolvedTarget : `${resolvedTarget}/`;
|
|
6601
6421
|
if (resolvedTarget === workspaceRoot || normalizedTarget.startsWith(normalizedWorkspace)) {
|
|
@@ -6633,8 +6453,8 @@ if (false) {}
|
|
|
6633
6453
|
init_layout();
|
|
6634
6454
|
|
|
6635
6455
|
// packages/runtime/src/control-plane/runtime/isolation/worktree.ts
|
|
6636
|
-
import { existsSync as
|
|
6637
|
-
import { dirname as dirname11, resolve as
|
|
6456
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync14, rmSync as rmSync10 } from "fs";
|
|
6457
|
+
import { dirname as dirname11, resolve as resolve28 } from "path";
|
|
6638
6458
|
async function resolveMonorepoBaseRef(monorepoRoot) {
|
|
6639
6459
|
const explicit = process.env.RIG_RUNTIME_BASE_REF?.trim();
|
|
6640
6460
|
if (explicit) {
|
|
@@ -6670,12 +6490,12 @@ function ensureProvisioningHostProjectRootEnv(projectRoot) {
|
|
|
6670
6490
|
}
|
|
6671
6491
|
async function provisionRuntimeWorktree(config) {
|
|
6672
6492
|
const branch = runtimeBranchName(config.taskId, config.runtimeId);
|
|
6673
|
-
let hasValidWorktree =
|
|
6674
|
-
if (
|
|
6675
|
-
|
|
6493
|
+
let hasValidWorktree = existsSync27(resolve28(config.workspaceDir, ".git")) && (await runGitCommand(config.workspaceDir, ["rev-parse", "--show-toplevel"])).exitCode === 0;
|
|
6494
|
+
if (existsSync27(config.workspaceDir) && !hasValidWorktree) {
|
|
6495
|
+
rmSync10(config.workspaceDir, { recursive: true, force: true });
|
|
6676
6496
|
}
|
|
6677
6497
|
if (!hasValidWorktree) {
|
|
6678
|
-
|
|
6498
|
+
mkdirSync14(dirname11(config.workspaceDir), { recursive: true });
|
|
6679
6499
|
const branchExists = await runGitCommand(config.monorepoRoot, ["show-ref", "--verify", "--quiet", `refs/heads/${branch}`]);
|
|
6680
6500
|
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
6501
|
if (add.exitCode !== 0) {
|
|
@@ -6851,31 +6671,31 @@ async function preferredBaseRemotes(repoRoot) {
|
|
|
6851
6671
|
|
|
6852
6672
|
// packages/runtime/src/control-plane/runtime/isolation/toolchain.ts
|
|
6853
6673
|
import {
|
|
6854
|
-
existsSync as
|
|
6674
|
+
existsSync as existsSync29,
|
|
6855
6675
|
lstatSync,
|
|
6856
|
-
mkdirSync as
|
|
6857
|
-
readdirSync as
|
|
6858
|
-
readFileSync as
|
|
6859
|
-
rmSync as
|
|
6676
|
+
mkdirSync as mkdirSync16,
|
|
6677
|
+
readdirSync as readdirSync6,
|
|
6678
|
+
readFileSync as readFileSync14,
|
|
6679
|
+
rmSync as rmSync11,
|
|
6860
6680
|
statSync as statSync8,
|
|
6861
6681
|
symlinkSync as symlinkSync4
|
|
6862
6682
|
} from "fs";
|
|
6863
6683
|
import { mkdir as mkdir2, writeFile } from "fs/promises";
|
|
6864
|
-
import { dirname as dirname13, resolve as
|
|
6684
|
+
import { dirname as dirname13, resolve as resolve30 } from "path";
|
|
6865
6685
|
|
|
6866
6686
|
// packages/runtime/src/control-plane/runtime/tooling/claude-router-binary.ts
|
|
6867
|
-
import { chmodSync as chmodSync6, copyFileSync as copyFileSync6, existsSync as
|
|
6687
|
+
import { chmodSync as chmodSync6, copyFileSync as copyFileSync6, existsSync as existsSync28, mkdirSync as mkdirSync15, statSync as statSync7 } from "fs";
|
|
6868
6688
|
import { tmpdir as tmpdir6 } from "os";
|
|
6869
|
-
import { dirname as dirname12, resolve as
|
|
6870
|
-
var sharedRouterOutputDir =
|
|
6871
|
-
var sharedRouterOutputPath =
|
|
6689
|
+
import { dirname as dirname12, resolve as resolve29 } from "path";
|
|
6690
|
+
var sharedRouterOutputDir = resolve29(tmpdir6(), "rig-native");
|
|
6691
|
+
var sharedRouterOutputPath = resolve29(sharedRouterOutputDir, `rig-tool-router-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
6872
6692
|
function runtimeClaudeToolRouterFileName() {
|
|
6873
6693
|
return `rig-tool-router${process.platform === "win32" ? ".exe" : ""}`;
|
|
6874
6694
|
}
|
|
6875
6695
|
async function ensureClaudeToolRouterBinaryPath(projectRoot, outputPath = sharedRouterOutputPath) {
|
|
6876
|
-
const sourcePath =
|
|
6877
|
-
|
|
6878
|
-
const needsBuild = !
|
|
6696
|
+
const sourcePath = resolve29(projectRoot, "packages/runtime/src/control-plane/runtime/tooling/claude-router.ts");
|
|
6697
|
+
mkdirSync15(dirname12(outputPath), { recursive: true });
|
|
6698
|
+
const needsBuild = !existsSync28(outputPath) || statSync7(sourcePath).mtimeMs > statSync7(outputPath).mtimeMs;
|
|
6879
6699
|
if (!needsBuild) {
|
|
6880
6700
|
return outputPath;
|
|
6881
6701
|
}
|
|
@@ -6889,9 +6709,9 @@ async function ensureClaudeToolRouterBinaryPath(projectRoot, outputPath = shared
|
|
|
6889
6709
|
}
|
|
6890
6710
|
async function materializeClaudeToolRouterBinary(projectRoot, targetDir) {
|
|
6891
6711
|
const sourcePath = await ensureClaudeToolRouterBinaryPath(projectRoot);
|
|
6892
|
-
const targetPath =
|
|
6893
|
-
|
|
6894
|
-
const needsCopy = !
|
|
6712
|
+
const targetPath = resolve29(targetDir, runtimeClaudeToolRouterFileName());
|
|
6713
|
+
mkdirSync15(targetDir, { recursive: true });
|
|
6714
|
+
const needsCopy = !existsSync28(targetPath) || statSync7(sourcePath).mtimeMs > statSync7(targetPath).mtimeMs;
|
|
6895
6715
|
if (needsCopy) {
|
|
6896
6716
|
copyFileSync6(sourcePath, targetPath);
|
|
6897
6717
|
chmodSync6(targetPath, 493);
|
|
@@ -6904,48 +6724,48 @@ var GIT_INDEX_LOCK_RETRY_DELAY_MS = 250;
|
|
|
6904
6724
|
var GIT_INDEX_LOCK_STALE_AFTER_MS = 5000;
|
|
6905
6725
|
function resolveRigSourceRoot(projectRoot) {
|
|
6906
6726
|
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim();
|
|
6907
|
-
if (hostProjectRoot &&
|
|
6727
|
+
if (hostProjectRoot && existsSync29(resolve30(hostProjectRoot, "packages/runtime/bin/rig-agent.ts"))) {
|
|
6908
6728
|
return hostProjectRoot;
|
|
6909
6729
|
}
|
|
6910
|
-
const fromModule =
|
|
6911
|
-
if (
|
|
6730
|
+
const fromModule = resolve30(import.meta.dir, "../../../../../..");
|
|
6731
|
+
if (existsSync29(resolve30(fromModule, "packages/runtime/bin/rig-agent.ts"))) {
|
|
6912
6732
|
return fromModule;
|
|
6913
6733
|
}
|
|
6914
6734
|
return projectRoot;
|
|
6915
6735
|
}
|
|
6916
6736
|
function prepareTrackedRuntimePaths(logsDir, stateDir, sessionDir) {
|
|
6917
|
-
for (const path of [logsDir, stateDir, sessionDir,
|
|
6737
|
+
for (const path of [logsDir, stateDir, sessionDir, resolve30(sessionDir, "session.json")]) {
|
|
6918
6738
|
removeSymbolicLink(path);
|
|
6919
6739
|
}
|
|
6920
6740
|
runtimePrepareTrackedPathsNative({
|
|
6921
6741
|
logsDir,
|
|
6922
6742
|
stateDir,
|
|
6923
6743
|
sessionDir,
|
|
6924
|
-
controlledBashLogFile:
|
|
6925
|
-
eventsFile:
|
|
6744
|
+
controlledBashLogFile: resolve30(logsDir, "controlled-bash.jsonl"),
|
|
6745
|
+
eventsFile: resolve30(logsDir, "control-plane.events.jsonl")
|
|
6926
6746
|
});
|
|
6927
6747
|
}
|
|
6928
6748
|
async function initializeRuntimeStateFiles(stateDir, sessionDir, taskId) {
|
|
6929
6749
|
await mkdir2(stateDir, { recursive: true });
|
|
6930
6750
|
await mkdir2(sessionDir, { recursive: true });
|
|
6931
|
-
const failedApproachesPath =
|
|
6932
|
-
if (!
|
|
6751
|
+
const failedApproachesPath = resolve30(stateDir, "failed_approaches.md");
|
|
6752
|
+
if (!existsSync29(failedApproachesPath)) {
|
|
6933
6753
|
await writeFile(failedApproachesPath, `# Failed Approaches
|
|
6934
6754
|
|
|
6935
6755
|
`);
|
|
6936
6756
|
}
|
|
6937
|
-
const hookTripsPath =
|
|
6938
|
-
if (!
|
|
6757
|
+
const hookTripsPath = resolve30(stateDir, "hook_trips.log");
|
|
6758
|
+
if (!existsSync29(hookTripsPath)) {
|
|
6939
6759
|
await writeFile(hookTripsPath, "");
|
|
6940
6760
|
}
|
|
6941
|
-
const sessionFile =
|
|
6761
|
+
const sessionFile = resolve30(sessionDir, "session.json");
|
|
6942
6762
|
if (taskId) {
|
|
6943
6763
|
await writeFile(sessionFile, JSON.stringify({ activeTaskIds: [taskId] }));
|
|
6944
6764
|
}
|
|
6945
6765
|
}
|
|
6946
6766
|
async function resetEphemeralTaskArtifacts(workspaceDir, taskId) {
|
|
6947
|
-
const artifactDir =
|
|
6948
|
-
const runtimeSnapshotDir =
|
|
6767
|
+
const artifactDir = resolve30(workspaceDir, "artifacts", taskId);
|
|
6768
|
+
const runtimeSnapshotDir = resolve30(artifactDir, "runtime-snapshots");
|
|
6949
6769
|
let preservedTrackedFiles = false;
|
|
6950
6770
|
for (const file of [
|
|
6951
6771
|
"changed-files.txt",
|
|
@@ -6961,13 +6781,13 @@ async function resetEphemeralTaskArtifacts(workspaceDir, taskId) {
|
|
|
6961
6781
|
preservedTrackedFiles = true;
|
|
6962
6782
|
continue;
|
|
6963
6783
|
}
|
|
6964
|
-
|
|
6784
|
+
rmSync11(resolve30(artifactDir, file), { force: true });
|
|
6965
6785
|
}
|
|
6966
6786
|
const runtimeSnapshotRelativePath = `artifacts/${taskId}/runtime-snapshots`;
|
|
6967
6787
|
if (await resetTrackedArtifactPath(workspaceDir, runtimeSnapshotRelativePath)) {
|
|
6968
6788
|
preservedTrackedFiles = true;
|
|
6969
6789
|
} else {
|
|
6970
|
-
|
|
6790
|
+
rmSync11(runtimeSnapshotDir, { recursive: true, force: true });
|
|
6971
6791
|
}
|
|
6972
6792
|
if (preservedTrackedFiles) {
|
|
6973
6793
|
console.log(`[rig-agent] Preserved tracked runtime artifact files in ${taskId}; skipped ephemeral cleanup for committed paths.`);
|
|
@@ -7000,28 +6820,28 @@ async function buildRuntimeToolchain(options) {
|
|
|
7000
6820
|
throw new Error("Failed to provision the native Zig runtime library.");
|
|
7001
6821
|
}
|
|
7002
6822
|
const rigSourceRoot = resolveRigSourceRoot(options.projectRoot);
|
|
7003
|
-
await buildBinary("packages/cli/bin/rig.ts",
|
|
7004
|
-
await buildBinary("packages/runtime/bin/rig-agent.ts",
|
|
6823
|
+
await buildBinary("packages/cli/bin/rig.ts", resolve30(options.binDir, "rig"), rigSourceRoot);
|
|
6824
|
+
await buildBinary("packages/runtime/bin/rig-agent.ts", resolve30(options.binDir, "rig-agent"), rigSourceRoot, {
|
|
7005
6825
|
...options.runtimeSecretDefines,
|
|
7006
6826
|
AGENT_TASK_ID: options.taskId,
|
|
7007
6827
|
AGENT_PROJECT_ROOT: options.projectRoot,
|
|
7008
6828
|
AGENT_RUNTIME_ID: options.runtimeId,
|
|
7009
6829
|
AGENT_SCOPE_HASH: options.bakedScopeHash,
|
|
7010
6830
|
AGENT_MANIFEST_PATH: options.manifestPath,
|
|
7011
|
-
AGENT_BINARY_PATH:
|
|
6831
|
+
AGENT_BINARY_PATH: resolve30(options.binDir, "rig-agent"),
|
|
7012
6832
|
AGENT_INFO_OUTPUT: options.bakedInfoOutput,
|
|
7013
6833
|
AGENT_DEPS_OUTPUT: options.bakedDepsOutput,
|
|
7014
6834
|
AGENT_STATUS_OUTPUT: options.bakedStatusOutput
|
|
7015
6835
|
});
|
|
7016
|
-
await buildBinary("packages/runtime/src/control-plane/controlled-bash.ts",
|
|
6836
|
+
await buildBinary("packages/runtime/src/control-plane/controlled-bash.ts", resolve30(options.binDir, "controlled-bash"), rigSourceRoot, {
|
|
7017
6837
|
AGENT_PROJECT_ROOT: options.projectRoot,
|
|
7018
6838
|
AGENT_LOGS_DIR: options.logsDir,
|
|
7019
6839
|
AGENT_MONOREPO_ROOT: resolveMonorepoRoot3(options.projectRoot),
|
|
7020
|
-
AGENT_TS_API_TESTS_DIR:
|
|
7021
|
-
AGENT_RIG_AGENT_BIN:
|
|
6840
|
+
AGENT_TS_API_TESTS_DIR: resolve30(options.workspaceDir, "TSAPITests"),
|
|
6841
|
+
AGENT_RIG_AGENT_BIN: resolve30(options.binDir, "rig-agent")
|
|
7022
6842
|
});
|
|
7023
|
-
await buildBinary("packages/runtime/bin/rig-browser-tool.ts",
|
|
7024
|
-
await buildBinary("packages/runtime/src/control-plane/runtime/snapshot/sidecar.ts",
|
|
6843
|
+
await buildBinary("packages/runtime/bin/rig-browser-tool.ts", resolve30(options.binDir, runtimeBrowserToolBinaryName()), rigSourceRoot);
|
|
6844
|
+
await buildBinary("packages/runtime/src/control-plane/runtime/snapshot/sidecar.ts", resolve30(options.binDir, "snapshot-sidecar"), rigSourceRoot, {
|
|
7025
6845
|
AGENT_PROJECT_ROOT: options.projectRoot,
|
|
7026
6846
|
AGENT_BUN_PATH: resolveBunBinaryPath()
|
|
7027
6847
|
});
|
|
@@ -7030,15 +6850,15 @@ async function buildRuntimeToolchain(options) {
|
|
|
7030
6850
|
AGENT_BUN_PATH: resolveBunBinaryPath()
|
|
7031
6851
|
};
|
|
7032
6852
|
for (const hookName of hookNames) {
|
|
7033
|
-
await buildBinary(`packages/runtime/src/control-plane/hooks/${hookName}.ts`,
|
|
6853
|
+
await buildBinary(`packages/runtime/src/control-plane/hooks/${hookName}.ts`, resolve30(runtimeBins.hooksDir, hookName), rigSourceRoot, hookDefines);
|
|
7034
6854
|
}
|
|
7035
|
-
const pluginsDir =
|
|
7036
|
-
if (
|
|
7037
|
-
for (const entry of
|
|
6855
|
+
const pluginsDir = resolve30(options.projectRoot, "rig/plugins");
|
|
6856
|
+
if (existsSync29(pluginsDir)) {
|
|
6857
|
+
for (const entry of readdirSync6(pluginsDir, { withFileTypes: true })) {
|
|
7038
6858
|
const match = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
7039
6859
|
if (!match)
|
|
7040
6860
|
continue;
|
|
7041
|
-
await buildBinary(`rig/plugins/${entry.name}`,
|
|
6861
|
+
await buildBinary(`rig/plugins/${entry.name}`, resolve30(runtimeBins.pluginsDir, match[1]), options.projectRoot);
|
|
7042
6862
|
}
|
|
7043
6863
|
}
|
|
7044
6864
|
await materializeRigGitBinary(options.binDir);
|
|
@@ -7048,8 +6868,8 @@ async function buildRuntimeToolchain(options) {
|
|
|
7048
6868
|
}
|
|
7049
6869
|
async function writeRuntimeManifest(config) {
|
|
7050
6870
|
const scopeHash = sha256Hex(JSON.stringify(config.scopes));
|
|
7051
|
-
const binarySha256 = sha256Hex(
|
|
7052
|
-
const manifestPath =
|
|
6871
|
+
const binarySha256 = sha256Hex(readFileSync14(config.binaryPath));
|
|
6872
|
+
const manifestPath = resolve30(config.runtimeRoot, "manifest.json");
|
|
7053
6873
|
const manifest = {
|
|
7054
6874
|
runtimeId: config.runtimeId,
|
|
7055
6875
|
taskId: config.taskId,
|
|
@@ -7083,7 +6903,7 @@ function removeSymbolicLink(path) {
|
|
|
7083
6903
|
} catch {
|
|
7084
6904
|
return;
|
|
7085
6905
|
}
|
|
7086
|
-
|
|
6906
|
+
rmSync11(path, { force: true, recursive: true });
|
|
7087
6907
|
}
|
|
7088
6908
|
async function resetTrackedArtifactPath(workspaceDir, relativePath) {
|
|
7089
6909
|
const tracked = await runGitLsFiles(workspaceDir, relativePath);
|
|
@@ -7109,7 +6929,7 @@ async function restoreTrackedArtifactPathWithRetry(workspaceDir, relativePath, r
|
|
|
7109
6929
|
const retryDelayMs = options.retryDelayMs ?? GIT_INDEX_LOCK_RETRY_DELAY_MS;
|
|
7110
6930
|
const now = options.now ?? Date.now;
|
|
7111
6931
|
const statMtimeMs = options.statMtimeMs ?? readFileMtimeMs;
|
|
7112
|
-
const removeFile = options.removeFile ?? ((path) =>
|
|
6932
|
+
const removeFile = options.removeFile ?? ((path) => rmSync11(path, { force: true }));
|
|
7113
6933
|
const log = options.log ?? console.warn;
|
|
7114
6934
|
let lastOutput = "";
|
|
7115
6935
|
for (let attempt = 0;attempt <= maxRetries; attempt += 1) {
|
|
@@ -7169,31 +6989,31 @@ function readFileMtimeMs(path) {
|
|
|
7169
6989
|
}
|
|
7170
6990
|
function linkRuntimeDependencyLayers(monorepoRoot, workspaceDir) {
|
|
7171
6991
|
linkGenericNodeModulesLayers(monorepoRoot, workspaceDir);
|
|
7172
|
-
const sourceNodeModules =
|
|
7173
|
-
if (!
|
|
7174
|
-
const runtimeHumoongate =
|
|
7175
|
-
if (
|
|
7176
|
-
const targetNodeModules =
|
|
6992
|
+
const sourceNodeModules = resolve30(monorepoRoot, "humoongate", "node_modules");
|
|
6993
|
+
if (!existsSync29(sourceNodeModules)) {} else {
|
|
6994
|
+
const runtimeHumoongate = resolve30(workspaceDir, "humoongate");
|
|
6995
|
+
if (existsSync29(resolve30(runtimeHumoongate, "package.json"))) {
|
|
6996
|
+
const targetNodeModules = resolve30(runtimeHumoongate, "node_modules");
|
|
7177
6997
|
runtimeLinkDependencyLayerNative(sourceNodeModules, targetNodeModules);
|
|
7178
6998
|
}
|
|
7179
6999
|
}
|
|
7180
|
-
const runtimeHpNext =
|
|
7181
|
-
if (!
|
|
7000
|
+
const runtimeHpNext = resolve30(workspaceDir, "microservices", "hp-next-frontend", "app");
|
|
7001
|
+
if (!existsSync29(resolve30(runtimeHpNext, "package.json"))) {
|
|
7182
7002
|
return;
|
|
7183
7003
|
}
|
|
7184
|
-
const sourceHpNextNodeModules =
|
|
7185
|
-
const sourceMonorepoNodeModules =
|
|
7186
|
-
const targetHpNextNodeModules =
|
|
7187
|
-
if (
|
|
7004
|
+
const sourceHpNextNodeModules = resolve30(monorepoRoot, "microservices", "hp-next-frontend", "app", "node_modules");
|
|
7005
|
+
const sourceMonorepoNodeModules = resolve30(monorepoRoot, "node_modules");
|
|
7006
|
+
const targetHpNextNodeModules = resolve30(runtimeHpNext, "node_modules");
|
|
7007
|
+
if (existsSync29(sourceHpNextNodeModules)) {
|
|
7188
7008
|
runtimeLinkDependencyLayerNative(sourceHpNextNodeModules, targetHpNextNodeModules);
|
|
7189
7009
|
return;
|
|
7190
7010
|
}
|
|
7191
|
-
if (
|
|
7011
|
+
if (existsSync29(sourceMonorepoNodeModules)) {
|
|
7192
7012
|
runtimeLinkDependencyLayerNative(sourceMonorepoNodeModules, targetHpNextNodeModules);
|
|
7193
7013
|
}
|
|
7194
7014
|
}
|
|
7195
7015
|
function linkGenericNodeModulesLayers(monorepoRoot, workspaceDir) {
|
|
7196
|
-
linkNodeModulesLayer(
|
|
7016
|
+
linkNodeModulesLayer(resolve30(monorepoRoot, "node_modules"), resolve30(workspaceDir, "node_modules"));
|
|
7197
7017
|
for (const relativePackageDir of [
|
|
7198
7018
|
"apps/native-app/apps/marketing",
|
|
7199
7019
|
"apps/native-app/apps/web",
|
|
@@ -7215,15 +7035,15 @@ function linkGenericNodeModulesLayers(monorepoRoot, workspaceDir) {
|
|
|
7215
7035
|
"packages/standard-plugin",
|
|
7216
7036
|
"packages/validator-kit"
|
|
7217
7037
|
]) {
|
|
7218
|
-
const workspacePackageDir =
|
|
7219
|
-
if (!
|
|
7038
|
+
const workspacePackageDir = resolve30(workspaceDir, relativePackageDir);
|
|
7039
|
+
if (!existsSync29(resolve30(workspacePackageDir, "package.json"))) {
|
|
7220
7040
|
continue;
|
|
7221
7041
|
}
|
|
7222
|
-
linkNodeModulesLayer(
|
|
7042
|
+
linkNodeModulesLayer(resolve30(monorepoRoot, relativePackageDir, "node_modules"), resolve30(workspacePackageDir, "node_modules"));
|
|
7223
7043
|
}
|
|
7224
7044
|
}
|
|
7225
7045
|
function linkNodeModulesLayer(sourceDir, targetDir) {
|
|
7226
|
-
if (!
|
|
7046
|
+
if (!existsSync29(sourceDir) || existsSync29(targetDir)) {
|
|
7227
7047
|
return;
|
|
7228
7048
|
}
|
|
7229
7049
|
try {
|
|
@@ -7232,30 +7052,30 @@ function linkNodeModulesLayer(sourceDir, targetDir) {
|
|
|
7232
7052
|
} catch (error) {
|
|
7233
7053
|
console.warn(`[rig-agent] Native dependency-layer linking failed for ${targetDir}; using symlink fallback: ${error instanceof Error ? error.message : String(error)}`);
|
|
7234
7054
|
}
|
|
7235
|
-
|
|
7055
|
+
mkdirSync16(dirname13(targetDir), { recursive: true });
|
|
7236
7056
|
symlinkSync4(sourceDir, targetDir, "dir");
|
|
7237
7057
|
}
|
|
7238
7058
|
function ensureRuntimeBinTrees(runtimeBinDir) {
|
|
7239
|
-
const hooksDir =
|
|
7240
|
-
const pluginsDir =
|
|
7241
|
-
const validatorsDir =
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7059
|
+
const hooksDir = resolve30(runtimeBinDir, "hooks");
|
|
7060
|
+
const pluginsDir = resolve30(runtimeBinDir, "plugins");
|
|
7061
|
+
const validatorsDir = resolve30(runtimeBinDir, "validators");
|
|
7062
|
+
mkdirSync16(hooksDir, { recursive: true });
|
|
7063
|
+
mkdirSync16(pluginsDir, { recursive: true });
|
|
7064
|
+
mkdirSync16(validatorsDir, { recursive: true });
|
|
7245
7065
|
return { hooksDir, pluginsDir, validatorsDir };
|
|
7246
7066
|
}
|
|
7247
7067
|
|
|
7248
7068
|
// packages/runtime/src/control-plane/runtime/isolation/runner.ts
|
|
7249
|
-
import { existsSync as
|
|
7250
|
-
import { basename as basename9, resolve as
|
|
7069
|
+
import { existsSync as existsSync32, rmSync as rmSync12, writeFileSync as writeFileSync13 } from "fs";
|
|
7070
|
+
import { basename as basename9, resolve as resolve34 } from "path";
|
|
7251
7071
|
|
|
7252
7072
|
// packages/runtime/src/control-plane/runtime/sandbox/backend.ts
|
|
7253
|
-
import { existsSync as
|
|
7073
|
+
import { existsSync as existsSync31 } from "fs";
|
|
7254
7074
|
|
|
7255
7075
|
// packages/runtime/src/control-plane/runtime/guard.ts
|
|
7256
7076
|
import { optimizeNextInvocation } from "bun:jsc";
|
|
7257
|
-
import { existsSync as
|
|
7258
|
-
import { resolve as
|
|
7077
|
+
import { existsSync as existsSync30, readFileSync as readFileSync15, statSync as statSync9 } from "fs";
|
|
7078
|
+
import { resolve as resolve31 } from "path";
|
|
7259
7079
|
|
|
7260
7080
|
// packages/runtime/src/control-plane/runtime/guard-types.ts
|
|
7261
7081
|
var POLICY_VERSION = 1;
|
|
@@ -7318,8 +7138,8 @@ function loadPolicy(projectRoot) {
|
|
|
7318
7138
|
if (seededPolicyConfig) {
|
|
7319
7139
|
return seededPolicyConfig;
|
|
7320
7140
|
}
|
|
7321
|
-
const configPath =
|
|
7322
|
-
if (!
|
|
7141
|
+
const configPath = resolve31(projectRoot, "rig/policy/policy.json");
|
|
7142
|
+
if (!existsSync30(configPath)) {
|
|
7323
7143
|
return defaultPolicy();
|
|
7324
7144
|
}
|
|
7325
7145
|
let mtimeMs;
|
|
@@ -7333,7 +7153,7 @@ function loadPolicy(projectRoot) {
|
|
|
7333
7153
|
}
|
|
7334
7154
|
let parsed;
|
|
7335
7155
|
try {
|
|
7336
|
-
parsed = JSON.parse(
|
|
7156
|
+
parsed = JSON.parse(readFileSync15(configPath, "utf-8"));
|
|
7337
7157
|
} catch {
|
|
7338
7158
|
return defaultPolicy();
|
|
7339
7159
|
}
|
|
@@ -7549,28 +7369,28 @@ function resolveAction(mode, matched) {
|
|
|
7549
7369
|
}
|
|
7550
7370
|
function resolveAbsolutePath(projectRoot, rawPath) {
|
|
7551
7371
|
if (rawPath.startsWith("/"))
|
|
7552
|
-
return
|
|
7553
|
-
return
|
|
7372
|
+
return resolve31(rawPath);
|
|
7373
|
+
return resolve31(projectRoot, rawPath);
|
|
7554
7374
|
}
|
|
7555
7375
|
function isHarnessPath(projectRoot, rawPath) {
|
|
7556
7376
|
const absPath = resolveAbsolutePath(projectRoot, rawPath);
|
|
7557
7377
|
const managedRoots = [
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7378
|
+
resolve31(projectRoot, "rig"),
|
|
7379
|
+
resolve31(projectRoot, ".rig"),
|
|
7380
|
+
resolve31(projectRoot, "artifacts")
|
|
7561
7381
|
];
|
|
7562
7382
|
return managedRoots.some((root) => absPath === root || absPath.startsWith(root + "/"));
|
|
7563
7383
|
}
|
|
7564
7384
|
function isRuntimePath(projectRoot, rawPath, taskWorkspace) {
|
|
7565
7385
|
const absPath = resolveAbsolutePath(projectRoot, rawPath);
|
|
7566
7386
|
if (taskWorkspace) {
|
|
7567
|
-
const workspaceRigRoot =
|
|
7568
|
-
const workspaceArtifactsRoot =
|
|
7387
|
+
const workspaceRigRoot = resolve31(taskWorkspace, ".rig");
|
|
7388
|
+
const workspaceArtifactsRoot = resolve31(taskWorkspace, "artifacts");
|
|
7569
7389
|
if (absPath === workspaceRigRoot || absPath.startsWith(workspaceRigRoot + "/") || absPath === workspaceArtifactsRoot || absPath.startsWith(workspaceArtifactsRoot + "/")) {
|
|
7570
7390
|
return true;
|
|
7571
7391
|
}
|
|
7572
7392
|
}
|
|
7573
|
-
const runtimeRoot =
|
|
7393
|
+
const runtimeRoot = resolve31(projectRoot, ".rig/runtime/agents");
|
|
7574
7394
|
return absPath === runtimeRoot || absPath.startsWith(runtimeRoot + "/");
|
|
7575
7395
|
}
|
|
7576
7396
|
function isTestFile(path) {
|
|
@@ -7618,7 +7438,7 @@ function evaluateScope(policy, context, filePath, access) {
|
|
|
7618
7438
|
return allowed();
|
|
7619
7439
|
}
|
|
7620
7440
|
if (context.taskWorkspace && context.taskWorkspace !== context.projectRoot && filePath.startsWith("/")) {
|
|
7621
|
-
const absPath =
|
|
7441
|
+
const absPath = resolve31(filePath);
|
|
7622
7442
|
if (!absPath.startsWith(context.taskWorkspace + "/") && !isHarnessPath(context.projectRoot, filePath)) {
|
|
7623
7443
|
const reason2 = `Absolute path '${filePath}' is outside task runtime boundary. Allowed root: ${context.taskWorkspace}`;
|
|
7624
7444
|
const matched2 = [{ id: "scope:workspace-boundary", category: "command", reason: reason2 }];
|
|
@@ -7946,13 +7766,13 @@ async function resolveBackend(projectRoot, options) {
|
|
|
7946
7766
|
depRoots
|
|
7947
7767
|
};
|
|
7948
7768
|
const fsContext = {
|
|
7949
|
-
pathExists: (p) =>
|
|
7769
|
+
pathExists: (p) => existsSync31(p),
|
|
7950
7770
|
realPath: toRealPath
|
|
7951
7771
|
};
|
|
7952
7772
|
if (process.platform === "darwin" && (!requestedBackend || requestedBackend === "macos-seatbelt")) {
|
|
7953
7773
|
const seatbelt = Bun.which("sandbox-exec");
|
|
7954
7774
|
probed.push("sandbox-exec");
|
|
7955
|
-
if (seatbelt &&
|
|
7775
|
+
if (seatbelt && existsSync31(seatbelt)) {
|
|
7956
7776
|
const SeatbeltBackendClass = loadSeatbeltBackend();
|
|
7957
7777
|
if (SeatbeltBackendClass) {
|
|
7958
7778
|
return {
|
|
@@ -8073,10 +7893,10 @@ init_layout();
|
|
|
8073
7893
|
var SNAPSHOT_SIDECAR_READY_TIMEOUT_MS = 1e4;
|
|
8074
7894
|
async function startRuntimeSnapshotSidecar(runtime, options = {}) {
|
|
8075
7895
|
const instanceId = sanitizeRuntimeRefSegment(options.instanceId?.trim() || runtime.id);
|
|
8076
|
-
const readyFile =
|
|
8077
|
-
const requestFile =
|
|
8078
|
-
|
|
8079
|
-
|
|
7896
|
+
const readyFile = resolve34(runtime.stateDir, `runtime-snapshot-sidecar-${instanceId}.ready`);
|
|
7897
|
+
const requestFile = resolve34(runtime.stateDir, `runtime-snapshot-sidecar-${instanceId}.request.json`);
|
|
7898
|
+
rmSync12(readyFile, { force: true });
|
|
7899
|
+
rmSync12(requestFile, { force: true });
|
|
8080
7900
|
const sidecarBinary = resolveSnapshotSidecarBinaryPath(runtime.binDir);
|
|
8081
7901
|
const useCompiledSidecar = shouldUseCompiledSnapshotSidecar(sidecarBinary);
|
|
8082
7902
|
const bunCli = useCompiledSidecar ? null : resolveBunCliInvocation();
|
|
@@ -8114,19 +7934,19 @@ async function startRuntimeSnapshotSidecar(runtime, options = {}) {
|
|
|
8114
7934
|
proc.kill("SIGTERM");
|
|
8115
7935
|
} catch {}
|
|
8116
7936
|
await proc.exited;
|
|
8117
|
-
|
|
8118
|
-
|
|
7937
|
+
rmSync12(readyFile, { force: true });
|
|
7938
|
+
rmSync12(requestFile, { force: true });
|
|
8119
7939
|
},
|
|
8120
7940
|
finalize: async (commandParts, exitCode) => {
|
|
8121
|
-
|
|
7941
|
+
writeFileSync13(requestFile, `${JSON.stringify({ command: commandParts, exitCode })}
|
|
8122
7942
|
`, "utf-8");
|
|
8123
7943
|
const [sidecarExitCode, stdout, stderr] = await Promise.all([
|
|
8124
7944
|
proc.exited,
|
|
8125
7945
|
stdoutTextPromise,
|
|
8126
7946
|
stderrTextPromise
|
|
8127
7947
|
]);
|
|
8128
|
-
|
|
8129
|
-
|
|
7948
|
+
rmSync12(readyFile, { force: true });
|
|
7949
|
+
rmSync12(requestFile, { force: true });
|
|
8130
7950
|
if (sidecarExitCode !== 0) {
|
|
8131
7951
|
throw new Error(`snapshot sidecar failed (${sidecarExitCode}): ${stderr || stdout}`);
|
|
8132
7952
|
}
|
|
@@ -8146,10 +7966,10 @@ function resolveSnapshotSidecarScriptPath() {
|
|
|
8146
7966
|
return resolveRuntimeSourceScriptPath("snapshot-sidecar.ts");
|
|
8147
7967
|
}
|
|
8148
7968
|
function resolveSnapshotSidecarBinaryPath(binDir) {
|
|
8149
|
-
return
|
|
7969
|
+
return resolve34(binDir, "snapshot-sidecar");
|
|
8150
7970
|
}
|
|
8151
7971
|
function shouldUseCompiledSnapshotSidecar(binaryPath) {
|
|
8152
|
-
if (!
|
|
7972
|
+
if (!existsSync32(binaryPath)) {
|
|
8153
7973
|
return false;
|
|
8154
7974
|
}
|
|
8155
7975
|
const preference = process.env.RIG_USE_COMPILED_SNAPSHOT_SIDECAR?.trim().toLowerCase();
|
|
@@ -8164,12 +7984,12 @@ function resolveRuntimeSourceScriptPath(fileName) {
|
|
|
8164
7984
|
process.env.PROJECT_RIG_ROOT?.trim()
|
|
8165
7985
|
].filter((value) => Boolean(value));
|
|
8166
7986
|
for (const root of hostRoots) {
|
|
8167
|
-
const candidate =
|
|
8168
|
-
if (
|
|
7987
|
+
const candidate = resolve34(root, "packages/runtime/src/control-plane/runtime", fileName);
|
|
7988
|
+
if (existsSync32(candidate)) {
|
|
8169
7989
|
return candidate;
|
|
8170
7990
|
}
|
|
8171
7991
|
}
|
|
8172
|
-
return
|
|
7992
|
+
return resolve34(import.meta.dir, "..", fileName);
|
|
8173
7993
|
}
|
|
8174
7994
|
function resolveBunCliInvocation() {
|
|
8175
7995
|
if (process.env.RIG_BUN_PATH?.trim()) {
|
|
@@ -8196,7 +8016,7 @@ function resolveBunCliInvocation() {
|
|
|
8196
8016
|
async function waitForSnapshotSidecarReady(readyFile, proc, stdoutTextPromise, stderrTextPromise) {
|
|
8197
8017
|
const deadline = Date.now() + SNAPSHOT_SIDECAR_READY_TIMEOUT_MS;
|
|
8198
8018
|
while (Date.now() < deadline) {
|
|
8199
|
-
if (
|
|
8019
|
+
if (existsSync32(readyFile)) {
|
|
8200
8020
|
return;
|
|
8201
8021
|
}
|
|
8202
8022
|
const exitCode = proc.exitCode;
|
|
@@ -8214,9 +8034,9 @@ var CANONICAL_MEMORY_DB_PATH2 = "rig/memory/project-memory.db";
|
|
|
8214
8034
|
async function hydrateRuntimeMemory(options) {
|
|
8215
8035
|
const snapshot = await readCanonicalMemoryDb(options.projectRoot);
|
|
8216
8036
|
const workspaceLayout = resolveRuntimeWorkspaceLayout(options.workspaceDir);
|
|
8217
|
-
const hydratedPath =
|
|
8037
|
+
const hydratedPath = resolve35(workspaceLayout.stateDir, "memory", "project-memory.db");
|
|
8218
8038
|
try {
|
|
8219
|
-
await mkdir3(
|
|
8039
|
+
await mkdir3(resolve35(workspaceLayout.stateDir, "memory"), { recursive: true });
|
|
8220
8040
|
await copyFile(snapshot.dbPath, hydratedPath);
|
|
8221
8041
|
return {
|
|
8222
8042
|
canonicalPath: CANONICAL_MEMORY_DB_PATH2,
|
|
@@ -8231,12 +8051,12 @@ async function hydrateRuntimeMemory(options) {
|
|
|
8231
8051
|
}
|
|
8232
8052
|
}
|
|
8233
8053
|
async function createRuntimeTaskRecordReader(options) {
|
|
8234
|
-
const legacyConfigPath =
|
|
8054
|
+
const legacyConfigPath = resolve35(options.projectRoot, ".rig", "task-config.json");
|
|
8235
8055
|
let pluginHostContext = null;
|
|
8236
8056
|
try {
|
|
8237
8057
|
pluginHostContext = await buildPluginHostContext(options.projectRoot);
|
|
8238
8058
|
} catch (error) {
|
|
8239
|
-
if (!
|
|
8059
|
+
if (!existsSync33(legacyConfigPath)) {
|
|
8240
8060
|
throw error;
|
|
8241
8061
|
}
|
|
8242
8062
|
const message = `Plugin task source unavailable; using source-aware .rig/task-config.json compatibility path: ${error instanceof Error ? error.message : String(error)}`;
|
|
@@ -8256,7 +8076,7 @@ async function createRuntimeTaskRecordReader(options) {
|
|
|
8256
8076
|
source: "plugin"
|
|
8257
8077
|
};
|
|
8258
8078
|
}
|
|
8259
|
-
if (
|
|
8079
|
+
if (existsSync33(legacyConfigPath)) {
|
|
8260
8080
|
const message = "Using source-aware .rig/task-config.json task source compatibility path";
|
|
8261
8081
|
options.diagnostics?.(message);
|
|
8262
8082
|
console.warn(message);
|
|
@@ -8273,10 +8093,10 @@ async function createRuntimeTaskRecordReader(options) {
|
|
|
8273
8093
|
};
|
|
8274
8094
|
}
|
|
8275
8095
|
function readConfiguredTaskSourceKindHint(projectRoot) {
|
|
8276
|
-
const jsonPath =
|
|
8277
|
-
if (
|
|
8096
|
+
const jsonPath = resolve35(projectRoot, "rig.config.json");
|
|
8097
|
+
if (existsSync33(jsonPath)) {
|
|
8278
8098
|
try {
|
|
8279
|
-
const parsed = JSON.parse(
|
|
8099
|
+
const parsed = JSON.parse(readFileSync16(jsonPath, "utf8"));
|
|
8280
8100
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
8281
8101
|
const taskSource = parsed.taskSource;
|
|
8282
8102
|
if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
|
|
@@ -8288,12 +8108,12 @@ function readConfiguredTaskSourceKindHint(projectRoot) {
|
|
|
8288
8108
|
return null;
|
|
8289
8109
|
}
|
|
8290
8110
|
}
|
|
8291
|
-
const tsPath =
|
|
8292
|
-
if (!
|
|
8111
|
+
const tsPath = resolve35(projectRoot, "rig.config.ts");
|
|
8112
|
+
if (!existsSync33(tsPath)) {
|
|
8293
8113
|
return null;
|
|
8294
8114
|
}
|
|
8295
8115
|
try {
|
|
8296
|
-
const source =
|
|
8116
|
+
const source = readFileSync16(tsPath, "utf8");
|
|
8297
8117
|
const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
|
|
8298
8118
|
const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
|
|
8299
8119
|
return kind ?? null;
|
|
@@ -8363,8 +8183,8 @@ async function writeRuntimeTaskConfigProjection(options) {
|
|
|
8363
8183
|
...options.taskEntry.validation && options.taskEntry.validation.length > 0 ? { validation: options.taskEntry.validation } : {},
|
|
8364
8184
|
...options.taskEntry.browser ? { browser: options.taskEntry.browser } : {}
|
|
8365
8185
|
};
|
|
8366
|
-
const configPath =
|
|
8367
|
-
await mkdir3(
|
|
8186
|
+
const configPath = resolve35(options.workspaceDir, ".rig", "task-config.json");
|
|
8187
|
+
await mkdir3(resolve35(options.workspaceDir, ".rig"), { recursive: true });
|
|
8368
8188
|
await writeFile2(configPath, `${JSON.stringify({ [options.task.id]: entry }, null, 2)}
|
|
8369
8189
|
`, "utf-8");
|
|
8370
8190
|
}
|
|
@@ -8428,9 +8248,9 @@ async function ensureAgentRuntime(options) {
|
|
|
8428
8248
|
}
|
|
8429
8249
|
ensureProvisioningHostProjectRootEnv(options.projectRoot);
|
|
8430
8250
|
const monorepoRoot = resolveMonorepoRoot3(options.projectRoot);
|
|
8431
|
-
const workspaceDir =
|
|
8251
|
+
const workspaceDir = resolve35(monorepoRoot, ".worktrees", runtimeWorktreeName(options.taskId, options.id));
|
|
8432
8252
|
const createdAt = new Date().toISOString();
|
|
8433
|
-
if (!
|
|
8253
|
+
if (!existsSync33(resolve35(monorepoRoot, ".git"))) {
|
|
8434
8254
|
throw new Error(`Monorepo root is not a git checkout: ${monorepoRoot}`);
|
|
8435
8255
|
}
|
|
8436
8256
|
const taskResolution = await resolveRuntimeTaskRecord({
|
|
@@ -8465,7 +8285,7 @@ async function ensureAgentRuntime(options) {
|
|
|
8465
8285
|
logsDir: overlay.logsDir,
|
|
8466
8286
|
stateDir: overlay.stateDir,
|
|
8467
8287
|
sessionDir: overlay.sessionDir,
|
|
8468
|
-
claudeHomeDir:
|
|
8288
|
+
claudeHomeDir: resolve35(workspaceLayout.homeDir, ".claude"),
|
|
8469
8289
|
contextFile: overlay.contextPath,
|
|
8470
8290
|
binDir: workspaceLayout.binDir,
|
|
8471
8291
|
createdAt
|
|
@@ -8478,10 +8298,14 @@ async function ensureAgentRuntime(options) {
|
|
|
8478
8298
|
projectRoot: options.projectRoot,
|
|
8479
8299
|
workspaceDir
|
|
8480
8300
|
});
|
|
8481
|
-
|
|
8482
|
-
|
|
8301
|
+
mkdirSync19(runtime.binDir, { recursive: true });
|
|
8302
|
+
mkdirSync19(workspaceLayout.distDir, { recursive: true });
|
|
8483
8303
|
prepareRuntimeWorkspace(options.projectRoot, workspaceDir);
|
|
8484
|
-
|
|
8304
|
+
if (options.preserveTaskArtifacts) {
|
|
8305
|
+
console.log(`[rig-agent] Preserving runtime task artifacts for resume of ${options.taskId}.`);
|
|
8306
|
+
} else {
|
|
8307
|
+
await resetEphemeralTaskArtifacts(workspaceDir, options.taskId);
|
|
8308
|
+
}
|
|
8485
8309
|
const ctx = {
|
|
8486
8310
|
runtimeId: options.id,
|
|
8487
8311
|
taskId: options.taskId,
|
|
@@ -8494,7 +8318,7 @@ async function ensureAgentRuntime(options) {
|
|
|
8494
8318
|
runtimeId: options.id
|
|
8495
8319
|
}),
|
|
8496
8320
|
workspaceDir,
|
|
8497
|
-
artifactRoot:
|
|
8321
|
+
artifactRoot: resolve35(workspaceDir, "artifacts", options.taskId),
|
|
8498
8322
|
hostProjectRoot: options.projectRoot,
|
|
8499
8323
|
monorepoMainRoot: monorepoRoot,
|
|
8500
8324
|
monorepoBaseRef: baseRef,
|
|
@@ -8510,8 +8334,8 @@ async function ensureAgentRuntime(options) {
|
|
|
8510
8334
|
stateDir: overlay.stateDir,
|
|
8511
8335
|
logsDir: overlay.logsDir,
|
|
8512
8336
|
sessionDir: overlay.sessionDir,
|
|
8513
|
-
sessionFile:
|
|
8514
|
-
policyFile:
|
|
8337
|
+
sessionFile: resolve35(overlay.sessionDir, "session.json"),
|
|
8338
|
+
policyFile: resolve35(options.projectRoot, "rig/policy/policy.json"),
|
|
8515
8339
|
binDir: runtime.binDir,
|
|
8516
8340
|
createdAt,
|
|
8517
8341
|
memory
|
|
@@ -8522,9 +8346,9 @@ async function ensureAgentRuntime(options) {
|
|
|
8522
8346
|
task: taskResolution.task,
|
|
8523
8347
|
taskEntry
|
|
8524
8348
|
});
|
|
8525
|
-
const manifestPath =
|
|
8349
|
+
const manifestPath = resolve35(runtimeRoot, "manifest.json");
|
|
8526
8350
|
const bakedScopeHash = sha256Hex(JSON.stringify(taskEntry.scope || []));
|
|
8527
|
-
const runtimeAgentBinary =
|
|
8351
|
+
const runtimeAgentBinary = resolve35(runtime.binDir, "rig-agent");
|
|
8528
8352
|
await ensureRigGitBinaryPath();
|
|
8529
8353
|
const bakedInfoOutput = await captureTaskInfoOutput({
|
|
8530
8354
|
projectRoot: options.projectRoot,
|
|
@@ -8539,10 +8363,10 @@ async function ensureAgentRuntime(options) {
|
|
|
8539
8363
|
const bakedStatusOutput = await captureStdout(async () => {
|
|
8540
8364
|
taskStatus(options.projectRoot);
|
|
8541
8365
|
});
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8366
|
+
rmSync13(runtime.binDir, { recursive: true, force: true });
|
|
8367
|
+
rmSync13(workspaceLayout.distDir, { recursive: true, force: true });
|
|
8368
|
+
mkdirSync19(runtime.binDir, { recursive: true });
|
|
8369
|
+
mkdirSync19(workspaceLayout.distDir, { recursive: true });
|
|
8546
8370
|
await buildRuntimeToolchain({
|
|
8547
8371
|
projectRoot: options.projectRoot,
|
|
8548
8372
|
workspaceDir,
|
|
@@ -8579,9 +8403,9 @@ async function ensureAgentRuntime(options) {
|
|
|
8579
8403
|
workspaceDir,
|
|
8580
8404
|
taskEntry
|
|
8581
8405
|
});
|
|
8582
|
-
const sandboxDir =
|
|
8406
|
+
const sandboxDir = resolve35(runtimeRoot, "sandbox");
|
|
8583
8407
|
await mkdir3(sandboxDir, { recursive: true });
|
|
8584
|
-
await writeFile2(
|
|
8408
|
+
await writeFile2(resolve35(runtimeRoot, "runtime.json"), JSON.stringify({
|
|
8585
8409
|
id: options.id,
|
|
8586
8410
|
taskId: options.taskId,
|
|
8587
8411
|
mode: "worktree",
|
|
@@ -8688,8 +8512,8 @@ async function runCodexAppServerTaskRun(options) {
|
|
|
8688
8512
|
const sendRequest = async (method, params) => {
|
|
8689
8513
|
const id = nextRequestId;
|
|
8690
8514
|
nextRequestId += 1;
|
|
8691
|
-
const resultPromise = new Promise((
|
|
8692
|
-
pendingResponses.set(id, { resolve:
|
|
8515
|
+
const resultPromise = new Promise((resolve36, reject) => {
|
|
8516
|
+
pendingResponses.set(id, { resolve: resolve36, reject });
|
|
8693
8517
|
});
|
|
8694
8518
|
await sendMessage({ id, method, params });
|
|
8695
8519
|
return resultPromise;
|
|
@@ -8888,8 +8712,8 @@ async function runCodexAppServerTaskRun(options) {
|
|
|
8888
8712
|
console.error(line);
|
|
8889
8713
|
}
|
|
8890
8714
|
});
|
|
8891
|
-
const exitPromise = new Promise((
|
|
8892
|
-
child.once("close", (code, signal) =>
|
|
8715
|
+
const exitPromise = new Promise((resolve36) => {
|
|
8716
|
+
child.once("close", (code, signal) => resolve36({ code, signal }));
|
|
8893
8717
|
});
|
|
8894
8718
|
await sendRequest("initialize", {
|
|
8895
8719
|
clientInfo: DEFAULT_CLIENT_INFO,
|
|
@@ -8930,7 +8754,7 @@ async function runCodexAppServerTaskRun(options) {
|
|
|
8930
8754
|
while (!completionState.current) {
|
|
8931
8755
|
exitResult = await Promise.race([
|
|
8932
8756
|
exitPromise,
|
|
8933
|
-
new Promise((
|
|
8757
|
+
new Promise((resolve36) => setTimeout(() => resolve36(null), 100))
|
|
8934
8758
|
]);
|
|
8935
8759
|
if (exitResult) {
|
|
8936
8760
|
break;
|
|
@@ -9079,13 +8903,13 @@ function sanitizeEnv(env) {
|
|
|
9079
8903
|
return next;
|
|
9080
8904
|
}
|
|
9081
8905
|
function writeChildLine(child, line) {
|
|
9082
|
-
return new Promise((
|
|
8906
|
+
return new Promise((resolve36, reject) => {
|
|
9083
8907
|
child.stdin.write(line, (error) => {
|
|
9084
8908
|
if (error) {
|
|
9085
8909
|
reject(error);
|
|
9086
8910
|
return;
|
|
9087
8911
|
}
|
|
9088
|
-
|
|
8912
|
+
resolve36();
|
|
9089
8913
|
});
|
|
9090
8914
|
});
|
|
9091
8915
|
}
|
|
@@ -9131,7 +8955,175 @@ function formatJsonRpcError(error) {
|
|
|
9131
8955
|
return parts.join(" ");
|
|
9132
8956
|
}
|
|
9133
8957
|
|
|
8958
|
+
// packages/runtime/src/control-plane/pi-sessiond/launcher.ts
|
|
8959
|
+
import { randomBytes } from "crypto";
|
|
8960
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync20, readFileSync as readFileSync17, rmSync as rmSync14 } from "fs";
|
|
8961
|
+
import { dirname as dirname14, resolve as resolve36 } from "path";
|
|
8962
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8963
|
+
|
|
8964
|
+
// packages/runtime/src/control-plane/pi-sessiond/client.ts
|
|
8965
|
+
class RigPiSessionDaemonClient {
|
|
8966
|
+
baseUrl;
|
|
8967
|
+
token;
|
|
8968
|
+
constructor(options) {
|
|
8969
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
8970
|
+
this.token = options.token;
|
|
8971
|
+
}
|
|
8972
|
+
static fromConnection(connection, token) {
|
|
8973
|
+
if (connection.mode === "http")
|
|
8974
|
+
return new RigPiSessionDaemonClient({ baseUrl: connection.baseUrl, token });
|
|
8975
|
+
throw new Error("Unix-socket Rig Pi daemon connections are not implemented in this build; use loopback HTTP.");
|
|
8976
|
+
}
|
|
8977
|
+
async request(method, path, body) {
|
|
8978
|
+
const response = await fetch(`${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`, {
|
|
8979
|
+
method,
|
|
8980
|
+
headers: {
|
|
8981
|
+
authorization: `Bearer ${this.token}`,
|
|
8982
|
+
...body === undefined ? {} : { "content-type": "application/json" }
|
|
8983
|
+
},
|
|
8984
|
+
body: body === undefined ? undefined : JSON.stringify(body)
|
|
8985
|
+
});
|
|
8986
|
+
const text = await response.text();
|
|
8987
|
+
const payload = text.trim() ? JSON.parse(text) : undefined;
|
|
8988
|
+
if (!response.ok) {
|
|
8989
|
+
const message = payload && typeof payload === "object" && !Array.isArray(payload) && typeof payload.error === "string" ? payload.error : text || response.statusText;
|
|
8990
|
+
throw new Error(`Rig Pi session daemon request failed (${response.status}): ${message}`);
|
|
8991
|
+
}
|
|
8992
|
+
return payload;
|
|
8993
|
+
}
|
|
8994
|
+
webSocketUrl(path) {
|
|
8995
|
+
const url = new URL(`${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`);
|
|
8996
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
8997
|
+
url.searchParams.set("token", this.token);
|
|
8998
|
+
return url.toString();
|
|
8999
|
+
}
|
|
9000
|
+
}
|
|
9001
|
+
|
|
9002
|
+
// packages/runtime/src/control-plane/pi-sessiond/launcher.ts
|
|
9003
|
+
var BUILD_CONFIG2 = {};
|
|
9004
|
+
var BAKED_RIG_SOURCE_ROOT = BUILD_CONFIG2.RIG_SOURCE_ROOT ?? "";
|
|
9005
|
+
async function ensureRigPiSessionDaemon(input) {
|
|
9006
|
+
const rootDir = resolve36(input.rootDir);
|
|
9007
|
+
mkdirSync20(rootDir, { recursive: true });
|
|
9008
|
+
const readyFile = resolve36(rootDir, "ready.json");
|
|
9009
|
+
const existing = readDaemonReadyFile(readyFile);
|
|
9010
|
+
const existingHandle = existing ? await tryReady(existing) : null;
|
|
9011
|
+
if (existingHandle)
|
|
9012
|
+
return existingHandle;
|
|
9013
|
+
try {
|
|
9014
|
+
rmSync14(readyFile, { force: true });
|
|
9015
|
+
} catch {}
|
|
9016
|
+
const token = randomBytes(32).toString("hex");
|
|
9017
|
+
const binPath = resolveRigPiSessionDaemonBinPath(input.env);
|
|
9018
|
+
const bunPath = input.env.RIG_BUN_PATH || process.execPath;
|
|
9019
|
+
const proc = Bun.spawn([bunPath, binPath], {
|
|
9020
|
+
cwd: rootDir,
|
|
9021
|
+
env: {
|
|
9022
|
+
...input.env,
|
|
9023
|
+
RIG_PI_SESSIOND_ROOT: rootDir,
|
|
9024
|
+
RIG_PI_SESSIOND_TOKEN: token,
|
|
9025
|
+
RIG_PI_SESSIOND_READY_FILE: readyFile,
|
|
9026
|
+
RIG_PI_SESSIOND_HOST: "127.0.0.1",
|
|
9027
|
+
RIG_PI_SESSIOND_PORT: "0",
|
|
9028
|
+
...input.version ? { RIG_VERSION: input.version } : {},
|
|
9029
|
+
...input.commit ? { RIG_GIT_COMMIT: input.commit } : {}
|
|
9030
|
+
},
|
|
9031
|
+
stdin: "ignore",
|
|
9032
|
+
stdout: "ignore",
|
|
9033
|
+
stderr: "inherit"
|
|
9034
|
+
});
|
|
9035
|
+
proc.unref();
|
|
9036
|
+
const deadline = Date.now() + (input.timeoutMs ?? 15000);
|
|
9037
|
+
while (Date.now() < deadline) {
|
|
9038
|
+
const ready = readDaemonReadyFile(readyFile);
|
|
9039
|
+
const handle = ready ? await tryReady(ready) : null;
|
|
9040
|
+
if (handle)
|
|
9041
|
+
return handle;
|
|
9042
|
+
await sleep(100);
|
|
9043
|
+
}
|
|
9044
|
+
throw new Error([
|
|
9045
|
+
`Rig Pi session daemon did not become ready at ${readyFile}.`,
|
|
9046
|
+
"Usual causes: the bundled Pi runtime is missing or broken. Run `rig doctor` to check Pi wiring,",
|
|
9047
|
+
"set RIG_PI_BINARY to a working Pi build, or run without Pi via RIG_RUNTIME_ADAPTER=claude-code."
|
|
9048
|
+
].join(`
|
|
9049
|
+
`));
|
|
9050
|
+
}
|
|
9051
|
+
function privateMetadataForDaemon(input) {
|
|
9052
|
+
return { public: input.publicMetadata, daemonConnection: input.connection };
|
|
9053
|
+
}
|
|
9054
|
+
async function tryReady(ready) {
|
|
9055
|
+
const host = typeof ready.host === "string" ? ready.host : "127.0.0.1";
|
|
9056
|
+
const port = typeof ready.port === "number" ? ready.port : Number(ready.port);
|
|
9057
|
+
const token = typeof ready.token === "string" ? ready.token : "";
|
|
9058
|
+
if (!Number.isFinite(port) || port <= 0 || !token)
|
|
9059
|
+
return null;
|
|
9060
|
+
const baseUrl = `http://${host}:${port}`;
|
|
9061
|
+
const client = new RigPiSessionDaemonClient({ baseUrl, token });
|
|
9062
|
+
try {
|
|
9063
|
+
await client.request("GET", "/health");
|
|
9064
|
+
} catch {
|
|
9065
|
+
return null;
|
|
9066
|
+
}
|
|
9067
|
+
return {
|
|
9068
|
+
client,
|
|
9069
|
+
connection: { mode: "http", baseUrl, tokenRef: tokenRefFromReady(ready) },
|
|
9070
|
+
token,
|
|
9071
|
+
ready
|
|
9072
|
+
};
|
|
9073
|
+
}
|
|
9074
|
+
function tokenRefFromReady(ready) {
|
|
9075
|
+
const token = typeof ready.token === "string" ? ready.token : "";
|
|
9076
|
+
return token ? `inline:${token}` : "missing";
|
|
9077
|
+
}
|
|
9078
|
+
function resolveRigPiSessionDaemonBinPath(env) {
|
|
9079
|
+
const explicit = env.RIG_PI_SESSIOND_BIN?.trim();
|
|
9080
|
+
if (explicit)
|
|
9081
|
+
return explicit;
|
|
9082
|
+
const roots = [
|
|
9083
|
+
env.RIG_CONTROL_PLANE_SOURCE_ROOT?.trim(),
|
|
9084
|
+
BAKED_RIG_SOURCE_ROOT.trim(),
|
|
9085
|
+
process.env.RIG_CONTROL_PLANE_SOURCE_ROOT?.trim(),
|
|
9086
|
+
process.env.RIG_HOST_PROJECT_ROOT?.trim(),
|
|
9087
|
+
process.env.PROJECT_RIG_ROOT?.trim()
|
|
9088
|
+
].filter((value) => Boolean(value));
|
|
9089
|
+
for (const root of roots) {
|
|
9090
|
+
const candidate = resolve36(root, "packages/runtime/src/control-plane/pi-sessiond/bin.ts");
|
|
9091
|
+
if (existsSync34(candidate))
|
|
9092
|
+
return candidate;
|
|
9093
|
+
}
|
|
9094
|
+
const moduleCandidate = fileURLToPath2(new URL("./bin.ts", import.meta.url));
|
|
9095
|
+
if (existsSync34(moduleCandidate))
|
|
9096
|
+
return moduleCandidate;
|
|
9097
|
+
throw new Error([
|
|
9098
|
+
"Unable to locate rig-pi-sessiond entrypoint.",
|
|
9099
|
+
"Set RIG_PI_SESSIOND_BIN or RIG_CONTROL_PLANE_SOURCE_ROOT to the Rig source checkout,",
|
|
9100
|
+
"or run without the Pi daemon via RIG_RUNTIME_ADAPTER=claude-code."
|
|
9101
|
+
].join(`
|
|
9102
|
+
`));
|
|
9103
|
+
}
|
|
9104
|
+
function readDaemonReadyFile(path) {
|
|
9105
|
+
if (!existsSync34(path))
|
|
9106
|
+
return null;
|
|
9107
|
+
try {
|
|
9108
|
+
const parsed = JSON.parse(readFileSync17(path, "utf8"));
|
|
9109
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
9110
|
+
} catch {
|
|
9111
|
+
return null;
|
|
9112
|
+
}
|
|
9113
|
+
}
|
|
9114
|
+
function sleep(ms) {
|
|
9115
|
+
return new Promise((resolveSleep) => setTimeout(resolveSleep, ms));
|
|
9116
|
+
}
|
|
9117
|
+
function resolveRigPiSessionDaemonRoot(stateDir) {
|
|
9118
|
+
const root = resolve36(stateDir, "pi-sessiond");
|
|
9119
|
+
mkdirSync20(dirname14(root), { recursive: true });
|
|
9120
|
+
if (!existsSync34(root))
|
|
9121
|
+
mkdirSync20(root, { recursive: true });
|
|
9122
|
+
return root;
|
|
9123
|
+
}
|
|
9124
|
+
|
|
9134
9125
|
// packages/runtime/src/control-plane/agent-wrapper.ts
|
|
9126
|
+
var requireFromRuntime = createRequire(import.meta.url);
|
|
9135
9127
|
async function finalizeRuntimeSnapshot(snapshotSidecar, providerCommand, exitCode, context) {
|
|
9136
9128
|
try {
|
|
9137
9129
|
await snapshotSidecar.finalize(providerCommand, exitCode);
|
|
@@ -9164,7 +9156,7 @@ async function startOptionalRuntimeSnapshotSidecar(runtime, startSidecar = start
|
|
|
9164
9156
|
}
|
|
9165
9157
|
}
|
|
9166
9158
|
async function runAgentWrapper(options = {}) {
|
|
9167
|
-
const projectRoot =
|
|
9159
|
+
const projectRoot = resolve37(options.projectRoot || process.env.PROJECT_RIG_ROOT || process.cwd());
|
|
9168
9160
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
9169
9161
|
const argv = options.argv || process.argv.slice(2);
|
|
9170
9162
|
if (argv.length === 0 || argv[0] === "--version" || argv[0] === "--help" || argv[0] === "help") {
|
|
@@ -9193,7 +9185,8 @@ async function runAgentWrapper(options = {}) {
|
|
|
9193
9185
|
taskId,
|
|
9194
9186
|
mode: "worktree",
|
|
9195
9187
|
provider,
|
|
9196
|
-
taskRecordReader: taskRecordReaderFromEnv(taskId)
|
|
9188
|
+
taskRecordReader: taskRecordReaderFromEnv(taskId),
|
|
9189
|
+
preserveTaskArtifacts: process.env.RIG_RUN_RESUME === "1" || process.env.RIG_RUNTIME_ARTIFACT_CLEANUP === "preserve"
|
|
9197
9190
|
});
|
|
9198
9191
|
emitWrapperEvent("runtime.provision.completed", {
|
|
9199
9192
|
runtimeId: runtime.id,
|
|
@@ -9226,7 +9219,8 @@ async function runAgentWrapper(options = {}) {
|
|
|
9226
9219
|
return 1;
|
|
9227
9220
|
}
|
|
9228
9221
|
const providerArgs = buildProviderArgs(provider, runtime, argv);
|
|
9229
|
-
const
|
|
9222
|
+
const normalPiDaemonPath = provider === "pi" && process.env.RIG_PI_RPC_FALLBACK !== "1";
|
|
9223
|
+
const providerCommand = normalPiDaemonPath ? ["rig-pi-sessiond", ...providerArgs] : [providerBinary(provider), ...providerArgs];
|
|
9230
9224
|
emitWrapperEvent("provider.launch", {
|
|
9231
9225
|
provider,
|
|
9232
9226
|
runtimeId: runtime.id,
|
|
@@ -9238,11 +9232,11 @@ async function runAgentWrapper(options = {}) {
|
|
|
9238
9232
|
const bypassOuterRuntimeSandbox = shouldBypassProviderSandboxOnPlatform(provider, process.platform);
|
|
9239
9233
|
const runClaudeCompatUnsandboxed = provider === "claude-code" && bypassOuterRuntimeSandbox;
|
|
9240
9234
|
if (runClaudeCompatUnsandboxed && process.env.HOME?.trim()) {
|
|
9241
|
-
env.CLAUDE_HOME =
|
|
9235
|
+
env.CLAUDE_HOME = resolve37(process.env.HOME.trim(), ".claude");
|
|
9242
9236
|
env.RIG_CLAUDE_RUNTIME_HOME = runtime.claudeHomeDir;
|
|
9243
9237
|
}
|
|
9244
9238
|
if (provider === "pi") {
|
|
9245
|
-
env.PI_CODING_AGENT_DIR =
|
|
9239
|
+
env.PI_CODING_AGENT_DIR = resolve37(runtime.homeDir, ".pi", "agent");
|
|
9246
9240
|
env.PI_CODING_AGENT_SESSION_DIR = runtime.sessionDir;
|
|
9247
9241
|
}
|
|
9248
9242
|
env.RIG_RUNTIME_SANDBOX = "enforce";
|
|
@@ -9276,14 +9270,36 @@ async function runAgentWrapper(options = {}) {
|
|
|
9276
9270
|
},
|
|
9277
9271
|
command: providerCommand
|
|
9278
9272
|
})).command;
|
|
9279
|
-
|
|
9280
|
-
|
|
9281
|
-
|
|
9282
|
-
|
|
9283
|
-
|
|
9284
|
-
|
|
9285
|
-
|
|
9286
|
-
|
|
9273
|
+
if (provider === "pi" && process.env.RIG_PI_RPC_FALLBACK !== "1") {
|
|
9274
|
+
const prompt = await readProcessStdin();
|
|
9275
|
+
exitCode = await runPiSessionDaemonProvider({
|
|
9276
|
+
projectRoot,
|
|
9277
|
+
runtime,
|
|
9278
|
+
env,
|
|
9279
|
+
prompt,
|
|
9280
|
+
runId: process.env.RIG_SERVER_RUN_ID?.trim() || process.env.RIG_RUN_ID?.trim() || undefined,
|
|
9281
|
+
sessionName: process.env.RIG_SERVER_RUN_ID?.trim() ? `Rig ${process.env.RIG_SERVER_RUN_ID.trim()}` : `Rig ${runtime.taskId}`
|
|
9282
|
+
});
|
|
9283
|
+
} else if (provider === "pi" && isPiRpcArgs(providerArgs)) {
|
|
9284
|
+
const prompt = await readProcessStdin();
|
|
9285
|
+
exitCode = await runPiRpcProviderFallback({
|
|
9286
|
+
command,
|
|
9287
|
+
cwd: runtime.workspaceDir,
|
|
9288
|
+
env,
|
|
9289
|
+
prompt,
|
|
9290
|
+
runId: process.env.RIG_SERVER_RUN_ID?.trim() || undefined,
|
|
9291
|
+
sessionName: process.env.RIG_SERVER_RUN_ID?.trim() ? `Rig ${process.env.RIG_SERVER_RUN_ID.trim()}` : `Rig ${runtime.taskId}`
|
|
9292
|
+
});
|
|
9293
|
+
} else {
|
|
9294
|
+
const proc = Bun.spawn(command, {
|
|
9295
|
+
cwd: runtime.workspaceDir,
|
|
9296
|
+
env,
|
|
9297
|
+
stdin: "inherit",
|
|
9298
|
+
stdout: "inherit",
|
|
9299
|
+
stderr: "inherit"
|
|
9300
|
+
});
|
|
9301
|
+
exitCode = await proc.exited;
|
|
9302
|
+
}
|
|
9287
9303
|
}
|
|
9288
9304
|
if (snapshotSidecar) {
|
|
9289
9305
|
await finalizeRuntimeSnapshot(snapshotSidecar, providerCommand, exitCode, {
|
|
@@ -9298,15 +9314,13 @@ async function runAgentWrapper(options = {}) {
|
|
|
9298
9314
|
throw error;
|
|
9299
9315
|
}
|
|
9300
9316
|
const serverManagedRun = Boolean(process.env.RIG_SERVER_RUN_ID?.trim());
|
|
9301
|
-
if (exitCode === 0 && serverManagedRun) {
|
|
9302
|
-
await updateTaskSourceAfterRun(monorepoRoot, taskId, runtime);
|
|
9303
|
-
}
|
|
9304
9317
|
const taskClosed = await isTaskClosed(monorepoRoot, taskId);
|
|
9305
9318
|
const finalExitCode = resolveFinalProviderExitCode({
|
|
9306
9319
|
providerExitCode: exitCode,
|
|
9307
9320
|
taskClosed,
|
|
9308
9321
|
serverManagedRun
|
|
9309
9322
|
});
|
|
9323
|
+
const handoffRequired = exitCode !== 0 || !taskClosed && !serverManagedRun;
|
|
9310
9324
|
emitWrapperEvent("provider.completed", {
|
|
9311
9325
|
provider,
|
|
9312
9326
|
runtimeId: runtime.id,
|
|
@@ -9315,24 +9329,352 @@ async function runAgentWrapper(options = {}) {
|
|
|
9315
9329
|
providerExitCode: exitCode,
|
|
9316
9330
|
taskClosed,
|
|
9317
9331
|
serverManagedRun,
|
|
9318
|
-
handoffRequired
|
|
9332
|
+
handoffRequired
|
|
9319
9333
|
});
|
|
9320
|
-
if (
|
|
9334
|
+
if (handoffRequired) {
|
|
9321
9335
|
recordRuntimeHandoff(projectRoot, runtime, taskId, exitCode);
|
|
9322
9336
|
}
|
|
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
9337
|
return finalExitCode;
|
|
9327
9338
|
}
|
|
9339
|
+
function parseJsonRecord(line) {
|
|
9340
|
+
try {
|
|
9341
|
+
const parsed = JSON.parse(line);
|
|
9342
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
9343
|
+
} catch {
|
|
9344
|
+
return null;
|
|
9345
|
+
}
|
|
9346
|
+
}
|
|
9347
|
+
async function readProcessStdin() {
|
|
9348
|
+
if (process.stdin.isTTY)
|
|
9349
|
+
return "";
|
|
9350
|
+
return await new Promise((resolveRead) => {
|
|
9351
|
+
let data = "";
|
|
9352
|
+
process.stdin.setEncoding("utf8");
|
|
9353
|
+
process.stdin.on("data", (chunk) => {
|
|
9354
|
+
data += String(chunk);
|
|
9355
|
+
});
|
|
9356
|
+
process.stdin.on("end", () => resolveRead(data));
|
|
9357
|
+
process.stdin.resume();
|
|
9358
|
+
});
|
|
9359
|
+
}
|
|
9360
|
+
async function pumpReadableLines(stream, onLine) {
|
|
9361
|
+
if (!stream)
|
|
9362
|
+
return;
|
|
9363
|
+
const reader = stream.getReader();
|
|
9364
|
+
const decoder = new TextDecoder;
|
|
9365
|
+
let buffer = "";
|
|
9366
|
+
try {
|
|
9367
|
+
while (true) {
|
|
9368
|
+
const { done, value } = await reader.read();
|
|
9369
|
+
if (done)
|
|
9370
|
+
break;
|
|
9371
|
+
buffer += decoder.decode(value, { stream: true });
|
|
9372
|
+
const parts = buffer.split(/\r?\n/);
|
|
9373
|
+
buffer = parts.pop() ?? "";
|
|
9374
|
+
for (const part of parts)
|
|
9375
|
+
onLine(part);
|
|
9376
|
+
}
|
|
9377
|
+
buffer += decoder.decode();
|
|
9378
|
+
if (buffer)
|
|
9379
|
+
onLine(buffer);
|
|
9380
|
+
} finally {
|
|
9381
|
+
reader.releaseLock();
|
|
9382
|
+
}
|
|
9383
|
+
}
|
|
9384
|
+
function isBlockingPiRpcUiRequest(record) {
|
|
9385
|
+
if (record.type !== "extension_ui_request")
|
|
9386
|
+
return false;
|
|
9387
|
+
return record.method === "select" || record.method === "confirm" || record.method === "input" || record.method === "editor";
|
|
9388
|
+
}
|
|
9389
|
+
function writeRpcCommand(stdin, command) {
|
|
9390
|
+
stdin.write(`${JSON.stringify(command)}
|
|
9391
|
+
`);
|
|
9392
|
+
}
|
|
9393
|
+
function joinUrl(baseUrl, pathname) {
|
|
9394
|
+
return `${baseUrl.replace(/\/+$/, "")}${pathname.startsWith("/") ? pathname : `/${pathname}`}`;
|
|
9395
|
+
}
|
|
9396
|
+
async function readQueuedSteeringFromServer(input) {
|
|
9397
|
+
if (!input.serverUrl || !input.runId)
|
|
9398
|
+
return [];
|
|
9399
|
+
const headers = {};
|
|
9400
|
+
if (input.authToken)
|
|
9401
|
+
headers.authorization = `Bearer ${input.authToken}`;
|
|
9402
|
+
const response = await fetch(joinUrl(input.serverUrl, `/api/runs/${encodeURIComponent(input.runId)}/steering?ack=1`), { headers });
|
|
9403
|
+
if (!response.ok)
|
|
9404
|
+
return [];
|
|
9405
|
+
const payload = await response.json().catch(() => null);
|
|
9406
|
+
const messages = payload && typeof payload === "object" && !Array.isArray(payload) ? payload.messages : null;
|
|
9407
|
+
return Array.isArray(messages) ? messages.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
|
|
9408
|
+
}
|
|
9409
|
+
function steeringMessageText(entry) {
|
|
9410
|
+
const message = typeof entry.message === "string" ? entry.message.trim() : "";
|
|
9411
|
+
return message || null;
|
|
9412
|
+
}
|
|
9413
|
+
function isPiRpcArgs(args) {
|
|
9414
|
+
return cliOptionValue(args, "--mode") === "rpc";
|
|
9415
|
+
}
|
|
9416
|
+
async function runPiSessionDaemonProvider(input) {
|
|
9417
|
+
const stdout = input.stdout ?? process.stdout;
|
|
9418
|
+
const stderr = input.stderr ?? process.stderr;
|
|
9419
|
+
const runId = input.runId ?? input.runtime.taskId;
|
|
9420
|
+
emitWrapperEvent("pi.sessiond.starting", {
|
|
9421
|
+
runId,
|
|
9422
|
+
runtimeId: input.runtime.id,
|
|
9423
|
+
workspaceDir: input.runtime.workspaceDir
|
|
9424
|
+
});
|
|
9425
|
+
const daemon = await ensureRigPiSessionDaemon({
|
|
9426
|
+
rootDir: resolveRigPiSessionDaemonRoot(input.runtime.stateDir),
|
|
9427
|
+
env: input.env,
|
|
9428
|
+
version: process.env.RIG_VERSION?.trim() || "dev",
|
|
9429
|
+
commit: process.env.RIG_GIT_COMMIT?.trim() || undefined
|
|
9430
|
+
});
|
|
9431
|
+
emitWrapperEvent("pi.sessiond.ready", {
|
|
9432
|
+
runId,
|
|
9433
|
+
runtimeId: input.runtime.id,
|
|
9434
|
+
connection: daemon.connection,
|
|
9435
|
+
ready: daemon.ready
|
|
9436
|
+
});
|
|
9437
|
+
const start = await daemon.client.request("POST", "/sessions", {
|
|
9438
|
+
runId,
|
|
9439
|
+
cwd: input.runtime.workspaceDir,
|
|
9440
|
+
agentDir: input.env.PI_CODING_AGENT_DIR || resolve37(input.runtime.homeDir, ".pi", "agent"),
|
|
9441
|
+
sessionDir: input.runtime.sessionDir,
|
|
9442
|
+
sessionName: input.sessionName
|
|
9443
|
+
});
|
|
9444
|
+
const privateMetadata = privateMetadataForDaemon({ publicMetadata: start.metadata, connection: daemon.connection });
|
|
9445
|
+
emitWrapperEvent("pi.session.ready", {
|
|
9446
|
+
runId,
|
|
9447
|
+
runtimeId: input.runtime.id,
|
|
9448
|
+
metadata: start.metadata,
|
|
9449
|
+
privateMetadata
|
|
9450
|
+
});
|
|
9451
|
+
const eventStream = waitForPiSessionEvents({
|
|
9452
|
+
url: daemon.client.webSocketUrl(`/sessions/${encodeURIComponent(start.metadata.sessionId)}/events`),
|
|
9453
|
+
stdout,
|
|
9454
|
+
stderr,
|
|
9455
|
+
runId
|
|
9456
|
+
});
|
|
9457
|
+
emitWrapperEvent("pi.session.event_stream.connected", { runId, sessionId: start.metadata.sessionId });
|
|
9458
|
+
const forwardSigterm = () => {
|
|
9459
|
+
daemon.client.request("POST", `/sessions/${encodeURIComponent(start.metadata.sessionId)}/abort`).catch(() => {
|
|
9460
|
+
return;
|
|
9461
|
+
});
|
|
9462
|
+
eventStream.close();
|
|
9463
|
+
};
|
|
9464
|
+
process.once("SIGTERM", forwardSigterm);
|
|
9465
|
+
try {
|
|
9466
|
+
if (input.prompt.trim()) {
|
|
9467
|
+
await daemon.client.request("POST", `/sessions/${encodeURIComponent(start.metadata.sessionId)}/prompt`, { text: input.prompt });
|
|
9468
|
+
emitWrapperEvent("pi.prompt.sent", { runId, sessionId: start.metadata.sessionId, bytes: Buffer.byteLength(input.prompt) });
|
|
9469
|
+
} else {
|
|
9470
|
+
emitWrapperEvent("pi.prompt.waiting", { runId, sessionId: start.metadata.sessionId, reason: "empty-initial-prompt" });
|
|
9471
|
+
}
|
|
9472
|
+
const result = await eventStream.done;
|
|
9473
|
+
if (result.error) {
|
|
9474
|
+
stderr.write(`[rig-agent] Pi session daemon stream failed: ${result.error}
|
|
9475
|
+
`);
|
|
9476
|
+
return 1;
|
|
9477
|
+
}
|
|
9478
|
+
return 0;
|
|
9479
|
+
} finally {
|
|
9480
|
+
process.off("SIGTERM", forwardSigterm);
|
|
9481
|
+
eventStream.close();
|
|
9482
|
+
}
|
|
9483
|
+
}
|
|
9484
|
+
function waitForPiSessionEvents(input) {
|
|
9485
|
+
let closed = false;
|
|
9486
|
+
let resolved = false;
|
|
9487
|
+
let socket = null;
|
|
9488
|
+
let resolveDone = () => {
|
|
9489
|
+
return;
|
|
9490
|
+
};
|
|
9491
|
+
const done = new Promise((resolveDoneInner) => {
|
|
9492
|
+
resolveDone = resolveDoneInner;
|
|
9493
|
+
});
|
|
9494
|
+
const finish = (value) => {
|
|
9495
|
+
if (resolved)
|
|
9496
|
+
return;
|
|
9497
|
+
resolved = true;
|
|
9498
|
+
resolveDone(value);
|
|
9499
|
+
};
|
|
9500
|
+
socket = new WebSocket(input.url);
|
|
9501
|
+
socket.addEventListener("message", (message) => {
|
|
9502
|
+
const text = typeof message.data === "string" ? message.data : Buffer.from(message.data).toString("utf8");
|
|
9503
|
+
input.stdout.write(`${text}
|
|
9504
|
+
`);
|
|
9505
|
+
const envelope = parseJsonRecord(text);
|
|
9506
|
+
if (!envelope)
|
|
9507
|
+
return;
|
|
9508
|
+
if (envelope.type === "pi.event") {
|
|
9509
|
+
const event = envelope.event && typeof envelope.event === "object" && !Array.isArray(envelope.event) ? envelope.event : null;
|
|
9510
|
+
if (event?.type === "agent_end") {
|
|
9511
|
+
emitWrapperEvent("pi.session.agent_end", { runId: input.runId, sessionId: envelope.sessionId });
|
|
9512
|
+
finish({});
|
|
9513
|
+
}
|
|
9514
|
+
}
|
|
9515
|
+
if (envelope.type === "error") {
|
|
9516
|
+
emitWrapperEvent("pi.session.error", { runId: input.runId, message: envelope.message, detail: envelope.detail ?? null });
|
|
9517
|
+
finish({ error: envelope.message });
|
|
9518
|
+
}
|
|
9519
|
+
});
|
|
9520
|
+
socket.addEventListener("error", () => {
|
|
9521
|
+
if (!closed)
|
|
9522
|
+
finish({ error: "WebSocket error" });
|
|
9523
|
+
});
|
|
9524
|
+
socket.addEventListener("close", () => {
|
|
9525
|
+
if (!closed && !resolved)
|
|
9526
|
+
finish({ error: "WebSocket closed before agent_end" });
|
|
9527
|
+
});
|
|
9528
|
+
return {
|
|
9529
|
+
done,
|
|
9530
|
+
close: () => {
|
|
9531
|
+
closed = true;
|
|
9532
|
+
try {
|
|
9533
|
+
socket?.close();
|
|
9534
|
+
} catch {}
|
|
9535
|
+
}
|
|
9536
|
+
};
|
|
9537
|
+
}
|
|
9538
|
+
async function runPiRpcProviderFallback(input) {
|
|
9539
|
+
const stdout = input.stdout ?? process.stdout;
|
|
9540
|
+
const stderr = input.stderr ?? process.stderr;
|
|
9541
|
+
const proc = Bun.spawn(input.command, {
|
|
9542
|
+
cwd: input.cwd,
|
|
9543
|
+
env: input.env,
|
|
9544
|
+
stdin: "pipe",
|
|
9545
|
+
stdout: "pipe",
|
|
9546
|
+
stderr: "pipe"
|
|
9547
|
+
});
|
|
9548
|
+
let sawAgentEnd = false;
|
|
9549
|
+
let promptError = null;
|
|
9550
|
+
let stdinOpen = true;
|
|
9551
|
+
let steeringPollStopped = false;
|
|
9552
|
+
const closeStdin = () => {
|
|
9553
|
+
if (!stdinOpen)
|
|
9554
|
+
return;
|
|
9555
|
+
stdinOpen = false;
|
|
9556
|
+
try {
|
|
9557
|
+
steeringPollStopped = true;
|
|
9558
|
+
proc.stdin.end();
|
|
9559
|
+
} catch {}
|
|
9560
|
+
};
|
|
9561
|
+
const send = (command) => {
|
|
9562
|
+
if (!stdinOpen)
|
|
9563
|
+
return;
|
|
9564
|
+
try {
|
|
9565
|
+
writeRpcCommand(proc.stdin, command);
|
|
9566
|
+
} catch (error) {
|
|
9567
|
+
promptError ??= error instanceof Error ? error.message : String(error);
|
|
9568
|
+
}
|
|
9569
|
+
};
|
|
9570
|
+
const forwardSigterm = () => {
|
|
9571
|
+
try {
|
|
9572
|
+
proc.kill("SIGTERM");
|
|
9573
|
+
} catch {}
|
|
9574
|
+
};
|
|
9575
|
+
process.once("SIGTERM", forwardSigterm);
|
|
9576
|
+
const pollSteering = async () => {
|
|
9577
|
+
const serverUrl = input.env.RIG_SERVER_URL || input.env.RIG_SERVER_BASE_URL;
|
|
9578
|
+
const authToken = input.env.RIG_AUTH_TOKEN || input.env.RIG_SERVER_AUTH_TOKEN;
|
|
9579
|
+
while (!steeringPollStopped && stdinOpen) {
|
|
9580
|
+
try {
|
|
9581
|
+
const messages = await readQueuedSteeringFromServer({ serverUrl, authToken, runId: input.runId });
|
|
9582
|
+
for (const message of messages) {
|
|
9583
|
+
const text = steeringMessageText(message);
|
|
9584
|
+
if (!text || !stdinOpen)
|
|
9585
|
+
continue;
|
|
9586
|
+
send({
|
|
9587
|
+
id: typeof message.id === "string" ? `rig_steer_${message.id}` : `rig_steer_${Date.now()}`,
|
|
9588
|
+
type: "prompt",
|
|
9589
|
+
message: text,
|
|
9590
|
+
streamingBehavior: "steer"
|
|
9591
|
+
});
|
|
9592
|
+
emitWrapperEvent("pi.rpc.steering.delivered", {
|
|
9593
|
+
runId: input.runId ?? null,
|
|
9594
|
+
steeringId: typeof message.id === "string" ? message.id : null,
|
|
9595
|
+
actor: typeof message.actor === "string" ? message.actor : "operator",
|
|
9596
|
+
message: text
|
|
9597
|
+
});
|
|
9598
|
+
}
|
|
9599
|
+
} catch (error) {
|
|
9600
|
+
emitWrapperEvent("pi.rpc.steering.poll.failed", {
|
|
9601
|
+
runId: input.runId ?? null,
|
|
9602
|
+
error: error instanceof Error ? error.message : String(error)
|
|
9603
|
+
});
|
|
9604
|
+
}
|
|
9605
|
+
await sleep2(1000);
|
|
9606
|
+
}
|
|
9607
|
+
};
|
|
9608
|
+
const stdoutPump = pumpReadableLines(proc.stdout, (line) => {
|
|
9609
|
+
stdout.write(`${line}
|
|
9610
|
+
`);
|
|
9611
|
+
const record = parseJsonRecord(line.trim());
|
|
9612
|
+
if (!record)
|
|
9613
|
+
return;
|
|
9614
|
+
if (record.type === "agent_end") {
|
|
9615
|
+
sawAgentEnd = true;
|
|
9616
|
+
closeStdin();
|
|
9617
|
+
return;
|
|
9618
|
+
}
|
|
9619
|
+
if (record.type === "response" && record.command === "prompt" && record.success === false) {
|
|
9620
|
+
promptError = typeof record.error === "string" ? record.error : "Pi RPC prompt failed.";
|
|
9621
|
+
closeStdin();
|
|
9622
|
+
return;
|
|
9623
|
+
}
|
|
9624
|
+
if (isBlockingPiRpcUiRequest(record)) {
|
|
9625
|
+
const id = typeof record.id === "string" ? record.id : "";
|
|
9626
|
+
if (id) {
|
|
9627
|
+
send({ type: "extension_ui_response", id, cancelled: true });
|
|
9628
|
+
emitWrapperEvent("pi.rpc.extension_ui.cancelled", {
|
|
9629
|
+
id,
|
|
9630
|
+
method: record.method,
|
|
9631
|
+
reason: "noninteractive Rig worker RPC session"
|
|
9632
|
+
});
|
|
9633
|
+
}
|
|
9634
|
+
}
|
|
9635
|
+
});
|
|
9636
|
+
const stderrPump = pumpReadableLines(proc.stderr, (line) => {
|
|
9637
|
+
stderr.write(`${line}
|
|
9638
|
+
`);
|
|
9639
|
+
});
|
|
9640
|
+
if (input.sessionName?.trim()) {
|
|
9641
|
+
send({ id: "rig_set_session_name", type: "set_session_name", name: input.sessionName.trim() });
|
|
9642
|
+
}
|
|
9643
|
+
const steeringPollPromise = pollSteering();
|
|
9644
|
+
if (input.prompt.trim()) {
|
|
9645
|
+
send({ id: "rig_initial_prompt", type: "prompt", message: input.prompt });
|
|
9646
|
+
emitWrapperEvent("pi.rpc.prompt.sent", {
|
|
9647
|
+
runId: input.runId ?? null,
|
|
9648
|
+
kind: "initial",
|
|
9649
|
+
bytes: Buffer.byteLength(input.prompt)
|
|
9650
|
+
});
|
|
9651
|
+
} else {
|
|
9652
|
+
closeStdin();
|
|
9653
|
+
}
|
|
9654
|
+
const exitCode = await proc.exited;
|
|
9655
|
+
process.off("SIGTERM", forwardSigterm);
|
|
9656
|
+
steeringPollStopped = true;
|
|
9657
|
+
await Promise.all([stdoutPump, stderrPump, steeringPollPromise]);
|
|
9658
|
+
if (promptError) {
|
|
9659
|
+
stderr.write(`[rig-agent] Pi RPC prompt failed: ${promptError}
|
|
9660
|
+
`);
|
|
9661
|
+
return exitCode === 0 ? 1 : exitCode;
|
|
9662
|
+
}
|
|
9663
|
+
if (input.prompt.trim() && !sawAgentEnd && exitCode === 0) {
|
|
9664
|
+
stderr.write(`[rig-agent] Pi RPC exited before emitting agent_end.
|
|
9665
|
+
`);
|
|
9666
|
+
return 1;
|
|
9667
|
+
}
|
|
9668
|
+
return exitCode;
|
|
9669
|
+
}
|
|
9328
9670
|
function resolveFinalProviderExitCode(input) {
|
|
9329
9671
|
if (input.providerExitCode !== 0) {
|
|
9330
9672
|
return input.providerExitCode;
|
|
9331
9673
|
}
|
|
9332
|
-
if (input.taskClosed) {
|
|
9674
|
+
if (input.taskClosed || input.serverManagedRun) {
|
|
9333
9675
|
return 0;
|
|
9334
9676
|
}
|
|
9335
|
-
return
|
|
9677
|
+
return 0;
|
|
9336
9678
|
}
|
|
9337
9679
|
function shouldBypassProviderSandboxOnPlatform(provider, platform) {
|
|
9338
9680
|
if (platform !== "darwin") {
|
|
@@ -9356,14 +9698,27 @@ function buildProviderArgs(provider, runtime, argv) {
|
|
|
9356
9698
|
}
|
|
9357
9699
|
if (provider === "pi") {
|
|
9358
9700
|
const piArgs = [...argv];
|
|
9701
|
+
if (piArgs.includes("__rig_pi_session_daemon__")) {
|
|
9702
|
+
return piArgs.filter((arg) => arg !== "__rig_pi_session_daemon__");
|
|
9703
|
+
}
|
|
9704
|
+
const piProvider = cliOptionValue(piArgs, "--provider") || process.env.RIG_PI_PROVIDER?.trim() || "openai-codex";
|
|
9359
9705
|
if (!hasCliOption(piArgs, "--provider")) {
|
|
9360
|
-
piArgs.unshift(
|
|
9706
|
+
piArgs.unshift(piProvider);
|
|
9361
9707
|
piArgs.unshift("--provider");
|
|
9362
9708
|
}
|
|
9363
|
-
|
|
9364
|
-
|
|
9709
|
+
const model = cliOptionValue(piArgs, "--model") || process.env.RIG_PI_MODEL?.trim() || "gpt-5.5";
|
|
9710
|
+
if (hasCliOption(piArgs, "--model")) {
|
|
9711
|
+
rewriteCliOptionValue(piArgs, "--model", normalizePiModelForProvider(model, piProvider));
|
|
9712
|
+
} else {
|
|
9713
|
+
piArgs.unshift(normalizePiModelForProvider(model, piProvider));
|
|
9365
9714
|
piArgs.unshift("--model");
|
|
9366
9715
|
}
|
|
9716
|
+
if (!hasCliOption(piArgs, "--mode")) {
|
|
9717
|
+
piArgs.push("--mode", process.env.RIG_PI_TRANSPORT?.trim() === "print" ? "json" : "rpc");
|
|
9718
|
+
if (process.env.RIG_PI_TRANSPORT?.trim() === "print" && !hasCliOption(piArgs, "--print")) {
|
|
9719
|
+
piArgs.push("--print");
|
|
9720
|
+
}
|
|
9721
|
+
}
|
|
9367
9722
|
return piArgs;
|
|
9368
9723
|
}
|
|
9369
9724
|
return [
|
|
@@ -9413,6 +9768,7 @@ async function runBeadsJson(projectRoot, args) {
|
|
|
9413
9768
|
return null;
|
|
9414
9769
|
}
|
|
9415
9770
|
}
|
|
9771
|
+
var warnedUnknownRuntimeAdapter = false;
|
|
9416
9772
|
function resolveProvider() {
|
|
9417
9773
|
const value = process.env.RIG_RUNTIME_ADAPTER?.trim().toLowerCase();
|
|
9418
9774
|
if (!value) {
|
|
@@ -9424,28 +9780,85 @@ function resolveProvider() {
|
|
|
9424
9780
|
if (value === "pi" || value === "rig-pi" || value === "@rig/pi") {
|
|
9425
9781
|
return "pi";
|
|
9426
9782
|
}
|
|
9783
|
+
if (value !== "claude-code" && value !== "claude" && !warnedUnknownRuntimeAdapter) {
|
|
9784
|
+
warnedUnknownRuntimeAdapter = true;
|
|
9785
|
+
console.warn(`[rig-agent] Unknown RIG_RUNTIME_ADAPTER value "${value}"; falling back to claude-code. Use pi|claude-code|codex.`);
|
|
9786
|
+
}
|
|
9427
9787
|
return "claude-code";
|
|
9428
9788
|
}
|
|
9429
9789
|
function hasCliOption(argv, option) {
|
|
9430
9790
|
return argv.some((arg) => arg === option || arg.startsWith(`${option}=`));
|
|
9431
9791
|
}
|
|
9792
|
+
function cliOptionValue(argv, option) {
|
|
9793
|
+
for (let index = 0;index < argv.length; index += 1) {
|
|
9794
|
+
const arg = argv[index];
|
|
9795
|
+
if (arg === option) {
|
|
9796
|
+
const next = argv[index + 1];
|
|
9797
|
+
return next && !next.startsWith("--") ? next : undefined;
|
|
9798
|
+
}
|
|
9799
|
+
if (arg?.startsWith(`${option}=`)) {
|
|
9800
|
+
return arg.slice(option.length + 1);
|
|
9801
|
+
}
|
|
9802
|
+
}
|
|
9803
|
+
return;
|
|
9804
|
+
}
|
|
9805
|
+
function rewriteCliOptionValue(argv, option, value) {
|
|
9806
|
+
for (let index = 0;index < argv.length; index += 1) {
|
|
9807
|
+
const arg = argv[index];
|
|
9808
|
+
if (arg === option && argv[index + 1] && !argv[index + 1].startsWith("--")) {
|
|
9809
|
+
argv[index + 1] = value;
|
|
9810
|
+
return;
|
|
9811
|
+
}
|
|
9812
|
+
if (arg?.startsWith(`${option}=`)) {
|
|
9813
|
+
argv[index] = `${option}=${value}`;
|
|
9814
|
+
return;
|
|
9815
|
+
}
|
|
9816
|
+
}
|
|
9817
|
+
}
|
|
9818
|
+
function normalizePiModelForProvider(model, provider) {
|
|
9819
|
+
if (provider === "openrouter" && model === "openai-codex/gpt-5.5") {
|
|
9820
|
+
return "openai/gpt-5.5";
|
|
9821
|
+
}
|
|
9822
|
+
return model;
|
|
9823
|
+
}
|
|
9824
|
+
function resolveFromShellPath(binary) {
|
|
9825
|
+
const resolved = Bun.spawnSync(["sh", "-lc", `command -v ${binary}`], {
|
|
9826
|
+
stdout: "pipe",
|
|
9827
|
+
stderr: "ignore",
|
|
9828
|
+
stdin: "ignore",
|
|
9829
|
+
env: process.env
|
|
9830
|
+
});
|
|
9831
|
+
if (resolved.exitCode !== 0)
|
|
9832
|
+
return null;
|
|
9833
|
+
const path = resolved.stdout.toString().trim().split(/\r?\n/)[0]?.trim();
|
|
9834
|
+
return path || null;
|
|
9835
|
+
}
|
|
9836
|
+
function resolveBundledPiBinary() {
|
|
9837
|
+
try {
|
|
9838
|
+
const packageJson = requireFromRuntime.resolve("@earendil-works/pi-coding-agent/package.json");
|
|
9839
|
+
const binaryPath = resolve37(packageJson, "..", "dist", "cli.js");
|
|
9840
|
+
return existsSync35(binaryPath) ? binaryPath : null;
|
|
9841
|
+
} catch {
|
|
9842
|
+
return null;
|
|
9843
|
+
}
|
|
9844
|
+
}
|
|
9432
9845
|
function providerBinary(provider) {
|
|
9433
9846
|
if (provider === "codex") {
|
|
9434
|
-
return Bun.which("codex") || "codex";
|
|
9847
|
+
return resolveFromShellPath("codex") || Bun.which("codex") || "codex";
|
|
9435
9848
|
}
|
|
9436
9849
|
if (provider === "pi") {
|
|
9437
|
-
return Bun.which("pi") || "pi";
|
|
9850
|
+
return process.env.RIG_PI_BINARY?.trim() || resolveBundledPiBinary() || resolveFromShellPath("pi") || Bun.which("pi") || "pi";
|
|
9438
9851
|
}
|
|
9439
9852
|
try {
|
|
9440
9853
|
return resolveClaudeBinaryPath();
|
|
9441
9854
|
} catch {
|
|
9442
|
-
return Bun.which("claude") || "claude";
|
|
9855
|
+
return resolveFromShellPath("claude") || Bun.which("claude") || "claude";
|
|
9443
9856
|
}
|
|
9444
9857
|
}
|
|
9445
9858
|
function emitWrapperEvent(type, payload) {
|
|
9446
9859
|
console.log(`__RIG_WRAPPER_EVENT__${JSON.stringify({ type, payload, at: new Date().toISOString() })}`);
|
|
9447
9860
|
}
|
|
9448
|
-
function
|
|
9861
|
+
function sleep2(ms) {
|
|
9449
9862
|
return new Promise((resolveSleep) => setTimeout(resolveSleep, ms));
|
|
9450
9863
|
}
|
|
9451
9864
|
async function waitForDirtyBaselineReady(runtime, taskId) {
|
|
@@ -9460,11 +9873,11 @@ async function waitForDirtyBaselineReady(runtime, taskId) {
|
|
|
9460
9873
|
workspaceDir: runtime.workspaceDir,
|
|
9461
9874
|
readyFile
|
|
9462
9875
|
});
|
|
9463
|
-
while (!
|
|
9876
|
+
while (!existsSync35(readyFile)) {
|
|
9464
9877
|
if (Date.now() >= deadline) {
|
|
9465
9878
|
throw new Error(`Timed out waiting for dirty baseline ready file: ${readyFile}`);
|
|
9466
9879
|
}
|
|
9467
|
-
await
|
|
9880
|
+
await sleep2(50);
|
|
9468
9881
|
}
|
|
9469
9882
|
emitWrapperEvent("runtime.baseline.completed", {
|
|
9470
9883
|
runtimeId: runtime.id,
|
|
@@ -9527,43 +9940,10 @@ async function readPluginTaskStatus(projectRoot, taskId) {
|
|
|
9527
9940
|
return readSourceAwareTaskStatus(projectRoot, taskId);
|
|
9528
9941
|
}
|
|
9529
9942
|
}
|
|
9530
|
-
async function updateTaskSourceAfterRun(projectRoot, taskId, runtime) {
|
|
9531
|
-
const comment = buildTaskRunLifecycleComment({
|
|
9532
|
-
runId: process.env.RIG_SERVER_RUN_ID || "(unknown)",
|
|
9533
|
-
status: "closed",
|
|
9534
|
-
summary: "Rig task run completed and closed this task.",
|
|
9535
|
-
runtimeWorkspace: runtime.workspaceDir,
|
|
9536
|
-
logsDir: runtime.logsDir,
|
|
9537
|
-
sessionDir: runtime.sessionDir
|
|
9538
|
-
});
|
|
9539
|
-
try {
|
|
9540
|
-
const result = await updateConfiguredTaskSourceTask(projectRoot, {
|
|
9541
|
-
taskId,
|
|
9542
|
-
update: { status: "closed", comment }
|
|
9543
|
-
});
|
|
9544
|
-
if (result.updated) {
|
|
9545
|
-
return;
|
|
9546
|
-
}
|
|
9547
|
-
throw new Error(result.source === "plugin" || result.sourceKind ? `configured task source${result.sourceKind ? ` (${result.sourceKind})` : ""} does not support lifecycle updates` : "no source-aware task source is configured");
|
|
9548
|
-
} catch (error) {
|
|
9549
|
-
let fallbackUpdated = false;
|
|
9550
|
-
try {
|
|
9551
|
-
fallbackUpdated = updateSourceAwareTaskConfigTask(projectRoot, taskId, { status: "closed", comment });
|
|
9552
|
-
} catch (fallbackError) {
|
|
9553
|
-
console.error(`[rig-agent] Source-aware compatibility update also failed for ${taskId}: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`);
|
|
9554
|
-
}
|
|
9555
|
-
const message = `[rig-agent] Failed to update task source for ${taskId}${fallbackUpdated ? "; applied source-aware compatibility update" : ""}: ${error instanceof Error ? error.message : String(error)}`;
|
|
9556
|
-
if (fallbackUpdated) {
|
|
9557
|
-
console.log(message);
|
|
9558
|
-
} else {
|
|
9559
|
-
console.error(message);
|
|
9560
|
-
}
|
|
9561
|
-
}
|
|
9562
|
-
}
|
|
9563
9943
|
function recordRuntimeHandoff(hostProjectRoot, runtime, taskId, exitCode) {
|
|
9564
|
-
const handoffDir =
|
|
9565
|
-
|
|
9566
|
-
const handoffPath =
|
|
9944
|
+
const handoffDir = resolve37(hostProjectRoot, ".rig/runtime/handoffs");
|
|
9945
|
+
mkdirSync21(handoffDir, { recursive: true });
|
|
9946
|
+
const handoffPath = resolve37(handoffDir, `${taskId}-${Date.now()}.json`);
|
|
9567
9947
|
const handoff = {
|
|
9568
9948
|
taskId,
|
|
9569
9949
|
runtimeId: runtime.id,
|
|
@@ -9579,7 +9959,7 @@ function recordRuntimeHandoff(hostProjectRoot, runtime, taskId, exitCode) {
|
|
|
9579
9959
|
`rig git open-pr --task ${taskId}`
|
|
9580
9960
|
]
|
|
9581
9961
|
};
|
|
9582
|
-
|
|
9962
|
+
writeFileSync14(handoffPath, `${JSON.stringify(handoff, null, 2)}
|
|
9583
9963
|
`, "utf-8");
|
|
9584
9964
|
console.log(`[rig-agent] Completion verification paused for ${taskId}.`);
|
|
9585
9965
|
console.log(`[rig-agent] Runtime handoff saved: ${handoffPath}`);
|
|
@@ -9629,13 +10009,13 @@ async function readTaskMetadata2(taskRoot, taskId) {
|
|
|
9629
10009
|
async function readTaskConfigHints(taskRoot, taskId) {
|
|
9630
10010
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
9631
10011
|
const candidates = [
|
|
9632
|
-
runtimeContext?.monorepoMainRoot ?
|
|
9633
|
-
process.env.MONOREPO_MAIN_ROOT?.trim() ?
|
|
9634
|
-
|
|
9635
|
-
|
|
10012
|
+
runtimeContext?.monorepoMainRoot ? resolve37(runtimeContext.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
10013
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve37(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
10014
|
+
resolve37(taskRoot, ".rig", "task-config.json"),
|
|
10015
|
+
resolve37(taskRoot, "rig", "task-config.json")
|
|
9636
10016
|
].filter(Boolean);
|
|
9637
10017
|
for (const configPath of candidates) {
|
|
9638
|
-
if (!
|
|
10018
|
+
if (!existsSync35(configPath)) {
|
|
9639
10019
|
continue;
|
|
9640
10020
|
}
|
|
9641
10021
|
try {
|