@h-rig/isolation-plugin 0.0.6-alpha.157 → 0.0.6-alpha.159

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,4062 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ function __accessProp(key) {
7
+ return this[key];
8
+ }
9
+ var __toCommonJS = (from) => {
10
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
11
+ if (entry)
12
+ return entry;
13
+ entry = __defProp({}, "__esModule", { value: true });
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (var key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(entry, key))
17
+ __defProp(entry, key, {
18
+ get: __accessProp.bind(from, key),
19
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
+ });
21
+ }
22
+ __moduleCache.set(from, entry);
23
+ return entry;
24
+ };
25
+ var __moduleCache;
26
+ var __returnValue = (v) => v;
27
+ function __exportSetter(name, newValue) {
28
+ this[name] = __returnValue.bind(null, newValue);
29
+ }
30
+ var __export = (target, all) => {
31
+ for (var name in all)
32
+ __defProp(target, name, {
33
+ get: all[name],
34
+ enumerable: true,
35
+ configurable: true,
36
+ set: __exportSetter.bind(all, name)
37
+ });
38
+ };
39
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
40
+ var __require = import.meta.require;
41
+
42
+ // packages/isolation-plugin/src/sandbox/utils.ts
43
+ import { existsSync as existsSync11, readdirSync as readdirSync2, realpathSync } from "fs";
44
+ import { resolve as resolve11 } from "path";
45
+ import { resolveMonorepoRoot as resolveMonorepoRoot2 } from "@rig/core/layout";
46
+ function toRealPath(path) {
47
+ if (!existsSync11(path)) {
48
+ return resolve11(path);
49
+ }
50
+ try {
51
+ return realpathSync.native(path);
52
+ } catch {
53
+ return resolve11(path);
54
+ }
55
+ }
56
+ function resolveHostGitMetadataPaths(projectRoot, workspaceDir) {
57
+ const candidates = new Set;
58
+ const addPath = (candidate) => {
59
+ if (existsSync11(candidate)) {
60
+ candidates.add(toRealPath(candidate));
61
+ }
62
+ };
63
+ addPath(resolve11(projectRoot, ".git"));
64
+ addPath(resolve11(workspaceDir, "..", "..", ".git"));
65
+ for (const repoRoot of resolveHostRepoRootPaths(projectRoot)) {
66
+ addPath(resolve11(repoRoot, ".git"));
67
+ }
68
+ const workspaceGit = resolve11(workspaceDir, ".git");
69
+ if (existsSync11(workspaceGit)) {
70
+ addPath(workspaceGit);
71
+ }
72
+ return [...candidates];
73
+ }
74
+ function resolveHostRepoRootPaths(projectRoot) {
75
+ const candidates = new Set;
76
+ const addPath = (candidate) => {
77
+ if (existsSync11(candidate)) {
78
+ candidates.add(toRealPath(candidate));
79
+ }
80
+ };
81
+ try {
82
+ const monorepoRoot = resolveMonorepoRoot2(projectRoot);
83
+ if (toRealPath(monorepoRoot) !== toRealPath(projectRoot)) {
84
+ addPath(monorepoRoot);
85
+ }
86
+ } catch {}
87
+ const reposDir = resolve11(projectRoot, "repos");
88
+ if (existsSync11(reposDir)) {
89
+ for (const entry of readdirSync2(reposDir, { withFileTypes: true })) {
90
+ if (entry.isDirectory() || entry.isSymbolicLink()) {
91
+ addPath(resolve11(reposDir, entry.name));
92
+ }
93
+ }
94
+ }
95
+ return [...candidates];
96
+ }
97
+ function resolveNetworkWithPolicy(sandboxConfig, envOverride) {
98
+ if (envOverride) {
99
+ const envValue = parseBooleanEnv(envOverride, sandboxConfig.network);
100
+ if (envValue !== sandboxConfig.network) {
101
+ console.warn(`[sandbox] RIG_RUNTIME_SANDBOX_NETWORK=${envOverride} overrides policy sandbox.network=${sandboxConfig.network}`);
102
+ }
103
+ return envValue;
104
+ }
105
+ return sandboxConfig.network;
106
+ }
107
+ function parseBooleanEnv(raw, fallback) {
108
+ if (!raw) {
109
+ return fallback;
110
+ }
111
+ const normalized = raw.trim().toLowerCase();
112
+ if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
113
+ return true;
114
+ }
115
+ if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
116
+ return false;
117
+ }
118
+ return fallback;
119
+ }
120
+ function uniq(values) {
121
+ return [...new Set(values)];
122
+ }
123
+ function seatbeltString(value) {
124
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
125
+ }
126
+ var init_utils = () => {};
127
+
128
+ // packages/isolation-plugin/src/sandbox/backend-seatbelt.ts
129
+ var exports_backend_seatbelt = {};
130
+ __export(exports_backend_seatbelt, {
131
+ SeatbeltBackend: () => SeatbeltBackend
132
+ });
133
+ import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync5 } from "fs";
134
+ import { resolve as resolve12 } from "path";
135
+
136
+ class SeatbeltBackend {
137
+ kind = "macos-seatbelt";
138
+ binaryPath;
139
+ config;
140
+ ctx;
141
+ resolvedPaths;
142
+ constructor(binaryPath, config, ctx, resolvedPaths) {
143
+ this.binaryPath = binaryPath;
144
+ this.config = config;
145
+ this.ctx = ctx;
146
+ this.resolvedPaths = resolvedPaths;
147
+ }
148
+ wrap(options) {
149
+ const profilePath = this.writeSeatbeltProfile(options);
150
+ return {
151
+ command: [this.binaryPath, "-f", profilePath, ...options.command],
152
+ enabled: true,
153
+ backend: "macos-seatbelt",
154
+ profilePath
155
+ };
156
+ }
157
+ writeSeatbeltProfile(options) {
158
+ const sandboxDir = resolve12(options.runtime.rootDir, "sandbox");
159
+ mkdirSync8(sandboxDir, { recursive: true });
160
+ const profilePath = resolve12(sandboxDir, "seatbelt.sb");
161
+ const profile = this.renderProfile(options);
162
+ writeFileSync5(profilePath, `${profile}
163
+ `, "utf-8");
164
+ return profilePath;
165
+ }
166
+ renderProfile(options) {
167
+ const { runtime, projectRoot } = options;
168
+ const { ctx, resolvedPaths, config } = this;
169
+ const workspaceReal = ctx.realPath(runtime.workspaceDir);
170
+ const runtimeRootReal = ctx.realPath(runtime.rootDir);
171
+ const homeReal = ctx.realPath(runtime.homeDir);
172
+ const tmpReal = ctx.realPath(runtime.tmpDir);
173
+ const cacheReal = ctx.realPath(runtime.cacheDir);
174
+ const hostGitDirs = resolveHostGitMetadataPaths(projectRoot, runtime.workspaceDir);
175
+ const hostRepoRoots = resolveHostRepoRootPaths(projectRoot).map((repoRoot) => ctx.realPath(repoRoot));
176
+ const bunDir = ctx.realPath(resolvedPaths.bunDir);
177
+ const claudeDir = resolvedPaths.claudeDir ? ctx.realPath(resolvedPaths.claudeDir) : null;
178
+ const allowNetwork = resolveNetworkWithPolicy(config, process.env.RIG_RUNTIME_SANDBOX_NETWORK);
179
+ const lines = [
180
+ "(version 1)",
181
+ "(deny default)",
182
+ '(import "system.sb")',
183
+ "(allow process*)",
184
+ "(allow process-info*)",
185
+ "(allow signal)",
186
+ "(allow sysctl-read)",
187
+ "(allow file-read-metadata)"
188
+ ];
189
+ if (allowNetwork) {
190
+ lines.push("(allow network*)");
191
+ }
192
+ for (const sysPath of [
193
+ "/usr/lib",
194
+ "/usr/bin",
195
+ "/usr/sbin",
196
+ "/usr/share",
197
+ "/bin",
198
+ "/sbin",
199
+ "/System",
200
+ "/Library",
201
+ "/Library/Frameworks",
202
+ "/Library/Developer",
203
+ "/Library/Apple",
204
+ "/Applications",
205
+ "/private/var/db",
206
+ "/opt/homebrew"
207
+ ]) {
208
+ lines.push(`(allow file-read* (subpath ${seatbeltString(sysPath)}))`);
209
+ }
210
+ lines.push(`(allow file-read* (subpath ${seatbeltString(bunDir)}))`);
211
+ if (claudeDir) {
212
+ lines.push(`(allow file-read* (subpath ${seatbeltString(claudeDir)}))`);
213
+ }
214
+ if (resolvedPaths.nodeDir) {
215
+ lines.push(`(allow file-read* (subpath ${seatbeltString(resolvedPaths.nodeDir)}))`);
216
+ }
217
+ for (const depPath of resolvedPaths.depRoots) {
218
+ lines.push(`(allow file-read* (subpath ${seatbeltString(depPath)}))`);
219
+ }
220
+ for (const rwPath of uniq([
221
+ workspaceReal,
222
+ runtimeRootReal,
223
+ homeReal,
224
+ tmpReal,
225
+ cacheReal
226
+ ])) {
227
+ lines.push(`(allow file-read* (subpath ${seatbeltString(rwPath)}))`);
228
+ lines.push(`(allow file-write* (subpath ${seatbeltString(rwPath)}))`);
229
+ }
230
+ for (const gitPath of hostGitDirs) {
231
+ lines.push(`(allow file-read* (subpath ${seatbeltString(gitPath)}))`);
232
+ lines.push(`(allow file-write* (subpath ${seatbeltString(gitPath)}))`);
233
+ }
234
+ const projectRootReal = ctx.realPath(projectRoot);
235
+ if (projectRootReal !== workspaceReal && !projectRootReal.startsWith(workspaceReal + "/")) {
236
+ lines.push(`(allow file-read* (subpath ${seatbeltString(projectRootReal)}))`);
237
+ }
238
+ for (const repoRoot of hostRepoRoots) {
239
+ if (!ctx.pathExists(repoRoot) || repoRoot === workspaceReal || repoRoot.startsWith(workspaceReal + "/") || repoRoot === projectRootReal || repoRoot.startsWith(projectRootReal + "/")) {
240
+ continue;
241
+ }
242
+ lines.push(`(allow file-read* (subpath ${seatbeltString(repoRoot)}))`);
243
+ }
244
+ const realHome = process.env.HOME?.trim();
245
+ if (realHome) {
246
+ for (const binSubdir of [".local/bin", ".cargo/bin"]) {
247
+ const binPath = resolve12(realHome, binSubdir);
248
+ if (ctx.pathExists(binPath)) {
249
+ lines.push(`(allow file-read* (subpath ${seatbeltString(ctx.realPath(binPath))}))`);
250
+ }
251
+ }
252
+ }
253
+ for (const tempPath of [
254
+ "/dev",
255
+ "/tmp",
256
+ "/private/tmp",
257
+ "/var/folders",
258
+ "/private/var/folders"
259
+ ]) {
260
+ lines.push(`(allow file-read* (subpath ${seatbeltString(tempPath)}))`);
261
+ lines.push(`(allow file-write* (subpath ${seatbeltString(tempPath)}))`);
262
+ }
263
+ return lines.join(`
264
+ `);
265
+ }
266
+ }
267
+ var init_backend_seatbelt = __esm(() => {
268
+ init_utils();
269
+ });
270
+
271
+ // packages/isolation-plugin/src/sandbox/backend-bwrap.ts
272
+ var exports_backend_bwrap = {};
273
+ __export(exports_backend_bwrap, {
274
+ BwrapBackend: () => BwrapBackend
275
+ });
276
+ import { mkdirSync as mkdirSync9 } from "fs";
277
+ import { resolve as resolve13 } from "path";
278
+
279
+ class BwrapBackend {
280
+ kind = "linux-bwrap";
281
+ binaryPath;
282
+ config;
283
+ ctx;
284
+ resolvedPaths;
285
+ which;
286
+ constructor(binaryPath, config, ctx, resolvedPaths, which) {
287
+ this.binaryPath = binaryPath;
288
+ this.config = config;
289
+ this.ctx = ctx;
290
+ this.resolvedPaths = resolvedPaths;
291
+ this.which = which ?? ((bin) => Bun.which(bin));
292
+ }
293
+ wrap(options) {
294
+ const command = this.buildCommand(options);
295
+ return {
296
+ command,
297
+ enabled: true,
298
+ backend: "linux-bwrap"
299
+ };
300
+ }
301
+ buildCommand(options) {
302
+ const { runtime, projectRoot, command } = options;
303
+ const { ctx, resolvedPaths, config } = this;
304
+ const workspaceReal = ctx.realPath(runtime.workspaceDir);
305
+ const runtimeRootReal = ctx.realPath(runtime.rootDir);
306
+ const homeReal = ctx.realPath(runtime.homeDir);
307
+ const tmpReal = ctx.realPath(runtime.tmpDir);
308
+ const cacheReal = ctx.realPath(runtime.cacheDir);
309
+ const hostGitDirs = resolveHostGitMetadataPaths(projectRoot, runtime.workspaceDir);
310
+ const hostRepoRoots = resolveHostRepoRootPaths(projectRoot).map((repoRoot) => ctx.realPath(repoRoot));
311
+ const bunDir = ctx.realPath(resolvedPaths.bunDir);
312
+ const claudeDir = resolvedPaths.claudeDir ? ctx.realPath(resolvedPaths.claudeDir) : null;
313
+ const allowNetwork = resolveNetworkWithPolicy(config, process.env.RIG_RUNTIME_SANDBOX_NETWORK);
314
+ const args = [
315
+ this.binaryPath,
316
+ "--die-with-parent",
317
+ "--new-session",
318
+ "--unshare-pid",
319
+ "--tmpfs",
320
+ "/",
321
+ "--ro-bind",
322
+ "/usr",
323
+ "/usr",
324
+ "--ro-bind",
325
+ "/bin",
326
+ "/bin",
327
+ "--ro-bind",
328
+ "/sbin",
329
+ "/sbin"
330
+ ];
331
+ for (const libPath of ["/lib", "/lib64"]) {
332
+ if (ctx.pathExists(libPath)) {
333
+ args.push("--ro-bind", libPath, libPath);
334
+ }
335
+ }
336
+ for (const etcEntry of [
337
+ "/etc/ld.so.cache",
338
+ "/etc/ld.so.conf",
339
+ "/etc/ld.so.conf.d",
340
+ "/etc/resolv.conf",
341
+ "/etc/hosts",
342
+ "/etc/nsswitch.conf",
343
+ "/etc/gai.conf",
344
+ "/etc/host.conf",
345
+ "/etc/ssl",
346
+ "/etc/ca-certificates",
347
+ "/etc/pki",
348
+ "/etc/passwd",
349
+ "/etc/group",
350
+ "/etc/localtime",
351
+ "/etc/timezone",
352
+ "/etc/locale.conf",
353
+ "/etc/default/locale"
354
+ ]) {
355
+ if (ctx.pathExists(etcEntry)) {
356
+ args.push("--ro-bind", etcEntry, etcEntry);
357
+ }
358
+ }
359
+ if (ctx.pathExists("/run/systemd/resolve")) {
360
+ args.push("--ro-bind", "/run/systemd/resolve", "/run/systemd/resolve");
361
+ }
362
+ if (ctx.pathExists("/run/nscd")) {
363
+ args.push("--ro-bind", "/run/nscd", "/run/nscd");
364
+ }
365
+ args.push("--ro-bind", bunDir, bunDir);
366
+ if (claudeDir) {
367
+ args.push("--ro-bind", claudeDir, claudeDir);
368
+ }
369
+ if (resolvedPaths.nodeDir && ctx.pathExists(resolvedPaths.nodeDir)) {
370
+ args.push("--ro-bind", resolvedPaths.nodeDir, resolvedPaths.nodeDir);
371
+ }
372
+ for (const depPath of resolvedPaths.depRoots) {
373
+ if (ctx.pathExists(depPath)) {
374
+ args.push("--ro-bind", depPath, depPath);
375
+ }
376
+ }
377
+ const projectRootReal = ctx.realPath(projectRoot);
378
+ if (projectRootReal !== workspaceReal && !projectRootReal.startsWith(workspaceReal + "/") && ctx.pathExists(projectRootReal)) {
379
+ args.push("--ro-bind", projectRootReal, projectRootReal);
380
+ }
381
+ for (const repoRoot of hostRepoRoots) {
382
+ if (!ctx.pathExists(repoRoot) || repoRoot === workspaceReal || repoRoot.startsWith(workspaceReal + "/") || repoRoot === projectRootReal || repoRoot.startsWith(projectRootReal + "/")) {
383
+ continue;
384
+ }
385
+ args.push("--ro-bind", repoRoot, repoRoot);
386
+ }
387
+ args.push("--bind", workspaceReal, workspaceReal);
388
+ args.push("--bind", runtimeRootReal, runtimeRootReal);
389
+ for (const rwPath of uniq([homeReal, tmpReal, cacheReal])) {
390
+ if (rwPath !== runtimeRootReal && !rwPath.startsWith(runtimeRootReal + "/")) {
391
+ args.push("--bind", rwPath, rwPath);
392
+ }
393
+ }
394
+ for (const gitPath of hostGitDirs) {
395
+ if (!ctx.pathExists(gitPath))
396
+ continue;
397
+ if (gitPath === runtimeRootReal || gitPath.startsWith(runtimeRootReal + "/"))
398
+ continue;
399
+ if (gitPath === workspaceReal || gitPath.startsWith(workspaceReal + "/"))
400
+ continue;
401
+ args.push("--bind", gitPath, gitPath);
402
+ }
403
+ const realHome = process.env.HOME?.trim();
404
+ if (realHome) {
405
+ for (const binSubdir of [".local/bin", ".local/lib", ".cargo/bin"]) {
406
+ const binPath = ctx.realPath(resolve13(realHome, binSubdir));
407
+ if (ctx.pathExists(binPath)) {
408
+ args.push("--ro-bind", binPath, binPath);
409
+ }
410
+ }
411
+ const agentSshDir = resolve13(homeReal, ".ssh");
412
+ if (ctx.pathExists(agentSshDir)) {
413
+ args.push("--ro-bind", agentSshDir, agentSshDir);
414
+ } else {
415
+ const hostSshDir = resolve13(realHome, ".ssh");
416
+ if (ctx.pathExists(hostSshDir)) {
417
+ mkdirSync9(agentSshDir, { recursive: true });
418
+ args.push("--ro-bind", hostSshDir, agentSshDir);
419
+ args.push("--ro-bind", hostSshDir, hostSshDir);
420
+ }
421
+ }
422
+ }
423
+ args.push("--proc", "/proc");
424
+ args.push("--dev", "/dev");
425
+ args.push("--tmpfs", "/tmp");
426
+ args.push("--unsetenv", "CLAUDECODE");
427
+ args.push("--setenv", "HOME", homeReal);
428
+ args.push("--setenv", "TMPDIR", "/tmp");
429
+ args.push("--chdir", workspaceReal);
430
+ if (!allowNetwork) {
431
+ args.push("--unshare-net");
432
+ }
433
+ args.push("--", ...this.resolveCommandBinary(command));
434
+ return args;
435
+ }
436
+ resolveCommandBinary(command) {
437
+ if (command.length === 0)
438
+ return command;
439
+ const [bin, ...rest] = command;
440
+ if (!bin)
441
+ return command;
442
+ const resolved = this.which(bin);
443
+ if (!resolved)
444
+ return command;
445
+ try {
446
+ const { realpathSync: realpathSync2 } = __require("fs");
447
+ const resolvedBinary = realpathSync2(resolved);
448
+ return [resolvedBinary, ...rest];
449
+ } catch {
450
+ return [resolved, ...rest];
451
+ }
452
+ }
453
+ }
454
+ var init_backend_bwrap = __esm(() => {
455
+ init_utils();
456
+ });
457
+
458
+ // packages/isolation-plugin/src/isolation/index.ts
459
+ import { existsSync as existsSync14, mkdirSync as mkdirSync10, readFileSync as readFileSync7, rmSync as rmSync8 } from "fs";
460
+ import { copyFile, mkdir as mkdir3, writeFile as writeFile2 } from "fs/promises";
461
+ import { resolve as resolve15 } from "path";
462
+ import { BROWSER_CONTRACT_SERVICE_CAPABILITY, MEMORY } from "@rig/contracts";
463
+ import { safePathSegment as safePathSegment3 } from "@rig/core/safe-identifiers";
464
+
465
+ // packages/isolation-plugin/src/isolation/git-native.ts
466
+ import { chmodSync, copyFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
467
+ import { tmpdir as tmpdir2 } from "os";
468
+ import { dirname, isAbsolute, resolve as resolve2 } from "path";
469
+
470
+ // packages/isolation-plugin/src/native-extract.ts
471
+ import { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "fs";
472
+ import { tmpdir } from "os";
473
+ import { resolve } from "path";
474
+
475
+ // packages/isolation-plugin/src/embedded-native-assets.ts
476
+ var embeddedNatives = null;
477
+
478
+ // packages/isolation-plugin/src/native-extract.ts
479
+ var sharedNativeOutputDir = resolve(tmpdir(), "rig-native");
480
+ var extractionCache = {};
481
+ function hasEmbeddedNatives() {
482
+ return embeddedNatives != null;
483
+ }
484
+ function extractEmbeddedNative(name) {
485
+ if (name in extractionCache) {
486
+ return extractionCache[name] ?? null;
487
+ }
488
+ const entry = embeddedNatives?.[name];
489
+ if (!entry) {
490
+ extractionCache[name] = null;
491
+ return null;
492
+ }
493
+ try {
494
+ const targetPath = resolve(sharedNativeOutputDir, entry.fileName);
495
+ mkdirSync(sharedNativeOutputDir, { recursive: true });
496
+ const upToDate = existsSync(targetPath) && statSync(targetPath).size === entry.size;
497
+ if (!upToDate) {
498
+ const bytes = readFileSync(entry.filePath);
499
+ const tempPath = `${targetPath}.${process.pid}.${Date.now()}.tmp`;
500
+ writeFileSync(tempPath, bytes, { mode: 493 });
501
+ renameSync(tempPath, targetPath);
502
+ }
503
+ extractionCache[name] = targetPath;
504
+ } catch {
505
+ extractionCache[name] = null;
506
+ }
507
+ return extractionCache[name] ?? null;
508
+ }
509
+
510
+ // packages/isolation-plugin/src/isolation/git-native.ts
511
+ var sharedGitNativeOutputDir = resolve2(tmpdir2(), "rig-native");
512
+ var sharedGitNativeOutputPath = resolve2(sharedGitNativeOutputDir, `rig-git-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
513
+ var trackerCommandUsageProbe = "usage: rig-git fetch-ref <repo-path> <remote> <branch>";
514
+ function temporaryGitBinaryOutputPath(outputPath) {
515
+ const suffix = process.platform === "win32" ? ".exe" : "";
516
+ return resolve2(dirname(outputPath), `.rig-git-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}${suffix}`);
517
+ }
518
+ function publishGitBinary(tempOutputPath, outputPath) {
519
+ try {
520
+ renameSync2(tempOutputPath, outputPath);
521
+ } catch (error) {
522
+ if (process.platform === "win32" && existsSync2(outputPath)) {
523
+ rmSync(outputPath, { force: true });
524
+ renameSync2(tempOutputPath, outputPath);
525
+ return;
526
+ }
527
+ throw error;
528
+ }
529
+ }
530
+ function isSharedGitNativeOutputPath(outputPath) {
531
+ return resolve2(outputPath) === sharedGitNativeOutputPath;
532
+ }
533
+ async function materializeFromSharedGitBinary(outputPath, buildKey) {
534
+ if (isSharedGitNativeOutputPath(outputPath))
535
+ return null;
536
+ const sharedManifest = nativeBuildManifestPath(sharedGitNativeOutputPath);
537
+ if (!existsSync2(sharedGitNativeOutputPath) || !await hasMatchingNativeBuildManifest(sharedManifest, buildKey) || !binarySupportsTrackerCommandsSync(sharedGitNativeOutputPath)) {
538
+ return null;
539
+ }
540
+ mkdirSync2(dirname(outputPath), { recursive: true });
541
+ copyFileSync(sharedGitNativeOutputPath, outputPath);
542
+ chmodSync(outputPath, 493);
543
+ await Bun.write(nativeBuildManifestPath(outputPath), `${JSON.stringify({ version: 1, buildKey }, null, 2)}
544
+ `);
545
+ return outputPath;
546
+ }
547
+ function runtimeRigGitFileName() {
548
+ return `rig-git${process.platform === "win32" ? ".exe" : ""}`;
549
+ }
550
+ function rigGitSourceCandidates() {
551
+ const execDir = process.execPath?.trim() ? dirname(process.execPath.trim()) : "";
552
+ const cwd = process.cwd()?.trim() || "";
553
+ const projectRoot = process.env.PROJECT_RIG_ROOT?.trim() || "";
554
+ const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || "";
555
+ const moduleRelativeSource = resolve2(import.meta.dir, "../../native/rig-git.zig");
556
+ return [...new Set([
557
+ process.env.RIG_NATIVE_GIT_SOURCE?.trim() || "",
558
+ moduleRelativeSource,
559
+ projectRoot ? resolve2(projectRoot, "packages/isolation-plugin/native/rig-git.zig") : "",
560
+ hostProjectRoot ? resolve2(hostProjectRoot, "packages/isolation-plugin/native/rig-git.zig") : "",
561
+ cwd ? resolve2(cwd, "packages/isolation-plugin/native/rig-git.zig") : "",
562
+ execDir ? resolve2(execDir, "..", "..", "packages/isolation-plugin/native/rig-git.zig") : "",
563
+ execDir ? resolve2(execDir, "..", "native", "rig-git.zig") : ""
564
+ ].filter(Boolean))];
565
+ }
566
+ function nativePackageBinaryCandidates(fromDir, fileName) {
567
+ const candidates = [];
568
+ let cursor = resolve2(fromDir);
569
+ for (let index = 0;index < 8; index += 1) {
570
+ candidates.push(resolve2(cursor, "native", `${process.platform}-${process.arch}`, fileName), resolve2(cursor, "native", `${process.platform}-${process.arch}`, "bin", fileName), resolve2(cursor, "native", fileName), resolve2(cursor, "native", "bin", fileName));
571
+ const parent = dirname(cursor);
572
+ if (parent === cursor)
573
+ break;
574
+ cursor = parent;
575
+ }
576
+ return candidates;
577
+ }
578
+ function rigGitBinaryCandidates() {
579
+ const execDir = process.execPath?.trim() ? dirname(process.execPath.trim()) : "";
580
+ const fileName = runtimeRigGitFileName();
581
+ const explicit = process.env.RIG_NATIVE_GIT_BIN?.trim() || "";
582
+ return [...new Set([
583
+ explicit,
584
+ ...nativePackageBinaryCandidates(import.meta.dir, fileName),
585
+ execDir ? resolve2(execDir, fileName) : "",
586
+ execDir ? resolve2(execDir, "..", fileName) : "",
587
+ execDir ? resolve2(execDir, "..", "bin", fileName) : "",
588
+ sharedGitNativeOutputPath
589
+ ].filter(Boolean))];
590
+ }
591
+ function resolveGitSourcePath() {
592
+ for (const candidate of rigGitSourceCandidates()) {
593
+ if (candidate && existsSync2(candidate)) {
594
+ return candidate;
595
+ }
596
+ }
597
+ return null;
598
+ }
599
+ function resolveGitBinaryPath() {
600
+ if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
601
+ return null;
602
+ }
603
+ for (const candidate of rigGitBinaryCandidates()) {
604
+ if (candidate && existsSync2(candidate)) {
605
+ return candidate;
606
+ }
607
+ }
608
+ return null;
609
+ }
610
+ function binarySupportsTrackerCommandsSync(binaryPath) {
611
+ try {
612
+ const probe = Bun.spawnSync([binaryPath, "fetch-ref", "."], {
613
+ stdout: "pipe",
614
+ stderr: "pipe"
615
+ });
616
+ const stdout = probe.stdout.toString().trim();
617
+ const stderr = probe.stderr.toString().trim();
618
+ if (stdout.includes('"error":"unknown command"')) {
619
+ return false;
620
+ }
621
+ return probe.exitCode === 2 && stderr.includes(trackerCommandUsageProbe);
622
+ } catch {
623
+ return false;
624
+ }
625
+ }
626
+ function nativeBuildManifestPath(outputPath) {
627
+ return `${outputPath}.build-manifest.json`;
628
+ }
629
+ async function hasMatchingNativeBuildManifest(manifestPath, buildKey) {
630
+ if (!existsSync2(manifestPath)) {
631
+ return false;
632
+ }
633
+ try {
634
+ const manifest = await Bun.file(manifestPath).json();
635
+ return manifest.version === 1 && manifest.buildKey === buildKey;
636
+ } catch {
637
+ return false;
638
+ }
639
+ }
640
+ async function sha256File(path) {
641
+ const hasher = new Bun.CryptoHasher("sha256");
642
+ hasher.update(await Bun.file(path).arrayBuffer());
643
+ return hasher.digest("hex");
644
+ }
645
+ async function ensureRigGitBinaryPath(outputPath = sharedGitNativeOutputPath) {
646
+ if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
647
+ throw new Error("Zig native git is disabled via RIG_DISABLE_ZIG_NATIVE=1");
648
+ }
649
+ const explicitBin = process.env.RIG_NATIVE_GIT_BIN?.trim();
650
+ if (explicitBin && existsSync2(explicitBin)) {
651
+ return explicitBin;
652
+ }
653
+ const embedded = extractEmbeddedNative("rig-git");
654
+ if (embedded) {
655
+ return embedded;
656
+ }
657
+ const sourcePath = resolveGitSourcePath();
658
+ if (!sourcePath) {
659
+ const binaryPath = resolveGitBinaryPath();
660
+ if (binaryPath) {
661
+ return binaryPath;
662
+ }
663
+ throw new Error("rig-git.zig source file not found.");
664
+ }
665
+ const zigBinary = Bun.which("zig");
666
+ if (!zigBinary) {
667
+ throw new Error("zig is required to build native Rig git tools.");
668
+ }
669
+ mkdirSync2(dirname(outputPath), { recursive: true });
670
+ const sourceDigest = await sha256File(sourcePath);
671
+ const buildKey = JSON.stringify({
672
+ version: 1,
673
+ zigBinary,
674
+ platform: process.platform,
675
+ arch: process.arch,
676
+ sourcePath,
677
+ sourceDigest
678
+ });
679
+ const manifestPath = nativeBuildManifestPath(outputPath);
680
+ const needsBuild = !existsSync2(outputPath) || !await hasMatchingNativeBuildManifest(manifestPath, buildKey) || !binarySupportsTrackerCommandsSync(outputPath);
681
+ if (!needsBuild) {
682
+ chmodSync(outputPath, 493);
683
+ return outputPath;
684
+ }
685
+ const materialized = await materializeFromSharedGitBinary(outputPath, buildKey);
686
+ if (materialized)
687
+ return materialized;
688
+ const tempOutputPath = temporaryGitBinaryOutputPath(outputPath);
689
+ const build = Bun.spawn([
690
+ zigBinary,
691
+ "build-exe",
692
+ sourcePath,
693
+ "-O",
694
+ "ReleaseFast",
695
+ `-femit-bin=${tempOutputPath}`
696
+ ], {
697
+ cwd: dirname(sourcePath),
698
+ stdout: "pipe",
699
+ stderr: "pipe"
700
+ });
701
+ const [exitCode, stdout, stderr] = await Promise.all([
702
+ build.exited,
703
+ new Response(build.stdout).text(),
704
+ new Response(build.stderr).text()
705
+ ]);
706
+ if (exitCode !== 0 || !existsSync2(tempOutputPath)) {
707
+ const details = [stderr.trim(), stdout.trim()].filter(Boolean).join(`
708
+ `);
709
+ throw new Error(`Failed to build native Rig git tools: ${details || `zig exited with code ${exitCode}`}`);
710
+ }
711
+ chmodSync(tempOutputPath, 493);
712
+ if (existsSync2(outputPath) && await hasMatchingNativeBuildManifest(manifestPath, buildKey)) {
713
+ rmSync(tempOutputPath, { force: true });
714
+ chmodSync(outputPath, 493);
715
+ return outputPath;
716
+ }
717
+ publishGitBinary(tempOutputPath, outputPath);
718
+ if (!binarySupportsTrackerCommandsSync(outputPath)) {
719
+ rmSync(outputPath, { force: true });
720
+ throw new Error("Failed to build native Rig git tools: tracker command probe failed");
721
+ }
722
+ await Bun.write(manifestPath, `${JSON.stringify({ version: 1, buildKey }, null, 2)}
723
+ `);
724
+ return outputPath;
725
+ }
726
+ async function materializeRigGitBinary(targetDir) {
727
+ const sourcePath = await ensureRigGitBinaryPath();
728
+ const targetPath = resolve2(targetDir, runtimeRigGitFileName());
729
+ mkdirSync2(targetDir, { recursive: true });
730
+ const sourceDigest = await sha256File(sourcePath);
731
+ const buildKey = JSON.stringify({
732
+ version: 1,
733
+ sourcePath,
734
+ sourceDigest
735
+ });
736
+ const needsCopy = !existsSync2(targetPath) || !await hasMatchingNativeBuildManifest(nativeBuildManifestPath(targetPath), buildKey);
737
+ if (needsCopy) {
738
+ copyFileSync(sourcePath, targetPath);
739
+ chmodSync(targetPath, 493);
740
+ await Bun.write(nativeBuildManifestPath(targetPath), `${JSON.stringify({ version: 1, buildKey }, null, 2)}
741
+ `);
742
+ }
743
+ return targetPath;
744
+ }
745
+
746
+ // packages/isolation-plugin/src/isolation/index.ts
747
+ import { defineCapability as defineCapability2 } from "@rig/core/capability";
748
+ import { loadCapabilityForRoot, requireCapabilityForRoot, requireInstalledCapability as requireInstalledCapability2 } from "@rig/core/capability-loaders";
749
+ import { buildPluginHostContext } from "@rig/core/plugin-host-context";
750
+ import { TASK_DATA_SERVICE_CAPABILITY } from "@rig/contracts";
751
+ import { resolveRuntimeWorkspaceLayout as resolveRuntimeWorkspaceLayout3 } from "@rig/core/layout";
752
+ import { ensureRuntimeOverlay } from "@rig/core/runtime-overlay";
753
+ import {
754
+ DEFAULT_RUNTIME_MEMORY_RETRIEVAL,
755
+ writeRuntimeContext
756
+ } from "@rig/core/runtime-context";
757
+ import { secretDefinesFromEnv } from "@rig/core/baked-secrets";
758
+
759
+ // packages/isolation-plugin/src/isolation/home.ts
760
+ import {
761
+ chmodSync as chmodSync2,
762
+ copyFileSync as copyFileSync3,
763
+ cpSync,
764
+ existsSync as existsSync5,
765
+ mkdirSync as mkdirSync4,
766
+ readFileSync as readFileSync4,
767
+ statSync as statSync3,
768
+ writeFileSync as writeFileSync3
769
+ } from "fs";
770
+ import { mkdir } from "fs/promises";
771
+ import { basename, delimiter, resolve as resolve5 } from "path";
772
+ import { resolveBunBinaryPath, resolveBunInstallDir, resolveClaudeBinaryPath, resolveClaudeInstallDir, resolveNodeInstallDir } from "@rig/core/runtime-paths";
773
+ import { resolveRuntimeSecrets } from "@rig/core/baked-secrets";
774
+
775
+ // packages/isolation-plugin/src/runtime-native.ts
776
+ import { dlopen, ptr, suffix, toBuffer } from "bun:ffi";
777
+ import { copyFileSync as copyFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync3, renameSync as renameSync3, rmSync as rmSync2, statSync as statSync2 } from "fs";
778
+ import { tmpdir as tmpdir3 } from "os";
779
+ import { dirname as dirname2, resolve as resolve3 } from "path";
780
+
781
+ // packages/isolation-plugin/src/sidecar-arg.ts
782
+ var RIG_NATIVE_RUNTIME_SIDECAR_ARG = "__rig_native_runtime_sidecar";
783
+
784
+ // packages/isolation-plugin/src/runtime-native.ts
785
+ var sharedNativeRuntimeOutputDir = resolve3(tmpdir3(), "rig-native");
786
+ var sharedNativeRuntimeOutputPath = resolve3(sharedNativeRuntimeOutputDir, `runtime-native-${process.platform}-${process.arch}.${suffix}`);
787
+ var colocatedNativeRuntimeFileName = `runtime-native.${suffix}`;
788
+ var nativeRuntimeLibrary = await loadNativeRuntimeLibrary();
789
+ function runtimePrepareTrackedPathsNative(input) {
790
+ const response = runNativeRuntimeSidecar({
791
+ op: "prepare-paths",
792
+ input
793
+ });
794
+ if (!response.ok) {
795
+ throw new Error(response.error);
796
+ }
797
+ }
798
+ function runtimeLinkDependencyLayerNative(sourceDir, targetDir) {
799
+ const response = runNativeRuntimeSidecar({
800
+ op: "link-dependency-layer",
801
+ input: { sourceDir, targetDir }
802
+ });
803
+ if (!response.ok) {
804
+ throw new Error(response.error);
805
+ }
806
+ }
807
+ function runtimeScanWorktreesNative(worktreesRoot) {
808
+ const response = runNativeRuntimeSidecar({
809
+ op: "scan-worktrees",
810
+ input: { worktreesRoot }
811
+ });
812
+ if (!response.ok) {
813
+ throw new Error(response.error);
814
+ }
815
+ return response.entries ?? [];
816
+ }
817
+ async function ensureNativeRuntimeLibraryPath(outputPath = sharedNativeRuntimeOutputPath, options = {}) {
818
+ const explicitLib = process.env.RIG_NATIVE_RUNTIME_LIB?.trim();
819
+ if (explicitLib && existsSync3(explicitLib)) {
820
+ return explicitLib;
821
+ }
822
+ const embeddedPath = extractEmbeddedNative("snapshot");
823
+ if (embeddedPath) {
824
+ return embeddedPath;
825
+ }
826
+ if (await buildNativeRuntimeLibrary(outputPath, options)) {
827
+ return outputPath;
828
+ }
829
+ return !options.force && existsSync3(outputPath) ? outputPath : null;
830
+ }
831
+ async function materializeNativeRuntimeLibrary(targetDir) {
832
+ const sourcePath = await ensureNativeRuntimeLibraryPath();
833
+ if (!sourcePath) {
834
+ return null;
835
+ }
836
+ const targetPath = resolve3(targetDir, colocatedNativeRuntimeFileName);
837
+ mkdirSync3(targetDir, { recursive: true });
838
+ const needsCopy = !existsSync3(targetPath) || statSync2(sourcePath).mtimeMs > statSync2(targetPath).mtimeMs;
839
+ if (needsCopy) {
840
+ copyFileSync2(sourcePath, targetPath);
841
+ }
842
+ return targetPath;
843
+ }
844
+ async function loadNativeRuntimeLibrary() {
845
+ if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
846
+ return null;
847
+ }
848
+ const explicitLib = process.env.RIG_NATIVE_RUNTIME_LIB?.trim();
849
+ if (explicitLib && existsSync3(explicitLib)) {
850
+ const loaded = tryDlopenNativeRuntimeLibrary(explicitLib);
851
+ if (loaded) {
852
+ return loaded;
853
+ }
854
+ }
855
+ const embeddedPath = extractEmbeddedNative("snapshot");
856
+ if (embeddedPath) {
857
+ const loaded = tryDlopenNativeRuntimeLibrary(embeddedPath);
858
+ if (loaded) {
859
+ return loaded;
860
+ }
861
+ }
862
+ for (const candidate of nativeRuntimeLibraryCandidates()) {
863
+ if (!candidate || !existsSync3(candidate)) {
864
+ continue;
865
+ }
866
+ const loaded = tryDlopenNativeRuntimeLibrary(candidate);
867
+ if (loaded) {
868
+ return loaded;
869
+ }
870
+ }
871
+ const builtLibraryPath = await ensureNativeRuntimeLibraryPath(sharedNativeRuntimeOutputPath, { force: true });
872
+ if (!builtLibraryPath) {
873
+ return null;
874
+ }
875
+ return tryDlopenNativeRuntimeLibrary(builtLibraryPath);
876
+ }
877
+ function nativePackageLibraryCandidates(fromDir, names) {
878
+ const candidates = [];
879
+ let cursor = resolve3(fromDir);
880
+ for (let index = 0;index < 8; index += 1) {
881
+ for (const name of names) {
882
+ candidates.push(resolve3(cursor, "native", `${process.platform}-${process.arch}`, name), resolve3(cursor, "native", `${process.platform}-${process.arch}`, "lib", name), resolve3(cursor, "native", name), resolve3(cursor, "native", "lib", name));
883
+ }
884
+ const parent = dirname2(cursor);
885
+ if (parent === cursor)
886
+ break;
887
+ cursor = parent;
888
+ }
889
+ return candidates;
890
+ }
891
+ function nativeRuntimeLibraryCandidates() {
892
+ const explicit = process.env.RIG_NATIVE_RUNTIME_LIB?.trim() || "";
893
+ const execDir = process.execPath?.trim() ? dirname2(process.execPath.trim()) : "";
894
+ const platformSpecific = `runtime-native-${process.platform}-${process.arch}.${suffix}`;
895
+ return [...new Set([
896
+ explicit,
897
+ ...nativePackageLibraryCandidates(import.meta.dir, [colocatedNativeRuntimeFileName, platformSpecific]),
898
+ execDir ? resolve3(execDir, colocatedNativeRuntimeFileName) : "",
899
+ execDir ? resolve3(execDir, platformSpecific) : "",
900
+ execDir ? resolve3(execDir, "..", colocatedNativeRuntimeFileName) : "",
901
+ execDir ? resolve3(execDir, "..", platformSpecific) : "",
902
+ execDir ? resolve3(execDir, "lib", colocatedNativeRuntimeFileName) : "",
903
+ execDir ? resolve3(execDir, "..", "lib", colocatedNativeRuntimeFileName) : "",
904
+ sharedNativeRuntimeOutputPath
905
+ ].filter(Boolean))];
906
+ }
907
+ function resolveNativeRuntimeSourcePath() {
908
+ const explicit = process.env.RIG_NATIVE_RUNTIME_SOURCE?.trim();
909
+ if (explicit && existsSync3(explicit)) {
910
+ return explicit;
911
+ }
912
+ const bundled = resolve3(import.meta.dir, "../native/snapshot.zig");
913
+ return existsSync3(bundled) ? bundled : null;
914
+ }
915
+ function resolveNativeRuntimeSidecarSourcePath() {
916
+ const envRoots = [
917
+ process.cwd()?.trim(),
918
+ process.env.RIG_HOST_PROJECT_ROOT?.trim(),
919
+ process.env.PROJECT_RIG_ROOT?.trim()
920
+ ].filter(Boolean);
921
+ for (const root of envRoots) {
922
+ for (const relative of [
923
+ "packages/isolation-plugin/src/runtime-native-sidecar.ts",
924
+ "packages/isolation-plugin/dist/src/runtime-native-sidecar.js"
925
+ ]) {
926
+ const candidate = resolve3(root, relative);
927
+ if (existsSync3(candidate)) {
928
+ return candidate;
929
+ }
930
+ }
931
+ }
932
+ for (const localCandidate of [
933
+ resolve3(import.meta.dir, "runtime-native-sidecar.js"),
934
+ resolve3(import.meta.dir, "runtime-native-sidecar.ts")
935
+ ]) {
936
+ if (existsSync3(localCandidate))
937
+ return localCandidate;
938
+ }
939
+ return null;
940
+ }
941
+ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
942
+ if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
943
+ return false;
944
+ }
945
+ const zigBinary = Bun.which("zig");
946
+ const sourcePath = resolveNativeRuntimeSourcePath();
947
+ if (!zigBinary || !sourcePath) {
948
+ return false;
949
+ }
950
+ const tempOutputPath = `${outputPath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
951
+ try {
952
+ mkdirSync3(dirname2(outputPath), { recursive: true });
953
+ const needsBuild = options.force === true || !existsSync3(outputPath) || statSync2(sourcePath).mtimeMs > statSync2(outputPath).mtimeMs;
954
+ if (!needsBuild) {
955
+ return true;
956
+ }
957
+ const build = Bun.spawn([
958
+ zigBinary,
959
+ "build-lib",
960
+ sourcePath,
961
+ "-dynamic",
962
+ "-O",
963
+ "ReleaseFast",
964
+ `-femit-bin=${tempOutputPath}`
965
+ ], {
966
+ cwd: import.meta.dir,
967
+ stdout: "pipe",
968
+ stderr: "pipe"
969
+ });
970
+ const exitCode = await build.exited;
971
+ if (exitCode !== 0 || !existsSync3(tempOutputPath)) {
972
+ rmSync2(tempOutputPath, { force: true });
973
+ return false;
974
+ }
975
+ renameSync3(tempOutputPath, outputPath);
976
+ return true;
977
+ } catch {
978
+ rmSync2(tempOutputPath, { force: true });
979
+ return false;
980
+ }
981
+ }
982
+ function tryDlopenNativeRuntimeLibrary(outputPath) {
983
+ try {
984
+ return dlopen(outputPath, {
985
+ rig_scope_match: {
986
+ args: ["ptr", "ptr"],
987
+ returns: "u8"
988
+ },
989
+ snapshot_capture: {
990
+ args: ["ptr", "u64", "ptr", "u64"],
991
+ returns: "ptr"
992
+ },
993
+ snapshot_delta: {
994
+ args: ["ptr", "ptr"],
995
+ returns: "ptr"
996
+ },
997
+ snapshot_store_delta: {
998
+ args: ["ptr", "ptr", "ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64"],
999
+ returns: "ptr"
1000
+ },
1001
+ snapshot_inspect_delta: {
1002
+ args: ["ptr", "u64"],
1003
+ returns: "ptr"
1004
+ },
1005
+ snapshot_apply_delta: {
1006
+ args: ["ptr", "u64", "ptr", "u64"],
1007
+ returns: "ptr"
1008
+ },
1009
+ snapshot_release: {
1010
+ args: ["ptr"],
1011
+ returns: "void"
1012
+ },
1013
+ runtime_hash_file: {
1014
+ args: ["ptr", "u64"],
1015
+ returns: "ptr"
1016
+ },
1017
+ runtime_hash_tree: {
1018
+ args: ["ptr", "u64"],
1019
+ returns: "ptr"
1020
+ },
1021
+ runtime_prepare_paths: {
1022
+ args: ["ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64"],
1023
+ returns: "ptr"
1024
+ },
1025
+ runtime_link_dependency_layer: {
1026
+ args: ["ptr", "u64", "ptr", "u64"],
1027
+ returns: "ptr"
1028
+ },
1029
+ runtime_scan_worktrees: {
1030
+ args: ["ptr", "u64"],
1031
+ returns: "ptr"
1032
+ }
1033
+ });
1034
+ } catch {
1035
+ return null;
1036
+ }
1037
+ }
1038
+ function resolveNativeRuntimeSidecarCommand(request) {
1039
+ if (hasEmbeddedNatives()) {
1040
+ return {
1041
+ argv: [process.execPath, RIG_NATIVE_RUNTIME_SIDECAR_ARG, JSON.stringify(request)],
1042
+ env: {}
1043
+ };
1044
+ }
1045
+ const hostBinary = process.env.RIG_NATIVE_HOST_BINARY?.trim();
1046
+ if (hostBinary) {
1047
+ return {
1048
+ argv: [hostBinary, RIG_NATIVE_RUNTIME_SIDECAR_ARG, JSON.stringify(request)],
1049
+ env: {}
1050
+ };
1051
+ }
1052
+ const sidecarSourcePath = resolveNativeRuntimeSidecarSourcePath();
1053
+ if (!sidecarSourcePath) {
1054
+ throw new Error("runtime-native-sidecar.ts source file not found.");
1055
+ }
1056
+ const bunCli = resolveNativeRuntimeSidecarInvocation();
1057
+ return {
1058
+ argv: [bunCli.command, sidecarSourcePath, JSON.stringify(request)],
1059
+ env: bunCli.env
1060
+ };
1061
+ }
1062
+ function runNativeRuntimeSidecar(request) {
1063
+ const { argv, env } = resolveNativeRuntimeSidecarCommand(request);
1064
+ const proc = Bun.spawnSync(argv, {
1065
+ cwd: process.env.RIG_HOST_PROJECT_ROOT?.trim() || process.cwd(),
1066
+ stdout: "pipe",
1067
+ stderr: "pipe",
1068
+ env: {
1069
+ ...process.env,
1070
+ ...env,
1071
+ RIG_NATIVE_RUNTIME_SIDECAR: "1"
1072
+ }
1073
+ });
1074
+ if (proc.exitCode !== 0) {
1075
+ throw new Error(proc.stderr.toString() || proc.stdout.toString() || `runtime native sidecar exited ${proc.exitCode}`);
1076
+ }
1077
+ const stdout = proc.stdout.toString().trim();
1078
+ if (!stdout) {
1079
+ throw new Error("runtime native sidecar returned empty output.");
1080
+ }
1081
+ const responseLine = stdout.split(`
1082
+ `).map((line) => line.trim()).filter((line) => line.startsWith("{")).at(-1);
1083
+ if (!responseLine) {
1084
+ throw new Error(`runtime native sidecar returned no JSON response: ${stdout}`);
1085
+ }
1086
+ return JSON.parse(responseLine);
1087
+ }
1088
+ function resolveNativeRuntimeSidecarInvocation() {
1089
+ const bunPath = Bun.which("bun");
1090
+ if (bunPath) {
1091
+ return { command: bunPath, env: {} };
1092
+ }
1093
+ if (process.execPath?.trim()) {
1094
+ return {
1095
+ command: process.execPath,
1096
+ env: { BUN_BE_BUN: "1" }
1097
+ };
1098
+ }
1099
+ throw new Error("bun is required to run the runtime native sidecar.");
1100
+ }
1101
+
1102
+ // packages/isolation-plugin/src/isolation/home.ts
1103
+ import { browserEnvFromContext, loadRuntimeContext, runtimeMemoryEnvFromContext, RUNTIME_CONTEXT_ENV } from "@rig/core/runtime-context";
1104
+
1105
+ // packages/isolation-plugin/src/isolation/shared.ts
1106
+ import { existsSync as existsSync4, readFileSync as readFileSync3, rmSync as rmSync3 } from "fs";
1107
+ import { resolve as resolve4 } from "path";
1108
+ import { agentId, safeGitRefComponent, taskRuntimeId } from "@rig/core/safe-identifiers";
1109
+ import { resolveCheckoutRoot } from "@rig/core/checkout-root";
1110
+ function isRuntimeGatewayGitPath(candidate) {
1111
+ return /\/\.rig\/bin\/git$/.test(candidate.replace(/\\/g, "/"));
1112
+ }
1113
+ function isRuntimeGatewayGhPath(candidate) {
1114
+ return /\/\.rig\/bin\/gh$/.test(candidate.replace(/\\/g, "/"));
1115
+ }
1116
+ function resolveHostGitBinary() {
1117
+ const candidates = [
1118
+ process.env.RIG_GIT_BIN?.trim() || "",
1119
+ "/usr/bin/git",
1120
+ "/opt/homebrew/bin/git",
1121
+ "/usr/local/bin/git"
1122
+ ];
1123
+ const bunResolved = Bun.which("git");
1124
+ if (bunResolved && !isRuntimeGatewayGitPath(bunResolved)) {
1125
+ candidates.push(bunResolved);
1126
+ }
1127
+ for (const candidate of candidates) {
1128
+ if (candidate && !isRuntimeGatewayGitPath(candidate) && existsSync4(candidate)) {
1129
+ return candidate;
1130
+ }
1131
+ }
1132
+ return "git";
1133
+ }
1134
+ function resolveGithubCliBinary(options = {}) {
1135
+ const candidates = new Set;
1136
+ const explicit = process.env.RIG_GH_BIN?.trim();
1137
+ if (explicit) {
1138
+ candidates.add(explicit);
1139
+ }
1140
+ for (const candidate of ["/usr/bin/gh", "/opt/homebrew/bin/gh", "/usr/local/bin/gh"]) {
1141
+ candidates.add(candidate);
1142
+ }
1143
+ if (options.scanPath) {
1144
+ for (const entry of (process.env.PATH || "").split(":").map((value) => value.trim()).filter(Boolean)) {
1145
+ candidates.add(resolve4(entry, "gh"));
1146
+ }
1147
+ }
1148
+ const bunResolved = Bun.which("gh");
1149
+ if (bunResolved) {
1150
+ candidates.add(bunResolved);
1151
+ }
1152
+ for (const candidate of candidates) {
1153
+ if (candidate && existsSync4(candidate) && !isRuntimeGatewayGhPath(candidate)) {
1154
+ return candidate;
1155
+ }
1156
+ }
1157
+ return "";
1158
+ }
1159
+ var generatedCredentialFiles = new Set;
1160
+ var credentialCleanupRegistered = false;
1161
+ function resolveMonorepoRoot(projectRoot) {
1162
+ return resolveCheckoutRoot(projectRoot);
1163
+ }
1164
+ async function runGitCommand(repoRoot, args) {
1165
+ const gitBinary = resolveHostGitBinary();
1166
+ return Bun.$`${gitBinary} -C ${repoRoot} ${args}`.quiet().nothrow();
1167
+ }
1168
+ async function readGitConfigValue(repoRoot, key, global = false) {
1169
+ const args = ["config", ...global ? ["--global"] : [], "--get", key];
1170
+ const result = await runGitCommand(repoRoot, args);
1171
+ if (result.exitCode !== 0) {
1172
+ return "";
1173
+ }
1174
+ return String(result.stdout).trim();
1175
+ }
1176
+ async function readGitStdout(repoRoot, args) {
1177
+ const result = await runGitCommand(repoRoot, args);
1178
+ if (result.exitCode !== 0) {
1179
+ throw new Error(`git -C ${repoRoot} ${args.join(" ")} failed: ${result.stderr || result.stdout}`);
1180
+ }
1181
+ return String(result.stdout).trim();
1182
+ }
1183
+ async function hasGitRemote(repoRoot, remote) {
1184
+ const result = await runGitCommand(repoRoot, ["remote", "get-url", remote]);
1185
+ return result.exitCode === 0;
1186
+ }
1187
+ async function ensureFullGitHistory(repoRoot) {
1188
+ const shallow = await runGitCommand(repoRoot, ["rev-parse", "--is-shallow-repository"]);
1189
+ if (shallow.exitCode !== 0 || String(shallow.stdout).trim() !== "true") {
1190
+ return;
1191
+ }
1192
+ const unshallow = await runGitCommand(repoRoot, ["fetch", "--unshallow", "--tags", "origin"]);
1193
+ if (unshallow.exitCode === 0) {
1194
+ return;
1195
+ }
1196
+ const output = `${unshallow.stderr}
1197
+ ${unshallow.stdout}`.trim();
1198
+ if (/--unshallow on a complete repository|does not make sense/i.test(output)) {
1199
+ return;
1200
+ }
1201
+ throw new Error(`Failed to expand git history for ${repoRoot}: ${output}`);
1202
+ }
1203
+ async function refreshRemoteBranch(repoRoot, remote, branch) {
1204
+ if (!await hasGitRemote(repoRoot, remote)) {
1205
+ return;
1206
+ }
1207
+ try {
1208
+ await ensureFullGitHistory(repoRoot);
1209
+ const fetch = await runGitCommand(repoRoot, [
1210
+ "fetch",
1211
+ "--prune",
1212
+ "--tags",
1213
+ remote,
1214
+ `+refs/heads/${branch}:refs/remotes/${remote}/${branch}`
1215
+ ]);
1216
+ if (fetch.exitCode !== 0) {
1217
+ return;
1218
+ }
1219
+ } catch {
1220
+ return;
1221
+ }
1222
+ }
1223
+ async function tryReadGitHead(repoRoot) {
1224
+ if (!existsSync4(resolve4(repoRoot, ".git"))) {
1225
+ return;
1226
+ }
1227
+ const result = await runGitCommand(repoRoot, ["rev-parse", "HEAD"]);
1228
+ if (result.exitCode !== 0) {
1229
+ return;
1230
+ }
1231
+ const value = String(result.stdout).trim();
1232
+ return value || undefined;
1233
+ }
1234
+ async function captureRepoDirtyFiles(repoRoot) {
1235
+ if (!existsSync4(resolve4(repoRoot, ".git"))) {
1236
+ return [];
1237
+ }
1238
+ const files = new Set;
1239
+ for (const args of [
1240
+ ["diff", "--name-only"],
1241
+ ["diff", "--cached", "--name-only"],
1242
+ ["ls-files", "--others", "--exclude-standard"]
1243
+ ]) {
1244
+ const result = await runGitCommand(repoRoot, args);
1245
+ if (result.exitCode !== 0) {
1246
+ continue;
1247
+ }
1248
+ for (const line of String(result.stdout).split(/\r?\n/)) {
1249
+ const trimmed = line.trim();
1250
+ if (trimmed) {
1251
+ files.add(trimmed);
1252
+ }
1253
+ }
1254
+ }
1255
+ return [...files].sort();
1256
+ }
1257
+ function sha256Hex(input) {
1258
+ const hasher = new Bun.CryptoHasher("sha256");
1259
+ hasher.update(input);
1260
+ return hasher.digest("hex");
1261
+ }
1262
+ function registerCredentialCleanup(path) {
1263
+ generatedCredentialFiles.add(path);
1264
+ if (credentialCleanupRegistered) {
1265
+ return;
1266
+ }
1267
+ credentialCleanupRegistered = true;
1268
+ const cleanup = () => {
1269
+ for (const filePath of generatedCredentialFiles) {
1270
+ try {
1271
+ rmSync3(filePath, { force: true });
1272
+ } catch {}
1273
+ }
1274
+ generatedCredentialFiles.clear();
1275
+ };
1276
+ process.on("exit", cleanup);
1277
+ process.on("beforeExit", cleanup);
1278
+ }
1279
+ async function captureStdout(fn) {
1280
+ const chunks = [];
1281
+ const originalWrite = process.stdout.write.bind(process.stdout);
1282
+ const originalLog = console.log;
1283
+ const originalError = console.error;
1284
+ process.stdout.write = (chunk, encoding, cb) => {
1285
+ chunks.push(typeof chunk === "string" ? chunk : Buffer.from(chunk).toString(typeof encoding === "string" ? encoding : undefined));
1286
+ const callback = typeof encoding === "function" ? encoding : cb;
1287
+ callback?.(null);
1288
+ return true;
1289
+ };
1290
+ console.log = (...args) => {
1291
+ chunks.push(`${args.map((value) => String(value)).join(" ")}
1292
+ `);
1293
+ };
1294
+ console.error = (...args) => {
1295
+ chunks.push(`${args.map((value) => String(value)).join(" ")}
1296
+ `);
1297
+ };
1298
+ try {
1299
+ await fn();
1300
+ return chunks.join("");
1301
+ } finally {
1302
+ process.stdout.write = originalWrite;
1303
+ console.log = originalLog;
1304
+ console.error = originalError;
1305
+ }
1306
+ }
1307
+ function sanitizeRuntimeRefSegment(value) {
1308
+ return safeGitRefComponent(value, { fallback: "runtime", maxLength: 64 });
1309
+ }
1310
+ function runtimeBranchBackupName(branch) {
1311
+ const branchId = branch.replace(/^rig\//, "");
1312
+ return `rig-backup/${sanitizeRuntimeRefSegment(branchId)}-${Date.now()}`;
1313
+ }
1314
+ function hashProjectPath(workspaceDir) {
1315
+ return sha256Hex(workspaceDir).slice(0, 16);
1316
+ }
1317
+ async function resolveGithubCliAuthToken(ghBinary = "") {
1318
+ const gh = ghBinary || resolveGithubCliBinary();
1319
+ if (!gh) {
1320
+ return "";
1321
+ }
1322
+ const auth = Bun.spawn([gh, "auth", "token"], {
1323
+ stdout: "pipe",
1324
+ stderr: "pipe"
1325
+ });
1326
+ const [exitCode, stdout] = await Promise.all([
1327
+ auth.exited,
1328
+ new Response(auth.stdout).text()
1329
+ ]);
1330
+ if (exitCode !== 0) {
1331
+ return "";
1332
+ }
1333
+ return stdout.trim();
1334
+ }
1335
+ function resolveSystemCertBundlePath() {
1336
+ const candidates = [
1337
+ process.env.SSL_CERT_FILE?.trim(),
1338
+ "/etc/ssl/cert.pem",
1339
+ "/private/etc/ssl/cert.pem",
1340
+ "/opt/homebrew/etc/openssl@3/cert.pem"
1341
+ ];
1342
+ for (const candidate of candidates) {
1343
+ if (candidate && existsSync4(candidate)) {
1344
+ return resolve4(candidate);
1345
+ }
1346
+ }
1347
+ return "";
1348
+ }
1349
+ function readKnownHosts(path) {
1350
+ if (!existsSync4(path)) {
1351
+ return new Set;
1352
+ }
1353
+ return new Set(readFileSync3(path, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
1354
+ }
1355
+
1356
+ // packages/isolation-plugin/src/isolation/home.ts
1357
+ var GITHUB_SSH_KEY_PLACEHOLDER = "<base64 encoded>";
1358
+ var GITHUB_KNOWN_HOSTS = [
1359
+ "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl",
1360
+ "github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=",
1361
+ "github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk="
1362
+ ].join(`
1363
+ `);
1364
+ function authStateToken(env = process.env) {
1365
+ const file = env.RIG_GITHUB_AUTH_STATE_FILE?.trim();
1366
+ if (!file || !existsSync5(file))
1367
+ return null;
1368
+ try {
1369
+ const parsed = JSON.parse(readFileSync4(file, "utf8"));
1370
+ const token = typeof parsed.token === "string" ? parsed.token.trim() : "";
1371
+ return token.length > 0 ? token : null;
1372
+ } catch {
1373
+ return null;
1374
+ }
1375
+ }
1376
+ function resolveControlPlaneSourceRoot(projectRoot) {
1377
+ const candidates = [
1378
+ process.env.RIG_CONTROL_PLANE_SOURCE_ROOT?.trim(),
1379
+ process.env.RIG_HOST_PROJECT_ROOT?.trim(),
1380
+ resolve5(import.meta.dir, "../../../../.."),
1381
+ projectRoot
1382
+ ].filter((value) => Boolean(value));
1383
+ for (const candidate of candidates) {
1384
+ const root = resolve5(candidate);
1385
+ if (existsSync5(resolve5(root, "packages/cli/bin/rig.ts"))) {
1386
+ return root;
1387
+ }
1388
+ }
1389
+ return "";
1390
+ }
1391
+ async function runtimeEnv(projectRoot, runtime) {
1392
+ const bunBinaryPath = resolveBunBinaryPath();
1393
+ const bunDir = resolveBunInstallDir(bunBinaryPath);
1394
+ const claudeBinaryPath = process.env.RIG_CLAUDE_PATH?.trim() || (() => {
1395
+ try {
1396
+ return resolveClaudeBinaryPath();
1397
+ } catch {
1398
+ return "";
1399
+ }
1400
+ })();
1401
+ const claudeDir = claudeBinaryPath ? (() => {
1402
+ try {
1403
+ return resolveClaudeInstallDir();
1404
+ } catch {
1405
+ return resolve5(claudeBinaryPath, "..");
1406
+ }
1407
+ })() : "";
1408
+ const nodeDir = resolveNodeInstallDir();
1409
+ const hostGhBinary = resolveGithubCliBinary();
1410
+ const runtimeCertBundlePath = await materializeRuntimeCertBundle(runtime);
1411
+ const monorepoMainRoot = resolveMonorepoRoot(projectRoot);
1412
+ const realHome = process.env.HOME?.trim();
1413
+ const inheritedPath = (process.env.PATH ?? "").split(delimiter).map((entry) => entry.trim()).filter(Boolean).filter((entry) => !entry.endsWith("/.rig/bin") && !entry.endsWith("/rig/tools"));
1414
+ const pathEntries = [
1415
+ runtime.binDir,
1416
+ `${projectRoot}/rig/tools`,
1417
+ `${bunDir}/bin`,
1418
+ claudeDir,
1419
+ nodeDir ? `${nodeDir}/bin` : "",
1420
+ realHome ? resolve5(realHome, ".local/bin") : "",
1421
+ realHome ? resolve5(realHome, ".cargo/bin") : "",
1422
+ ...inheritedPath,
1423
+ "/usr/local/bin",
1424
+ "/usr/local/sbin",
1425
+ "/opt/homebrew/bin",
1426
+ "/opt/homebrew/sbin",
1427
+ "/usr/bin",
1428
+ "/bin",
1429
+ "/usr/sbin",
1430
+ "/sbin"
1431
+ ].filter(Boolean);
1432
+ const runtimeBash = resolve5(runtime.binDir, "bash");
1433
+ const runtimeRigGit = resolve5(runtime.binDir, runtimeRigGitFileName());
1434
+ const preferredShell = existsSync5(runtimeBash) ? runtimeBash : "/bin/bash";
1435
+ const nativeRuntimeLibraryPath = await materializeNativeRuntimeLibrary(runtime.binDir);
1436
+ const controlPlaneSourceRoot = resolveControlPlaneSourceRoot(projectRoot);
1437
+ const env = {
1438
+ PROJECT_RIG_ROOT: projectRoot,
1439
+ RIG_HOST_PROJECT_ROOT: projectRoot,
1440
+ ...controlPlaneSourceRoot ? { RIG_CONTROL_PLANE_SOURCE_ROOT: controlPlaneSourceRoot } : {},
1441
+ HOME: runtime.homeDir,
1442
+ TMPDIR: runtime.tmpDir,
1443
+ XDG_CACHE_HOME: runtime.cacheDir,
1444
+ XDG_STATE_HOME: runtime.stateDir,
1445
+ RIG_AGENT_ID: runtime.id,
1446
+ ...process.env.RIG_RUN_ID?.trim() ? { RIG_RUN_ID: process.env.RIG_RUN_ID.trim() } : {},
1447
+ ...process.env.RIG_SERVER_RUN_ID?.trim() ? { RIG_SERVER_RUN_ID: process.env.RIG_SERVER_RUN_ID.trim() } : {},
1448
+ ...process.env.RIG_SERVER_URL?.trim() ? { RIG_SERVER_URL: process.env.RIG_SERVER_URL.trim() } : {},
1449
+ ...process.env.RIG_AUTH_TOKEN?.trim() ? { RIG_AUTH_TOKEN: process.env.RIG_AUTH_TOKEN.trim() } : {},
1450
+ RIG_TASK_ID: runtime.taskId,
1451
+ RIG_TASK_RUNTIME_ID: runtime.id,
1452
+ RIG_TASK_WORKSPACE: runtime.workspaceDir,
1453
+ RIG_TASK_RUNTIME_MODE: runtime.mode,
1454
+ RIG_RUNTIME_MODE: runtime.mode,
1455
+ RIG_RUNTIME_ADAPTER: "pi",
1456
+ RIG_RUNTIME_HOME: runtime.rootDir,
1457
+ RIG_RUNTIME_BIN_DIR: runtime.binDir,
1458
+ ...existsSync5(runtimeRigGit) ? { RIG_NATIVE_GIT_BIN: runtimeRigGit } : {},
1459
+ RIG_BUN_PATH: bunBinaryPath,
1460
+ ...claudeBinaryPath ? { RIG_CLAUDE_PATH: claudeBinaryPath } : {},
1461
+ RIG_AGENT_BIN: resolve5(runtime.binDir, "rig-agent"),
1462
+ RIG_HOOKS_ACTIVE: "1",
1463
+ RIG_AUTO_PR_ON_COMPLETE: "1",
1464
+ RIG_POLICY_FILE: resolve5(projectRoot, "rig/policy/policy.json"),
1465
+ RIG_STATE_DIR: runtime.stateDir,
1466
+ RIG_LOGS_DIR: runtime.logsDir,
1467
+ RIG_SESSION_FILE: resolve5(runtime.sessionDir, "session.json"),
1468
+ MONOREPO_ROOT: runtime.workspaceDir,
1469
+ MONOREPO_MAIN_ROOT: monorepoMainRoot,
1470
+ TS_API_TESTS_DIR: resolve5(runtime.workspaceDir, "TSAPITests"),
1471
+ BASH: preferredShell,
1472
+ SHELL: preferredShell,
1473
+ PATH: [...new Set(pathEntries)].join(delimiter),
1474
+ LANG: process.env.LANG ?? "en_US.UTF-8",
1475
+ TERM: process.env.TERM ?? "xterm-256color",
1476
+ PYTHONDONTWRITEBYTECODE: "1",
1477
+ PYTHONPYCACHEPREFIX: resolve5(runtime.cacheDir, "python"),
1478
+ ...process.env.RIG_PR_BASE_PROJECT && { RIG_PR_BASE_PROJECT: process.env.RIG_PR_BASE_PROJECT },
1479
+ ...process.env.RIG_PR_BASE_MONOREPO && { RIG_PR_BASE_MONOREPO: process.env.RIG_PR_BASE_MONOREPO },
1480
+ CLAUDE_HOME: runtime.claudeHomeDir,
1481
+ PI_CODING_AGENT_DIR: resolve5(runtime.homeDir, ".pi", "agent"),
1482
+ OMP_SKIP_SETUP: "1",
1483
+ [RUNTIME_CONTEXT_ENV]: runtime.contextFile,
1484
+ ...nativeRuntimeLibraryPath ? { RIG_NATIVE_RUNTIME_LIB: nativeRuntimeLibraryPath } : {},
1485
+ ...hostGhBinary ? { RIG_GH_BIN: hostGhBinary } : {},
1486
+ ...runtimeCertBundlePath ? {
1487
+ SSL_CERT_FILE: runtimeCertBundlePath,
1488
+ CURL_CA_BUNDLE: runtimeCertBundlePath,
1489
+ REQUESTS_CA_BUNDLE: runtimeCertBundlePath,
1490
+ NODE_EXTRA_CA_CERTS: runtimeCertBundlePath
1491
+ } : {}
1492
+ };
1493
+ const knownHostsPath = resolve5(runtime.homeDir, ".ssh", "known_hosts");
1494
+ if (existsSync5(knownHostsPath)) {
1495
+ const agentSshKey = resolve5(runtime.homeDir, ".ssh", "rig-agent-key");
1496
+ const sshParts = [
1497
+ "ssh",
1498
+ `-o UserKnownHostsFile="${knownHostsPath}"`,
1499
+ "-o StrictHostKeyChecking=yes",
1500
+ "-F /dev/null"
1501
+ ];
1502
+ if (existsSync5(agentSshKey)) {
1503
+ sshParts.splice(1, 0, `-i "${agentSshKey}"`, "-o IdentitiesOnly=yes");
1504
+ }
1505
+ env.GIT_SSH_COMMAND = sshParts.join(" ");
1506
+ }
1507
+ const persistedSecretsPath = resolve5(runtime.rootDir, "runtime-secrets.json");
1508
+ if (existsSync5(persistedSecretsPath)) {
1509
+ try {
1510
+ const persisted = JSON.parse(readFileSync4(persistedSecretsPath, "utf8"));
1511
+ if (persisted && typeof persisted === "object") {
1512
+ for (const [key, value] of Object.entries(persisted)) {
1513
+ if (key === "GITHUB_SSH_KEY")
1514
+ continue;
1515
+ if (typeof value === "string" && value && !env[key])
1516
+ env[key] = value;
1517
+ }
1518
+ }
1519
+ } catch {}
1520
+ }
1521
+ for (const [key, value] of Object.entries(resolveRuntimeSecrets(process.env))) {
1522
+ if (key === "GITHUB_SSH_KEY") {
1523
+ continue;
1524
+ }
1525
+ if (value) {
1526
+ env[key] = value;
1527
+ }
1528
+ }
1529
+ const authStateGithubToken = authStateToken(process.env) || "";
1530
+ const explicitRigGithubToken = process.env.RIG_GITHUB_TOKEN?.trim() || "";
1531
+ const rigGithubToken = explicitRigGithubToken || authStateGithubToken;
1532
+ if (rigGithubToken) {
1533
+ env.RIG_GITHUB_TOKEN = rigGithubToken;
1534
+ env.GITHUB_TOKEN = rigGithubToken;
1535
+ env.GH_TOKEN = rigGithubToken;
1536
+ }
1537
+ const fallbackGithubToken = !env.GITHUB_TOKEN && !env.GH_TOKEN ? await resolveGithubCliAuthToken(hostGhBinary) : "";
1538
+ if (fallbackGithubToken) {
1539
+ env.GITHUB_TOKEN = fallbackGithubToken;
1540
+ }
1541
+ if (!env.GITHUB_TOKEN && env.GH_TOKEN) {
1542
+ env.GITHUB_TOKEN = env.GH_TOKEN;
1543
+ }
1544
+ if (!env.GH_TOKEN && env.GITHUB_TOKEN) {
1545
+ env.GH_TOKEN = env.GITHUB_TOKEN;
1546
+ }
1547
+ const gitHubToken = env.GITHUB_TOKEN || env.GH_TOKEN || rigGithubToken;
1548
+ if (gitHubToken) {
1549
+ env.RIG_GITHUB_TOKEN = gitHubToken;
1550
+ env.GITHUB_TOKEN = env.GITHUB_TOKEN || gitHubToken;
1551
+ env.GH_TOKEN = env.GH_TOKEN || gitHubToken;
1552
+ applyGitHubCredentialHelperEnv(env);
1553
+ }
1554
+ if (!env.GREPTILE_GITHUB_TOKEN && env.GITHUB_TOKEN) {
1555
+ env.GREPTILE_GITHUB_TOKEN = env.GITHUB_TOKEN;
1556
+ }
1557
+ if (existsSync5(runtime.contextFile)) {
1558
+ const runtimeContext = loadRuntimeContext(runtime.contextFile);
1559
+ Object.assign(env, runtimeMemoryEnvFromContext(runtimeContext));
1560
+ Object.assign(env, browserEnvFromContext(runtimeContext.browser));
1561
+ }
1562
+ persistRuntimeSecrets(runtime.rootDir, env);
1563
+ return env;
1564
+ }
1565
+ function runtimeCommandEnv(baseEnv, command) {
1566
+ const env = { ...baseEnv };
1567
+ delete env.ENV;
1568
+ delete env.BASH_ENV;
1569
+ const executable = command[0]?.trim() ?? "";
1570
+ const shellName = basename(executable);
1571
+ const isPosixSh = executable === "/bin/sh" || shellName === "sh" || shellName === "dash";
1572
+ if (isPosixSh) {
1573
+ delete env.BASH;
1574
+ if (executable) {
1575
+ env.SHELL = executable;
1576
+ }
1577
+ }
1578
+ return env;
1579
+ }
1580
+ async function provisionRuntimeHome(runtime, options = {}) {
1581
+ await mkdir(runtime.homeDir, { recursive: true });
1582
+ await mkdir(runtime.tmpDir, { recursive: true });
1583
+ await mkdir(runtime.cacheDir, { recursive: true });
1584
+ await provisionAgentSshKey(runtime.homeDir);
1585
+ if (options.provider === "pi") {
1586
+ const hasPiAuth = await injectPiAgentConfig(resolve5(runtime.homeDir, ".pi", "agent"));
1587
+ if (!hasPiAuth) {
1588
+ console.warn("[rig] No Pi auth.json found for isolated runtime. " + "Run `pi /login` in your host shell, then retry the agent run.");
1589
+ }
1590
+ }
1591
+ }
1592
+ async function provisionClaudeHome(config) {
1593
+ mkdirSync4(config.claudeHomeDir, { recursive: true });
1594
+ const workspaceSettings = resolve5(config.workspaceDir, ".claude/settings.json");
1595
+ const hostSettings = resolve5(config.hostProjectRoot, ".claude/settings.json");
1596
+ const projectSettings = existsSync5(workspaceSettings) ? workspaceSettings : hostSettings;
1597
+ const runtimeSettings = await loadRuntimeClaudeSettings(projectSettings);
1598
+ if (existsSync5(projectSettings)) {
1599
+ writeFileSync3(resolve5(config.claudeHomeDir, "settings.local.json"), `${JSON.stringify(runtimeSettings, null, 2)}
1600
+ `, "utf-8");
1601
+ }
1602
+ writeClaudeProjectSettings(config.claudeHomeDir, config.workspaceDir, runtimeSettings);
1603
+ writeFileSync3(resolve5(config.claudeHomeDir, "settings.json"), JSON.stringify({
1604
+ permissions: { defaultMode: "bypassPermissions" },
1605
+ autoMemoryEnabled: false
1606
+ }, null, 2));
1607
+ const hasCredentials = await injectClaudeCredentials(config.claudeHomeDir);
1608
+ if (!hasCredentials) {
1609
+ console.warn("[rig] No Claude credentials found for isolated runtime. " + "Run `claude /login` in your host shell, then retry the agent run.");
1610
+ }
1611
+ const realClaudeHome = resolve5(process.env.HOME ?? "", ".claude");
1612
+ if (process.env.HOME && existsSync5(resolve5(realClaudeHome, "CLAUDE.md"))) {
1613
+ cpSync(resolve5(realClaudeHome, "CLAUDE.md"), resolve5(config.claudeHomeDir, "CLAUDE.md"));
1614
+ }
1615
+ if (process.env.HOME && existsSync5(resolve5(realClaudeHome, "agents"))) {
1616
+ cpSync(resolve5(realClaudeHome, "agents"), resolve5(config.claudeHomeDir, "agents"), { recursive: true });
1617
+ }
1618
+ if (process.platform === "darwin" && process.env.HOME) {
1619
+ writeClaudeProjectSettings(realClaudeHome, config.workspaceDir, runtimeSettings);
1620
+ }
1621
+ }
1622
+ async function materializeRuntimeCertBundle(runtime) {
1623
+ const sourcePath = resolveSystemCertBundlePath();
1624
+ if (!sourcePath) {
1625
+ return "";
1626
+ }
1627
+ const certsDir = resolve5(runtime.rootDir, "certs");
1628
+ const targetPath = resolve5(certsDir, "ca-certificates.pem");
1629
+ await mkdir(certsDir, { recursive: true });
1630
+ let shouldCopy = !existsSync5(targetPath);
1631
+ if (!shouldCopy) {
1632
+ try {
1633
+ shouldCopy = statSync3(sourcePath).mtimeMs > statSync3(targetPath).mtimeMs;
1634
+ } catch {
1635
+ shouldCopy = true;
1636
+ }
1637
+ }
1638
+ if (shouldCopy) {
1639
+ copyFileSync3(sourcePath, targetPath);
1640
+ }
1641
+ return targetPath;
1642
+ }
1643
+ function applyGitHubCredentialHelperEnv(env) {
1644
+ env.GIT_TERMINAL_PROMPT = "0";
1645
+ env.GIT_CONFIG_COUNT = "2";
1646
+ env.GIT_CONFIG_KEY_0 = "credential.helper";
1647
+ env.GIT_CONFIG_VALUE_0 = "";
1648
+ env.GIT_CONFIG_KEY_1 = "credential.helper";
1649
+ 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';
1650
+ }
1651
+ var PERSISTED_RUNTIME_SECRET_KEYS = [
1652
+ "ANTHROPIC_API_KEY",
1653
+ "OPENAI_API_KEY",
1654
+ "OPENROUTER_API_KEY",
1655
+ "AI_REVIEW_MODE",
1656
+ "AI_REVIEW_PROVIDER",
1657
+ "GREPTILE_API_BASE",
1658
+ "GREPTILE_REMOTE",
1659
+ "GREPTILE_REPOSITORY",
1660
+ "GREPTILE_CONTEXT_BRANCH",
1661
+ "GREPTILE_DEFAULT_BRANCH",
1662
+ "GREPTILE_API_KEY",
1663
+ "GREPTILE_GITHUB_TOKEN",
1664
+ "GREPTILE_POLL_ATTEMPTS",
1665
+ "GREPTILE_POLL_INTERVAL_MS",
1666
+ "GH_TOKEN",
1667
+ "GITHUB_TOKEN",
1668
+ "AWS_ACCESS_KEY_ID",
1669
+ "AWS_SECRET_ACCESS_KEY",
1670
+ "AWS_REGION",
1671
+ "LINEAR_API_KEY",
1672
+ "LINEAR_WEBHOOK_SECRET",
1673
+ "RIG_GITHUB_TOKEN"
1674
+ ];
1675
+ function persistRuntimeSecrets(runtimeRoot, env) {
1676
+ const secretsPath = resolve5(runtimeRoot, "runtime-secrets.json");
1677
+ const resolvedSecrets = resolveRuntimeSecrets(env);
1678
+ const persisted = {};
1679
+ const secretSource = {
1680
+ ...resolvedSecrets,
1681
+ RIG_GITHUB_TOKEN: env.RIG_GITHUB_TOKEN
1682
+ };
1683
+ for (const key of PERSISTED_RUNTIME_SECRET_KEYS) {
1684
+ const value = secretSource[key]?.trim();
1685
+ if (value) {
1686
+ persisted[key] = value;
1687
+ }
1688
+ }
1689
+ if (Object.keys(persisted).length === 0) {
1690
+ return;
1691
+ }
1692
+ writeFileSync3(secretsPath, `${JSON.stringify(persisted, null, 2)}
1693
+ `, { encoding: "utf-8", mode: 384 });
1694
+ chmodSync2(secretsPath, 384);
1695
+ }
1696
+ async function provisionAgentSshKey(homeDir) {
1697
+ const sshDir = resolve5(homeDir, ".ssh");
1698
+ if (!existsSync5(sshDir)) {
1699
+ await mkdir(sshDir, { recursive: true });
1700
+ }
1701
+ seedKnownHosts(sshDir);
1702
+ const secrets = resolveRuntimeSecrets(process.env);
1703
+ const privateKey = decodeProvisionedSshKey(secrets.GITHUB_SSH_KEY);
1704
+ if (!privateKey) {
1705
+ const hostKeyPath = resolveHostSshKeyPath(process.env.HOME ?? "");
1706
+ if (!process.env.HOME || !existsSync5(hostKeyPath)) {
1707
+ return;
1708
+ }
1709
+ const agentKeyPath2 = resolve5(sshDir, "rig-agent-key");
1710
+ if (!existsSync5(agentKeyPath2)) {
1711
+ copyFileSync3(hostKeyPath, agentKeyPath2);
1712
+ chmodSync2(agentKeyPath2, 384);
1713
+ }
1714
+ const hostPubPath = `${hostKeyPath}.pub`;
1715
+ if (existsSync5(hostPubPath)) {
1716
+ const agentPubPath = `${agentKeyPath2}.pub`;
1717
+ if (!existsSync5(agentPubPath)) {
1718
+ copyFileSync3(hostPubPath, agentPubPath);
1719
+ }
1720
+ }
1721
+ writeSshConfig(sshDir, agentKeyPath2);
1722
+ return;
1723
+ }
1724
+ const agentKeyPath = resolve5(sshDir, "rig-agent-key");
1725
+ if (!existsSync5(agentKeyPath)) {
1726
+ writeFileSync3(agentKeyPath, privateKey, { mode: 384 });
1727
+ }
1728
+ writeSshConfig(sshDir, agentKeyPath);
1729
+ }
1730
+ function decodeProvisionedSshKey(encodedKey) {
1731
+ const trimmed = encodedKey?.trim();
1732
+ if (!trimmed || trimmed === GITHUB_SSH_KEY_PLACEHOLDER) {
1733
+ return null;
1734
+ }
1735
+ const decoded = Buffer.from(trimmed, "base64").toString("utf-8").trim();
1736
+ if (!decoded.includes("PRIVATE KEY")) {
1737
+ return null;
1738
+ }
1739
+ return `${decoded}
1740
+ `;
1741
+ }
1742
+ function resolveHostSshKeyPath(homeDir) {
1743
+ const sshDir = resolve5(homeDir, ".ssh");
1744
+ const candidates = [
1745
+ "rig-agent-key",
1746
+ "id_ed25519",
1747
+ "id_ecdsa",
1748
+ "id_rsa"
1749
+ ].map((name) => resolve5(sshDir, name));
1750
+ return candidates.find((candidate) => existsSync5(candidate)) ?? resolve5(sshDir, "rig-agent-key");
1751
+ }
1752
+ function writeSshConfig(sshDir, keyPath) {
1753
+ const configPath = resolve5(sshDir, "config");
1754
+ if (existsSync5(configPath)) {
1755
+ return;
1756
+ }
1757
+ const knownHostsPath = resolve5(sshDir, "known_hosts");
1758
+ const config = [
1759
+ "Host github.com",
1760
+ ` IdentityFile ${keyPath}`,
1761
+ " IdentitiesOnly yes",
1762
+ ` UserKnownHostsFile ${knownHostsPath}`,
1763
+ " StrictHostKeyChecking yes",
1764
+ ""
1765
+ ].join(`
1766
+ `);
1767
+ writeFileSync3(configPath, config, { mode: 420 });
1768
+ }
1769
+ function seedKnownHosts(sshDir) {
1770
+ const knownHostsPath = resolve5(sshDir, "known_hosts");
1771
+ const existingLines = readKnownHosts(knownHostsPath);
1772
+ const requiredLines = GITHUB_KNOWN_HOSTS.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
1773
+ const missing = requiredLines.filter((line) => !existingLines.has(line));
1774
+ if (missing.length === 0) {
1775
+ return;
1776
+ }
1777
+ try {
1778
+ for (const line of missing) {
1779
+ existingLines.add(line);
1780
+ }
1781
+ writeFileSync3(knownHostsPath, `${Array.from(existingLines).join(`
1782
+ `)}
1783
+ `, { mode: 420 });
1784
+ } catch (err) {
1785
+ const hint = existsSync5(knownHostsPath) ? "" : " \u2014 known_hosts is missing; git SSH operations may fail";
1786
+ console.warn(`[rig] Could not update ${knownHostsPath}: ${err instanceof Error ? err.message : String(err)}${hint}`);
1787
+ }
1788
+ }
1789
+ function writeClaudeProjectSettings(claudeHomeDir, workspaceDir, runtimeSettings) {
1790
+ const projectHash = hashProjectPath(workspaceDir);
1791
+ const projectDir = resolve5(claudeHomeDir, "projects", projectHash);
1792
+ mkdirSync4(projectDir, { recursive: true });
1793
+ writeFileSync3(resolve5(projectDir, "settings.json"), `${JSON.stringify(runtimeSettings, null, 2)}
1794
+ `, "utf-8");
1795
+ }
1796
+ async function loadRuntimeClaudeSettings(projectSettingsPath) {
1797
+ if (!existsSync5(projectSettingsPath)) {
1798
+ return {};
1799
+ }
1800
+ let parsed;
1801
+ try {
1802
+ parsed = await Bun.file(projectSettingsPath).json();
1803
+ } catch {
1804
+ return {};
1805
+ }
1806
+ const clone = JSON.parse(JSON.stringify(parsed));
1807
+ const hooks = clone.hooks;
1808
+ if (!hooks || typeof hooks !== "object") {
1809
+ return clone;
1810
+ }
1811
+ for (const key of ["PreToolUse", "PostToolUse", "SessionStart", "Stop"]) {
1812
+ const groups = hooks[key];
1813
+ if (!Array.isArray(groups)) {
1814
+ continue;
1815
+ }
1816
+ for (const group of groups) {
1817
+ if (!group || typeof group !== "object" || Array.isArray(group)) {
1818
+ continue;
1819
+ }
1820
+ const hookGroup = group;
1821
+ if (!Array.isArray(hookGroup.hooks)) {
1822
+ continue;
1823
+ }
1824
+ for (const hook of hookGroup.hooks) {
1825
+ if (!hook || hook.type !== "command" || typeof hook.command !== "string") {
1826
+ continue;
1827
+ }
1828
+ const shMatch = hook.command.match(/rig\/hooks\/([a-z0-9-]+)\.sh$/i);
1829
+ if (shMatch) {
1830
+ hook.command = `.rig/bin/hooks/${shMatch[1]}`;
1831
+ continue;
1832
+ }
1833
+ const splinterMatch = hook.command.match(/\.splinter\/bin\/hooks\/([a-z0-9-]+)$/i);
1834
+ if (splinterMatch) {
1835
+ hook.command = `.rig/bin/hooks/${splinterMatch[1]}`;
1836
+ }
1837
+ }
1838
+ }
1839
+ }
1840
+ return clone;
1841
+ }
1842
+ async function injectClaudeCredentials(claudeHomeDir, options = {}) {
1843
+ const credentialsPath = resolve5(claudeHomeDir, ".credentials.json");
1844
+ const platform = options.platform ?? process.platform;
1845
+ if (platform === "darwin") {
1846
+ const raw = options.loadKeychainCredentials ? await options.loadKeychainCredentials() : await (async () => {
1847
+ const result = await Bun.$`security find-generic-password -s "Claude Code-credentials" -w`.quiet().nothrow();
1848
+ return result.exitCode === 0 ? result.stdout.toString().trim() : "";
1849
+ })();
1850
+ if (raw) {
1851
+ try {
1852
+ JSON.parse(raw);
1853
+ writeFileSync3(credentialsPath, raw, { mode: 384 });
1854
+ registerCredentialCleanup(credentialsPath);
1855
+ return true;
1856
+ } catch {}
1857
+ }
1858
+ }
1859
+ 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") : "";
1860
+ if (hostClaudeHome) {
1861
+ const realCredentials = resolve5(hostClaudeHome, ".credentials.json");
1862
+ if (existsSync5(realCredentials)) {
1863
+ cpSync(realCredentials, credentialsPath);
1864
+ return true;
1865
+ }
1866
+ }
1867
+ return false;
1868
+ }
1869
+ async function injectPiAgentConfig(piAgentDir) {
1870
+ mkdirSync4(piAgentDir, { recursive: true });
1871
+ const runtimeConfigPath = resolve5(piAgentDir, "config.yml");
1872
+ if (!existsSync5(runtimeConfigPath)) {
1873
+ writeFileSync3(runtimeConfigPath, `setupVersion: 1000
1874
+ startup:
1875
+ setupWizard: false
1876
+ checkUpdate: false
1877
+ `, { mode: 384 });
1878
+ }
1879
+ 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") : "";
1880
+ if (!hostPiAgentDir) {
1881
+ return false;
1882
+ }
1883
+ const hostAuthPath = resolve5(hostPiAgentDir, "auth.json");
1884
+ if (!existsSync5(hostAuthPath)) {
1885
+ return false;
1886
+ }
1887
+ const runtimeAuthPath = resolve5(piAgentDir, "auth.json");
1888
+ copyFileSync3(hostAuthPath, runtimeAuthPath);
1889
+ chmodSync2(runtimeAuthPath, 384);
1890
+ const hostSettingsPath = resolve5(hostPiAgentDir, "settings.json");
1891
+ if (existsSync5(hostSettingsPath)) {
1892
+ const runtimeSettingsPath = resolve5(piAgentDir, "settings.json");
1893
+ copyFileSync3(hostSettingsPath, runtimeSettingsPath);
1894
+ chmodSync2(runtimeSettingsPath, 384);
1895
+ }
1896
+ return true;
1897
+ }
1898
+
1899
+ // packages/isolation-plugin/src/isolation/discovery.ts
1900
+ import { existsSync as existsSync9 } from "fs";
1901
+ import { resolve as resolve9 } from "path";
1902
+ import { resolveRuntimeWorkspaceLayout } from "@rig/core/layout";
1903
+ import { loadRuntimeContext as loadRuntimeContext2 } from "@rig/core/runtime-context";
1904
+
1905
+ // packages/isolation-plugin/src/isolation/worktree.ts
1906
+ import { existsSync as existsSync6, mkdirSync as mkdirSync5, rmSync as rmSync4 } from "fs";
1907
+ import { dirname as dirname3, resolve as resolve6 } from "path";
1908
+ import { assertPathInsideRoot, safeGitRefComponent as safeGitRefComponent2, safePathSegment } from "@rig/core/safe-identifiers";
1909
+ async function resolveMonorepoBaseRef(monorepoRoot) {
1910
+ const explicit = process.env.RIG_RUNTIME_BASE_REF?.trim();
1911
+ if (explicit) {
1912
+ const exists = await runGitCommand(monorepoRoot, ["rev-parse", "--verify", "--quiet", explicit]);
1913
+ if (exists.exitCode !== 0) {
1914
+ throw new Error(`RIG_RUNTIME_BASE_REF=${explicit} does not resolve at ${monorepoRoot}.`);
1915
+ }
1916
+ return explicit;
1917
+ }
1918
+ for (const remote of await preferredBaseRemotes(monorepoRoot)) {
1919
+ await refreshRemoteBranch(monorepoRoot, remote, "main");
1920
+ const remoteMain = await runGitCommand(monorepoRoot, ["show-ref", "--verify", "--quiet", `refs/remotes/${remote}/main`]);
1921
+ if (remoteMain.exitCode === 0) {
1922
+ return `${remote}/main`;
1923
+ }
1924
+ }
1925
+ const localMain = await runGitCommand(monorepoRoot, ["show-ref", "--verify", "--quiet", "refs/heads/main"]);
1926
+ if (localMain.exitCode === 0) {
1927
+ return "main";
1928
+ }
1929
+ throw new Error(`Failed to resolve a monorepo base ref at ${monorepoRoot}. Expected local main or a remote main ref.`);
1930
+ }
1931
+ function ensureProvisioningHostProjectRootEnv(projectRoot) {
1932
+ if (!projectRoot.trim()) {
1933
+ return;
1934
+ }
1935
+ if (!process.env.RIG_HOST_PROJECT_ROOT?.trim()) {
1936
+ process.env.RIG_HOST_PROJECT_ROOT = projectRoot;
1937
+ }
1938
+ if (!process.env.PROJECT_RIG_ROOT?.trim()) {
1939
+ process.env.PROJECT_RIG_ROOT = projectRoot;
1940
+ }
1941
+ }
1942
+ async function provisionRuntimeWorktree(config) {
1943
+ const worktreesRoot = resolve6(config.monorepoRoot, ".worktrees");
1944
+ assertPathInsideRoot(worktreesRoot, config.workspaceDir, "runtime worktree path");
1945
+ const branch = runtimeBranchName(config.taskId, config.runtimeId);
1946
+ let hasValidWorktree = existsSync6(resolve6(config.workspaceDir, ".git")) && (await runGitCommand(config.workspaceDir, ["rev-parse", "--show-toplevel"])).exitCode === 0;
1947
+ if (existsSync6(config.workspaceDir) && !hasValidWorktree) {
1948
+ rmSync4(config.workspaceDir, { recursive: true, force: true });
1949
+ }
1950
+ if (!hasValidWorktree) {
1951
+ mkdirSync5(dirname3(config.workspaceDir), { recursive: true });
1952
+ const branchExists = await runGitCommand(config.monorepoRoot, ["show-ref", "--verify", "--quiet", `refs/heads/${branch}`]);
1953
+ const addArgs = branchExists.exitCode === 0 ? ["worktree", "add", "--force", config.workspaceDir, branch] : ["worktree", "add", "--force", "-b", branch, config.workspaceDir, config.baseRef];
1954
+ const add = await runGitWithLockRetry(config.monorepoRoot, addArgs);
1955
+ if (add.exitCode !== 0) {
1956
+ throw new Error(`Failed to create monorepo worktree for ${config.runtimeId}: ${add.stderr.toString() || add.stdout.toString()}`);
1957
+ }
1958
+ hasValidWorktree = true;
1959
+ }
1960
+ await ensureRuntimeBranch(config.workspaceDir, branch, config.baseRef);
1961
+ }
1962
+ function isGitLockContention(result) {
1963
+ if (result.exitCode === 0) {
1964
+ return false;
1965
+ }
1966
+ const text = `${result.stderr != null ? String(result.stderr) : ""}
1967
+ ${result.stdout != null ? String(result.stdout) : ""}`;
1968
+ return /could not lock|cannot lock|unable to create '[^']*\.lock'|index\.lock|is already locked|File exists/i.test(text);
1969
+ }
1970
+ async function runGitWithLockRetry(repoRoot, args, attempts = 5) {
1971
+ let result = await runGitCommand(repoRoot, args);
1972
+ for (let attempt = 1;attempt < attempts && isGitLockContention(result); attempt++) {
1973
+ await Bun.sleep(50 * attempt);
1974
+ result = await runGitCommand(repoRoot, args);
1975
+ }
1976
+ return result;
1977
+ }
1978
+ async function cleanupRuntimeWorktree(monorepoRoot, workspaceDir) {
1979
+ assertPathInsideRoot(resolve6(monorepoRoot, ".worktrees"), workspaceDir, "runtime worktree path");
1980
+ await runGitCommand(monorepoRoot, ["worktree", "remove", "--force", workspaceDir]);
1981
+ }
1982
+ async function configureRuntimeGitIdentity(projectRoot, repoRoot) {
1983
+ const userName = process.env.RIG_GIT_USER_NAME?.trim() || await readGitConfigValue(projectRoot, "user.name") || await readGitConfigValue(projectRoot, "user.name", true) || process.env.GIT_AUTHOR_NAME?.trim() || process.env.GIT_COMMITTER_NAME?.trim() || "rig-agent";
1984
+ const userEmail = process.env.RIG_GIT_USER_EMAIL?.trim() || await readGitConfigValue(projectRoot, "user.email") || await readGitConfigValue(projectRoot, "user.email", true) || process.env.GIT_AUTHOR_EMAIL?.trim() || process.env.GIT_COMMITTER_EMAIL?.trim() || "rig-agent@users.noreply.github.com";
1985
+ for (const [key, value] of [
1986
+ ["user.name", userName],
1987
+ ["user.email", userEmail]
1988
+ ]) {
1989
+ await runGitCommand(repoRoot, ["config", "--local", key, value]);
1990
+ }
1991
+ }
1992
+ async function resolveMonorepoBaseCommit(monorepoRoot, baseRef) {
1993
+ return readGitStdout(monorepoRoot, ["rev-parse", baseRef]);
1994
+ }
1995
+ async function ensureRuntimeBranch(repoRoot, branch, baseRef) {
1996
+ const pruneWorktrees = async () => {
1997
+ await runGitCommand(repoRoot, ["worktree", "prune", "--expire", "now"]);
1998
+ };
1999
+ await pruneWorktrees();
2000
+ await clearInterruptedRuntimeGitState(repoRoot, branch);
2001
+ const current = await runGitCommand(repoRoot, ["rev-parse", "--abbrev-ref", "HEAD"]);
2002
+ if (current.exitCode === 0 && current.stdout.toString().trim() === branch) {
2003
+ await repairDisconnectedRuntimeBranch(repoRoot, branch, baseRef);
2004
+ await clearInterruptedRuntimeGitState(repoRoot, branch);
2005
+ return;
2006
+ }
2007
+ let checkout = await runGitCommand(repoRoot, ["checkout", "-B", branch]);
2008
+ const checkoutError = checkout.stderr.toString() || checkout.stdout.toString();
2009
+ if (checkout.exitCode !== 0 && checkoutError.includes("already used by worktree")) {
2010
+ await pruneWorktrees();
2011
+ checkout = await runGitCommand(repoRoot, ["checkout", "-B", branch]);
2012
+ }
2013
+ if (checkout.exitCode !== 0 && /resolve your current index first|would be overwritten by checkout/i.test(checkoutError)) {
2014
+ await discardTrackedRuntimeChanges(repoRoot, branch, checkoutError);
2015
+ checkout = await runGitCommand(repoRoot, ["checkout", "-B", branch]);
2016
+ }
2017
+ if (checkout.exitCode !== 0) {
2018
+ throw new Error(`Failed to prepare runtime branch ${branch} in ${repoRoot}: ${checkout.stderr.toString() || checkout.stdout.toString()}`);
2019
+ }
2020
+ await repairDisconnectedRuntimeBranch(repoRoot, branch, baseRef);
2021
+ await clearInterruptedRuntimeGitState(repoRoot, branch);
2022
+ }
2023
+ async function repairDisconnectedRuntimeBranch(repoRoot, branch, baseRef) {
2024
+ const mergeBase = await runGitCommand(repoRoot, ["merge-base", "HEAD", baseRef]);
2025
+ if (mergeBase.exitCode === 0) {
2026
+ const counts = await runGitCommand(repoRoot, ["rev-list", "--left-right", "--count", `HEAD...${baseRef}`]);
2027
+ if (counts.exitCode === 0) {
2028
+ const [aheadRaw = "0", behindRaw = "0"] = String(counts.stdout).trim().split(/\s+/);
2029
+ const ahead = Number.parseInt(aheadRaw, 10);
2030
+ const behind = Number.parseInt(behindRaw, 10);
2031
+ if (Number.isFinite(ahead) && Number.isFinite(behind) && ahead === 0 && behind > 0) {
2032
+ const reset = await runGitCommand(repoRoot, ["reset", "--hard", baseRef]);
2033
+ if (reset.exitCode !== 0) {
2034
+ throw new Error(`Failed to reset stale runtime branch ${branch} to ${baseRef} in ${repoRoot}: ${reset.stderr.toString() || reset.stdout.toString()}`);
2035
+ }
2036
+ console.log(`[rig-agent] Reset stale runtime branch ${branch} to ${baseRef} in ${repoRoot}`);
2037
+ }
2038
+ }
2039
+ return;
2040
+ }
2041
+ const backupBranch = runtimeBranchBackupName(branch);
2042
+ const rename = await runGitCommand(repoRoot, ["branch", "-m", backupBranch]);
2043
+ if (rename.exitCode !== 0) {
2044
+ throw new Error(`Failed to archive disconnected runtime branch ${branch} in ${repoRoot}: ${rename.stderr.toString() || rename.stdout.toString()}`);
2045
+ }
2046
+ const recreate = await runGitCommand(repoRoot, ["checkout", "-B", branch, baseRef]);
2047
+ if (recreate.exitCode !== 0) {
2048
+ throw new Error(`Failed to recreate runtime branch ${branch} from ${baseRef} in ${repoRoot}: ${recreate.stderr.toString() || recreate.stdout.toString()}`);
2049
+ }
2050
+ console.log(`[rig-agent] Recreated disconnected runtime branch ${branch} from ${baseRef}; archived as ${backupBranch}`);
2051
+ }
2052
+ async function clearInterruptedRuntimeGitState(repoRoot, branch) {
2053
+ let cleared = false;
2054
+ for (const [sentinel, abortArgs] of [
2055
+ ["MERGE_HEAD", ["merge", "--abort"]],
2056
+ ["REBASE_HEAD", ["rebase", "--abort"]],
2057
+ ["CHERRY_PICK_HEAD", ["cherry-pick", "--abort"]]
2058
+ ]) {
2059
+ const state = await runGitCommand(repoRoot, ["rev-parse", "--verify", "--quiet", sentinel]);
2060
+ if (state.exitCode !== 0) {
2061
+ continue;
2062
+ }
2063
+ cleared = true;
2064
+ const abort = await runGitCommand(repoRoot, [...abortArgs]);
2065
+ if (abort.exitCode === 0) {
2066
+ continue;
2067
+ }
2068
+ const reset = await runGitCommand(repoRoot, ["reset", "--hard", "HEAD"]);
2069
+ if (reset.exitCode !== 0) {
2070
+ throw new Error(`Failed to recover interrupted git state for runtime branch ${branch} in ${repoRoot}: ${reset.stderr.toString() || reset.stdout.toString()}`);
2071
+ }
2072
+ }
2073
+ const unmerged = await runGitCommand(repoRoot, ["ls-files", "-u"]);
2074
+ if (unmerged.exitCode === 0 && String(unmerged.stdout).trim()) {
2075
+ cleared = true;
2076
+ const reset = await runGitCommand(repoRoot, ["reset", "--hard", "HEAD"]);
2077
+ if (reset.exitCode !== 0) {
2078
+ throw new Error(`Failed to clear unmerged files for runtime branch ${branch} in ${repoRoot}: ${reset.stderr.toString() || reset.stdout.toString()}`);
2079
+ }
2080
+ }
2081
+ if (cleared) {
2082
+ console.log(`[rig-agent] Reset interrupted git state in runtime branch ${branch} at ${repoRoot}`);
2083
+ }
2084
+ }
2085
+ async function discardTrackedRuntimeChanges(repoRoot, branch, reason) {
2086
+ const status = await runGitCommand(repoRoot, ["status", "--porcelain"]);
2087
+ if (status.exitCode !== 0) {
2088
+ throw new Error(`Failed to inspect runtime worktree state for ${branch} in ${repoRoot}: ${status.stderr.toString() || status.stdout.toString()}`);
2089
+ }
2090
+ const trackedChanges = String(status.stdout).split(/\r?\n/).map((line) => line.trimEnd()).filter(Boolean).filter((line) => !line.startsWith("?? "));
2091
+ if (trackedChanges.length === 0) {
2092
+ return;
2093
+ }
2094
+ const reset = await runGitCommand(repoRoot, ["reset", "--hard", "HEAD"]);
2095
+ if (reset.exitCode !== 0) {
2096
+ throw new Error(`Failed to discard tracked runtime changes for ${branch} in ${repoRoot}: ${reset.stderr.toString() || reset.stdout.toString()}`);
2097
+ }
2098
+ console.log(`[rig-agent] Reset tracked runtime changes in ${branch} at ${repoRoot} after checkout failed: ${reason.trim()}`);
2099
+ }
2100
+ function runtimeBranchName(taskId, runtimeId) {
2101
+ const taskComponent = safeGitRefComponent2(taskId, { fallback: "task", maxLength: 72 });
2102
+ if (runtimeId === taskRuntimeId(taskId)) {
2103
+ return `rig/${taskComponent}`;
2104
+ }
2105
+ return `rig/${taskComponent}-${safeGitRefComponent2(runtimeId, { fallback: "runtime", maxLength: 48 })}`;
2106
+ }
2107
+ function runtimeWorktreeName(taskId, runtimeId) {
2108
+ if (runtimeId === taskRuntimeId(taskId)) {
2109
+ return safePathSegment(taskId, { fallback: "task", maxLength: 72 });
2110
+ }
2111
+ return safePathSegment(runtimeId, { fallback: "runtime", maxLength: 72 });
2112
+ }
2113
+ function runtimeWorktreeNameFromRuntimeId(runtimeId) {
2114
+ return safePathSegment(runtimeId.replace(/^task-/, ""), { fallback: "runtime", maxLength: 72 });
2115
+ }
2116
+ async function preferredBaseRemotes(repoRoot) {
2117
+ const remotesResult = await runGitCommand(repoRoot, ["remote"]);
2118
+ if (remotesResult.exitCode !== 0) {
2119
+ return [];
2120
+ }
2121
+ const remotes = String(remotesResult.stdout).split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
2122
+ if (remotes.length === 0) {
2123
+ return [];
2124
+ }
2125
+ const preferred = [];
2126
+ const pushRemote = (remote) => {
2127
+ if (!preferred.includes(remote)) {
2128
+ preferred.push(remote);
2129
+ }
2130
+ };
2131
+ if (await hasGitRemote(repoRoot, "github")) {
2132
+ pushRemote("github");
2133
+ }
2134
+ for (const remote of remotes) {
2135
+ if (remote === "github") {
2136
+ continue;
2137
+ }
2138
+ const urlResult = await runGitCommand(repoRoot, ["remote", "get-url", remote]);
2139
+ const url = urlResult.exitCode === 0 ? String(urlResult.stdout).trim() : "";
2140
+ if (/github\.com[:/]/i.test(url)) {
2141
+ pushRemote(remote);
2142
+ }
2143
+ }
2144
+ for (const remote of remotes) {
2145
+ pushRemote(remote);
2146
+ }
2147
+ return preferred;
2148
+ }
2149
+
2150
+ // packages/isolation-plugin/src/isolation/toolchain.ts
2151
+ import {
2152
+ existsSync as existsSync8,
2153
+ lstatSync,
2154
+ mkdirSync as mkdirSync7,
2155
+ readdirSync,
2156
+ readFileSync as readFileSync5,
2157
+ rmSync as rmSync6,
2158
+ statSync as statSync4,
2159
+ symlinkSync
2160
+ } from "fs";
2161
+ import { mkdir as mkdir2, writeFile } from "fs/promises";
2162
+ import { dirname as dirname5, resolve as resolve8 } from "path";
2163
+ import { assertPathInsideRoot as assertPathInsideRoot2, safePathSegment as safePathSegment2 } from "@rig/core/safe-identifiers";
2164
+
2165
+ // packages/isolation-plugin/src/isolation/runtime-binary-build.ts
2166
+ import { chmodSync as chmodSync3, copyFileSync as copyFileSync4, cpSync as cpSync2, existsSync as existsSync7, linkSync, mkdirSync as mkdirSync6, renameSync as renameSync4, rmSync as rmSync5, writeFileSync as writeFileSync4 } from "fs";
2167
+ import { basename as basename2, dirname as dirname4, resolve as resolve7 } from "path";
2168
+ import { fileURLToPath } from "url";
2169
+ import { drainMicrotasks, gcAndSweep } from "bun:jsc";
2170
+ import { resolveRigLayout } from "@rig/core/layout";
2171
+ import { runtimeProvisioningEnv } from "@rig/core/runtime-provisioning-env";
2172
+ var runtimeRigCliBinaryExternals = ["mupdf"];
2173
+ var runtimeBinaryBuildQueue = Promise.resolve();
2174
+ function materializeSelfExecRole(outputPath, define) {
2175
+ const selfPath = process.execPath;
2176
+ mkdirSync6(dirname4(outputPath), { recursive: true });
2177
+ rmSync5(outputPath, { force: true });
2178
+ try {
2179
+ linkSync(selfPath, outputPath);
2180
+ } catch {
2181
+ copyFileSync4(selfPath, outputPath);
2182
+ }
2183
+ chmodSync3(outputPath, 493);
2184
+ const role = basename2(outputPath).replace(/\.exe$/i, "");
2185
+ writeFileSync4(`${outputPath}.rig-runconfig.json`, `${JSON.stringify({ role, define: define ?? {} }, null, 2)}
2186
+ `, { mode: 384 });
2187
+ }
2188
+ async function buildBinary(entrypoint, outputPath, cwd, defines, external) {
2189
+ if (hasEmbeddedNatives()) {
2190
+ materializeSelfExecRole(outputPath, defines);
2191
+ return;
2192
+ }
2193
+ await buildRuntimeBinary({
2194
+ sourcePath: entrypoint,
2195
+ outputPath,
2196
+ cwd,
2197
+ ...defines ? { define: defines } : {},
2198
+ env: runtimeProvisioningEnv(),
2199
+ ...external ? { external } : {}
2200
+ });
2201
+ }
2202
+ async function buildRuntimeBinary(options) {
2203
+ return runSerializedRuntimeBinaryBuild(async () => {
2204
+ const resolved = resolveRuntimeBinaryBuildOptions(options);
2205
+ runBestEffortBuildGc();
2206
+ const manifestPath = runtimeBinaryCacheManifestPath(resolved.outputPath);
2207
+ const buildKey = createRuntimeBinaryBuildKey({
2208
+ entrypoint: resolved.entrypoint,
2209
+ define: resolved.define,
2210
+ env: resolved.env,
2211
+ external: resolved.external
2212
+ });
2213
+ if (await isRuntimeBinaryBuildFresh({ outputPath: resolved.outputPath, manifestPath, buildKey })) {
2214
+ return;
2215
+ }
2216
+ if (shouldUseRuntimeBinaryBuildWorker()) {
2217
+ await buildRuntimeBinaryViaWorker(resolved);
2218
+ } else {
2219
+ await buildRuntimeBinaryInProcess(resolved, { manifestPath, buildKey });
2220
+ }
2221
+ runBestEffortBuildGc();
2222
+ });
2223
+ }
2224
+ async function buildRuntimeBinaryInProcess(options, manifest) {
2225
+ const tempBuildDir = resolve7(dirname4(options.outputPath), `.bun-build-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
2226
+ const tempOutputPath = resolve7(tempBuildDir, basename2(options.outputPath));
2227
+ mkdirSync6(tempBuildDir, { recursive: true });
2228
+ await withTemporaryEnv({
2229
+ ...options.env,
2230
+ ...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
2231
+ }, async () => withTemporaryCwd(tempBuildDir, async () => {
2232
+ const buildResult = await Bun.build({
2233
+ entrypoints: [options.entrypoint],
2234
+ compile: {
2235
+ target: currentCompileTarget(),
2236
+ outfile: tempOutputPath
2237
+ },
2238
+ target: "bun",
2239
+ format: "esm",
2240
+ minify: true,
2241
+ bytecode: true,
2242
+ metafile: true,
2243
+ ...options.external ? { external: options.external } : {},
2244
+ ...options.define ? { define: { __RIG_BUILD_CONFIG__: JSON.stringify(options.define) } } : {}
2245
+ });
2246
+ if (!buildResult.success) {
2247
+ 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(`
2248
+ `);
2249
+ throw new Error(`Failed to build ${options.entrypoint}: ${details || "Bun.build() returned errors"}`);
2250
+ }
2251
+ if (!existsSync7(tempOutputPath)) {
2252
+ const emitted = buildResult.outputs.map((output) => output.path).join(", ") || "(none)";
2253
+ throw new Error(`Failed to build ${options.entrypoint}: Bun.build() did not emit ${tempOutputPath}. Emitted: ${emitted}`);
2254
+ }
2255
+ renameSync4(tempOutputPath, options.outputPath);
2256
+ chmodSync3(options.outputPath, 493);
2257
+ if (manifest) {
2258
+ await writeRuntimeBinaryCacheManifest({
2259
+ manifestPath: manifest.manifestPath,
2260
+ buildKey: manifest.buildKey,
2261
+ cwd: tempBuildDir,
2262
+ metafile: buildResult.metafile
2263
+ });
2264
+ }
2265
+ })).finally(() => {
2266
+ rmSync5(tempBuildDir, { recursive: true, force: true });
2267
+ });
2268
+ }
2269
+ function runBestEffortBuildGc() {
2270
+ try {
2271
+ drainMicrotasks();
2272
+ } catch {}
2273
+ try {
2274
+ gcAndSweep();
2275
+ } catch {}
2276
+ }
2277
+ function runtimeBinaryCacheManifestPath(outputPath) {
2278
+ return `${outputPath}.build-manifest.json`;
2279
+ }
2280
+ function resolveRuntimeBinaryBuildOptions(options) {
2281
+ return {
2282
+ ...options,
2283
+ entrypoint: resolve7(options.cwd, options.sourcePath),
2284
+ outputPath: resolve7(options.outputPath)
2285
+ };
2286
+ }
2287
+ function shouldUseRuntimeBinaryBuildWorker() {
2288
+ if (process.env.RIG_RUNTIME_BUILD_WORKER === "1") {
2289
+ return false;
2290
+ }
2291
+ if (process.env.RIG_RUNTIME_BUILD_IN_PROCESS === "1") {
2292
+ return false;
2293
+ }
2294
+ return true;
2295
+ }
2296
+ async function buildRuntimeBinaryViaWorker(options) {
2297
+ const workerSourcePath = resolveRuntimeBinaryBuildWorkerSourcePath(options);
2298
+ if (!workerSourcePath || !existsSync7(workerSourcePath)) {
2299
+ await buildRuntimeBinaryInProcess(options, {
2300
+ manifestPath: runtimeBinaryCacheManifestPath(options.outputPath),
2301
+ buildKey: createRuntimeBinaryBuildKey({
2302
+ entrypoint: options.entrypoint,
2303
+ define: options.define,
2304
+ env: options.env,
2305
+ external: options.external
2306
+ })
2307
+ });
2308
+ return;
2309
+ }
2310
+ const payloadPath = createRuntimeBinaryBuildWorkerPayloadPath(options.outputPath);
2311
+ const bunCli = resolveRuntimeBinaryBuildWorkerInvocation();
2312
+ await Bun.write(payloadPath, `${JSON.stringify(options)}
2313
+ `);
2314
+ const build = Bun.spawn([bunCli.command, workerSourcePath, payloadPath], {
2315
+ cwd: options.cwd,
2316
+ stdout: "pipe",
2317
+ stderr: "pipe",
2318
+ env: {
2319
+ ...process.env,
2320
+ ...options.env,
2321
+ ...bunCli.env,
2322
+ RIG_RUNTIME_BUILD_WORKER: "1"
2323
+ }
2324
+ });
2325
+ const [exitCode, stdout, stderr] = await Promise.all([
2326
+ build.exited,
2327
+ new Response(build.stdout).text(),
2328
+ new Response(build.stderr).text()
2329
+ ]);
2330
+ rmSync5(payloadPath, { force: true });
2331
+ if (exitCode !== 0) {
2332
+ throw new Error(`Failed to build ${options.entrypoint}: ${(stderr || stdout || `worker exited ${exitCode}`).trim()}`);
2333
+ }
2334
+ }
2335
+ function createRuntimeBinaryBuildWorkerPayloadPath(outputPath) {
2336
+ return resolve7(dirname4(outputPath), `.bun-build-worker-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
2337
+ }
2338
+ function resolveRuntimeBinaryBuildWorkerSourcePath(options) {
2339
+ const envRoots = [
2340
+ options.cwd?.trim(),
2341
+ process.env.RIG_HOST_PROJECT_ROOT?.trim(),
2342
+ process.env.PROJECT_RIG_ROOT?.trim()
2343
+ ].filter(Boolean);
2344
+ for (const root of envRoots) {
2345
+ const candidate = resolve7(root, "packages/isolation-plugin/src/isolation/binary-build-worker.ts");
2346
+ if (existsSync7(candidate)) {
2347
+ return candidate;
2348
+ }
2349
+ }
2350
+ const localCandidate = resolve7(import.meta.dir, "binary-build-worker.ts");
2351
+ return existsSync7(localCandidate) ? localCandidate : null;
2352
+ }
2353
+ function resolveRuntimeBinaryBuildWorkerInvocation() {
2354
+ const bunPath = Bun.which("bun");
2355
+ if (bunPath) {
2356
+ return { command: bunPath, env: {} };
2357
+ }
2358
+ if (process.execPath?.trim()) {
2359
+ return {
2360
+ command: process.execPath,
2361
+ env: { BUN_BE_BUN: "1" }
2362
+ };
2363
+ }
2364
+ throw new Error("bun is required to run the runtime binary build worker.");
2365
+ }
2366
+ function currentCompileTarget() {
2367
+ if (process.platform === "darwin") {
2368
+ return process.arch === "arm64" ? "bun-darwin-arm64" : "bun-darwin-x64";
2369
+ }
2370
+ if (process.platform === "linux") {
2371
+ return process.arch === "arm64" ? "bun-linux-arm64" : "bun-linux-x64";
2372
+ }
2373
+ return "bun-windows-x64";
2374
+ }
2375
+ function createRuntimeBinaryBuildKey(input) {
2376
+ return JSON.stringify({
2377
+ version: 1,
2378
+ bunVersion: Bun.version,
2379
+ platform: process.platform,
2380
+ arch: process.arch,
2381
+ entrypoint: input.entrypoint,
2382
+ define: sortRecord(input.define),
2383
+ external: input.external ? [...input.external].sort() : undefined,
2384
+ env: sortRecord(input.env)
2385
+ });
2386
+ }
2387
+ async function isRuntimeBinaryBuildFresh(input) {
2388
+ if (!existsSync7(input.outputPath) || !existsSync7(input.manifestPath)) {
2389
+ return false;
2390
+ }
2391
+ let manifest = null;
2392
+ try {
2393
+ manifest = await Bun.file(input.manifestPath).json();
2394
+ } catch {
2395
+ return false;
2396
+ }
2397
+ if (!manifest || manifest.version !== 1 || manifest.buildKey !== input.buildKey) {
2398
+ return false;
2399
+ }
2400
+ for (const [filePath, expectedDigest] of Object.entries(manifest.inputs || {})) {
2401
+ if (!existsSync7(filePath)) {
2402
+ return false;
2403
+ }
2404
+ if (await sha256File2(filePath) !== expectedDigest) {
2405
+ return false;
2406
+ }
2407
+ }
2408
+ return true;
2409
+ }
2410
+ async function writeRuntimeBinaryCacheManifest(input) {
2411
+ const inputs = {};
2412
+ for (const inputPath of Object.keys(input.metafile?.inputs || {}).sort()) {
2413
+ const normalized = normalizeBuildInputPath(input.cwd, inputPath);
2414
+ if (!normalized || !existsSync7(normalized)) {
2415
+ continue;
2416
+ }
2417
+ inputs[normalized] = await sha256File2(normalized);
2418
+ }
2419
+ const manifest = {
2420
+ version: 1,
2421
+ buildKey: input.buildKey,
2422
+ inputs
2423
+ };
2424
+ await Bun.write(input.manifestPath, `${JSON.stringify(manifest, null, 2)}
2425
+ `);
2426
+ }
2427
+ function normalizeBuildInputPath(cwd, inputPath) {
2428
+ if (!inputPath) {
2429
+ return null;
2430
+ }
2431
+ if (inputPath.startsWith("file://")) {
2432
+ return fileURLToPath(inputPath);
2433
+ }
2434
+ if (inputPath.startsWith("<")) {
2435
+ return null;
2436
+ }
2437
+ return resolve7(cwd, inputPath);
2438
+ }
2439
+ async function sha256File2(path) {
2440
+ const hasher = new Bun.CryptoHasher("sha256");
2441
+ hasher.update(await Bun.file(path).arrayBuffer());
2442
+ return hasher.digest("hex");
2443
+ }
2444
+ function sortRecord(value) {
2445
+ if (!value) {
2446
+ return;
2447
+ }
2448
+ return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)));
2449
+ }
2450
+ async function runSerializedRuntimeBinaryBuild(action) {
2451
+ const previous = runtimeBinaryBuildQueue;
2452
+ let release;
2453
+ runtimeBinaryBuildQueue = new Promise((resolve8) => {
2454
+ release = resolve8;
2455
+ });
2456
+ await previous;
2457
+ try {
2458
+ return await action();
2459
+ } finally {
2460
+ release();
2461
+ }
2462
+ }
2463
+ async function withTemporaryEnv(env, action) {
2464
+ if (!env) {
2465
+ return action();
2466
+ }
2467
+ const previousValues = new Map;
2468
+ for (const [key, value] of Object.entries(env)) {
2469
+ previousValues.set(key, process.env[key]);
2470
+ if (value === undefined) {
2471
+ delete process.env[key];
2472
+ } else {
2473
+ process.env[key] = value;
2474
+ }
2475
+ }
2476
+ try {
2477
+ return await action();
2478
+ } finally {
2479
+ for (const [key, value] of previousValues.entries()) {
2480
+ if (value === undefined) {
2481
+ delete process.env[key];
2482
+ } else {
2483
+ process.env[key] = value;
2484
+ }
2485
+ }
2486
+ }
2487
+ }
2488
+ async function withTemporaryCwd(cwd, action) {
2489
+ const previousCwd = process.cwd();
2490
+ process.chdir(cwd);
2491
+ try {
2492
+ return await action();
2493
+ } finally {
2494
+ process.chdir(previousCwd);
2495
+ }
2496
+ }
2497
+
2498
+ // packages/isolation-plugin/src/isolation/toolchain.ts
2499
+ import {
2500
+ GUARD_TOOLCHAIN_SOURCES,
2501
+ LIFECYCLE_TOOLCHAIN_SOURCES,
2502
+ TOOL_MATERIALIZER
2503
+ } from "@rig/contracts";
2504
+ import { defineCapability } from "@rig/core/capability";
2505
+ import { buildProjectPluginHost, requireInstalledCapability } from "@rig/core/capability-loaders";
2506
+ import { resolveBunBinaryPath as resolveBunBinaryPath2 } from "@rig/core/runtime-paths";
2507
+ var ToolMaterializerCap = defineCapability(TOOL_MATERIALIZER);
2508
+ var GuardToolchainSourcesCap = defineCapability(GUARD_TOOLCHAIN_SOURCES);
2509
+ var LifecycleToolchainSourcesCap = defineCapability(LIFECYCLE_TOOLCHAIN_SOURCES);
2510
+ var SNAPSHOT_SIDECAR_SOURCE = ["packages", "isolation-plugin", "src", "snapshot-sidecar.ts"].join("/");
2511
+ async function resolveContributedToolchainSources(projectRoot) {
2512
+ const host = await buildProjectPluginHost(projectRoot);
2513
+ const contributions = [];
2514
+ if (host) {
2515
+ for (const cap of [GuardToolchainSourcesCap, LifecycleToolchainSourcesCap]) {
2516
+ const contribution = await cap.resolve(host);
2517
+ if (contribution)
2518
+ contributions.push(contribution);
2519
+ }
2520
+ }
2521
+ const hookSources = contributions.flatMap((c) => (c.hookBinaries ?? []).map((hb) => [hb.name, hb.source]));
2522
+ const namedSources = {};
2523
+ for (const c of contributions) {
2524
+ for (const [key, value] of Object.entries(c.namedSources ?? {}))
2525
+ namedSources[key] = value;
2526
+ }
2527
+ return { hookSources, namedSources };
2528
+ }
2529
+ var toolMaterializer = () => requireInstalledCapability(ToolMaterializerCap, "tool-materializer capability unavailable: load @rig/provider-plugin (default bundle) before provisioning runtimes.");
2530
+ var GIT_INDEX_LOCK_MAX_RETRIES = 20;
2531
+ var GIT_INDEX_LOCK_RETRY_DELAY_MS = 250;
2532
+ var GIT_INDEX_LOCK_STALE_AFTER_MS = 5000;
2533
+ function resolveRigSourceRoot(projectRoot) {
2534
+ const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim();
2535
+ if (hostProjectRoot && existsSync8(resolve8(hostProjectRoot, "packages/cli/bin/rig-agent.ts"))) {
2536
+ return hostProjectRoot;
2537
+ }
2538
+ const fromModule = resolve8(import.meta.dir, "../../../../../..");
2539
+ if (existsSync8(resolve8(fromModule, "packages/cli/bin/rig-agent.ts"))) {
2540
+ return fromModule;
2541
+ }
2542
+ return projectRoot;
2543
+ }
2544
+ function prepareTrackedRuntimePaths(logsDir, stateDir, sessionDir) {
2545
+ for (const path of [logsDir, stateDir, sessionDir, resolve8(sessionDir, "session.json")]) {
2546
+ removeSymbolicLink(path);
2547
+ }
2548
+ runtimePrepareTrackedPathsNative({
2549
+ logsDir,
2550
+ stateDir,
2551
+ sessionDir,
2552
+ controlledBashLogFile: resolve8(logsDir, "controlled-bash.jsonl"),
2553
+ eventsFile: resolve8(logsDir, "control-plane.events.jsonl")
2554
+ });
2555
+ }
2556
+ async function initializeRuntimeStateFiles(stateDir, sessionDir, taskId) {
2557
+ await mkdir2(stateDir, { recursive: true });
2558
+ await mkdir2(sessionDir, { recursive: true });
2559
+ const failedApproachesPath = resolve8(stateDir, "failed_approaches.md");
2560
+ if (!existsSync8(failedApproachesPath)) {
2561
+ await writeFile(failedApproachesPath, `# Failed Approaches
2562
+
2563
+ `);
2564
+ }
2565
+ const hookTripsPath = resolve8(stateDir, "hook_trips.log");
2566
+ if (!existsSync8(hookTripsPath)) {
2567
+ await writeFile(hookTripsPath, "");
2568
+ }
2569
+ const sessionFile = resolve8(sessionDir, "session.json");
2570
+ if (taskId) {
2571
+ await writeFile(sessionFile, JSON.stringify({ activeTaskIds: [taskId] }));
2572
+ }
2573
+ }
2574
+ async function resetEphemeralTaskArtifacts(workspaceDir, taskId) {
2575
+ const artifactsRoot = resolve8(workspaceDir, "artifacts");
2576
+ const taskSegment = safePathSegment2(taskId, { fallback: "task", maxLength: 96 });
2577
+ const artifactDir = assertPathInsideRoot2(artifactsRoot, resolve8(artifactsRoot, taskSegment), "task artifact directory");
2578
+ const runtimeSnapshotDir = assertPathInsideRoot2(artifactDir, resolve8(artifactDir, "runtime-snapshots"), "runtime snapshot directory");
2579
+ let preservedTrackedFiles = false;
2580
+ for (const file of [
2581
+ "changed-files.txt",
2582
+ "pr-state.json",
2583
+ "review-state.json",
2584
+ "review-feedback.md",
2585
+ "review-greptile-raw.json",
2586
+ "review-status.txt",
2587
+ "validation-summary.json"
2588
+ ]) {
2589
+ const relativePath = `artifacts/${taskSegment}/${file}`;
2590
+ if (await resetTrackedArtifactPath(workspaceDir, relativePath)) {
2591
+ preservedTrackedFiles = true;
2592
+ continue;
2593
+ }
2594
+ rmSync6(assertPathInsideRoot2(artifactDir, resolve8(artifactDir, file), "task artifact file"), { force: true });
2595
+ }
2596
+ const runtimeSnapshotRelativePath = `artifacts/${taskSegment}/runtime-snapshots`;
2597
+ if (await resetTrackedArtifactPath(workspaceDir, runtimeSnapshotRelativePath)) {
2598
+ preservedTrackedFiles = true;
2599
+ } else {
2600
+ rmSync6(runtimeSnapshotDir, { recursive: true, force: true });
2601
+ }
2602
+ if (preservedTrackedFiles) {
2603
+ console.log(`[rig-agent] Preserved tracked runtime artifact files in ${taskId}; skipped ephemeral cleanup for committed paths.`);
2604
+ }
2605
+ }
2606
+ function prepareRuntimeWorkspace(projectRoot, workspaceDir) {
2607
+ const monorepoRoot = resolveMonorepoRoot(projectRoot);
2608
+ linkRuntimeDependencyLayers(monorepoRoot, workspaceDir);
2609
+ syncRuntimeWorkspaceSources(projectRoot, workspaceDir);
2610
+ }
2611
+ async function materializeRuntimeHostToolWrappers(binDir) {
2612
+ const mat = toolMaterializer();
2613
+ await mat.materializeRuntimeToolGateway(binDir);
2614
+ await mat.materializeRuntimeFileTools(binDir);
2615
+ }
2616
+ async function buildRuntimeToolchain(options) {
2617
+ const { hookSources, namedSources } = await resolveContributedToolchainSources(options.projectRoot);
2618
+ const controlledBashSource = namedSources["controlled-bash"];
2619
+ const runtimeBins = ensureRuntimeBinTrees(options.binDir);
2620
+ const nativeRuntimeLibraryPath = await materializeNativeRuntimeLibrary(options.binDir);
2621
+ if (!nativeRuntimeLibraryPath) {
2622
+ throw new Error("Failed to provision the native Zig runtime library.");
2623
+ }
2624
+ const rigSourceRoot = resolveRigSourceRoot(options.projectRoot);
2625
+ await buildBinary("packages/cli/bin/rig.ts", resolve8(options.binDir, "rig"), rigSourceRoot, undefined, runtimeRigCliBinaryExternals);
2626
+ await buildBinary("packages/cli/bin/rig-agent.ts", resolve8(options.binDir, "rig-agent"), rigSourceRoot, {
2627
+ ...options.runtimeSecretDefines,
2628
+ AGENT_TASK_ID: options.taskId,
2629
+ AGENT_PROJECT_ROOT: options.projectRoot,
2630
+ AGENT_RUNTIME_ID: options.runtimeId,
2631
+ AGENT_SCOPE_HASH: options.bakedScopeHash,
2632
+ AGENT_MANIFEST_PATH: options.manifestPath,
2633
+ AGENT_BINARY_PATH: resolve8(options.binDir, "rig-agent"),
2634
+ AGENT_INFO_OUTPUT: options.bakedInfoOutput,
2635
+ AGENT_DEPS_OUTPUT: options.bakedDepsOutput,
2636
+ AGENT_STATUS_OUTPUT: options.bakedStatusOutput
2637
+ });
2638
+ if (controlledBashSource) {
2639
+ await buildBinary(controlledBashSource, resolve8(options.binDir, "controlled-bash"), rigSourceRoot, {
2640
+ AGENT_PROJECT_ROOT: options.projectRoot,
2641
+ AGENT_LOGS_DIR: options.logsDir,
2642
+ AGENT_MONOREPO_ROOT: resolveMonorepoRoot(options.projectRoot),
2643
+ AGENT_TS_API_TESTS_DIR: resolve8(options.workspaceDir, "TSAPITests"),
2644
+ AGENT_RIG_AGENT_BIN: resolve8(options.binDir, "rig-agent")
2645
+ });
2646
+ }
2647
+ await buildBinary("packages/cli/bin/rig-browser-tool.ts", resolve8(options.binDir, toolMaterializer().runtimeBrowserToolBinaryName()), rigSourceRoot);
2648
+ await buildBinary(SNAPSHOT_SIDECAR_SOURCE, resolve8(options.binDir, "snapshot-sidecar"), rigSourceRoot, {
2649
+ AGENT_PROJECT_ROOT: options.projectRoot,
2650
+ AGENT_BUN_PATH: resolveBunBinaryPath2()
2651
+ });
2652
+ const hookDefines = {
2653
+ AGENT_PROJECT_ROOT: options.projectRoot,
2654
+ AGENT_BUN_PATH: resolveBunBinaryPath2()
2655
+ };
2656
+ for (const [hookName, hookSource] of hookSources) {
2657
+ await buildBinary(hookSource, resolve8(runtimeBins.hooksDir, hookName), rigSourceRoot, hookDefines);
2658
+ }
2659
+ const pluginsDir = resolve8(options.projectRoot, "rig/plugins");
2660
+ if (existsSync8(pluginsDir)) {
2661
+ for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
2662
+ const match = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
2663
+ if (!match)
2664
+ continue;
2665
+ await buildBinary(`rig/plugins/${entry.name}`, resolve8(runtimeBins.pluginsDir, match[1]), options.projectRoot);
2666
+ }
2667
+ }
2668
+ await materializeRigGitBinary(options.binDir);
2669
+ const mat = toolMaterializer();
2670
+ await mat.materializeClaudeToolRouterBinary(rigSourceRoot, options.binDir);
2671
+ await materializeRuntimeHostToolWrappers(options.binDir);
2672
+ await mat.materializeRuntimeBrowserTools(options.binDir);
2673
+ }
2674
+ async function writeRuntimeManifest(config) {
2675
+ const scopeHash = sha256Hex(JSON.stringify(config.scopes));
2676
+ const binarySha256 = sha256Hex(readFileSync5(config.binaryPath));
2677
+ const manifestPath = resolve8(config.runtimeRoot, "manifest.json");
2678
+ const manifest = {
2679
+ runtimeId: config.runtimeId,
2680
+ taskId: config.taskId,
2681
+ scopeHash,
2682
+ builtAt: new Date().toISOString(),
2683
+ workspaceDir: config.workspaceDir,
2684
+ binDir: config.binDir,
2685
+ binary: {
2686
+ path: config.binaryPath,
2687
+ sha256: binarySha256
2688
+ }
2689
+ };
2690
+ await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
2691
+ `, "utf-8");
2692
+ }
2693
+ function syncRuntimeWorkspaceSources(projectRoot, workspaceDir) {}
2694
+ function removeSymbolicLink(path) {
2695
+ try {
2696
+ if (!lstatSync(path).isSymbolicLink()) {
2697
+ return;
2698
+ }
2699
+ } catch {
2700
+ return;
2701
+ }
2702
+ rmSync6(path, { force: true, recursive: true });
2703
+ }
2704
+ async function resetTrackedArtifactPath(workspaceDir, relativePath) {
2705
+ const tracked = await runGitLsFiles(workspaceDir, relativePath);
2706
+ if (!tracked) {
2707
+ return false;
2708
+ }
2709
+ await restoreTrackedArtifactPathWithRetry(workspaceDir, relativePath, async () => {
2710
+ const restore = await Bun.$`git -C ${workspaceDir} checkout -- ${relativePath}`.quiet().nothrow();
2711
+ return {
2712
+ exitCode: restore.exitCode,
2713
+ output: restore.stderr.toString() || restore.stdout.toString()
2714
+ };
2715
+ }, { sleep: Bun.sleep });
2716
+ return true;
2717
+ }
2718
+ async function runGitLsFiles(workspaceDir, relativePath) {
2719
+ const tracked = await Bun.$`git -C ${workspaceDir} ls-files --error-unmatch -- ${relativePath}`.quiet().nothrow();
2720
+ return tracked.exitCode === 0;
2721
+ }
2722
+ async function restoreTrackedArtifactPathWithRetry(workspaceDir, relativePath, restorePath, options = {}) {
2723
+ const sleep = options.sleep ?? Bun.sleep;
2724
+ const maxRetries = options.maxRetries ?? GIT_INDEX_LOCK_MAX_RETRIES;
2725
+ const retryDelayMs = options.retryDelayMs ?? GIT_INDEX_LOCK_RETRY_DELAY_MS;
2726
+ const now = options.now ?? Date.now;
2727
+ const statMtimeMs = options.statMtimeMs ?? readFileMtimeMs;
2728
+ const removeFile = options.removeFile ?? ((path) => rmSync6(path, { force: true }));
2729
+ const log = options.log ?? console.warn;
2730
+ let lastOutput = "";
2731
+ for (let attempt = 0;attempt <= maxRetries; attempt += 1) {
2732
+ const restore = await restorePath();
2733
+ if (restore.exitCode === 0) {
2734
+ return;
2735
+ }
2736
+ lastOutput = restore.output;
2737
+ if (!isGitIndexLockError(lastOutput)) {
2738
+ break;
2739
+ }
2740
+ const lockPath = parseGitIndexLockPath(lastOutput);
2741
+ if (attempt === maxRetries) {
2742
+ if (lockPath && tryClearStaleGitIndexLock(lockPath, {
2743
+ now,
2744
+ statMtimeMs,
2745
+ removeFile,
2746
+ log
2747
+ })) {
2748
+ const recovered = await restorePath();
2749
+ if (recovered.exitCode === 0) {
2750
+ return;
2751
+ }
2752
+ lastOutput = recovered.output;
2753
+ }
2754
+ break;
2755
+ }
2756
+ await sleep(retryDelayMs);
2757
+ }
2758
+ throw new Error(`Failed to restore tracked runtime artifact path ${relativePath} in ${workspaceDir}: ${lastOutput}`);
2759
+ }
2760
+ function isGitIndexLockError(output) {
2761
+ return /index\.lock|Unable to create '.+index\.lock'.*File exists/i.test(output);
2762
+ }
2763
+ function parseGitIndexLockPath(output) {
2764
+ const match = output.match(/Unable to create '([^']+index\.lock)'/i);
2765
+ return match?.[1] ?? null;
2766
+ }
2767
+ function tryClearStaleGitIndexLock(lockPath, options) {
2768
+ const mtimeMs = options.statMtimeMs(lockPath);
2769
+ if (mtimeMs === null) {
2770
+ return false;
2771
+ }
2772
+ if (options.now() - mtimeMs < GIT_INDEX_LOCK_STALE_AFTER_MS) {
2773
+ return false;
2774
+ }
2775
+ options.removeFile(lockPath);
2776
+ options.log(`[rig-agent] Cleared stale git index lock during run recovery: ${lockPath}`);
2777
+ return true;
2778
+ }
2779
+ function readFileMtimeMs(path) {
2780
+ try {
2781
+ return statSync4(path).mtimeMs;
2782
+ } catch {
2783
+ return null;
2784
+ }
2785
+ }
2786
+ function linkRuntimeDependencyLayers(monorepoRoot, workspaceDir) {
2787
+ linkGenericNodeModulesLayers(monorepoRoot, workspaceDir);
2788
+ const sourceNodeModules = resolve8(monorepoRoot, "humoongate", "node_modules");
2789
+ if (!existsSync8(sourceNodeModules)) {} else {
2790
+ const runtimeHumoongate = resolve8(workspaceDir, "humoongate");
2791
+ if (existsSync8(resolve8(runtimeHumoongate, "package.json"))) {
2792
+ const targetNodeModules = resolve8(runtimeHumoongate, "node_modules");
2793
+ runtimeLinkDependencyLayerNative(sourceNodeModules, targetNodeModules);
2794
+ }
2795
+ }
2796
+ const runtimeHpNext = resolve8(workspaceDir, "microservices", "hp-next-frontend", "app");
2797
+ if (!existsSync8(resolve8(runtimeHpNext, "package.json"))) {
2798
+ return;
2799
+ }
2800
+ const sourceHpNextNodeModules = resolve8(monorepoRoot, "microservices", "hp-next-frontend", "app", "node_modules");
2801
+ const sourceMonorepoNodeModules = resolve8(monorepoRoot, "node_modules");
2802
+ const targetHpNextNodeModules = resolve8(runtimeHpNext, "node_modules");
2803
+ if (existsSync8(sourceHpNextNodeModules)) {
2804
+ runtimeLinkDependencyLayerNative(sourceHpNextNodeModules, targetHpNextNodeModules);
2805
+ return;
2806
+ }
2807
+ if (existsSync8(sourceMonorepoNodeModules)) {
2808
+ runtimeLinkDependencyLayerNative(sourceMonorepoNodeModules, targetHpNextNodeModules);
2809
+ }
2810
+ }
2811
+ function linkGenericNodeModulesLayers(monorepoRoot, workspaceDir) {
2812
+ linkNodeModulesLayer(resolve8(monorepoRoot, "node_modules"), resolve8(workspaceDir, "node_modules"));
2813
+ for (const relativePackageDir of [
2814
+ "apps/native-app/apps/marketing",
2815
+ "apps/native-app/apps/web",
2816
+ "apps/native-app/apps/browser",
2817
+ "apps/native-app/apps/desktop",
2818
+ "apps/native-app/scripts",
2819
+ "packages/cli",
2820
+ "packages/client",
2821
+ "packages/contracts",
2822
+ "packages/core",
2823
+ "packages/hook-kit",
2824
+ "packages/plugin-testkit",
2825
+ "packages/runtime",
2826
+ "packages/scripts",
2827
+ "packages/shared",
2828
+ "packages/skill-loader",
2829
+ "packages/standard-plugin",
2830
+ "packages/validator-kit"
2831
+ ]) {
2832
+ const workspacePackageDir = resolve8(workspaceDir, relativePackageDir);
2833
+ if (!existsSync8(resolve8(workspacePackageDir, "package.json"))) {
2834
+ continue;
2835
+ }
2836
+ linkNodeModulesLayer(resolve8(monorepoRoot, relativePackageDir, "node_modules"), resolve8(workspacePackageDir, "node_modules"));
2837
+ }
2838
+ }
2839
+ function linkNodeModulesLayer(sourceDir, targetDir) {
2840
+ if (!existsSync8(sourceDir) || existsSync8(targetDir)) {
2841
+ return;
2842
+ }
2843
+ try {
2844
+ runtimeLinkDependencyLayerNative(sourceDir, targetDir);
2845
+ return;
2846
+ } catch (error) {
2847
+ console.warn(`[rig-agent] Native dependency-layer linking failed for ${targetDir}; using symlink fallback: ${error instanceof Error ? error.message : String(error)}`);
2848
+ }
2849
+ mkdirSync7(dirname5(targetDir), { recursive: true });
2850
+ symlinkSync(sourceDir, targetDir, "dir");
2851
+ }
2852
+ function ensureRuntimeBinTrees(runtimeBinDir) {
2853
+ const hooksDir = resolve8(runtimeBinDir, "hooks");
2854
+ const pluginsDir = resolve8(runtimeBinDir, "plugins");
2855
+ const validatorsDir = resolve8(runtimeBinDir, "validators");
2856
+ mkdirSync7(hooksDir, { recursive: true });
2857
+ mkdirSync7(pluginsDir, { recursive: true });
2858
+ mkdirSync7(validatorsDir, { recursive: true });
2859
+ return { hooksDir, pluginsDir, validatorsDir };
2860
+ }
2861
+ function runtimeWorktreeId(workspaceDir) {
2862
+ return workspaceDir.split("/").at(-1) || "runtime";
2863
+ }
2864
+
2865
+ // packages/isolation-plugin/src/isolation/discovery.ts
2866
+ async function readRuntimeMetadata(metadataPath) {
2867
+ if (!existsSync9(metadataPath)) {
2868
+ return null;
2869
+ }
2870
+ try {
2871
+ return await Bun.file(metadataPath).json();
2872
+ } catch {
2873
+ return null;
2874
+ }
2875
+ }
2876
+ async function listAgentRuntimes(projectRoot) {
2877
+ const runtimes = [];
2878
+ const monorepoRoot = resolveMonorepoRoot(projectRoot);
2879
+ const worktreesRoot = resolve9(monorepoRoot, ".worktrees");
2880
+ if (!existsSync9(worktreesRoot)) {
2881
+ return [];
2882
+ }
2883
+ const workspaces = runtimeScanWorktreesNative(worktreesRoot);
2884
+ for (let scan of workspaces) {
2885
+ let workspacePath = scan.workspaceDir;
2886
+ const workspaceLayout = resolveRuntimeWorkspaceLayout(workspacePath);
2887
+ const rootDir = scan.runtimeDir || workspaceLayout.runtimeDir;
2888
+ const metadataPath = scan.metadataPath || resolve9(rootDir, "runtime.json");
2889
+ const contextFile = scan.contextPath || workspaceLayout.contextPath;
2890
+ let mode = "worktree";
2891
+ let createdAt = new Date().toISOString();
2892
+ let taskId = "";
2893
+ let runtimeId = "";
2894
+ let binDir = workspaceLayout.binDir;
2895
+ let logsDir = workspaceLayout.logsDir;
2896
+ let stateDir = workspaceLayout.stateDir;
2897
+ let sessionDir = workspaceLayout.sessionDir;
2898
+ const metadata = await readRuntimeMetadata(metadataPath);
2899
+ if (metadata) {
2900
+ runtimeId = metadata.id;
2901
+ mode = metadata.mode;
2902
+ createdAt = metadata.createdAt;
2903
+ }
2904
+ if (existsSync9(contextFile)) {
2905
+ try {
2906
+ const ctx = loadRuntimeContext2(contextFile);
2907
+ taskId = ctx.taskId;
2908
+ workspacePath = ctx.workspaceDir;
2909
+ binDir = ctx.binDir;
2910
+ logsDir = ctx.logsDir;
2911
+ stateDir = ctx.stateDir;
2912
+ sessionDir = ctx.sessionDir;
2913
+ } catch {}
2914
+ }
2915
+ if (!runtimeId) {
2916
+ runtimeId = taskRuntimeId(taskId || runtimeWorktreeId(workspacePath));
2917
+ }
2918
+ runtimes.push({
2919
+ id: runtimeId,
2920
+ taskId,
2921
+ mode,
2922
+ rootDir,
2923
+ workspaceDir: workspacePath,
2924
+ homeDir: resolve9(rootDir, "home"),
2925
+ tmpDir: resolve9(rootDir, "tmp"),
2926
+ cacheDir: resolve9(rootDir, "cache"),
2927
+ logsDir,
2928
+ stateDir,
2929
+ sessionDir,
2930
+ claudeHomeDir: resolve9(rootDir, "home", ".claude"),
2931
+ contextFile,
2932
+ binDir,
2933
+ createdAt
2934
+ });
2935
+ }
2936
+ return runtimes;
2937
+ }
2938
+ function runtimeRootForCleanup(projectRoot, runtimeId) {
2939
+ let monorepoRoot = null;
2940
+ try {
2941
+ monorepoRoot = resolveMonorepoRoot(projectRoot);
2942
+ } catch {}
2943
+ const workspaceRootCandidate = monorepoRoot ?? projectRoot;
2944
+ const initialWorkspaceDir = resolve9(workspaceRootCandidate, ".worktrees", runtimeWorktreeNameFromRuntimeId(runtimeId));
2945
+ const runtimeRoot = resolveRuntimeWorkspaceLayout(initialWorkspaceDir).runtimeDir;
2946
+ return { monorepoRoot, initialWorkspaceDir, runtimeRoot };
2947
+ }
2948
+
2949
+ // packages/isolation-plugin/src/isolation/runner.ts
2950
+ import { existsSync as existsSync13, rmSync as rmSync7, writeFileSync as writeFileSync6 } from "fs";
2951
+ import { basename as basename4, resolve as resolve14 } from "path";
2952
+
2953
+ // packages/isolation-plugin/src/sandbox/backend.ts
2954
+ import { existsSync as existsSync12 } from "fs";
2955
+
2956
+ // packages/isolation-plugin/src/runtime-config.ts
2957
+ import { existsSync as existsSync10, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
2958
+ import { resolve as resolve10 } from "path";
2959
+ import {
2960
+ POLICY_VERSION
2961
+ } from "@rig/contracts";
2962
+ var DEFAULT_SCOPE = {
2963
+ fail_closed: true,
2964
+ harness_paths_exempt: true,
2965
+ runtime_paths_exempt: true
2966
+ };
2967
+ var DEFAULT_SANDBOX = {
2968
+ mode: "enforce",
2969
+ network: true,
2970
+ read_deny: [],
2971
+ write_allow_from_runtime: true
2972
+ };
2973
+ var DEFAULT_ISOLATION = {
2974
+ default_mode: "worktree",
2975
+ repo_symlink_fallback: false,
2976
+ strict_provisioning: true,
2977
+ fail_closed_on_provision_error: true
2978
+ };
2979
+ var DEFAULT_COMPLETION = {
2980
+ derive_checks_from_scope: true,
2981
+ checks: [],
2982
+ typescript_config_probe: ["tsconfig.json"],
2983
+ eslint_config_probe: [".eslintrc.js", ".eslintrc.json", "eslint.config.js"]
2984
+ };
2985
+ var DEFAULT_RUNTIME_IMAGE = {
2986
+ deps: { monorepo_install: false, hp_next_install: false },
2987
+ plugins_require_binaries: true
2988
+ };
2989
+ var DEFAULT_RUNTIME_SNAPSHOT = { enabled: true };
2990
+ var policyCache = null;
2991
+ var policyCachePath = null;
2992
+ function loadSandboxConfig(projectRoot) {
2993
+ return loadPolicy(projectRoot).sandbox;
2994
+ }
2995
+ function defaultPolicy() {
2996
+ return {
2997
+ version: POLICY_VERSION,
2998
+ mode: "enforce",
2999
+ scope: { ...DEFAULT_SCOPE },
3000
+ rules: [],
3001
+ sandbox: { ...DEFAULT_SANDBOX },
3002
+ isolation: { ...DEFAULT_ISOLATION },
3003
+ completion: { ...DEFAULT_COMPLETION },
3004
+ runtime_image: {
3005
+ deps: { ...DEFAULT_RUNTIME_IMAGE.deps },
3006
+ plugins_require_binaries: DEFAULT_RUNTIME_IMAGE.plugins_require_binaries
3007
+ },
3008
+ runtime_snapshot: { ...DEFAULT_RUNTIME_SNAPSHOT }
3009
+ };
3010
+ }
3011
+ function loadPolicy(projectRoot) {
3012
+ const configPath = resolve10(projectRoot, "rig/policy/policy.json");
3013
+ if (!existsSync10(configPath))
3014
+ return defaultPolicy();
3015
+ let mtimeMs;
3016
+ try {
3017
+ mtimeMs = statSync5(configPath).mtimeMs;
3018
+ } catch {
3019
+ return defaultPolicy();
3020
+ }
3021
+ if (policyCache && policyCachePath === configPath && policyCache.mtimeMs === mtimeMs) {
3022
+ return policyCache.config;
3023
+ }
3024
+ try {
3025
+ const config = mergeWithDefaults(JSON.parse(readFileSync6(configPath, "utf-8")));
3026
+ policyCache = { mtimeMs, config };
3027
+ policyCachePath = configPath;
3028
+ return config;
3029
+ } catch {
3030
+ return defaultPolicy();
3031
+ }
3032
+ }
3033
+ function mergeWithDefaults(parsed) {
3034
+ const base = defaultPolicy();
3035
+ if (typeof parsed.mode === "string" && isValidMode(parsed.mode))
3036
+ base.mode = parsed.mode;
3037
+ if (parsed.scope && typeof parsed.scope === "object" && !Array.isArray(parsed.scope)) {
3038
+ const scope = parsed.scope;
3039
+ if (typeof scope.fail_closed === "boolean")
3040
+ base.scope.fail_closed = scope.fail_closed;
3041
+ if (typeof scope.harness_paths_exempt === "boolean")
3042
+ base.scope.harness_paths_exempt = scope.harness_paths_exempt;
3043
+ if (typeof scope.runtime_paths_exempt === "boolean")
3044
+ base.scope.runtime_paths_exempt = scope.runtime_paths_exempt;
3045
+ }
3046
+ if (Array.isArray(parsed.rules))
3047
+ base.rules = precompilePolicyRuleRegexes(parsed.rules.filter(isValidRule));
3048
+ if (Array.isArray(parsed.deny) && base.rules.length === 0) {
3049
+ base.rules = precompilePolicyRuleRegexes(migrateLegacyDeny(parsed.deny));
3050
+ }
3051
+ if (parsed.sandbox && typeof parsed.sandbox === "object" && !Array.isArray(parsed.sandbox)) {
3052
+ const sandbox = parsed.sandbox;
3053
+ if (typeof sandbox.mode === "string" && isValidMode(sandbox.mode))
3054
+ base.sandbox.mode = sandbox.mode;
3055
+ if (typeof sandbox.network === "boolean")
3056
+ base.sandbox.network = sandbox.network;
3057
+ if (Array.isArray(sandbox.read_deny))
3058
+ base.sandbox.read_deny = sandbox.read_deny.filter((value) => typeof value === "string");
3059
+ if (typeof sandbox.write_allow_from_runtime === "boolean")
3060
+ base.sandbox.write_allow_from_runtime = sandbox.write_allow_from_runtime;
3061
+ }
3062
+ if (parsed.isolation && typeof parsed.isolation === "object" && !Array.isArray(parsed.isolation)) {
3063
+ const isolation = parsed.isolation;
3064
+ if (isolation.default_mode === "worktree")
3065
+ base.isolation.default_mode = isolation.default_mode;
3066
+ if (typeof isolation.repo_symlink_fallback === "boolean")
3067
+ base.isolation.repo_symlink_fallback = isolation.repo_symlink_fallback;
3068
+ if (typeof isolation.strict_provisioning === "boolean")
3069
+ base.isolation.strict_provisioning = isolation.strict_provisioning;
3070
+ if (typeof isolation.fail_closed_on_provision_error === "boolean")
3071
+ base.isolation.fail_closed_on_provision_error = isolation.fail_closed_on_provision_error;
3072
+ }
3073
+ if (parsed.completion && typeof parsed.completion === "object" && !Array.isArray(parsed.completion)) {
3074
+ const completion = parsed.completion;
3075
+ if (typeof completion.derive_checks_from_scope === "boolean")
3076
+ base.completion.derive_checks_from_scope = completion.derive_checks_from_scope;
3077
+ if (Array.isArray(completion.checks))
3078
+ base.completion.checks = completion.checks.filter((value) => typeof value === "string");
3079
+ if (Array.isArray(completion.typescript_config_probe))
3080
+ base.completion.typescript_config_probe = completion.typescript_config_probe.filter((value) => typeof value === "string");
3081
+ if (Array.isArray(completion.eslint_config_probe))
3082
+ base.completion.eslint_config_probe = completion.eslint_config_probe.filter((value) => typeof value === "string");
3083
+ }
3084
+ if (parsed.runtime_image && typeof parsed.runtime_image === "object" && !Array.isArray(parsed.runtime_image)) {
3085
+ const runtimeImage = parsed.runtime_image;
3086
+ if (runtimeImage.deps && typeof runtimeImage.deps === "object" && !Array.isArray(runtimeImage.deps)) {
3087
+ const deps = runtimeImage.deps;
3088
+ if (typeof deps.monorepo_install === "boolean")
3089
+ base.runtime_image.deps.monorepo_install = deps.monorepo_install;
3090
+ if (typeof deps.hp_next_install === "boolean")
3091
+ base.runtime_image.deps.hp_next_install = deps.hp_next_install;
3092
+ }
3093
+ if (typeof runtimeImage.plugins_require_binaries === "boolean")
3094
+ base.runtime_image.plugins_require_binaries = runtimeImage.plugins_require_binaries;
3095
+ }
3096
+ if (parsed.runtime_snapshot && typeof parsed.runtime_snapshot === "object" && !Array.isArray(parsed.runtime_snapshot)) {
3097
+ const runtimeSnapshot = parsed.runtime_snapshot;
3098
+ if (typeof runtimeSnapshot.enabled === "boolean")
3099
+ base.runtime_snapshot.enabled = runtimeSnapshot.enabled;
3100
+ }
3101
+ return base;
3102
+ }
3103
+ function isValidMode(value) {
3104
+ return value === "off" || value === "observe" || value === "enforce";
3105
+ }
3106
+ function isValidRule(value) {
3107
+ if (!value || typeof value !== "object" || Array.isArray(value))
3108
+ return false;
3109
+ const rule = value;
3110
+ return typeof rule.id === "string" && typeof rule.category === "string" && !!rule.match && typeof rule.match === "object";
3111
+ }
3112
+ function migrateLegacyDeny(deny) {
3113
+ const rules = [];
3114
+ for (const entry of deny) {
3115
+ if (typeof entry.id !== "string")
3116
+ continue;
3117
+ const match = {};
3118
+ if (typeof entry.pattern === "string")
3119
+ match.pattern = entry.pattern;
3120
+ if (typeof entry.regex === "string")
3121
+ match.regex = entry.regex;
3122
+ if (!match.pattern && !match.regex)
3123
+ continue;
3124
+ const rule = {
3125
+ id: entry.id,
3126
+ category: "command",
3127
+ match,
3128
+ action: entry.action === "warn" ? "warn" : "block"
3129
+ };
3130
+ if (typeof entry.reason === "string") {
3131
+ rule.description = entry.reason;
3132
+ }
3133
+ rules.push(rule);
3134
+ }
3135
+ return rules;
3136
+ }
3137
+ function precompilePolicyRuleRegexes(rules) {
3138
+ return rules.map((rule) => {
3139
+ const compiled = { ...rule };
3140
+ const matchRegex = compileRegex(rule.match?.regex);
3141
+ const unlessRegex = compileRegex(rule.unless?.regex);
3142
+ if (matchRegex) {
3143
+ compiled.compiledRegex = matchRegex;
3144
+ }
3145
+ if (unlessRegex) {
3146
+ compiled.compiledUnlessRegex = unlessRegex;
3147
+ }
3148
+ return compiled;
3149
+ });
3150
+ }
3151
+ function compileRegex(pattern) {
3152
+ if (!pattern)
3153
+ return;
3154
+ try {
3155
+ return new RegExp(pattern);
3156
+ } catch {
3157
+ return;
3158
+ }
3159
+ }
3160
+
3161
+ // packages/isolation-plugin/src/sandbox/backend.ts
3162
+ init_utils();
3163
+ import {
3164
+ resolveBunInstallDir as resolveBunInstallDir2,
3165
+ resolveClaudeInstallDir as resolveClaudeInstallDir2,
3166
+ resolveNodeInstallDir as resolveNodeInstallDir2,
3167
+ resolveRuntimeDependencyRoots
3168
+ } from "@rig/core/runtime-paths";
3169
+
3170
+ // packages/isolation-plugin/src/sandbox/backend-none.ts
3171
+ class NoSandboxBackend {
3172
+ kind = "none";
3173
+ reason;
3174
+ constructor(reason) {
3175
+ this.reason = reason;
3176
+ }
3177
+ wrap(options) {
3178
+ return {
3179
+ command: options.command,
3180
+ enabled: false,
3181
+ backend: "none",
3182
+ ...this.reason !== undefined ? { reason: this.reason } : {}
3183
+ };
3184
+ }
3185
+ }
3186
+
3187
+ // packages/isolation-plugin/src/sandbox/backend.ts
3188
+ class SandboxError extends Error {
3189
+ code;
3190
+ constructor(code, message) {
3191
+ super(message);
3192
+ this.code = code;
3193
+ this.name = "SandboxError";
3194
+ }
3195
+ }
3196
+ function resolveRuntimeSandboxModeWithPolicy(sandboxConfig, envOverride) {
3197
+ if (envOverride) {
3198
+ const normalized = envOverride.trim().toLowerCase();
3199
+ if (normalized === "off" || normalized === "auto" || normalized === "enforce") {
3200
+ if (normalized !== sandboxConfig.mode) {
3201
+ console.warn(`[sandbox] RIG_RUNTIME_SANDBOX=${normalized} overrides policy sandbox.mode=${sandboxConfig.mode}`);
3202
+ }
3203
+ return normalized;
3204
+ }
3205
+ }
3206
+ const policyMode = sandboxConfig.mode;
3207
+ if (policyMode === "off")
3208
+ return "off";
3209
+ if (policyMode === "observe")
3210
+ return "auto";
3211
+ return "enforce";
3212
+ }
3213
+ var bwrapProbeCache = null;
3214
+ async function probeBubblewrap(binary) {
3215
+ if (bwrapProbeCache !== null) {
3216
+ return bwrapProbeCache;
3217
+ }
3218
+ const probe = await Bun.$`${binary} ${["--ro-bind", "/", "/", "--proc", "/proc", "--dev", "/dev", "--", "true"]}`.quiet().nothrow();
3219
+ bwrapProbeCache = probe.exitCode === 0;
3220
+ return bwrapProbeCache;
3221
+ }
3222
+ async function resolveBackend(projectRoot, options) {
3223
+ const config = loadSandboxConfig(projectRoot);
3224
+ const mode = resolveRuntimeSandboxModeWithPolicy(config, options?.envOverride);
3225
+ const probed = [];
3226
+ if (mode === "off") {
3227
+ return {
3228
+ backend: new NoSandboxBackend,
3229
+ selectedKind: "none",
3230
+ probed,
3231
+ reason: "disabled-by-config"
3232
+ };
3233
+ }
3234
+ const explicitBackend = options?.backendOverride ?? process.env.RIG_SANDBOX_BACKEND?.trim().toLowerCase();
3235
+ const requestedBackend = resolveExplicitBackend(explicitBackend);
3236
+ if (requestedBackend) {
3237
+ if (requestedBackend === "docker") {
3238
+ throw new SandboxError("backend-unavailable", `Backend "docker" is not yet implemented.`);
3239
+ }
3240
+ if (requestedBackend === "none") {
3241
+ return {
3242
+ backend: new NoSandboxBackend("explicit-none"),
3243
+ selectedKind: "none",
3244
+ probed,
3245
+ reason: "explicit-none"
3246
+ };
3247
+ }
3248
+ }
3249
+ const bunDir = resolveBunInstallDir2();
3250
+ const claudeDir = (() => {
3251
+ try {
3252
+ return resolveClaudeInstallDir2();
3253
+ } catch {
3254
+ return null;
3255
+ }
3256
+ })();
3257
+ const nodeDir = resolveNodeInstallDir2();
3258
+ const depRoots = resolveRuntimeDependencyRoots([bunDir, claudeDir, nodeDir].filter(Boolean));
3259
+ const resolvedPaths = {
3260
+ bunDir,
3261
+ claudeDir,
3262
+ nodeDir,
3263
+ depRoots
3264
+ };
3265
+ const fsContext = {
3266
+ pathExists: (p) => existsSync12(p),
3267
+ realPath: toRealPath
3268
+ };
3269
+ if (process.platform === "darwin" && (!requestedBackend || requestedBackend === "macos-seatbelt")) {
3270
+ const seatbelt = Bun.which("sandbox-exec");
3271
+ probed.push("sandbox-exec");
3272
+ if (seatbelt && existsSync12(seatbelt)) {
3273
+ const SeatbeltBackendClass = loadSeatbeltBackend();
3274
+ if (SeatbeltBackendClass) {
3275
+ return {
3276
+ backend: new SeatbeltBackendClass(seatbelt, config, fsContext, resolvedPaths),
3277
+ selectedKind: "macos-seatbelt",
3278
+ probed,
3279
+ reason: "detected-seatbelt"
3280
+ };
3281
+ }
3282
+ return handleUnavailableBackend(mode, probed, "macos-seatbelt", "Seatbelt sandbox backend module failed to load.", "seatbelt-backend-module-unavailable", { explicit: requestedBackend === "macos-seatbelt" });
3283
+ }
3284
+ }
3285
+ if (process.platform === "linux" && (!requestedBackend || requestedBackend === "linux-bwrap")) {
3286
+ const bwrap = Bun.which("bwrap");
3287
+ probed.push("bwrap");
3288
+ if (bwrap && await probeBubblewrap(bwrap)) {
3289
+ const BwrapBackendClass = loadBwrapBackend();
3290
+ if (BwrapBackendClass) {
3291
+ return {
3292
+ backend: new BwrapBackendClass(bwrap, config, fsContext, resolvedPaths),
3293
+ selectedKind: "linux-bwrap",
3294
+ probed,
3295
+ reason: "detected-bwrap"
3296
+ };
3297
+ }
3298
+ return handleUnavailableBackend(mode, probed, "linux-bwrap", "Bubblewrap sandbox backend module failed to load.", "bwrap-backend-module-unavailable", { explicit: requestedBackend === "linux-bwrap" });
3299
+ }
3300
+ }
3301
+ if (requestedBackend) {
3302
+ return handleUnavailableBackend(mode, probed, requestedBackend, `Explicit sandbox backend "${requestedBackend}" is unavailable on ${process.platform}.`, "explicit-backend-unavailable", { explicit: true });
3303
+ }
3304
+ if (mode === "enforce") {
3305
+ throw new SandboxError("backend-unavailable", `Runtime sandbox required (mode=enforce) but no backend available. Probed: ${probed.join(", ")}`);
3306
+ }
3307
+ return {
3308
+ backend: new NoSandboxBackend("sandbox-backend-unavailable"),
3309
+ selectedKind: "none",
3310
+ probed,
3311
+ reason: "sandbox-backend-unavailable"
3312
+ };
3313
+ }
3314
+ function resolveExplicitBackend(explicitBackend) {
3315
+ if (!explicitBackend) {
3316
+ return null;
3317
+ }
3318
+ switch (explicitBackend) {
3319
+ case "none":
3320
+ case "macos-seatbelt":
3321
+ case "linux-bwrap":
3322
+ case "docker":
3323
+ return explicitBackend;
3324
+ default:
3325
+ throw new SandboxError("backend-unavailable", `Unknown sandbox backend "${explicitBackend}".`);
3326
+ }
3327
+ }
3328
+ function loadSeatbeltBackend() {
3329
+ try {
3330
+ const mod = (init_backend_seatbelt(), __toCommonJS(exports_backend_seatbelt));
3331
+ return mod.SeatbeltBackend ?? null;
3332
+ } catch {
3333
+ return null;
3334
+ }
3335
+ }
3336
+ function loadBwrapBackend() {
3337
+ try {
3338
+ const mod = (init_backend_bwrap(), __toCommonJS(exports_backend_bwrap));
3339
+ return mod.BwrapBackend ?? null;
3340
+ } catch {
3341
+ return null;
3342
+ }
3343
+ }
3344
+ function handleUnavailableBackend(mode, probed, detectedKind, message, reason, options) {
3345
+ if (mode === "enforce" || options?.explicit) {
3346
+ throw new SandboxError("backend-unavailable", `${message} Probed: ${probed.join(", ")}`);
3347
+ }
3348
+ return {
3349
+ backend: new NoSandboxBackend(reason),
3350
+ selectedKind: "none",
3351
+ probed,
3352
+ reason: `${reason}:${detectedKind}`
3353
+ };
3354
+ }
3355
+
3356
+ // packages/isolation-plugin/src/sandbox/orchestrator.ts
3357
+ function shouldSandboxRuntime(_runtime) {
3358
+ return true;
3359
+ }
3360
+ async function wrapWithRuntimeSandbox(options) {
3361
+ const envOverride = process.env.RIG_RUNTIME_SANDBOX;
3362
+ const resolution = await resolveBackend(options.projectRoot, { ...envOverride !== undefined ? { envOverride } : {} });
3363
+ if (resolution.backend.kind === "none") {
3364
+ const plan = resolution.backend.wrap({
3365
+ projectRoot: options.projectRoot,
3366
+ runtime: options.runtime,
3367
+ command: options.command
3368
+ });
3369
+ return {
3370
+ ...plan,
3371
+ reason: plan.reason ?? resolution.reason
3372
+ };
3373
+ }
3374
+ if (!shouldSandboxRuntime(options.runtime)) {
3375
+ return {
3376
+ command: options.command,
3377
+ enabled: false,
3378
+ backend: "none",
3379
+ reason: "runtime-mode-not-sandboxed"
3380
+ };
3381
+ }
3382
+ return resolution.backend.wrap({
3383
+ projectRoot: options.projectRoot,
3384
+ runtime: options.runtime,
3385
+ command: options.command
3386
+ });
3387
+ }
3388
+
3389
+ // packages/isolation-plugin/src/isolation/runner.ts
3390
+ import { resolveRuntimeWorkspaceLayout as resolveRuntimeWorkspaceLayout2 } from "@rig/core/layout";
3391
+ import { resolveBunBinaryPath as resolveBunBinaryPath3 } from "@rig/core/runtime-paths";
3392
+ var SNAPSHOT_SIDECAR_READY_TIMEOUT_MS = 1e4;
3393
+ async function startRuntimeSnapshotSidecar(runtime, options = {}) {
3394
+ const instanceId = sanitizeRuntimeRefSegment(options.instanceId?.trim() || runtime.id);
3395
+ const readyFile = resolve14(runtime.stateDir, `runtime-snapshot-sidecar-${instanceId}.ready`);
3396
+ const requestFile = resolve14(runtime.stateDir, `runtime-snapshot-sidecar-${instanceId}.request.json`);
3397
+ rmSync7(readyFile, { force: true });
3398
+ rmSync7(requestFile, { force: true });
3399
+ const sidecarBinary = resolveSnapshotSidecarBinaryPath(runtime.binDir);
3400
+ const useCompiledSidecar = shouldUseCompiledSnapshotSidecar(sidecarBinary);
3401
+ const bunCli = useCompiledSidecar ? null : resolveBunCliInvocation();
3402
+ const command = useCompiledSidecar ? [sidecarBinary] : [bunCli.command, resolveSnapshotSidecarScriptPath()];
3403
+ const proc = Bun.spawn([
3404
+ ...command,
3405
+ "--workspace",
3406
+ runtime.workspaceDir,
3407
+ "--task",
3408
+ runtime.taskId,
3409
+ "--runtime-id",
3410
+ runtime.id,
3411
+ "--instance-id",
3412
+ instanceId,
3413
+ "--ready-file",
3414
+ readyFile,
3415
+ "--request-file",
3416
+ requestFile
3417
+ ], {
3418
+ cwd: runtime.workspaceDir,
3419
+ stdin: "ignore",
3420
+ stdout: "pipe",
3421
+ stderr: "pipe",
3422
+ env: {
3423
+ ...process.env,
3424
+ ...bunCli?.env ?? {}
3425
+ }
3426
+ });
3427
+ const stdoutTextPromise = drainStream(proc.stdout);
3428
+ const stderrTextPromise = drainStream(proc.stderr);
3429
+ await waitForSnapshotSidecarReady(readyFile, proc, stdoutTextPromise, stderrTextPromise);
3430
+ return {
3431
+ cancel: async () => {
3432
+ try {
3433
+ proc.kill("SIGTERM");
3434
+ } catch {}
3435
+ await proc.exited;
3436
+ rmSync7(readyFile, { force: true });
3437
+ rmSync7(requestFile, { force: true });
3438
+ },
3439
+ finalize: async (commandParts, exitCode) => {
3440
+ writeFileSync6(requestFile, `${JSON.stringify({ command: commandParts, exitCode })}
3441
+ `, "utf-8");
3442
+ const [sidecarExitCode, stdout, stderr] = await Promise.all([
3443
+ proc.exited,
3444
+ stdoutTextPromise,
3445
+ stderrTextPromise
3446
+ ]);
3447
+ rmSync7(readyFile, { force: true });
3448
+ rmSync7(requestFile, { force: true });
3449
+ if (sidecarExitCode !== 0) {
3450
+ throw new Error(`snapshot sidecar failed (${sidecarExitCode}): ${stderr || stdout}`);
3451
+ }
3452
+ }
3453
+ };
3454
+ }
3455
+ async function drainStream(stream) {
3456
+ if (!stream)
3457
+ return "";
3458
+ try {
3459
+ return await new Response(stream).text();
3460
+ } catch {
3461
+ return "";
3462
+ }
3463
+ }
3464
+ async function runInAgentRuntime(options) {
3465
+ const snapshotSidecar = await startRuntimeSnapshotSidecar(options.runtime);
3466
+ try {
3467
+ const runtimeCommand = resolveInternalRuntimeCommand(options.command);
3468
+ const sandboxPlan = await wrapWithRuntimeSandbox({
3469
+ projectRoot: options.projectRoot,
3470
+ runtime: {
3471
+ id: options.runtime.id,
3472
+ mode: options.runtime.mode,
3473
+ rootDir: options.runtime.rootDir,
3474
+ workspaceDir: options.runtime.workspaceDir,
3475
+ homeDir: options.runtime.homeDir,
3476
+ tmpDir: options.runtime.tmpDir,
3477
+ cacheDir: options.runtime.cacheDir,
3478
+ stateDir: options.runtime.stateDir,
3479
+ sessionDir: options.runtime.sessionDir,
3480
+ claudeHomeDir: options.runtime.claudeHomeDir,
3481
+ binDir: options.runtime.binDir
3482
+ },
3483
+ command: runtimeCommand
3484
+ });
3485
+ const proc = Bun.spawn(sandboxPlan.command, {
3486
+ cwd: options.runtime.workspaceDir,
3487
+ env: runtimeCommandEnv(await runtimeEnv(options.projectRoot, options.runtime), sandboxPlan.command),
3488
+ stdin: options.inheritStdio ? "inherit" : "pipe",
3489
+ stdout: options.inheritStdio ? "inherit" : "pipe",
3490
+ stderr: options.inheritStdio ? "inherit" : "pipe"
3491
+ });
3492
+ const exitCode = await proc.exited;
3493
+ if (options.inheritStdio) {
3494
+ await snapshotSidecar.finalize(runtimeCommand, exitCode);
3495
+ return {
3496
+ exitCode,
3497
+ sandboxBackend: sandboxPlan.backend,
3498
+ sandboxEnabled: sandboxPlan.enabled
3499
+ };
3500
+ }
3501
+ const stdout = await new Response(proc.stdout).text();
3502
+ const stderr = await new Response(proc.stderr).text();
3503
+ try {
3504
+ await Bun.write(resolve14(options.runtime.logsDir, "agent-stdout.log"), stdout);
3505
+ await Bun.write(resolve14(options.runtime.logsDir, "agent-stderr.log"), stderr);
3506
+ } catch {}
3507
+ await snapshotSidecar.finalize(runtimeCommand, exitCode);
3508
+ return {
3509
+ exitCode,
3510
+ stdout,
3511
+ stderr,
3512
+ sandboxBackend: sandboxPlan.backend,
3513
+ sandboxEnabled: sandboxPlan.enabled
3514
+ };
3515
+ } catch (error) {
3516
+ await snapshotSidecar.cancel();
3517
+ throw error;
3518
+ }
3519
+ }
3520
+ function resolveInternalRuntimeCommand(command) {
3521
+ if (command.length === 0) {
3522
+ return [];
3523
+ }
3524
+ const executable = command[0]?.trim() ?? "";
3525
+ if (!executable) {
3526
+ return [...command];
3527
+ }
3528
+ if (basename4(executable) === "bun") {
3529
+ return [resolveBunBinaryPath3(), ...command.slice(1)];
3530
+ }
3531
+ return [...command];
3532
+ }
3533
+ async function cleanupAgentRuntime(options) {
3534
+ const { monorepoRoot, initialWorkspaceDir, runtimeRoot } = runtimeRootForCleanup(options.projectRoot, options.id);
3535
+ const metadataPath = resolve14(runtimeRoot, "runtime.json");
3536
+ if (!existsSync13(runtimeRoot)) {
3537
+ return;
3538
+ }
3539
+ let mode = "worktree";
3540
+ let workspaceDir = "";
3541
+ const metadata = await readRuntimeMetadata2(metadataPath);
3542
+ const metadataMatchesRequestedRuntime = metadata !== null && metadata.id === options.id && resolve14(metadata.workspaceDir) === resolve14(initialWorkspaceDir);
3543
+ if (metadata && metadataMatchesRequestedRuntime) {
3544
+ mode = metadata.mode;
3545
+ workspaceDir = metadata.workspaceDir;
3546
+ } else if (existsSync13(initialWorkspaceDir)) {
3547
+ workspaceDir = initialWorkspaceDir;
3548
+ }
3549
+ const preservesTaskWorktree = metadataMatchesRequestedRuntime && metadata ? options.id === taskRuntimeId(metadata.taskId) : false;
3550
+ if (mode === "worktree" && workspaceDir && monorepoRoot && !preservesTaskWorktree) {
3551
+ await cleanupRuntimeWorktree(monorepoRoot, workspaceDir);
3552
+ } else if (mode === "worktree" && workspaceDir && preservesTaskWorktree) {
3553
+ cleanupTaskRuntimeOverlay(workspaceDir);
3554
+ }
3555
+ rmSync7(runtimeRoot, { recursive: true, force: true });
3556
+ }
3557
+ function cleanupTaskRuntimeOverlay(workspaceDir) {
3558
+ const layout = resolveRuntimeWorkspaceLayout2(workspaceDir);
3559
+ for (const path of [
3560
+ layout.homeDir,
3561
+ layout.tmpDir,
3562
+ layout.cacheDir,
3563
+ layout.logsDir,
3564
+ layout.stateDir,
3565
+ layout.sessionDir,
3566
+ layout.binDir,
3567
+ layout.distDir,
3568
+ layout.runtimeDir,
3569
+ layout.contextPath
3570
+ ]) {
3571
+ rmSync7(path, { recursive: true, force: true });
3572
+ }
3573
+ }
3574
+ function resolveSnapshotSidecarScriptPath() {
3575
+ return resolveRuntimeSourceScriptPath("snapshot-sidecar.ts");
3576
+ }
3577
+ function resolveSnapshotSidecarBinaryPath(binDir) {
3578
+ return resolve14(binDir, "snapshot-sidecar");
3579
+ }
3580
+ function shouldUseCompiledSnapshotSidecar(binaryPath) {
3581
+ if (!existsSync13(binaryPath)) {
3582
+ return false;
3583
+ }
3584
+ const preference = process.env.RIG_USE_COMPILED_SNAPSHOT_SIDECAR?.trim().toLowerCase();
3585
+ if (!preference) {
3586
+ return false;
3587
+ }
3588
+ return preference === "1" || preference === "true" || preference === "yes";
3589
+ }
3590
+ function resolveRuntimeSourceScriptPath(fileName) {
3591
+ const hostRoots = [
3592
+ process.env.RIG_HOST_PROJECT_ROOT?.trim(),
3593
+ process.env.PROJECT_RIG_ROOT?.trim()
3594
+ ].filter((value) => Boolean(value));
3595
+ for (const root of hostRoots) {
3596
+ const candidate = resolve14(root, "packages/isolation-plugin/src", fileName);
3597
+ if (existsSync13(candidate)) {
3598
+ return candidate;
3599
+ }
3600
+ }
3601
+ return resolve14(import.meta.dir, "..", fileName);
3602
+ }
3603
+ function resolveBunCliInvocation() {
3604
+ if (process.env.RIG_BUN_PATH?.trim()) {
3605
+ return {
3606
+ command: process.env.RIG_BUN_PATH.trim(),
3607
+ env: {}
3608
+ };
3609
+ }
3610
+ const systemBun = Bun.which("bun")?.trim();
3611
+ if (systemBun) {
3612
+ return {
3613
+ command: systemBun,
3614
+ env: {}
3615
+ };
3616
+ }
3617
+ if (process.execPath?.trim()) {
3618
+ return {
3619
+ command: process.execPath,
3620
+ env: { BUN_BE_BUN: "1" }
3621
+ };
3622
+ }
3623
+ return { command: "bun", env: {} };
3624
+ }
3625
+ async function waitForSnapshotSidecarReady(readyFile, proc, stdoutTextPromise, stderrTextPromise) {
3626
+ const deadline = Date.now() + SNAPSHOT_SIDECAR_READY_TIMEOUT_MS;
3627
+ while (Date.now() < deadline) {
3628
+ if (existsSync13(readyFile)) {
3629
+ return;
3630
+ }
3631
+ const exitCode = proc.exitCode;
3632
+ if (exitCode !== null) {
3633
+ const [stderr, stdout] = await Promise.all([stderrTextPromise, stdoutTextPromise]);
3634
+ throw new Error(`snapshot sidecar exited before ready (${exitCode}): ${stderr || stdout}`);
3635
+ }
3636
+ await Bun.sleep(25);
3637
+ }
3638
+ throw new Error(`snapshot sidecar did not become ready within ${SNAPSHOT_SIDECAR_READY_TIMEOUT_MS}ms`);
3639
+ }
3640
+ async function readRuntimeMetadata2(metadataPath) {
3641
+ if (!existsSync13(metadataPath)) {
3642
+ return null;
3643
+ }
3644
+ try {
3645
+ return await Bun.file(metadataPath).json();
3646
+ } catch {
3647
+ return null;
3648
+ }
3649
+ }
3650
+
3651
+ // packages/isolation-plugin/src/isolation/index.ts
3652
+ var TaskDataCap = defineCapability2(TASK_DATA_SERVICE_CAPABILITY);
3653
+ var taskData = () => requireInstalledCapability2(TaskDataCap, "task-data capability unavailable: load @rig/task-sources-plugin (default bundle) before provisioning runtimes.");
3654
+ var CANONICAL_MEMORY_DB_PATH = "rig/memory/project-memory.db";
3655
+ async function hydrateRuntimeMemory(options) {
3656
+ const memoryService = await requireCapabilityForRoot(options.projectRoot, defineCapability2(MEMORY), "Shared memory requires the @rig/memory-plugin plugin in rig.config.");
3657
+ const snapshot = await memoryService.readCanonicalMemoryDb(options.projectRoot);
3658
+ const workspaceLayout = resolveRuntimeWorkspaceLayout3(options.workspaceDir);
3659
+ const hydratedPath = resolve15(workspaceLayout.stateDir, "memory", "project-memory.db");
3660
+ try {
3661
+ await mkdir3(resolve15(workspaceLayout.stateDir, "memory"), { recursive: true });
3662
+ await copyFile(snapshot.dbPath, hydratedPath);
3663
+ return {
3664
+ canonicalPath: CANONICAL_MEMORY_DB_PATH,
3665
+ canonicalRef: "origin/main",
3666
+ ...snapshot.baseOid ? { canonicalBaseOid: snapshot.baseOid } : {},
3667
+ hydratedPath,
3668
+ createdFresh: snapshot.createdFresh,
3669
+ retrieval: DEFAULT_RUNTIME_MEMORY_RETRIEVAL
3670
+ };
3671
+ } finally {
3672
+ await snapshot.cleanup();
3673
+ }
3674
+ }
3675
+ async function createRuntimeTaskRecordReader(options) {
3676
+ const legacyConfigPath = resolve15(options.projectRoot, ".rig", "task-config.json");
3677
+ let pluginHostContext = null;
3678
+ try {
3679
+ pluginHostContext = await buildPluginHostContext(options.projectRoot);
3680
+ } catch (error) {
3681
+ if (!existsSync14(legacyConfigPath)) {
3682
+ throw error;
3683
+ }
3684
+ const message = `Plugin task source unavailable; using source-aware .rig/task-config.json compatibility path: ${error instanceof Error ? error.message : String(error)}`;
3685
+ options.diagnostics?.(message);
3686
+ console.warn(message);
3687
+ return {
3688
+ reader: taskData().createSourceAwareTaskConfigRecordReader(options.projectRoot, {
3689
+ allowLocalTaskConfigStatusFallback: readConfiguredTaskSourceKindHint(options.projectRoot) !== "github-issues"
3690
+ }),
3691
+ source: "legacy"
3692
+ };
3693
+ }
3694
+ const pluginSources = pluginHostContext?.taskSourceRegistry.list() ?? [];
3695
+ if (pluginHostContext && pluginSources.length > 0) {
3696
+ return {
3697
+ reader: taskData().createPluginTaskRecordReader({ taskSourceRegistry: pluginHostContext.taskSourceRegistry }, { projectRoot: options.projectRoot }),
3698
+ source: "plugin"
3699
+ };
3700
+ }
3701
+ if (existsSync14(legacyConfigPath)) {
3702
+ const message = "Using source-aware .rig/task-config.json task source compatibility path";
3703
+ options.diagnostics?.(message);
3704
+ console.warn(message);
3705
+ return {
3706
+ reader: taskData().createSourceAwareTaskConfigRecordReader(options.projectRoot, {
3707
+ allowLocalTaskConfigStatusFallback: readConfiguredTaskSourceKindHint(options.projectRoot) !== "github-issues"
3708
+ }),
3709
+ source: "legacy"
3710
+ };
3711
+ }
3712
+ return {
3713
+ reader: taskData().createLegacyTaskConfigRecordReader(options.projectRoot),
3714
+ source: "legacy"
3715
+ };
3716
+ }
3717
+ function readConfiguredTaskSourceKindHint(projectRoot) {
3718
+ const jsonPath = resolve15(projectRoot, "rig.config.json");
3719
+ if (existsSync14(jsonPath)) {
3720
+ try {
3721
+ const parsed = JSON.parse(readFileSync7(jsonPath, "utf8"));
3722
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
3723
+ const taskSource = parsed.taskSource;
3724
+ if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
3725
+ const kind = taskSource.kind;
3726
+ return typeof kind === "string" ? kind : null;
3727
+ }
3728
+ }
3729
+ } catch {
3730
+ return null;
3731
+ }
3732
+ }
3733
+ const tsPath = resolve15(projectRoot, "rig.config.ts");
3734
+ if (!existsSync14(tsPath)) {
3735
+ return null;
3736
+ }
3737
+ try {
3738
+ const source = readFileSync7(tsPath, "utf8");
3739
+ const taskSourceBlock = source.match(/taskSource\s*:\s*\{[\s\S]*?\}/m)?.[0] ?? "";
3740
+ const kind = taskSourceBlock.match(/kind\s*:\s*["']([^"']+)["']/)?.[1];
3741
+ return kind ?? null;
3742
+ } catch {
3743
+ return null;
3744
+ }
3745
+ }
3746
+ async function resolveRuntimeTaskRecord(options) {
3747
+ const readerResolution = options.taskRecordReader ? { reader: options.taskRecordReader, source: "injected" } : await createRuntimeTaskRecordReader({
3748
+ projectRoot: options.projectRoot,
3749
+ ...options.diagnostics ? { diagnostics: options.diagnostics } : {}
3750
+ });
3751
+ const task = await readerResolution.reader.getTask(options.taskId);
3752
+ if (!task) {
3753
+ throw new Error(`Task ${options.taskId} not found in configured task source`);
3754
+ }
3755
+ return {
3756
+ task,
3757
+ taskEntry: taskRecordToRuntimeTaskEntry(task),
3758
+ source: readerResolution.source
3759
+ };
3760
+ }
3761
+ function runtimeSourceTaskContract(task) {
3762
+ const record = task;
3763
+ return {
3764
+ id: task.id,
3765
+ ...copyOptionalString(record, "title"),
3766
+ ...copyOptionalString(record, "description"),
3767
+ ...copyOptionalString(record, "body"),
3768
+ ...copyOptionalString(record, "acceptanceCriteria"),
3769
+ ...copyOptionalString(record, "acceptance_criteria"),
3770
+ ...copyOptionalString(record, "sourceIssueId"),
3771
+ ...copyOptionalString(record, "status"),
3772
+ ...copyOptionalString(record, "issueType"),
3773
+ ...copyOptionalString(record, "role"),
3774
+ ...copyOptionalString(record, "externalRef"),
3775
+ scope: readStringList(record.scope),
3776
+ validation: readStringList(record.validation),
3777
+ validators: readStringList(record.validators),
3778
+ labels: readStringList(record.labels)
3779
+ };
3780
+ }
3781
+ function copyOptionalString(record, key) {
3782
+ const value = record[String(key)];
3783
+ return typeof value === "string" ? { [key]: value } : {};
3784
+ }
3785
+ function taskRecordToRuntimeTaskEntry(task) {
3786
+ const role = typeof task.role === "string" ? task.role : undefined;
3787
+ const scope = readStringList(task.scope);
3788
+ const validation = readStringList(task.validation).length > 0 ? readStringList(task.validation) : readStringList(task.validators);
3789
+ const browser = isTaskBrowserConfig(task.browser) ? task.browser : undefined;
3790
+ return {
3791
+ ...role ? { role } : {},
3792
+ ...scope.length > 0 ? { scope } : {},
3793
+ ...validation.length > 0 ? { validation } : {},
3794
+ ...browser ? { browser } : {}
3795
+ };
3796
+ }
3797
+ async function writeRuntimeTaskConfigProjection(options) {
3798
+ const record = options.task;
3799
+ const entry = {
3800
+ ...copyOptionalString(record, "description"),
3801
+ ...copyOptionalString(record, "acceptance_criteria"),
3802
+ ...typeof record.acceptanceCriteria === "string" ? { acceptance_criteria: record.acceptanceCriteria } : {},
3803
+ ...options.taskEntry.role ? { role: options.taskEntry.role } : {},
3804
+ ...options.taskEntry.scope && options.taskEntry.scope.length > 0 ? { scope: options.taskEntry.scope } : {},
3805
+ ...options.taskEntry.validation && options.taskEntry.validation.length > 0 ? { validation: options.taskEntry.validation } : {},
3806
+ ...options.taskEntry.browser ? { browser: options.taskEntry.browser } : {}
3807
+ };
3808
+ const configPath = resolve15(options.workspaceDir, ".rig", "task-config.json");
3809
+ await mkdir3(resolve15(options.workspaceDir, ".rig"), { recursive: true });
3810
+ await writeFile2(configPath, `${JSON.stringify({ [options.task.id]: entry }, null, 2)}
3811
+ `, "utf-8");
3812
+ }
3813
+ function readStringList(candidate) {
3814
+ return Array.isArray(candidate) ? candidate.filter((value) => typeof value === "string") : [];
3815
+ }
3816
+ function isTaskBrowserConfig(candidate) {
3817
+ return typeof candidate === "object" && candidate !== null && !Array.isArray(candidate);
3818
+ }
3819
+ function fallbackTaskInfoOutput(task, taskEntry) {
3820
+ const lines = [
3821
+ `=== Task: ${task.id} ===`,
3822
+ "",
3823
+ `Role: ${taskEntry.role || "unassigned"}`
3824
+ ];
3825
+ if (typeof task.title === "string" && task.title.trim()) {
3826
+ lines.push(`Title: ${task.title}`);
3827
+ }
3828
+ if (typeof task.status === "string" && task.status.trim()) {
3829
+ lines.push(`Status: ${task.status.toUpperCase()}`);
3830
+ }
3831
+ const description = typeof task.description === "string" ? task.description : typeof task.body === "string" ? task.body : "";
3832
+ if (description.trim()) {
3833
+ lines.push("", "Description:", description);
3834
+ }
3835
+ const acceptanceCriteria = typeof task.acceptanceCriteria === "string" ? task.acceptanceCriteria : typeof task.acceptance_criteria === "string" ? task.acceptance_criteria : "";
3836
+ if (acceptanceCriteria.trim()) {
3837
+ lines.push("", "Acceptance Criteria:", acceptanceCriteria);
3838
+ }
3839
+ lines.push("", "Scope globs:");
3840
+ for (const scope of taskEntry.scope ?? []) {
3841
+ lines.push(` - ${scope}`);
3842
+ }
3843
+ lines.push("", "Validation:");
3844
+ for (const command of taskEntry.validation ?? []) {
3845
+ lines.push(` $ ${command}`);
3846
+ }
3847
+ return `${lines.join(`
3848
+ `)}
3849
+ `;
3850
+ }
3851
+ async function captureTaskInfoOutput(options) {
3852
+ try {
3853
+ return await captureStdout(async () => {
3854
+ await taskData().taskInfo(options.projectRoot, options.taskId, options.provider);
3855
+ });
3856
+ } catch (error) {
3857
+ const message = error instanceof Error ? error.message : String(error);
3858
+ if (!message.includes("Task config missing")) {
3859
+ throw error;
3860
+ }
3861
+ return fallbackTaskInfoOutput(options.task, options.taskEntry);
3862
+ }
3863
+ }
3864
+ async function ensureAgentRuntime(options) {
3865
+ if (!options.taskId.trim()) {
3866
+ throw new Error("Task runtime provisioning requires a non-empty taskId.");
3867
+ }
3868
+ if (options.mode !== "worktree") {
3869
+ throw new Error(`Unsupported runtime isolation mode: ${options.mode}`);
3870
+ }
3871
+ ensureProvisioningHostProjectRootEnv(options.projectRoot);
3872
+ const monorepoRoot = resolveMonorepoRoot(options.projectRoot);
3873
+ const workspaceDir = resolve15(monorepoRoot, ".worktrees", runtimeWorktreeName(options.taskId, options.id));
3874
+ const createdAt = new Date().toISOString();
3875
+ if (!existsSync14(resolve15(monorepoRoot, ".git"))) {
3876
+ throw new Error(`Monorepo root is not a git checkout: ${monorepoRoot}`);
3877
+ }
3878
+ const taskResolution = await resolveRuntimeTaskRecord({
3879
+ projectRoot: options.projectRoot,
3880
+ taskId: options.taskId,
3881
+ ...options.taskRecordReader ? { taskRecordReader: options.taskRecordReader } : {}
3882
+ });
3883
+ const taskEntry = taskResolution.taskEntry;
3884
+ const workspaceLayout = resolveRuntimeWorkspaceLayout3(workspaceDir);
3885
+ const baseRef = await resolveMonorepoBaseRef(monorepoRoot);
3886
+ const monorepoBaseCommit = await resolveMonorepoBaseCommit(monorepoRoot, baseRef);
3887
+ console.log(`[rig-agent] Provisioning worktree runtime ${options.id} for ${options.taskId}`);
3888
+ await provisionRuntimeWorktree({
3889
+ monorepoRoot,
3890
+ taskId: options.taskId,
3891
+ runtimeId: options.id,
3892
+ workspaceDir,
3893
+ baseRef
3894
+ });
3895
+ await configureRuntimeGitIdentity(monorepoRoot, workspaceDir);
3896
+ const runtimeRoot = workspaceLayout.runtimeDir;
3897
+ const overlay = ensureRuntimeOverlay(options.projectRoot, options.id, workspaceDir);
3898
+ const runtime = {
3899
+ id: options.id,
3900
+ taskId: options.taskId,
3901
+ mode: "worktree",
3902
+ rootDir: runtimeRoot,
3903
+ workspaceDir,
3904
+ homeDir: workspaceLayout.homeDir,
3905
+ tmpDir: workspaceLayout.tmpDir,
3906
+ cacheDir: workspaceLayout.cacheDir,
3907
+ logsDir: overlay.logsDir,
3908
+ stateDir: overlay.stateDir,
3909
+ sessionDir: overlay.sessionDir,
3910
+ claudeHomeDir: resolve15(workspaceLayout.homeDir, ".claude"),
3911
+ contextFile: overlay.contextPath,
3912
+ binDir: workspaceLayout.binDir,
3913
+ createdAt
3914
+ };
3915
+ await provisionRuntimeHome(runtime, { ...options.provider !== undefined ? { provider: options.provider } : {} });
3916
+ prepareTrackedRuntimePaths(runtime.logsDir, runtime.stateDir, runtime.sessionDir);
3917
+ await mkdir3(runtime.logsDir, { recursive: true });
3918
+ await initializeRuntimeStateFiles(runtime.stateDir, runtime.sessionDir, options.taskId);
3919
+ const memory = await hydrateRuntimeMemory({
3920
+ projectRoot: options.projectRoot,
3921
+ workspaceDir
3922
+ });
3923
+ mkdirSync10(runtime.binDir, { recursive: true });
3924
+ mkdirSync10(workspaceLayout.distDir, { recursive: true });
3925
+ prepareRuntimeWorkspace(options.projectRoot, workspaceDir);
3926
+ if (options.preserveTaskArtifacts) {
3927
+ console.log(`[rig-agent] Preserving runtime task artifacts for resume of ${options.taskId}.`);
3928
+ } else {
3929
+ await resetEphemeralTaskArtifacts(workspaceDir, options.taskId);
3930
+ }
3931
+ const browserContractService = await loadCapabilityForRoot(options.projectRoot, defineCapability2(BROWSER_CONTRACT_SERVICE_CAPABILITY));
3932
+ const browserContext = browserContractService?.resolveTaskBrowserContext(taskEntry.browser, {
3933
+ hostProjectRoot: options.projectRoot,
3934
+ runtimeId: options.id
3935
+ });
3936
+ const projectHeadCommit = await tryReadGitHead(options.projectRoot);
3937
+ const monorepoHeadCommit = await tryReadGitHead(workspaceDir);
3938
+ const ctx = {
3939
+ runtimeId: options.id,
3940
+ taskId: options.taskId,
3941
+ role: taskEntry.role || "extractor",
3942
+ scopes: taskEntry.scope || [],
3943
+ validation: taskEntry.validation || [],
3944
+ sourceTask: runtimeSourceTaskContract(taskResolution.task),
3945
+ ...browserContext !== undefined ? { browser: browserContext } : {},
3946
+ workspaceDir,
3947
+ artifactRoot: resolve15(workspaceDir, "artifacts", safePathSegment3(options.taskId, { fallback: "task", maxLength: 96 })),
3948
+ hostProjectRoot: options.projectRoot,
3949
+ monorepoMainRoot: monorepoRoot,
3950
+ monorepoBaseRef: baseRef,
3951
+ monorepoBaseCommit,
3952
+ initialHeadCommits: {
3953
+ ...projectHeadCommit !== undefined ? { project: projectHeadCommit } : {},
3954
+ ...monorepoHeadCommit !== undefined ? { monorepo: monorepoHeadCommit } : {}
3955
+ },
3956
+ initialDirtyFiles: {
3957
+ project: await captureRepoDirtyFiles(options.projectRoot),
3958
+ monorepo: await captureRepoDirtyFiles(workspaceDir)
3959
+ },
3960
+ stateDir: overlay.stateDir,
3961
+ logsDir: overlay.logsDir,
3962
+ sessionDir: overlay.sessionDir,
3963
+ sessionFile: resolve15(overlay.sessionDir, "session.json"),
3964
+ policyFile: resolve15(options.projectRoot, "rig/policy/policy.json"),
3965
+ binDir: runtime.binDir,
3966
+ createdAt,
3967
+ memory
3968
+ };
3969
+ writeRuntimeContext(overlay.contextPath, ctx);
3970
+ await writeRuntimeTaskConfigProjection({
3971
+ workspaceDir,
3972
+ task: taskResolution.task,
3973
+ taskEntry
3974
+ });
3975
+ const manifestPath = resolve15(runtimeRoot, "manifest.json");
3976
+ const bakedScopeHash = sha256Hex(JSON.stringify(taskEntry.scope || []));
3977
+ const runtimeAgentBinary = resolve15(runtime.binDir, "rig-agent");
3978
+ await ensureRigGitBinaryPath();
3979
+ const bakedInfoOutput = await captureTaskInfoOutput({
3980
+ projectRoot: options.projectRoot,
3981
+ taskId: options.taskId,
3982
+ ...options.provider !== undefined ? { provider: options.provider } : {},
3983
+ task: taskResolution.task,
3984
+ taskEntry
3985
+ });
3986
+ const bakedDepsOutput = await captureStdout(async () => {
3987
+ await taskData().taskDeps(options.projectRoot, options.taskId);
3988
+ });
3989
+ const bakedStatusOutput = await captureStdout(async () => {
3990
+ taskData().taskStatus(options.projectRoot);
3991
+ });
3992
+ rmSync8(runtime.binDir, { recursive: true, force: true });
3993
+ rmSync8(workspaceLayout.distDir, { recursive: true, force: true });
3994
+ mkdirSync10(runtime.binDir, { recursive: true });
3995
+ mkdirSync10(workspaceLayout.distDir, { recursive: true });
3996
+ await buildRuntimeToolchain({
3997
+ projectRoot: options.projectRoot,
3998
+ workspaceDir,
3999
+ binDir: runtime.binDir,
4000
+ distDir: workspaceLayout.distDir,
4001
+ taskId: options.taskId,
4002
+ runtimeId: options.id,
4003
+ manifestPath,
4004
+ taskEntry,
4005
+ bakedScopeHash,
4006
+ bakedInfoOutput,
4007
+ bakedDepsOutput,
4008
+ bakedStatusOutput,
4009
+ runtimeSecretDefines: secretDefinesFromEnv(process.env, options.projectRoot),
4010
+ logsDir: runtime.logsDir
4011
+ });
4012
+ await writeRuntimeManifest({
4013
+ runtimeRoot,
4014
+ workspaceDir,
4015
+ runtimeId: options.id,
4016
+ taskId: options.taskId,
4017
+ scopes: taskEntry.scope || [],
4018
+ binaryPath: runtimeAgentBinary,
4019
+ binDir: runtime.binDir
4020
+ });
4021
+ await provisionClaudeHome({
4022
+ claudeHomeDir: runtime.claudeHomeDir,
4023
+ hostProjectRoot: options.projectRoot,
4024
+ workspaceDir,
4025
+ taskEntry
4026
+ });
4027
+ const sandboxDir = resolve15(runtimeRoot, "sandbox");
4028
+ await mkdir3(sandboxDir, { recursive: true });
4029
+ await writeFile2(resolve15(runtimeRoot, "runtime.json"), JSON.stringify({
4030
+ id: options.id,
4031
+ taskId: options.taskId,
4032
+ mode: "worktree",
4033
+ workspaceDir,
4034
+ createdAt
4035
+ }, null, 2), "utf-8");
4036
+ return runtime;
4037
+ }
4038
+ export {
4039
+ taskRuntimeId,
4040
+ startRuntimeSnapshotSidecar,
4041
+ runtimeWorktreeNameFromRuntimeId,
4042
+ runtimeWorktreeName,
4043
+ runtimeEnv,
4044
+ runtimeCommandEnv,
4045
+ runtimeBranchName,
4046
+ runInAgentRuntime,
4047
+ resolveRuntimeTaskRecord,
4048
+ resolveMonorepoRoot,
4049
+ resolveMonorepoBaseRef,
4050
+ resolveContributedToolchainSources,
4051
+ prepareTrackedRuntimePaths,
4052
+ persistRuntimeSecrets,
4053
+ materializeRuntimeHostToolWrappers,
4054
+ listAgentRuntimes,
4055
+ hydrateRuntimeMemory,
4056
+ ensureAgentRuntime,
4057
+ createRuntimeTaskRecordReader,
4058
+ configureRuntimeGitIdentity,
4059
+ cleanupAgentRuntime,
4060
+ buildBinary,
4061
+ agentId
4062
+ };