@h-rig/isolation-plugin 0.0.6-alpha.157 → 0.0.6-alpha.158
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/src/embedded-native-assets.d.ts +7 -0
- package/dist/src/embedded-native-assets.js +6 -0
- package/dist/src/image-fingerprint-sidecar.d.ts +1 -0
- package/dist/src/image-fingerprint-sidecar.js +515 -0
- package/dist/src/image.d.ts +40 -0
- package/dist/src/image.js +1498 -0
- package/dist/src/index.js +4220 -20
- package/dist/src/isolation/binary-build-worker.d.ts +1 -0
- package/dist/src/isolation/binary-build-worker.js +323 -0
- package/dist/src/isolation/discovery.d.ts +7 -0
- package/dist/src/isolation/discovery.js +477 -0
- package/dist/src/isolation/git-native.d.ts +28 -0
- package/dist/src/isolation/git-native.js +598 -0
- package/dist/src/isolation/home.d.ts +25 -0
- package/dist/src/isolation/home.js +929 -0
- package/dist/src/isolation/index.d.ts +43 -0
- package/dist/src/isolation/index.js +4062 -0
- package/dist/src/isolation/provisioning-env.d.ts +1 -0
- package/dist/src/isolation/provisioning-env.js +6 -0
- package/dist/src/isolation/runner.d.ts +20 -0
- package/dist/src/isolation/runner.js +1881 -0
- package/dist/src/isolation/runtime-binary-build.d.ts +88 -0
- package/dist/src/isolation/runtime-binary-build.js +480 -0
- package/dist/src/isolation/shared.d.ts +29 -0
- package/dist/src/isolation/shared.js +283 -0
- package/dist/src/isolation/toolchain.d.ts +71 -0
- package/dist/src/isolation/toolchain.js +1348 -0
- package/dist/src/isolation/types.d.ts +15 -0
- package/dist/src/isolation/types.js +1 -0
- package/dist/src/isolation/worktree.d.ts +22 -0
- package/dist/src/isolation/worktree.js +353 -0
- package/dist/src/native-extract.d.ts +2 -0
- package/dist/src/native-extract.js +44 -0
- package/dist/src/plugin.d.ts +2 -2
- package/dist/src/plugin.js +4219 -19
- package/dist/src/runtime-config.d.ts +3 -0
- package/dist/src/runtime-config.js +215 -0
- package/dist/src/runtime-native-sidecar.d.ts +8 -0
- package/dist/src/runtime-native-sidecar.js +368 -0
- package/dist/src/runtime-native.d.ts +51 -0
- package/dist/src/runtime-native.js +485 -0
- package/dist/src/sandbox/backend-bwrap.d.ts +20 -0
- package/dist/src/sandbox/backend-bwrap.js +268 -0
- package/dist/src/sandbox/backend-none.d.ts +11 -0
- package/dist/src/sandbox/backend-none.js +20 -0
- package/dist/src/sandbox/backend-seatbelt.d.ts +13 -0
- package/dist/src/sandbox/backend-seatbelt.js +225 -0
- package/dist/src/sandbox/backend.d.ts +117 -0
- package/dist/src/sandbox/backend.js +864 -0
- package/dist/src/sandbox/orchestrator.d.ts +21 -0
- package/dist/src/sandbox/orchestrator.js +895 -0
- package/dist/src/sandbox/utils.d.ts +43 -0
- package/dist/src/sandbox/utils.js +94 -0
- package/dist/src/service.d.ts +10 -5
- package/dist/src/service.js +4145 -2
- package/dist/src/sidecar-arg.d.ts +7 -0
- package/dist/src/sidecar-arg.js +6 -0
- package/dist/src/sidecar-entrypoint.d.ts +9 -0
- package/dist/src/sidecar-entrypoint.js +401 -0
- package/dist/src/snapshot-sidecar.d.ts +2 -0
- package/dist/src/snapshot-sidecar.js +566 -0
- package/dist/src/snapshot.d.ts +64 -0
- package/dist/src/snapshot.js +515 -0
- package/dist/src/task-run-snapshot.d.ts +26 -0
- package/dist/src/task-run-snapshot.js +713 -0
- package/native/darwin-arm64/rig-git +0 -0
- package/native/darwin-arm64/rig-git.build-manifest.json +4 -0
- package/native/darwin-arm64/runtime-native.dylib +0 -0
- package/native/darwin-x64/rig-git +0 -0
- package/native/darwin-x64/runtime-native.dylib +0 -0
- package/native/linux-arm64/rig-git +0 -0
- package/native/linux-arm64/runtime-native.so +0 -0
- package/native/linux-x64/rig-git +0 -0
- package/native/linux-x64/runtime-native.so +0 -0
- package/native/win32-x64/rig-git.exe +0 -0
- package/native/win32-x64/runtime-native.dll +0 -0
- package/package.json +45 -5
|
@@ -0,0 +1,1348 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/isolation-plugin/src/isolation/toolchain.ts
|
|
3
|
+
import {
|
|
4
|
+
existsSync as existsSync5,
|
|
5
|
+
lstatSync,
|
|
6
|
+
mkdirSync as mkdirSync5,
|
|
7
|
+
readdirSync,
|
|
8
|
+
readFileSync as readFileSync3,
|
|
9
|
+
rmSync as rmSync4,
|
|
10
|
+
statSync as statSync3,
|
|
11
|
+
symlinkSync
|
|
12
|
+
} from "fs";
|
|
13
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
14
|
+
import { dirname as dirname4, resolve as resolve5 } from "path";
|
|
15
|
+
import { assertPathInsideRoot, safePathSegment } from "@rig/core/safe-identifiers";
|
|
16
|
+
|
|
17
|
+
// packages/isolation-plugin/src/isolation/runtime-binary-build.ts
|
|
18
|
+
import { chmodSync, copyFileSync, cpSync, existsSync as existsSync2, linkSync, mkdirSync as mkdirSync2, renameSync as renameSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
19
|
+
import { basename, dirname, resolve as resolve2 } from "path";
|
|
20
|
+
import { fileURLToPath } from "url";
|
|
21
|
+
import { drainMicrotasks, gcAndSweep } from "bun:jsc";
|
|
22
|
+
import { resolveRigLayout } from "@rig/core/layout";
|
|
23
|
+
import { runtimeProvisioningEnv } from "@rig/core/runtime-provisioning-env";
|
|
24
|
+
|
|
25
|
+
// packages/isolation-plugin/src/native-extract.ts
|
|
26
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "fs";
|
|
27
|
+
import { tmpdir } from "os";
|
|
28
|
+
import { resolve } from "path";
|
|
29
|
+
|
|
30
|
+
// packages/isolation-plugin/src/embedded-native-assets.ts
|
|
31
|
+
var embeddedNatives = null;
|
|
32
|
+
|
|
33
|
+
// packages/isolation-plugin/src/native-extract.ts
|
|
34
|
+
var sharedNativeOutputDir = resolve(tmpdir(), "rig-native");
|
|
35
|
+
var extractionCache = {};
|
|
36
|
+
function hasEmbeddedNatives() {
|
|
37
|
+
return embeddedNatives != null;
|
|
38
|
+
}
|
|
39
|
+
function extractEmbeddedNative(name) {
|
|
40
|
+
if (name in extractionCache) {
|
|
41
|
+
return extractionCache[name] ?? null;
|
|
42
|
+
}
|
|
43
|
+
const entry = embeddedNatives?.[name];
|
|
44
|
+
if (!entry) {
|
|
45
|
+
extractionCache[name] = null;
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const targetPath = resolve(sharedNativeOutputDir, entry.fileName);
|
|
50
|
+
mkdirSync(sharedNativeOutputDir, { recursive: true });
|
|
51
|
+
const upToDate = existsSync(targetPath) && statSync(targetPath).size === entry.size;
|
|
52
|
+
if (!upToDate) {
|
|
53
|
+
const bytes = readFileSync(entry.filePath);
|
|
54
|
+
const tempPath = `${targetPath}.${process.pid}.${Date.now()}.tmp`;
|
|
55
|
+
writeFileSync(tempPath, bytes, { mode: 493 });
|
|
56
|
+
renameSync(tempPath, targetPath);
|
|
57
|
+
}
|
|
58
|
+
extractionCache[name] = targetPath;
|
|
59
|
+
} catch {
|
|
60
|
+
extractionCache[name] = null;
|
|
61
|
+
}
|
|
62
|
+
return extractionCache[name] ?? null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// packages/isolation-plugin/src/isolation/runtime-binary-build.ts
|
|
66
|
+
var runtimeRigCliBinaryExternals = ["mupdf"];
|
|
67
|
+
var runtimeBinaryBuildQueue = Promise.resolve();
|
|
68
|
+
function materializeSelfExecRole(outputPath, define) {
|
|
69
|
+
const selfPath = process.execPath;
|
|
70
|
+
mkdirSync2(dirname(outputPath), { recursive: true });
|
|
71
|
+
rmSync(outputPath, { force: true });
|
|
72
|
+
try {
|
|
73
|
+
linkSync(selfPath, outputPath);
|
|
74
|
+
} catch {
|
|
75
|
+
copyFileSync(selfPath, outputPath);
|
|
76
|
+
}
|
|
77
|
+
chmodSync(outputPath, 493);
|
|
78
|
+
const role = basename(outputPath).replace(/\.exe$/i, "");
|
|
79
|
+
writeFileSync2(`${outputPath}.rig-runconfig.json`, `${JSON.stringify({ role, define: define ?? {} }, null, 2)}
|
|
80
|
+
`, { mode: 384 });
|
|
81
|
+
}
|
|
82
|
+
async function buildBinary(entrypoint, outputPath, cwd, defines, external) {
|
|
83
|
+
if (hasEmbeddedNatives()) {
|
|
84
|
+
materializeSelfExecRole(outputPath, defines);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
await buildRuntimeBinary({
|
|
88
|
+
sourcePath: entrypoint,
|
|
89
|
+
outputPath,
|
|
90
|
+
cwd,
|
|
91
|
+
...defines ? { define: defines } : {},
|
|
92
|
+
env: runtimeProvisioningEnv(),
|
|
93
|
+
...external ? { external } : {}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
async function buildRuntimeBinary(options) {
|
|
97
|
+
return runSerializedRuntimeBinaryBuild(async () => {
|
|
98
|
+
const resolved = resolveRuntimeBinaryBuildOptions(options);
|
|
99
|
+
runBestEffortBuildGc();
|
|
100
|
+
const manifestPath = runtimeBinaryCacheManifestPath(resolved.outputPath);
|
|
101
|
+
const buildKey = createRuntimeBinaryBuildKey({
|
|
102
|
+
entrypoint: resolved.entrypoint,
|
|
103
|
+
define: resolved.define,
|
|
104
|
+
env: resolved.env,
|
|
105
|
+
external: resolved.external
|
|
106
|
+
});
|
|
107
|
+
if (await isRuntimeBinaryBuildFresh({ outputPath: resolved.outputPath, manifestPath, buildKey })) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (shouldUseRuntimeBinaryBuildWorker()) {
|
|
111
|
+
await buildRuntimeBinaryViaWorker(resolved);
|
|
112
|
+
} else {
|
|
113
|
+
await buildRuntimeBinaryInProcess(resolved, { manifestPath, buildKey });
|
|
114
|
+
}
|
|
115
|
+
runBestEffortBuildGc();
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
119
|
+
const tempBuildDir = resolve2(dirname(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
120
|
+
const tempOutputPath = resolve2(tempBuildDir, basename(options.outputPath));
|
|
121
|
+
mkdirSync2(tempBuildDir, { recursive: true });
|
|
122
|
+
await withTemporaryEnv({
|
|
123
|
+
...options.env,
|
|
124
|
+
...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
|
|
125
|
+
}, async () => withTemporaryCwd(tempBuildDir, async () => {
|
|
126
|
+
const buildResult = await Bun.build({
|
|
127
|
+
entrypoints: [options.entrypoint],
|
|
128
|
+
compile: {
|
|
129
|
+
target: currentCompileTarget(),
|
|
130
|
+
outfile: tempOutputPath
|
|
131
|
+
},
|
|
132
|
+
target: "bun",
|
|
133
|
+
format: "esm",
|
|
134
|
+
minify: true,
|
|
135
|
+
bytecode: true,
|
|
136
|
+
metafile: true,
|
|
137
|
+
...options.external ? { external: options.external } : {},
|
|
138
|
+
...options.define ? { define: { __RIG_BUILD_CONFIG__: JSON.stringify(options.define) } } : {}
|
|
139
|
+
});
|
|
140
|
+
if (!buildResult.success) {
|
|
141
|
+
const details = buildResult.logs.map((log) => [log.message, log.position?.file ? `${log.position.file}:${log.position.line}:${log.position.column}` : ""].filter(Boolean).join(" ")).filter(Boolean).join(`
|
|
142
|
+
`);
|
|
143
|
+
throw new Error(`Failed to build ${options.entrypoint}: ${details || "Bun.build() returned errors"}`);
|
|
144
|
+
}
|
|
145
|
+
if (!existsSync2(tempOutputPath)) {
|
|
146
|
+
const emitted = buildResult.outputs.map((output) => output.path).join(", ") || "(none)";
|
|
147
|
+
throw new Error(`Failed to build ${options.entrypoint}: Bun.build() did not emit ${tempOutputPath}. Emitted: ${emitted}`);
|
|
148
|
+
}
|
|
149
|
+
renameSync2(tempOutputPath, options.outputPath);
|
|
150
|
+
chmodSync(options.outputPath, 493);
|
|
151
|
+
if (manifest) {
|
|
152
|
+
await writeRuntimeBinaryCacheManifest({
|
|
153
|
+
manifestPath: manifest.manifestPath,
|
|
154
|
+
buildKey: manifest.buildKey,
|
|
155
|
+
cwd: tempBuildDir,
|
|
156
|
+
metafile: buildResult.metafile
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
})).finally(() => {
|
|
160
|
+
rmSync(tempBuildDir, { recursive: true, force: true });
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
function runBestEffortBuildGc() {
|
|
164
|
+
try {
|
|
165
|
+
drainMicrotasks();
|
|
166
|
+
} catch {}
|
|
167
|
+
try {
|
|
168
|
+
gcAndSweep();
|
|
169
|
+
} catch {}
|
|
170
|
+
}
|
|
171
|
+
function runtimeBinaryCacheManifestPath(outputPath) {
|
|
172
|
+
return `${outputPath}.build-manifest.json`;
|
|
173
|
+
}
|
|
174
|
+
function resolveRuntimeBinaryBuildOptions(options) {
|
|
175
|
+
return {
|
|
176
|
+
...options,
|
|
177
|
+
entrypoint: resolve2(options.cwd, options.sourcePath),
|
|
178
|
+
outputPath: resolve2(options.outputPath)
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function shouldUseRuntimeBinaryBuildWorker() {
|
|
182
|
+
if (process.env.RIG_RUNTIME_BUILD_WORKER === "1") {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
if (process.env.RIG_RUNTIME_BUILD_IN_PROCESS === "1") {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
async function buildRuntimeBinaryViaWorker(options) {
|
|
191
|
+
const workerSourcePath = resolveRuntimeBinaryBuildWorkerSourcePath(options);
|
|
192
|
+
if (!workerSourcePath || !existsSync2(workerSourcePath)) {
|
|
193
|
+
await buildRuntimeBinaryInProcess(options, {
|
|
194
|
+
manifestPath: runtimeBinaryCacheManifestPath(options.outputPath),
|
|
195
|
+
buildKey: createRuntimeBinaryBuildKey({
|
|
196
|
+
entrypoint: options.entrypoint,
|
|
197
|
+
define: options.define,
|
|
198
|
+
env: options.env,
|
|
199
|
+
external: options.external
|
|
200
|
+
})
|
|
201
|
+
});
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const payloadPath = createRuntimeBinaryBuildWorkerPayloadPath(options.outputPath);
|
|
205
|
+
const bunCli = resolveRuntimeBinaryBuildWorkerInvocation();
|
|
206
|
+
await Bun.write(payloadPath, `${JSON.stringify(options)}
|
|
207
|
+
`);
|
|
208
|
+
const build = Bun.spawn([bunCli.command, workerSourcePath, payloadPath], {
|
|
209
|
+
cwd: options.cwd,
|
|
210
|
+
stdout: "pipe",
|
|
211
|
+
stderr: "pipe",
|
|
212
|
+
env: {
|
|
213
|
+
...process.env,
|
|
214
|
+
...options.env,
|
|
215
|
+
...bunCli.env,
|
|
216
|
+
RIG_RUNTIME_BUILD_WORKER: "1"
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
const [exitCode, stdout, stderr] = await Promise.all([
|
|
220
|
+
build.exited,
|
|
221
|
+
new Response(build.stdout).text(),
|
|
222
|
+
new Response(build.stderr).text()
|
|
223
|
+
]);
|
|
224
|
+
rmSync(payloadPath, { force: true });
|
|
225
|
+
if (exitCode !== 0) {
|
|
226
|
+
throw new Error(`Failed to build ${options.entrypoint}: ${(stderr || stdout || `worker exited ${exitCode}`).trim()}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
|
|
230
|
+
return resolve2(dirname(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
231
|
+
}
|
|
232
|
+
function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
233
|
+
const envRoots = [
|
|
234
|
+
options.cwd?.trim(),
|
|
235
|
+
process.env.RIG_HOST_PROJECT_ROOT?.trim(),
|
|
236
|
+
process.env.PROJECT_RIG_ROOT?.trim()
|
|
237
|
+
].filter(Boolean);
|
|
238
|
+
for (const root of envRoots) {
|
|
239
|
+
const candidate = resolve2(root, "packages/isolation-plugin/src/isolation/binary-build-worker.ts");
|
|
240
|
+
if (existsSync2(candidate)) {
|
|
241
|
+
return candidate;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
const localCandidate = resolve2(import.meta.dir, "binary-build-worker.ts");
|
|
245
|
+
return existsSync2(localCandidate) ? localCandidate : null;
|
|
246
|
+
}
|
|
247
|
+
function resolveRuntimeBinaryBuildWorkerInvocation() {
|
|
248
|
+
const bunPath = Bun.which("bun");
|
|
249
|
+
if (bunPath) {
|
|
250
|
+
return { command: bunPath, env: {} };
|
|
251
|
+
}
|
|
252
|
+
if (process.execPath?.trim()) {
|
|
253
|
+
return {
|
|
254
|
+
command: process.execPath,
|
|
255
|
+
env: { BUN_BE_BUN: "1" }
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
throw new Error("bun is required to run the runtime binary build worker.");
|
|
259
|
+
}
|
|
260
|
+
function currentCompileTarget() {
|
|
261
|
+
if (process.platform === "darwin") {
|
|
262
|
+
return process.arch === "arm64" ? "bun-darwin-arm64" : "bun-darwin-x64";
|
|
263
|
+
}
|
|
264
|
+
if (process.platform === "linux") {
|
|
265
|
+
return process.arch === "arm64" ? "bun-linux-arm64" : "bun-linux-x64";
|
|
266
|
+
}
|
|
267
|
+
return "bun-windows-x64";
|
|
268
|
+
}
|
|
269
|
+
function createRuntimeBinaryBuildKey(input) {
|
|
270
|
+
return JSON.stringify({
|
|
271
|
+
version: 1,
|
|
272
|
+
bunVersion: Bun.version,
|
|
273
|
+
platform: process.platform,
|
|
274
|
+
arch: process.arch,
|
|
275
|
+
entrypoint: input.entrypoint,
|
|
276
|
+
define: sortRecord(input.define),
|
|
277
|
+
external: input.external ? [...input.external].sort() : undefined,
|
|
278
|
+
env: sortRecord(input.env)
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
async function isRuntimeBinaryBuildFresh(input) {
|
|
282
|
+
if (!existsSync2(input.outputPath) || !existsSync2(input.manifestPath)) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
let manifest = null;
|
|
286
|
+
try {
|
|
287
|
+
manifest = await Bun.file(input.manifestPath).json();
|
|
288
|
+
} catch {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
if (!manifest || manifest.version !== 1 || manifest.buildKey !== input.buildKey) {
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
for (const [filePath, expectedDigest] of Object.entries(manifest.inputs || {})) {
|
|
295
|
+
if (!existsSync2(filePath)) {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
if (await sha256File(filePath) !== expectedDigest) {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
async function writeRuntimeBinaryCacheManifest(input) {
|
|
305
|
+
const inputs = {};
|
|
306
|
+
for (const inputPath of Object.keys(input.metafile?.inputs || {}).sort()) {
|
|
307
|
+
const normalized = normalizeBuildInputPath(input.cwd, inputPath);
|
|
308
|
+
if (!normalized || !existsSync2(normalized)) {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
inputs[normalized] = await sha256File(normalized);
|
|
312
|
+
}
|
|
313
|
+
const manifest = {
|
|
314
|
+
version: 1,
|
|
315
|
+
buildKey: input.buildKey,
|
|
316
|
+
inputs
|
|
317
|
+
};
|
|
318
|
+
await Bun.write(input.manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
319
|
+
`);
|
|
320
|
+
}
|
|
321
|
+
function normalizeBuildInputPath(cwd, inputPath) {
|
|
322
|
+
if (!inputPath) {
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
if (inputPath.startsWith("file://")) {
|
|
326
|
+
return fileURLToPath(inputPath);
|
|
327
|
+
}
|
|
328
|
+
if (inputPath.startsWith("<")) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
return resolve2(cwd, inputPath);
|
|
332
|
+
}
|
|
333
|
+
async function sha256File(path) {
|
|
334
|
+
const hasher = new Bun.CryptoHasher("sha256");
|
|
335
|
+
hasher.update(await Bun.file(path).arrayBuffer());
|
|
336
|
+
return hasher.digest("hex");
|
|
337
|
+
}
|
|
338
|
+
function sortRecord(value) {
|
|
339
|
+
if (!value) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)));
|
|
343
|
+
}
|
|
344
|
+
async function runSerializedRuntimeBinaryBuild(action) {
|
|
345
|
+
const previous = runtimeBinaryBuildQueue;
|
|
346
|
+
let release;
|
|
347
|
+
runtimeBinaryBuildQueue = new Promise((resolve3) => {
|
|
348
|
+
release = resolve3;
|
|
349
|
+
});
|
|
350
|
+
await previous;
|
|
351
|
+
try {
|
|
352
|
+
return await action();
|
|
353
|
+
} finally {
|
|
354
|
+
release();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
async function withTemporaryEnv(env, action) {
|
|
358
|
+
if (!env) {
|
|
359
|
+
return action();
|
|
360
|
+
}
|
|
361
|
+
const previousValues = new Map;
|
|
362
|
+
for (const [key, value] of Object.entries(env)) {
|
|
363
|
+
previousValues.set(key, process.env[key]);
|
|
364
|
+
if (value === undefined) {
|
|
365
|
+
delete process.env[key];
|
|
366
|
+
} else {
|
|
367
|
+
process.env[key] = value;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
try {
|
|
371
|
+
return await action();
|
|
372
|
+
} finally {
|
|
373
|
+
for (const [key, value] of previousValues.entries()) {
|
|
374
|
+
if (value === undefined) {
|
|
375
|
+
delete process.env[key];
|
|
376
|
+
} else {
|
|
377
|
+
process.env[key] = value;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
async function withTemporaryCwd(cwd, action) {
|
|
383
|
+
const previousCwd = process.cwd();
|
|
384
|
+
process.chdir(cwd);
|
|
385
|
+
try {
|
|
386
|
+
return await action();
|
|
387
|
+
} finally {
|
|
388
|
+
process.chdir(previousCwd);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// packages/isolation-plugin/src/isolation/git-native.ts
|
|
393
|
+
import { chmodSync as chmodSync2, copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
394
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
395
|
+
import { dirname as dirname2, isAbsolute, resolve as resolve3 } from "path";
|
|
396
|
+
var sharedGitNativeOutputDir = resolve3(tmpdir2(), "rig-native");
|
|
397
|
+
var sharedGitNativeOutputPath = resolve3(sharedGitNativeOutputDir, `rig-git-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
398
|
+
var trackerCommandUsageProbe = "usage: rig-git fetch-ref <repo-path> <remote> <branch>";
|
|
399
|
+
function temporaryGitBinaryOutputPath(outputPath) {
|
|
400
|
+
const suffix = process.platform === "win32" ? ".exe" : "";
|
|
401
|
+
return resolve3(dirname2(outputPath), `.rig-git-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}${suffix}`);
|
|
402
|
+
}
|
|
403
|
+
function publishGitBinary(tempOutputPath, outputPath) {
|
|
404
|
+
try {
|
|
405
|
+
renameSync3(tempOutputPath, outputPath);
|
|
406
|
+
} catch (error) {
|
|
407
|
+
if (process.platform === "win32" && existsSync3(outputPath)) {
|
|
408
|
+
rmSync2(outputPath, { force: true });
|
|
409
|
+
renameSync3(tempOutputPath, outputPath);
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
throw error;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
function isSharedGitNativeOutputPath(outputPath) {
|
|
416
|
+
return resolve3(outputPath) === sharedGitNativeOutputPath;
|
|
417
|
+
}
|
|
418
|
+
async function materializeFromSharedGitBinary(outputPath, buildKey) {
|
|
419
|
+
if (isSharedGitNativeOutputPath(outputPath))
|
|
420
|
+
return null;
|
|
421
|
+
const sharedManifest = nativeBuildManifestPath(sharedGitNativeOutputPath);
|
|
422
|
+
if (!existsSync3(sharedGitNativeOutputPath) || !await hasMatchingNativeBuildManifest(sharedManifest, buildKey) || !binarySupportsTrackerCommandsSync(sharedGitNativeOutputPath)) {
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
mkdirSync3(dirname2(outputPath), { recursive: true });
|
|
426
|
+
copyFileSync2(sharedGitNativeOutputPath, outputPath);
|
|
427
|
+
chmodSync2(outputPath, 493);
|
|
428
|
+
await Bun.write(nativeBuildManifestPath(outputPath), `${JSON.stringify({ version: 1, buildKey }, null, 2)}
|
|
429
|
+
`);
|
|
430
|
+
return outputPath;
|
|
431
|
+
}
|
|
432
|
+
function runtimeRigGitFileName() {
|
|
433
|
+
return `rig-git${process.platform === "win32" ? ".exe" : ""}`;
|
|
434
|
+
}
|
|
435
|
+
function rigGitSourceCandidates() {
|
|
436
|
+
const execDir = process.execPath?.trim() ? dirname2(process.execPath.trim()) : "";
|
|
437
|
+
const cwd = process.cwd()?.trim() || "";
|
|
438
|
+
const projectRoot = process.env.PROJECT_RIG_ROOT?.trim() || "";
|
|
439
|
+
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || "";
|
|
440
|
+
const moduleRelativeSource = resolve3(import.meta.dir, "../../native/rig-git.zig");
|
|
441
|
+
return [...new Set([
|
|
442
|
+
process.env.RIG_NATIVE_GIT_SOURCE?.trim() || "",
|
|
443
|
+
moduleRelativeSource,
|
|
444
|
+
projectRoot ? resolve3(projectRoot, "packages/isolation-plugin/native/rig-git.zig") : "",
|
|
445
|
+
hostProjectRoot ? resolve3(hostProjectRoot, "packages/isolation-plugin/native/rig-git.zig") : "",
|
|
446
|
+
cwd ? resolve3(cwd, "packages/isolation-plugin/native/rig-git.zig") : "",
|
|
447
|
+
execDir ? resolve3(execDir, "..", "..", "packages/isolation-plugin/native/rig-git.zig") : "",
|
|
448
|
+
execDir ? resolve3(execDir, "..", "native", "rig-git.zig") : ""
|
|
449
|
+
].filter(Boolean))];
|
|
450
|
+
}
|
|
451
|
+
function nativePackageBinaryCandidates(fromDir, fileName) {
|
|
452
|
+
const candidates = [];
|
|
453
|
+
let cursor = resolve3(fromDir);
|
|
454
|
+
for (let index = 0;index < 8; index += 1) {
|
|
455
|
+
candidates.push(resolve3(cursor, "native", `${process.platform}-${process.arch}`, fileName), resolve3(cursor, "native", `${process.platform}-${process.arch}`, "bin", fileName), resolve3(cursor, "native", fileName), resolve3(cursor, "native", "bin", fileName));
|
|
456
|
+
const parent = dirname2(cursor);
|
|
457
|
+
if (parent === cursor)
|
|
458
|
+
break;
|
|
459
|
+
cursor = parent;
|
|
460
|
+
}
|
|
461
|
+
return candidates;
|
|
462
|
+
}
|
|
463
|
+
function rigGitBinaryCandidates() {
|
|
464
|
+
const execDir = process.execPath?.trim() ? dirname2(process.execPath.trim()) : "";
|
|
465
|
+
const fileName = runtimeRigGitFileName();
|
|
466
|
+
const explicit = process.env.RIG_NATIVE_GIT_BIN?.trim() || "";
|
|
467
|
+
return [...new Set([
|
|
468
|
+
explicit,
|
|
469
|
+
...nativePackageBinaryCandidates(import.meta.dir, fileName),
|
|
470
|
+
execDir ? resolve3(execDir, fileName) : "",
|
|
471
|
+
execDir ? resolve3(execDir, "..", fileName) : "",
|
|
472
|
+
execDir ? resolve3(execDir, "..", "bin", fileName) : "",
|
|
473
|
+
sharedGitNativeOutputPath
|
|
474
|
+
].filter(Boolean))];
|
|
475
|
+
}
|
|
476
|
+
function resolveGitSourcePath() {
|
|
477
|
+
for (const candidate of rigGitSourceCandidates()) {
|
|
478
|
+
if (candidate && existsSync3(candidate)) {
|
|
479
|
+
return candidate;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return null;
|
|
483
|
+
}
|
|
484
|
+
function resolveGitBinaryPath() {
|
|
485
|
+
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
486
|
+
return null;
|
|
487
|
+
}
|
|
488
|
+
for (const candidate of rigGitBinaryCandidates()) {
|
|
489
|
+
if (candidate && existsSync3(candidate)) {
|
|
490
|
+
return candidate;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
495
|
+
function binarySupportsTrackerCommandsSync(binaryPath) {
|
|
496
|
+
try {
|
|
497
|
+
const probe = Bun.spawnSync([binaryPath, "fetch-ref", "."], {
|
|
498
|
+
stdout: "pipe",
|
|
499
|
+
stderr: "pipe"
|
|
500
|
+
});
|
|
501
|
+
const stdout = probe.stdout.toString().trim();
|
|
502
|
+
const stderr = probe.stderr.toString().trim();
|
|
503
|
+
if (stdout.includes('"error":"unknown command"')) {
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
return probe.exitCode === 2 && stderr.includes(trackerCommandUsageProbe);
|
|
507
|
+
} catch {
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
function nativeBuildManifestPath(outputPath) {
|
|
512
|
+
return `${outputPath}.build-manifest.json`;
|
|
513
|
+
}
|
|
514
|
+
async function hasMatchingNativeBuildManifest(manifestPath, buildKey) {
|
|
515
|
+
if (!existsSync3(manifestPath)) {
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
try {
|
|
519
|
+
const manifest = await Bun.file(manifestPath).json();
|
|
520
|
+
return manifest.version === 1 && manifest.buildKey === buildKey;
|
|
521
|
+
} catch {
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
async function sha256File2(path) {
|
|
526
|
+
const hasher = new Bun.CryptoHasher("sha256");
|
|
527
|
+
hasher.update(await Bun.file(path).arrayBuffer());
|
|
528
|
+
return hasher.digest("hex");
|
|
529
|
+
}
|
|
530
|
+
async function ensureRigGitBinaryPath(outputPath = sharedGitNativeOutputPath) {
|
|
531
|
+
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
532
|
+
throw new Error("Zig native git is disabled via RIG_DISABLE_ZIG_NATIVE=1");
|
|
533
|
+
}
|
|
534
|
+
const explicitBin = process.env.RIG_NATIVE_GIT_BIN?.trim();
|
|
535
|
+
if (explicitBin && existsSync3(explicitBin)) {
|
|
536
|
+
return explicitBin;
|
|
537
|
+
}
|
|
538
|
+
const embedded = extractEmbeddedNative("rig-git");
|
|
539
|
+
if (embedded) {
|
|
540
|
+
return embedded;
|
|
541
|
+
}
|
|
542
|
+
const sourcePath = resolveGitSourcePath();
|
|
543
|
+
if (!sourcePath) {
|
|
544
|
+
const binaryPath = resolveGitBinaryPath();
|
|
545
|
+
if (binaryPath) {
|
|
546
|
+
return binaryPath;
|
|
547
|
+
}
|
|
548
|
+
throw new Error("rig-git.zig source file not found.");
|
|
549
|
+
}
|
|
550
|
+
const zigBinary = Bun.which("zig");
|
|
551
|
+
if (!zigBinary) {
|
|
552
|
+
throw new Error("zig is required to build native Rig git tools.");
|
|
553
|
+
}
|
|
554
|
+
mkdirSync3(dirname2(outputPath), { recursive: true });
|
|
555
|
+
const sourceDigest = await sha256File2(sourcePath);
|
|
556
|
+
const buildKey = JSON.stringify({
|
|
557
|
+
version: 1,
|
|
558
|
+
zigBinary,
|
|
559
|
+
platform: process.platform,
|
|
560
|
+
arch: process.arch,
|
|
561
|
+
sourcePath,
|
|
562
|
+
sourceDigest
|
|
563
|
+
});
|
|
564
|
+
const manifestPath = nativeBuildManifestPath(outputPath);
|
|
565
|
+
const needsBuild = !existsSync3(outputPath) || !await hasMatchingNativeBuildManifest(manifestPath, buildKey) || !binarySupportsTrackerCommandsSync(outputPath);
|
|
566
|
+
if (!needsBuild) {
|
|
567
|
+
chmodSync2(outputPath, 493);
|
|
568
|
+
return outputPath;
|
|
569
|
+
}
|
|
570
|
+
const materialized = await materializeFromSharedGitBinary(outputPath, buildKey);
|
|
571
|
+
if (materialized)
|
|
572
|
+
return materialized;
|
|
573
|
+
const tempOutputPath = temporaryGitBinaryOutputPath(outputPath);
|
|
574
|
+
const build = Bun.spawn([
|
|
575
|
+
zigBinary,
|
|
576
|
+
"build-exe",
|
|
577
|
+
sourcePath,
|
|
578
|
+
"-O",
|
|
579
|
+
"ReleaseFast",
|
|
580
|
+
`-femit-bin=${tempOutputPath}`
|
|
581
|
+
], {
|
|
582
|
+
cwd: dirname2(sourcePath),
|
|
583
|
+
stdout: "pipe",
|
|
584
|
+
stderr: "pipe"
|
|
585
|
+
});
|
|
586
|
+
const [exitCode, stdout, stderr] = await Promise.all([
|
|
587
|
+
build.exited,
|
|
588
|
+
new Response(build.stdout).text(),
|
|
589
|
+
new Response(build.stderr).text()
|
|
590
|
+
]);
|
|
591
|
+
if (exitCode !== 0 || !existsSync3(tempOutputPath)) {
|
|
592
|
+
const details = [stderr.trim(), stdout.trim()].filter(Boolean).join(`
|
|
593
|
+
`);
|
|
594
|
+
throw new Error(`Failed to build native Rig git tools: ${details || `zig exited with code ${exitCode}`}`);
|
|
595
|
+
}
|
|
596
|
+
chmodSync2(tempOutputPath, 493);
|
|
597
|
+
if (existsSync3(outputPath) && await hasMatchingNativeBuildManifest(manifestPath, buildKey)) {
|
|
598
|
+
rmSync2(tempOutputPath, { force: true });
|
|
599
|
+
chmodSync2(outputPath, 493);
|
|
600
|
+
return outputPath;
|
|
601
|
+
}
|
|
602
|
+
publishGitBinary(tempOutputPath, outputPath);
|
|
603
|
+
if (!binarySupportsTrackerCommandsSync(outputPath)) {
|
|
604
|
+
rmSync2(outputPath, { force: true });
|
|
605
|
+
throw new Error("Failed to build native Rig git tools: tracker command probe failed");
|
|
606
|
+
}
|
|
607
|
+
await Bun.write(manifestPath, `${JSON.stringify({ version: 1, buildKey }, null, 2)}
|
|
608
|
+
`);
|
|
609
|
+
return outputPath;
|
|
610
|
+
}
|
|
611
|
+
async function materializeRigGitBinary(targetDir) {
|
|
612
|
+
const sourcePath = await ensureRigGitBinaryPath();
|
|
613
|
+
const targetPath = resolve3(targetDir, runtimeRigGitFileName());
|
|
614
|
+
mkdirSync3(targetDir, { recursive: true });
|
|
615
|
+
const sourceDigest = await sha256File2(sourcePath);
|
|
616
|
+
const buildKey = JSON.stringify({
|
|
617
|
+
version: 1,
|
|
618
|
+
sourcePath,
|
|
619
|
+
sourceDigest
|
|
620
|
+
});
|
|
621
|
+
const needsCopy = !existsSync3(targetPath) || !await hasMatchingNativeBuildManifest(nativeBuildManifestPath(targetPath), buildKey);
|
|
622
|
+
if (needsCopy) {
|
|
623
|
+
copyFileSync2(sourcePath, targetPath);
|
|
624
|
+
chmodSync2(targetPath, 493);
|
|
625
|
+
await Bun.write(nativeBuildManifestPath(targetPath), `${JSON.stringify({ version: 1, buildKey }, null, 2)}
|
|
626
|
+
`);
|
|
627
|
+
}
|
|
628
|
+
return targetPath;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// packages/isolation-plugin/src/runtime-native.ts
|
|
632
|
+
import { dlopen, ptr, suffix, toBuffer } from "bun:ffi";
|
|
633
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync4, renameSync as renameSync4, rmSync as rmSync3, statSync as statSync2 } from "fs";
|
|
634
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
635
|
+
import { dirname as dirname3, resolve as resolve4 } from "path";
|
|
636
|
+
|
|
637
|
+
// packages/isolation-plugin/src/sidecar-arg.ts
|
|
638
|
+
var RIG_NATIVE_RUNTIME_SIDECAR_ARG = "__rig_native_runtime_sidecar";
|
|
639
|
+
|
|
640
|
+
// packages/isolation-plugin/src/runtime-native.ts
|
|
641
|
+
var sharedNativeRuntimeOutputDir = resolve4(tmpdir3(), "rig-native");
|
|
642
|
+
var sharedNativeRuntimeOutputPath = resolve4(sharedNativeRuntimeOutputDir, `runtime-native-${process.platform}-${process.arch}.${suffix}`);
|
|
643
|
+
var colocatedNativeRuntimeFileName = `runtime-native.${suffix}`;
|
|
644
|
+
var nativeRuntimeLibrary = await loadNativeRuntimeLibrary();
|
|
645
|
+
function runtimePrepareTrackedPathsNative(input) {
|
|
646
|
+
const response = runNativeRuntimeSidecar({
|
|
647
|
+
op: "prepare-paths",
|
|
648
|
+
input
|
|
649
|
+
});
|
|
650
|
+
if (!response.ok) {
|
|
651
|
+
throw new Error(response.error);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
function runtimeLinkDependencyLayerNative(sourceDir, targetDir) {
|
|
655
|
+
const response = runNativeRuntimeSidecar({
|
|
656
|
+
op: "link-dependency-layer",
|
|
657
|
+
input: { sourceDir, targetDir }
|
|
658
|
+
});
|
|
659
|
+
if (!response.ok) {
|
|
660
|
+
throw new Error(response.error);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
async function ensureNativeRuntimeLibraryPath(outputPath = sharedNativeRuntimeOutputPath, options = {}) {
|
|
664
|
+
const explicitLib = process.env.RIG_NATIVE_RUNTIME_LIB?.trim();
|
|
665
|
+
if (explicitLib && existsSync4(explicitLib)) {
|
|
666
|
+
return explicitLib;
|
|
667
|
+
}
|
|
668
|
+
const embeddedPath = extractEmbeddedNative("snapshot");
|
|
669
|
+
if (embeddedPath) {
|
|
670
|
+
return embeddedPath;
|
|
671
|
+
}
|
|
672
|
+
if (await buildNativeRuntimeLibrary(outputPath, options)) {
|
|
673
|
+
return outputPath;
|
|
674
|
+
}
|
|
675
|
+
return !options.force && existsSync4(outputPath) ? outputPath : null;
|
|
676
|
+
}
|
|
677
|
+
async function materializeNativeRuntimeLibrary(targetDir) {
|
|
678
|
+
const sourcePath = await ensureNativeRuntimeLibraryPath();
|
|
679
|
+
if (!sourcePath) {
|
|
680
|
+
return null;
|
|
681
|
+
}
|
|
682
|
+
const targetPath = resolve4(targetDir, colocatedNativeRuntimeFileName);
|
|
683
|
+
mkdirSync4(targetDir, { recursive: true });
|
|
684
|
+
const needsCopy = !existsSync4(targetPath) || statSync2(sourcePath).mtimeMs > statSync2(targetPath).mtimeMs;
|
|
685
|
+
if (needsCopy) {
|
|
686
|
+
copyFileSync3(sourcePath, targetPath);
|
|
687
|
+
}
|
|
688
|
+
return targetPath;
|
|
689
|
+
}
|
|
690
|
+
async function loadNativeRuntimeLibrary() {
|
|
691
|
+
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
692
|
+
return null;
|
|
693
|
+
}
|
|
694
|
+
const explicitLib = process.env.RIG_NATIVE_RUNTIME_LIB?.trim();
|
|
695
|
+
if (explicitLib && existsSync4(explicitLib)) {
|
|
696
|
+
const loaded = tryDlopenNativeRuntimeLibrary(explicitLib);
|
|
697
|
+
if (loaded) {
|
|
698
|
+
return loaded;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
const embeddedPath = extractEmbeddedNative("snapshot");
|
|
702
|
+
if (embeddedPath) {
|
|
703
|
+
const loaded = tryDlopenNativeRuntimeLibrary(embeddedPath);
|
|
704
|
+
if (loaded) {
|
|
705
|
+
return loaded;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
for (const candidate of nativeRuntimeLibraryCandidates()) {
|
|
709
|
+
if (!candidate || !existsSync4(candidate)) {
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
const loaded = tryDlopenNativeRuntimeLibrary(candidate);
|
|
713
|
+
if (loaded) {
|
|
714
|
+
return loaded;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
const builtLibraryPath = await ensureNativeRuntimeLibraryPath(sharedNativeRuntimeOutputPath, { force: true });
|
|
718
|
+
if (!builtLibraryPath) {
|
|
719
|
+
return null;
|
|
720
|
+
}
|
|
721
|
+
return tryDlopenNativeRuntimeLibrary(builtLibraryPath);
|
|
722
|
+
}
|
|
723
|
+
function nativePackageLibraryCandidates(fromDir, names) {
|
|
724
|
+
const candidates = [];
|
|
725
|
+
let cursor = resolve4(fromDir);
|
|
726
|
+
for (let index = 0;index < 8; index += 1) {
|
|
727
|
+
for (const name of names) {
|
|
728
|
+
candidates.push(resolve4(cursor, "native", `${process.platform}-${process.arch}`, name), resolve4(cursor, "native", `${process.platform}-${process.arch}`, "lib", name), resolve4(cursor, "native", name), resolve4(cursor, "native", "lib", name));
|
|
729
|
+
}
|
|
730
|
+
const parent = dirname3(cursor);
|
|
731
|
+
if (parent === cursor)
|
|
732
|
+
break;
|
|
733
|
+
cursor = parent;
|
|
734
|
+
}
|
|
735
|
+
return candidates;
|
|
736
|
+
}
|
|
737
|
+
function nativeRuntimeLibraryCandidates() {
|
|
738
|
+
const explicit = process.env.RIG_NATIVE_RUNTIME_LIB?.trim() || "";
|
|
739
|
+
const execDir = process.execPath?.trim() ? dirname3(process.execPath.trim()) : "";
|
|
740
|
+
const platformSpecific = `runtime-native-${process.platform}-${process.arch}.${suffix}`;
|
|
741
|
+
return [...new Set([
|
|
742
|
+
explicit,
|
|
743
|
+
...nativePackageLibraryCandidates(import.meta.dir, [colocatedNativeRuntimeFileName, platformSpecific]),
|
|
744
|
+
execDir ? resolve4(execDir, colocatedNativeRuntimeFileName) : "",
|
|
745
|
+
execDir ? resolve4(execDir, platformSpecific) : "",
|
|
746
|
+
execDir ? resolve4(execDir, "..", colocatedNativeRuntimeFileName) : "",
|
|
747
|
+
execDir ? resolve4(execDir, "..", platformSpecific) : "",
|
|
748
|
+
execDir ? resolve4(execDir, "lib", colocatedNativeRuntimeFileName) : "",
|
|
749
|
+
execDir ? resolve4(execDir, "..", "lib", colocatedNativeRuntimeFileName) : "",
|
|
750
|
+
sharedNativeRuntimeOutputPath
|
|
751
|
+
].filter(Boolean))];
|
|
752
|
+
}
|
|
753
|
+
function resolveNativeRuntimeSourcePath() {
|
|
754
|
+
const explicit = process.env.RIG_NATIVE_RUNTIME_SOURCE?.trim();
|
|
755
|
+
if (explicit && existsSync4(explicit)) {
|
|
756
|
+
return explicit;
|
|
757
|
+
}
|
|
758
|
+
const bundled = resolve4(import.meta.dir, "../native/snapshot.zig");
|
|
759
|
+
return existsSync4(bundled) ? bundled : null;
|
|
760
|
+
}
|
|
761
|
+
function resolveNativeRuntimeSidecarSourcePath() {
|
|
762
|
+
const envRoots = [
|
|
763
|
+
process.cwd()?.trim(),
|
|
764
|
+
process.env.RIG_HOST_PROJECT_ROOT?.trim(),
|
|
765
|
+
process.env.PROJECT_RIG_ROOT?.trim()
|
|
766
|
+
].filter(Boolean);
|
|
767
|
+
for (const root of envRoots) {
|
|
768
|
+
for (const relative of [
|
|
769
|
+
"packages/isolation-plugin/src/runtime-native-sidecar.ts",
|
|
770
|
+
"packages/isolation-plugin/dist/src/runtime-native-sidecar.js"
|
|
771
|
+
]) {
|
|
772
|
+
const candidate = resolve4(root, relative);
|
|
773
|
+
if (existsSync4(candidate)) {
|
|
774
|
+
return candidate;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
for (const localCandidate of [
|
|
779
|
+
resolve4(import.meta.dir, "runtime-native-sidecar.js"),
|
|
780
|
+
resolve4(import.meta.dir, "runtime-native-sidecar.ts")
|
|
781
|
+
]) {
|
|
782
|
+
if (existsSync4(localCandidate))
|
|
783
|
+
return localCandidate;
|
|
784
|
+
}
|
|
785
|
+
return null;
|
|
786
|
+
}
|
|
787
|
+
async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
788
|
+
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
789
|
+
return false;
|
|
790
|
+
}
|
|
791
|
+
const zigBinary = Bun.which("zig");
|
|
792
|
+
const sourcePath = resolveNativeRuntimeSourcePath();
|
|
793
|
+
if (!zigBinary || !sourcePath) {
|
|
794
|
+
return false;
|
|
795
|
+
}
|
|
796
|
+
const tempOutputPath = `${outputPath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
797
|
+
try {
|
|
798
|
+
mkdirSync4(dirname3(outputPath), { recursive: true });
|
|
799
|
+
const needsBuild = options.force === true || !existsSync4(outputPath) || statSync2(sourcePath).mtimeMs > statSync2(outputPath).mtimeMs;
|
|
800
|
+
if (!needsBuild) {
|
|
801
|
+
return true;
|
|
802
|
+
}
|
|
803
|
+
const build = Bun.spawn([
|
|
804
|
+
zigBinary,
|
|
805
|
+
"build-lib",
|
|
806
|
+
sourcePath,
|
|
807
|
+
"-dynamic",
|
|
808
|
+
"-O",
|
|
809
|
+
"ReleaseFast",
|
|
810
|
+
`-femit-bin=${tempOutputPath}`
|
|
811
|
+
], {
|
|
812
|
+
cwd: import.meta.dir,
|
|
813
|
+
stdout: "pipe",
|
|
814
|
+
stderr: "pipe"
|
|
815
|
+
});
|
|
816
|
+
const exitCode = await build.exited;
|
|
817
|
+
if (exitCode !== 0 || !existsSync4(tempOutputPath)) {
|
|
818
|
+
rmSync3(tempOutputPath, { force: true });
|
|
819
|
+
return false;
|
|
820
|
+
}
|
|
821
|
+
renameSync4(tempOutputPath, outputPath);
|
|
822
|
+
return true;
|
|
823
|
+
} catch {
|
|
824
|
+
rmSync3(tempOutputPath, { force: true });
|
|
825
|
+
return false;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
function tryDlopenNativeRuntimeLibrary(outputPath) {
|
|
829
|
+
try {
|
|
830
|
+
return dlopen(outputPath, {
|
|
831
|
+
rig_scope_match: {
|
|
832
|
+
args: ["ptr", "ptr"],
|
|
833
|
+
returns: "u8"
|
|
834
|
+
},
|
|
835
|
+
snapshot_capture: {
|
|
836
|
+
args: ["ptr", "u64", "ptr", "u64"],
|
|
837
|
+
returns: "ptr"
|
|
838
|
+
},
|
|
839
|
+
snapshot_delta: {
|
|
840
|
+
args: ["ptr", "ptr"],
|
|
841
|
+
returns: "ptr"
|
|
842
|
+
},
|
|
843
|
+
snapshot_store_delta: {
|
|
844
|
+
args: ["ptr", "ptr", "ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64"],
|
|
845
|
+
returns: "ptr"
|
|
846
|
+
},
|
|
847
|
+
snapshot_inspect_delta: {
|
|
848
|
+
args: ["ptr", "u64"],
|
|
849
|
+
returns: "ptr"
|
|
850
|
+
},
|
|
851
|
+
snapshot_apply_delta: {
|
|
852
|
+
args: ["ptr", "u64", "ptr", "u64"],
|
|
853
|
+
returns: "ptr"
|
|
854
|
+
},
|
|
855
|
+
snapshot_release: {
|
|
856
|
+
args: ["ptr"],
|
|
857
|
+
returns: "void"
|
|
858
|
+
},
|
|
859
|
+
runtime_hash_file: {
|
|
860
|
+
args: ["ptr", "u64"],
|
|
861
|
+
returns: "ptr"
|
|
862
|
+
},
|
|
863
|
+
runtime_hash_tree: {
|
|
864
|
+
args: ["ptr", "u64"],
|
|
865
|
+
returns: "ptr"
|
|
866
|
+
},
|
|
867
|
+
runtime_prepare_paths: {
|
|
868
|
+
args: ["ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64"],
|
|
869
|
+
returns: "ptr"
|
|
870
|
+
},
|
|
871
|
+
runtime_link_dependency_layer: {
|
|
872
|
+
args: ["ptr", "u64", "ptr", "u64"],
|
|
873
|
+
returns: "ptr"
|
|
874
|
+
},
|
|
875
|
+
runtime_scan_worktrees: {
|
|
876
|
+
args: ["ptr", "u64"],
|
|
877
|
+
returns: "ptr"
|
|
878
|
+
}
|
|
879
|
+
});
|
|
880
|
+
} catch {
|
|
881
|
+
return null;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
function resolveNativeRuntimeSidecarCommand(request) {
|
|
885
|
+
if (hasEmbeddedNatives()) {
|
|
886
|
+
return {
|
|
887
|
+
argv: [process.execPath, RIG_NATIVE_RUNTIME_SIDECAR_ARG, JSON.stringify(request)],
|
|
888
|
+
env: {}
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
const hostBinary = process.env.RIG_NATIVE_HOST_BINARY?.trim();
|
|
892
|
+
if (hostBinary) {
|
|
893
|
+
return {
|
|
894
|
+
argv: [hostBinary, RIG_NATIVE_RUNTIME_SIDECAR_ARG, JSON.stringify(request)],
|
|
895
|
+
env: {}
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
const sidecarSourcePath = resolveNativeRuntimeSidecarSourcePath();
|
|
899
|
+
if (!sidecarSourcePath) {
|
|
900
|
+
throw new Error("runtime-native-sidecar.ts source file not found.");
|
|
901
|
+
}
|
|
902
|
+
const bunCli = resolveNativeRuntimeSidecarInvocation();
|
|
903
|
+
return {
|
|
904
|
+
argv: [bunCli.command, sidecarSourcePath, JSON.stringify(request)],
|
|
905
|
+
env: bunCli.env
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
function runNativeRuntimeSidecar(request) {
|
|
909
|
+
const { argv, env } = resolveNativeRuntimeSidecarCommand(request);
|
|
910
|
+
const proc = Bun.spawnSync(argv, {
|
|
911
|
+
cwd: process.env.RIG_HOST_PROJECT_ROOT?.trim() || process.cwd(),
|
|
912
|
+
stdout: "pipe",
|
|
913
|
+
stderr: "pipe",
|
|
914
|
+
env: {
|
|
915
|
+
...process.env,
|
|
916
|
+
...env,
|
|
917
|
+
RIG_NATIVE_RUNTIME_SIDECAR: "1"
|
|
918
|
+
}
|
|
919
|
+
});
|
|
920
|
+
if (proc.exitCode !== 0) {
|
|
921
|
+
throw new Error(proc.stderr.toString() || proc.stdout.toString() || `runtime native sidecar exited ${proc.exitCode}`);
|
|
922
|
+
}
|
|
923
|
+
const stdout = proc.stdout.toString().trim();
|
|
924
|
+
if (!stdout) {
|
|
925
|
+
throw new Error("runtime native sidecar returned empty output.");
|
|
926
|
+
}
|
|
927
|
+
const responseLine = stdout.split(`
|
|
928
|
+
`).map((line) => line.trim()).filter((line) => line.startsWith("{")).at(-1);
|
|
929
|
+
if (!responseLine) {
|
|
930
|
+
throw new Error(`runtime native sidecar returned no JSON response: ${stdout}`);
|
|
931
|
+
}
|
|
932
|
+
return JSON.parse(responseLine);
|
|
933
|
+
}
|
|
934
|
+
function resolveNativeRuntimeSidecarInvocation() {
|
|
935
|
+
const bunPath = Bun.which("bun");
|
|
936
|
+
if (bunPath) {
|
|
937
|
+
return { command: bunPath, env: {} };
|
|
938
|
+
}
|
|
939
|
+
if (process.execPath?.trim()) {
|
|
940
|
+
return {
|
|
941
|
+
command: process.execPath,
|
|
942
|
+
env: { BUN_BE_BUN: "1" }
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
throw new Error("bun is required to run the runtime native sidecar.");
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// packages/isolation-plugin/src/isolation/toolchain.ts
|
|
949
|
+
import {
|
|
950
|
+
GUARD_TOOLCHAIN_SOURCES,
|
|
951
|
+
LIFECYCLE_TOOLCHAIN_SOURCES,
|
|
952
|
+
TOOL_MATERIALIZER
|
|
953
|
+
} from "@rig/contracts";
|
|
954
|
+
import { defineCapability } from "@rig/core/capability";
|
|
955
|
+
import { buildProjectPluginHost, requireInstalledCapability } from "@rig/core/capability-loaders";
|
|
956
|
+
import { resolveBunBinaryPath } from "@rig/core/runtime-paths";
|
|
957
|
+
|
|
958
|
+
// packages/isolation-plugin/src/isolation/shared.ts
|
|
959
|
+
import { agentId, safeGitRefComponent, taskRuntimeId } from "@rig/core/safe-identifiers";
|
|
960
|
+
import { resolveCheckoutRoot } from "@rig/core/checkout-root";
|
|
961
|
+
var generatedCredentialFiles = new Set;
|
|
962
|
+
function resolveMonorepoRoot(projectRoot) {
|
|
963
|
+
return resolveCheckoutRoot(projectRoot);
|
|
964
|
+
}
|
|
965
|
+
function sha256Hex(input) {
|
|
966
|
+
const hasher = new Bun.CryptoHasher("sha256");
|
|
967
|
+
hasher.update(input);
|
|
968
|
+
return hasher.digest("hex");
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
// packages/isolation-plugin/src/isolation/toolchain.ts
|
|
972
|
+
var ToolMaterializerCap = defineCapability(TOOL_MATERIALIZER);
|
|
973
|
+
var GuardToolchainSourcesCap = defineCapability(GUARD_TOOLCHAIN_SOURCES);
|
|
974
|
+
var LifecycleToolchainSourcesCap = defineCapability(LIFECYCLE_TOOLCHAIN_SOURCES);
|
|
975
|
+
var SNAPSHOT_SIDECAR_SOURCE = ["packages", "isolation-plugin", "src", "snapshot-sidecar.ts"].join("/");
|
|
976
|
+
async function resolveContributedToolchainSources(projectRoot) {
|
|
977
|
+
const host = await buildProjectPluginHost(projectRoot);
|
|
978
|
+
const contributions = [];
|
|
979
|
+
if (host) {
|
|
980
|
+
for (const cap of [GuardToolchainSourcesCap, LifecycleToolchainSourcesCap]) {
|
|
981
|
+
const contribution = await cap.resolve(host);
|
|
982
|
+
if (contribution)
|
|
983
|
+
contributions.push(contribution);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
const hookSources = contributions.flatMap((c) => (c.hookBinaries ?? []).map((hb) => [hb.name, hb.source]));
|
|
987
|
+
const namedSources = {};
|
|
988
|
+
for (const c of contributions) {
|
|
989
|
+
for (const [key, value] of Object.entries(c.namedSources ?? {}))
|
|
990
|
+
namedSources[key] = value;
|
|
991
|
+
}
|
|
992
|
+
return { hookSources, namedSources };
|
|
993
|
+
}
|
|
994
|
+
var toolMaterializer = () => requireInstalledCapability(ToolMaterializerCap, "tool-materializer capability unavailable: load @rig/provider-plugin (default bundle) before provisioning runtimes.");
|
|
995
|
+
var GIT_INDEX_LOCK_MAX_RETRIES = 20;
|
|
996
|
+
var GIT_INDEX_LOCK_RETRY_DELAY_MS = 250;
|
|
997
|
+
var GIT_INDEX_LOCK_STALE_AFTER_MS = 5000;
|
|
998
|
+
function resolveRigSourceRoot(projectRoot) {
|
|
999
|
+
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim();
|
|
1000
|
+
if (hostProjectRoot && existsSync5(resolve5(hostProjectRoot, "packages/cli/bin/rig-agent.ts"))) {
|
|
1001
|
+
return hostProjectRoot;
|
|
1002
|
+
}
|
|
1003
|
+
const fromModule = resolve5(import.meta.dir, "../../../../../..");
|
|
1004
|
+
if (existsSync5(resolve5(fromModule, "packages/cli/bin/rig-agent.ts"))) {
|
|
1005
|
+
return fromModule;
|
|
1006
|
+
}
|
|
1007
|
+
return projectRoot;
|
|
1008
|
+
}
|
|
1009
|
+
function prepareTrackedRuntimePaths(logsDir, stateDir, sessionDir) {
|
|
1010
|
+
for (const path of [logsDir, stateDir, sessionDir, resolve5(sessionDir, "session.json")]) {
|
|
1011
|
+
removeSymbolicLink(path);
|
|
1012
|
+
}
|
|
1013
|
+
runtimePrepareTrackedPathsNative({
|
|
1014
|
+
logsDir,
|
|
1015
|
+
stateDir,
|
|
1016
|
+
sessionDir,
|
|
1017
|
+
controlledBashLogFile: resolve5(logsDir, "controlled-bash.jsonl"),
|
|
1018
|
+
eventsFile: resolve5(logsDir, "control-plane.events.jsonl")
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
async function initializeRuntimeStateFiles(stateDir, sessionDir, taskId) {
|
|
1022
|
+
await mkdir(stateDir, { recursive: true });
|
|
1023
|
+
await mkdir(sessionDir, { recursive: true });
|
|
1024
|
+
const failedApproachesPath = resolve5(stateDir, "failed_approaches.md");
|
|
1025
|
+
if (!existsSync5(failedApproachesPath)) {
|
|
1026
|
+
await writeFile(failedApproachesPath, `# Failed Approaches
|
|
1027
|
+
|
|
1028
|
+
`);
|
|
1029
|
+
}
|
|
1030
|
+
const hookTripsPath = resolve5(stateDir, "hook_trips.log");
|
|
1031
|
+
if (!existsSync5(hookTripsPath)) {
|
|
1032
|
+
await writeFile(hookTripsPath, "");
|
|
1033
|
+
}
|
|
1034
|
+
const sessionFile = resolve5(sessionDir, "session.json");
|
|
1035
|
+
if (taskId) {
|
|
1036
|
+
await writeFile(sessionFile, JSON.stringify({ activeTaskIds: [taskId] }));
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
async function resetEphemeralTaskArtifacts(workspaceDir, taskId) {
|
|
1040
|
+
const artifactsRoot = resolve5(workspaceDir, "artifacts");
|
|
1041
|
+
const taskSegment = safePathSegment(taskId, { fallback: "task", maxLength: 96 });
|
|
1042
|
+
const artifactDir = assertPathInsideRoot(artifactsRoot, resolve5(artifactsRoot, taskSegment), "task artifact directory");
|
|
1043
|
+
const runtimeSnapshotDir = assertPathInsideRoot(artifactDir, resolve5(artifactDir, "runtime-snapshots"), "runtime snapshot directory");
|
|
1044
|
+
let preservedTrackedFiles = false;
|
|
1045
|
+
for (const file of [
|
|
1046
|
+
"changed-files.txt",
|
|
1047
|
+
"pr-state.json",
|
|
1048
|
+
"review-state.json",
|
|
1049
|
+
"review-feedback.md",
|
|
1050
|
+
"review-greptile-raw.json",
|
|
1051
|
+
"review-status.txt",
|
|
1052
|
+
"validation-summary.json"
|
|
1053
|
+
]) {
|
|
1054
|
+
const relativePath = `artifacts/${taskSegment}/${file}`;
|
|
1055
|
+
if (await resetTrackedArtifactPath(workspaceDir, relativePath)) {
|
|
1056
|
+
preservedTrackedFiles = true;
|
|
1057
|
+
continue;
|
|
1058
|
+
}
|
|
1059
|
+
rmSync4(assertPathInsideRoot(artifactDir, resolve5(artifactDir, file), "task artifact file"), { force: true });
|
|
1060
|
+
}
|
|
1061
|
+
const runtimeSnapshotRelativePath = `artifacts/${taskSegment}/runtime-snapshots`;
|
|
1062
|
+
if (await resetTrackedArtifactPath(workspaceDir, runtimeSnapshotRelativePath)) {
|
|
1063
|
+
preservedTrackedFiles = true;
|
|
1064
|
+
} else {
|
|
1065
|
+
rmSync4(runtimeSnapshotDir, { recursive: true, force: true });
|
|
1066
|
+
}
|
|
1067
|
+
if (preservedTrackedFiles) {
|
|
1068
|
+
console.log(`[rig-agent] Preserved tracked runtime artifact files in ${taskId}; skipped ephemeral cleanup for committed paths.`);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
function prepareRuntimeWorkspace(projectRoot, workspaceDir) {
|
|
1072
|
+
const monorepoRoot = resolveMonorepoRoot(projectRoot);
|
|
1073
|
+
linkRuntimeDependencyLayers(monorepoRoot, workspaceDir);
|
|
1074
|
+
syncRuntimeWorkspaceSources(projectRoot, workspaceDir);
|
|
1075
|
+
}
|
|
1076
|
+
async function materializeRuntimeHostToolWrappers(binDir) {
|
|
1077
|
+
const mat = toolMaterializer();
|
|
1078
|
+
await mat.materializeRuntimeToolGateway(binDir);
|
|
1079
|
+
await mat.materializeRuntimeFileTools(binDir);
|
|
1080
|
+
}
|
|
1081
|
+
async function buildRuntimeToolchain(options) {
|
|
1082
|
+
const { hookSources, namedSources } = await resolveContributedToolchainSources(options.projectRoot);
|
|
1083
|
+
const controlledBashSource = namedSources["controlled-bash"];
|
|
1084
|
+
const runtimeBins = ensureRuntimeBinTrees(options.binDir);
|
|
1085
|
+
const nativeRuntimeLibraryPath = await materializeNativeRuntimeLibrary(options.binDir);
|
|
1086
|
+
if (!nativeRuntimeLibraryPath) {
|
|
1087
|
+
throw new Error("Failed to provision the native Zig runtime library.");
|
|
1088
|
+
}
|
|
1089
|
+
const rigSourceRoot = resolveRigSourceRoot(options.projectRoot);
|
|
1090
|
+
await buildBinary("packages/cli/bin/rig.ts", resolve5(options.binDir, "rig"), rigSourceRoot, undefined, runtimeRigCliBinaryExternals);
|
|
1091
|
+
await buildBinary("packages/cli/bin/rig-agent.ts", resolve5(options.binDir, "rig-agent"), rigSourceRoot, {
|
|
1092
|
+
...options.runtimeSecretDefines,
|
|
1093
|
+
AGENT_TASK_ID: options.taskId,
|
|
1094
|
+
AGENT_PROJECT_ROOT: options.projectRoot,
|
|
1095
|
+
AGENT_RUNTIME_ID: options.runtimeId,
|
|
1096
|
+
AGENT_SCOPE_HASH: options.bakedScopeHash,
|
|
1097
|
+
AGENT_MANIFEST_PATH: options.manifestPath,
|
|
1098
|
+
AGENT_BINARY_PATH: resolve5(options.binDir, "rig-agent"),
|
|
1099
|
+
AGENT_INFO_OUTPUT: options.bakedInfoOutput,
|
|
1100
|
+
AGENT_DEPS_OUTPUT: options.bakedDepsOutput,
|
|
1101
|
+
AGENT_STATUS_OUTPUT: options.bakedStatusOutput
|
|
1102
|
+
});
|
|
1103
|
+
if (controlledBashSource) {
|
|
1104
|
+
await buildBinary(controlledBashSource, resolve5(options.binDir, "controlled-bash"), rigSourceRoot, {
|
|
1105
|
+
AGENT_PROJECT_ROOT: options.projectRoot,
|
|
1106
|
+
AGENT_LOGS_DIR: options.logsDir,
|
|
1107
|
+
AGENT_MONOREPO_ROOT: resolveMonorepoRoot(options.projectRoot),
|
|
1108
|
+
AGENT_TS_API_TESTS_DIR: resolve5(options.workspaceDir, "TSAPITests"),
|
|
1109
|
+
AGENT_RIG_AGENT_BIN: resolve5(options.binDir, "rig-agent")
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
await buildBinary("packages/cli/bin/rig-browser-tool.ts", resolve5(options.binDir, toolMaterializer().runtimeBrowserToolBinaryName()), rigSourceRoot);
|
|
1113
|
+
await buildBinary(SNAPSHOT_SIDECAR_SOURCE, resolve5(options.binDir, "snapshot-sidecar"), rigSourceRoot, {
|
|
1114
|
+
AGENT_PROJECT_ROOT: options.projectRoot,
|
|
1115
|
+
AGENT_BUN_PATH: resolveBunBinaryPath()
|
|
1116
|
+
});
|
|
1117
|
+
const hookDefines = {
|
|
1118
|
+
AGENT_PROJECT_ROOT: options.projectRoot,
|
|
1119
|
+
AGENT_BUN_PATH: resolveBunBinaryPath()
|
|
1120
|
+
};
|
|
1121
|
+
for (const [hookName, hookSource] of hookSources) {
|
|
1122
|
+
await buildBinary(hookSource, resolve5(runtimeBins.hooksDir, hookName), rigSourceRoot, hookDefines);
|
|
1123
|
+
}
|
|
1124
|
+
const pluginsDir = resolve5(options.projectRoot, "rig/plugins");
|
|
1125
|
+
if (existsSync5(pluginsDir)) {
|
|
1126
|
+
for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
|
|
1127
|
+
const match = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
1128
|
+
if (!match)
|
|
1129
|
+
continue;
|
|
1130
|
+
await buildBinary(`rig/plugins/${entry.name}`, resolve5(runtimeBins.pluginsDir, match[1]), options.projectRoot);
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
await materializeRigGitBinary(options.binDir);
|
|
1134
|
+
const mat = toolMaterializer();
|
|
1135
|
+
await mat.materializeClaudeToolRouterBinary(rigSourceRoot, options.binDir);
|
|
1136
|
+
await materializeRuntimeHostToolWrappers(options.binDir);
|
|
1137
|
+
await mat.materializeRuntimeBrowserTools(options.binDir);
|
|
1138
|
+
}
|
|
1139
|
+
async function writeRuntimeManifest(config) {
|
|
1140
|
+
const scopeHash = sha256Hex(JSON.stringify(config.scopes));
|
|
1141
|
+
const binarySha256 = sha256Hex(readFileSync3(config.binaryPath));
|
|
1142
|
+
const manifestPath = resolve5(config.runtimeRoot, "manifest.json");
|
|
1143
|
+
const manifest = {
|
|
1144
|
+
runtimeId: config.runtimeId,
|
|
1145
|
+
taskId: config.taskId,
|
|
1146
|
+
scopeHash,
|
|
1147
|
+
builtAt: new Date().toISOString(),
|
|
1148
|
+
workspaceDir: config.workspaceDir,
|
|
1149
|
+
binDir: config.binDir,
|
|
1150
|
+
binary: {
|
|
1151
|
+
path: config.binaryPath,
|
|
1152
|
+
sha256: binarySha256
|
|
1153
|
+
}
|
|
1154
|
+
};
|
|
1155
|
+
await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
1156
|
+
`, "utf-8");
|
|
1157
|
+
}
|
|
1158
|
+
function syncRuntimeWorkspaceSources(projectRoot, workspaceDir) {}
|
|
1159
|
+
function removeSymbolicLink(path) {
|
|
1160
|
+
try {
|
|
1161
|
+
if (!lstatSync(path).isSymbolicLink()) {
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
} catch {
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
rmSync4(path, { force: true, recursive: true });
|
|
1168
|
+
}
|
|
1169
|
+
async function resetTrackedArtifactPath(workspaceDir, relativePath) {
|
|
1170
|
+
const tracked = await runGitLsFiles(workspaceDir, relativePath);
|
|
1171
|
+
if (!tracked) {
|
|
1172
|
+
return false;
|
|
1173
|
+
}
|
|
1174
|
+
await restoreTrackedArtifactPathWithRetry(workspaceDir, relativePath, async () => {
|
|
1175
|
+
const restore = await Bun.$`git -C ${workspaceDir} checkout -- ${relativePath}`.quiet().nothrow();
|
|
1176
|
+
return {
|
|
1177
|
+
exitCode: restore.exitCode,
|
|
1178
|
+
output: restore.stderr.toString() || restore.stdout.toString()
|
|
1179
|
+
};
|
|
1180
|
+
}, { sleep: Bun.sleep });
|
|
1181
|
+
return true;
|
|
1182
|
+
}
|
|
1183
|
+
async function runGitLsFiles(workspaceDir, relativePath) {
|
|
1184
|
+
const tracked = await Bun.$`git -C ${workspaceDir} ls-files --error-unmatch -- ${relativePath}`.quiet().nothrow();
|
|
1185
|
+
return tracked.exitCode === 0;
|
|
1186
|
+
}
|
|
1187
|
+
async function restoreTrackedArtifactPathWithRetry(workspaceDir, relativePath, restorePath, options = {}) {
|
|
1188
|
+
const sleep = options.sleep ?? Bun.sleep;
|
|
1189
|
+
const maxRetries = options.maxRetries ?? GIT_INDEX_LOCK_MAX_RETRIES;
|
|
1190
|
+
const retryDelayMs = options.retryDelayMs ?? GIT_INDEX_LOCK_RETRY_DELAY_MS;
|
|
1191
|
+
const now = options.now ?? Date.now;
|
|
1192
|
+
const statMtimeMs = options.statMtimeMs ?? readFileMtimeMs;
|
|
1193
|
+
const removeFile = options.removeFile ?? ((path) => rmSync4(path, { force: true }));
|
|
1194
|
+
const log = options.log ?? console.warn;
|
|
1195
|
+
let lastOutput = "";
|
|
1196
|
+
for (let attempt = 0;attempt <= maxRetries; attempt += 1) {
|
|
1197
|
+
const restore = await restorePath();
|
|
1198
|
+
if (restore.exitCode === 0) {
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
lastOutput = restore.output;
|
|
1202
|
+
if (!isGitIndexLockError(lastOutput)) {
|
|
1203
|
+
break;
|
|
1204
|
+
}
|
|
1205
|
+
const lockPath = parseGitIndexLockPath(lastOutput);
|
|
1206
|
+
if (attempt === maxRetries) {
|
|
1207
|
+
if (lockPath && tryClearStaleGitIndexLock(lockPath, {
|
|
1208
|
+
now,
|
|
1209
|
+
statMtimeMs,
|
|
1210
|
+
removeFile,
|
|
1211
|
+
log
|
|
1212
|
+
})) {
|
|
1213
|
+
const recovered = await restorePath();
|
|
1214
|
+
if (recovered.exitCode === 0) {
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
lastOutput = recovered.output;
|
|
1218
|
+
}
|
|
1219
|
+
break;
|
|
1220
|
+
}
|
|
1221
|
+
await sleep(retryDelayMs);
|
|
1222
|
+
}
|
|
1223
|
+
throw new Error(`Failed to restore tracked runtime artifact path ${relativePath} in ${workspaceDir}: ${lastOutput}`);
|
|
1224
|
+
}
|
|
1225
|
+
function isGitIndexLockError(output) {
|
|
1226
|
+
return /index\.lock|Unable to create '.+index\.lock'.*File exists/i.test(output);
|
|
1227
|
+
}
|
|
1228
|
+
function parseGitIndexLockPath(output) {
|
|
1229
|
+
const match = output.match(/Unable to create '([^']+index\.lock)'/i);
|
|
1230
|
+
return match?.[1] ?? null;
|
|
1231
|
+
}
|
|
1232
|
+
function tryClearStaleGitIndexLock(lockPath, options) {
|
|
1233
|
+
const mtimeMs = options.statMtimeMs(lockPath);
|
|
1234
|
+
if (mtimeMs === null) {
|
|
1235
|
+
return false;
|
|
1236
|
+
}
|
|
1237
|
+
if (options.now() - mtimeMs < GIT_INDEX_LOCK_STALE_AFTER_MS) {
|
|
1238
|
+
return false;
|
|
1239
|
+
}
|
|
1240
|
+
options.removeFile(lockPath);
|
|
1241
|
+
options.log(`[rig-agent] Cleared stale git index lock during run recovery: ${lockPath}`);
|
|
1242
|
+
return true;
|
|
1243
|
+
}
|
|
1244
|
+
function readFileMtimeMs(path) {
|
|
1245
|
+
try {
|
|
1246
|
+
return statSync3(path).mtimeMs;
|
|
1247
|
+
} catch {
|
|
1248
|
+
return null;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
function linkRuntimeDependencyLayers(monorepoRoot, workspaceDir) {
|
|
1252
|
+
linkGenericNodeModulesLayers(monorepoRoot, workspaceDir);
|
|
1253
|
+
const sourceNodeModules = resolve5(monorepoRoot, "humoongate", "node_modules");
|
|
1254
|
+
if (!existsSync5(sourceNodeModules)) {} else {
|
|
1255
|
+
const runtimeHumoongate = resolve5(workspaceDir, "humoongate");
|
|
1256
|
+
if (existsSync5(resolve5(runtimeHumoongate, "package.json"))) {
|
|
1257
|
+
const targetNodeModules = resolve5(runtimeHumoongate, "node_modules");
|
|
1258
|
+
runtimeLinkDependencyLayerNative(sourceNodeModules, targetNodeModules);
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
const runtimeHpNext = resolve5(workspaceDir, "microservices", "hp-next-frontend", "app");
|
|
1262
|
+
if (!existsSync5(resolve5(runtimeHpNext, "package.json"))) {
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
const sourceHpNextNodeModules = resolve5(monorepoRoot, "microservices", "hp-next-frontend", "app", "node_modules");
|
|
1266
|
+
const sourceMonorepoNodeModules = resolve5(monorepoRoot, "node_modules");
|
|
1267
|
+
const targetHpNextNodeModules = resolve5(runtimeHpNext, "node_modules");
|
|
1268
|
+
if (existsSync5(sourceHpNextNodeModules)) {
|
|
1269
|
+
runtimeLinkDependencyLayerNative(sourceHpNextNodeModules, targetHpNextNodeModules);
|
|
1270
|
+
return;
|
|
1271
|
+
}
|
|
1272
|
+
if (existsSync5(sourceMonorepoNodeModules)) {
|
|
1273
|
+
runtimeLinkDependencyLayerNative(sourceMonorepoNodeModules, targetHpNextNodeModules);
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
function linkGenericNodeModulesLayers(monorepoRoot, workspaceDir) {
|
|
1277
|
+
linkNodeModulesLayer(resolve5(monorepoRoot, "node_modules"), resolve5(workspaceDir, "node_modules"));
|
|
1278
|
+
for (const relativePackageDir of [
|
|
1279
|
+
"apps/native-app/apps/marketing",
|
|
1280
|
+
"apps/native-app/apps/web",
|
|
1281
|
+
"apps/native-app/apps/browser",
|
|
1282
|
+
"apps/native-app/apps/desktop",
|
|
1283
|
+
"apps/native-app/scripts",
|
|
1284
|
+
"packages/cli",
|
|
1285
|
+
"packages/client",
|
|
1286
|
+
"packages/contracts",
|
|
1287
|
+
"packages/core",
|
|
1288
|
+
"packages/hook-kit",
|
|
1289
|
+
"packages/plugin-testkit",
|
|
1290
|
+
"packages/runtime",
|
|
1291
|
+
"packages/scripts",
|
|
1292
|
+
"packages/shared",
|
|
1293
|
+
"packages/skill-loader",
|
|
1294
|
+
"packages/standard-plugin",
|
|
1295
|
+
"packages/validator-kit"
|
|
1296
|
+
]) {
|
|
1297
|
+
const workspacePackageDir = resolve5(workspaceDir, relativePackageDir);
|
|
1298
|
+
if (!existsSync5(resolve5(workspacePackageDir, "package.json"))) {
|
|
1299
|
+
continue;
|
|
1300
|
+
}
|
|
1301
|
+
linkNodeModulesLayer(resolve5(monorepoRoot, relativePackageDir, "node_modules"), resolve5(workspacePackageDir, "node_modules"));
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
function linkNodeModulesLayer(sourceDir, targetDir) {
|
|
1305
|
+
if (!existsSync5(sourceDir) || existsSync5(targetDir)) {
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1308
|
+
try {
|
|
1309
|
+
runtimeLinkDependencyLayerNative(sourceDir, targetDir);
|
|
1310
|
+
return;
|
|
1311
|
+
} catch (error) {
|
|
1312
|
+
console.warn(`[rig-agent] Native dependency-layer linking failed for ${targetDir}; using symlink fallback: ${error instanceof Error ? error.message : String(error)}`);
|
|
1313
|
+
}
|
|
1314
|
+
mkdirSync5(dirname4(targetDir), { recursive: true });
|
|
1315
|
+
symlinkSync(sourceDir, targetDir, "dir");
|
|
1316
|
+
}
|
|
1317
|
+
function ensureRuntimeBinTrees(runtimeBinDir) {
|
|
1318
|
+
const hooksDir = resolve5(runtimeBinDir, "hooks");
|
|
1319
|
+
const pluginsDir = resolve5(runtimeBinDir, "plugins");
|
|
1320
|
+
const validatorsDir = resolve5(runtimeBinDir, "validators");
|
|
1321
|
+
mkdirSync5(hooksDir, { recursive: true });
|
|
1322
|
+
mkdirSync5(pluginsDir, { recursive: true });
|
|
1323
|
+
mkdirSync5(validatorsDir, { recursive: true });
|
|
1324
|
+
return { hooksDir, pluginsDir, validatorsDir };
|
|
1325
|
+
}
|
|
1326
|
+
function runtimeWorktreeId(workspaceDir) {
|
|
1327
|
+
return workspaceDir.split("/").at(-1) || "runtime";
|
|
1328
|
+
}
|
|
1329
|
+
var __testOnly = {
|
|
1330
|
+
isGitIndexLockError,
|
|
1331
|
+
parseGitIndexLockPath,
|
|
1332
|
+
restoreTrackedArtifactPathWithRetry,
|
|
1333
|
+
tryClearStaleGitIndexLock
|
|
1334
|
+
};
|
|
1335
|
+
export {
|
|
1336
|
+
writeRuntimeManifest,
|
|
1337
|
+
syncRuntimeWorkspaceSources,
|
|
1338
|
+
runtimeWorktreeId,
|
|
1339
|
+
resolveContributedToolchainSources,
|
|
1340
|
+
resetEphemeralTaskArtifacts,
|
|
1341
|
+
prepareTrackedRuntimePaths,
|
|
1342
|
+
prepareRuntimeWorkspace,
|
|
1343
|
+
materializeRuntimeHostToolWrappers,
|
|
1344
|
+
initializeRuntimeStateFiles,
|
|
1345
|
+
buildRuntimeToolchain,
|
|
1346
|
+
buildBinary,
|
|
1347
|
+
__testOnly
|
|
1348
|
+
};
|