@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.
Files changed (77) hide show
  1. package/dist/src/embedded-native-assets.d.ts +7 -0
  2. package/dist/src/embedded-native-assets.js +6 -0
  3. package/dist/src/image-fingerprint-sidecar.d.ts +1 -0
  4. package/dist/src/image-fingerprint-sidecar.js +515 -0
  5. package/dist/src/image.d.ts +40 -0
  6. package/dist/src/image.js +1498 -0
  7. package/dist/src/index.js +4220 -20
  8. package/dist/src/isolation/binary-build-worker.d.ts +1 -0
  9. package/dist/src/isolation/binary-build-worker.js +323 -0
  10. package/dist/src/isolation/discovery.d.ts +7 -0
  11. package/dist/src/isolation/discovery.js +477 -0
  12. package/dist/src/isolation/git-native.d.ts +28 -0
  13. package/dist/src/isolation/git-native.js +598 -0
  14. package/dist/src/isolation/home.d.ts +25 -0
  15. package/dist/src/isolation/home.js +929 -0
  16. package/dist/src/isolation/index.d.ts +43 -0
  17. package/dist/src/isolation/index.js +4062 -0
  18. package/dist/src/isolation/provisioning-env.d.ts +1 -0
  19. package/dist/src/isolation/provisioning-env.js +6 -0
  20. package/dist/src/isolation/runner.d.ts +20 -0
  21. package/dist/src/isolation/runner.js +1881 -0
  22. package/dist/src/isolation/runtime-binary-build.d.ts +88 -0
  23. package/dist/src/isolation/runtime-binary-build.js +480 -0
  24. package/dist/src/isolation/shared.d.ts +29 -0
  25. package/dist/src/isolation/shared.js +283 -0
  26. package/dist/src/isolation/toolchain.d.ts +71 -0
  27. package/dist/src/isolation/toolchain.js +1348 -0
  28. package/dist/src/isolation/types.d.ts +15 -0
  29. package/dist/src/isolation/types.js +1 -0
  30. package/dist/src/isolation/worktree.d.ts +22 -0
  31. package/dist/src/isolation/worktree.js +353 -0
  32. package/dist/src/native-extract.d.ts +2 -0
  33. package/dist/src/native-extract.js +44 -0
  34. package/dist/src/plugin.d.ts +2 -2
  35. package/dist/src/plugin.js +4219 -19
  36. package/dist/src/runtime-config.d.ts +3 -0
  37. package/dist/src/runtime-config.js +215 -0
  38. package/dist/src/runtime-native-sidecar.d.ts +8 -0
  39. package/dist/src/runtime-native-sidecar.js +368 -0
  40. package/dist/src/runtime-native.d.ts +51 -0
  41. package/dist/src/runtime-native.js +485 -0
  42. package/dist/src/sandbox/backend-bwrap.d.ts +20 -0
  43. package/dist/src/sandbox/backend-bwrap.js +268 -0
  44. package/dist/src/sandbox/backend-none.d.ts +11 -0
  45. package/dist/src/sandbox/backend-none.js +20 -0
  46. package/dist/src/sandbox/backend-seatbelt.d.ts +13 -0
  47. package/dist/src/sandbox/backend-seatbelt.js +225 -0
  48. package/dist/src/sandbox/backend.d.ts +117 -0
  49. package/dist/src/sandbox/backend.js +864 -0
  50. package/dist/src/sandbox/orchestrator.d.ts +21 -0
  51. package/dist/src/sandbox/orchestrator.js +895 -0
  52. package/dist/src/sandbox/utils.d.ts +43 -0
  53. package/dist/src/sandbox/utils.js +94 -0
  54. package/dist/src/service.d.ts +10 -5
  55. package/dist/src/service.js +4145 -2
  56. package/dist/src/sidecar-arg.d.ts +7 -0
  57. package/dist/src/sidecar-arg.js +6 -0
  58. package/dist/src/sidecar-entrypoint.d.ts +9 -0
  59. package/dist/src/sidecar-entrypoint.js +401 -0
  60. package/dist/src/snapshot-sidecar.d.ts +2 -0
  61. package/dist/src/snapshot-sidecar.js +566 -0
  62. package/dist/src/snapshot.d.ts +64 -0
  63. package/dist/src/snapshot.js +515 -0
  64. package/dist/src/task-run-snapshot.d.ts +26 -0
  65. package/dist/src/task-run-snapshot.js +713 -0
  66. package/native/darwin-arm64/rig-git +0 -0
  67. package/native/darwin-arm64/rig-git.build-manifest.json +4 -0
  68. package/native/darwin-arm64/runtime-native.dylib +0 -0
  69. package/native/darwin-x64/rig-git +0 -0
  70. package/native/darwin-x64/runtime-native.dylib +0 -0
  71. package/native/linux-arm64/rig-git +0 -0
  72. package/native/linux-arm64/runtime-native.so +0 -0
  73. package/native/linux-x64/rig-git +0 -0
  74. package/native/linux-x64/runtime-native.so +0 -0
  75. package/native/win32-x64/rig-git.exe +0 -0
  76. package/native/win32-x64/runtime-native.dll +0 -0
  77. package/package.json +45 -5
@@ -0,0 +1,929 @@
1
+ // @bun
2
+ // packages/isolation-plugin/src/isolation/home.ts
3
+ import {
4
+ chmodSync,
5
+ copyFileSync as copyFileSync2,
6
+ cpSync,
7
+ existsSync as existsSync4,
8
+ mkdirSync as mkdirSync3,
9
+ readFileSync as readFileSync3,
10
+ statSync as statSync3,
11
+ writeFileSync as writeFileSync2
12
+ } from "fs";
13
+ import { mkdir } from "fs/promises";
14
+ import { basename, delimiter, resolve as resolve5 } from "path";
15
+ import { resolveBunBinaryPath, resolveBunInstallDir, resolveClaudeBinaryPath, resolveClaudeInstallDir, resolveNodeInstallDir } from "@rig/core/runtime-paths";
16
+ import { resolveRuntimeSecrets } from "@rig/core/baked-secrets";
17
+
18
+ // packages/isolation-plugin/src/runtime-native.ts
19
+ import { dlopen, ptr, suffix, toBuffer } from "bun:ffi";
20
+ import { copyFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2, renameSync as renameSync2, rmSync, statSync as statSync2 } from "fs";
21
+ import { tmpdir as tmpdir2 } from "os";
22
+ import { dirname, resolve as resolve2 } from "path";
23
+
24
+ // packages/isolation-plugin/src/native-extract.ts
25
+ import { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "fs";
26
+ import { tmpdir } from "os";
27
+ import { resolve } from "path";
28
+
29
+ // packages/isolation-plugin/src/embedded-native-assets.ts
30
+ var embeddedNatives = null;
31
+
32
+ // packages/isolation-plugin/src/native-extract.ts
33
+ var sharedNativeOutputDir = resolve(tmpdir(), "rig-native");
34
+ var extractionCache = {};
35
+ function extractEmbeddedNative(name) {
36
+ if (name in extractionCache) {
37
+ return extractionCache[name] ?? null;
38
+ }
39
+ const entry = embeddedNatives?.[name];
40
+ if (!entry) {
41
+ extractionCache[name] = null;
42
+ return null;
43
+ }
44
+ try {
45
+ const targetPath = resolve(sharedNativeOutputDir, entry.fileName);
46
+ mkdirSync(sharedNativeOutputDir, { recursive: true });
47
+ const upToDate = existsSync(targetPath) && statSync(targetPath).size === entry.size;
48
+ if (!upToDate) {
49
+ const bytes = readFileSync(entry.filePath);
50
+ const tempPath = `${targetPath}.${process.pid}.${Date.now()}.tmp`;
51
+ writeFileSync(tempPath, bytes, { mode: 493 });
52
+ renameSync(tempPath, targetPath);
53
+ }
54
+ extractionCache[name] = targetPath;
55
+ } catch {
56
+ extractionCache[name] = null;
57
+ }
58
+ return extractionCache[name] ?? null;
59
+ }
60
+
61
+ // packages/isolation-plugin/src/runtime-native.ts
62
+ var sharedNativeRuntimeOutputDir = resolve2(tmpdir2(), "rig-native");
63
+ var sharedNativeRuntimeOutputPath = resolve2(sharedNativeRuntimeOutputDir, `runtime-native-${process.platform}-${process.arch}.${suffix}`);
64
+ var colocatedNativeRuntimeFileName = `runtime-native.${suffix}`;
65
+ var nativeRuntimeLibrary = await loadNativeRuntimeLibrary();
66
+ async function ensureNativeRuntimeLibraryPath(outputPath = sharedNativeRuntimeOutputPath, options = {}) {
67
+ const explicitLib = process.env.RIG_NATIVE_RUNTIME_LIB?.trim();
68
+ if (explicitLib && existsSync2(explicitLib)) {
69
+ return explicitLib;
70
+ }
71
+ const embeddedPath = extractEmbeddedNative("snapshot");
72
+ if (embeddedPath) {
73
+ return embeddedPath;
74
+ }
75
+ if (await buildNativeRuntimeLibrary(outputPath, options)) {
76
+ return outputPath;
77
+ }
78
+ return !options.force && existsSync2(outputPath) ? outputPath : null;
79
+ }
80
+ async function materializeNativeRuntimeLibrary(targetDir) {
81
+ const sourcePath = await ensureNativeRuntimeLibraryPath();
82
+ if (!sourcePath) {
83
+ return null;
84
+ }
85
+ const targetPath = resolve2(targetDir, colocatedNativeRuntimeFileName);
86
+ mkdirSync2(targetDir, { recursive: true });
87
+ const needsCopy = !existsSync2(targetPath) || statSync2(sourcePath).mtimeMs > statSync2(targetPath).mtimeMs;
88
+ if (needsCopy) {
89
+ copyFileSync(sourcePath, targetPath);
90
+ }
91
+ return targetPath;
92
+ }
93
+ async function loadNativeRuntimeLibrary() {
94
+ if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
95
+ return null;
96
+ }
97
+ const explicitLib = process.env.RIG_NATIVE_RUNTIME_LIB?.trim();
98
+ if (explicitLib && existsSync2(explicitLib)) {
99
+ const loaded = tryDlopenNativeRuntimeLibrary(explicitLib);
100
+ if (loaded) {
101
+ return loaded;
102
+ }
103
+ }
104
+ const embeddedPath = extractEmbeddedNative("snapshot");
105
+ if (embeddedPath) {
106
+ const loaded = tryDlopenNativeRuntimeLibrary(embeddedPath);
107
+ if (loaded) {
108
+ return loaded;
109
+ }
110
+ }
111
+ for (const candidate of nativeRuntimeLibraryCandidates()) {
112
+ if (!candidate || !existsSync2(candidate)) {
113
+ continue;
114
+ }
115
+ const loaded = tryDlopenNativeRuntimeLibrary(candidate);
116
+ if (loaded) {
117
+ return loaded;
118
+ }
119
+ }
120
+ const builtLibraryPath = await ensureNativeRuntimeLibraryPath(sharedNativeRuntimeOutputPath, { force: true });
121
+ if (!builtLibraryPath) {
122
+ return null;
123
+ }
124
+ return tryDlopenNativeRuntimeLibrary(builtLibraryPath);
125
+ }
126
+ function nativePackageLibraryCandidates(fromDir, names) {
127
+ const candidates = [];
128
+ let cursor = resolve2(fromDir);
129
+ for (let index = 0;index < 8; index += 1) {
130
+ for (const name of names) {
131
+ 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));
132
+ }
133
+ const parent = dirname(cursor);
134
+ if (parent === cursor)
135
+ break;
136
+ cursor = parent;
137
+ }
138
+ return candidates;
139
+ }
140
+ function nativeRuntimeLibraryCandidates() {
141
+ const explicit = process.env.RIG_NATIVE_RUNTIME_LIB?.trim() || "";
142
+ const execDir = process.execPath?.trim() ? dirname(process.execPath.trim()) : "";
143
+ const platformSpecific = `runtime-native-${process.platform}-${process.arch}.${suffix}`;
144
+ return [...new Set([
145
+ explicit,
146
+ ...nativePackageLibraryCandidates(import.meta.dir, [colocatedNativeRuntimeFileName, platformSpecific]),
147
+ execDir ? resolve2(execDir, colocatedNativeRuntimeFileName) : "",
148
+ execDir ? resolve2(execDir, platformSpecific) : "",
149
+ execDir ? resolve2(execDir, "..", colocatedNativeRuntimeFileName) : "",
150
+ execDir ? resolve2(execDir, "..", platformSpecific) : "",
151
+ execDir ? resolve2(execDir, "lib", colocatedNativeRuntimeFileName) : "",
152
+ execDir ? resolve2(execDir, "..", "lib", colocatedNativeRuntimeFileName) : "",
153
+ sharedNativeRuntimeOutputPath
154
+ ].filter(Boolean))];
155
+ }
156
+ function resolveNativeRuntimeSourcePath() {
157
+ const explicit = process.env.RIG_NATIVE_RUNTIME_SOURCE?.trim();
158
+ if (explicit && existsSync2(explicit)) {
159
+ return explicit;
160
+ }
161
+ const bundled = resolve2(import.meta.dir, "../native/snapshot.zig");
162
+ return existsSync2(bundled) ? bundled : null;
163
+ }
164
+ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
165
+ if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
166
+ return false;
167
+ }
168
+ const zigBinary = Bun.which("zig");
169
+ const sourcePath = resolveNativeRuntimeSourcePath();
170
+ if (!zigBinary || !sourcePath) {
171
+ return false;
172
+ }
173
+ const tempOutputPath = `${outputPath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
174
+ try {
175
+ mkdirSync2(dirname(outputPath), { recursive: true });
176
+ const needsBuild = options.force === true || !existsSync2(outputPath) || statSync2(sourcePath).mtimeMs > statSync2(outputPath).mtimeMs;
177
+ if (!needsBuild) {
178
+ return true;
179
+ }
180
+ const build = Bun.spawn([
181
+ zigBinary,
182
+ "build-lib",
183
+ sourcePath,
184
+ "-dynamic",
185
+ "-O",
186
+ "ReleaseFast",
187
+ `-femit-bin=${tempOutputPath}`
188
+ ], {
189
+ cwd: import.meta.dir,
190
+ stdout: "pipe",
191
+ stderr: "pipe"
192
+ });
193
+ const exitCode = await build.exited;
194
+ if (exitCode !== 0 || !existsSync2(tempOutputPath)) {
195
+ rmSync(tempOutputPath, { force: true });
196
+ return false;
197
+ }
198
+ renameSync2(tempOutputPath, outputPath);
199
+ return true;
200
+ } catch {
201
+ rmSync(tempOutputPath, { force: true });
202
+ return false;
203
+ }
204
+ }
205
+ function tryDlopenNativeRuntimeLibrary(outputPath) {
206
+ try {
207
+ return dlopen(outputPath, {
208
+ rig_scope_match: {
209
+ args: ["ptr", "ptr"],
210
+ returns: "u8"
211
+ },
212
+ snapshot_capture: {
213
+ args: ["ptr", "u64", "ptr", "u64"],
214
+ returns: "ptr"
215
+ },
216
+ snapshot_delta: {
217
+ args: ["ptr", "ptr"],
218
+ returns: "ptr"
219
+ },
220
+ snapshot_store_delta: {
221
+ args: ["ptr", "ptr", "ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64"],
222
+ returns: "ptr"
223
+ },
224
+ snapshot_inspect_delta: {
225
+ args: ["ptr", "u64"],
226
+ returns: "ptr"
227
+ },
228
+ snapshot_apply_delta: {
229
+ args: ["ptr", "u64", "ptr", "u64"],
230
+ returns: "ptr"
231
+ },
232
+ snapshot_release: {
233
+ args: ["ptr"],
234
+ returns: "void"
235
+ },
236
+ runtime_hash_file: {
237
+ args: ["ptr", "u64"],
238
+ returns: "ptr"
239
+ },
240
+ runtime_hash_tree: {
241
+ args: ["ptr", "u64"],
242
+ returns: "ptr"
243
+ },
244
+ runtime_prepare_paths: {
245
+ args: ["ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64"],
246
+ returns: "ptr"
247
+ },
248
+ runtime_link_dependency_layer: {
249
+ args: ["ptr", "u64", "ptr", "u64"],
250
+ returns: "ptr"
251
+ },
252
+ runtime_scan_worktrees: {
253
+ args: ["ptr", "u64"],
254
+ returns: "ptr"
255
+ }
256
+ });
257
+ } catch {
258
+ return null;
259
+ }
260
+ }
261
+
262
+ // packages/isolation-plugin/src/isolation/home.ts
263
+ import { browserEnvFromContext, loadRuntimeContext, runtimeMemoryEnvFromContext, RUNTIME_CONTEXT_ENV } from "@rig/core/runtime-context";
264
+
265
+ // packages/isolation-plugin/src/isolation/shared.ts
266
+ import { existsSync as existsSync3, readFileSync as readFileSync2, rmSync as rmSync2 } from "fs";
267
+ import { resolve as resolve3 } from "path";
268
+ import { agentId, safeGitRefComponent, taskRuntimeId } from "@rig/core/safe-identifiers";
269
+ import { resolveCheckoutRoot } from "@rig/core/checkout-root";
270
+ function isRuntimeGatewayGhPath(candidate) {
271
+ return /\/\.rig\/bin\/gh$/.test(candidate.replace(/\\/g, "/"));
272
+ }
273
+ function resolveGithubCliBinary(options = {}) {
274
+ const candidates = new Set;
275
+ const explicit = process.env.RIG_GH_BIN?.trim();
276
+ if (explicit) {
277
+ candidates.add(explicit);
278
+ }
279
+ for (const candidate of ["/usr/bin/gh", "/opt/homebrew/bin/gh", "/usr/local/bin/gh"]) {
280
+ candidates.add(candidate);
281
+ }
282
+ if (options.scanPath) {
283
+ for (const entry of (process.env.PATH || "").split(":").map((value) => value.trim()).filter(Boolean)) {
284
+ candidates.add(resolve3(entry, "gh"));
285
+ }
286
+ }
287
+ const bunResolved = Bun.which("gh");
288
+ if (bunResolved) {
289
+ candidates.add(bunResolved);
290
+ }
291
+ for (const candidate of candidates) {
292
+ if (candidate && existsSync3(candidate) && !isRuntimeGatewayGhPath(candidate)) {
293
+ return candidate;
294
+ }
295
+ }
296
+ return "";
297
+ }
298
+ var generatedCredentialFiles = new Set;
299
+ var credentialCleanupRegistered = false;
300
+ function resolveMonorepoRoot(projectRoot) {
301
+ return resolveCheckoutRoot(projectRoot);
302
+ }
303
+ function sha256Hex(input) {
304
+ const hasher = new Bun.CryptoHasher("sha256");
305
+ hasher.update(input);
306
+ return hasher.digest("hex");
307
+ }
308
+ function registerCredentialCleanup(path) {
309
+ generatedCredentialFiles.add(path);
310
+ if (credentialCleanupRegistered) {
311
+ return;
312
+ }
313
+ credentialCleanupRegistered = true;
314
+ const cleanup = () => {
315
+ for (const filePath of generatedCredentialFiles) {
316
+ try {
317
+ rmSync2(filePath, { force: true });
318
+ } catch {}
319
+ }
320
+ generatedCredentialFiles.clear();
321
+ };
322
+ process.on("exit", cleanup);
323
+ process.on("beforeExit", cleanup);
324
+ }
325
+ function hashProjectPath(workspaceDir) {
326
+ return sha256Hex(workspaceDir).slice(0, 16);
327
+ }
328
+ async function resolveGithubCliAuthToken(ghBinary = "") {
329
+ const gh = ghBinary || resolveGithubCliBinary();
330
+ if (!gh) {
331
+ return "";
332
+ }
333
+ const auth = Bun.spawn([gh, "auth", "token"], {
334
+ stdout: "pipe",
335
+ stderr: "pipe"
336
+ });
337
+ const [exitCode, stdout] = await Promise.all([
338
+ auth.exited,
339
+ new Response(auth.stdout).text()
340
+ ]);
341
+ if (exitCode !== 0) {
342
+ return "";
343
+ }
344
+ return stdout.trim();
345
+ }
346
+ function resolveSystemCertBundlePath() {
347
+ const candidates = [
348
+ process.env.SSL_CERT_FILE?.trim(),
349
+ "/etc/ssl/cert.pem",
350
+ "/private/etc/ssl/cert.pem",
351
+ "/opt/homebrew/etc/openssl@3/cert.pem"
352
+ ];
353
+ for (const candidate of candidates) {
354
+ if (candidate && existsSync3(candidate)) {
355
+ return resolve3(candidate);
356
+ }
357
+ }
358
+ return "";
359
+ }
360
+ function readKnownHosts(path) {
361
+ if (!existsSync3(path)) {
362
+ return new Set;
363
+ }
364
+ return new Set(readFileSync2(path, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
365
+ }
366
+
367
+ // packages/isolation-plugin/src/isolation/git-native.ts
368
+ import { tmpdir as tmpdir3 } from "os";
369
+ import { dirname as dirname2, isAbsolute, resolve as resolve4 } from "path";
370
+ var sharedGitNativeOutputDir = resolve4(tmpdir3(), "rig-native");
371
+ var sharedGitNativeOutputPath = resolve4(sharedGitNativeOutputDir, `rig-git-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
372
+ function runtimeRigGitFileName() {
373
+ return `rig-git${process.platform === "win32" ? ".exe" : ""}`;
374
+ }
375
+
376
+ // packages/isolation-plugin/src/isolation/home.ts
377
+ var GITHUB_SSH_KEY_PLACEHOLDER = "<base64 encoded>";
378
+ var GITHUB_KNOWN_HOSTS = [
379
+ "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl",
380
+ "github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=",
381
+ "github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk="
382
+ ].join(`
383
+ `);
384
+ function authStateToken(env = process.env) {
385
+ const file = env.RIG_GITHUB_AUTH_STATE_FILE?.trim();
386
+ if (!file || !existsSync4(file))
387
+ return null;
388
+ try {
389
+ const parsed = JSON.parse(readFileSync3(file, "utf8"));
390
+ const token = typeof parsed.token === "string" ? parsed.token.trim() : "";
391
+ return token.length > 0 ? token : null;
392
+ } catch {
393
+ return null;
394
+ }
395
+ }
396
+ function resolveControlPlaneSourceRoot(projectRoot) {
397
+ const candidates = [
398
+ process.env.RIG_CONTROL_PLANE_SOURCE_ROOT?.trim(),
399
+ process.env.RIG_HOST_PROJECT_ROOT?.trim(),
400
+ resolve5(import.meta.dir, "../../../../.."),
401
+ projectRoot
402
+ ].filter((value) => Boolean(value));
403
+ for (const candidate of candidates) {
404
+ const root = resolve5(candidate);
405
+ if (existsSync4(resolve5(root, "packages/cli/bin/rig.ts"))) {
406
+ return root;
407
+ }
408
+ }
409
+ return "";
410
+ }
411
+ async function runtimeEnv(projectRoot, runtime) {
412
+ const bunBinaryPath = resolveBunBinaryPath();
413
+ const bunDir = resolveBunInstallDir(bunBinaryPath);
414
+ const claudeBinaryPath = process.env.RIG_CLAUDE_PATH?.trim() || (() => {
415
+ try {
416
+ return resolveClaudeBinaryPath();
417
+ } catch {
418
+ return "";
419
+ }
420
+ })();
421
+ const claudeDir = claudeBinaryPath ? (() => {
422
+ try {
423
+ return resolveClaudeInstallDir();
424
+ } catch {
425
+ return resolve5(claudeBinaryPath, "..");
426
+ }
427
+ })() : "";
428
+ const nodeDir = resolveNodeInstallDir();
429
+ const hostGhBinary = resolveGithubCliBinary();
430
+ const runtimeCertBundlePath = await materializeRuntimeCertBundle(runtime);
431
+ const monorepoMainRoot = resolveMonorepoRoot(projectRoot);
432
+ const realHome = process.env.HOME?.trim();
433
+ const inheritedPath = (process.env.PATH ?? "").split(delimiter).map((entry) => entry.trim()).filter(Boolean).filter((entry) => !entry.endsWith("/.rig/bin") && !entry.endsWith("/rig/tools"));
434
+ const pathEntries = [
435
+ runtime.binDir,
436
+ `${projectRoot}/rig/tools`,
437
+ `${bunDir}/bin`,
438
+ claudeDir,
439
+ nodeDir ? `${nodeDir}/bin` : "",
440
+ realHome ? resolve5(realHome, ".local/bin") : "",
441
+ realHome ? resolve5(realHome, ".cargo/bin") : "",
442
+ ...inheritedPath,
443
+ "/usr/local/bin",
444
+ "/usr/local/sbin",
445
+ "/opt/homebrew/bin",
446
+ "/opt/homebrew/sbin",
447
+ "/usr/bin",
448
+ "/bin",
449
+ "/usr/sbin",
450
+ "/sbin"
451
+ ].filter(Boolean);
452
+ const runtimeBash = resolve5(runtime.binDir, "bash");
453
+ const runtimeRigGit = resolve5(runtime.binDir, runtimeRigGitFileName());
454
+ const preferredShell = existsSync4(runtimeBash) ? runtimeBash : "/bin/bash";
455
+ const nativeRuntimeLibraryPath = await materializeNativeRuntimeLibrary(runtime.binDir);
456
+ const controlPlaneSourceRoot = resolveControlPlaneSourceRoot(projectRoot);
457
+ const env = {
458
+ PROJECT_RIG_ROOT: projectRoot,
459
+ RIG_HOST_PROJECT_ROOT: projectRoot,
460
+ ...controlPlaneSourceRoot ? { RIG_CONTROL_PLANE_SOURCE_ROOT: controlPlaneSourceRoot } : {},
461
+ HOME: runtime.homeDir,
462
+ TMPDIR: runtime.tmpDir,
463
+ XDG_CACHE_HOME: runtime.cacheDir,
464
+ XDG_STATE_HOME: runtime.stateDir,
465
+ RIG_AGENT_ID: runtime.id,
466
+ ...process.env.RIG_RUN_ID?.trim() ? { RIG_RUN_ID: process.env.RIG_RUN_ID.trim() } : {},
467
+ ...process.env.RIG_SERVER_RUN_ID?.trim() ? { RIG_SERVER_RUN_ID: process.env.RIG_SERVER_RUN_ID.trim() } : {},
468
+ ...process.env.RIG_SERVER_URL?.trim() ? { RIG_SERVER_URL: process.env.RIG_SERVER_URL.trim() } : {},
469
+ ...process.env.RIG_AUTH_TOKEN?.trim() ? { RIG_AUTH_TOKEN: process.env.RIG_AUTH_TOKEN.trim() } : {},
470
+ RIG_TASK_ID: runtime.taskId,
471
+ RIG_TASK_RUNTIME_ID: runtime.id,
472
+ RIG_TASK_WORKSPACE: runtime.workspaceDir,
473
+ RIG_TASK_RUNTIME_MODE: runtime.mode,
474
+ RIG_RUNTIME_MODE: runtime.mode,
475
+ RIG_RUNTIME_ADAPTER: "pi",
476
+ RIG_RUNTIME_HOME: runtime.rootDir,
477
+ RIG_RUNTIME_BIN_DIR: runtime.binDir,
478
+ ...existsSync4(runtimeRigGit) ? { RIG_NATIVE_GIT_BIN: runtimeRigGit } : {},
479
+ RIG_BUN_PATH: bunBinaryPath,
480
+ ...claudeBinaryPath ? { RIG_CLAUDE_PATH: claudeBinaryPath } : {},
481
+ RIG_AGENT_BIN: resolve5(runtime.binDir, "rig-agent"),
482
+ RIG_HOOKS_ACTIVE: "1",
483
+ RIG_AUTO_PR_ON_COMPLETE: "1",
484
+ RIG_POLICY_FILE: resolve5(projectRoot, "rig/policy/policy.json"),
485
+ RIG_STATE_DIR: runtime.stateDir,
486
+ RIG_LOGS_DIR: runtime.logsDir,
487
+ RIG_SESSION_FILE: resolve5(runtime.sessionDir, "session.json"),
488
+ MONOREPO_ROOT: runtime.workspaceDir,
489
+ MONOREPO_MAIN_ROOT: monorepoMainRoot,
490
+ TS_API_TESTS_DIR: resolve5(runtime.workspaceDir, "TSAPITests"),
491
+ BASH: preferredShell,
492
+ SHELL: preferredShell,
493
+ PATH: [...new Set(pathEntries)].join(delimiter),
494
+ LANG: process.env.LANG ?? "en_US.UTF-8",
495
+ TERM: process.env.TERM ?? "xterm-256color",
496
+ PYTHONDONTWRITEBYTECODE: "1",
497
+ PYTHONPYCACHEPREFIX: resolve5(runtime.cacheDir, "python"),
498
+ ...process.env.RIG_PR_BASE_PROJECT && { RIG_PR_BASE_PROJECT: process.env.RIG_PR_BASE_PROJECT },
499
+ ...process.env.RIG_PR_BASE_MONOREPO && { RIG_PR_BASE_MONOREPO: process.env.RIG_PR_BASE_MONOREPO },
500
+ CLAUDE_HOME: runtime.claudeHomeDir,
501
+ PI_CODING_AGENT_DIR: resolve5(runtime.homeDir, ".pi", "agent"),
502
+ OMP_SKIP_SETUP: "1",
503
+ [RUNTIME_CONTEXT_ENV]: runtime.contextFile,
504
+ ...nativeRuntimeLibraryPath ? { RIG_NATIVE_RUNTIME_LIB: nativeRuntimeLibraryPath } : {},
505
+ ...hostGhBinary ? { RIG_GH_BIN: hostGhBinary } : {},
506
+ ...runtimeCertBundlePath ? {
507
+ SSL_CERT_FILE: runtimeCertBundlePath,
508
+ CURL_CA_BUNDLE: runtimeCertBundlePath,
509
+ REQUESTS_CA_BUNDLE: runtimeCertBundlePath,
510
+ NODE_EXTRA_CA_CERTS: runtimeCertBundlePath
511
+ } : {}
512
+ };
513
+ const knownHostsPath = resolve5(runtime.homeDir, ".ssh", "known_hosts");
514
+ if (existsSync4(knownHostsPath)) {
515
+ const agentSshKey = resolve5(runtime.homeDir, ".ssh", "rig-agent-key");
516
+ const sshParts = [
517
+ "ssh",
518
+ `-o UserKnownHostsFile="${knownHostsPath}"`,
519
+ "-o StrictHostKeyChecking=yes",
520
+ "-F /dev/null"
521
+ ];
522
+ if (existsSync4(agentSshKey)) {
523
+ sshParts.splice(1, 0, `-i "${agentSshKey}"`, "-o IdentitiesOnly=yes");
524
+ }
525
+ env.GIT_SSH_COMMAND = sshParts.join(" ");
526
+ }
527
+ const persistedSecretsPath = resolve5(runtime.rootDir, "runtime-secrets.json");
528
+ if (existsSync4(persistedSecretsPath)) {
529
+ try {
530
+ const persisted = JSON.parse(readFileSync3(persistedSecretsPath, "utf8"));
531
+ if (persisted && typeof persisted === "object") {
532
+ for (const [key, value] of Object.entries(persisted)) {
533
+ if (key === "GITHUB_SSH_KEY")
534
+ continue;
535
+ if (typeof value === "string" && value && !env[key])
536
+ env[key] = value;
537
+ }
538
+ }
539
+ } catch {}
540
+ }
541
+ for (const [key, value] of Object.entries(resolveRuntimeSecrets(process.env))) {
542
+ if (key === "GITHUB_SSH_KEY") {
543
+ continue;
544
+ }
545
+ if (value) {
546
+ env[key] = value;
547
+ }
548
+ }
549
+ const authStateGithubToken = authStateToken(process.env) || "";
550
+ const explicitRigGithubToken = process.env.RIG_GITHUB_TOKEN?.trim() || "";
551
+ const rigGithubToken = explicitRigGithubToken || authStateGithubToken;
552
+ if (rigGithubToken) {
553
+ env.RIG_GITHUB_TOKEN = rigGithubToken;
554
+ env.GITHUB_TOKEN = rigGithubToken;
555
+ env.GH_TOKEN = rigGithubToken;
556
+ }
557
+ const fallbackGithubToken = !env.GITHUB_TOKEN && !env.GH_TOKEN ? await resolveGithubCliAuthToken(hostGhBinary) : "";
558
+ if (fallbackGithubToken) {
559
+ env.GITHUB_TOKEN = fallbackGithubToken;
560
+ }
561
+ if (!env.GITHUB_TOKEN && env.GH_TOKEN) {
562
+ env.GITHUB_TOKEN = env.GH_TOKEN;
563
+ }
564
+ if (!env.GH_TOKEN && env.GITHUB_TOKEN) {
565
+ env.GH_TOKEN = env.GITHUB_TOKEN;
566
+ }
567
+ const gitHubToken = env.GITHUB_TOKEN || env.GH_TOKEN || rigGithubToken;
568
+ if (gitHubToken) {
569
+ env.RIG_GITHUB_TOKEN = gitHubToken;
570
+ env.GITHUB_TOKEN = env.GITHUB_TOKEN || gitHubToken;
571
+ env.GH_TOKEN = env.GH_TOKEN || gitHubToken;
572
+ applyGitHubCredentialHelperEnv(env);
573
+ }
574
+ if (!env.GREPTILE_GITHUB_TOKEN && env.GITHUB_TOKEN) {
575
+ env.GREPTILE_GITHUB_TOKEN = env.GITHUB_TOKEN;
576
+ }
577
+ if (existsSync4(runtime.contextFile)) {
578
+ const runtimeContext = loadRuntimeContext(runtime.contextFile);
579
+ Object.assign(env, runtimeMemoryEnvFromContext(runtimeContext));
580
+ Object.assign(env, browserEnvFromContext(runtimeContext.browser));
581
+ }
582
+ persistRuntimeSecrets(runtime.rootDir, env);
583
+ return env;
584
+ }
585
+ function runtimeCommandEnv(baseEnv, command) {
586
+ const env = { ...baseEnv };
587
+ delete env.ENV;
588
+ delete env.BASH_ENV;
589
+ const executable = command[0]?.trim() ?? "";
590
+ const shellName = basename(executable);
591
+ const isPosixSh = executable === "/bin/sh" || shellName === "sh" || shellName === "dash";
592
+ if (isPosixSh) {
593
+ delete env.BASH;
594
+ if (executable) {
595
+ env.SHELL = executable;
596
+ }
597
+ }
598
+ return env;
599
+ }
600
+ async function provisionRuntimeHome(runtime, options = {}) {
601
+ await mkdir(runtime.homeDir, { recursive: true });
602
+ await mkdir(runtime.tmpDir, { recursive: true });
603
+ await mkdir(runtime.cacheDir, { recursive: true });
604
+ await provisionAgentSshKey(runtime.homeDir);
605
+ if (options.provider === "pi") {
606
+ const hasPiAuth = await injectPiAgentConfig(resolve5(runtime.homeDir, ".pi", "agent"));
607
+ if (!hasPiAuth) {
608
+ console.warn("[rig] No Pi auth.json found for isolated runtime. " + "Run `pi /login` in your host shell, then retry the agent run.");
609
+ }
610
+ }
611
+ }
612
+ async function provisionClaudeHome(config) {
613
+ mkdirSync3(config.claudeHomeDir, { recursive: true });
614
+ const workspaceSettings = resolve5(config.workspaceDir, ".claude/settings.json");
615
+ const hostSettings = resolve5(config.hostProjectRoot, ".claude/settings.json");
616
+ const projectSettings = existsSync4(workspaceSettings) ? workspaceSettings : hostSettings;
617
+ const runtimeSettings = await loadRuntimeClaudeSettings(projectSettings);
618
+ if (existsSync4(projectSettings)) {
619
+ writeFileSync2(resolve5(config.claudeHomeDir, "settings.local.json"), `${JSON.stringify(runtimeSettings, null, 2)}
620
+ `, "utf-8");
621
+ }
622
+ writeClaudeProjectSettings(config.claudeHomeDir, config.workspaceDir, runtimeSettings);
623
+ writeFileSync2(resolve5(config.claudeHomeDir, "settings.json"), JSON.stringify({
624
+ permissions: { defaultMode: "bypassPermissions" },
625
+ autoMemoryEnabled: false
626
+ }, null, 2));
627
+ const hasCredentials = await injectClaudeCredentials(config.claudeHomeDir);
628
+ if (!hasCredentials) {
629
+ console.warn("[rig] No Claude credentials found for isolated runtime. " + "Run `claude /login` in your host shell, then retry the agent run.");
630
+ }
631
+ const realClaudeHome = resolve5(process.env.HOME ?? "", ".claude");
632
+ if (process.env.HOME && existsSync4(resolve5(realClaudeHome, "CLAUDE.md"))) {
633
+ cpSync(resolve5(realClaudeHome, "CLAUDE.md"), resolve5(config.claudeHomeDir, "CLAUDE.md"));
634
+ }
635
+ if (process.env.HOME && existsSync4(resolve5(realClaudeHome, "agents"))) {
636
+ cpSync(resolve5(realClaudeHome, "agents"), resolve5(config.claudeHomeDir, "agents"), { recursive: true });
637
+ }
638
+ if (process.platform === "darwin" && process.env.HOME) {
639
+ writeClaudeProjectSettings(realClaudeHome, config.workspaceDir, runtimeSettings);
640
+ }
641
+ }
642
+ async function materializeRuntimeCertBundle(runtime) {
643
+ const sourcePath = resolveSystemCertBundlePath();
644
+ if (!sourcePath) {
645
+ return "";
646
+ }
647
+ const certsDir = resolve5(runtime.rootDir, "certs");
648
+ const targetPath = resolve5(certsDir, "ca-certificates.pem");
649
+ await mkdir(certsDir, { recursive: true });
650
+ let shouldCopy = !existsSync4(targetPath);
651
+ if (!shouldCopy) {
652
+ try {
653
+ shouldCopy = statSync3(sourcePath).mtimeMs > statSync3(targetPath).mtimeMs;
654
+ } catch {
655
+ shouldCopy = true;
656
+ }
657
+ }
658
+ if (shouldCopy) {
659
+ copyFileSync2(sourcePath, targetPath);
660
+ }
661
+ return targetPath;
662
+ }
663
+ function applyGitHubCredentialHelperEnv(env) {
664
+ env.GIT_TERMINAL_PROMPT = "0";
665
+ env.GIT_CONFIG_COUNT = "2";
666
+ env.GIT_CONFIG_KEY_0 = "credential.helper";
667
+ env.GIT_CONFIG_VALUE_0 = "";
668
+ env.GIT_CONFIG_KEY_1 = "credential.helper";
669
+ env.GIT_CONFIG_VALUE_1 = '!f() { test "$1" = get || exit 0; token="${GITHUB_TOKEN:-${GH_TOKEN:-${RIG_GITHUB_TOKEN:-}}}"; test -n "$token" || exit 0; echo username=x-access-token; echo password="$token"; }; f';
670
+ }
671
+ var PERSISTED_RUNTIME_SECRET_KEYS = [
672
+ "ANTHROPIC_API_KEY",
673
+ "OPENAI_API_KEY",
674
+ "OPENROUTER_API_KEY",
675
+ "AI_REVIEW_MODE",
676
+ "AI_REVIEW_PROVIDER",
677
+ "GREPTILE_API_BASE",
678
+ "GREPTILE_REMOTE",
679
+ "GREPTILE_REPOSITORY",
680
+ "GREPTILE_CONTEXT_BRANCH",
681
+ "GREPTILE_DEFAULT_BRANCH",
682
+ "GREPTILE_API_KEY",
683
+ "GREPTILE_GITHUB_TOKEN",
684
+ "GREPTILE_POLL_ATTEMPTS",
685
+ "GREPTILE_POLL_INTERVAL_MS",
686
+ "GH_TOKEN",
687
+ "GITHUB_TOKEN",
688
+ "AWS_ACCESS_KEY_ID",
689
+ "AWS_SECRET_ACCESS_KEY",
690
+ "AWS_REGION",
691
+ "LINEAR_API_KEY",
692
+ "LINEAR_WEBHOOK_SECRET",
693
+ "RIG_GITHUB_TOKEN"
694
+ ];
695
+ function persistRuntimeSecrets(runtimeRoot, env) {
696
+ const secretsPath = resolve5(runtimeRoot, "runtime-secrets.json");
697
+ const resolvedSecrets = resolveRuntimeSecrets(env);
698
+ const persisted = {};
699
+ const secretSource = {
700
+ ...resolvedSecrets,
701
+ RIG_GITHUB_TOKEN: env.RIG_GITHUB_TOKEN
702
+ };
703
+ for (const key of PERSISTED_RUNTIME_SECRET_KEYS) {
704
+ const value = secretSource[key]?.trim();
705
+ if (value) {
706
+ persisted[key] = value;
707
+ }
708
+ }
709
+ if (Object.keys(persisted).length === 0) {
710
+ return;
711
+ }
712
+ writeFileSync2(secretsPath, `${JSON.stringify(persisted, null, 2)}
713
+ `, { encoding: "utf-8", mode: 384 });
714
+ chmodSync(secretsPath, 384);
715
+ }
716
+ async function provisionAgentSshKey(homeDir) {
717
+ const sshDir = resolve5(homeDir, ".ssh");
718
+ if (!existsSync4(sshDir)) {
719
+ await mkdir(sshDir, { recursive: true });
720
+ }
721
+ seedKnownHosts(sshDir);
722
+ const secrets = resolveRuntimeSecrets(process.env);
723
+ const privateKey = decodeProvisionedSshKey(secrets.GITHUB_SSH_KEY);
724
+ if (!privateKey) {
725
+ const hostKeyPath = resolveHostSshKeyPath(process.env.HOME ?? "");
726
+ if (!process.env.HOME || !existsSync4(hostKeyPath)) {
727
+ return;
728
+ }
729
+ const agentKeyPath2 = resolve5(sshDir, "rig-agent-key");
730
+ if (!existsSync4(agentKeyPath2)) {
731
+ copyFileSync2(hostKeyPath, agentKeyPath2);
732
+ chmodSync(agentKeyPath2, 384);
733
+ }
734
+ const hostPubPath = `${hostKeyPath}.pub`;
735
+ if (existsSync4(hostPubPath)) {
736
+ const agentPubPath = `${agentKeyPath2}.pub`;
737
+ if (!existsSync4(agentPubPath)) {
738
+ copyFileSync2(hostPubPath, agentPubPath);
739
+ }
740
+ }
741
+ writeSshConfig(sshDir, agentKeyPath2);
742
+ return;
743
+ }
744
+ const agentKeyPath = resolve5(sshDir, "rig-agent-key");
745
+ if (!existsSync4(agentKeyPath)) {
746
+ writeFileSync2(agentKeyPath, privateKey, { mode: 384 });
747
+ }
748
+ writeSshConfig(sshDir, agentKeyPath);
749
+ }
750
+ function decodeProvisionedSshKey(encodedKey) {
751
+ const trimmed = encodedKey?.trim();
752
+ if (!trimmed || trimmed === GITHUB_SSH_KEY_PLACEHOLDER) {
753
+ return null;
754
+ }
755
+ const decoded = Buffer.from(trimmed, "base64").toString("utf-8").trim();
756
+ if (!decoded.includes("PRIVATE KEY")) {
757
+ return null;
758
+ }
759
+ return `${decoded}
760
+ `;
761
+ }
762
+ function resolveHostSshKeyPath(homeDir) {
763
+ const sshDir = resolve5(homeDir, ".ssh");
764
+ const candidates = [
765
+ "rig-agent-key",
766
+ "id_ed25519",
767
+ "id_ecdsa",
768
+ "id_rsa"
769
+ ].map((name) => resolve5(sshDir, name));
770
+ return candidates.find((candidate) => existsSync4(candidate)) ?? resolve5(sshDir, "rig-agent-key");
771
+ }
772
+ function writeSshConfig(sshDir, keyPath) {
773
+ const configPath = resolve5(sshDir, "config");
774
+ if (existsSync4(configPath)) {
775
+ return;
776
+ }
777
+ const knownHostsPath = resolve5(sshDir, "known_hosts");
778
+ const config = [
779
+ "Host github.com",
780
+ ` IdentityFile ${keyPath}`,
781
+ " IdentitiesOnly yes",
782
+ ` UserKnownHostsFile ${knownHostsPath}`,
783
+ " StrictHostKeyChecking yes",
784
+ ""
785
+ ].join(`
786
+ `);
787
+ writeFileSync2(configPath, config, { mode: 420 });
788
+ }
789
+ function seedKnownHosts(sshDir) {
790
+ const knownHostsPath = resolve5(sshDir, "known_hosts");
791
+ const existingLines = readKnownHosts(knownHostsPath);
792
+ const requiredLines = GITHUB_KNOWN_HOSTS.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
793
+ const missing = requiredLines.filter((line) => !existingLines.has(line));
794
+ if (missing.length === 0) {
795
+ return;
796
+ }
797
+ try {
798
+ for (const line of missing) {
799
+ existingLines.add(line);
800
+ }
801
+ writeFileSync2(knownHostsPath, `${Array.from(existingLines).join(`
802
+ `)}
803
+ `, { mode: 420 });
804
+ } catch (err) {
805
+ const hint = existsSync4(knownHostsPath) ? "" : " \u2014 known_hosts is missing; git SSH operations may fail";
806
+ console.warn(`[rig] Could not update ${knownHostsPath}: ${err instanceof Error ? err.message : String(err)}${hint}`);
807
+ }
808
+ }
809
+ function writeClaudeProjectSettings(claudeHomeDir, workspaceDir, runtimeSettings) {
810
+ const projectHash = hashProjectPath(workspaceDir);
811
+ const projectDir = resolve5(claudeHomeDir, "projects", projectHash);
812
+ mkdirSync3(projectDir, { recursive: true });
813
+ writeFileSync2(resolve5(projectDir, "settings.json"), `${JSON.stringify(runtimeSettings, null, 2)}
814
+ `, "utf-8");
815
+ }
816
+ async function loadRuntimeClaudeSettings(projectSettingsPath) {
817
+ if (!existsSync4(projectSettingsPath)) {
818
+ return {};
819
+ }
820
+ let parsed;
821
+ try {
822
+ parsed = await Bun.file(projectSettingsPath).json();
823
+ } catch {
824
+ return {};
825
+ }
826
+ const clone = JSON.parse(JSON.stringify(parsed));
827
+ const hooks = clone.hooks;
828
+ if (!hooks || typeof hooks !== "object") {
829
+ return clone;
830
+ }
831
+ for (const key of ["PreToolUse", "PostToolUse", "SessionStart", "Stop"]) {
832
+ const groups = hooks[key];
833
+ if (!Array.isArray(groups)) {
834
+ continue;
835
+ }
836
+ for (const group of groups) {
837
+ if (!group || typeof group !== "object" || Array.isArray(group)) {
838
+ continue;
839
+ }
840
+ const hookGroup = group;
841
+ if (!Array.isArray(hookGroup.hooks)) {
842
+ continue;
843
+ }
844
+ for (const hook of hookGroup.hooks) {
845
+ if (!hook || hook.type !== "command" || typeof hook.command !== "string") {
846
+ continue;
847
+ }
848
+ const shMatch = hook.command.match(/rig\/hooks\/([a-z0-9-]+)\.sh$/i);
849
+ if (shMatch) {
850
+ hook.command = `.rig/bin/hooks/${shMatch[1]}`;
851
+ continue;
852
+ }
853
+ const splinterMatch = hook.command.match(/\.splinter\/bin\/hooks\/([a-z0-9-]+)$/i);
854
+ if (splinterMatch) {
855
+ hook.command = `.rig/bin/hooks/${splinterMatch[1]}`;
856
+ }
857
+ }
858
+ }
859
+ }
860
+ return clone;
861
+ }
862
+ async function injectClaudeCredentials(claudeHomeDir, options = {}) {
863
+ const credentialsPath = resolve5(claudeHomeDir, ".credentials.json");
864
+ const platform = options.platform ?? process.platform;
865
+ if (platform === "darwin") {
866
+ const raw = options.loadKeychainCredentials ? await options.loadKeychainCredentials() : await (async () => {
867
+ const result = await Bun.$`security find-generic-password -s "Claude Code-credentials" -w`.quiet().nothrow();
868
+ return result.exitCode === 0 ? result.stdout.toString().trim() : "";
869
+ })();
870
+ if (raw) {
871
+ try {
872
+ JSON.parse(raw);
873
+ writeFileSync2(credentialsPath, raw, { mode: 384 });
874
+ registerCredentialCleanup(credentialsPath);
875
+ return true;
876
+ } catch {}
877
+ }
878
+ }
879
+ const hostClaudeHome = options.hostClaudeHome ? resolve5(options.hostClaudeHome) : process.env.CLAUDE_HOME?.trim() ? resolve5(process.env.CLAUDE_HOME) : process.env.HOME ? resolve5(process.env.HOME, ".claude") : "";
880
+ if (hostClaudeHome) {
881
+ const realCredentials = resolve5(hostClaudeHome, ".credentials.json");
882
+ if (existsSync4(realCredentials)) {
883
+ cpSync(realCredentials, credentialsPath);
884
+ return true;
885
+ }
886
+ }
887
+ return false;
888
+ }
889
+ async function injectPiAgentConfig(piAgentDir) {
890
+ mkdirSync3(piAgentDir, { recursive: true });
891
+ const runtimeConfigPath = resolve5(piAgentDir, "config.yml");
892
+ if (!existsSync4(runtimeConfigPath)) {
893
+ writeFileSync2(runtimeConfigPath, `setupVersion: 1000
894
+ startup:
895
+ setupWizard: false
896
+ checkUpdate: false
897
+ `, { mode: 384 });
898
+ }
899
+ const hostPiAgentDir = process.env.PI_CODING_AGENT_DIR?.trim() ? resolve5(process.env.PI_CODING_AGENT_DIR) : process.env.HOME ? resolve5(process.env.HOME, ".pi", "agent") : "";
900
+ if (!hostPiAgentDir) {
901
+ return false;
902
+ }
903
+ const hostAuthPath = resolve5(hostPiAgentDir, "auth.json");
904
+ if (!existsSync4(hostAuthPath)) {
905
+ return false;
906
+ }
907
+ const runtimeAuthPath = resolve5(piAgentDir, "auth.json");
908
+ copyFileSync2(hostAuthPath, runtimeAuthPath);
909
+ chmodSync(runtimeAuthPath, 384);
910
+ const hostSettingsPath = resolve5(hostPiAgentDir, "settings.json");
911
+ if (existsSync4(hostSettingsPath)) {
912
+ const runtimeSettingsPath = resolve5(piAgentDir, "settings.json");
913
+ copyFileSync2(hostSettingsPath, runtimeSettingsPath);
914
+ chmodSync(runtimeSettingsPath, 384);
915
+ }
916
+ return true;
917
+ }
918
+ var __testOnly = {
919
+ injectClaudeCredentials,
920
+ injectPiAgentConfig
921
+ };
922
+ export {
923
+ runtimeEnv,
924
+ runtimeCommandEnv,
925
+ provisionRuntimeHome,
926
+ provisionClaudeHome,
927
+ persistRuntimeSecrets,
928
+ __testOnly
929
+ };