@h-rig/isolation-plugin 0.0.6-alpha.156 → 0.0.6-alpha.158

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/src/embedded-native-assets.d.ts +7 -0
  2. package/dist/src/embedded-native-assets.js +6 -0
  3. package/dist/src/image-fingerprint-sidecar.d.ts +1 -0
  4. package/dist/src/image-fingerprint-sidecar.js +515 -0
  5. package/dist/src/image.d.ts +40 -0
  6. package/dist/src/image.js +1498 -0
  7. package/dist/src/index.js +4220 -20
  8. package/dist/src/isolation/binary-build-worker.d.ts +1 -0
  9. package/dist/src/isolation/binary-build-worker.js +323 -0
  10. package/dist/src/isolation/discovery.d.ts +7 -0
  11. package/dist/src/isolation/discovery.js +477 -0
  12. package/dist/src/isolation/git-native.d.ts +28 -0
  13. package/dist/src/isolation/git-native.js +598 -0
  14. package/dist/src/isolation/home.d.ts +25 -0
  15. package/dist/src/isolation/home.js +929 -0
  16. package/dist/src/isolation/index.d.ts +43 -0
  17. package/dist/src/isolation/index.js +4062 -0
  18. package/dist/src/isolation/provisioning-env.d.ts +1 -0
  19. package/dist/src/isolation/provisioning-env.js +6 -0
  20. package/dist/src/isolation/runner.d.ts +20 -0
  21. package/dist/src/isolation/runner.js +1881 -0
  22. package/dist/src/isolation/runtime-binary-build.d.ts +88 -0
  23. package/dist/src/isolation/runtime-binary-build.js +480 -0
  24. package/dist/src/isolation/shared.d.ts +29 -0
  25. package/dist/src/isolation/shared.js +283 -0
  26. package/dist/src/isolation/toolchain.d.ts +71 -0
  27. package/dist/src/isolation/toolchain.js +1348 -0
  28. package/dist/src/isolation/types.d.ts +15 -0
  29. package/dist/src/isolation/types.js +1 -0
  30. package/dist/src/isolation/worktree.d.ts +22 -0
  31. package/dist/src/isolation/worktree.js +353 -0
  32. package/dist/src/native-extract.d.ts +2 -0
  33. package/dist/src/native-extract.js +44 -0
  34. package/dist/src/plugin.d.ts +2 -2
  35. package/dist/src/plugin.js +4219 -19
  36. package/dist/src/runtime-config.d.ts +3 -0
  37. package/dist/src/runtime-config.js +215 -0
  38. package/dist/src/runtime-native-sidecar.d.ts +8 -0
  39. package/dist/src/runtime-native-sidecar.js +368 -0
  40. package/dist/src/runtime-native.d.ts +51 -0
  41. package/dist/src/runtime-native.js +485 -0
  42. package/dist/src/sandbox/backend-bwrap.d.ts +20 -0
  43. package/dist/src/sandbox/backend-bwrap.js +268 -0
  44. package/dist/src/sandbox/backend-none.d.ts +11 -0
  45. package/dist/src/sandbox/backend-none.js +20 -0
  46. package/dist/src/sandbox/backend-seatbelt.d.ts +13 -0
  47. package/dist/src/sandbox/backend-seatbelt.js +225 -0
  48. package/dist/src/sandbox/backend.d.ts +117 -0
  49. package/dist/src/sandbox/backend.js +864 -0
  50. package/dist/src/sandbox/orchestrator.d.ts +21 -0
  51. package/dist/src/sandbox/orchestrator.js +895 -0
  52. package/dist/src/sandbox/utils.d.ts +43 -0
  53. package/dist/src/sandbox/utils.js +94 -0
  54. package/dist/src/service.d.ts +10 -5
  55. package/dist/src/service.js +4145 -2
  56. package/dist/src/sidecar-arg.d.ts +7 -0
  57. package/dist/src/sidecar-arg.js +6 -0
  58. package/dist/src/sidecar-entrypoint.d.ts +9 -0
  59. package/dist/src/sidecar-entrypoint.js +401 -0
  60. package/dist/src/snapshot-sidecar.d.ts +2 -0
  61. package/dist/src/snapshot-sidecar.js +566 -0
  62. package/dist/src/snapshot.d.ts +64 -0
  63. package/dist/src/snapshot.js +515 -0
  64. package/dist/src/task-run-snapshot.d.ts +26 -0
  65. package/dist/src/task-run-snapshot.js +713 -0
  66. package/native/darwin-arm64/rig-git +0 -0
  67. package/native/darwin-arm64/rig-git.build-manifest.json +4 -0
  68. package/native/darwin-arm64/runtime-native.dylib +0 -0
  69. package/native/darwin-x64/rig-git +0 -0
  70. package/native/darwin-x64/runtime-native.dylib +0 -0
  71. package/native/linux-arm64/rig-git +0 -0
  72. package/native/linux-arm64/runtime-native.so +0 -0
  73. package/native/linux-x64/rig-git +0 -0
  74. package/native/linux-x64/runtime-native.so +0 -0
  75. package/native/win32-x64/rig-git.exe +0 -0
  76. package/native/win32-x64/runtime-native.dll +0 -0
  77. package/package.json +45 -5
@@ -0,0 +1,15 @@
1
+ import type { AgentRuntime, IsolationMode, RuntimeSnapshotSidecar, TaskBrowserConfig } from "@rig/contracts";
2
+ export type { AgentRuntime, IsolationMode, RuntimeSnapshotSidecar };
3
+ export type RuntimeMetadata = {
4
+ id: string;
5
+ taskId: string;
6
+ mode: IsolationMode;
7
+ workspaceDir: string;
8
+ createdAt: string;
9
+ };
10
+ export type RuntimeTaskEntry = {
11
+ role?: string;
12
+ scope?: string[];
13
+ validation?: string[];
14
+ browser?: TaskBrowserConfig;
15
+ };
@@ -0,0 +1 @@
1
+ // @bun
@@ -0,0 +1,22 @@
1
+ import { runGitCommand } from "./shared";
2
+ export declare function resolveMonorepoBaseRef(monorepoRoot: string): Promise<string>;
3
+ export declare function ensureProvisioningHostProjectRootEnv(projectRoot: string): void;
4
+ export declare function provisionRuntimeWorktree(config: {
5
+ monorepoRoot: string;
6
+ taskId: string;
7
+ runtimeId: string;
8
+ workspaceDir: string;
9
+ baseRef: string;
10
+ }): Promise<void>;
11
+ export declare function isGitLockContention(result: {
12
+ exitCode: number;
13
+ stdout?: unknown;
14
+ stderr?: unknown;
15
+ }): boolean;
16
+ export declare function runGitWithLockRetry(repoRoot: string, args: string[], attempts?: number): Promise<Awaited<ReturnType<typeof runGitCommand>>>;
17
+ export declare function cleanupRuntimeWorktree(monorepoRoot: string, workspaceDir: string): Promise<void>;
18
+ export declare function configureRuntimeGitIdentity(projectRoot: string, repoRoot: string): Promise<void>;
19
+ export declare function resolveMonorepoBaseCommit(monorepoRoot: string, baseRef: string): Promise<string>;
20
+ export declare function runtimeBranchName(taskId: string, runtimeId: string): string;
21
+ export declare function runtimeWorktreeName(taskId: string, runtimeId: string): string;
22
+ export declare function runtimeWorktreeNameFromRuntimeId(runtimeId: string): string;
@@ -0,0 +1,353 @@
1
+ // @bun
2
+ // packages/isolation-plugin/src/isolation/worktree.ts
3
+ import { existsSync as existsSync2, mkdirSync, rmSync as rmSync2 } from "fs";
4
+ import { dirname, resolve } from "path";
5
+ import { assertPathInsideRoot, safeGitRefComponent as safeGitRefComponent2, safePathSegment } from "@rig/core/safe-identifiers";
6
+
7
+ // packages/isolation-plugin/src/isolation/shared.ts
8
+ import { existsSync, readFileSync, rmSync } from "fs";
9
+ import { agentId, safeGitRefComponent, taskRuntimeId } from "@rig/core/safe-identifiers";
10
+ import { resolveCheckoutRoot } from "@rig/core/checkout-root";
11
+ function isRuntimeGatewayGitPath(candidate) {
12
+ return /\/\.rig\/bin\/git$/.test(candidate.replace(/\\/g, "/"));
13
+ }
14
+ function resolveHostGitBinary() {
15
+ const candidates = [
16
+ process.env.RIG_GIT_BIN?.trim() || "",
17
+ "/usr/bin/git",
18
+ "/opt/homebrew/bin/git",
19
+ "/usr/local/bin/git"
20
+ ];
21
+ const bunResolved = Bun.which("git");
22
+ if (bunResolved && !isRuntimeGatewayGitPath(bunResolved)) {
23
+ candidates.push(bunResolved);
24
+ }
25
+ for (const candidate of candidates) {
26
+ if (candidate && !isRuntimeGatewayGitPath(candidate) && existsSync(candidate)) {
27
+ return candidate;
28
+ }
29
+ }
30
+ return "git";
31
+ }
32
+ var generatedCredentialFiles = new Set;
33
+ async function runGitCommand(repoRoot, args) {
34
+ const gitBinary = resolveHostGitBinary();
35
+ return Bun.$`${gitBinary} -C ${repoRoot} ${args}`.quiet().nothrow();
36
+ }
37
+ async function readGitConfigValue(repoRoot, key, global = false) {
38
+ const args = ["config", ...global ? ["--global"] : [], "--get", key];
39
+ const result = await runGitCommand(repoRoot, args);
40
+ if (result.exitCode !== 0) {
41
+ return "";
42
+ }
43
+ return String(result.stdout).trim();
44
+ }
45
+ async function readGitStdout(repoRoot, args) {
46
+ const result = await runGitCommand(repoRoot, args);
47
+ if (result.exitCode !== 0) {
48
+ throw new Error(`git -C ${repoRoot} ${args.join(" ")} failed: ${result.stderr || result.stdout}`);
49
+ }
50
+ return String(result.stdout).trim();
51
+ }
52
+ async function hasGitRemote(repoRoot, remote) {
53
+ const result = await runGitCommand(repoRoot, ["remote", "get-url", remote]);
54
+ return result.exitCode === 0;
55
+ }
56
+ async function ensureFullGitHistory(repoRoot) {
57
+ const shallow = await runGitCommand(repoRoot, ["rev-parse", "--is-shallow-repository"]);
58
+ if (shallow.exitCode !== 0 || String(shallow.stdout).trim() !== "true") {
59
+ return;
60
+ }
61
+ const unshallow = await runGitCommand(repoRoot, ["fetch", "--unshallow", "--tags", "origin"]);
62
+ if (unshallow.exitCode === 0) {
63
+ return;
64
+ }
65
+ const output = `${unshallow.stderr}
66
+ ${unshallow.stdout}`.trim();
67
+ if (/--unshallow on a complete repository|does not make sense/i.test(output)) {
68
+ return;
69
+ }
70
+ throw new Error(`Failed to expand git history for ${repoRoot}: ${output}`);
71
+ }
72
+ async function refreshRemoteBranch(repoRoot, remote, branch) {
73
+ if (!await hasGitRemote(repoRoot, remote)) {
74
+ return;
75
+ }
76
+ try {
77
+ await ensureFullGitHistory(repoRoot);
78
+ const fetch = await runGitCommand(repoRoot, [
79
+ "fetch",
80
+ "--prune",
81
+ "--tags",
82
+ remote,
83
+ `+refs/heads/${branch}:refs/remotes/${remote}/${branch}`
84
+ ]);
85
+ if (fetch.exitCode !== 0) {
86
+ return;
87
+ }
88
+ } catch {
89
+ return;
90
+ }
91
+ }
92
+ function sanitizeRuntimeRefSegment(value) {
93
+ return safeGitRefComponent(value, { fallback: "runtime", maxLength: 64 });
94
+ }
95
+ function runtimeBranchBackupName(branch) {
96
+ const branchId = branch.replace(/^rig\//, "");
97
+ return `rig-backup/${sanitizeRuntimeRefSegment(branchId)}-${Date.now()}`;
98
+ }
99
+
100
+ // packages/isolation-plugin/src/isolation/worktree.ts
101
+ async function resolveMonorepoBaseRef(monorepoRoot) {
102
+ const explicit = process.env.RIG_RUNTIME_BASE_REF?.trim();
103
+ if (explicit) {
104
+ const exists = await runGitCommand(monorepoRoot, ["rev-parse", "--verify", "--quiet", explicit]);
105
+ if (exists.exitCode !== 0) {
106
+ throw new Error(`RIG_RUNTIME_BASE_REF=${explicit} does not resolve at ${monorepoRoot}.`);
107
+ }
108
+ return explicit;
109
+ }
110
+ for (const remote of await preferredBaseRemotes(monorepoRoot)) {
111
+ await refreshRemoteBranch(monorepoRoot, remote, "main");
112
+ const remoteMain = await runGitCommand(monorepoRoot, ["show-ref", "--verify", "--quiet", `refs/remotes/${remote}/main`]);
113
+ if (remoteMain.exitCode === 0) {
114
+ return `${remote}/main`;
115
+ }
116
+ }
117
+ const localMain = await runGitCommand(monorepoRoot, ["show-ref", "--verify", "--quiet", "refs/heads/main"]);
118
+ if (localMain.exitCode === 0) {
119
+ return "main";
120
+ }
121
+ throw new Error(`Failed to resolve a monorepo base ref at ${monorepoRoot}. Expected local main or a remote main ref.`);
122
+ }
123
+ function ensureProvisioningHostProjectRootEnv(projectRoot) {
124
+ if (!projectRoot.trim()) {
125
+ return;
126
+ }
127
+ if (!process.env.RIG_HOST_PROJECT_ROOT?.trim()) {
128
+ process.env.RIG_HOST_PROJECT_ROOT = projectRoot;
129
+ }
130
+ if (!process.env.PROJECT_RIG_ROOT?.trim()) {
131
+ process.env.PROJECT_RIG_ROOT = projectRoot;
132
+ }
133
+ }
134
+ async function provisionRuntimeWorktree(config) {
135
+ const worktreesRoot = resolve(config.monorepoRoot, ".worktrees");
136
+ assertPathInsideRoot(worktreesRoot, config.workspaceDir, "runtime worktree path");
137
+ const branch = runtimeBranchName(config.taskId, config.runtimeId);
138
+ let hasValidWorktree = existsSync2(resolve(config.workspaceDir, ".git")) && (await runGitCommand(config.workspaceDir, ["rev-parse", "--show-toplevel"])).exitCode === 0;
139
+ if (existsSync2(config.workspaceDir) && !hasValidWorktree) {
140
+ rmSync2(config.workspaceDir, { recursive: true, force: true });
141
+ }
142
+ if (!hasValidWorktree) {
143
+ mkdirSync(dirname(config.workspaceDir), { recursive: true });
144
+ const branchExists = await runGitCommand(config.monorepoRoot, ["show-ref", "--verify", "--quiet", `refs/heads/${branch}`]);
145
+ const addArgs = branchExists.exitCode === 0 ? ["worktree", "add", "--force", config.workspaceDir, branch] : ["worktree", "add", "--force", "-b", branch, config.workspaceDir, config.baseRef];
146
+ const add = await runGitWithLockRetry(config.monorepoRoot, addArgs);
147
+ if (add.exitCode !== 0) {
148
+ throw new Error(`Failed to create monorepo worktree for ${config.runtimeId}: ${add.stderr.toString() || add.stdout.toString()}`);
149
+ }
150
+ hasValidWorktree = true;
151
+ }
152
+ await ensureRuntimeBranch(config.workspaceDir, branch, config.baseRef);
153
+ }
154
+ function isGitLockContention(result) {
155
+ if (result.exitCode === 0) {
156
+ return false;
157
+ }
158
+ const text = `${result.stderr != null ? String(result.stderr) : ""}
159
+ ${result.stdout != null ? String(result.stdout) : ""}`;
160
+ return /could not lock|cannot lock|unable to create '[^']*\.lock'|index\.lock|is already locked|File exists/i.test(text);
161
+ }
162
+ async function runGitWithLockRetry(repoRoot, args, attempts = 5) {
163
+ let result = await runGitCommand(repoRoot, args);
164
+ for (let attempt = 1;attempt < attempts && isGitLockContention(result); attempt++) {
165
+ await Bun.sleep(50 * attempt);
166
+ result = await runGitCommand(repoRoot, args);
167
+ }
168
+ return result;
169
+ }
170
+ async function cleanupRuntimeWorktree(monorepoRoot, workspaceDir) {
171
+ assertPathInsideRoot(resolve(monorepoRoot, ".worktrees"), workspaceDir, "runtime worktree path");
172
+ await runGitCommand(monorepoRoot, ["worktree", "remove", "--force", workspaceDir]);
173
+ }
174
+ async function configureRuntimeGitIdentity(projectRoot, repoRoot) {
175
+ 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";
176
+ 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";
177
+ for (const [key, value] of [
178
+ ["user.name", userName],
179
+ ["user.email", userEmail]
180
+ ]) {
181
+ await runGitCommand(repoRoot, ["config", "--local", key, value]);
182
+ }
183
+ }
184
+ async function resolveMonorepoBaseCommit(monorepoRoot, baseRef) {
185
+ return readGitStdout(monorepoRoot, ["rev-parse", baseRef]);
186
+ }
187
+ async function ensureRuntimeBranch(repoRoot, branch, baseRef) {
188
+ const pruneWorktrees = async () => {
189
+ await runGitCommand(repoRoot, ["worktree", "prune", "--expire", "now"]);
190
+ };
191
+ await pruneWorktrees();
192
+ await clearInterruptedRuntimeGitState(repoRoot, branch);
193
+ const current = await runGitCommand(repoRoot, ["rev-parse", "--abbrev-ref", "HEAD"]);
194
+ if (current.exitCode === 0 && current.stdout.toString().trim() === branch) {
195
+ await repairDisconnectedRuntimeBranch(repoRoot, branch, baseRef);
196
+ await clearInterruptedRuntimeGitState(repoRoot, branch);
197
+ return;
198
+ }
199
+ let checkout = await runGitCommand(repoRoot, ["checkout", "-B", branch]);
200
+ const checkoutError = checkout.stderr.toString() || checkout.stdout.toString();
201
+ if (checkout.exitCode !== 0 && checkoutError.includes("already used by worktree")) {
202
+ await pruneWorktrees();
203
+ checkout = await runGitCommand(repoRoot, ["checkout", "-B", branch]);
204
+ }
205
+ if (checkout.exitCode !== 0 && /resolve your current index first|would be overwritten by checkout/i.test(checkoutError)) {
206
+ await discardTrackedRuntimeChanges(repoRoot, branch, checkoutError);
207
+ checkout = await runGitCommand(repoRoot, ["checkout", "-B", branch]);
208
+ }
209
+ if (checkout.exitCode !== 0) {
210
+ throw new Error(`Failed to prepare runtime branch ${branch} in ${repoRoot}: ${checkout.stderr.toString() || checkout.stdout.toString()}`);
211
+ }
212
+ await repairDisconnectedRuntimeBranch(repoRoot, branch, baseRef);
213
+ await clearInterruptedRuntimeGitState(repoRoot, branch);
214
+ }
215
+ async function repairDisconnectedRuntimeBranch(repoRoot, branch, baseRef) {
216
+ const mergeBase = await runGitCommand(repoRoot, ["merge-base", "HEAD", baseRef]);
217
+ if (mergeBase.exitCode === 0) {
218
+ const counts = await runGitCommand(repoRoot, ["rev-list", "--left-right", "--count", `HEAD...${baseRef}`]);
219
+ if (counts.exitCode === 0) {
220
+ const [aheadRaw = "0", behindRaw = "0"] = String(counts.stdout).trim().split(/\s+/);
221
+ const ahead = Number.parseInt(aheadRaw, 10);
222
+ const behind = Number.parseInt(behindRaw, 10);
223
+ if (Number.isFinite(ahead) && Number.isFinite(behind) && ahead === 0 && behind > 0) {
224
+ const reset = await runGitCommand(repoRoot, ["reset", "--hard", baseRef]);
225
+ if (reset.exitCode !== 0) {
226
+ throw new Error(`Failed to reset stale runtime branch ${branch} to ${baseRef} in ${repoRoot}: ${reset.stderr.toString() || reset.stdout.toString()}`);
227
+ }
228
+ console.log(`[rig-agent] Reset stale runtime branch ${branch} to ${baseRef} in ${repoRoot}`);
229
+ }
230
+ }
231
+ return;
232
+ }
233
+ const backupBranch = runtimeBranchBackupName(branch);
234
+ const rename = await runGitCommand(repoRoot, ["branch", "-m", backupBranch]);
235
+ if (rename.exitCode !== 0) {
236
+ throw new Error(`Failed to archive disconnected runtime branch ${branch} in ${repoRoot}: ${rename.stderr.toString() || rename.stdout.toString()}`);
237
+ }
238
+ const recreate = await runGitCommand(repoRoot, ["checkout", "-B", branch, baseRef]);
239
+ if (recreate.exitCode !== 0) {
240
+ throw new Error(`Failed to recreate runtime branch ${branch} from ${baseRef} in ${repoRoot}: ${recreate.stderr.toString() || recreate.stdout.toString()}`);
241
+ }
242
+ console.log(`[rig-agent] Recreated disconnected runtime branch ${branch} from ${baseRef}; archived as ${backupBranch}`);
243
+ }
244
+ async function clearInterruptedRuntimeGitState(repoRoot, branch) {
245
+ let cleared = false;
246
+ for (const [sentinel, abortArgs] of [
247
+ ["MERGE_HEAD", ["merge", "--abort"]],
248
+ ["REBASE_HEAD", ["rebase", "--abort"]],
249
+ ["CHERRY_PICK_HEAD", ["cherry-pick", "--abort"]]
250
+ ]) {
251
+ const state = await runGitCommand(repoRoot, ["rev-parse", "--verify", "--quiet", sentinel]);
252
+ if (state.exitCode !== 0) {
253
+ continue;
254
+ }
255
+ cleared = true;
256
+ const abort = await runGitCommand(repoRoot, [...abortArgs]);
257
+ if (abort.exitCode === 0) {
258
+ continue;
259
+ }
260
+ const reset = await runGitCommand(repoRoot, ["reset", "--hard", "HEAD"]);
261
+ if (reset.exitCode !== 0) {
262
+ throw new Error(`Failed to recover interrupted git state for runtime branch ${branch} in ${repoRoot}: ${reset.stderr.toString() || reset.stdout.toString()}`);
263
+ }
264
+ }
265
+ const unmerged = await runGitCommand(repoRoot, ["ls-files", "-u"]);
266
+ if (unmerged.exitCode === 0 && String(unmerged.stdout).trim()) {
267
+ cleared = true;
268
+ const reset = await runGitCommand(repoRoot, ["reset", "--hard", "HEAD"]);
269
+ if (reset.exitCode !== 0) {
270
+ throw new Error(`Failed to clear unmerged files for runtime branch ${branch} in ${repoRoot}: ${reset.stderr.toString() || reset.stdout.toString()}`);
271
+ }
272
+ }
273
+ if (cleared) {
274
+ console.log(`[rig-agent] Reset interrupted git state in runtime branch ${branch} at ${repoRoot}`);
275
+ }
276
+ }
277
+ async function discardTrackedRuntimeChanges(repoRoot, branch, reason) {
278
+ const status = await runGitCommand(repoRoot, ["status", "--porcelain"]);
279
+ if (status.exitCode !== 0) {
280
+ throw new Error(`Failed to inspect runtime worktree state for ${branch} in ${repoRoot}: ${status.stderr.toString() || status.stdout.toString()}`);
281
+ }
282
+ const trackedChanges = String(status.stdout).split(/\r?\n/).map((line) => line.trimEnd()).filter(Boolean).filter((line) => !line.startsWith("?? "));
283
+ if (trackedChanges.length === 0) {
284
+ return;
285
+ }
286
+ const reset = await runGitCommand(repoRoot, ["reset", "--hard", "HEAD"]);
287
+ if (reset.exitCode !== 0) {
288
+ throw new Error(`Failed to discard tracked runtime changes for ${branch} in ${repoRoot}: ${reset.stderr.toString() || reset.stdout.toString()}`);
289
+ }
290
+ console.log(`[rig-agent] Reset tracked runtime changes in ${branch} at ${repoRoot} after checkout failed: ${reason.trim()}`);
291
+ }
292
+ function runtimeBranchName(taskId, runtimeId) {
293
+ const taskComponent = safeGitRefComponent2(taskId, { fallback: "task", maxLength: 72 });
294
+ if (runtimeId === taskRuntimeId(taskId)) {
295
+ return `rig/${taskComponent}`;
296
+ }
297
+ return `rig/${taskComponent}-${safeGitRefComponent2(runtimeId, { fallback: "runtime", maxLength: 48 })}`;
298
+ }
299
+ function runtimeWorktreeName(taskId, runtimeId) {
300
+ if (runtimeId === taskRuntimeId(taskId)) {
301
+ return safePathSegment(taskId, { fallback: "task", maxLength: 72 });
302
+ }
303
+ return safePathSegment(runtimeId, { fallback: "runtime", maxLength: 72 });
304
+ }
305
+ function runtimeWorktreeNameFromRuntimeId(runtimeId) {
306
+ return safePathSegment(runtimeId.replace(/^task-/, ""), { fallback: "runtime", maxLength: 72 });
307
+ }
308
+ async function preferredBaseRemotes(repoRoot) {
309
+ const remotesResult = await runGitCommand(repoRoot, ["remote"]);
310
+ if (remotesResult.exitCode !== 0) {
311
+ return [];
312
+ }
313
+ const remotes = String(remotesResult.stdout).split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
314
+ if (remotes.length === 0) {
315
+ return [];
316
+ }
317
+ const preferred = [];
318
+ const pushRemote = (remote) => {
319
+ if (!preferred.includes(remote)) {
320
+ preferred.push(remote);
321
+ }
322
+ };
323
+ if (await hasGitRemote(repoRoot, "github")) {
324
+ pushRemote("github");
325
+ }
326
+ for (const remote of remotes) {
327
+ if (remote === "github") {
328
+ continue;
329
+ }
330
+ const urlResult = await runGitCommand(repoRoot, ["remote", "get-url", remote]);
331
+ const url = urlResult.exitCode === 0 ? String(urlResult.stdout).trim() : "";
332
+ if (/github\.com[:/]/i.test(url)) {
333
+ pushRemote(remote);
334
+ }
335
+ }
336
+ for (const remote of remotes) {
337
+ pushRemote(remote);
338
+ }
339
+ return preferred;
340
+ }
341
+ export {
342
+ runtimeWorktreeNameFromRuntimeId,
343
+ runtimeWorktreeName,
344
+ runtimeBranchName,
345
+ runGitWithLockRetry,
346
+ resolveMonorepoBaseRef,
347
+ resolveMonorepoBaseCommit,
348
+ provisionRuntimeWorktree,
349
+ isGitLockContention,
350
+ ensureProvisioningHostProjectRootEnv,
351
+ configureRuntimeGitIdentity,
352
+ cleanupRuntimeWorktree
353
+ };
@@ -0,0 +1,2 @@
1
+ export declare function hasEmbeddedNatives(): boolean;
2
+ export declare function extractEmbeddedNative(name: string): string | null;
@@ -0,0 +1,44 @@
1
+ // @bun
2
+ // packages/isolation-plugin/src/native-extract.ts
3
+ import { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "fs";
4
+ import { tmpdir } from "os";
5
+ import { resolve } from "path";
6
+
7
+ // packages/isolation-plugin/src/embedded-native-assets.ts
8
+ var embeddedNatives = null;
9
+
10
+ // packages/isolation-plugin/src/native-extract.ts
11
+ var sharedNativeOutputDir = resolve(tmpdir(), "rig-native");
12
+ var extractionCache = {};
13
+ function hasEmbeddedNatives() {
14
+ return embeddedNatives != null;
15
+ }
16
+ function extractEmbeddedNative(name) {
17
+ if (name in extractionCache) {
18
+ return extractionCache[name] ?? null;
19
+ }
20
+ const entry = embeddedNatives?.[name];
21
+ if (!entry) {
22
+ extractionCache[name] = null;
23
+ return null;
24
+ }
25
+ try {
26
+ const targetPath = resolve(sharedNativeOutputDir, entry.fileName);
27
+ mkdirSync(sharedNativeOutputDir, { recursive: true });
28
+ const upToDate = existsSync(targetPath) && statSync(targetPath).size === entry.size;
29
+ if (!upToDate) {
30
+ const bytes = readFileSync(entry.filePath);
31
+ const tempPath = `${targetPath}.${process.pid}.${Date.now()}.tmp`;
32
+ writeFileSync(tempPath, bytes, { mode: 493 });
33
+ renameSync(tempPath, targetPath);
34
+ }
35
+ extractionCache[name] = targetPath;
36
+ } catch {
37
+ extractionCache[name] = null;
38
+ }
39
+ return extractionCache[name] ?? null;
40
+ }
41
+ export {
42
+ hasEmbeddedNatives,
43
+ extractEmbeddedNative
44
+ };
@@ -1,4 +1,4 @@
1
1
  export declare const ISOLATION_PLUGIN_NAME = "@rig/isolation-plugin";
2
- export declare const isolationPlugin: import("@rig/core").RigPlugin;
3
- export declare function createIsolationPlugin(): import("@rig/core").RigPlugin;
2
+ export declare const isolationPlugin: import("@rig/core/config").RigPlugin;
3
+ export declare function createIsolationPlugin(): import("@rig/core/config").RigPlugin;
4
4
  export default isolationPlugin;