@h-rig/cli-surface-plugin 0.0.6-alpha.157 → 0.0.6-alpha.158

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/dist/src/app/drone-ui.d.ts +0 -11
  2. package/dist/src/app/drone-ui.js +0 -114
  3. package/dist/src/commands/_async-ui.d.ts +1 -1
  4. package/dist/src/commands/_cli-format.d.ts +0 -29
  5. package/dist/src/commands/_cli-format.js +59 -113
  6. package/dist/src/commands/_connection-state.d.ts +6 -33
  7. package/dist/src/commands/_connection-state.js +654 -138
  8. package/dist/src/commands/_doctor-checks.d.ts +2 -5
  9. package/dist/src/commands/_doctor-checks.js +10 -9
  10. package/dist/src/commands/_help-catalog.d.ts +2 -1
  11. package/dist/src/commands/_help-catalog.js +654 -7
  12. package/dist/src/commands/_inprocess-services.d.ts +5 -5
  13. package/dist/src/commands/_inprocess-services.js +1 -1
  14. package/dist/src/commands/_parsers.js +651 -12
  15. package/dist/src/commands/_paths.d.ts +0 -2
  16. package/dist/src/commands/_paths.js +2 -10
  17. package/dist/src/commands/_pi-install.d.ts +2 -12
  18. package/dist/src/commands/_pi-install.js +3 -36
  19. package/dist/src/commands/_policy.js +659 -20
  20. package/dist/src/commands/agent.d.ts +1 -1
  21. package/dist/src/commands/agent.js +675 -24
  22. package/dist/src/commands/config.d.ts +1 -1
  23. package/dist/src/commands/config.js +656 -21
  24. package/dist/src/commands/dist.d.ts +1 -1
  25. package/dist/src/commands/dist.js +828 -102
  26. package/dist/src/commands/doctor.d.ts +1 -1
  27. package/dist/src/commands/doctor.js +658 -12
  28. package/dist/src/commands/github.d.ts +1 -1
  29. package/dist/src/commands/github.js +658 -19
  30. package/dist/src/commands/inbox.d.ts +12 -8
  31. package/dist/src/commands/inbox.js +741 -22
  32. package/dist/src/commands/init.d.ts +17 -19
  33. package/dist/src/commands/init.js +836 -306
  34. package/dist/src/commands/inspect.d.ts +5 -6
  35. package/dist/src/commands/inspect.js +754 -42
  36. package/dist/src/commands/pi.d.ts +1 -1
  37. package/dist/src/commands/pi.js +655 -16
  38. package/dist/src/commands/plugin.d.ts +9 -9
  39. package/dist/src/commands/plugin.js +652 -13
  40. package/dist/src/commands/profile-and-review.d.ts +1 -1
  41. package/dist/src/commands/profile-and-review.js +655 -16
  42. package/dist/src/commands/queue.d.ts +1 -1
  43. package/dist/src/commands/queue.js +871 -12
  44. package/dist/src/commands/remote-client.d.ts +152 -0
  45. package/dist/src/commands/remote-client.js +475 -0
  46. package/dist/src/commands/remote.d.ts +1 -1
  47. package/dist/src/commands/remote.js +1100 -29
  48. package/dist/src/commands/repo-git-harness.d.ts +1 -1
  49. package/dist/src/commands/repo-git-harness.js +2321 -47
  50. package/dist/src/commands/run.d.ts +10 -6
  51. package/dist/src/commands/run.js +830 -50
  52. package/dist/src/commands/server.d.ts +1 -1
  53. package/dist/src/commands/server.js +649 -11
  54. package/dist/src/commands/setup.d.ts +2 -2
  55. package/dist/src/commands/setup.js +829 -18
  56. package/dist/src/commands/stats.d.ts +2 -4
  57. package/dist/src/commands/stats.js +1299 -20
  58. package/dist/src/commands/test.d.ts +1 -1
  59. package/dist/src/commands/test.js +648 -9
  60. package/dist/src/commands/triage.d.ts +2 -3
  61. package/dist/src/commands/triage.js +657 -11
  62. package/dist/src/commands/workspace.d.ts +1 -1
  63. package/dist/src/commands/workspace.js +1280 -15
  64. package/dist/src/control-plane/agent-binary-build.d.ts +9 -0
  65. package/dist/src/control-plane/agent-binary-build.js +88 -0
  66. package/dist/src/control-plane/embedded-native-assets.d.ts +7 -0
  67. package/dist/src/control-plane/embedded-native-assets.js +6 -0
  68. package/dist/src/control-plane/guard.d.ts +17 -0
  69. package/dist/src/control-plane/guard.js +684 -0
  70. package/dist/src/control-plane/harness-cli.d.ts +12 -0
  71. package/dist/src/control-plane/harness-cli.js +1623 -0
  72. package/dist/src/control-plane/native/git-ops.d.ts +67 -0
  73. package/dist/src/control-plane/native/git-ops.js +1381 -0
  74. package/dist/src/control-plane/native/github-auth-env.d.ts +1 -0
  75. package/dist/src/control-plane/native/github-auth-env.js +21 -0
  76. package/dist/src/control-plane/native/host-git.d.ts +4 -0
  77. package/dist/src/control-plane/native/host-git.js +51 -0
  78. package/dist/src/control-plane/priority-queue.d.ts +22 -0
  79. package/dist/src/control-plane/priority-queue.js +212 -0
  80. package/dist/src/control-plane/rigfig.d.ts +9 -0
  81. package/dist/src/control-plane/rigfig.js +70 -0
  82. package/dist/src/control-plane/scope.d.ts +3 -0
  83. package/dist/src/control-plane/scope.js +58 -0
  84. package/dist/src/control-plane/setup-status.d.ts +44 -0
  85. package/dist/src/control-plane/setup-status.js +164 -0
  86. package/dist/src/control-plane/task-data.d.ts +2 -0
  87. package/dist/src/control-plane/task-data.js +12 -0
  88. package/dist/src/control-plane/workspace-ops.d.ts +79 -0
  89. package/dist/src/control-plane/workspace-ops.js +639 -0
  90. package/dist/src/help-catalog-data.d.ts +7 -0
  91. package/dist/src/help-catalog-data.js +660 -0
  92. package/dist/src/kernel-dispatch.js +1 -3
  93. package/dist/src/plugin.js +10072 -30
  94. package/dist/src/runner.d.ts +7 -9
  95. package/dist/src/runner.js +750 -30
  96. package/package.json +12 -13
  97. package/dist/src/commands/_json-output.d.ts +0 -11
  98. package/dist/src/commands/_json-output.js +0 -54
  99. package/dist/src/commands/_pi-frontend.d.ts +0 -35
  100. package/dist/src/commands/_pi-frontend.js +0 -64
  101. package/dist/src/commands/_run-driver-helpers.d.ts +0 -26
  102. package/dist/src/commands/_run-driver-helpers.js +0 -132
  103. package/dist/src/commands/task-run-driver.d.ts +0 -93
  104. package/dist/src/commands/task-run-driver.js +0 -136
  105. package/dist/src/commands/task.d.ts +0 -46
  106. package/dist/src/commands/task.js +0 -555
  107. package/dist/src/provider-model.d.ts +0 -34
  108. package/dist/src/provider-model.js +0 -56
  109. package/dist/src/rig-config-package-deps.d.ts +0 -10
  110. package/dist/src/rig-config-package-deps.js +0 -272
  111. package/dist/src/version.d.ts +0 -8
  112. package/dist/src/version.js +0 -47
@@ -1,20 +1,740 @@
1
1
  // @bun
2
2
  // packages/cli-surface-plugin/src/runner.ts
3
3
  var {$ } = globalThis.Bun;
4
- import { existsSync, mkdirSync } from "fs";
4
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
5
+ import { resolve as resolve3 } from "path";
6
+ import { EventBus } from "@rig/core/runtime-events";
7
+ import { CliError as RuntimeCliError } from "@rig/contracts";
8
+
9
+ // packages/cli-surface-plugin/src/control-plane/guard.ts
10
+ import { optimizeNextInvocation } from "bun:jsc";
11
+ import { existsSync, readFileSync, statSync } from "fs";
5
12
  import { resolve } from "path";
6
- import { EventBus } from "@rig/runtime/control-plane/runtime/events";
7
- import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
8
- import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
9
- import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
10
13
 
14
+ // packages/cli-surface-plugin/src/control-plane/scope.ts
15
+ import { getScopeRules } from "@rig/core/scope-rules";
16
+ var scopeRegexCache = new Map;
17
+ function unique(values) {
18
+ return [...new Set(values)];
19
+ }
20
+ function normalizeRelativeScopePath(inputPath) {
21
+ let normalized = inputPath.replace(/^\.\//, "");
22
+ const rules = getScopeRules();
23
+ if (rules?.stripPrefixes) {
24
+ for (const prefix of rules.stripPrefixes) {
25
+ if (normalized.startsWith(prefix)) {
26
+ normalized = normalized.slice(prefix.length);
27
+ }
28
+ }
29
+ }
30
+ return normalized;
31
+ }
32
+ function normalizePathToScope(projectRoot, monorepoRoot, inputPath) {
33
+ let normalized = inputPath.replace(/^\.\//, "");
34
+ if (normalized.startsWith(projectRoot + "/")) {
35
+ normalized = normalized.slice(projectRoot.length + 1);
36
+ }
37
+ if (normalized.startsWith(monorepoRoot + "/")) {
38
+ normalized = normalized.slice(monorepoRoot.length + 1);
39
+ }
40
+ return normalizeRelativeScopePath(normalized);
41
+ }
42
+ function scopeGlobToRegex(glob) {
43
+ const cached = scopeRegexCache.get(glob);
44
+ if (cached) {
45
+ return cached;
46
+ }
47
+ const escaped = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "__GLOBSTAR__").replace(/\*/g, "[^/]*").replace(/__GLOBSTAR__/g, ".*");
48
+ const compiled = new RegExp(`^${escaped}$`);
49
+ scopeRegexCache.set(glob, compiled);
50
+ return compiled;
51
+ }
52
+ function scopeMatches(path, scopes) {
53
+ const pathVariants = unique([path, normalizeRelativeScopePath(path)]);
54
+ for (const scope of scopes) {
55
+ const scopeVariants = unique([scope, normalizeRelativeScopePath(scope)]);
56
+ for (const candidatePath of pathVariants) {
57
+ for (const candidateScope of scopeVariants) {
58
+ if (candidatePath === candidateScope || scopeGlobToRegex(candidateScope).test(candidatePath)) {
59
+ return true;
60
+ }
61
+ }
62
+ }
63
+ }
64
+ return false;
65
+ }
66
+
67
+ // packages/cli-surface-plugin/src/control-plane/guard.ts
68
+ import {
69
+ POLICY_VERSION
70
+ } from "@rig/contracts";
71
+ var DEFAULT_SCOPE = {
72
+ fail_closed: true,
73
+ harness_paths_exempt: true,
74
+ runtime_paths_exempt: true
75
+ };
76
+ var DEFAULT_SANDBOX = {
77
+ mode: "enforce",
78
+ network: true,
79
+ read_deny: [],
80
+ write_allow_from_runtime: true
81
+ };
82
+ var DEFAULT_ISOLATION = {
83
+ default_mode: "worktree",
84
+ repo_symlink_fallback: false,
85
+ strict_provisioning: true,
86
+ fail_closed_on_provision_error: true
87
+ };
88
+ var DEFAULT_COMPLETION = {
89
+ derive_checks_from_scope: true,
90
+ checks: [],
91
+ typescript_config_probe: ["tsconfig.json"],
92
+ eslint_config_probe: [".eslintrc.js", ".eslintrc.json", "eslint.config.js"]
93
+ };
94
+ var DEFAULT_RUNTIME_IMAGE = {
95
+ deps: {
96
+ monorepo_install: false,
97
+ hp_next_install: false
98
+ },
99
+ plugins_require_binaries: true
100
+ };
101
+ var DEFAULT_RUNTIME_SNAPSHOT = {
102
+ enabled: true
103
+ };
104
+ function defaultPolicy() {
105
+ return {
106
+ version: POLICY_VERSION,
107
+ mode: "enforce",
108
+ scope: { ...DEFAULT_SCOPE },
109
+ rules: [],
110
+ sandbox: { ...DEFAULT_SANDBOX },
111
+ isolation: { ...DEFAULT_ISOLATION },
112
+ completion: { ...DEFAULT_COMPLETION },
113
+ runtime_image: {
114
+ deps: { ...DEFAULT_RUNTIME_IMAGE.deps },
115
+ plugins_require_binaries: DEFAULT_RUNTIME_IMAGE.plugins_require_binaries
116
+ },
117
+ runtime_snapshot: { ...DEFAULT_RUNTIME_SNAPSHOT }
118
+ };
119
+ }
120
+ var policyCache = null;
121
+ var policyCachePath = null;
122
+ var seededPolicyConfig = null;
123
+ var compiledRegexCache = new Map;
124
+ function loadPolicy(projectRoot) {
125
+ if (seededPolicyConfig) {
126
+ return seededPolicyConfig;
127
+ }
128
+ const configPath = resolve(projectRoot, "rig/policy/policy.json");
129
+ if (!existsSync(configPath)) {
130
+ return defaultPolicy();
131
+ }
132
+ let mtimeMs;
133
+ try {
134
+ mtimeMs = statSync(configPath).mtimeMs;
135
+ } catch {
136
+ return defaultPolicy();
137
+ }
138
+ if (policyCache && policyCachePath === configPath && policyCache.mtimeMs === mtimeMs) {
139
+ return policyCache.config;
140
+ }
141
+ let parsed;
142
+ try {
143
+ parsed = JSON.parse(readFileSync(configPath, "utf-8"));
144
+ } catch {
145
+ return defaultPolicy();
146
+ }
147
+ const config = mergeWithDefaults(parsed);
148
+ policyCache = { mtimeMs, config };
149
+ policyCachePath = configPath;
150
+ return config;
151
+ }
152
+ function mergeWithDefaults(parsed) {
153
+ const base = defaultPolicy();
154
+ if (typeof parsed.mode === "string" && isValidMode(parsed.mode)) {
155
+ base.mode = parsed.mode;
156
+ }
157
+ if (parsed.scope && typeof parsed.scope === "object" && !Array.isArray(parsed.scope)) {
158
+ const s = parsed.scope;
159
+ if (typeof s.fail_closed === "boolean")
160
+ base.scope.fail_closed = s.fail_closed;
161
+ if (typeof s.harness_paths_exempt === "boolean")
162
+ base.scope.harness_paths_exempt = s.harness_paths_exempt;
163
+ if (typeof s.runtime_paths_exempt === "boolean")
164
+ base.scope.runtime_paths_exempt = s.runtime_paths_exempt;
165
+ }
166
+ if (Array.isArray(parsed.rules)) {
167
+ base.rules = precompilePolicyRuleRegexes(parsed.rules.filter(isValidRule));
168
+ }
169
+ if (Array.isArray(parsed.deny) && base.rules.length === 0) {
170
+ base.rules = precompilePolicyRuleRegexes(migrateLegacyDeny(parsed.deny));
171
+ }
172
+ if (parsed.sandbox && typeof parsed.sandbox === "object" && !Array.isArray(parsed.sandbox)) {
173
+ const sb = parsed.sandbox;
174
+ if (typeof sb.mode === "string" && isValidMode(sb.mode))
175
+ base.sandbox.mode = sb.mode;
176
+ if (typeof sb.network === "boolean")
177
+ base.sandbox.network = sb.network;
178
+ if (Array.isArray(sb.read_deny))
179
+ base.sandbox.read_deny = sb.read_deny.filter((v) => typeof v === "string");
180
+ if (typeof sb.write_allow_from_runtime === "boolean")
181
+ base.sandbox.write_allow_from_runtime = sb.write_allow_from_runtime;
182
+ }
183
+ if (parsed.isolation && typeof parsed.isolation === "object" && !Array.isArray(parsed.isolation)) {
184
+ const iso = parsed.isolation;
185
+ if (iso.default_mode === "worktree")
186
+ base.isolation.default_mode = iso.default_mode;
187
+ if (typeof iso.repo_symlink_fallback === "boolean")
188
+ base.isolation.repo_symlink_fallback = iso.repo_symlink_fallback;
189
+ if (typeof iso.strict_provisioning === "boolean")
190
+ base.isolation.strict_provisioning = iso.strict_provisioning;
191
+ if (typeof iso.fail_closed_on_provision_error === "boolean")
192
+ base.isolation.fail_closed_on_provision_error = iso.fail_closed_on_provision_error;
193
+ }
194
+ if (parsed.completion && typeof parsed.completion === "object" && !Array.isArray(parsed.completion)) {
195
+ const comp = parsed.completion;
196
+ if (typeof comp.derive_checks_from_scope === "boolean")
197
+ base.completion.derive_checks_from_scope = comp.derive_checks_from_scope;
198
+ if (Array.isArray(comp.checks))
199
+ base.completion.checks = comp.checks.filter((v) => typeof v === "string");
200
+ if (Array.isArray(comp.typescript_config_probe))
201
+ base.completion.typescript_config_probe = comp.typescript_config_probe.filter((v) => typeof v === "string");
202
+ if (Array.isArray(comp.eslint_config_probe))
203
+ base.completion.eslint_config_probe = comp.eslint_config_probe.filter((v) => typeof v === "string");
204
+ }
205
+ if (parsed.runtime_image && typeof parsed.runtime_image === "object" && !Array.isArray(parsed.runtime_image)) {
206
+ const runtimeImage = parsed.runtime_image;
207
+ if (runtimeImage.deps && typeof runtimeImage.deps === "object" && !Array.isArray(runtimeImage.deps)) {
208
+ const deps = runtimeImage.deps;
209
+ if (typeof deps.monorepo_install === "boolean") {
210
+ base.runtime_image.deps.monorepo_install = deps.monorepo_install;
211
+ }
212
+ if (typeof deps.hp_next_install === "boolean") {
213
+ base.runtime_image.deps.hp_next_install = deps.hp_next_install;
214
+ }
215
+ }
216
+ if (typeof runtimeImage.plugins_require_binaries === "boolean") {
217
+ base.runtime_image.plugins_require_binaries = runtimeImage.plugins_require_binaries;
218
+ }
219
+ }
220
+ if (parsed.runtime_snapshot && typeof parsed.runtime_snapshot === "object" && !Array.isArray(parsed.runtime_snapshot)) {
221
+ const runtimeSnapshot = parsed.runtime_snapshot;
222
+ if (typeof runtimeSnapshot.enabled === "boolean") {
223
+ base.runtime_snapshot.enabled = runtimeSnapshot.enabled;
224
+ }
225
+ }
226
+ return base;
227
+ }
228
+ function isValidMode(value) {
229
+ return value === "off" || value === "observe" || value === "enforce";
230
+ }
231
+ function isValidRule(value) {
232
+ if (!value || typeof value !== "object" || Array.isArray(value))
233
+ return false;
234
+ const r = value;
235
+ return typeof r.id === "string" && typeof r.category === "string" && r.match != null && typeof r.match === "object";
236
+ }
237
+ function migrateLegacyDeny(deny) {
238
+ const rules = [];
239
+ for (const entry of deny) {
240
+ if (typeof entry.id !== "string")
241
+ continue;
242
+ const match = {};
243
+ if (typeof entry.pattern === "string")
244
+ match.pattern = entry.pattern;
245
+ if (typeof entry.regex === "string")
246
+ match.regex = entry.regex;
247
+ if (!match.pattern && !match.regex)
248
+ continue;
249
+ rules.push({
250
+ id: entry.id,
251
+ category: "command",
252
+ match,
253
+ action: "block",
254
+ ...typeof entry.description === "string" ? { description: entry.description } : {}
255
+ });
256
+ }
257
+ return rules;
258
+ }
259
+ function precompilePolicyRuleRegexes(rules) {
260
+ return rules.map((rule) => {
261
+ const compiledRegex = rule.match.regex ? compileSafeRegex(rule.match.regex, `rules.${rule.id}.match.regex`, true) : undefined;
262
+ const compiledUnlessRegex = rule.unless?.regex ? compileSafeRegex(rule.unless.regex, `rules.${rule.id}.unless.regex`, true) : undefined;
263
+ return {
264
+ ...rule,
265
+ ...compiledRegex ? { compiledRegex } : {},
266
+ ...compiledUnlessRegex ? { compiledUnlessRegex } : {}
267
+ };
268
+ });
269
+ }
270
+ function getRegexUnsafeReason(pattern) {
271
+ if (pattern.length > 512) {
272
+ return "pattern exceeds max safe length (512 chars)";
273
+ }
274
+ if (/\\[1-9]/.test(pattern)) {
275
+ return "pattern uses backreferences";
276
+ }
277
+ if (/\((?:[^()\\]|\\.)*[+*](?:[^()\\]|\\.)*\)\s*[*+{]/.test(pattern)) {
278
+ return "pattern contains nested quantifiers";
279
+ }
280
+ if (/\((?:[^()\\]|\\.)*\.\\?[+*](?:[^()\\]|\\.)*\)\s*[*+{]/.test(pattern)) {
281
+ return "pattern contains nested broad quantifiers";
282
+ }
283
+ return null;
284
+ }
285
+ function compileSafeRegex(pattern, sourceLabel, logOnFailure) {
286
+ const cached = compiledRegexCache.get(pattern);
287
+ if (cached !== undefined) {
288
+ return cached ?? undefined;
289
+ }
290
+ const unsafeReason = getRegexUnsafeReason(pattern);
291
+ if (unsafeReason) {
292
+ if (logOnFailure) {
293
+ console.warn(`[policy] Skipping unsafe regex in ${sourceLabel}: ${unsafeReason}`);
294
+ }
295
+ compiledRegexCache.set(pattern, null);
296
+ return;
297
+ }
298
+ try {
299
+ const compiled = new RegExp(pattern);
300
+ compiledRegexCache.set(pattern, compiled);
301
+ return compiled;
302
+ } catch (error) {
303
+ if (logOnFailure) {
304
+ const message = error instanceof Error ? error.message : String(error);
305
+ console.warn(`[policy] Skipping invalid regex in ${sourceLabel}: ${message}`);
306
+ }
307
+ compiledRegexCache.set(pattern, null);
308
+ return;
309
+ }
310
+ }
311
+ function matchRule(rule, input) {
312
+ const { match } = rule;
313
+ if (match.pattern && input.includes(match.pattern)) {
314
+ return true;
315
+ }
316
+ if (match.regex) {
317
+ const compiled = rule.compiledRegex || compileSafeRegex(match.regex, `rules.${rule.id}.match.regex`, false);
318
+ if (!compiled) {
319
+ return false;
320
+ }
321
+ try {
322
+ return compiled.test(input);
323
+ } catch {
324
+ return false;
325
+ }
326
+ }
327
+ return false;
328
+ }
329
+ function matchRuleUnless(rule, command, taskId) {
330
+ if (!rule.unless)
331
+ return false;
332
+ if (rule.unless.regex) {
333
+ const compiled = rule.compiledUnlessRegex || compileSafeRegex(rule.unless.regex, `rules.${rule.id}.unless.regex`, false);
334
+ if (!compiled) {
335
+ return false;
336
+ }
337
+ try {
338
+ if (compiled.test(command))
339
+ return true;
340
+ } catch {}
341
+ }
342
+ if (rule.unless.task_in && taskId) {
343
+ if (rule.unless.task_in.includes(taskId))
344
+ return true;
345
+ }
346
+ return false;
347
+ }
348
+ function resolveAction(mode, matched) {
349
+ if (matched.length === 0)
350
+ return "allow";
351
+ if (mode === "off")
352
+ return "allow";
353
+ if (mode === "observe")
354
+ return "warn";
355
+ return "block";
356
+ }
357
+ function resolveAbsolutePath(projectRoot, rawPath) {
358
+ if (rawPath.startsWith("/"))
359
+ return resolve(rawPath);
360
+ return resolve(projectRoot, rawPath);
361
+ }
362
+ function isHarnessPath(projectRoot, rawPath) {
363
+ const absPath = resolveAbsolutePath(projectRoot, rawPath);
364
+ const managedRoots = [
365
+ resolve(projectRoot, "rig"),
366
+ resolve(projectRoot, ".rig"),
367
+ resolve(projectRoot, "artifacts")
368
+ ];
369
+ return managedRoots.some((root) => absPath === root || absPath.startsWith(root + "/"));
370
+ }
371
+ function isRuntimePath(projectRoot, rawPath, taskWorkspace) {
372
+ const absPath = resolveAbsolutePath(projectRoot, rawPath);
373
+ if (taskWorkspace) {
374
+ const workspaceRigRoot = resolve(taskWorkspace, ".rig");
375
+ const workspaceArtifactsRoot = resolve(taskWorkspace, "artifacts");
376
+ if (absPath === workspaceRigRoot || absPath.startsWith(workspaceRigRoot + "/") || absPath === workspaceArtifactsRoot || absPath.startsWith(workspaceArtifactsRoot + "/")) {
377
+ return true;
378
+ }
379
+ }
380
+ const runtimeRoot = resolve(projectRoot, ".rig/runtime/agents");
381
+ return absPath === runtimeRoot || absPath.startsWith(runtimeRoot + "/");
382
+ }
383
+ function isTestFile(path) {
384
+ return /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(path) || /\/(__tests__|tests|test)\//.test(path);
385
+ }
386
+ function evaluate(context) {
387
+ const policy = loadPolicy(context.projectRoot);
388
+ switch (context.evaluation.type) {
389
+ case "tool-call":
390
+ return evaluateToolCall(policy, context);
391
+ case "command":
392
+ return evaluateCommand(policy, context);
393
+ case "content-write":
394
+ return evaluateContent(policy, context);
395
+ case "file-access":
396
+ return evaluateScope(policy, context, context.evaluation.file_path, context.evaluation.access);
397
+ }
398
+ }
399
+ function evaluateScope(policy, context, filePath, access) {
400
+ const allowed = () => ({
401
+ allowed: true,
402
+ matchedRules: [],
403
+ action: "allow",
404
+ failClosed: false
405
+ });
406
+ if (policy.scope.harness_paths_exempt && isHarnessPath(context.projectRoot, filePath)) {
407
+ return allowed();
408
+ }
409
+ if (policy.scope.runtime_paths_exempt && isRuntimePath(context.projectRoot, filePath, context.taskWorkspace)) {
410
+ return allowed();
411
+ }
412
+ if (!context.taskId) {
413
+ if (access === "write" && policy.scope.fail_closed) {
414
+ return {
415
+ allowed: false,
416
+ matchedRules: [],
417
+ action: resolveAction(policy.mode, [{ id: "scope:no-task", category: "command", reason: "No active task; fail-closed for write operations" }]),
418
+ failClosed: true
419
+ };
420
+ }
421
+ return allowed();
422
+ }
423
+ const scopes = context.taskScopes || [];
424
+ if (scopes.length === 0) {
425
+ return allowed();
426
+ }
427
+ if (context.taskWorkspace && context.taskWorkspace !== context.projectRoot && filePath.startsWith("/")) {
428
+ const absPath = resolve(filePath);
429
+ if (!absPath.startsWith(context.taskWorkspace + "/") && !isHarnessPath(context.projectRoot, filePath)) {
430
+ const reason2 = `Absolute path '${filePath}' is outside task runtime boundary. Allowed root: ${context.taskWorkspace}`;
431
+ const matched2 = [{ id: "scope:workspace-boundary", category: "command", reason: reason2 }];
432
+ return {
433
+ allowed: policy.mode !== "enforce",
434
+ matchedRules: matched2,
435
+ action: resolveAction(policy.mode, matched2),
436
+ failClosed: false
437
+ };
438
+ }
439
+ }
440
+ const monorepoRoot = context.monorepoRoot || process.env.MONOREPO_ROOT?.trim() || context.taskWorkspace || context.projectRoot;
441
+ let normalizedPath = filePath;
442
+ if (context.taskWorkspace && context.taskWorkspace !== context.projectRoot && filePath.startsWith(context.taskWorkspace + "/")) {
443
+ normalizedPath = filePath.slice(context.taskWorkspace.length + 1);
444
+ }
445
+ normalizedPath = normalizePathToScope(context.projectRoot, monorepoRoot, normalizedPath);
446
+ if (scopeMatches(filePath, scopes) || scopeMatches(normalizedPath, scopes)) {
447
+ return allowed();
448
+ }
449
+ const reason = `File '${filePath}' (normalized: '${normalizedPath}') is outside scope of task ${context.taskId}`;
450
+ const matched = [{ id: "scope:out-of-scope", category: "command", reason }];
451
+ return {
452
+ allowed: policy.mode !== "enforce",
453
+ matchedRules: matched,
454
+ action: resolveAction(policy.mode, matched),
455
+ failClosed: false
456
+ };
457
+ }
458
+ function evaluateCommand(policy, context) {
459
+ const evaluation = context.evaluation;
460
+ if (evaluation.type !== "command") {
461
+ return { allowed: true, matchedRules: [], action: "allow", failClosed: false };
462
+ }
463
+ const command = evaluation.command;
464
+ const matchedRules = [];
465
+ for (const rule of policy.rules) {
466
+ if (rule.category !== "command")
467
+ continue;
468
+ if (!matchRule(rule, command))
469
+ continue;
470
+ if (matchRuleUnless(rule, command, context.taskId))
471
+ continue;
472
+ matchedRules.push({
473
+ id: rule.id,
474
+ category: rule.category,
475
+ ...rule.description !== undefined ? { description: rule.description } : {},
476
+ reason: rule.description || `Matched rule ${rule.id}`
477
+ });
478
+ }
479
+ const writeTarget = extractWriteTarget(command);
480
+ if (writeTarget && !/^\/dev\//.test(writeTarget) && !/^\/proc\//.test(writeTarget)) {
481
+ const scopeResult = evaluateScope(policy, context, writeTarget, "write");
482
+ if (!scopeResult.allowed || scopeResult.matchedRules.length > 0) {
483
+ matchedRules.push(...scopeResult.matchedRules);
484
+ }
485
+ }
486
+ const action = resolveAction(policy.mode, matchedRules);
487
+ return {
488
+ allowed: action !== "block",
489
+ matchedRules,
490
+ action,
491
+ failClosed: false
492
+ };
493
+ }
494
+ function extractWriteTarget(command) {
495
+ const redirect = command.match(/>>?\s+([^\s;|&]+)/);
496
+ if (redirect?.[1])
497
+ return redirect[1];
498
+ const tee = command.match(/tee\s+(-a\s+)?([^\s;|&]+)/);
499
+ if (tee?.[2])
500
+ return tee[2];
501
+ return "";
502
+ }
503
+ function evaluateContent(policy, context) {
504
+ const evaluation = context.evaluation;
505
+ if (evaluation.type !== "content-write") {
506
+ return { allowed: true, matchedRules: [], action: "allow", failClosed: false };
507
+ }
508
+ const { content, file_path } = evaluation;
509
+ const matchedRules = [];
510
+ const scopeResult = evaluateScope(policy, context, file_path, "write");
511
+ if (scopeResult.matchedRules.length > 0) {
512
+ matchedRules.push(...scopeResult.matchedRules);
513
+ }
514
+ for (const rule of policy.rules) {
515
+ if (rule.category !== "content" && rule.category !== "import" && rule.category !== "test-integrity")
516
+ continue;
517
+ if (rule.applies_to === "test-files" && !isTestFile(file_path))
518
+ continue;
519
+ if (!matchRule(rule, content))
520
+ continue;
521
+ if (matchRuleUnless(rule, content, context.taskId))
522
+ continue;
523
+ matchedRules.push({
524
+ id: rule.id,
525
+ category: rule.category,
526
+ ...rule.description !== undefined ? { description: rule.description } : {},
527
+ reason: rule.description || `Matched rule ${rule.id}`
528
+ });
529
+ }
530
+ const action = resolveAction(policy.mode, matchedRules);
531
+ return {
532
+ allowed: action !== "block",
533
+ matchedRules,
534
+ action,
535
+ failClosed: false
536
+ };
537
+ }
538
+ function evaluateToolCall(policy, context) {
539
+ const evaluation = context.evaluation;
540
+ if (evaluation.type !== "tool-call") {
541
+ return { allowed: true, matchedRules: [], action: "allow", failClosed: false };
542
+ }
543
+ const { tool_name, tool_input } = evaluation;
544
+ const allMatched = [];
545
+ const filePaths = extractFilePathsFromToolInput(tool_name, tool_input);
546
+ for (const fp of filePaths) {
547
+ const access = isWriteTool(tool_name) ? "write" : "read";
548
+ const scopeResult = evaluateScope(policy, context, fp, access);
549
+ if (scopeResult.matchedRules.length > 0) {
550
+ allMatched.push(...scopeResult.matchedRules);
551
+ }
552
+ }
553
+ const content = extractContentFromToolInput(tool_input);
554
+ if (content) {
555
+ const filePath = filePaths[0] || "";
556
+ const contentContext = {
557
+ ...context,
558
+ evaluation: { type: "content-write", file_path: filePath, content }
559
+ };
560
+ const contentPolicy = loadPolicy(context.projectRoot);
561
+ for (const rule of contentPolicy.rules) {
562
+ if (rule.category !== "content" && rule.category !== "import" && rule.category !== "test-integrity")
563
+ continue;
564
+ if (rule.applies_to === "test-files" && !isTestFile(filePath))
565
+ continue;
566
+ if (!matchRule(rule, content))
567
+ continue;
568
+ if (matchRuleUnless(rule, content, context.taskId))
569
+ continue;
570
+ allMatched.push({
571
+ id: rule.id,
572
+ category: rule.category,
573
+ ...rule.description !== undefined ? { description: rule.description } : {},
574
+ reason: rule.description || `Matched rule ${rule.id}`
575
+ });
576
+ }
577
+ }
578
+ if (tool_name === "Bash") {
579
+ const command = String(tool_input.command || tool_input.cmd || "");
580
+ if (command) {
581
+ const cmdContext = {
582
+ ...context,
583
+ evaluation: { type: "command", command }
584
+ };
585
+ const cmdResult = evaluateCommand(policy, cmdContext);
586
+ if (cmdResult.matchedRules.length > 0) {
587
+ allMatched.push(...cmdResult.matchedRules);
588
+ }
589
+ }
590
+ }
591
+ const seen = new Set;
592
+ const deduplicated = [];
593
+ for (const rule of allMatched) {
594
+ if (!seen.has(rule.id)) {
595
+ seen.add(rule.id);
596
+ deduplicated.push(rule);
597
+ }
598
+ }
599
+ const action = resolveAction(policy.mode, deduplicated);
600
+ return {
601
+ allowed: action !== "block",
602
+ matchedRules: deduplicated,
603
+ action,
604
+ failClosed: false
605
+ };
606
+ }
607
+ function isWriteTool(toolName) {
608
+ return toolName === "Write" || toolName === "Edit" || toolName === "MultiEdit";
609
+ }
610
+ function extractFilePathsFromToolInput(toolName, input) {
611
+ const paths = [];
612
+ const add = (value) => {
613
+ if (typeof value === "string" && value.trim()) {
614
+ paths.push(value.trim());
615
+ }
616
+ };
617
+ if (toolName === "Read" || toolName === "Write" || toolName === "Edit" || toolName === "MultiEdit") {
618
+ add(input.file_path);
619
+ add(input.path);
620
+ } else if (toolName === "Glob") {
621
+ add(input.path);
622
+ } else if (toolName === "Grep") {
623
+ add(input.path);
624
+ } else {
625
+ add(input.file_path);
626
+ add(input.path);
627
+ }
628
+ return paths;
629
+ }
630
+ function extractContentFromToolInput(input) {
631
+ if (typeof input.content === "string")
632
+ return input.content;
633
+ if (typeof input.new_string === "string")
634
+ return input.new_string;
635
+ return "";
636
+ }
637
+ var guardHotPathPrimed = false;
638
+ function primeGuardHotPaths() {
639
+ if (guardHotPathPrimed) {
640
+ return;
641
+ }
642
+ guardHotPathPrimed = true;
643
+ try {
644
+ optimizeNextInvocation(matchRule);
645
+ optimizeNextInvocation(evaluate);
646
+ } catch {}
647
+ }
648
+ primeGuardHotPaths();
649
+
650
+ // packages/cli-surface-plugin/src/control-plane/agent-binary-build.ts
651
+ import { chmodSync, copyFileSync, linkSync, mkdirSync, rmSync, writeFileSync } from "fs";
652
+ import { basename, dirname, resolve as resolve2 } from "path";
653
+ import { runtimeProvisioningEnv } from "@rig/core/runtime-provisioning-env";
654
+
655
+ // packages/cli-surface-plugin/src/control-plane/embedded-native-assets.ts
656
+ var embeddedNatives = null;
657
+
658
+ // packages/cli-surface-plugin/src/control-plane/agent-binary-build.ts
659
+ function materializeSelfExecRole(outputPath, define) {
660
+ const selfPath = process.execPath;
661
+ mkdirSync(dirname(outputPath), { recursive: true });
662
+ rmSync(outputPath, { force: true });
663
+ try {
664
+ linkSync(selfPath, outputPath);
665
+ } catch {
666
+ copyFileSync(selfPath, outputPath);
667
+ }
668
+ chmodSync(outputPath, 493);
669
+ const role = basename(outputPath).replace(/\.exe$/i, "");
670
+ writeFileSync(`${outputPath}.rig-runconfig.json`, `${JSON.stringify({ role, define: define ?? {} }, null, 2)}
671
+ `, { mode: 384 });
672
+ }
673
+ function hasEmbeddedNatives() {
674
+ return embeddedNatives !== null;
675
+ }
676
+ async function buildAgentBinary(entrypoint, outputPath, cwd, defines) {
677
+ if (hasEmbeddedNatives()) {
678
+ materializeSelfExecRole(outputPath, defines);
679
+ return;
680
+ }
681
+ await buildRuntimeBinary({
682
+ entrypoint,
683
+ outputPath,
684
+ cwd,
685
+ ...defines ? { define: defines } : {},
686
+ env: runtimeProvisioningEnv()
687
+ });
688
+ }
689
+ async function buildRuntimeBinary(options) {
690
+ mkdirSync(dirname(options.outputPath), { recursive: true });
691
+ await withTemporaryEnv({
692
+ ...options.env,
693
+ ...options.define ? { RIG_BUILD_CONFIG_JSON: JSON.stringify(options.define) } : {}
694
+ }, async () => {
695
+ const result = await Bun.build({
696
+ entrypoints: [resolve2(options.cwd, options.entrypoint)],
697
+ compile: { outfile: options.outputPath },
698
+ target: "bun",
699
+ format: "esm",
700
+ minify: true,
701
+ bytecode: true,
702
+ ...options.define ? { define: { __RIG_BUILD_CONFIG__: JSON.stringify(options.define) } } : {}
703
+ });
704
+ if (!result.success) {
705
+ throw new Error(result.logs.map((log) => log.message).join(`
706
+ `) || `Failed to compile ${options.entrypoint}`);
707
+ }
708
+ });
709
+ chmodSync(options.outputPath, 493);
710
+ }
711
+ async function withTemporaryEnv(env, callback) {
712
+ const previous = {};
713
+ for (const [key, value] of Object.entries(env)) {
714
+ previous[key] = process.env[key];
715
+ if (value === undefined) {
716
+ delete process.env[key];
717
+ } else {
718
+ process.env[key] = value;
719
+ }
720
+ }
721
+ try {
722
+ return await callback();
723
+ } finally {
724
+ for (const [key, value] of Object.entries(previous)) {
725
+ if (value === undefined) {
726
+ delete process.env[key];
727
+ } else {
728
+ process.env[key] = value;
729
+ }
730
+ }
731
+ }
732
+ }
733
+
734
+ // packages/cli-surface-plugin/src/runner.ts
11
735
  class CliError extends RuntimeCliError {
12
- hint;
13
736
  constructor(message, exitCode = 1, options = {}) {
14
- super(message, exitCode);
15
- if (options.hint?.trim()) {
16
- this.hint = options.hint.trim();
17
- }
737
+ super(message, exitCode, options);
18
738
  }
19
739
  }
20
740
  function withProjectRoot(projectRoot) {
@@ -23,9 +743,9 @@ function withProjectRoot(projectRoot) {
23
743
  function formatCommand(parts) {
24
744
  return parts.map((part) => /[^a-zA-Z0-9_./:-]/.test(part) ? JSON.stringify(part) : part).join(" ");
25
745
  }
26
- var AGENT_DISPATCH_SOURCE = "packages/runtime/bin/rig-agent-dispatch.ts";
746
+ var AGENT_DISPATCH_SOURCE = "packages/cli/bin/rig-agent-dispatch.ts";
27
747
  function hasAgentDispatchSource(root) {
28
- return existsSync(resolve(root, AGENT_DISPATCH_SOURCE));
748
+ return existsSync2(resolve3(root, AGENT_DISPATCH_SOURCE));
29
749
  }
30
750
  function resolveAgentMaterializationSourceRoot(projectRoot, options = {}) {
31
751
  const env = options.env ?? process.env;
@@ -33,59 +753,60 @@ function resolveAgentMaterializationSourceRoot(projectRoot, options = {}) {
33
753
  env.RIG_HOST_PROJECT_ROOT?.trim(),
34
754
  env.PROJECT_RIG_ROOT?.trim(),
35
755
  options.cwd ?? process.cwd(),
36
- resolve(options.moduleDir ?? import.meta.dir, "../../.."),
756
+ resolve3(options.moduleDir ?? import.meta.dir, "../../.."),
37
757
  projectRoot
38
758
  ].filter((value) => Boolean(value));
39
759
  for (const candidate of candidates) {
40
- const root = resolve(candidate);
760
+ const root = resolve3(candidate);
41
761
  if (hasAgentDispatchSource(root)) {
42
762
  return root;
43
763
  }
44
764
  }
45
- return resolve(projectRoot);
765
+ return resolve3(projectRoot);
46
766
  }
47
767
  async function ensureAgentShellBinary(projectRoot, options = {}) {
48
- const agentBinary = resolve(projectRoot, ".rig", "bin", "rig-agent");
49
- if (existsSync(agentBinary)) {
768
+ const agentBinary = resolve3(projectRoot, ".rig", "bin", "rig-agent");
769
+ if (existsSync2(agentBinary)) {
50
770
  return agentBinary;
51
771
  }
52
772
  const sourceRoot = resolveAgentMaterializationSourceRoot(projectRoot, options);
53
773
  if (!hasAgentDispatchSource(sourceRoot)) {
54
774
  throw new CliError(`Missing compiled agent dispatch binary at ${agentBinary}, and no Rig source checkout with ${AGENT_DISPATCH_SOURCE} was found to materialize it automatically.`, 2);
55
775
  }
56
- mkdirSync(resolve(agentBinary, ".."), { recursive: true });
776
+ mkdirSync2(resolve3(agentBinary, ".."), { recursive: true });
57
777
  try {
58
- await (options.build ?? buildBinary)(AGENT_DISPATCH_SOURCE, agentBinary, sourceRoot, {
778
+ await (options.build ?? buildAgentBinary)(AGENT_DISPATCH_SOURCE, agentBinary, sourceRoot, {
59
779
  AGENT_PROJECT_ROOT: projectRoot
60
780
  });
61
781
  } catch (error) {
62
782
  throw new CliError(`Missing compiled agent dispatch binary at ${agentBinary}, and automatic materialization from ${sourceRoot} failed: ${error instanceof Error ? error.message : String(error)}`, 2);
63
783
  }
64
- if (!existsSync(agentBinary)) {
784
+ if (!existsSync2(agentBinary)) {
65
785
  throw new CliError(`Automatic agent dispatch materialization from ${sourceRoot} did not create ${agentBinary}.`, 2);
66
786
  }
67
787
  return agentBinary;
68
788
  }
69
789
  async function initializeRuntime(options) {
70
- const eventBus = new EventBus({ projectRoot: options.projectRoot, runId: options.runId });
71
- const context = {
790
+ const eventBus = new EventBus({ projectRoot: options.projectRoot, ...options.runId !== undefined ? { runId: options.runId } : {} });
791
+ let context;
792
+ context = {
72
793
  projectRoot: options.projectRoot,
73
794
  dryRun: options.dryRun,
74
795
  outputMode: options.outputMode,
75
796
  runId: eventBus.getRunId(),
76
- policyMode: options.policyMode,
797
+ ...options.policyMode !== undefined ? { policyMode: options.policyMode } : {},
77
798
  eventBus,
78
799
  emitEvent: async (type, payload) => {
79
800
  await eventBus.emit(type, payload);
80
- }
801
+ },
802
+ runCommand: async (parts) => runCommand(context, parts)
81
803
  };
82
- context.runCommand = async (parts) => runCommand(context, parts);
83
804
  await context.emitEvent("runtime.init", {
84
805
  runId: context.runId,
85
806
  outputMode: context.outputMode,
86
807
  dryRun: context.dryRun,
87
808
  policyMode: context.policyMode ?? loadPolicy(options.projectRoot).mode,
88
- policyFile: resolve(options.projectRoot, "rig/policy/policy.json")
809
+ policyFile: resolve3(options.projectRoot, "rig/policy/policy.json")
89
810
  });
90
811
  return context;
91
812
  }
@@ -95,7 +816,7 @@ async function runCommand(context, parts) {
95
816
  }
96
817
  const envMode = process.env.RIG_BASH_MODE;
97
818
  const effectiveMode = context.policyMode || (envMode === "off" || envMode === "observe" || envMode === "enforce" ? envMode : loadPolicy(context.projectRoot).mode);
98
- const controlledPath = `${resolve(context.projectRoot, ".rig", "bin")}:${context.projectRoot}/rig/tools:${process.env.PATH ?? ""}`;
819
+ const controlledPath = `${resolve3(context.projectRoot, ".rig", "bin")}:${context.projectRoot}/rig/tools:${process.env.PATH ?? ""}`;
99
820
  const usesInfrastructureBinary = parts[0] === "rig-server";
100
821
  const controlledBash = usesInfrastructureBinary ? null : await ensureAgentShellBinary(context.projectRoot);
101
822
  const commandEnv = [
@@ -104,7 +825,7 @@ async function runCommand(context, parts) {
104
825
  `PROJECT_RIG_ROOT=${context.projectRoot}`,
105
826
  ...controlledBash ? [`BASH=${controlledBash}`] : [],
106
827
  `RIG_BASH_MODE=${effectiveMode}`,
107
- `RIG_POLICY_FILE=${resolve(context.projectRoot, "rig/policy/policy.json")}`,
828
+ `RIG_POLICY_FILE=${resolve3(context.projectRoot, "rig/policy/policy.json")}`,
108
829
  ...context.eventBus.getEventsFile() ? [`RIG_EVENTS_FILE=${context.eventBus.getEventsFile()}`] : []
109
830
  ];
110
831
  const commandWithEnv = [...commandEnv, ...parts];
@@ -191,8 +912,7 @@ async function runCommand(context, parts) {
191
912
  durationMs: finishedAt.getTime() - startedAt.getTime(),
192
913
  startedAt: startedAt.toISOString(),
193
914
  finishedAt: finishedAt.toISOString(),
194
- stdout: context.outputMode === "json" ? stdout : undefined,
195
- stderr: context.outputMode === "json" ? stderr : undefined
915
+ ...context.outputMode === "json" ? { stdout, stderr } : {}
196
916
  };
197
917
  if (exitCode !== 0) {
198
918
  await context.emitEvent("command.failed", {