@h-rig/runtime 0.0.6-alpha.0

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 (176) hide show
  1. package/README.md +27 -0
  2. package/dist/bin/rig-agent-dispatch.js +9615 -0
  3. package/dist/bin/rig-agent.js +9512 -0
  4. package/dist/bin/rig-browser-tool.js +269 -0
  5. package/dist/src/agent-mode.js +48 -0
  6. package/dist/src/baked-secrets.js +121 -0
  7. package/dist/src/binary-build-worker.js +312 -0
  8. package/dist/src/binary-run.js +540 -0
  9. package/dist/src/boundaries.js +1 -0
  10. package/dist/src/build-time-config.js +25 -0
  11. package/dist/src/control-plane/agent-roles.js +27 -0
  12. package/dist/src/control-plane/agent-wrapper.js +9621 -0
  13. package/dist/src/control-plane/authority-files.js +582 -0
  14. package/dist/src/control-plane/browser-contract.js +135 -0
  15. package/dist/src/control-plane/controlled-bash.js +1111 -0
  16. package/dist/src/control-plane/errors.js +13 -0
  17. package/dist/src/control-plane/harness-main.js +10828 -0
  18. package/dist/src/control-plane/hook-materializer.js +75 -0
  19. package/dist/src/control-plane/hooks/audit-trail.js +353 -0
  20. package/dist/src/control-plane/hooks/completion-verification.js +7552 -0
  21. package/dist/src/control-plane/hooks/import-guard.js +890 -0
  22. package/dist/src/control-plane/hooks/inject-context.js +4189 -0
  23. package/dist/src/control-plane/hooks/post-edit-lint.js +43 -0
  24. package/dist/src/control-plane/hooks/safety-guard.js +910 -0
  25. package/dist/src/control-plane/hooks/scope-guard.js +907 -0
  26. package/dist/src/control-plane/hooks/shared.js +44 -0
  27. package/dist/src/control-plane/hooks/submodule-branch.js +7797 -0
  28. package/dist/src/control-plane/hooks/task-runtime-start.js +7799 -0
  29. package/dist/src/control-plane/hooks/test-integrity-guard.js +891 -0
  30. package/dist/src/control-plane/materialize-task-config.js +453 -0
  31. package/dist/src/control-plane/memory-sync/cli.js +2019 -0
  32. package/dist/src/control-plane/memory-sync/db.js +753 -0
  33. package/dist/src/control-plane/memory-sync/embed.js +281 -0
  34. package/dist/src/control-plane/memory-sync/index.js +2049 -0
  35. package/dist/src/control-plane/memory-sync/query.js +294 -0
  36. package/dist/src/control-plane/memory-sync/read.js +784 -0
  37. package/dist/src/control-plane/memory-sync/types.js +6 -0
  38. package/dist/src/control-plane/memory-sync/write.js +1547 -0
  39. package/dist/src/control-plane/native/git-native.js +490 -0
  40. package/dist/src/control-plane/native/git-ops.js +2860 -0
  41. package/dist/src/control-plane/native/harness-cli.js +9721 -0
  42. package/dist/src/control-plane/native/pr-automation.js +373 -0
  43. package/dist/src/control-plane/native/profile-ops.js +481 -0
  44. package/dist/src/control-plane/native/repo-ops.js +2342 -0
  45. package/dist/src/control-plane/native/root-resolver.js +66 -0
  46. package/dist/src/control-plane/native/run-ops.js +3281 -0
  47. package/dist/src/control-plane/native/runtime-native-sidecar.js +299 -0
  48. package/dist/src/control-plane/native/runtime-native.js +392 -0
  49. package/dist/src/control-plane/native/scope-rules.js +17 -0
  50. package/dist/src/control-plane/native/task-ops.js +6320 -0
  51. package/dist/src/control-plane/native/task-state.js +1512 -0
  52. package/dist/src/control-plane/native/utils.js +535 -0
  53. package/dist/src/control-plane/native/validator-binaries.js +889 -0
  54. package/dist/src/control-plane/native/validator.js +2197 -0
  55. package/dist/src/control-plane/native/verifier.js +3249 -0
  56. package/dist/src/control-plane/native/workspace-ops.js +1635 -0
  57. package/dist/src/control-plane/plugin-host-context.js +334 -0
  58. package/dist/src/control-plane/project-main-pre-run-sync.js +630 -0
  59. package/dist/src/control-plane/provider/claude-stream-records.js +158 -0
  60. package/dist/src/control-plane/provider/codex-app-server.js +885 -0
  61. package/dist/src/control-plane/provider/codex-exec-records.js +203 -0
  62. package/dist/src/control-plane/provider/rig-task-run-skill.js +39 -0
  63. package/dist/src/control-plane/provider/runtime-instructions.js +96 -0
  64. package/dist/src/control-plane/remote.js +854 -0
  65. package/dist/src/control-plane/repos/index.js +473 -0
  66. package/dist/src/control-plane/repos/layout.js +124 -0
  67. package/dist/src/control-plane/repos/mirror/bootstrap.js +268 -0
  68. package/dist/src/control-plane/repos/mirror/refresh.js +398 -0
  69. package/dist/src/control-plane/repos/mirror/state.js +167 -0
  70. package/dist/src/control-plane/repos/registry.js +77 -0
  71. package/dist/src/control-plane/repos/types.js +1 -0
  72. package/dist/src/control-plane/runtime/agent-mode.js +48 -0
  73. package/dist/src/control-plane/runtime/baked-secrets.js +120 -0
  74. package/dist/src/control-plane/runtime/claude-tool-router-binary.js +343 -0
  75. package/dist/src/control-plane/runtime/claude-tool-router.js +520 -0
  76. package/dist/src/control-plane/runtime/context.js +216 -0
  77. package/dist/src/control-plane/runtime/events.js +218 -0
  78. package/dist/src/control-plane/runtime/guard-types.js +6 -0
  79. package/dist/src/control-plane/runtime/guard.js +880 -0
  80. package/dist/src/control-plane/runtime/image/fingerprint-sidecar.js +1194 -0
  81. package/dist/src/control-plane/runtime/image/index.js +2255 -0
  82. package/dist/src/control-plane/runtime/image-fingerprint-sidecar.js +1191 -0
  83. package/dist/src/control-plane/runtime/image.js +2255 -0
  84. package/dist/src/control-plane/runtime/index.js +8511 -0
  85. package/dist/src/control-plane/runtime/isolation/discovery.js +599 -0
  86. package/dist/src/control-plane/runtime/isolation/home.js +1217 -0
  87. package/dist/src/control-plane/runtime/isolation/index.js +8193 -0
  88. package/dist/src/control-plane/runtime/isolation/runner.js +2651 -0
  89. package/dist/src/control-plane/runtime/isolation/shared.js +501 -0
  90. package/dist/src/control-plane/runtime/isolation/toolchain.js +1892 -0
  91. package/dist/src/control-plane/runtime/isolation/types.js +1 -0
  92. package/dist/src/control-plane/runtime/isolation/worktree.js +509 -0
  93. package/dist/src/control-plane/runtime/isolation.js +8193 -0
  94. package/dist/src/control-plane/runtime/overlay.js +67 -0
  95. package/dist/src/control-plane/runtime/plugin-mode.js +41 -0
  96. package/dist/src/control-plane/runtime/plugins.js +1131 -0
  97. package/dist/src/control-plane/runtime/provisioning-env.js +220 -0
  98. package/dist/src/control-plane/runtime/queue.js +8358 -0
  99. package/dist/src/control-plane/runtime/rig-shell.js +205 -0
  100. package/dist/src/control-plane/runtime/rig-tools.js +182 -0
  101. package/dist/src/control-plane/runtime/runner-context.js +1 -0
  102. package/dist/src/control-plane/runtime/runtime-paths.js +184 -0
  103. package/dist/src/control-plane/runtime/sandbox/backend-bwrap.js +311 -0
  104. package/dist/src/control-plane/runtime/sandbox/backend-none.js +21 -0
  105. package/dist/src/control-plane/runtime/sandbox/backend-seatbelt.js +268 -0
  106. package/dist/src/control-plane/runtime/sandbox/backend.js +1718 -0
  107. package/dist/src/control-plane/runtime/sandbox/orchestrator.js +1745 -0
  108. package/dist/src/control-plane/runtime/sandbox/utils.js +137 -0
  109. package/dist/src/control-plane/runtime/sandbox-backend-bwrap.js +311 -0
  110. package/dist/src/control-plane/runtime/sandbox-backend-none.js +21 -0
  111. package/dist/src/control-plane/runtime/sandbox-backend-seatbelt.js +268 -0
  112. package/dist/src/control-plane/runtime/sandbox-backend.js +1718 -0
  113. package/dist/src/control-plane/runtime/sandbox-orchestrator.js +1745 -0
  114. package/dist/src/control-plane/runtime/sandbox-utils.js +137 -0
  115. package/dist/src/control-plane/runtime/snapshot/index.js +454 -0
  116. package/dist/src/control-plane/runtime/snapshot/sidecar.js +502 -0
  117. package/dist/src/control-plane/runtime/snapshot/task-run.js +1578 -0
  118. package/dist/src/control-plane/runtime/snapshot-sidecar.js +498 -0
  119. package/dist/src/control-plane/runtime/snapshot.js +454 -0
  120. package/dist/src/control-plane/runtime/task-run-snapshot.js +1578 -0
  121. package/dist/src/control-plane/runtime/tool-gateway.js +422 -0
  122. package/dist/src/control-plane/runtime/tooling/browser-tools.js +32 -0
  123. package/dist/src/control-plane/runtime/tooling/claude-router-binary.js +343 -0
  124. package/dist/src/control-plane/runtime/tooling/claude-router.js +524 -0
  125. package/dist/src/control-plane/runtime/tooling/file-tools.js +182 -0
  126. package/dist/src/control-plane/runtime/tooling/gateway.js +422 -0
  127. package/dist/src/control-plane/runtime/tooling/index.js +1290 -0
  128. package/dist/src/control-plane/runtime/tooling/shell.js +205 -0
  129. package/dist/src/control-plane/runtime/types.js +1 -0
  130. package/dist/src/control-plane/setup-version.js +14 -0
  131. package/dist/src/control-plane/state-sync/index.js +1509 -0
  132. package/dist/src/control-plane/state-sync/read.js +856 -0
  133. package/dist/src/control-plane/state-sync/reconcile.js +260 -0
  134. package/dist/src/control-plane/state-sync/repo.js +302 -0
  135. package/dist/src/control-plane/state-sync/types.js +111 -0
  136. package/dist/src/control-plane/state-sync/write.js +1469 -0
  137. package/dist/src/control-plane/task-fields.js +38 -0
  138. package/dist/src/control-plane/task-source-bootstrap.js +46 -0
  139. package/dist/src/control-plane/task-source.js +30 -0
  140. package/dist/src/control-plane/tasks/legacy-task-config-source.js +130 -0
  141. package/dist/src/control-plane/tasks/plugin-task-source.js +103 -0
  142. package/dist/src/control-plane/tasks/source-aware-task-config-source.js +611 -0
  143. package/dist/src/control-plane/tasks/source-lifecycle.js +1093 -0
  144. package/dist/src/control-plane/tasks/task-record-reader.js +9 -0
  145. package/dist/src/control-plane/validators/boundary/public-apis.js +107 -0
  146. package/dist/src/control-plane/validators/integration/_shared.js +51 -0
  147. package/dist/src/control-plane/validators/integration/adm-audit-http.js +85 -0
  148. package/dist/src/control-plane/validators/integration/adm-auth-http.js +78 -0
  149. package/dist/src/control-plane/validators/integration/adm-issuer-http.js +80 -0
  150. package/dist/src/control-plane/validators/integration/adm-migration.js +78 -0
  151. package/dist/src/control-plane/validators/integration/adm-scaffold.js +78 -0
  152. package/dist/src/control-plane/validators/runtime-registration.js +64 -0
  153. package/dist/src/control-plane/validators/shared.js +683 -0
  154. package/dist/src/events.js +218 -0
  155. package/dist/src/execution.js +35 -0
  156. package/dist/src/index.js +1633 -0
  157. package/dist/src/layout.js +145 -0
  158. package/dist/src/local-server.js +202 -0
  159. package/dist/src/plugins.js +329 -0
  160. package/dist/src/remote-http.js +83 -0
  161. package/dist/src/runtime-context.js +216 -0
  162. package/dist/src/types.js +1 -0
  163. package/native/darwin-arm64/bin/rig-git +0 -0
  164. package/native/darwin-arm64/bin/rig-shell +0 -0
  165. package/native/darwin-arm64/bin/rig-tools +0 -0
  166. package/native/darwin-arm64/lib/runtime-native-darwin-arm64.dylib +0 -0
  167. package/native/darwin-arm64/lib/runtime-native.dylib +0 -0
  168. package/native/darwin-arm64/manifest.json +1 -0
  169. package/native/linux-x64/bin/rig-git +0 -0
  170. package/native/linux-x64/bin/rig-shell +0 -0
  171. package/native/linux-x64/bin/rig-tools +0 -0
  172. package/native/linux-x64/lib/runtime-native-linux-x64.so +0 -0
  173. package/native/linux-x64/lib/runtime-native.so +0 -0
  174. package/native/linux-x64/manifest.json +1 -0
  175. package/package.json +74 -0
  176. package/skills/rig-task-run.md +71 -0
@@ -0,0 +1,1745 @@
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/runtime/src/layout.ts
43
+ import { existsSync } from "fs";
44
+ import { basename, dirname, resolve } from "path";
45
+ function resolveMonorepoRoot(projectRoot) {
46
+ const normalizedProjectRoot = resolve(projectRoot);
47
+ const explicit = process.env.MONOREPO_ROOT?.trim();
48
+ if (explicit) {
49
+ const explicitRoot = resolve(explicit);
50
+ const explicitParent = dirname(explicitRoot);
51
+ if (basename(explicitParent) === ".worktrees") {
52
+ const owner = dirname(explicitParent);
53
+ const ownerHasGit = existsSync(resolve(owner, ".git"));
54
+ const ownerHasTaskConfig = existsSync(resolve(owner, ".rig", "task-config.json"));
55
+ const ownerHasRigConfig = existsSync(resolve(owner, "rig.config.ts"));
56
+ if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
57
+ return owner;
58
+ }
59
+ throw new Error(`MONOREPO_ROOT points to worktree ${explicitRoot}, but the owner checkout is incomplete at ${owner}.`);
60
+ }
61
+ if (!existsSync(resolve(explicitRoot, ".git"))) {
62
+ throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but no git checkout was found there.`);
63
+ }
64
+ const hasTaskConfig = existsSync(resolve(explicitRoot, ".rig", "task-config.json"));
65
+ const hasRigConfig = existsSync(resolve(explicitRoot, "rig.config.ts"));
66
+ if (!hasTaskConfig && !hasRigConfig) {
67
+ throw new Error(`MONOREPO_ROOT points to ${explicitRoot}, but neither .rig/task-config.json nor rig.config.ts exists there.`);
68
+ }
69
+ return explicitRoot;
70
+ }
71
+ const projectParent = dirname(normalizedProjectRoot);
72
+ if (basename(projectParent) === ".worktrees") {
73
+ const worktreeOwner = dirname(projectParent);
74
+ const ownerHasGit = existsSync(resolve(worktreeOwner, ".git"));
75
+ const ownerHasTaskConfig = existsSync(resolve(worktreeOwner, ".rig", "task-config.json"));
76
+ const ownerHasRigConfig = existsSync(resolve(worktreeOwner, "rig.config.ts"));
77
+ if (ownerHasGit && (ownerHasTaskConfig || ownerHasRigConfig)) {
78
+ return worktreeOwner;
79
+ }
80
+ }
81
+ return normalizedProjectRoot;
82
+ }
83
+ var init_layout = () => {};
84
+
85
+ // packages/runtime/src/control-plane/runtime/sandbox/utils.ts
86
+ import { existsSync as existsSync4, readdirSync, realpathSync } from "fs";
87
+ import { resolve as resolve4 } from "path";
88
+ function toRealPath(path) {
89
+ if (!existsSync4(path)) {
90
+ return resolve4(path);
91
+ }
92
+ try {
93
+ return realpathSync.native(path);
94
+ } catch {
95
+ return resolve4(path);
96
+ }
97
+ }
98
+ function resolveHostGitMetadataPaths(projectRoot, workspaceDir) {
99
+ const candidates = new Set;
100
+ const addPath = (candidate) => {
101
+ if (existsSync4(candidate)) {
102
+ candidates.add(toRealPath(candidate));
103
+ }
104
+ };
105
+ addPath(resolve4(projectRoot, ".git"));
106
+ addPath(resolve4(workspaceDir, "..", "..", ".git"));
107
+ for (const repoRoot of resolveHostRepoRootPaths(projectRoot)) {
108
+ addPath(resolve4(repoRoot, ".git"));
109
+ }
110
+ const workspaceGit = resolve4(workspaceDir, ".git");
111
+ if (existsSync4(workspaceGit)) {
112
+ addPath(workspaceGit);
113
+ }
114
+ return [...candidates];
115
+ }
116
+ function resolveHostRepoRootPaths(projectRoot) {
117
+ const candidates = new Set;
118
+ const addPath = (candidate) => {
119
+ if (existsSync4(candidate)) {
120
+ candidates.add(toRealPath(candidate));
121
+ }
122
+ };
123
+ try {
124
+ const monorepoRoot = resolveMonorepoRoot(projectRoot);
125
+ if (toRealPath(monorepoRoot) !== toRealPath(projectRoot)) {
126
+ addPath(monorepoRoot);
127
+ }
128
+ } catch {}
129
+ const reposDir = resolve4(projectRoot, "repos");
130
+ if (existsSync4(reposDir)) {
131
+ for (const entry of readdirSync(reposDir, { withFileTypes: true })) {
132
+ if (entry.isDirectory() || entry.isSymbolicLink()) {
133
+ addPath(resolve4(reposDir, entry.name));
134
+ }
135
+ }
136
+ }
137
+ return [...candidates];
138
+ }
139
+ function resolveNetworkWithPolicy(sandboxConfig, envOverride) {
140
+ if (envOverride) {
141
+ const envValue = parseBooleanEnv(envOverride, sandboxConfig.network);
142
+ if (envValue !== sandboxConfig.network) {
143
+ console.warn(`[sandbox] RIG_RUNTIME_SANDBOX_NETWORK=${envOverride} overrides policy sandbox.network=${sandboxConfig.network}`);
144
+ }
145
+ return envValue;
146
+ }
147
+ return sandboxConfig.network;
148
+ }
149
+ function parseBooleanEnv(raw, fallback) {
150
+ if (!raw) {
151
+ return fallback;
152
+ }
153
+ const normalized = raw.trim().toLowerCase();
154
+ if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
155
+ return true;
156
+ }
157
+ if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
158
+ return false;
159
+ }
160
+ return fallback;
161
+ }
162
+ function uniq(values) {
163
+ return [...new Set(values)];
164
+ }
165
+ function seatbeltString(value) {
166
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
167
+ }
168
+ var init_utils = __esm(() => {
169
+ init_layout();
170
+ });
171
+
172
+ // packages/runtime/src/control-plane/runtime/sandbox/backend-seatbelt.ts
173
+ var exports_backend_seatbelt = {};
174
+ __export(exports_backend_seatbelt, {
175
+ SeatbeltBackend: () => SeatbeltBackend
176
+ });
177
+ import { mkdirSync as mkdirSync2, writeFileSync } from "fs";
178
+ import { resolve as resolve6 } from "path";
179
+
180
+ class SeatbeltBackend {
181
+ kind = "macos-seatbelt";
182
+ binaryPath;
183
+ config;
184
+ ctx;
185
+ resolvedPaths;
186
+ constructor(binaryPath, config, ctx, resolvedPaths) {
187
+ this.binaryPath = binaryPath;
188
+ this.config = config;
189
+ this.ctx = ctx;
190
+ this.resolvedPaths = resolvedPaths;
191
+ }
192
+ wrap(options) {
193
+ const profilePath = this.writeSeatbeltProfile(options);
194
+ return {
195
+ command: [this.binaryPath, "-f", profilePath, ...options.command],
196
+ enabled: true,
197
+ backend: "macos-seatbelt",
198
+ profilePath
199
+ };
200
+ }
201
+ writeSeatbeltProfile(options) {
202
+ const sandboxDir = resolve6(options.runtime.rootDir, "sandbox");
203
+ mkdirSync2(sandboxDir, { recursive: true });
204
+ const profilePath = resolve6(sandboxDir, "seatbelt.sb");
205
+ const profile = this.renderProfile(options);
206
+ writeFileSync(profilePath, `${profile}
207
+ `, "utf-8");
208
+ return profilePath;
209
+ }
210
+ renderProfile(options) {
211
+ const { runtime, projectRoot } = options;
212
+ const { ctx, resolvedPaths, config } = this;
213
+ const workspaceReal = ctx.realPath(runtime.workspaceDir);
214
+ const runtimeRootReal = ctx.realPath(runtime.rootDir);
215
+ const homeReal = ctx.realPath(runtime.homeDir);
216
+ const tmpReal = ctx.realPath(runtime.tmpDir);
217
+ const cacheReal = ctx.realPath(runtime.cacheDir);
218
+ const hostGitDirs = resolveHostGitMetadataPaths(projectRoot, runtime.workspaceDir);
219
+ const hostRepoRoots = resolveHostRepoRootPaths(projectRoot).map((repoRoot) => ctx.realPath(repoRoot));
220
+ const bunDir = ctx.realPath(resolvedPaths.bunDir);
221
+ const claudeDir = resolvedPaths.claudeDir ? ctx.realPath(resolvedPaths.claudeDir) : null;
222
+ const allowNetwork = resolveNetworkWithPolicy(config, process.env.RIG_RUNTIME_SANDBOX_NETWORK);
223
+ const lines = [
224
+ "(version 1)",
225
+ "(deny default)",
226
+ '(import "system.sb")',
227
+ "(allow process*)",
228
+ "(allow process-info*)",
229
+ "(allow signal)",
230
+ "(allow sysctl-read)",
231
+ "(allow file-read-metadata)"
232
+ ];
233
+ if (allowNetwork) {
234
+ lines.push("(allow network*)");
235
+ }
236
+ for (const sysPath of [
237
+ "/usr/lib",
238
+ "/usr/bin",
239
+ "/usr/sbin",
240
+ "/usr/share",
241
+ "/bin",
242
+ "/sbin",
243
+ "/System",
244
+ "/Library",
245
+ "/Library/Frameworks",
246
+ "/Library/Developer",
247
+ "/Library/Apple",
248
+ "/Applications",
249
+ "/private/var/db",
250
+ "/opt/homebrew"
251
+ ]) {
252
+ lines.push(`(allow file-read* (subpath ${seatbeltString(sysPath)}))`);
253
+ }
254
+ lines.push(`(allow file-read* (subpath ${seatbeltString(bunDir)}))`);
255
+ if (claudeDir) {
256
+ lines.push(`(allow file-read* (subpath ${seatbeltString(claudeDir)}))`);
257
+ }
258
+ if (resolvedPaths.nodeDir) {
259
+ lines.push(`(allow file-read* (subpath ${seatbeltString(resolvedPaths.nodeDir)}))`);
260
+ }
261
+ for (const depPath of resolvedPaths.depRoots) {
262
+ lines.push(`(allow file-read* (subpath ${seatbeltString(depPath)}))`);
263
+ }
264
+ for (const rwPath of uniq([
265
+ workspaceReal,
266
+ runtimeRootReal,
267
+ homeReal,
268
+ tmpReal,
269
+ cacheReal
270
+ ])) {
271
+ lines.push(`(allow file-read* (subpath ${seatbeltString(rwPath)}))`);
272
+ lines.push(`(allow file-write* (subpath ${seatbeltString(rwPath)}))`);
273
+ }
274
+ for (const gitPath of hostGitDirs) {
275
+ lines.push(`(allow file-read* (subpath ${seatbeltString(gitPath)}))`);
276
+ lines.push(`(allow file-write* (subpath ${seatbeltString(gitPath)}))`);
277
+ }
278
+ const projectRootReal = ctx.realPath(projectRoot);
279
+ if (projectRootReal !== workspaceReal && !projectRootReal.startsWith(workspaceReal + "/")) {
280
+ lines.push(`(allow file-read* (subpath ${seatbeltString(projectRootReal)}))`);
281
+ }
282
+ for (const repoRoot of hostRepoRoots) {
283
+ if (!ctx.pathExists(repoRoot) || repoRoot === workspaceReal || repoRoot.startsWith(workspaceReal + "/") || repoRoot === projectRootReal || repoRoot.startsWith(projectRootReal + "/")) {
284
+ continue;
285
+ }
286
+ lines.push(`(allow file-read* (subpath ${seatbeltString(repoRoot)}))`);
287
+ }
288
+ const realHome = process.env.HOME?.trim();
289
+ if (realHome) {
290
+ for (const binSubdir of [".local/bin", ".cargo/bin"]) {
291
+ const binPath = resolve6(realHome, binSubdir);
292
+ if (ctx.pathExists(binPath)) {
293
+ lines.push(`(allow file-read* (subpath ${seatbeltString(ctx.realPath(binPath))}))`);
294
+ }
295
+ }
296
+ }
297
+ for (const tempPath of [
298
+ "/dev",
299
+ "/tmp",
300
+ "/private/tmp",
301
+ "/var/folders",
302
+ "/private/var/folders"
303
+ ]) {
304
+ lines.push(`(allow file-read* (subpath ${seatbeltString(tempPath)}))`);
305
+ lines.push(`(allow file-write* (subpath ${seatbeltString(tempPath)}))`);
306
+ }
307
+ return lines.join(`
308
+ `);
309
+ }
310
+ }
311
+ var init_backend_seatbelt = __esm(() => {
312
+ init_utils();
313
+ });
314
+
315
+ // packages/runtime/src/control-plane/runtime/sandbox/backend-bwrap.ts
316
+ var exports_backend_bwrap = {};
317
+ __export(exports_backend_bwrap, {
318
+ BwrapBackend: () => BwrapBackend
319
+ });
320
+ import { mkdirSync as mkdirSync3 } from "fs";
321
+ import { resolve as resolve7 } from "path";
322
+
323
+ class BwrapBackend {
324
+ kind = "linux-bwrap";
325
+ binaryPath;
326
+ config;
327
+ ctx;
328
+ resolvedPaths;
329
+ which;
330
+ constructor(binaryPath, config, ctx, resolvedPaths, which) {
331
+ this.binaryPath = binaryPath;
332
+ this.config = config;
333
+ this.ctx = ctx;
334
+ this.resolvedPaths = resolvedPaths;
335
+ this.which = which ?? ((bin) => Bun.which(bin));
336
+ }
337
+ wrap(options) {
338
+ const command = this.buildCommand(options);
339
+ return {
340
+ command,
341
+ enabled: true,
342
+ backend: "linux-bwrap"
343
+ };
344
+ }
345
+ buildCommand(options) {
346
+ const { runtime, projectRoot, command } = options;
347
+ const { ctx, resolvedPaths, config } = this;
348
+ const workspaceReal = ctx.realPath(runtime.workspaceDir);
349
+ const runtimeRootReal = ctx.realPath(runtime.rootDir);
350
+ const homeReal = ctx.realPath(runtime.homeDir);
351
+ const tmpReal = ctx.realPath(runtime.tmpDir);
352
+ const cacheReal = ctx.realPath(runtime.cacheDir);
353
+ const hostGitDirs = resolveHostGitMetadataPaths(projectRoot, runtime.workspaceDir);
354
+ const hostRepoRoots = resolveHostRepoRootPaths(projectRoot).map((repoRoot) => ctx.realPath(repoRoot));
355
+ const bunDir = ctx.realPath(resolvedPaths.bunDir);
356
+ const claudeDir = resolvedPaths.claudeDir ? ctx.realPath(resolvedPaths.claudeDir) : null;
357
+ const allowNetwork = resolveNetworkWithPolicy(config, process.env.RIG_RUNTIME_SANDBOX_NETWORK);
358
+ const args = [
359
+ this.binaryPath,
360
+ "--die-with-parent",
361
+ "--new-session",
362
+ "--unshare-pid",
363
+ "--tmpfs",
364
+ "/",
365
+ "--ro-bind",
366
+ "/usr",
367
+ "/usr",
368
+ "--ro-bind",
369
+ "/bin",
370
+ "/bin",
371
+ "--ro-bind",
372
+ "/sbin",
373
+ "/sbin"
374
+ ];
375
+ for (const libPath of ["/lib", "/lib64"]) {
376
+ if (ctx.pathExists(libPath)) {
377
+ args.push("--ro-bind", libPath, libPath);
378
+ }
379
+ }
380
+ for (const etcEntry of [
381
+ "/etc/ld.so.cache",
382
+ "/etc/ld.so.conf",
383
+ "/etc/ld.so.conf.d",
384
+ "/etc/resolv.conf",
385
+ "/etc/hosts",
386
+ "/etc/nsswitch.conf",
387
+ "/etc/gai.conf",
388
+ "/etc/host.conf",
389
+ "/etc/ssl",
390
+ "/etc/ca-certificates",
391
+ "/etc/pki",
392
+ "/etc/passwd",
393
+ "/etc/group",
394
+ "/etc/localtime",
395
+ "/etc/timezone",
396
+ "/etc/locale.conf",
397
+ "/etc/default/locale"
398
+ ]) {
399
+ if (ctx.pathExists(etcEntry)) {
400
+ args.push("--ro-bind", etcEntry, etcEntry);
401
+ }
402
+ }
403
+ if (ctx.pathExists("/run/systemd/resolve")) {
404
+ args.push("--ro-bind", "/run/systemd/resolve", "/run/systemd/resolve");
405
+ }
406
+ if (ctx.pathExists("/run/nscd")) {
407
+ args.push("--ro-bind", "/run/nscd", "/run/nscd");
408
+ }
409
+ args.push("--ro-bind", bunDir, bunDir);
410
+ if (claudeDir) {
411
+ args.push("--ro-bind", claudeDir, claudeDir);
412
+ }
413
+ if (resolvedPaths.nodeDir && ctx.pathExists(resolvedPaths.nodeDir)) {
414
+ args.push("--ro-bind", resolvedPaths.nodeDir, resolvedPaths.nodeDir);
415
+ }
416
+ for (const depPath of resolvedPaths.depRoots) {
417
+ if (ctx.pathExists(depPath)) {
418
+ args.push("--ro-bind", depPath, depPath);
419
+ }
420
+ }
421
+ const projectRootReal = ctx.realPath(projectRoot);
422
+ if (projectRootReal !== workspaceReal && !projectRootReal.startsWith(workspaceReal + "/") && ctx.pathExists(projectRootReal)) {
423
+ args.push("--ro-bind", projectRootReal, projectRootReal);
424
+ }
425
+ for (const repoRoot of hostRepoRoots) {
426
+ if (!ctx.pathExists(repoRoot) || repoRoot === workspaceReal || repoRoot.startsWith(workspaceReal + "/") || repoRoot === projectRootReal || repoRoot.startsWith(projectRootReal + "/")) {
427
+ continue;
428
+ }
429
+ args.push("--ro-bind", repoRoot, repoRoot);
430
+ }
431
+ args.push("--bind", workspaceReal, workspaceReal);
432
+ args.push("--bind", runtimeRootReal, runtimeRootReal);
433
+ for (const rwPath of uniq([homeReal, tmpReal, cacheReal])) {
434
+ if (rwPath !== runtimeRootReal && !rwPath.startsWith(runtimeRootReal + "/")) {
435
+ args.push("--bind", rwPath, rwPath);
436
+ }
437
+ }
438
+ for (const gitPath of hostGitDirs) {
439
+ if (!ctx.pathExists(gitPath))
440
+ continue;
441
+ if (gitPath === runtimeRootReal || gitPath.startsWith(runtimeRootReal + "/"))
442
+ continue;
443
+ if (gitPath === workspaceReal || gitPath.startsWith(workspaceReal + "/"))
444
+ continue;
445
+ args.push("--bind", gitPath, gitPath);
446
+ }
447
+ const realHome = process.env.HOME?.trim();
448
+ if (realHome) {
449
+ for (const binSubdir of [".local/bin", ".local/lib", ".cargo/bin"]) {
450
+ const binPath = ctx.realPath(resolve7(realHome, binSubdir));
451
+ if (ctx.pathExists(binPath)) {
452
+ args.push("--ro-bind", binPath, binPath);
453
+ }
454
+ }
455
+ const agentSshDir = resolve7(homeReal, ".ssh");
456
+ if (ctx.pathExists(agentSshDir)) {
457
+ args.push("--ro-bind", agentSshDir, agentSshDir);
458
+ } else {
459
+ const hostSshDir = resolve7(realHome, ".ssh");
460
+ if (ctx.pathExists(hostSshDir)) {
461
+ mkdirSync3(agentSshDir, { recursive: true });
462
+ args.push("--ro-bind", hostSshDir, agentSshDir);
463
+ args.push("--ro-bind", hostSshDir, hostSshDir);
464
+ }
465
+ }
466
+ }
467
+ args.push("--proc", "/proc");
468
+ args.push("--dev", "/dev");
469
+ args.push("--tmpfs", "/tmp");
470
+ args.push("--unsetenv", "CLAUDECODE");
471
+ args.push("--setenv", "HOME", homeReal);
472
+ args.push("--setenv", "TMPDIR", "/tmp");
473
+ args.push("--chdir", workspaceReal);
474
+ if (!allowNetwork) {
475
+ args.push("--unshare-net");
476
+ }
477
+ args.push("--", ...this.resolveCommandBinary(command));
478
+ return args;
479
+ }
480
+ resolveCommandBinary(command) {
481
+ if (command.length === 0)
482
+ return command;
483
+ const [bin, ...rest] = command;
484
+ if (!bin)
485
+ return command;
486
+ const resolved = this.which(bin);
487
+ if (!resolved)
488
+ return command;
489
+ try {
490
+ const { realpathSync: realpathSync3 } = __require("fs");
491
+ const resolvedBinary = realpathSync3(resolved);
492
+ return [resolvedBinary, ...rest];
493
+ } catch {
494
+ return [resolved, ...rest];
495
+ }
496
+ }
497
+ }
498
+ var init_backend_bwrap = __esm(() => {
499
+ init_utils();
500
+ });
501
+
502
+ // packages/runtime/src/control-plane/runtime/sandbox/backend.ts
503
+ import { existsSync as existsSync6 } from "fs";
504
+
505
+ // packages/runtime/src/control-plane/runtime/guard.ts
506
+ import { optimizeNextInvocation } from "bun:jsc";
507
+ import { existsSync as existsSync3, readFileSync, statSync as statSync2 } from "fs";
508
+ import { resolve as resolve3 } from "path";
509
+
510
+ // packages/runtime/src/control-plane/native/utils.ts
511
+ import { ptr as ptr2 } from "bun:ffi";
512
+ init_layout();
513
+
514
+ // packages/runtime/src/control-plane/native/runtime-native.ts
515
+ import { dlopen, ptr, suffix, toBuffer } from "bun:ffi";
516
+ import { copyFileSync, existsSync as existsSync2, mkdirSync, renameSync, rmSync, statSync } from "fs";
517
+ import { tmpdir } from "os";
518
+ import { dirname as dirname2, resolve as resolve2 } from "path";
519
+ var sharedNativeRuntimeOutputDir = resolve2(tmpdir(), "rig-native");
520
+ var sharedNativeRuntimeOutputPath = resolve2(sharedNativeRuntimeOutputDir, `runtime-native-${process.platform}-${process.arch}.${suffix}`);
521
+ var colocatedNativeRuntimeFileName = `runtime-native.${suffix}`;
522
+ var nativeRuntimeLibrary = await loadNativeRuntimeLibrary();
523
+ function requireNativeRuntimeLibrary(feature) {
524
+ if (!nativeRuntimeLibrary) {
525
+ throw new Error(`Native Zig runtime is required for ${feature}`);
526
+ }
527
+ return nativeRuntimeLibrary;
528
+ }
529
+ async function ensureNativeRuntimeLibraryPath(outputPath = sharedNativeRuntimeOutputPath, options = {}) {
530
+ if (await buildNativeRuntimeLibrary(outputPath, options)) {
531
+ return outputPath;
532
+ }
533
+ return !options.force && existsSync2(outputPath) ? outputPath : null;
534
+ }
535
+ async function loadNativeRuntimeLibrary() {
536
+ if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
537
+ return null;
538
+ }
539
+ for (const candidate of nativeRuntimeLibraryCandidates()) {
540
+ if (!candidate || !existsSync2(candidate)) {
541
+ continue;
542
+ }
543
+ const loaded = tryDlopenNativeRuntimeLibrary(candidate);
544
+ if (loaded) {
545
+ return loaded;
546
+ }
547
+ }
548
+ const builtLibraryPath = await ensureNativeRuntimeLibraryPath(sharedNativeRuntimeOutputPath, { force: true });
549
+ if (!builtLibraryPath) {
550
+ return null;
551
+ }
552
+ return tryDlopenNativeRuntimeLibrary(builtLibraryPath);
553
+ }
554
+ function nativePackageLibraryCandidates(fromDir, names) {
555
+ const candidates = [];
556
+ let cursor = resolve2(fromDir);
557
+ for (let index = 0;index < 8; index += 1) {
558
+ for (const name of names) {
559
+ candidates.push(resolve2(cursor, "native", `${process.platform}-${process.arch}`, name), resolve2(cursor, "native", `${process.platform}-${process.arch}`, "lib", name), resolve2(cursor, "native", name), resolve2(cursor, "native", "lib", name));
560
+ }
561
+ const parent = dirname2(cursor);
562
+ if (parent === cursor)
563
+ break;
564
+ cursor = parent;
565
+ }
566
+ return candidates;
567
+ }
568
+ function nativeRuntimeLibraryCandidates() {
569
+ const explicit = process.env.RIG_NATIVE_RUNTIME_LIB?.trim() || "";
570
+ const execDir = process.execPath?.trim() ? dirname2(process.execPath.trim()) : "";
571
+ const platformSpecific = `runtime-native-${process.platform}-${process.arch}.${suffix}`;
572
+ return [...new Set([
573
+ explicit,
574
+ ...nativePackageLibraryCandidates(import.meta.dir, [colocatedNativeRuntimeFileName, platformSpecific]),
575
+ execDir ? resolve2(execDir, colocatedNativeRuntimeFileName) : "",
576
+ execDir ? resolve2(execDir, platformSpecific) : "",
577
+ execDir ? resolve2(execDir, "..", colocatedNativeRuntimeFileName) : "",
578
+ execDir ? resolve2(execDir, "..", platformSpecific) : "",
579
+ execDir ? resolve2(execDir, "lib", colocatedNativeRuntimeFileName) : "",
580
+ execDir ? resolve2(execDir, "..", "lib", colocatedNativeRuntimeFileName) : "",
581
+ sharedNativeRuntimeOutputPath
582
+ ].filter(Boolean))];
583
+ }
584
+ function resolveNativeRuntimeSourcePath() {
585
+ const explicit = process.env.RIG_NATIVE_RUNTIME_SOURCE?.trim();
586
+ if (explicit && existsSync2(explicit)) {
587
+ return explicit;
588
+ }
589
+ const bundled = resolve2(import.meta.dir, "../../../native/snapshot.zig");
590
+ return existsSync2(bundled) ? bundled : null;
591
+ }
592
+ async function buildNativeRuntimeLibrary(outputPath, options = {}) {
593
+ if (process.env.RIG_DISABLE_ZIG_NATIVE === "1") {
594
+ return false;
595
+ }
596
+ const zigBinary = Bun.which("zig");
597
+ const sourcePath = resolveNativeRuntimeSourcePath();
598
+ if (!zigBinary || !sourcePath) {
599
+ return false;
600
+ }
601
+ const tempOutputPath = `${outputPath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
602
+ try {
603
+ mkdirSync(dirname2(outputPath), { recursive: true });
604
+ const needsBuild = options.force === true || !existsSync2(outputPath) || statSync(sourcePath).mtimeMs > statSync(outputPath).mtimeMs;
605
+ if (!needsBuild) {
606
+ return true;
607
+ }
608
+ const build = Bun.spawn([
609
+ zigBinary,
610
+ "build-lib",
611
+ sourcePath,
612
+ "-dynamic",
613
+ "-O",
614
+ "ReleaseFast",
615
+ `-femit-bin=${tempOutputPath}`
616
+ ], {
617
+ cwd: import.meta.dir,
618
+ stdout: "pipe",
619
+ stderr: "pipe"
620
+ });
621
+ const exitCode = await build.exited;
622
+ if (exitCode !== 0 || !existsSync2(tempOutputPath)) {
623
+ rmSync(tempOutputPath, { force: true });
624
+ return false;
625
+ }
626
+ renameSync(tempOutputPath, outputPath);
627
+ return true;
628
+ } catch {
629
+ rmSync(tempOutputPath, { force: true });
630
+ return false;
631
+ }
632
+ }
633
+ function tryDlopenNativeRuntimeLibrary(outputPath) {
634
+ try {
635
+ return dlopen(outputPath, {
636
+ rig_scope_match: {
637
+ args: ["ptr", "ptr"],
638
+ returns: "u8"
639
+ },
640
+ snapshot_capture: {
641
+ args: ["ptr", "u64", "ptr", "u64"],
642
+ returns: "ptr"
643
+ },
644
+ snapshot_delta: {
645
+ args: ["ptr", "ptr"],
646
+ returns: "ptr"
647
+ },
648
+ snapshot_store_delta: {
649
+ args: ["ptr", "ptr", "ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64"],
650
+ returns: "ptr"
651
+ },
652
+ snapshot_inspect_delta: {
653
+ args: ["ptr", "u64"],
654
+ returns: "ptr"
655
+ },
656
+ snapshot_apply_delta: {
657
+ args: ["ptr", "u64", "ptr", "u64"],
658
+ returns: "ptr"
659
+ },
660
+ snapshot_release: {
661
+ args: ["ptr"],
662
+ returns: "void"
663
+ },
664
+ runtime_hash_file: {
665
+ args: ["ptr", "u64"],
666
+ returns: "ptr"
667
+ },
668
+ runtime_hash_tree: {
669
+ args: ["ptr", "u64"],
670
+ returns: "ptr"
671
+ },
672
+ runtime_prepare_paths: {
673
+ args: ["ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64", "ptr", "u64"],
674
+ returns: "ptr"
675
+ },
676
+ runtime_link_dependency_layer: {
677
+ args: ["ptr", "u64", "ptr", "u64"],
678
+ returns: "ptr"
679
+ },
680
+ runtime_scan_worktrees: {
681
+ args: ["ptr", "u64"],
682
+ returns: "ptr"
683
+ }
684
+ });
685
+ } catch {
686
+ return null;
687
+ }
688
+ }
689
+
690
+ // packages/runtime/src/control-plane/native/scope-rules.ts
691
+ var activeRules = null;
692
+ function getScopeRules() {
693
+ return activeRules;
694
+ }
695
+
696
+ // packages/runtime/src/control-plane/native/utils.ts
697
+ var nativeScopeMatcher = null;
698
+ var scopeRegexCache = new Map;
699
+ function unique(values) {
700
+ return [...new Set(values)];
701
+ }
702
+ function normalizeRelativeScopePath(inputPath) {
703
+ let normalized = inputPath.replace(/^\.\//, "");
704
+ const rules = getScopeRules();
705
+ if (rules?.stripPrefixes) {
706
+ for (const prefix of rules.stripPrefixes) {
707
+ if (normalized.startsWith(prefix)) {
708
+ normalized = normalized.slice(prefix.length);
709
+ }
710
+ }
711
+ }
712
+ return normalized;
713
+ }
714
+ function normalizePathToScope(projectRoot, monorepoRoot, inputPath) {
715
+ let normalized = inputPath.replace(/^\.\//, "");
716
+ if (normalized.startsWith(projectRoot + "/")) {
717
+ normalized = normalized.slice(projectRoot.length + 1);
718
+ }
719
+ if (normalized.startsWith(monorepoRoot + "/")) {
720
+ normalized = normalized.slice(monorepoRoot.length + 1);
721
+ }
722
+ return normalizeRelativeScopePath(normalized);
723
+ }
724
+ function scopeMatches(path, scopes) {
725
+ const matcher = getNativeScopeMatcher();
726
+ const pathVariants = unique([path, normalizeRelativeScopePath(path)]);
727
+ for (const scope of scopes) {
728
+ const scopeVariants = unique([scope, normalizeRelativeScopePath(scope)]);
729
+ for (const candidatePath of pathVariants) {
730
+ for (const candidateScope of scopeVariants) {
731
+ if (candidatePath === candidateScope) {
732
+ return true;
733
+ }
734
+ if (matcher.match(candidateScope, candidatePath)) {
735
+ return true;
736
+ }
737
+ }
738
+ }
739
+ }
740
+ return false;
741
+ }
742
+ function getNativeScopeMatcher() {
743
+ if (nativeScopeMatcher) {
744
+ return nativeScopeMatcher;
745
+ }
746
+ nativeScopeMatcher = createNativeScopeMatcher();
747
+ return nativeScopeMatcher;
748
+ }
749
+ function createNativeScopeMatcher() {
750
+ const library = requireNativeRuntimeLibrary("scope matching");
751
+ return {
752
+ match: (pattern, path) => {
753
+ const patternBuffer = Buffer.from(`${pattern}\x00`);
754
+ const pathBuffer = Buffer.from(`${path}\x00`);
755
+ return library.symbols.rig_scope_match(Number(ptr2(patternBuffer)), Number(ptr2(pathBuffer))) !== 0;
756
+ }
757
+ };
758
+ }
759
+
760
+ // packages/runtime/src/control-plane/runtime/guard-types.ts
761
+ var POLICY_VERSION = 1;
762
+
763
+ // packages/runtime/src/control-plane/runtime/guard.ts
764
+ var DEFAULT_SCOPE = {
765
+ fail_closed: true,
766
+ harness_paths_exempt: true,
767
+ runtime_paths_exempt: true
768
+ };
769
+ var DEFAULT_SANDBOX = {
770
+ mode: "enforce",
771
+ network: true,
772
+ read_deny: [],
773
+ write_allow_from_runtime: true
774
+ };
775
+ var DEFAULT_ISOLATION = {
776
+ default_mode: "worktree",
777
+ repo_symlink_fallback: false,
778
+ strict_provisioning: true,
779
+ fail_closed_on_provision_error: true
780
+ };
781
+ var DEFAULT_COMPLETION = {
782
+ derive_checks_from_scope: true,
783
+ checks: [],
784
+ typescript_config_probe: ["tsconfig.json"],
785
+ eslint_config_probe: [".eslintrc.js", ".eslintrc.json", "eslint.config.js"]
786
+ };
787
+ var DEFAULT_RUNTIME_IMAGE = {
788
+ deps: {
789
+ monorepo_install: false,
790
+ hp_next_install: false
791
+ },
792
+ plugins_require_binaries: true
793
+ };
794
+ var DEFAULT_RUNTIME_SNAPSHOT = {
795
+ enabled: true
796
+ };
797
+ function defaultPolicy() {
798
+ return {
799
+ version: POLICY_VERSION,
800
+ mode: "enforce",
801
+ scope: { ...DEFAULT_SCOPE },
802
+ rules: [],
803
+ sandbox: { ...DEFAULT_SANDBOX },
804
+ isolation: { ...DEFAULT_ISOLATION },
805
+ completion: { ...DEFAULT_COMPLETION },
806
+ runtime_image: {
807
+ deps: { ...DEFAULT_RUNTIME_IMAGE.deps },
808
+ plugins_require_binaries: DEFAULT_RUNTIME_IMAGE.plugins_require_binaries
809
+ },
810
+ runtime_snapshot: { ...DEFAULT_RUNTIME_SNAPSHOT }
811
+ };
812
+ }
813
+ var policyCache = null;
814
+ var policyCachePath = null;
815
+ var seededPolicyConfig = null;
816
+ var compiledRegexCache = new Map;
817
+ function loadPolicy(projectRoot) {
818
+ if (seededPolicyConfig) {
819
+ return seededPolicyConfig;
820
+ }
821
+ const configPath = resolve3(projectRoot, "rig/policy/policy.json");
822
+ if (!existsSync3(configPath)) {
823
+ return defaultPolicy();
824
+ }
825
+ let mtimeMs;
826
+ try {
827
+ mtimeMs = statSync2(configPath).mtimeMs;
828
+ } catch {
829
+ return defaultPolicy();
830
+ }
831
+ if (policyCache && policyCachePath === configPath && policyCache.mtimeMs === mtimeMs) {
832
+ return policyCache.config;
833
+ }
834
+ let parsed;
835
+ try {
836
+ parsed = JSON.parse(readFileSync(configPath, "utf-8"));
837
+ } catch {
838
+ return defaultPolicy();
839
+ }
840
+ const config = mergeWithDefaults(parsed);
841
+ policyCache = { mtimeMs, config };
842
+ policyCachePath = configPath;
843
+ return config;
844
+ }
845
+ function mergeWithDefaults(parsed) {
846
+ const base = defaultPolicy();
847
+ if (typeof parsed.mode === "string" && isValidMode(parsed.mode)) {
848
+ base.mode = parsed.mode;
849
+ }
850
+ if (parsed.scope && typeof parsed.scope === "object" && !Array.isArray(parsed.scope)) {
851
+ const s = parsed.scope;
852
+ if (typeof s.fail_closed === "boolean")
853
+ base.scope.fail_closed = s.fail_closed;
854
+ if (typeof s.harness_paths_exempt === "boolean")
855
+ base.scope.harness_paths_exempt = s.harness_paths_exempt;
856
+ if (typeof s.runtime_paths_exempt === "boolean")
857
+ base.scope.runtime_paths_exempt = s.runtime_paths_exempt;
858
+ }
859
+ if (Array.isArray(parsed.rules)) {
860
+ base.rules = precompilePolicyRuleRegexes(parsed.rules.filter(isValidRule));
861
+ }
862
+ if (Array.isArray(parsed.deny) && base.rules.length === 0) {
863
+ base.rules = precompilePolicyRuleRegexes(migrateLegacyDeny(parsed.deny));
864
+ }
865
+ if (parsed.sandbox && typeof parsed.sandbox === "object" && !Array.isArray(parsed.sandbox)) {
866
+ const sb = parsed.sandbox;
867
+ if (typeof sb.mode === "string" && isValidMode(sb.mode))
868
+ base.sandbox.mode = sb.mode;
869
+ if (typeof sb.network === "boolean")
870
+ base.sandbox.network = sb.network;
871
+ if (Array.isArray(sb.read_deny))
872
+ base.sandbox.read_deny = sb.read_deny.filter((v) => typeof v === "string");
873
+ if (typeof sb.write_allow_from_runtime === "boolean")
874
+ base.sandbox.write_allow_from_runtime = sb.write_allow_from_runtime;
875
+ }
876
+ if (parsed.isolation && typeof parsed.isolation === "object" && !Array.isArray(parsed.isolation)) {
877
+ const iso = parsed.isolation;
878
+ if (iso.default_mode === "worktree")
879
+ base.isolation.default_mode = iso.default_mode;
880
+ if (typeof iso.repo_symlink_fallback === "boolean")
881
+ base.isolation.repo_symlink_fallback = iso.repo_symlink_fallback;
882
+ if (typeof iso.strict_provisioning === "boolean")
883
+ base.isolation.strict_provisioning = iso.strict_provisioning;
884
+ if (typeof iso.fail_closed_on_provision_error === "boolean")
885
+ base.isolation.fail_closed_on_provision_error = iso.fail_closed_on_provision_error;
886
+ }
887
+ if (parsed.completion && typeof parsed.completion === "object" && !Array.isArray(parsed.completion)) {
888
+ const comp = parsed.completion;
889
+ if (typeof comp.derive_checks_from_scope === "boolean")
890
+ base.completion.derive_checks_from_scope = comp.derive_checks_from_scope;
891
+ if (Array.isArray(comp.checks))
892
+ base.completion.checks = comp.checks.filter((v) => typeof v === "string");
893
+ if (Array.isArray(comp.typescript_config_probe))
894
+ base.completion.typescript_config_probe = comp.typescript_config_probe.filter((v) => typeof v === "string");
895
+ if (Array.isArray(comp.eslint_config_probe))
896
+ base.completion.eslint_config_probe = comp.eslint_config_probe.filter((v) => typeof v === "string");
897
+ }
898
+ if (parsed.runtime_image && typeof parsed.runtime_image === "object" && !Array.isArray(parsed.runtime_image)) {
899
+ const runtimeImage = parsed.runtime_image;
900
+ if (runtimeImage.deps && typeof runtimeImage.deps === "object" && !Array.isArray(runtimeImage.deps)) {
901
+ const deps = runtimeImage.deps;
902
+ if (typeof deps.monorepo_install === "boolean") {
903
+ base.runtime_image.deps.monorepo_install = deps.monorepo_install;
904
+ }
905
+ if (typeof deps.hp_next_install === "boolean") {
906
+ base.runtime_image.deps.hp_next_install = deps.hp_next_install;
907
+ }
908
+ }
909
+ if (typeof runtimeImage.plugins_require_binaries === "boolean") {
910
+ base.runtime_image.plugins_require_binaries = runtimeImage.plugins_require_binaries;
911
+ }
912
+ }
913
+ if (parsed.runtime_snapshot && typeof parsed.runtime_snapshot === "object" && !Array.isArray(parsed.runtime_snapshot)) {
914
+ const runtimeSnapshot = parsed.runtime_snapshot;
915
+ if (typeof runtimeSnapshot.enabled === "boolean") {
916
+ base.runtime_snapshot.enabled = runtimeSnapshot.enabled;
917
+ }
918
+ }
919
+ return base;
920
+ }
921
+ function isValidMode(value) {
922
+ return value === "off" || value === "observe" || value === "enforce";
923
+ }
924
+ function isValidRule(value) {
925
+ if (!value || typeof value !== "object" || Array.isArray(value))
926
+ return false;
927
+ const r = value;
928
+ return typeof r.id === "string" && typeof r.category === "string" && r.match != null && typeof r.match === "object";
929
+ }
930
+ function migrateLegacyDeny(deny) {
931
+ const rules = [];
932
+ for (const entry of deny) {
933
+ if (typeof entry.id !== "string")
934
+ continue;
935
+ const match = {};
936
+ if (typeof entry.pattern === "string")
937
+ match.pattern = entry.pattern;
938
+ if (typeof entry.regex === "string")
939
+ match.regex = entry.regex;
940
+ if (!match.pattern && !match.regex)
941
+ continue;
942
+ rules.push({
943
+ id: entry.id,
944
+ category: "command",
945
+ match,
946
+ action: "block",
947
+ ...typeof entry.description === "string" ? { description: entry.description } : {}
948
+ });
949
+ }
950
+ return rules;
951
+ }
952
+ function precompilePolicyRuleRegexes(rules) {
953
+ return rules.map((rule) => {
954
+ const compiledRegex = rule.match.regex ? compileSafeRegex(rule.match.regex, `rules.${rule.id}.match.regex`, true) : undefined;
955
+ const compiledUnlessRegex = rule.unless?.regex ? compileSafeRegex(rule.unless.regex, `rules.${rule.id}.unless.regex`, true) : undefined;
956
+ return {
957
+ ...rule,
958
+ ...compiledRegex ? { compiledRegex } : {},
959
+ ...compiledUnlessRegex ? { compiledUnlessRegex } : {}
960
+ };
961
+ });
962
+ }
963
+ function getRegexUnsafeReason(pattern) {
964
+ if (pattern.length > 512) {
965
+ return "pattern exceeds max safe length (512 chars)";
966
+ }
967
+ if (/\\[1-9]/.test(pattern)) {
968
+ return "pattern uses backreferences";
969
+ }
970
+ if (/\((?:[^()\\]|\\.)*[+*](?:[^()\\]|\\.)*\)\s*[*+{]/.test(pattern)) {
971
+ return "pattern contains nested quantifiers";
972
+ }
973
+ if (/\((?:[^()\\]|\\.)*\.\\?[+*](?:[^()\\]|\\.)*\)\s*[*+{]/.test(pattern)) {
974
+ return "pattern contains nested broad quantifiers";
975
+ }
976
+ return null;
977
+ }
978
+ function compileSafeRegex(pattern, sourceLabel, logOnFailure) {
979
+ const cached = compiledRegexCache.get(pattern);
980
+ if (cached !== undefined) {
981
+ return cached ?? undefined;
982
+ }
983
+ const unsafeReason = getRegexUnsafeReason(pattern);
984
+ if (unsafeReason) {
985
+ if (logOnFailure) {
986
+ console.warn(`[policy] Skipping unsafe regex in ${sourceLabel}: ${unsafeReason}`);
987
+ }
988
+ compiledRegexCache.set(pattern, null);
989
+ return;
990
+ }
991
+ try {
992
+ const compiled = new RegExp(pattern);
993
+ compiledRegexCache.set(pattern, compiled);
994
+ return compiled;
995
+ } catch (error) {
996
+ if (logOnFailure) {
997
+ const message = error instanceof Error ? error.message : String(error);
998
+ console.warn(`[policy] Skipping invalid regex in ${sourceLabel}: ${message}`);
999
+ }
1000
+ compiledRegexCache.set(pattern, null);
1001
+ return;
1002
+ }
1003
+ }
1004
+ function matchRule(rule, input) {
1005
+ const { match } = rule;
1006
+ if (match.pattern && input.includes(match.pattern)) {
1007
+ return true;
1008
+ }
1009
+ if (match.regex) {
1010
+ const compiled = rule.compiledRegex || compileSafeRegex(match.regex, `rules.${rule.id}.match.regex`, false);
1011
+ if (!compiled) {
1012
+ return false;
1013
+ }
1014
+ try {
1015
+ return compiled.test(input);
1016
+ } catch {
1017
+ return false;
1018
+ }
1019
+ }
1020
+ return false;
1021
+ }
1022
+ function matchRuleUnless(rule, command, taskId) {
1023
+ if (!rule.unless)
1024
+ return false;
1025
+ if (rule.unless.regex) {
1026
+ const compiled = rule.compiledUnlessRegex || compileSafeRegex(rule.unless.regex, `rules.${rule.id}.unless.regex`, false);
1027
+ if (!compiled) {
1028
+ return false;
1029
+ }
1030
+ try {
1031
+ if (compiled.test(command))
1032
+ return true;
1033
+ } catch {}
1034
+ }
1035
+ if (rule.unless.task_in && taskId) {
1036
+ if (rule.unless.task_in.includes(taskId))
1037
+ return true;
1038
+ }
1039
+ return false;
1040
+ }
1041
+ function resolveAction(mode, matched) {
1042
+ if (matched.length === 0)
1043
+ return "allow";
1044
+ if (mode === "off")
1045
+ return "allow";
1046
+ if (mode === "observe")
1047
+ return "warn";
1048
+ return "block";
1049
+ }
1050
+ function resolveAbsolutePath(projectRoot, rawPath) {
1051
+ if (rawPath.startsWith("/"))
1052
+ return resolve3(rawPath);
1053
+ return resolve3(projectRoot, rawPath);
1054
+ }
1055
+ function isHarnessPath(projectRoot, rawPath) {
1056
+ const absPath = resolveAbsolutePath(projectRoot, rawPath);
1057
+ const managedRoots = [
1058
+ resolve3(projectRoot, "rig"),
1059
+ resolve3(projectRoot, ".rig"),
1060
+ resolve3(projectRoot, "artifacts")
1061
+ ];
1062
+ return managedRoots.some((root) => absPath === root || absPath.startsWith(root + "/"));
1063
+ }
1064
+ function isRuntimePath(projectRoot, rawPath, taskWorkspace) {
1065
+ const absPath = resolveAbsolutePath(projectRoot, rawPath);
1066
+ if (taskWorkspace) {
1067
+ const workspaceRigRoot = resolve3(taskWorkspace, ".rig");
1068
+ const workspaceArtifactsRoot = resolve3(taskWorkspace, "artifacts");
1069
+ if (absPath === workspaceRigRoot || absPath.startsWith(workspaceRigRoot + "/") || absPath === workspaceArtifactsRoot || absPath.startsWith(workspaceArtifactsRoot + "/")) {
1070
+ return true;
1071
+ }
1072
+ }
1073
+ const runtimeRoot = resolve3(projectRoot, ".rig/runtime/agents");
1074
+ return absPath === runtimeRoot || absPath.startsWith(runtimeRoot + "/");
1075
+ }
1076
+ function isTestFile(path) {
1077
+ return /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(path) || /\/(__tests__|tests|test)\//.test(path);
1078
+ }
1079
+ function evaluate(context) {
1080
+ const policy = loadPolicy(context.projectRoot);
1081
+ switch (context.evaluation.type) {
1082
+ case "tool-call":
1083
+ return evaluateToolCall(policy, context);
1084
+ case "command":
1085
+ return evaluateCommand(policy, context);
1086
+ case "content-write":
1087
+ return evaluateContent(policy, context);
1088
+ case "file-access":
1089
+ return evaluateScope(policy, context, context.evaluation.file_path, context.evaluation.access);
1090
+ }
1091
+ }
1092
+ function evaluateScope(policy, context, filePath, access) {
1093
+ const allowed = () => ({
1094
+ allowed: true,
1095
+ matchedRules: [],
1096
+ action: "allow",
1097
+ failClosed: false
1098
+ });
1099
+ if (policy.scope.harness_paths_exempt && isHarnessPath(context.projectRoot, filePath)) {
1100
+ return allowed();
1101
+ }
1102
+ if (policy.scope.runtime_paths_exempt && isRuntimePath(context.projectRoot, filePath, context.taskWorkspace)) {
1103
+ return allowed();
1104
+ }
1105
+ if (!context.taskId) {
1106
+ if (access === "write" && policy.scope.fail_closed) {
1107
+ return {
1108
+ allowed: false,
1109
+ matchedRules: [],
1110
+ action: resolveAction(policy.mode, [{ id: "scope:no-task", category: "command", reason: "No active task; fail-closed for write operations" }]),
1111
+ failClosed: true
1112
+ };
1113
+ }
1114
+ return allowed();
1115
+ }
1116
+ const scopes = context.taskScopes || [];
1117
+ if (scopes.length === 0) {
1118
+ return allowed();
1119
+ }
1120
+ if (context.taskWorkspace && context.taskWorkspace !== context.projectRoot && filePath.startsWith("/")) {
1121
+ const absPath = resolve3(filePath);
1122
+ if (!absPath.startsWith(context.taskWorkspace + "/") && !isHarnessPath(context.projectRoot, filePath)) {
1123
+ const reason2 = `Absolute path '${filePath}' is outside task runtime boundary. Allowed root: ${context.taskWorkspace}`;
1124
+ const matched2 = [{ id: "scope:workspace-boundary", category: "command", reason: reason2 }];
1125
+ return {
1126
+ allowed: policy.mode !== "enforce",
1127
+ matchedRules: matched2,
1128
+ action: resolveAction(policy.mode, matched2),
1129
+ failClosed: false
1130
+ };
1131
+ }
1132
+ }
1133
+ const monorepoRoot = context.monorepoRoot || process.env.MONOREPO_ROOT?.trim() || context.taskWorkspace || context.projectRoot;
1134
+ let normalizedPath = filePath;
1135
+ if (context.taskWorkspace && context.taskWorkspace !== context.projectRoot && filePath.startsWith(context.taskWorkspace + "/")) {
1136
+ normalizedPath = filePath.slice(context.taskWorkspace.length + 1);
1137
+ }
1138
+ normalizedPath = normalizePathToScope(context.projectRoot, monorepoRoot, normalizedPath);
1139
+ if (scopeMatches(filePath, scopes) || scopeMatches(normalizedPath, scopes)) {
1140
+ return allowed();
1141
+ }
1142
+ const reason = `File '${filePath}' (normalized: '${normalizedPath}') is outside scope of task ${context.taskId}`;
1143
+ const matched = [{ id: "scope:out-of-scope", category: "command", reason }];
1144
+ return {
1145
+ allowed: policy.mode !== "enforce",
1146
+ matchedRules: matched,
1147
+ action: resolveAction(policy.mode, matched),
1148
+ failClosed: false
1149
+ };
1150
+ }
1151
+ function evaluateCommand(policy, context) {
1152
+ const evaluation = context.evaluation;
1153
+ if (evaluation.type !== "command") {
1154
+ return { allowed: true, matchedRules: [], action: "allow", failClosed: false };
1155
+ }
1156
+ const command = evaluation.command;
1157
+ const matchedRules = [];
1158
+ for (const rule of policy.rules) {
1159
+ if (rule.category !== "command")
1160
+ continue;
1161
+ if (!matchRule(rule, command))
1162
+ continue;
1163
+ if (matchRuleUnless(rule, command, context.taskId))
1164
+ continue;
1165
+ matchedRules.push({
1166
+ id: rule.id,
1167
+ category: rule.category,
1168
+ description: rule.description,
1169
+ reason: rule.description || `Matched rule ${rule.id}`
1170
+ });
1171
+ }
1172
+ const writeTarget = extractWriteTarget(command);
1173
+ if (writeTarget && !/^\/dev\//.test(writeTarget) && !/^\/proc\//.test(writeTarget)) {
1174
+ const scopeResult = evaluateScope(policy, context, writeTarget, "write");
1175
+ if (!scopeResult.allowed || scopeResult.matchedRules.length > 0) {
1176
+ matchedRules.push(...scopeResult.matchedRules);
1177
+ }
1178
+ }
1179
+ const action = resolveAction(policy.mode, matchedRules);
1180
+ return {
1181
+ allowed: action !== "block",
1182
+ matchedRules,
1183
+ action,
1184
+ failClosed: false
1185
+ };
1186
+ }
1187
+ function extractWriteTarget(command) {
1188
+ const redirect = command.match(/>>?\s+([^\s;|&]+)/);
1189
+ if (redirect?.[1])
1190
+ return redirect[1];
1191
+ const tee = command.match(/tee\s+(-a\s+)?([^\s;|&]+)/);
1192
+ if (tee?.[2])
1193
+ return tee[2];
1194
+ return "";
1195
+ }
1196
+ function evaluateContent(policy, context) {
1197
+ const evaluation = context.evaluation;
1198
+ if (evaluation.type !== "content-write") {
1199
+ return { allowed: true, matchedRules: [], action: "allow", failClosed: false };
1200
+ }
1201
+ const { content, file_path } = evaluation;
1202
+ const matchedRules = [];
1203
+ const scopeResult = evaluateScope(policy, context, file_path, "write");
1204
+ if (scopeResult.matchedRules.length > 0) {
1205
+ matchedRules.push(...scopeResult.matchedRules);
1206
+ }
1207
+ for (const rule of policy.rules) {
1208
+ if (rule.category !== "content" && rule.category !== "import" && rule.category !== "test-integrity")
1209
+ continue;
1210
+ if (rule.applies_to === "test-files" && !isTestFile(file_path))
1211
+ continue;
1212
+ if (!matchRule(rule, content))
1213
+ continue;
1214
+ if (matchRuleUnless(rule, content, context.taskId))
1215
+ continue;
1216
+ matchedRules.push({
1217
+ id: rule.id,
1218
+ category: rule.category,
1219
+ description: rule.description,
1220
+ reason: rule.description || `Matched rule ${rule.id}`
1221
+ });
1222
+ }
1223
+ const action = resolveAction(policy.mode, matchedRules);
1224
+ return {
1225
+ allowed: action !== "block",
1226
+ matchedRules,
1227
+ action,
1228
+ failClosed: false
1229
+ };
1230
+ }
1231
+ function evaluateToolCall(policy, context) {
1232
+ const evaluation = context.evaluation;
1233
+ if (evaluation.type !== "tool-call") {
1234
+ return { allowed: true, matchedRules: [], action: "allow", failClosed: false };
1235
+ }
1236
+ const { tool_name, tool_input } = evaluation;
1237
+ const allMatched = [];
1238
+ const filePaths = extractFilePathsFromToolInput(tool_name, tool_input);
1239
+ for (const fp of filePaths) {
1240
+ const access = isWriteTool(tool_name) ? "write" : "read";
1241
+ const scopeResult = evaluateScope(policy, context, fp, access);
1242
+ if (scopeResult.matchedRules.length > 0) {
1243
+ allMatched.push(...scopeResult.matchedRules);
1244
+ }
1245
+ }
1246
+ const content = extractContentFromToolInput(tool_input);
1247
+ if (content) {
1248
+ const filePath = filePaths[0] || "";
1249
+ const contentContext = {
1250
+ ...context,
1251
+ evaluation: { type: "content-write", file_path: filePath, content }
1252
+ };
1253
+ const contentPolicy = loadPolicy(context.projectRoot);
1254
+ for (const rule of contentPolicy.rules) {
1255
+ if (rule.category !== "content" && rule.category !== "import" && rule.category !== "test-integrity")
1256
+ continue;
1257
+ if (rule.applies_to === "test-files" && !isTestFile(filePath))
1258
+ continue;
1259
+ if (!matchRule(rule, content))
1260
+ continue;
1261
+ if (matchRuleUnless(rule, content, context.taskId))
1262
+ continue;
1263
+ allMatched.push({
1264
+ id: rule.id,
1265
+ category: rule.category,
1266
+ description: rule.description,
1267
+ reason: rule.description || `Matched rule ${rule.id}`
1268
+ });
1269
+ }
1270
+ }
1271
+ if (tool_name === "Bash") {
1272
+ const command = String(tool_input.command || tool_input.cmd || "");
1273
+ if (command) {
1274
+ const cmdContext = {
1275
+ ...context,
1276
+ evaluation: { type: "command", command }
1277
+ };
1278
+ const cmdResult = evaluateCommand(policy, cmdContext);
1279
+ if (cmdResult.matchedRules.length > 0) {
1280
+ allMatched.push(...cmdResult.matchedRules);
1281
+ }
1282
+ }
1283
+ }
1284
+ const seen = new Set;
1285
+ const deduplicated = [];
1286
+ for (const rule of allMatched) {
1287
+ if (!seen.has(rule.id)) {
1288
+ seen.add(rule.id);
1289
+ deduplicated.push(rule);
1290
+ }
1291
+ }
1292
+ const action = resolveAction(policy.mode, deduplicated);
1293
+ return {
1294
+ allowed: action !== "block",
1295
+ matchedRules: deduplicated,
1296
+ action,
1297
+ failClosed: false
1298
+ };
1299
+ }
1300
+ function isWriteTool(toolName) {
1301
+ return toolName === "Write" || toolName === "Edit" || toolName === "MultiEdit";
1302
+ }
1303
+ function extractFilePathsFromToolInput(toolName, input) {
1304
+ const paths = [];
1305
+ const add = (value) => {
1306
+ if (typeof value === "string" && value.trim()) {
1307
+ paths.push(value.trim());
1308
+ }
1309
+ };
1310
+ if (toolName === "Read" || toolName === "Write" || toolName === "Edit" || toolName === "MultiEdit") {
1311
+ add(input.file_path);
1312
+ add(input.path);
1313
+ } else if (toolName === "Glob") {
1314
+ add(input.path);
1315
+ } else if (toolName === "Grep") {
1316
+ add(input.path);
1317
+ } else {
1318
+ add(input.file_path);
1319
+ add(input.path);
1320
+ }
1321
+ return paths;
1322
+ }
1323
+ function extractContentFromToolInput(input) {
1324
+ if (typeof input.content === "string")
1325
+ return input.content;
1326
+ if (typeof input.new_string === "string")
1327
+ return input.new_string;
1328
+ return "";
1329
+ }
1330
+ function loadSandboxConfig(projectRoot) {
1331
+ return loadPolicy(projectRoot).sandbox;
1332
+ }
1333
+ var guardHotPathPrimed = false;
1334
+ function primeGuardHotPaths() {
1335
+ if (guardHotPathPrimed) {
1336
+ return;
1337
+ }
1338
+ guardHotPathPrimed = true;
1339
+ try {
1340
+ optimizeNextInvocation(matchRule);
1341
+ optimizeNextInvocation(evaluate);
1342
+ } catch {}
1343
+ }
1344
+ primeGuardHotPaths();
1345
+
1346
+ // packages/runtime/src/control-plane/runtime/runtime-paths.ts
1347
+ import { existsSync as existsSync5, readdirSync as readdirSync2, realpathSync as realpathSync2 } from "fs";
1348
+ import { resolve as resolve5 } from "path";
1349
+
1350
+ // packages/runtime/src/control-plane/runtime/sandbox-utils.ts
1351
+ init_utils();
1352
+
1353
+ // packages/runtime/src/control-plane/runtime/runtime-paths.ts
1354
+ function resolveBunBinaryPath() {
1355
+ const explicit = normalizeExecutablePath(process.env.RIG_BUN_PATH?.trim());
1356
+ if (explicit) {
1357
+ return explicit;
1358
+ }
1359
+ const pathBun = normalizeExecutablePath(Bun.which("bun")?.trim());
1360
+ if (pathBun && !looksLikeRuntimeGateway(pathBun)) {
1361
+ return pathBun;
1362
+ }
1363
+ const home = process.env.HOME?.trim();
1364
+ const fallbackCandidates = [
1365
+ home ? resolve5(home, ".bun/bin/bun") : "",
1366
+ "/opt/homebrew/bin/bun",
1367
+ "/usr/local/bin/bun",
1368
+ "/usr/bin/bun"
1369
+ ];
1370
+ for (const candidate of fallbackCandidates) {
1371
+ const normalized = normalizeExecutablePath(candidate);
1372
+ if (normalized) {
1373
+ return normalized;
1374
+ }
1375
+ }
1376
+ const execPath = normalizeExecutablePath(process.execPath?.trim());
1377
+ if (execPath && !looksLikeRuntimeGateway(execPath)) {
1378
+ return execPath;
1379
+ }
1380
+ throw new Error("bun not found in PATH");
1381
+ }
1382
+ function resolveClaudeBinaryPath() {
1383
+ const explicit = normalizeExecutablePath(process.env.RIG_CLAUDE_PATH?.trim());
1384
+ if (explicit) {
1385
+ return explicit;
1386
+ }
1387
+ const pathClaude = normalizeExecutablePath(Bun.which("claude")?.trim());
1388
+ if (pathClaude && !looksLikeRuntimeGateway(pathClaude)) {
1389
+ return pathClaude;
1390
+ }
1391
+ const home = process.env.HOME?.trim();
1392
+ const fallbackCandidates = [
1393
+ home ? resolve5(home, ".local/bin/claude") : "",
1394
+ home ? resolve5(home, ".local/share/claude/local/claude") : "",
1395
+ "/opt/homebrew/bin/claude",
1396
+ "/usr/local/bin/claude",
1397
+ "/usr/bin/claude"
1398
+ ];
1399
+ for (const candidate of fallbackCandidates) {
1400
+ const normalized = normalizeExecutablePath(candidate);
1401
+ if (normalized) {
1402
+ return normalized;
1403
+ }
1404
+ }
1405
+ throw new Error("claude not found in PATH");
1406
+ }
1407
+ function resolveBunInstallDir(bunBinaryPath = resolveBunBinaryPath()) {
1408
+ return resolve5(bunBinaryPath, "../..");
1409
+ }
1410
+ function resolveClaudeInstallDir() {
1411
+ const realPath = resolveClaudeBinaryPath();
1412
+ return resolve5(realPath, "..");
1413
+ }
1414
+ function resolveNodeInstallDir() {
1415
+ const preferredNode = resolvePreferredNodeBinary();
1416
+ if (!preferredNode)
1417
+ return null;
1418
+ const explicitNode = process.env.RIG_NODE_BIN?.trim();
1419
+ if (explicitNode && resolve5(explicitNode) === resolve5(preferredNode)) {
1420
+ return preferredNode.endsWith("/bin/node") ? resolve5(preferredNode, "../..") : resolve5(preferredNode, "..");
1421
+ }
1422
+ try {
1423
+ const realPath = realpathSync2(preferredNode);
1424
+ if (realPath.endsWith("/bin/node")) {
1425
+ return resolve5(realPath, "../..");
1426
+ }
1427
+ return resolve5(realPath, "..");
1428
+ } catch {
1429
+ return resolve5(preferredNode, "..");
1430
+ }
1431
+ }
1432
+ function resolveRuntimeDependencyRoots(runtimeDirs) {
1433
+ const roots = [];
1434
+ if (process.platform === "darwin") {
1435
+ for (const macPath of ["/opt/homebrew", "/opt/homebrew/opt"]) {
1436
+ if (existsSync5(macPath)) {
1437
+ roots.push(macPath);
1438
+ }
1439
+ }
1440
+ }
1441
+ for (const dir of runtimeDirs) {
1442
+ if (dir.startsWith("/opt/homebrew/Cellar/")) {
1443
+ roots.push("/opt/homebrew/opt");
1444
+ } else if (dir.startsWith("/usr/local/Cellar/")) {
1445
+ roots.push("/usr/local/opt");
1446
+ }
1447
+ }
1448
+ return uniq(roots);
1449
+ }
1450
+ function resolvePreferredNodeBinary() {
1451
+ const candidates = [];
1452
+ const envNode = process.env.RIG_NODE_BIN?.trim();
1453
+ if (envNode) {
1454
+ const explicit = resolve5(envNode);
1455
+ if (existsSync5(explicit)) {
1456
+ return explicit;
1457
+ }
1458
+ }
1459
+ const nvmBin = process.env.NVM_BIN?.trim();
1460
+ if (nvmBin) {
1461
+ candidates.push(resolve5(nvmBin, "node"));
1462
+ }
1463
+ const home = process.env.HOME?.trim();
1464
+ if (home) {
1465
+ const nvmVersionsDir = resolve5(home, ".nvm/versions/node");
1466
+ if (existsSync5(nvmVersionsDir)) {
1467
+ try {
1468
+ const versionDirs = readdirSync2(nvmVersionsDir).map((entry) => entry.trim()).filter((entry) => /^v\d+\.\d+\.\d+$/.test(entry)).sort((a, b) => Bun.semver.order(b.replace(/^v/, ""), a.replace(/^v/, "")));
1469
+ for (const versionDir of versionDirs) {
1470
+ candidates.push(resolve5(nvmVersionsDir, versionDir, "bin/node"));
1471
+ }
1472
+ } catch {}
1473
+ }
1474
+ }
1475
+ const whichNode = Bun.which("node");
1476
+ if (whichNode) {
1477
+ candidates.push(whichNode);
1478
+ }
1479
+ const deduped = uniq(candidates.map((candidate) => resolve5(candidate)));
1480
+ const existing = deduped.filter((candidate) => existsSync5(candidate));
1481
+ if (existing.length === 0) {
1482
+ return null;
1483
+ }
1484
+ const stable = existing.find((candidate) => {
1485
+ const major = inferNodeMajor(candidate);
1486
+ return typeof major === "number" && major >= 18 && major <= 24;
1487
+ });
1488
+ if (stable) {
1489
+ return stable;
1490
+ }
1491
+ return existing[0] ?? null;
1492
+ }
1493
+ function inferNodeMajor(nodeBinaryPath) {
1494
+ const normalized = resolve5(nodeBinaryPath).replace(/\\/g, "/");
1495
+ const match = normalized.match(/(?:^|\/)(?:node-)?v?(\d+)\.\d+\.\d+(?:\/|$)/);
1496
+ if (!match) {
1497
+ return null;
1498
+ }
1499
+ const major = Number.parseInt(match[1], 10);
1500
+ return Number.isFinite(major) ? major : null;
1501
+ }
1502
+ function normalizeExecutablePath(candidate) {
1503
+ if (!candidate) {
1504
+ return "";
1505
+ }
1506
+ const normalized = resolve5(candidate);
1507
+ if (!existsSync5(normalized)) {
1508
+ return "";
1509
+ }
1510
+ try {
1511
+ return realpathSync2(normalized);
1512
+ } catch {
1513
+ return normalized;
1514
+ }
1515
+ }
1516
+ function looksLikeRuntimeGateway(candidate) {
1517
+ const normalized = resolve5(candidate).replace(/\\/g, "/");
1518
+ return normalized.includes("/.rig/bin/") || normalized.endsWith("/rig-shell") || normalized.endsWith("/rig-agent");
1519
+ }
1520
+
1521
+ // packages/runtime/src/control-plane/runtime/sandbox/backend.ts
1522
+ init_utils();
1523
+
1524
+ // packages/runtime/src/control-plane/runtime/sandbox/backend-none.ts
1525
+ class NoSandboxBackend {
1526
+ kind = "none";
1527
+ reason;
1528
+ constructor(reason) {
1529
+ this.reason = reason;
1530
+ }
1531
+ wrap(options) {
1532
+ return {
1533
+ command: options.command,
1534
+ enabled: false,
1535
+ backend: "none",
1536
+ reason: this.reason,
1537
+ metadata: undefined
1538
+ };
1539
+ }
1540
+ }
1541
+
1542
+ // packages/runtime/src/control-plane/runtime/sandbox/backend.ts
1543
+ class SandboxError extends Error {
1544
+ code;
1545
+ constructor(code, message) {
1546
+ super(message);
1547
+ this.code = code;
1548
+ this.name = "SandboxError";
1549
+ }
1550
+ }
1551
+ function resolveRuntimeSandboxModeWithPolicy(sandboxConfig, envOverride) {
1552
+ if (envOverride) {
1553
+ const normalized = envOverride.trim().toLowerCase();
1554
+ if (normalized === "off" || normalized === "auto" || normalized === "enforce") {
1555
+ if (normalized !== sandboxConfig.mode) {
1556
+ console.warn(`[sandbox] RIG_RUNTIME_SANDBOX=${normalized} overrides policy sandbox.mode=${sandboxConfig.mode}`);
1557
+ }
1558
+ return normalized;
1559
+ }
1560
+ }
1561
+ const policyMode = sandboxConfig.mode;
1562
+ if (policyMode === "off")
1563
+ return "off";
1564
+ if (policyMode === "observe")
1565
+ return "auto";
1566
+ return "enforce";
1567
+ }
1568
+ var bwrapProbeCache = null;
1569
+ async function probeBubblewrap(binary) {
1570
+ if (bwrapProbeCache !== null) {
1571
+ return bwrapProbeCache;
1572
+ }
1573
+ const probe = await Bun.$`${binary} ${["--ro-bind", "/", "/", "--proc", "/proc", "--dev", "/dev", "--", "true"]}`.quiet().nothrow();
1574
+ bwrapProbeCache = probe.exitCode === 0;
1575
+ return bwrapProbeCache;
1576
+ }
1577
+ async function resolveBackend(projectRoot, options) {
1578
+ const config = loadSandboxConfig(projectRoot);
1579
+ const mode = resolveRuntimeSandboxModeWithPolicy(config, options?.envOverride);
1580
+ const probed = [];
1581
+ if (mode === "off") {
1582
+ return {
1583
+ backend: new NoSandboxBackend,
1584
+ selectedKind: "none",
1585
+ probed,
1586
+ reason: "disabled-by-config"
1587
+ };
1588
+ }
1589
+ const explicitBackend = options?.backendOverride ?? process.env.RIG_SANDBOX_BACKEND?.trim().toLowerCase();
1590
+ const requestedBackend = resolveExplicitBackend(explicitBackend);
1591
+ if (requestedBackend) {
1592
+ if (requestedBackend === "docker") {
1593
+ throw new SandboxError("backend-unavailable", `Backend "docker" is not yet implemented.`);
1594
+ }
1595
+ if (requestedBackend === "none") {
1596
+ return {
1597
+ backend: new NoSandboxBackend("explicit-none"),
1598
+ selectedKind: "none",
1599
+ probed,
1600
+ reason: "explicit-none"
1601
+ };
1602
+ }
1603
+ }
1604
+ const bunDir = resolveBunInstallDir();
1605
+ const claudeDir = (() => {
1606
+ try {
1607
+ return resolveClaudeInstallDir();
1608
+ } catch {
1609
+ return null;
1610
+ }
1611
+ })();
1612
+ const nodeDir = resolveNodeInstallDir();
1613
+ const depRoots = resolveRuntimeDependencyRoots([bunDir, claudeDir, nodeDir].filter(Boolean));
1614
+ const resolvedPaths = {
1615
+ bunDir,
1616
+ claudeDir,
1617
+ nodeDir,
1618
+ depRoots
1619
+ };
1620
+ const fsContext = {
1621
+ pathExists: (p) => existsSync6(p),
1622
+ realPath: toRealPath
1623
+ };
1624
+ if (process.platform === "darwin" && (!requestedBackend || requestedBackend === "macos-seatbelt")) {
1625
+ const seatbelt = Bun.which("sandbox-exec");
1626
+ probed.push("sandbox-exec");
1627
+ if (seatbelt && existsSync6(seatbelt)) {
1628
+ const SeatbeltBackendClass = loadSeatbeltBackend();
1629
+ if (SeatbeltBackendClass) {
1630
+ return {
1631
+ backend: new SeatbeltBackendClass(seatbelt, config, fsContext, resolvedPaths),
1632
+ selectedKind: "macos-seatbelt",
1633
+ probed,
1634
+ reason: "detected-seatbelt"
1635
+ };
1636
+ }
1637
+ return handleUnavailableBackend(mode, probed, "macos-seatbelt", "Seatbelt sandbox backend module failed to load.", "seatbelt-backend-module-unavailable", { explicit: requestedBackend === "macos-seatbelt" });
1638
+ }
1639
+ }
1640
+ if (process.platform === "linux" && (!requestedBackend || requestedBackend === "linux-bwrap")) {
1641
+ const bwrap = Bun.which("bwrap");
1642
+ probed.push("bwrap");
1643
+ if (bwrap && await probeBubblewrap(bwrap)) {
1644
+ const BwrapBackendClass = loadBwrapBackend();
1645
+ if (BwrapBackendClass) {
1646
+ return {
1647
+ backend: new BwrapBackendClass(bwrap, config, fsContext, resolvedPaths),
1648
+ selectedKind: "linux-bwrap",
1649
+ probed,
1650
+ reason: "detected-bwrap"
1651
+ };
1652
+ }
1653
+ return handleUnavailableBackend(mode, probed, "linux-bwrap", "Bubblewrap sandbox backend module failed to load.", "bwrap-backend-module-unavailable", { explicit: requestedBackend === "linux-bwrap" });
1654
+ }
1655
+ }
1656
+ if (requestedBackend) {
1657
+ return handleUnavailableBackend(mode, probed, requestedBackend, `Explicit sandbox backend "${requestedBackend}" is unavailable on ${process.platform}.`, "explicit-backend-unavailable", { explicit: true });
1658
+ }
1659
+ if (mode === "enforce") {
1660
+ throw new SandboxError("backend-unavailable", `Runtime sandbox required (mode=enforce) but no backend available. Probed: ${probed.join(", ")}`);
1661
+ }
1662
+ return {
1663
+ backend: new NoSandboxBackend("sandbox-backend-unavailable"),
1664
+ selectedKind: "none",
1665
+ probed,
1666
+ reason: "sandbox-backend-unavailable"
1667
+ };
1668
+ }
1669
+ function resolveExplicitBackend(explicitBackend) {
1670
+ if (!explicitBackend) {
1671
+ return null;
1672
+ }
1673
+ switch (explicitBackend) {
1674
+ case "none":
1675
+ case "macos-seatbelt":
1676
+ case "linux-bwrap":
1677
+ case "docker":
1678
+ return explicitBackend;
1679
+ default:
1680
+ throw new SandboxError("backend-unavailable", `Unknown sandbox backend "${explicitBackend}".`);
1681
+ }
1682
+ }
1683
+ function loadSeatbeltBackend() {
1684
+ try {
1685
+ const mod = (init_backend_seatbelt(), __toCommonJS(exports_backend_seatbelt));
1686
+ return mod.SeatbeltBackend ?? null;
1687
+ } catch {
1688
+ return null;
1689
+ }
1690
+ }
1691
+ function loadBwrapBackend() {
1692
+ try {
1693
+ const mod = (init_backend_bwrap(), __toCommonJS(exports_backend_bwrap));
1694
+ return mod.BwrapBackend ?? null;
1695
+ } catch {
1696
+ return null;
1697
+ }
1698
+ }
1699
+ function handleUnavailableBackend(mode, probed, detectedKind, message, reason, options) {
1700
+ if (mode === "enforce" || options?.explicit) {
1701
+ throw new SandboxError("backend-unavailable", `${message} Probed: ${probed.join(", ")}`);
1702
+ }
1703
+ return {
1704
+ backend: new NoSandboxBackend(reason),
1705
+ selectedKind: "none",
1706
+ probed,
1707
+ reason: `${reason}:${detectedKind}`
1708
+ };
1709
+ }
1710
+
1711
+ // packages/runtime/src/control-plane/runtime/sandbox/orchestrator.ts
1712
+ function shouldSandboxRuntime(_runtime) {
1713
+ return true;
1714
+ }
1715
+ async function wrapWithRuntimeSandbox(options) {
1716
+ const envOverride = process.env.RIG_RUNTIME_SANDBOX;
1717
+ const resolution = await resolveBackend(options.projectRoot, { envOverride });
1718
+ if (resolution.backend.kind === "none") {
1719
+ const plan = resolution.backend.wrap({
1720
+ projectRoot: options.projectRoot,
1721
+ runtime: options.runtime,
1722
+ command: options.command
1723
+ });
1724
+ return {
1725
+ ...plan,
1726
+ reason: plan.reason ?? resolution.reason
1727
+ };
1728
+ }
1729
+ if (!shouldSandboxRuntime(options.runtime)) {
1730
+ return {
1731
+ command: options.command,
1732
+ enabled: false,
1733
+ backend: "none",
1734
+ reason: "runtime-mode-not-sandboxed"
1735
+ };
1736
+ }
1737
+ return resolution.backend.wrap({
1738
+ projectRoot: options.projectRoot,
1739
+ runtime: options.runtime,
1740
+ command: options.command
1741
+ });
1742
+ }
1743
+ export {
1744
+ wrapWithRuntimeSandbox
1745
+ };