@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,1498 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
3
|
+
|
|
4
|
+
// packages/isolation-plugin/src/sandbox/utils.ts
|
|
5
|
+
import { resolveMonorepoRoot as resolveMonorepoRoot2 } from "@rig/core/layout";
|
|
6
|
+
var init_utils = () => {};
|
|
7
|
+
|
|
8
|
+
// packages/isolation-plugin/src/image.ts
|
|
9
|
+
import { ptr as ptr2, toBuffer as toBuffer2 } from "bun:ffi";
|
|
10
|
+
import {
|
|
11
|
+
existsSync as existsSync5,
|
|
12
|
+
readFileSync as readFileSync3,
|
|
13
|
+
readdirSync,
|
|
14
|
+
mkdirSync as mkdirSync4,
|
|
15
|
+
writeFileSync as writeFileSync3,
|
|
16
|
+
renameSync as renameSync4,
|
|
17
|
+
rmSync as rmSync3,
|
|
18
|
+
cpSync as cpSync2,
|
|
19
|
+
lstatSync,
|
|
20
|
+
unlinkSync,
|
|
21
|
+
symlinkSync
|
|
22
|
+
} from "fs";
|
|
23
|
+
import { resolve as resolve6 } from "path";
|
|
24
|
+
import { resolveRigLayout as resolveRigLayout2 } from "@rig/core/layout";
|
|
25
|
+
|
|
26
|
+
// packages/isolation-plugin/src/runtime-native.ts
|
|
27
|
+
import { dlopen, ptr, suffix, toBuffer } from "bun:ffi";
|
|
28
|
+
import { copyFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2, renameSync as renameSync2, rmSync, statSync as statSync2 } from "fs";
|
|
29
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
30
|
+
import { dirname, resolve as resolve2 } from "path";
|
|
31
|
+
|
|
32
|
+
// packages/isolation-plugin/src/native-extract.ts
|
|
33
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "fs";
|
|
34
|
+
import { tmpdir } from "os";
|
|
35
|
+
import { resolve } from "path";
|
|
36
|
+
|
|
37
|
+
// packages/isolation-plugin/src/embedded-native-assets.ts
|
|
38
|
+
var embeddedNatives = null;
|
|
39
|
+
|
|
40
|
+
// packages/isolation-plugin/src/native-extract.ts
|
|
41
|
+
var sharedNativeOutputDir = resolve(tmpdir(), "rig-native");
|
|
42
|
+
var extractionCache = {};
|
|
43
|
+
function hasEmbeddedNatives() {
|
|
44
|
+
return embeddedNatives != null;
|
|
45
|
+
}
|
|
46
|
+
function extractEmbeddedNative(name) {
|
|
47
|
+
if (name in extractionCache) {
|
|
48
|
+
return extractionCache[name] ?? null;
|
|
49
|
+
}
|
|
50
|
+
const entry = embeddedNatives?.[name];
|
|
51
|
+
if (!entry) {
|
|
52
|
+
extractionCache[name] = null;
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const targetPath = resolve(sharedNativeOutputDir, entry.fileName);
|
|
57
|
+
mkdirSync(sharedNativeOutputDir, { recursive: true });
|
|
58
|
+
const upToDate = existsSync(targetPath) && statSync(targetPath).size === entry.size;
|
|
59
|
+
if (!upToDate) {
|
|
60
|
+
const bytes = readFileSync(entry.filePath);
|
|
61
|
+
const tempPath = `${targetPath}.${process.pid}.${Date.now()}.tmp`;
|
|
62
|
+
writeFileSync(tempPath, bytes, { mode: 493 });
|
|
63
|
+
renameSync(tempPath, targetPath);
|
|
64
|
+
}
|
|
65
|
+
extractionCache[name] = targetPath;
|
|
66
|
+
} catch {
|
|
67
|
+
extractionCache[name] = null;
|
|
68
|
+
}
|
|
69
|
+
return extractionCache[name] ?? null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// packages/isolation-plugin/src/runtime-native.ts
|
|
73
|
+
var sharedNativeRuntimeOutputDir = resolve2(tmpdir2(), "rig-native");
|
|
74
|
+
var sharedNativeRuntimeOutputPath = resolve2(sharedNativeRuntimeOutputDir, `runtime-native-${process.platform}-${process.arch}.${suffix}`);
|
|
75
|
+
var colocatedNativeRuntimeFileName = `runtime-native.${suffix}`;
|
|
76
|
+
var nativeRuntimeLibrary = await loadNativeRuntimeLibrary();
|
|
77
|
+
function requireNativeRuntimeLibrary(feature) {
|
|
78
|
+
if (!nativeRuntimeLibrary) {
|
|
79
|
+
throw new Error(`Native Zig runtime is required for ${feature}`);
|
|
80
|
+
}
|
|
81
|
+
return nativeRuntimeLibrary;
|
|
82
|
+
}
|
|
83
|
+
async function ensureNativeRuntimeLibraryPath(outputPath = sharedNativeRuntimeOutputPath, options = {}) {
|
|
84
|
+
const explicitLib = process.env.RIG_NATIVE_RUNTIME_LIB?.trim();
|
|
85
|
+
if (explicitLib && existsSync2(explicitLib)) {
|
|
86
|
+
return explicitLib;
|
|
87
|
+
}
|
|
88
|
+
const embeddedPath = extractEmbeddedNative("snapshot");
|
|
89
|
+
if (embeddedPath) {
|
|
90
|
+
return embeddedPath;
|
|
91
|
+
}
|
|
92
|
+
if (await buildNativeRuntimeLibrary(outputPath, options)) {
|
|
93
|
+
return outputPath;
|
|
94
|
+
}
|
|
95
|
+
return !options.force && existsSync2(outputPath) ? outputPath : null;
|
|
96
|
+
}
|
|
97
|
+
async function materializeNativeRuntimeLibrary(targetDir) {
|
|
98
|
+
const sourcePath = await ensureNativeRuntimeLibraryPath();
|
|
99
|
+
if (!sourcePath) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const targetPath = resolve2(targetDir, colocatedNativeRuntimeFileName);
|
|
103
|
+
mkdirSync2(targetDir, { recursive: true });
|
|
104
|
+
const needsCopy = !existsSync2(targetPath) || statSync2(sourcePath).mtimeMs > statSync2(targetPath).mtimeMs;
|
|
105
|
+
if (needsCopy) {
|
|
106
|
+
copyFileSync(sourcePath, targetPath);
|
|
107
|
+
}
|
|
108
|
+
return targetPath;
|
|
109
|
+
}
|
|
110
|
+
async function loadNativeRuntimeLibrary() {
|
|
111
|
+
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
const explicitLib = process.env.RIG_NATIVE_RUNTIME_LIB?.trim();
|
|
115
|
+
if (explicitLib && existsSync2(explicitLib)) {
|
|
116
|
+
const loaded = tryDlopenNativeRuntimeLibrary(explicitLib);
|
|
117
|
+
if (loaded) {
|
|
118
|
+
return loaded;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const embeddedPath = extractEmbeddedNative("snapshot");
|
|
122
|
+
if (embeddedPath) {
|
|
123
|
+
const loaded = tryDlopenNativeRuntimeLibrary(embeddedPath);
|
|
124
|
+
if (loaded) {
|
|
125
|
+
return loaded;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
for (const candidate of nativeRuntimeLibraryCandidates()) {
|
|
129
|
+
if (!candidate || !existsSync2(candidate)) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const loaded = tryDlopenNativeRuntimeLibrary(candidate);
|
|
133
|
+
if (loaded) {
|
|
134
|
+
return loaded;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const builtLibraryPath = await ensureNativeRuntimeLibraryPath(sharedNativeRuntimeOutputPath, { force: true });
|
|
138
|
+
if (!builtLibraryPath) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
return tryDlopenNativeRuntimeLibrary(builtLibraryPath);
|
|
142
|
+
}
|
|
143
|
+
function nativePackageLibraryCandidates(fromDir, names) {
|
|
144
|
+
const candidates = [];
|
|
145
|
+
let cursor = resolve2(fromDir);
|
|
146
|
+
for (let index = 0;index < 8; index += 1) {
|
|
147
|
+
for (const name of names) {
|
|
148
|
+
candidates.push(resolve2(cursor, "native", `${process.platform}-${process.arch}`, name), resolve2(cursor, "native", `${process.platform}-${process.arch}`, "lib", name), resolve2(cursor, "native", name), resolve2(cursor, "native", "lib", name));
|
|
149
|
+
}
|
|
150
|
+
const parent = dirname(cursor);
|
|
151
|
+
if (parent === cursor)
|
|
152
|
+
break;
|
|
153
|
+
cursor = parent;
|
|
154
|
+
}
|
|
155
|
+
return candidates;
|
|
156
|
+
}
|
|
157
|
+
function nativeRuntimeLibraryCandidates() {
|
|
158
|
+
const explicit = process.env.RIG_NATIVE_RUNTIME_LIB?.trim() || "";
|
|
159
|
+
const execDir = process.execPath?.trim() ? dirname(process.execPath.trim()) : "";
|
|
160
|
+
const platformSpecific = `runtime-native-${process.platform}-${process.arch}.${suffix}`;
|
|
161
|
+
return [...new Set([
|
|
162
|
+
explicit,
|
|
163
|
+
...nativePackageLibraryCandidates(import.meta.dir, [colocatedNativeRuntimeFileName, platformSpecific]),
|
|
164
|
+
execDir ? resolve2(execDir, colocatedNativeRuntimeFileName) : "",
|
|
165
|
+
execDir ? resolve2(execDir, platformSpecific) : "",
|
|
166
|
+
execDir ? resolve2(execDir, "..", colocatedNativeRuntimeFileName) : "",
|
|
167
|
+
execDir ? resolve2(execDir, "..", platformSpecific) : "",
|
|
168
|
+
execDir ? resolve2(execDir, "lib", colocatedNativeRuntimeFileName) : "",
|
|
169
|
+
execDir ? resolve2(execDir, "..", "lib", colocatedNativeRuntimeFileName) : "",
|
|
170
|
+
sharedNativeRuntimeOutputPath
|
|
171
|
+
].filter(Boolean))];
|
|
172
|
+
}
|
|
173
|
+
function resolveNativeRuntimeSourcePath() {
|
|
174
|
+
const explicit = process.env.RIG_NATIVE_RUNTIME_SOURCE?.trim();
|
|
175
|
+
if (explicit && existsSync2(explicit)) {
|
|
176
|
+
return explicit;
|
|
177
|
+
}
|
|
178
|
+
const bundled = resolve2(import.meta.dir, "../native/snapshot.zig");
|
|
179
|
+
return existsSync2(bundled) ? bundled : null;
|
|
180
|
+
}
|
|
181
|
+
async function buildNativeRuntimeLibrary(outputPath, options = {}) {
|
|
182
|
+
if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
const zigBinary = Bun.which("zig");
|
|
186
|
+
const sourcePath = resolveNativeRuntimeSourcePath();
|
|
187
|
+
if (!zigBinary || !sourcePath) {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
const tempOutputPath = `${outputPath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
191
|
+
try {
|
|
192
|
+
mkdirSync2(dirname(outputPath), { recursive: true });
|
|
193
|
+
const needsBuild = options.force === true || !existsSync2(outputPath) || statSync2(sourcePath).mtimeMs > statSync2(outputPath).mtimeMs;
|
|
194
|
+
if (!needsBuild) {
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
const build = Bun.spawn([
|
|
198
|
+
zigBinary,
|
|
199
|
+
"build-lib",
|
|
200
|
+
sourcePath,
|
|
201
|
+
"-dynamic",
|
|
202
|
+
"-O",
|
|
203
|
+
"ReleaseFast",
|
|
204
|
+
`-femit-bin=${tempOutputPath}`
|
|
205
|
+
], {
|
|
206
|
+
cwd: import.meta.dir,
|
|
207
|
+
stdout: "pipe",
|
|
208
|
+
stderr: "pipe"
|
|
209
|
+
});
|
|
210
|
+
const exitCode = await build.exited;
|
|
211
|
+
if (exitCode !== 0 || !existsSync2(tempOutputPath)) {
|
|
212
|
+
rmSync(tempOutputPath, { force: true });
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
renameSync2(tempOutputPath, outputPath);
|
|
216
|
+
return true;
|
|
217
|
+
} catch {
|
|
218
|
+
rmSync(tempOutputPath, { force: true });
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function tryDlopenNativeRuntimeLibrary(outputPath) {
|
|
223
|
+
try {
|
|
224
|
+
return dlopen(outputPath, {
|
|
225
|
+
rig_scope_match: {
|
|
226
|
+
args: ["ptr", "ptr"],
|
|
227
|
+
returns: "u8"
|
|
228
|
+
},
|
|
229
|
+
snapshot_capture: {
|
|
230
|
+
args: ["ptr", "u64", "ptr", "u64"],
|
|
231
|
+
returns: "ptr"
|
|
232
|
+
},
|
|
233
|
+
snapshot_delta: {
|
|
234
|
+
args: ["ptr", "ptr"],
|
|
235
|
+
returns: "ptr"
|
|
236
|
+
},
|
|
237
|
+
snapshot_store_delta: {
|
|
238
|
+
args: ["ptr", "ptr", "ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64"],
|
|
239
|
+
returns: "ptr"
|
|
240
|
+
},
|
|
241
|
+
snapshot_inspect_delta: {
|
|
242
|
+
args: ["ptr", "u64"],
|
|
243
|
+
returns: "ptr"
|
|
244
|
+
},
|
|
245
|
+
snapshot_apply_delta: {
|
|
246
|
+
args: ["ptr", "u64", "ptr", "u64"],
|
|
247
|
+
returns: "ptr"
|
|
248
|
+
},
|
|
249
|
+
snapshot_release: {
|
|
250
|
+
args: ["ptr"],
|
|
251
|
+
returns: "void"
|
|
252
|
+
},
|
|
253
|
+
runtime_hash_file: {
|
|
254
|
+
args: ["ptr", "u64"],
|
|
255
|
+
returns: "ptr"
|
|
256
|
+
},
|
|
257
|
+
runtime_hash_tree: {
|
|
258
|
+
args: ["ptr", "u64"],
|
|
259
|
+
returns: "ptr"
|
|
260
|
+
},
|
|
261
|
+
runtime_prepare_paths: {
|
|
262
|
+
args: ["ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64"],
|
|
263
|
+
returns: "ptr"
|
|
264
|
+
},
|
|
265
|
+
runtime_link_dependency_layer: {
|
|
266
|
+
args: ["ptr", "u64", "ptr", "u64"],
|
|
267
|
+
returns: "ptr"
|
|
268
|
+
},
|
|
269
|
+
runtime_scan_worktrees: {
|
|
270
|
+
args: ["ptr", "u64"],
|
|
271
|
+
returns: "ptr"
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
} catch {
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// packages/isolation-plugin/src/isolation/index.ts
|
|
280
|
+
import { BROWSER_CONTRACT_SERVICE_CAPABILITY, MEMORY } from "@rig/contracts";
|
|
281
|
+
import { safePathSegment as safePathSegment3 } from "@rig/core/safe-identifiers";
|
|
282
|
+
|
|
283
|
+
// packages/isolation-plugin/src/isolation/git-native.ts
|
|
284
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
285
|
+
import { dirname as dirname2, isAbsolute, resolve as resolve3 } from "path";
|
|
286
|
+
var sharedGitNativeOutputDir = resolve3(tmpdir3(), "rig-native");
|
|
287
|
+
var sharedGitNativeOutputPath = resolve3(sharedGitNativeOutputDir, `rig-git-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
|
|
288
|
+
|
|
289
|
+
// packages/isolation-plugin/src/isolation/index.ts
|
|
290
|
+
import { defineCapability as defineCapability2 } from "@rig/core/capability";
|
|
291
|
+
import { loadCapabilityForRoot, requireCapabilityForRoot, requireInstalledCapability as requireInstalledCapability2 } from "@rig/core/capability-loaders";
|
|
292
|
+
import { buildPluginHostContext } from "@rig/core/plugin-host-context";
|
|
293
|
+
import { TASK_DATA_SERVICE_CAPABILITY } from "@rig/contracts";
|
|
294
|
+
import { resolveRuntimeWorkspaceLayout as resolveRuntimeWorkspaceLayout3 } from "@rig/core/layout";
|
|
295
|
+
import { ensureRuntimeOverlay } from "@rig/core/runtime-overlay";
|
|
296
|
+
import {
|
|
297
|
+
DEFAULT_RUNTIME_MEMORY_RETRIEVAL,
|
|
298
|
+
writeRuntimeContext
|
|
299
|
+
} from "@rig/core/runtime-context";
|
|
300
|
+
import { secretDefinesFromEnv } from "@rig/core/baked-secrets";
|
|
301
|
+
|
|
302
|
+
// packages/isolation-plugin/src/isolation/home.ts
|
|
303
|
+
import { resolveBunBinaryPath, resolveBunInstallDir, resolveClaudeBinaryPath, resolveClaudeInstallDir, resolveNodeInstallDir } from "@rig/core/runtime-paths";
|
|
304
|
+
import { resolveRuntimeSecrets } from "@rig/core/baked-secrets";
|
|
305
|
+
import { browserEnvFromContext, loadRuntimeContext, runtimeMemoryEnvFromContext, RUNTIME_CONTEXT_ENV } from "@rig/core/runtime-context";
|
|
306
|
+
|
|
307
|
+
// packages/isolation-plugin/src/isolation/shared.ts
|
|
308
|
+
import { agentId, safeGitRefComponent, taskRuntimeId } from "@rig/core/safe-identifiers";
|
|
309
|
+
import { resolveCheckoutRoot } from "@rig/core/checkout-root";
|
|
310
|
+
var generatedCredentialFiles = new Set;
|
|
311
|
+
|
|
312
|
+
// packages/isolation-plugin/src/isolation/home.ts
|
|
313
|
+
var GITHUB_KNOWN_HOSTS = [
|
|
314
|
+
"github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl",
|
|
315
|
+
"github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=",
|
|
316
|
+
"github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk="
|
|
317
|
+
].join(`
|
|
318
|
+
`);
|
|
319
|
+
|
|
320
|
+
// packages/isolation-plugin/src/isolation/discovery.ts
|
|
321
|
+
import { resolveRuntimeWorkspaceLayout } from "@rig/core/layout";
|
|
322
|
+
import { loadRuntimeContext as loadRuntimeContext2 } from "@rig/core/runtime-context";
|
|
323
|
+
|
|
324
|
+
// packages/isolation-plugin/src/isolation/worktree.ts
|
|
325
|
+
import { assertPathInsideRoot, safeGitRefComponent as safeGitRefComponent2, safePathSegment } from "@rig/core/safe-identifiers";
|
|
326
|
+
|
|
327
|
+
// packages/isolation-plugin/src/isolation/toolchain.ts
|
|
328
|
+
import { assertPathInsideRoot as assertPathInsideRoot2, safePathSegment as safePathSegment2 } from "@rig/core/safe-identifiers";
|
|
329
|
+
|
|
330
|
+
// packages/isolation-plugin/src/isolation/runtime-binary-build.ts
|
|
331
|
+
import { chmodSync, copyFileSync as copyFileSync2, cpSync, existsSync as existsSync3, linkSync, mkdirSync as mkdirSync3, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
332
|
+
import { basename, dirname as dirname3, resolve as resolve4 } from "path";
|
|
333
|
+
import { fileURLToPath } from "url";
|
|
334
|
+
import { drainMicrotasks, gcAndSweep } from "bun:jsc";
|
|
335
|
+
import { resolveRigLayout } from "@rig/core/layout";
|
|
336
|
+
import { runtimeProvisioningEnv } from "@rig/core/runtime-provisioning-env";
|
|
337
|
+
var runtimeBinaryBuildQueue = Promise.resolve();
|
|
338
|
+
function materializeSelfExecRole(outputPath, define) {
|
|
339
|
+
const selfPath = process.execPath;
|
|
340
|
+
mkdirSync3(dirname3(outputPath), { recursive: true });
|
|
341
|
+
rmSync2(outputPath, { force: true });
|
|
342
|
+
try {
|
|
343
|
+
linkSync(selfPath, outputPath);
|
|
344
|
+
} catch {
|
|
345
|
+
copyFileSync2(selfPath, outputPath);
|
|
346
|
+
}
|
|
347
|
+
chmodSync(outputPath, 493);
|
|
348
|
+
const role = basename(outputPath).replace(/\.exe$/i, "");
|
|
349
|
+
writeFileSync2(`${outputPath}.rig-runconfig.json`, `${JSON.stringify({ role, define: define ?? {} }, null, 2)}
|
|
350
|
+
`, { mode: 384 });
|
|
351
|
+
}
|
|
352
|
+
async function buildBinary(entrypoint, outputPath, cwd, defines, external) {
|
|
353
|
+
if (hasEmbeddedNatives()) {
|
|
354
|
+
materializeSelfExecRole(outputPath, defines);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
await buildRuntimeBinary({
|
|
358
|
+
sourcePath: entrypoint,
|
|
359
|
+
outputPath,
|
|
360
|
+
cwd,
|
|
361
|
+
...defines ? { define: defines } : {},
|
|
362
|
+
env: runtimeProvisioningEnv(),
|
|
363
|
+
...external ? { external } : {}
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
async function buildRuntimeBinary(options) {
|
|
367
|
+
return runSerializedRuntimeBinaryBuild(async () => {
|
|
368
|
+
const resolved = resolveRuntimeBinaryBuildOptions(options);
|
|
369
|
+
runBestEffortBuildGc();
|
|
370
|
+
const manifestPath = runtimeBinaryCacheManifestPath(resolved.outputPath);
|
|
371
|
+
const buildKey = createRuntimeBinaryBuildKey({
|
|
372
|
+
entrypoint: resolved.entrypoint,
|
|
373
|
+
define: resolved.define,
|
|
374
|
+
env: resolved.env,
|
|
375
|
+
external: resolved.external
|
|
376
|
+
});
|
|
377
|
+
if (await isRuntimeBinaryBuildFresh({ outputPath: resolved.outputPath, manifestPath, buildKey })) {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
if (shouldUseRuntimeBinaryBuildWorker()) {
|
|
381
|
+
await buildRuntimeBinaryViaWorker(resolved);
|
|
382
|
+
} else {
|
|
383
|
+
await buildRuntimeBinaryInProcess(resolved, { manifestPath, buildKey });
|
|
384
|
+
}
|
|
385
|
+
runBestEffortBuildGc();
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
async function buildRuntimeBinaryInProcess(options, manifest) {
|
|
389
|
+
const tempBuildDir = resolve4(dirname3(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
390
|
+
const tempOutputPath = resolve4(tempBuildDir, basename(options.outputPath));
|
|
391
|
+
mkdirSync3(tempBuildDir, { recursive: true });
|
|
392
|
+
await withTemporaryEnv({
|
|
393
|
+
...options.env,
|
|
394
|
+
...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
|
|
395
|
+
}, async () => withTemporaryCwd(tempBuildDir, async () => {
|
|
396
|
+
const buildResult = await Bun.build({
|
|
397
|
+
entrypoints: [options.entrypoint],
|
|
398
|
+
compile: {
|
|
399
|
+
target: currentCompileTarget(),
|
|
400
|
+
outfile: tempOutputPath
|
|
401
|
+
},
|
|
402
|
+
target: "bun",
|
|
403
|
+
format: "esm",
|
|
404
|
+
minify: true,
|
|
405
|
+
bytecode: true,
|
|
406
|
+
metafile: true,
|
|
407
|
+
...options.external ? { external: options.external } : {},
|
|
408
|
+
...options.define ? { define: { __RIG_BUILD_CONFIG__: JSON.stringify(options.define) } } : {}
|
|
409
|
+
});
|
|
410
|
+
if (!buildResult.success) {
|
|
411
|
+
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(`
|
|
412
|
+
`);
|
|
413
|
+
throw new Error(`Failed to build ${options.entrypoint}: ${details || "Bun.build() returned errors"}`);
|
|
414
|
+
}
|
|
415
|
+
if (!existsSync3(tempOutputPath)) {
|
|
416
|
+
const emitted = buildResult.outputs.map((output) => output.path).join(", ") || "(none)";
|
|
417
|
+
throw new Error(`Failed to build ${options.entrypoint}: Bun.build() did not emit ${tempOutputPath}. Emitted: ${emitted}`);
|
|
418
|
+
}
|
|
419
|
+
renameSync3(tempOutputPath, options.outputPath);
|
|
420
|
+
chmodSync(options.outputPath, 493);
|
|
421
|
+
if (manifest) {
|
|
422
|
+
await writeRuntimeBinaryCacheManifest({
|
|
423
|
+
manifestPath: manifest.manifestPath,
|
|
424
|
+
buildKey: manifest.buildKey,
|
|
425
|
+
cwd: tempBuildDir,
|
|
426
|
+
metafile: buildResult.metafile
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
})).finally(() => {
|
|
430
|
+
rmSync2(tempBuildDir, { recursive: true, force: true });
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
function runBestEffortBuildGc() {
|
|
434
|
+
try {
|
|
435
|
+
drainMicrotasks();
|
|
436
|
+
} catch {}
|
|
437
|
+
try {
|
|
438
|
+
gcAndSweep();
|
|
439
|
+
} catch {}
|
|
440
|
+
}
|
|
441
|
+
function runtimeBinaryCacheManifestPath(outputPath) {
|
|
442
|
+
return `${outputPath}.build-manifest.json`;
|
|
443
|
+
}
|
|
444
|
+
function resolveRuntimeBinaryBuildOptions(options) {
|
|
445
|
+
return {
|
|
446
|
+
...options,
|
|
447
|
+
entrypoint: resolve4(options.cwd, options.sourcePath),
|
|
448
|
+
outputPath: resolve4(options.outputPath)
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
function shouldUseRuntimeBinaryBuildWorker() {
|
|
452
|
+
if (process.env.RIG_RUNTIME_BUILD_WORKER === "1") {
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
if (process.env.RIG_RUNTIME_BUILD_IN_PROCESS === "1") {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
return true;
|
|
459
|
+
}
|
|
460
|
+
async function buildRuntimeBinaryViaWorker(options) {
|
|
461
|
+
const workerSourcePath = resolveRuntimeBinaryBuildWorkerSourcePath(options);
|
|
462
|
+
if (!workerSourcePath || !existsSync3(workerSourcePath)) {
|
|
463
|
+
await buildRuntimeBinaryInProcess(options, {
|
|
464
|
+
manifestPath: runtimeBinaryCacheManifestPath(options.outputPath),
|
|
465
|
+
buildKey: createRuntimeBinaryBuildKey({
|
|
466
|
+
entrypoint: options.entrypoint,
|
|
467
|
+
define: options.define,
|
|
468
|
+
env: options.env,
|
|
469
|
+
external: options.external
|
|
470
|
+
})
|
|
471
|
+
});
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const payloadPath = createRuntimeBinaryBuildWorkerPayloadPath(options.outputPath);
|
|
475
|
+
const bunCli = resolveRuntimeBinaryBuildWorkerInvocation();
|
|
476
|
+
await Bun.write(payloadPath, `${JSON.stringify(options)}
|
|
477
|
+
`);
|
|
478
|
+
const build = Bun.spawn([bunCli.command, workerSourcePath, payloadPath], {
|
|
479
|
+
cwd: options.cwd,
|
|
480
|
+
stdout: "pipe",
|
|
481
|
+
stderr: "pipe",
|
|
482
|
+
env: {
|
|
483
|
+
...process.env,
|
|
484
|
+
...options.env,
|
|
485
|
+
...bunCli.env,
|
|
486
|
+
RIG_RUNTIME_BUILD_WORKER: "1"
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
const [exitCode, stdout, stderr] = await Promise.all([
|
|
490
|
+
build.exited,
|
|
491
|
+
new Response(build.stdout).text(),
|
|
492
|
+
new Response(build.stderr).text()
|
|
493
|
+
]);
|
|
494
|
+
rmSync2(payloadPath, { force: true });
|
|
495
|
+
if (exitCode !== 0) {
|
|
496
|
+
throw new Error(`Failed to build ${options.entrypoint}: ${(stderr || stdout || `worker exited ${exitCode}`).trim()}`);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
|
|
500
|
+
return resolve4(dirname3(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
501
|
+
}
|
|
502
|
+
function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
|
|
503
|
+
const envRoots = [
|
|
504
|
+
options.cwd?.trim(),
|
|
505
|
+
process.env.RIG_HOST_PROJECT_ROOT?.trim(),
|
|
506
|
+
process.env.PROJECT_RIG_ROOT?.trim()
|
|
507
|
+
].filter(Boolean);
|
|
508
|
+
for (const root of envRoots) {
|
|
509
|
+
const candidate = resolve4(root, "packages/isolation-plugin/src/isolation/binary-build-worker.ts");
|
|
510
|
+
if (existsSync3(candidate)) {
|
|
511
|
+
return candidate;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
const localCandidate = resolve4(import.meta.dir, "binary-build-worker.ts");
|
|
515
|
+
return existsSync3(localCandidate) ? localCandidate : null;
|
|
516
|
+
}
|
|
517
|
+
function resolveRuntimeBinaryBuildWorkerInvocation() {
|
|
518
|
+
const bunPath = Bun.which("bun");
|
|
519
|
+
if (bunPath) {
|
|
520
|
+
return { command: bunPath, env: {} };
|
|
521
|
+
}
|
|
522
|
+
if (process.execPath?.trim()) {
|
|
523
|
+
return {
|
|
524
|
+
command: process.execPath,
|
|
525
|
+
env: { BUN_BE_BUN: "1" }
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
throw new Error("bun is required to run the runtime binary build worker.");
|
|
529
|
+
}
|
|
530
|
+
function currentCompileTarget() {
|
|
531
|
+
if (process.platform === "darwin") {
|
|
532
|
+
return process.arch === "arm64" ? "bun-darwin-arm64" : "bun-darwin-x64";
|
|
533
|
+
}
|
|
534
|
+
if (process.platform === "linux") {
|
|
535
|
+
return process.arch === "arm64" ? "bun-linux-arm64" : "bun-linux-x64";
|
|
536
|
+
}
|
|
537
|
+
return "bun-windows-x64";
|
|
538
|
+
}
|
|
539
|
+
function createRuntimeBinaryBuildKey(input) {
|
|
540
|
+
return JSON.stringify({
|
|
541
|
+
version: 1,
|
|
542
|
+
bunVersion: Bun.version,
|
|
543
|
+
platform: process.platform,
|
|
544
|
+
arch: process.arch,
|
|
545
|
+
entrypoint: input.entrypoint,
|
|
546
|
+
define: sortRecord(input.define),
|
|
547
|
+
external: input.external ? [...input.external].sort() : undefined,
|
|
548
|
+
env: sortRecord(input.env)
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
async function isRuntimeBinaryBuildFresh(input) {
|
|
552
|
+
if (!existsSync3(input.outputPath) || !existsSync3(input.manifestPath)) {
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
let manifest = null;
|
|
556
|
+
try {
|
|
557
|
+
manifest = await Bun.file(input.manifestPath).json();
|
|
558
|
+
} catch {
|
|
559
|
+
return false;
|
|
560
|
+
}
|
|
561
|
+
if (!manifest || manifest.version !== 1 || manifest.buildKey !== input.buildKey) {
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
for (const [filePath, expectedDigest] of Object.entries(manifest.inputs || {})) {
|
|
565
|
+
if (!existsSync3(filePath)) {
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
568
|
+
if (await sha256File(filePath) !== expectedDigest) {
|
|
569
|
+
return false;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return true;
|
|
573
|
+
}
|
|
574
|
+
async function writeRuntimeBinaryCacheManifest(input) {
|
|
575
|
+
const inputs = {};
|
|
576
|
+
for (const inputPath of Object.keys(input.metafile?.inputs || {}).sort()) {
|
|
577
|
+
const normalized = normalizeBuildInputPath(input.cwd, inputPath);
|
|
578
|
+
if (!normalized || !existsSync3(normalized)) {
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
inputs[normalized] = await sha256File(normalized);
|
|
582
|
+
}
|
|
583
|
+
const manifest = {
|
|
584
|
+
version: 1,
|
|
585
|
+
buildKey: input.buildKey,
|
|
586
|
+
inputs
|
|
587
|
+
};
|
|
588
|
+
await Bun.write(input.manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
589
|
+
`);
|
|
590
|
+
}
|
|
591
|
+
function normalizeBuildInputPath(cwd, inputPath) {
|
|
592
|
+
if (!inputPath) {
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
if (inputPath.startsWith("file://")) {
|
|
596
|
+
return fileURLToPath(inputPath);
|
|
597
|
+
}
|
|
598
|
+
if (inputPath.startsWith("<")) {
|
|
599
|
+
return null;
|
|
600
|
+
}
|
|
601
|
+
return resolve4(cwd, inputPath);
|
|
602
|
+
}
|
|
603
|
+
async function sha256File(path) {
|
|
604
|
+
const hasher = new Bun.CryptoHasher("sha256");
|
|
605
|
+
hasher.update(await Bun.file(path).arrayBuffer());
|
|
606
|
+
return hasher.digest("hex");
|
|
607
|
+
}
|
|
608
|
+
function sortRecord(value) {
|
|
609
|
+
if (!value) {
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)));
|
|
613
|
+
}
|
|
614
|
+
async function runSerializedRuntimeBinaryBuild(action) {
|
|
615
|
+
const previous = runtimeBinaryBuildQueue;
|
|
616
|
+
let release;
|
|
617
|
+
runtimeBinaryBuildQueue = new Promise((resolve5) => {
|
|
618
|
+
release = resolve5;
|
|
619
|
+
});
|
|
620
|
+
await previous;
|
|
621
|
+
try {
|
|
622
|
+
return await action();
|
|
623
|
+
} finally {
|
|
624
|
+
release();
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
async function withTemporaryEnv(env, action) {
|
|
628
|
+
if (!env) {
|
|
629
|
+
return action();
|
|
630
|
+
}
|
|
631
|
+
const previousValues = new Map;
|
|
632
|
+
for (const [key, value] of Object.entries(env)) {
|
|
633
|
+
previousValues.set(key, process.env[key]);
|
|
634
|
+
if (value === undefined) {
|
|
635
|
+
delete process.env[key];
|
|
636
|
+
} else {
|
|
637
|
+
process.env[key] = value;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
try {
|
|
641
|
+
return await action();
|
|
642
|
+
} finally {
|
|
643
|
+
for (const [key, value] of previousValues.entries()) {
|
|
644
|
+
if (value === undefined) {
|
|
645
|
+
delete process.env[key];
|
|
646
|
+
} else {
|
|
647
|
+
process.env[key] = value;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
async function withTemporaryCwd(cwd, action) {
|
|
653
|
+
const previousCwd = process.cwd();
|
|
654
|
+
process.chdir(cwd);
|
|
655
|
+
try {
|
|
656
|
+
return await action();
|
|
657
|
+
} finally {
|
|
658
|
+
process.chdir(previousCwd);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// packages/isolation-plugin/src/isolation/toolchain.ts
|
|
663
|
+
import {
|
|
664
|
+
GUARD_TOOLCHAIN_SOURCES,
|
|
665
|
+
LIFECYCLE_TOOLCHAIN_SOURCES,
|
|
666
|
+
TOOL_MATERIALIZER
|
|
667
|
+
} from "@rig/contracts";
|
|
668
|
+
import { defineCapability } from "@rig/core/capability";
|
|
669
|
+
import { buildProjectPluginHost, requireInstalledCapability } from "@rig/core/capability-loaders";
|
|
670
|
+
import { resolveBunBinaryPath as resolveBunBinaryPath2 } from "@rig/core/runtime-paths";
|
|
671
|
+
var ToolMaterializerCap = defineCapability(TOOL_MATERIALIZER);
|
|
672
|
+
var GuardToolchainSourcesCap = defineCapability(GUARD_TOOLCHAIN_SOURCES);
|
|
673
|
+
var LifecycleToolchainSourcesCap = defineCapability(LIFECYCLE_TOOLCHAIN_SOURCES);
|
|
674
|
+
var SNAPSHOT_SIDECAR_SOURCE = ["packages", "isolation-plugin", "src", "snapshot-sidecar.ts"].join("/");
|
|
675
|
+
async function resolveContributedToolchainSources(projectRoot) {
|
|
676
|
+
const host = await buildProjectPluginHost(projectRoot);
|
|
677
|
+
const contributions = [];
|
|
678
|
+
if (host) {
|
|
679
|
+
for (const cap of [GuardToolchainSourcesCap, LifecycleToolchainSourcesCap]) {
|
|
680
|
+
const contribution = await cap.resolve(host);
|
|
681
|
+
if (contribution)
|
|
682
|
+
contributions.push(contribution);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
const hookSources = contributions.flatMap((c) => (c.hookBinaries ?? []).map((hb) => [hb.name, hb.source]));
|
|
686
|
+
const namedSources = {};
|
|
687
|
+
for (const c of contributions) {
|
|
688
|
+
for (const [key, value] of Object.entries(c.namedSources ?? {}))
|
|
689
|
+
namedSources[key] = value;
|
|
690
|
+
}
|
|
691
|
+
return { hookSources, namedSources };
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// packages/isolation-plugin/src/runtime-config.ts
|
|
695
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, statSync as statSync3 } from "fs";
|
|
696
|
+
import { resolve as resolve5 } from "path";
|
|
697
|
+
import {
|
|
698
|
+
POLICY_VERSION
|
|
699
|
+
} from "@rig/contracts";
|
|
700
|
+
var DEFAULT_SCOPE = {
|
|
701
|
+
fail_closed: true,
|
|
702
|
+
harness_paths_exempt: true,
|
|
703
|
+
runtime_paths_exempt: true
|
|
704
|
+
};
|
|
705
|
+
var DEFAULT_SANDBOX = {
|
|
706
|
+
mode: "enforce",
|
|
707
|
+
network: true,
|
|
708
|
+
read_deny: [],
|
|
709
|
+
write_allow_from_runtime: true
|
|
710
|
+
};
|
|
711
|
+
var DEFAULT_ISOLATION = {
|
|
712
|
+
default_mode: "worktree",
|
|
713
|
+
repo_symlink_fallback: false,
|
|
714
|
+
strict_provisioning: true,
|
|
715
|
+
fail_closed_on_provision_error: true
|
|
716
|
+
};
|
|
717
|
+
var DEFAULT_COMPLETION = {
|
|
718
|
+
derive_checks_from_scope: true,
|
|
719
|
+
checks: [],
|
|
720
|
+
typescript_config_probe: ["tsconfig.json"],
|
|
721
|
+
eslint_config_probe: [".eslintrc.js", ".eslintrc.json", "eslint.config.js"]
|
|
722
|
+
};
|
|
723
|
+
var DEFAULT_RUNTIME_IMAGE = {
|
|
724
|
+
deps: { monorepo_install: false, hp_next_install: false },
|
|
725
|
+
plugins_require_binaries: true
|
|
726
|
+
};
|
|
727
|
+
var DEFAULT_RUNTIME_SNAPSHOT = { enabled: true };
|
|
728
|
+
var policyCache = null;
|
|
729
|
+
var policyCachePath = null;
|
|
730
|
+
function loadRuntimeImageConfig(projectRoot) {
|
|
731
|
+
return loadPolicy(projectRoot).runtime_image ?? {
|
|
732
|
+
deps: { ...DEFAULT_RUNTIME_IMAGE.deps },
|
|
733
|
+
plugins_require_binaries: DEFAULT_RUNTIME_IMAGE.plugins_require_binaries
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
function defaultPolicy() {
|
|
737
|
+
return {
|
|
738
|
+
version: POLICY_VERSION,
|
|
739
|
+
mode: "enforce",
|
|
740
|
+
scope: { ...DEFAULT_SCOPE },
|
|
741
|
+
rules: [],
|
|
742
|
+
sandbox: { ...DEFAULT_SANDBOX },
|
|
743
|
+
isolation: { ...DEFAULT_ISOLATION },
|
|
744
|
+
completion: { ...DEFAULT_COMPLETION },
|
|
745
|
+
runtime_image: {
|
|
746
|
+
deps: { ...DEFAULT_RUNTIME_IMAGE.deps },
|
|
747
|
+
plugins_require_binaries: DEFAULT_RUNTIME_IMAGE.plugins_require_binaries
|
|
748
|
+
},
|
|
749
|
+
runtime_snapshot: { ...DEFAULT_RUNTIME_SNAPSHOT }
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
function loadPolicy(projectRoot) {
|
|
753
|
+
const configPath = resolve5(projectRoot, "rig/policy/policy.json");
|
|
754
|
+
if (!existsSync4(configPath))
|
|
755
|
+
return defaultPolicy();
|
|
756
|
+
let mtimeMs;
|
|
757
|
+
try {
|
|
758
|
+
mtimeMs = statSync3(configPath).mtimeMs;
|
|
759
|
+
} catch {
|
|
760
|
+
return defaultPolicy();
|
|
761
|
+
}
|
|
762
|
+
if (policyCache && policyCachePath === configPath && policyCache.mtimeMs === mtimeMs) {
|
|
763
|
+
return policyCache.config;
|
|
764
|
+
}
|
|
765
|
+
try {
|
|
766
|
+
const config = mergeWithDefaults(JSON.parse(readFileSync2(configPath, "utf-8")));
|
|
767
|
+
policyCache = { mtimeMs, config };
|
|
768
|
+
policyCachePath = configPath;
|
|
769
|
+
return config;
|
|
770
|
+
} catch {
|
|
771
|
+
return defaultPolicy();
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
function mergeWithDefaults(parsed) {
|
|
775
|
+
const base = defaultPolicy();
|
|
776
|
+
if (typeof parsed.mode === "string" && isValidMode(parsed.mode))
|
|
777
|
+
base.mode = parsed.mode;
|
|
778
|
+
if (parsed.scope && typeof parsed.scope === "object" && !Array.isArray(parsed.scope)) {
|
|
779
|
+
const scope = parsed.scope;
|
|
780
|
+
if (typeof scope.fail_closed === "boolean")
|
|
781
|
+
base.scope.fail_closed = scope.fail_closed;
|
|
782
|
+
if (typeof scope.harness_paths_exempt === "boolean")
|
|
783
|
+
base.scope.harness_paths_exempt = scope.harness_paths_exempt;
|
|
784
|
+
if (typeof scope.runtime_paths_exempt === "boolean")
|
|
785
|
+
base.scope.runtime_paths_exempt = scope.runtime_paths_exempt;
|
|
786
|
+
}
|
|
787
|
+
if (Array.isArray(parsed.rules))
|
|
788
|
+
base.rules = precompilePolicyRuleRegexes(parsed.rules.filter(isValidRule));
|
|
789
|
+
if (Array.isArray(parsed.deny) && base.rules.length === 0) {
|
|
790
|
+
base.rules = precompilePolicyRuleRegexes(migrateLegacyDeny(parsed.deny));
|
|
791
|
+
}
|
|
792
|
+
if (parsed.sandbox && typeof parsed.sandbox === "object" && !Array.isArray(parsed.sandbox)) {
|
|
793
|
+
const sandbox = parsed.sandbox;
|
|
794
|
+
if (typeof sandbox.mode === "string" && isValidMode(sandbox.mode))
|
|
795
|
+
base.sandbox.mode = sandbox.mode;
|
|
796
|
+
if (typeof sandbox.network === "boolean")
|
|
797
|
+
base.sandbox.network = sandbox.network;
|
|
798
|
+
if (Array.isArray(sandbox.read_deny))
|
|
799
|
+
base.sandbox.read_deny = sandbox.read_deny.filter((value) => typeof value === "string");
|
|
800
|
+
if (typeof sandbox.write_allow_from_runtime === "boolean")
|
|
801
|
+
base.sandbox.write_allow_from_runtime = sandbox.write_allow_from_runtime;
|
|
802
|
+
}
|
|
803
|
+
if (parsed.isolation && typeof parsed.isolation === "object" && !Array.isArray(parsed.isolation)) {
|
|
804
|
+
const isolation = parsed.isolation;
|
|
805
|
+
if (isolation.default_mode === "worktree")
|
|
806
|
+
base.isolation.default_mode = isolation.default_mode;
|
|
807
|
+
if (typeof isolation.repo_symlink_fallback === "boolean")
|
|
808
|
+
base.isolation.repo_symlink_fallback = isolation.repo_symlink_fallback;
|
|
809
|
+
if (typeof isolation.strict_provisioning === "boolean")
|
|
810
|
+
base.isolation.strict_provisioning = isolation.strict_provisioning;
|
|
811
|
+
if (typeof isolation.fail_closed_on_provision_error === "boolean")
|
|
812
|
+
base.isolation.fail_closed_on_provision_error = isolation.fail_closed_on_provision_error;
|
|
813
|
+
}
|
|
814
|
+
if (parsed.completion && typeof parsed.completion === "object" && !Array.isArray(parsed.completion)) {
|
|
815
|
+
const completion = parsed.completion;
|
|
816
|
+
if (typeof completion.derive_checks_from_scope === "boolean")
|
|
817
|
+
base.completion.derive_checks_from_scope = completion.derive_checks_from_scope;
|
|
818
|
+
if (Array.isArray(completion.checks))
|
|
819
|
+
base.completion.checks = completion.checks.filter((value) => typeof value === "string");
|
|
820
|
+
if (Array.isArray(completion.typescript_config_probe))
|
|
821
|
+
base.completion.typescript_config_probe = completion.typescript_config_probe.filter((value) => typeof value === "string");
|
|
822
|
+
if (Array.isArray(completion.eslint_config_probe))
|
|
823
|
+
base.completion.eslint_config_probe = completion.eslint_config_probe.filter((value) => typeof value === "string");
|
|
824
|
+
}
|
|
825
|
+
if (parsed.runtime_image && typeof parsed.runtime_image === "object" && !Array.isArray(parsed.runtime_image)) {
|
|
826
|
+
const runtimeImage = parsed.runtime_image;
|
|
827
|
+
if (runtimeImage.deps && typeof runtimeImage.deps === "object" && !Array.isArray(runtimeImage.deps)) {
|
|
828
|
+
const deps = runtimeImage.deps;
|
|
829
|
+
if (typeof deps.monorepo_install === "boolean")
|
|
830
|
+
base.runtime_image.deps.monorepo_install = deps.monorepo_install;
|
|
831
|
+
if (typeof deps.hp_next_install === "boolean")
|
|
832
|
+
base.runtime_image.deps.hp_next_install = deps.hp_next_install;
|
|
833
|
+
}
|
|
834
|
+
if (typeof runtimeImage.plugins_require_binaries === "boolean")
|
|
835
|
+
base.runtime_image.plugins_require_binaries = runtimeImage.plugins_require_binaries;
|
|
836
|
+
}
|
|
837
|
+
if (parsed.runtime_snapshot && typeof parsed.runtime_snapshot === "object" && !Array.isArray(parsed.runtime_snapshot)) {
|
|
838
|
+
const runtimeSnapshot = parsed.runtime_snapshot;
|
|
839
|
+
if (typeof runtimeSnapshot.enabled === "boolean")
|
|
840
|
+
base.runtime_snapshot.enabled = runtimeSnapshot.enabled;
|
|
841
|
+
}
|
|
842
|
+
return base;
|
|
843
|
+
}
|
|
844
|
+
function isValidMode(value) {
|
|
845
|
+
return value === "off" || value === "observe" || value === "enforce";
|
|
846
|
+
}
|
|
847
|
+
function isValidRule(value) {
|
|
848
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
849
|
+
return false;
|
|
850
|
+
const rule = value;
|
|
851
|
+
return typeof rule.id === "string" && typeof rule.category === "string" && !!rule.match && typeof rule.match === "object";
|
|
852
|
+
}
|
|
853
|
+
function migrateLegacyDeny(deny) {
|
|
854
|
+
const rules = [];
|
|
855
|
+
for (const entry of deny) {
|
|
856
|
+
if (typeof entry.id !== "string")
|
|
857
|
+
continue;
|
|
858
|
+
const match = {};
|
|
859
|
+
if (typeof entry.pattern === "string")
|
|
860
|
+
match.pattern = entry.pattern;
|
|
861
|
+
if (typeof entry.regex === "string")
|
|
862
|
+
match.regex = entry.regex;
|
|
863
|
+
if (!match.pattern && !match.regex)
|
|
864
|
+
continue;
|
|
865
|
+
const rule = {
|
|
866
|
+
id: entry.id,
|
|
867
|
+
category: "command",
|
|
868
|
+
match,
|
|
869
|
+
action: entry.action === "warn" ? "warn" : "block"
|
|
870
|
+
};
|
|
871
|
+
if (typeof entry.reason === "string") {
|
|
872
|
+
rule.description = entry.reason;
|
|
873
|
+
}
|
|
874
|
+
rules.push(rule);
|
|
875
|
+
}
|
|
876
|
+
return rules;
|
|
877
|
+
}
|
|
878
|
+
function precompilePolicyRuleRegexes(rules) {
|
|
879
|
+
return rules.map((rule) => {
|
|
880
|
+
const compiled = { ...rule };
|
|
881
|
+
const matchRegex = compileRegex(rule.match?.regex);
|
|
882
|
+
const unlessRegex = compileRegex(rule.unless?.regex);
|
|
883
|
+
if (matchRegex) {
|
|
884
|
+
compiled.compiledRegex = matchRegex;
|
|
885
|
+
}
|
|
886
|
+
if (unlessRegex) {
|
|
887
|
+
compiled.compiledUnlessRegex = unlessRegex;
|
|
888
|
+
}
|
|
889
|
+
return compiled;
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
function compileRegex(pattern) {
|
|
893
|
+
if (!pattern)
|
|
894
|
+
return;
|
|
895
|
+
try {
|
|
896
|
+
return new RegExp(pattern);
|
|
897
|
+
} catch {
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// packages/isolation-plugin/src/sandbox/backend.ts
|
|
903
|
+
init_utils();
|
|
904
|
+
import {
|
|
905
|
+
resolveBunInstallDir as resolveBunInstallDir2,
|
|
906
|
+
resolveClaudeInstallDir as resolveClaudeInstallDir2,
|
|
907
|
+
resolveNodeInstallDir as resolveNodeInstallDir2,
|
|
908
|
+
resolveRuntimeDependencyRoots
|
|
909
|
+
} from "@rig/core/runtime-paths";
|
|
910
|
+
|
|
911
|
+
// packages/isolation-plugin/src/isolation/runner.ts
|
|
912
|
+
import { resolveRuntimeWorkspaceLayout as resolveRuntimeWorkspaceLayout2 } from "@rig/core/layout";
|
|
913
|
+
import { resolveBunBinaryPath as resolveBunBinaryPath3 } from "@rig/core/runtime-paths";
|
|
914
|
+
|
|
915
|
+
// packages/isolation-plugin/src/isolation/index.ts
|
|
916
|
+
var TaskDataCap = defineCapability2(TASK_DATA_SERVICE_CAPABILITY);
|
|
917
|
+
|
|
918
|
+
// packages/isolation-plugin/src/isolation/provisioning-env.ts
|
|
919
|
+
import { runtimeProvisioningEnv as runtimeProvisioningEnv2 } from "@rig/core/runtime-provisioning-env";
|
|
920
|
+
|
|
921
|
+
// packages/isolation-plugin/src/image.ts
|
|
922
|
+
import { resolveBunBinaryPath as resolveBunBinaryPath4 } from "@rig/core/runtime-paths";
|
|
923
|
+
var HASH_RESULT_SIZE = 40;
|
|
924
|
+
var nativeRuntimeLibrary2 = null;
|
|
925
|
+
function sha256Hex2(input) {
|
|
926
|
+
const hasher = new Bun.CryptoHasher("sha256");
|
|
927
|
+
hasher.update(input);
|
|
928
|
+
return hasher.digest("hex");
|
|
929
|
+
}
|
|
930
|
+
function hashFile(filePath) {
|
|
931
|
+
if (!existsSync5(filePath)) {
|
|
932
|
+
return "";
|
|
933
|
+
}
|
|
934
|
+
return hashPathWithNative("runtime_hash_file", filePath);
|
|
935
|
+
}
|
|
936
|
+
function hashDirectory(dir) {
|
|
937
|
+
if (!existsSync5(dir)) {
|
|
938
|
+
return sha256Hex2("(empty)");
|
|
939
|
+
}
|
|
940
|
+
return hashPathWithNative("runtime_hash_tree", dir);
|
|
941
|
+
}
|
|
942
|
+
function hashDirectories(dirs) {
|
|
943
|
+
const combined = new Bun.CryptoHasher("sha256");
|
|
944
|
+
for (const { label, path } of dirs) {
|
|
945
|
+
const dirHash = hashDirectory(path);
|
|
946
|
+
combined.update(`${label}:${dirHash}
|
|
947
|
+
`);
|
|
948
|
+
}
|
|
949
|
+
return combined.digest("hex");
|
|
950
|
+
}
|
|
951
|
+
async function probeVersion(args) {
|
|
952
|
+
try {
|
|
953
|
+
const proc = Bun.spawn(args, { stdout: "pipe", stderr: "pipe" });
|
|
954
|
+
const [exitCode, stdout] = await Promise.all([
|
|
955
|
+
proc.exited,
|
|
956
|
+
new Response(proc.stdout).text()
|
|
957
|
+
]);
|
|
958
|
+
if (exitCode === 0) {
|
|
959
|
+
return stdout.trim().split(`
|
|
960
|
+
`)[0] ?? "";
|
|
961
|
+
}
|
|
962
|
+
return "";
|
|
963
|
+
} catch {
|
|
964
|
+
return "";
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
async function computeRuntimeImageFingerprint(projectRoot) {
|
|
968
|
+
return runFingerprintSidecar(projectRoot);
|
|
969
|
+
}
|
|
970
|
+
async function computeRuntimeImageFingerprintNative(projectRoot) {
|
|
971
|
+
const [nodeVersion, claudeVersion] = await Promise.all([
|
|
972
|
+
probeVersion(["node", "--version"]),
|
|
973
|
+
probeVersion(["claude", "--version"])
|
|
974
|
+
]);
|
|
975
|
+
const runtimeDir = resolve6(projectRoot, "packages", "runtime");
|
|
976
|
+
const cliDir = resolve6(projectRoot, "packages", "cli");
|
|
977
|
+
const runtimeCodeHash = hashDirectories([
|
|
978
|
+
{ label: "packages/runtime", path: runtimeDir },
|
|
979
|
+
{ label: "packages/cli", path: cliDir }
|
|
980
|
+
]);
|
|
981
|
+
const policyPath = resolve6(projectRoot, "rig/policy/policy.json");
|
|
982
|
+
const policyHash = hashFile(policyPath);
|
|
983
|
+
const pluginsDir = resolve6(projectRoot, "rig/plugins");
|
|
984
|
+
const pluginsHash = hashDirectory(pluginsDir);
|
|
985
|
+
const baseLockfiles = [
|
|
986
|
+
"bun.lock",
|
|
987
|
+
"bun.lockb",
|
|
988
|
+
"package-lock.json",
|
|
989
|
+
"package.json",
|
|
990
|
+
"tsconfig.json"
|
|
991
|
+
];
|
|
992
|
+
const extra = process.env.RIG_RUNTIME_IMAGE_EXTRA_LOCKFILES?.trim();
|
|
993
|
+
const lockfileCandidates = extra ? [...baseLockfiles, ...extra.split(",").map((p) => p.trim()).filter(Boolean)] : baseLockfiles;
|
|
994
|
+
const lockfileHashes = {};
|
|
995
|
+
for (const relPath of lockfileCandidates) {
|
|
996
|
+
const fullPath = resolve6(projectRoot, relPath);
|
|
997
|
+
if (existsSync5(fullPath)) {
|
|
998
|
+
lockfileHashes[relPath] = hashFile(fullPath);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
return {
|
|
1002
|
+
platform: process.platform,
|
|
1003
|
+
bunVersion: Bun.version,
|
|
1004
|
+
nodeVersion,
|
|
1005
|
+
claudeVersion,
|
|
1006
|
+
runtimeCodeHash,
|
|
1007
|
+
policyHash,
|
|
1008
|
+
pluginsHash,
|
|
1009
|
+
lockfileHashes
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
async function runFingerprintSidecar(projectRoot) {
|
|
1013
|
+
const sidecarPath = resolveRuntimeSourceScriptPath(projectRoot, "image-fingerprint-sidecar.ts");
|
|
1014
|
+
const bunCli = resolveBunCliInvocation();
|
|
1015
|
+
const proc = Bun.spawn([bunCli.command, sidecarPath, "--project-root", projectRoot], {
|
|
1016
|
+
cwd: projectRoot,
|
|
1017
|
+
env: {
|
|
1018
|
+
...process.env,
|
|
1019
|
+
...bunCli.env
|
|
1020
|
+
},
|
|
1021
|
+
stdout: "pipe",
|
|
1022
|
+
stderr: "pipe"
|
|
1023
|
+
});
|
|
1024
|
+
const [exitCode, stdout, stderr] = await Promise.all([
|
|
1025
|
+
proc.exited,
|
|
1026
|
+
new Response(proc.stdout).text(),
|
|
1027
|
+
new Response(proc.stderr).text()
|
|
1028
|
+
]);
|
|
1029
|
+
if (exitCode !== 0) {
|
|
1030
|
+
throw new Error(stderr.trim() || stdout.trim() || `runtime image sidecar exited with ${exitCode}`);
|
|
1031
|
+
}
|
|
1032
|
+
return JSON.parse(stdout);
|
|
1033
|
+
}
|
|
1034
|
+
function resolveRuntimeSourceScriptPath(projectRoot, fileName) {
|
|
1035
|
+
const hostRoots = [
|
|
1036
|
+
process.env.RIG_HOST_PROJECT_ROOT?.trim(),
|
|
1037
|
+
process.env.PROJECT_RIG_ROOT?.trim(),
|
|
1038
|
+
projectRoot.trim()
|
|
1039
|
+
].filter((value) => Boolean(value));
|
|
1040
|
+
for (const root of hostRoots) {
|
|
1041
|
+
const candidate = resolve6(root, "packages/isolation-plugin/src", fileName);
|
|
1042
|
+
if (existsSync5(candidate)) {
|
|
1043
|
+
return candidate;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
return resolve6(import.meta.dir, fileName);
|
|
1047
|
+
}
|
|
1048
|
+
function resolveBunCliInvocation() {
|
|
1049
|
+
if (process.env.RIG_BUN_PATH?.trim()) {
|
|
1050
|
+
return {
|
|
1051
|
+
command: process.env.RIG_BUN_PATH.trim(),
|
|
1052
|
+
env: {}
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
try {
|
|
1056
|
+
const systemBun = resolveBunBinaryPath4();
|
|
1057
|
+
return {
|
|
1058
|
+
command: systemBun,
|
|
1059
|
+
env: {}
|
|
1060
|
+
};
|
|
1061
|
+
} catch {}
|
|
1062
|
+
if (process.execPath?.trim()) {
|
|
1063
|
+
return {
|
|
1064
|
+
command: process.execPath,
|
|
1065
|
+
env: { BUN_BE_BUN: "1" }
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
1068
|
+
return { command: "bun", env: {} };
|
|
1069
|
+
}
|
|
1070
|
+
function hashPathWithNative(symbol, path) {
|
|
1071
|
+
const pathBuffer = Buffer.from(path, "utf8");
|
|
1072
|
+
const runtimeLibrary = getNativeRuntimeLibrary();
|
|
1073
|
+
const resultPtr = runtimeLibrary.symbols[symbol](Number(ptr2(pathBuffer)), pathBuffer.byteLength);
|
|
1074
|
+
if (!resultPtr) {
|
|
1075
|
+
throw new Error(`${symbol} returned null for ${path}`);
|
|
1076
|
+
}
|
|
1077
|
+
try {
|
|
1078
|
+
const view = viewAt(resultPtr, HASH_RESULT_SIZE);
|
|
1079
|
+
const error = readError(view, 24, 32);
|
|
1080
|
+
if (error) {
|
|
1081
|
+
throw new Error(`${symbol} failed: ${error}`);
|
|
1082
|
+
}
|
|
1083
|
+
return readString(readU64(view, 8), readU64(view, 16));
|
|
1084
|
+
} finally {
|
|
1085
|
+
runtimeLibrary.symbols.snapshot_release(resultPtr);
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
function getNativeRuntimeLibrary() {
|
|
1089
|
+
if (nativeRuntimeLibrary2) {
|
|
1090
|
+
return nativeRuntimeLibrary2;
|
|
1091
|
+
}
|
|
1092
|
+
nativeRuntimeLibrary2 = requireNativeRuntimeLibrary("runtime image hashing");
|
|
1093
|
+
return nativeRuntimeLibrary2;
|
|
1094
|
+
}
|
|
1095
|
+
function viewAt(pointer, size) {
|
|
1096
|
+
const buffer = toBuffer2(pointer, 0, size);
|
|
1097
|
+
return new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
1098
|
+
}
|
|
1099
|
+
function readString(pointer, length) {
|
|
1100
|
+
if (!pointer || length === 0) {
|
|
1101
|
+
return "";
|
|
1102
|
+
}
|
|
1103
|
+
return Buffer.from(toBuffer2(pointer, 0, length)).toString("utf8");
|
|
1104
|
+
}
|
|
1105
|
+
function readU64(view, offset) {
|
|
1106
|
+
return Number(view.getBigUint64(offset, true));
|
|
1107
|
+
}
|
|
1108
|
+
function readError(view, pointerOffset, lengthOffset) {
|
|
1109
|
+
const errorPointer = readU64(view, pointerOffset);
|
|
1110
|
+
const errorLength = readU64(view, lengthOffset);
|
|
1111
|
+
if (!errorPointer || !errorLength) {
|
|
1112
|
+
return null;
|
|
1113
|
+
}
|
|
1114
|
+
return readString(errorPointer, errorLength);
|
|
1115
|
+
}
|
|
1116
|
+
function computeRuntimeImageId(fp) {
|
|
1117
|
+
const serialized = JSON.stringify(fp);
|
|
1118
|
+
return sha256Hex2(serialized).slice(0, 16);
|
|
1119
|
+
}
|
|
1120
|
+
var LOCK_STALE_MS = 10 * 60 * 1000;
|
|
1121
|
+
function isPidAlive(pid) {
|
|
1122
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
1123
|
+
return false;
|
|
1124
|
+
}
|
|
1125
|
+
try {
|
|
1126
|
+
process.kill(pid, 0);
|
|
1127
|
+
return true;
|
|
1128
|
+
} catch {
|
|
1129
|
+
return false;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
function readRuntimeImageLockData(lockPath) {
|
|
1133
|
+
try {
|
|
1134
|
+
const stat = lstatSync(lockPath);
|
|
1135
|
+
const raw = stat.isDirectory() ? readFileSync3(resolve6(lockPath, "owner.json"), "utf-8") : readFileSync3(lockPath, "utf-8");
|
|
1136
|
+
return JSON.parse(raw);
|
|
1137
|
+
} catch {
|
|
1138
|
+
return null;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
function acquireRuntimeImageLock(lockPath) {
|
|
1142
|
+
const lockData = { pid: process.pid, timestamp: Date.now() };
|
|
1143
|
+
const lockBody = JSON.stringify(lockData);
|
|
1144
|
+
const tryExclusiveCreate = () => {
|
|
1145
|
+
try {
|
|
1146
|
+
mkdirSync4(lockPath);
|
|
1147
|
+
writeFileSync3(resolve6(lockPath, "owner.json"), lockBody, "utf-8");
|
|
1148
|
+
return true;
|
|
1149
|
+
} catch {
|
|
1150
|
+
try {
|
|
1151
|
+
if (existsSync5(lockPath) && !lstatSync(lockPath).isDirectory()) {
|
|
1152
|
+
rmSync3(lockPath, { force: true });
|
|
1153
|
+
}
|
|
1154
|
+
} catch {}
|
|
1155
|
+
return false;
|
|
1156
|
+
}
|
|
1157
|
+
};
|
|
1158
|
+
if (tryExclusiveCreate()) {
|
|
1159
|
+
return true;
|
|
1160
|
+
}
|
|
1161
|
+
if (existsSync5(lockPath)) {
|
|
1162
|
+
const data = readRuntimeImageLockData(lockPath);
|
|
1163
|
+
if (data) {
|
|
1164
|
+
const age = Date.now() - data.timestamp;
|
|
1165
|
+
if (age < LOCK_STALE_MS) {
|
|
1166
|
+
return false;
|
|
1167
|
+
}
|
|
1168
|
+
if (isPidAlive(data.pid)) {
|
|
1169
|
+
return false;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
rmSync3(lockPath, { recursive: true, force: true });
|
|
1173
|
+
}
|
|
1174
|
+
return tryExclusiveCreate();
|
|
1175
|
+
}
|
|
1176
|
+
function releaseRuntimeImageLock(lockPath) {
|
|
1177
|
+
try {
|
|
1178
|
+
rmSync3(lockPath, { recursive: true, force: true });
|
|
1179
|
+
} catch {}
|
|
1180
|
+
}
|
|
1181
|
+
async function waitForRuntimeImageManifest(manifestPath, timeoutMs, pollMs = 500) {
|
|
1182
|
+
const deadline = Date.now() + timeoutMs;
|
|
1183
|
+
while (!existsSync5(manifestPath) && Date.now() < deadline) {
|
|
1184
|
+
await Bun.sleep(pollMs);
|
|
1185
|
+
}
|
|
1186
|
+
return existsSync5(manifestPath);
|
|
1187
|
+
}
|
|
1188
|
+
var SHARED_HOOK_NAMES = [
|
|
1189
|
+
"scope-guard",
|
|
1190
|
+
"import-guard",
|
|
1191
|
+
"safety-guard",
|
|
1192
|
+
"test-integrity-guard",
|
|
1193
|
+
"audit-trail",
|
|
1194
|
+
"post-edit-lint",
|
|
1195
|
+
"inject-context",
|
|
1196
|
+
"task-runtime-start"
|
|
1197
|
+
];
|
|
1198
|
+
function discoverValidators(projectRoot) {
|
|
1199
|
+
const validatorsRoot = resolve6(projectRoot, "packages/validator-kit/src/validators");
|
|
1200
|
+
const entries = [];
|
|
1201
|
+
if (!existsSync5(validatorsRoot)) {
|
|
1202
|
+
return entries;
|
|
1203
|
+
}
|
|
1204
|
+
const categories = readdirSync(validatorsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
1205
|
+
for (const category of categories) {
|
|
1206
|
+
const categoryDir = resolve6(validatorsRoot, category);
|
|
1207
|
+
const files = readdirSync(categoryDir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".ts")).map((e) => e.name).sort();
|
|
1208
|
+
for (const file of files) {
|
|
1209
|
+
const check = file.replace(/\.ts$/, "");
|
|
1210
|
+
if (!/^[a-z][\w-]*$/.test(check)) {
|
|
1211
|
+
continue;
|
|
1212
|
+
}
|
|
1213
|
+
entries.push({
|
|
1214
|
+
category,
|
|
1215
|
+
check,
|
|
1216
|
+
sourcePath: `packages/validator-kit/src/validators/${category}/${check}.ts`
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
return entries;
|
|
1221
|
+
}
|
|
1222
|
+
function discoverPlugins(projectRoot) {
|
|
1223
|
+
const pluginsRoot = resolve6(projectRoot, "rig/plugins");
|
|
1224
|
+
if (!existsSync5(pluginsRoot)) {
|
|
1225
|
+
return [];
|
|
1226
|
+
}
|
|
1227
|
+
return readdirSync(pluginsRoot, { withFileTypes: true }).filter((entry) => entry.isFile() && /\.plugin\.(ts|js|mjs|cjs)$/.test(entry.name)).map((entry) => {
|
|
1228
|
+
const name = entry.name.replace(/\.plugin\.(ts|js|mjs|cjs)$/, "");
|
|
1229
|
+
return {
|
|
1230
|
+
name,
|
|
1231
|
+
sourcePath: `rig/plugins/${entry.name}`
|
|
1232
|
+
};
|
|
1233
|
+
}).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
1234
|
+
}
|
|
1235
|
+
async function provisionDependencyLayer(projectRoot, tempDepsDir) {
|
|
1236
|
+
const config = loadRuntimeImageConfig(projectRoot);
|
|
1237
|
+
if (!config.deps.monorepo_install && !config.deps.hp_next_install)
|
|
1238
|
+
return;
|
|
1239
|
+
const linkNodeModules = (sourceNodeModules, targetNodeModules) => {
|
|
1240
|
+
if (existsSync5(targetNodeModules)) {
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
try {
|
|
1244
|
+
symlinkSync(sourceNodeModules, targetNodeModules);
|
|
1245
|
+
} catch {
|
|
1246
|
+
cpSync2(sourceNodeModules, targetNodeModules, {
|
|
1247
|
+
recursive: true,
|
|
1248
|
+
force: true,
|
|
1249
|
+
dereference: true
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1252
|
+
};
|
|
1253
|
+
const ensureInstall = async (cwd, label) => {
|
|
1254
|
+
const bunCli = resolveBunBinaryPath4();
|
|
1255
|
+
const install = Bun.spawn([bunCli, "install"], {
|
|
1256
|
+
cwd,
|
|
1257
|
+
stdout: "pipe",
|
|
1258
|
+
stderr: "pipe",
|
|
1259
|
+
env: runtimeProvisioningEnv2()
|
|
1260
|
+
});
|
|
1261
|
+
const [exitCode, stdout, stderr] = await Promise.all([
|
|
1262
|
+
install.exited,
|
|
1263
|
+
new Response(install.stdout).text(),
|
|
1264
|
+
new Response(install.stderr).text()
|
|
1265
|
+
]);
|
|
1266
|
+
if (exitCode !== 0) {
|
|
1267
|
+
throw new Error([
|
|
1268
|
+
`Failed to install shared runtime dependencies for ${label}.`,
|
|
1269
|
+
`cwd: ${cwd}`,
|
|
1270
|
+
stderr.trim() || stdout.trim()
|
|
1271
|
+
].filter(Boolean).join(`
|
|
1272
|
+
`));
|
|
1273
|
+
}
|
|
1274
|
+
};
|
|
1275
|
+
if (config.deps.monorepo_install) {
|
|
1276
|
+
const monorepoSubRel = process.env.RIG_MONOREPO_INSTALL_PATH?.trim() || "repos/spliter-monorepo/humoongate";
|
|
1277
|
+
const monorepoSubRoot = resolve6(projectRoot, monorepoSubRel);
|
|
1278
|
+
const monorepoSubPackage = resolve6(monorepoSubRoot, "package.json");
|
|
1279
|
+
if (existsSync5(monorepoSubPackage)) {
|
|
1280
|
+
const sourceNodeModules = resolve6(monorepoSubRoot, "node_modules");
|
|
1281
|
+
try {
|
|
1282
|
+
if (lstatSync(sourceNodeModules).isSymbolicLink() && !existsSync5(sourceNodeModules)) {
|
|
1283
|
+
unlinkSync(sourceNodeModules);
|
|
1284
|
+
}
|
|
1285
|
+
} catch {}
|
|
1286
|
+
if (!existsSync5(sourceNodeModules)) {
|
|
1287
|
+
await ensureInstall(monorepoSubRoot, "monorepo");
|
|
1288
|
+
}
|
|
1289
|
+
const targetRoot = resolve6(tempDepsDir, "humoongate");
|
|
1290
|
+
const targetNodeModules = resolve6(targetRoot, "node_modules");
|
|
1291
|
+
mkdirSync4(targetRoot, { recursive: true });
|
|
1292
|
+
linkNodeModules(sourceNodeModules, targetNodeModules);
|
|
1293
|
+
for (const fileName of ["package.json", "bun.lockb"]) {
|
|
1294
|
+
const source = resolve6(monorepoSubRoot, fileName);
|
|
1295
|
+
if (existsSync5(source)) {
|
|
1296
|
+
cpSync2(source, resolve6(targetRoot, fileName), { force: true });
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
if (config.deps.hp_next_install) {
|
|
1302
|
+
const monorepoRel = process.env.RIG_HP_NEXT_MONOREPO_PATH?.trim() || "repos/spliter-monorepo";
|
|
1303
|
+
const appRel = process.env.RIG_HP_NEXT_APP_PATH?.trim() || "microservices/hp-next-frontend/app";
|
|
1304
|
+
const monorepoRoot = resolve6(projectRoot, monorepoRel);
|
|
1305
|
+
const hpNextRoot = resolve6(monorepoRoot, appRel);
|
|
1306
|
+
const hpNextPackage = resolve6(hpNextRoot, "package.json");
|
|
1307
|
+
if (existsSync5(hpNextPackage)) {
|
|
1308
|
+
const rootNodeModules = resolve6(monorepoRoot, "node_modules");
|
|
1309
|
+
const hpNextNodeModules = resolve6(hpNextRoot, "node_modules");
|
|
1310
|
+
if (!existsSync5(rootNodeModules) && !existsSync5(hpNextNodeModules)) {
|
|
1311
|
+
await ensureInstall(monorepoRoot, "spliter-monorepo hp-next workspace");
|
|
1312
|
+
}
|
|
1313
|
+
const targetRoot = resolve6(tempDepsDir, "microservices", "hp-next-frontend", "app");
|
|
1314
|
+
mkdirSync4(targetRoot, { recursive: true });
|
|
1315
|
+
if (existsSync5(rootNodeModules)) {
|
|
1316
|
+
linkNodeModules(rootNodeModules, resolve6(targetRoot, "root-node_modules"));
|
|
1317
|
+
}
|
|
1318
|
+
if (existsSync5(hpNextNodeModules)) {
|
|
1319
|
+
linkNodeModules(hpNextNodeModules, resolve6(targetRoot, "node_modules"));
|
|
1320
|
+
}
|
|
1321
|
+
for (const fileName of ["package.json", "bun.lock", "bun.lockb", "package-lock.json"]) {
|
|
1322
|
+
const source = resolve6(hpNextRoot, fileName);
|
|
1323
|
+
if (existsSync5(source)) {
|
|
1324
|
+
cpSync2(source, resolve6(targetRoot, fileName), { force: true });
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
for (const fileName of ["package.json", "bun.lock", "bun.lockb", "package-lock.json"]) {
|
|
1328
|
+
const source = resolve6(monorepoRoot, fileName);
|
|
1329
|
+
if (existsSync5(source)) {
|
|
1330
|
+
cpSync2(source, resolve6(targetRoot, `workspace-${fileName}`), { force: true });
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
function imageFromDir(rootDir, fingerprint, id) {
|
|
1337
|
+
return {
|
|
1338
|
+
id,
|
|
1339
|
+
rootDir,
|
|
1340
|
+
binDir: resolve6(rootDir, "bin"),
|
|
1341
|
+
hooksDir: resolve6(rootDir, "bin/hooks"),
|
|
1342
|
+
pluginsDir: resolve6(rootDir, "bin/plugins"),
|
|
1343
|
+
validatorsDir: resolve6(rootDir, "bin/validators"),
|
|
1344
|
+
depsDir: resolve6(rootDir, "deps"),
|
|
1345
|
+
manifestPath: resolve6(rootDir, "image-manifest.json"),
|
|
1346
|
+
fingerprint
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
function cleanupImageBuildDirs(rootDir, currentBuildDir) {
|
|
1350
|
+
const imagesRootDir = resolve6(rootDir, "..");
|
|
1351
|
+
const buildPrefix = `${rootDir}.building-`;
|
|
1352
|
+
try {
|
|
1353
|
+
for (const entry of readdirSync(imagesRootDir)) {
|
|
1354
|
+
const fullPath = resolve6(imagesRootDir, entry);
|
|
1355
|
+
if (fullPath.startsWith(buildPrefix) && fullPath !== currentBuildDir) {
|
|
1356
|
+
rmSync3(fullPath, { recursive: true, force: true });
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
} catch {}
|
|
1360
|
+
}
|
|
1361
|
+
async function buildImage(projectRoot, image) {
|
|
1362
|
+
const { rootDir } = image;
|
|
1363
|
+
const bunPath = resolveBunBinaryPath4();
|
|
1364
|
+
const buildDir = `${rootDir}.building-${process.pid}`;
|
|
1365
|
+
cleanupImageBuildDirs(rootDir, buildDir);
|
|
1366
|
+
if (existsSync5(buildDir)) {
|
|
1367
|
+
rmSync3(buildDir, { recursive: true, force: true });
|
|
1368
|
+
}
|
|
1369
|
+
let promoted = false;
|
|
1370
|
+
try {
|
|
1371
|
+
const tempBinDir = resolve6(buildDir, "bin");
|
|
1372
|
+
const tempHooksDir = resolve6(buildDir, "bin/hooks");
|
|
1373
|
+
const tempPluginsDir = resolve6(buildDir, "bin/plugins");
|
|
1374
|
+
const tempValidatorsDir = resolve6(buildDir, "bin/validators");
|
|
1375
|
+
const tempDepsDir = resolve6(buildDir, "deps");
|
|
1376
|
+
mkdirSync4(tempBinDir, { recursive: true });
|
|
1377
|
+
mkdirSync4(tempHooksDir, { recursive: true });
|
|
1378
|
+
mkdirSync4(tempPluginsDir, { recursive: true });
|
|
1379
|
+
mkdirSync4(tempValidatorsDir, { recursive: true });
|
|
1380
|
+
mkdirSync4(tempDepsDir, { recursive: true });
|
|
1381
|
+
const nativeRuntimeLibraryPath = await materializeNativeRuntimeLibrary(tempBinDir);
|
|
1382
|
+
if (!nativeRuntimeLibraryPath) {
|
|
1383
|
+
throw new Error("Failed to provision the native Zig runtime library for runtime images.");
|
|
1384
|
+
}
|
|
1385
|
+
await buildBinary("packages/cli/bin/rig.ts", resolve6(tempBinDir, "rig"), projectRoot);
|
|
1386
|
+
await buildBinary("packages/cli/bin/rig-agent.ts", resolve6(tempBinDir, "rig-agent"), projectRoot);
|
|
1387
|
+
const { hookSources, namedSources } = await resolveContributedToolchainSources(projectRoot);
|
|
1388
|
+
const controlledBashSource = namedSources["controlled-bash"];
|
|
1389
|
+
if (!controlledBashSource) {
|
|
1390
|
+
throw new Error("No controlled-bash toolchain source contribution is registered.");
|
|
1391
|
+
}
|
|
1392
|
+
await buildBinary(controlledBashSource, resolve6(tempBinDir, "controlled-bash"), projectRoot);
|
|
1393
|
+
for (const [hookName, source] of hookSources) {
|
|
1394
|
+
await buildBinary(source, resolve6(tempHooksDir, hookName), projectRoot);
|
|
1395
|
+
}
|
|
1396
|
+
const plugins = discoverPlugins(projectRoot);
|
|
1397
|
+
for (const plugin of plugins) {
|
|
1398
|
+
if (existsSync5(resolve6(projectRoot, plugin.sourcePath))) {
|
|
1399
|
+
await buildBinary(plugin.sourcePath, resolve6(tempPluginsDir, plugin.name), projectRoot);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
const validators = discoverValidators(projectRoot);
|
|
1403
|
+
for (const { category, check, sourcePath } of validators) {
|
|
1404
|
+
if (!existsSync5(resolve6(projectRoot, sourcePath))) {
|
|
1405
|
+
continue;
|
|
1406
|
+
}
|
|
1407
|
+
await buildBinary(sourcePath, resolve6(tempValidatorsDir, `${category}-${check}`), projectRoot, {
|
|
1408
|
+
AGENT_BUN_PATH: bunPath
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
await provisionDependencyLayer(projectRoot, tempDepsDir);
|
|
1412
|
+
const manifest = {
|
|
1413
|
+
id: image.id,
|
|
1414
|
+
fingerprint: image.fingerprint,
|
|
1415
|
+
builtAt: new Date().toISOString(),
|
|
1416
|
+
pid: process.pid
|
|
1417
|
+
};
|
|
1418
|
+
writeFileSync3(resolve6(buildDir, "image-manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
|
|
1419
|
+
if (existsSync5(rootDir)) {
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
try {
|
|
1423
|
+
renameSync4(buildDir, rootDir);
|
|
1424
|
+
promoted = true;
|
|
1425
|
+
} catch {
|
|
1426
|
+
if (existsSync5(rootDir)) {
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
throw new Error(`Failed to promote runtime image build directory: ${buildDir} -> ${rootDir}`);
|
|
1430
|
+
}
|
|
1431
|
+
} finally {
|
|
1432
|
+
if (!promoted && existsSync5(buildDir)) {
|
|
1433
|
+
rmSync3(buildDir, { recursive: true, force: true });
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
function isRuntimeImageHealthy(projectRoot, image) {
|
|
1438
|
+
if (!existsSync5(image.manifestPath)) {
|
|
1439
|
+
return false;
|
|
1440
|
+
}
|
|
1441
|
+
const requiredPaths = [
|
|
1442
|
+
resolve6(image.binDir, "rig"),
|
|
1443
|
+
resolve6(image.binDir, "rig-agent"),
|
|
1444
|
+
resolve6(image.binDir, "controlled-bash"),
|
|
1445
|
+
...SHARED_HOOK_NAMES.map((hookName) => resolve6(image.hooksDir, hookName)),
|
|
1446
|
+
...discoverPlugins(projectRoot).map((plugin) => resolve6(image.pluginsDir, plugin.name)),
|
|
1447
|
+
...discoverValidators(projectRoot).map(({ category, check }) => resolve6(image.validatorsDir, `${category}-${check}`))
|
|
1448
|
+
];
|
|
1449
|
+
return requiredPaths.every((path) => existsSync5(path));
|
|
1450
|
+
}
|
|
1451
|
+
function computeRuntimeImageIdFromFingerprint(fp) {
|
|
1452
|
+
return computeRuntimeImageId(fp);
|
|
1453
|
+
}
|
|
1454
|
+
async function ensureRuntimeImage(projectRoot) {
|
|
1455
|
+
const fingerprint = await computeRuntimeImageFingerprint(projectRoot);
|
|
1456
|
+
const id = computeRuntimeImageId(fingerprint);
|
|
1457
|
+
const layout = resolveRigLayout2(projectRoot);
|
|
1458
|
+
const imagesRoot = resolve6(layout.runtimeDir, "images");
|
|
1459
|
+
mkdirSync4(imagesRoot, { recursive: true });
|
|
1460
|
+
const imageRootDir = resolve6(imagesRoot, id);
|
|
1461
|
+
const image = imageFromDir(imageRootDir, fingerprint, id);
|
|
1462
|
+
if (isRuntimeImageHealthy(projectRoot, image)) {
|
|
1463
|
+
return image;
|
|
1464
|
+
}
|
|
1465
|
+
const lockPath = resolve6(imagesRoot, `${id}.lock`);
|
|
1466
|
+
const acquired = acquireRuntimeImageLock(lockPath);
|
|
1467
|
+
try {
|
|
1468
|
+
if (isRuntimeImageHealthy(projectRoot, image)) {
|
|
1469
|
+
return image;
|
|
1470
|
+
}
|
|
1471
|
+
if (!acquired) {
|
|
1472
|
+
const ready = await waitForRuntimeImageManifest(image.manifestPath, LOCK_STALE_MS);
|
|
1473
|
+
if (!ready || !isRuntimeImageHealthy(projectRoot, image)) {
|
|
1474
|
+
throw new Error(`Runtime image ${id} is being built by another process and is not healthy after waiting. ` + `Lock file: ${lockPath}`);
|
|
1475
|
+
}
|
|
1476
|
+
return image;
|
|
1477
|
+
}
|
|
1478
|
+
if (existsSync5(image.rootDir)) {
|
|
1479
|
+
rmSync3(image.rootDir, { recursive: true, force: true });
|
|
1480
|
+
}
|
|
1481
|
+
await buildImage(projectRoot, image);
|
|
1482
|
+
return image;
|
|
1483
|
+
} finally {
|
|
1484
|
+
if (acquired) {
|
|
1485
|
+
releaseRuntimeImageLock(lockPath);
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
export {
|
|
1490
|
+
waitForRuntimeImageManifest,
|
|
1491
|
+
releaseRuntimeImageLock,
|
|
1492
|
+
ensureRuntimeImage,
|
|
1493
|
+
computeRuntimeImageIdFromFingerprint,
|
|
1494
|
+
computeRuntimeImageId,
|
|
1495
|
+
computeRuntimeImageFingerprintNative,
|
|
1496
|
+
computeRuntimeImageFingerprint,
|
|
1497
|
+
acquireRuntimeImageLock
|
|
1498
|
+
};
|