@h-rig/harness-plugin 0.0.6-alpha.186

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 (82) hide show
  1. package/README.md +1 -0
  2. package/dist/bin/rig-agent-dispatch.d.ts +2 -0
  3. package/dist/bin/rig-agent-dispatch.js +826 -0
  4. package/dist/src/agent-command.d.ts +3 -0
  5. package/dist/src/agent-command.js +233 -0
  6. package/dist/src/agent-harness/agent-mode.d.ts +1 -0
  7. package/dist/src/agent-harness/agent-mode.js +48 -0
  8. package/dist/src/agent-harness/agent-wrapper.d.ts +60 -0
  9. package/dist/src/agent-harness/agent-wrapper.js +842 -0
  10. package/dist/src/agent-harness/controlled-bash.d.ts +3 -0
  11. package/dist/src/agent-harness/controlled-bash.js +45 -0
  12. package/dist/src/agent-harness/git-ops.d.ts +2 -0
  13. package/dist/src/agent-harness/git-ops.js +27 -0
  14. package/dist/src/agent-harness/repo-ops.d.ts +14 -0
  15. package/dist/src/agent-harness/repo-ops.js +37 -0
  16. package/dist/src/agent-harness/rig-agent-entrypoint.d.ts +1 -0
  17. package/dist/src/agent-harness/rig-agent-entrypoint.js +1362 -0
  18. package/dist/src/agent-harness/rig-agent.d.ts +2 -0
  19. package/dist/src/agent-harness/rig-agent.js +1324 -0
  20. package/dist/src/agent-harness/runtime-snapshot-config.d.ts +2 -0
  21. package/dist/src/agent-harness/runtime-snapshot-config.js +25 -0
  22. package/dist/src/agent-harness/task-data.d.ts +27 -0
  23. package/dist/src/agent-harness/task-data.js +286 -0
  24. package/dist/src/agent-harness/task-ops.d.ts +10 -0
  25. package/dist/src/agent-harness/task-ops.js +352 -0
  26. package/dist/src/index.d.ts +6 -0
  27. package/dist/src/index.js +4525 -0
  28. package/dist/src/model.d.ts +80 -0
  29. package/dist/src/model.js +64 -0
  30. package/dist/src/pi-command.d.ts +3 -0
  31. package/dist/src/pi-command.js +154 -0
  32. package/dist/src/pi-settings-materializer.d.ts +10 -0
  33. package/dist/src/pi-settings-materializer.js +52 -0
  34. package/dist/src/plugin.d.ts +24 -0
  35. package/dist/src/plugin.js +4486 -0
  36. package/dist/src/profile-command.d.ts +3 -0
  37. package/dist/src/profile-command.js +79 -0
  38. package/dist/src/profile-state.d.ts +7 -0
  39. package/dist/src/profile-state.js +39 -0
  40. package/dist/src/rig-task-run-skill.d.ts +8 -0
  41. package/dist/src/rig-task-run-skill.js +39 -0
  42. package/dist/src/runtime-instructions.d.ts +4 -0
  43. package/dist/src/runtime-instructions.js +26 -0
  44. package/dist/src/runtime-secrets.d.ts +6 -0
  45. package/dist/src/runtime-secrets.js +58 -0
  46. package/dist/src/service.d.ts +14 -0
  47. package/dist/src/service.js +33 -0
  48. package/dist/src/session-asset-materializer-service.d.ts +13 -0
  49. package/dist/src/session-asset-materializer-service.js +164 -0
  50. package/dist/src/session-hook-materializer-service.d.ts +34 -0
  51. package/dist/src/session-hook-materializer-service.js +142 -0
  52. package/dist/src/skill-materializer.d.ts +25 -0
  53. package/dist/src/skill-materializer.js +86 -0
  54. package/dist/src/tooling/browser-tool-entrypoint.d.ts +2 -0
  55. package/dist/src/tooling/browser-tool-entrypoint.js +125 -0
  56. package/dist/src/tooling/browser-tools.d.ts +3 -0
  57. package/dist/src/tooling/browser-tools.js +27 -0
  58. package/dist/src/tooling/claude-router-binary.d.ts +3 -0
  59. package/dist/src/tooling/claude-router-binary.js +62 -0
  60. package/dist/src/tooling/claude-router.d.ts +22 -0
  61. package/dist/src/tooling/claude-router.js +524 -0
  62. package/dist/src/tooling/embedded-native-assets.d.ts +7 -0
  63. package/dist/src/tooling/embedded-native-assets.js +6 -0
  64. package/dist/src/tooling/file-tools.d.ts +5 -0
  65. package/dist/src/tooling/file-tools.js +192 -0
  66. package/dist/src/tooling/gateway.d.ts +4 -0
  67. package/dist/src/tooling/gateway.js +400 -0
  68. package/dist/src/tooling/shell-tools.d.ts +5 -0
  69. package/dist/src/tooling/shell-tools.js +185 -0
  70. package/native/darwin-arm64/rig-shell +0 -0
  71. package/native/darwin-arm64/rig-shell.build-manifest.json +4 -0
  72. package/native/darwin-arm64/rig-tools +0 -0
  73. package/native/darwin-arm64/rig-tools.build-manifest.json +4 -0
  74. package/native/darwin-x64/rig-shell +0 -0
  75. package/native/darwin-x64/rig-tools +0 -0
  76. package/native/linux-arm64/rig-shell +0 -0
  77. package/native/linux-arm64/rig-tools +0 -0
  78. package/native/linux-x64/rig-shell +0 -0
  79. package/native/linux-x64/rig-tools +0 -0
  80. package/native/win32-x64/rig-shell.exe +0 -0
  81. package/native/win32-x64/rig-tools.exe +0 -0
  82. package/package.json +101 -0
@@ -0,0 +1,4486 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true,
12
+ configurable: true,
13
+ set: __exportSetter.bind(all, name)
14
+ });
15
+ };
16
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
+ var __require = import.meta.require;
18
+
19
+ // packages/harness-plugin/src/agent-harness/controlled-bash.ts
20
+ import { existsSync } from "fs";
21
+ import { resolve } from "path";
22
+ import { resolveRigLayout } from "@rig/core/layout";
23
+ function controlledBashCandidates(projectRoot) {
24
+ const layout = resolveRigLayout(projectRoot);
25
+ const candidates = [
26
+ process.env.RIG_CONTROLLED_BASH_BIN?.trim() || "",
27
+ resolve(layout.binDir, "controlled-bash"),
28
+ Bun.which("controlled-bash") || ""
29
+ ];
30
+ return candidates.filter((candidate) => Boolean(candidate));
31
+ }
32
+ function resolveControlledBash(projectRoot) {
33
+ for (const candidate of controlledBashCandidates(projectRoot)) {
34
+ if (existsSync(candidate))
35
+ return candidate;
36
+ }
37
+ return null;
38
+ }
39
+ async function runControlledBash(args, options) {
40
+ const projectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || process.env.PROJECT_RIG_ROOT?.trim() || process.env.RIG_TASK_WORKSPACE?.trim() || process.cwd() || options.projectRootFallbackDir;
41
+ const controlled = resolveControlledBash(projectRoot);
42
+ if (!controlled) {
43
+ console.error("[rig-agent] controlled-bash entrypoint unavailable; refusing to run an unguarded shell.");
44
+ return 126;
45
+ }
46
+ const command = [controlled, ...args];
47
+ const child = Bun.spawn(command, {
48
+ stdin: "inherit",
49
+ stdout: "inherit",
50
+ stderr: "inherit",
51
+ cwd: process.cwd(),
52
+ env: {
53
+ ...process.env,
54
+ PROJECT_RIG_ROOT: projectRoot,
55
+ RIG_BASH_ACTIVE: "1"
56
+ }
57
+ });
58
+ return await child.exited;
59
+ }
60
+ var init_controlled_bash = () => {};
61
+
62
+ // packages/harness-plugin/src/agent-harness/agent-mode.ts
63
+ function looksLikeShellInvocation(args, mode = process.env.RIG_AGENT_MODE) {
64
+ if (mode === "shell") {
65
+ return true;
66
+ }
67
+ if (mode === "agent") {
68
+ return false;
69
+ }
70
+ if (args.length === 0) {
71
+ return false;
72
+ }
73
+ const first = args[0];
74
+ if (!first) {
75
+ return false;
76
+ }
77
+ const bashLikeFlags = new Set([
78
+ "-c",
79
+ "-lc",
80
+ "-l",
81
+ "-i",
82
+ "-s",
83
+ "--login",
84
+ "--noprofile",
85
+ "--norc",
86
+ "--posix",
87
+ "--rcfile",
88
+ "--init-file",
89
+ "--restricted",
90
+ "--debug",
91
+ "--debugger",
92
+ "--verbose",
93
+ "--wordexp",
94
+ "--dump-strings",
95
+ "--dump-po-strings",
96
+ "--help"
97
+ ]);
98
+ if (bashLikeFlags.has(first)) {
99
+ return true;
100
+ }
101
+ if (!first.startsWith("-")) {
102
+ return first.endsWith(".sh");
103
+ }
104
+ return false;
105
+ }
106
+
107
+ // packages/harness-plugin/src/runtime-secrets.ts
108
+ var exports_runtime_secrets = {};
109
+ __export(exports_runtime_secrets, {
110
+ secretDefinesFromEnv: () => secretDefinesFromEnv,
111
+ runtimeSecretsService: () => runtimeSecretsService,
112
+ resolveRuntimeSecrets: () => resolveRuntimeSecrets,
113
+ loadDotEnvSecrets: () => loadDotEnvSecrets,
114
+ BAKED_RUNTIME_SECRETS: () => BAKED_RUNTIME_SECRETS
115
+ });
116
+ import { loadDotEnvValues, resolveRuntimeConfigValues } from "@rig/core/baked-secrets";
117
+ function resolveRuntimeSecrets(env, baked = BAKED_RUNTIME_SECRETS) {
118
+ return resolveRuntimeConfigValues(env, RUNTIME_SECRET_KEYS, baked);
119
+ }
120
+ function loadDotEnvSecrets(projectRoot, env = process.env) {
121
+ return loadDotEnvValues(projectRoot, RUNTIME_SECRET_KEYS, env);
122
+ }
123
+ function secretDefinesFromEnv(env = process.env, projectRoot) {
124
+ const dotenvSecrets = projectRoot ? loadDotEnvSecrets(projectRoot, env) : {};
125
+ const resolved = resolveRuntimeSecrets(env, {
126
+ ...BAKED_RUNTIME_SECRETS,
127
+ ...dotenvSecrets
128
+ });
129
+ return {
130
+ RIG_BAKED_ANTHROPIC_API_KEY: resolved.ANTHROPIC_API_KEY || "",
131
+ RIG_BAKED_OPENAI_API_KEY: resolved.OPENAI_API_KEY || "",
132
+ RIG_BAKED_OPENROUTER_API_KEY: resolved.OPENROUTER_API_KEY || "",
133
+ RIG_BAKED_AI_REVIEW_MODE: resolved.AI_REVIEW_MODE || "",
134
+ RIG_BAKED_AI_REVIEW_PROVIDER: resolved.AI_REVIEW_PROVIDER || "",
135
+ RIG_BAKED_GITHUB_TOKEN: resolved.GITHUB_TOKEN || resolved.GH_TOKEN || "",
136
+ RIG_BAKED_GITHUB_SSH_KEY: resolved.GITHUB_SSH_KEY || "",
137
+ RIG_BAKED_AWS_ACCESS_KEY_ID: resolved.AWS_ACCESS_KEY_ID || "",
138
+ RIG_BAKED_AWS_SECRET_ACCESS_KEY: resolved.AWS_SECRET_ACCESS_KEY || "",
139
+ RIG_BAKED_AWS_REGION: resolved.AWS_REGION || "",
140
+ RIG_BAKED_LINEAR_API_KEY: resolved.LINEAR_API_KEY || "",
141
+ RIG_BAKED_LINEAR_WEBHOOK_SECRET: resolved.LINEAR_WEBHOOK_SECRET || ""
142
+ };
143
+ }
144
+ var BAKED_RUNTIME_SECRETS, RUNTIME_SECRET_KEYS, runtimeSecretsService;
145
+ var init_runtime_secrets = __esm(() => {
146
+ BAKED_RUNTIME_SECRETS = {
147
+ ANTHROPIC_API_KEY: typeof RIG_BAKED_ANTHROPIC_API_KEY !== "undefined" ? RIG_BAKED_ANTHROPIC_API_KEY : "",
148
+ OPENAI_API_KEY: typeof RIG_BAKED_OPENAI_API_KEY !== "undefined" ? RIG_BAKED_OPENAI_API_KEY : "",
149
+ OPENROUTER_API_KEY: typeof RIG_BAKED_OPENROUTER_API_KEY !== "undefined" ? RIG_BAKED_OPENROUTER_API_KEY : "",
150
+ AI_REVIEW_MODE: typeof RIG_BAKED_AI_REVIEW_MODE !== "undefined" ? RIG_BAKED_AI_REVIEW_MODE : "",
151
+ AI_REVIEW_PROVIDER: typeof RIG_BAKED_AI_REVIEW_PROVIDER !== "undefined" ? RIG_BAKED_AI_REVIEW_PROVIDER : "",
152
+ GH_TOKEN: typeof RIG_BAKED_GITHUB_TOKEN !== "undefined" ? RIG_BAKED_GITHUB_TOKEN : "",
153
+ GITHUB_TOKEN: typeof RIG_BAKED_GITHUB_TOKEN !== "undefined" ? RIG_BAKED_GITHUB_TOKEN : "",
154
+ GITHUB_SSH_KEY: typeof RIG_BAKED_GITHUB_SSH_KEY !== "undefined" ? RIG_BAKED_GITHUB_SSH_KEY : "",
155
+ AWS_ACCESS_KEY_ID: typeof RIG_BAKED_AWS_ACCESS_KEY_ID !== "undefined" ? RIG_BAKED_AWS_ACCESS_KEY_ID : "",
156
+ AWS_SECRET_ACCESS_KEY: typeof RIG_BAKED_AWS_SECRET_ACCESS_KEY !== "undefined" ? RIG_BAKED_AWS_SECRET_ACCESS_KEY : "",
157
+ AWS_REGION: typeof RIG_BAKED_AWS_REGION !== "undefined" ? RIG_BAKED_AWS_REGION : "",
158
+ LINEAR_API_KEY: typeof RIG_BAKED_LINEAR_API_KEY !== "undefined" ? RIG_BAKED_LINEAR_API_KEY : "",
159
+ LINEAR_WEBHOOK_SECRET: typeof RIG_BAKED_LINEAR_WEBHOOK_SECRET !== "undefined" ? RIG_BAKED_LINEAR_WEBHOOK_SECRET : ""
160
+ };
161
+ RUNTIME_SECRET_KEYS = Object.keys(BAKED_RUNTIME_SECRETS);
162
+ runtimeSecretsService = {
163
+ resolveRuntimeSecrets,
164
+ loadDotEnvSecrets,
165
+ secretDefinesFromEnv
166
+ };
167
+ });
168
+
169
+ // packages/harness-plugin/src/agent-harness/git-ops.ts
170
+ import { LIFECYCLE_GIT_AGENT } from "@rig/contracts";
171
+ import { defineCapability } from "@rig/core/capability";
172
+ import { buildPluginHostContext } from "@rig/core/plugin-host-context";
173
+ import { loadCapabilityForRoot } from "@rig/core/capability-loaders";
174
+ async function ensureHostContext(projectRoot) {
175
+ let cached = hostContextByRoot.get(projectRoot);
176
+ if (!cached) {
177
+ cached = buildPluginHostContext(projectRoot);
178
+ hostContextByRoot.set(projectRoot, cached);
179
+ }
180
+ await cached;
181
+ }
182
+ async function loadLifecycleGit(projectRoot) {
183
+ await ensureHostContext(projectRoot);
184
+ const git = await loadCapabilityForRoot(projectRoot, LifecycleGitAgentCap);
185
+ if (!git) {
186
+ throw new Error("lifecycle git capability unavailable: load @rig/lifecycle-plugin (default bundle) before running rig-agent git commands.");
187
+ }
188
+ return git;
189
+ }
190
+ var LifecycleGitAgentCap, hostContextByRoot;
191
+ var init_git_ops = __esm(() => {
192
+ LifecycleGitAgentCap = defineCapability(LIFECYCLE_GIT_AGENT);
193
+ hostContextByRoot = new Map;
194
+ });
195
+
196
+ // packages/harness-plugin/src/profile-state.ts
197
+ var exports_profile_state = {};
198
+ __export(exports_profile_state, {
199
+ writeHarnessStateJson: () => writeHarnessStateJson,
200
+ readHarnessStateJson: () => readHarnessStateJson,
201
+ harnessStateJsonPath: () => harnessStateJsonPath,
202
+ harnessProfileStateService: () => harnessProfileStateService
203
+ });
204
+ import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
205
+ import { resolve as resolve2 } from "path";
206
+ import { resolveHarnessPaths } from "@rig/core/harness-paths";
207
+ function harnessStateJsonPath(projectRoot, filename) {
208
+ return resolve2(resolveHarnessPaths(projectRoot).stateDir, filename);
209
+ }
210
+ function readHarnessStateJson(projectRoot, filename) {
211
+ const path = harnessStateJsonPath(projectRoot, filename);
212
+ if (!existsSync2(path)) {
213
+ return null;
214
+ }
215
+ try {
216
+ const parsed = JSON.parse(readFileSync(path, "utf-8"));
217
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
218
+ } catch {
219
+ return null;
220
+ }
221
+ }
222
+ function writeHarnessStateJson(projectRoot, filename, value) {
223
+ const paths = resolveHarnessPaths(projectRoot);
224
+ mkdirSync(paths.stateDir, { recursive: true });
225
+ const path = resolve2(paths.stateDir, filename);
226
+ writeFileSync(path, `${JSON.stringify(value, null, 2)}
227
+ `, "utf-8");
228
+ return path;
229
+ }
230
+ var harnessProfileStateService;
231
+ var init_profile_state = __esm(() => {
232
+ harnessProfileStateService = {
233
+ harnessStateJsonPath,
234
+ readHarnessStateJson,
235
+ writeHarnessStateJson
236
+ };
237
+ });
238
+
239
+ // packages/harness-plugin/src/agent-harness/repo-ops.ts
240
+ import {
241
+ REPO_OPERATIONS_CAPABILITY
242
+ } from "@rig/contracts";
243
+ import { defineCapability as defineCapability2 } from "@rig/core/capability";
244
+ import { requireInstalledCapability } from "@rig/core/capability-loaders";
245
+ function repoOperations() {
246
+ return requireInstalledCapability(RepoOperationsCap, "repo operations capability unavailable: load @rig/repos-plugin before using provider harness repo operations.");
247
+ }
248
+ function repoEnsure(projectRoot, taskId) {
249
+ repoOperations().repoEnsure(projectRoot, taskId);
250
+ }
251
+ function repoPins(projectRoot, taskId) {
252
+ return repoOperations().repoPins(projectRoot, taskId);
253
+ }
254
+ function repoVerify(projectRoot, taskId) {
255
+ return repoOperations().repoVerify(projectRoot, taskId);
256
+ }
257
+ function repoDiscover(projectRoot, taskId) {
258
+ return repoOperations().repoDiscover(projectRoot, taskId);
259
+ }
260
+ function repoBaseline(projectRoot, refresh = false) {
261
+ return repoOperations().repoBaseline(projectRoot, refresh);
262
+ }
263
+ var RepoOperationsCap;
264
+ var init_repo_ops = __esm(() => {
265
+ RepoOperationsCap = defineCapability2(REPO_OPERATIONS_CAPABILITY);
266
+ });
267
+
268
+ // packages/harness-plugin/src/agent-harness/task-data.ts
269
+ import { basename } from "path";
270
+ import {
271
+ REPO_CHANGE_SET,
272
+ TASK_ARTIFACTS,
273
+ TASK_STATE_STORE,
274
+ TASK_SOURCE_CONFIG_PROJECTION
275
+ } from "@rig/contracts";
276
+ import { defineCapability as defineCapability3 } from "@rig/core/capability";
277
+ import { requireInstalledCapability as requireInstalledCapability2 } from "@rig/core/capability-loaders";
278
+ function stateStore() {
279
+ return requireInstalledCapability2(TaskStateStoreCap, "task state store capability unavailable: load @rig/tasks-plugin (default bundle) before running the provider agent harness.");
280
+ }
281
+ function artifacts() {
282
+ return requireInstalledCapability2(TaskArtifactsCap, "task artifacts capability unavailable: load @rig/tasks-plugin (default bundle) before running the provider agent harness.");
283
+ }
284
+ function taskSourceConfigProjection() {
285
+ return requireInstalledCapability2(TaskSourceConfigProjectionCap, "task source config projection capability unavailable: load @rig/tasks-plugin (default bundle) before reading validation descriptions.");
286
+ }
287
+ function repoChangeSet() {
288
+ return requireInstalledCapability2(RepoChangeSetCap, "repo change-set capability unavailable: load @rig/repos-plugin (default bundle) before reading task file changes.");
289
+ }
290
+ function currentTaskId(projectRoot) {
291
+ return stateStore().readCurrentTaskId(projectRoot) ?? "";
292
+ }
293
+ function readTaskConfig(projectRoot) {
294
+ return stateStore().readTaskConfig(projectRoot);
295
+ }
296
+ function readSourceTaskConfig(projectRoot) {
297
+ return stateStore().readSourceTaskConfig(projectRoot);
298
+ }
299
+ function readValidationDescriptions(projectRoot) {
300
+ return taskSourceConfigProjection().readSourceValidationDescriptions(projectRoot);
301
+ }
302
+ function lookupTask(_projectRoot, input) {
303
+ return input;
304
+ }
305
+ function artifactDirForId(projectRoot, id) {
306
+ return artifacts().artifactDir({ projectRoot, taskId: id });
307
+ }
308
+ function readStringList(candidate) {
309
+ return Array.isArray(candidate) ? candidate.filter((entry) => typeof entry === "string") : [];
310
+ }
311
+ function firstStringList(...candidates) {
312
+ for (const candidate of candidates) {
313
+ const values = readStringList(candidate);
314
+ if (values.length > 0)
315
+ return values;
316
+ }
317
+ return [];
318
+ }
319
+ function unique(values) {
320
+ return Array.from(new Set(values));
321
+ }
322
+ function readTaskEntry(projectRoot, taskId) {
323
+ try {
324
+ return readTaskConfig(projectRoot)[taskId] ?? readSourceTaskConfig(projectRoot)[taskId] ?? null;
325
+ } catch {
326
+ return null;
327
+ }
328
+ }
329
+ function taskDependencyIds(projectRoot, taskId) {
330
+ const entry = readTaskEntry(projectRoot, taskId);
331
+ if (!entry)
332
+ return [];
333
+ const record = entry;
334
+ return unique(firstStringList(record.deps, record.dependencies, record.validation_deps, record.validationDeps)).filter((id) => id !== taskId);
335
+ }
336
+ function taskScopePatterns(projectRoot, taskId) {
337
+ const entry = readTaskEntry(projectRoot, taskId);
338
+ return entry ? readStringList(entry.scope) : [];
339
+ }
340
+ function syncRepoChangeSetPaths(result, operation) {
341
+ if (result && typeof result.then === "function") {
342
+ throw new Error(`repo change-set ${operation} returned a Promise; lifecycle task adapter requires a synchronous provider.`);
343
+ }
344
+ return unique(result.map((entry) => entry.path).filter(Boolean));
345
+ }
346
+ function changedFilesForTask(projectRoot, taskId, scoped) {
347
+ return syncRepoChangeSetPaths(repoChangeSet().changedFiles({ projectRoot, selector: { kind: "task", taskId, scoped } }), "changedFiles");
348
+ }
349
+ function pendingFilesForTask(projectRoot, taskId, scoped) {
350
+ return syncRepoChangeSetPaths(repoChangeSet().pendingFiles({ projectRoot, selector: { kind: "task", taskId, scoped } }), "pendingFiles");
351
+ }
352
+ function taskLookup(projectRoot, id) {
353
+ const result = lookupTask(projectRoot, id);
354
+ if (!result)
355
+ throw new Error(`Not found: ${id}`);
356
+ return result;
357
+ }
358
+ function taskConfigEntryToRecord(id, entry, source) {
359
+ const record = entry;
360
+ const deps = firstStringList(record.deps, record.dependencies, record.validation_deps, record.validationDeps);
361
+ return {
362
+ id,
363
+ deps,
364
+ status: typeof entry.status === "string" ? entry.status : "open",
365
+ source,
366
+ ...typeof entry.title === "string" ? { title: entry.title } : {},
367
+ ...typeof entry.description === "string" ? { description: entry.description } : {},
368
+ ...typeof entry.acceptance_criteria === "string" ? { acceptanceCriteria: entry.acceptance_criteria } : {},
369
+ ...Array.isArray(entry.scope) ? { scope: entry.scope } : {},
370
+ ...Array.isArray(entry.validation) ? { validation: entry.validation } : {},
371
+ ...typeof entry.role === "string" ? { role: entry.role } : {},
372
+ ...entry.browser ? { browser: entry.browser } : {},
373
+ ...entry.repo_pins ? { repo_pins: entry.repo_pins } : {},
374
+ ...entry.criticality ? { criticality: entry.criticality } : {},
375
+ ...typeof entry.queue_weight === "number" ? { queue_weight: entry.queue_weight } : {},
376
+ ...entry.creates_repo !== undefined ? { creates_repo: entry.creates_repo } : {},
377
+ ...entry.auto_synced !== undefined ? { auto_synced: entry.auto_synced } : {}
378
+ };
379
+ }
380
+ async function taskInfo(projectRoot, taskId, deprecatedRuntimeProviderOverride) {
381
+ const activeTask = taskId || currentTaskId(projectRoot);
382
+ if (!activeTask)
383
+ throw new Error("No active task.");
384
+ const entry = readTaskEntry(projectRoot, activeTask);
385
+ if (!entry)
386
+ throw new Error(`Not found: ${activeTask}`);
387
+ process.stdout.write(`${JSON.stringify(taskConfigEntryToRecord(activeTask, entry, "task-config"), null, 2)}
388
+ `);
389
+ }
390
+ async function taskDeps(projectRoot, taskId) {
391
+ const activeTask = taskId || currentTaskId(projectRoot);
392
+ if (!activeTask)
393
+ throw new Error("No active task.");
394
+ const deps = taskDependencyIds(projectRoot, activeTask);
395
+ if (deps.length > 0)
396
+ process.stdout.write(`${deps.join(`
397
+ `)}
398
+ `);
399
+ }
400
+ function taskStatus(projectRoot) {
401
+ let tasks = [];
402
+ try {
403
+ tasks = Object.entries(readSourceTaskConfig(projectRoot)).map(([id, entry]) => taskConfigEntryToRecord(id, entry, "source-task-config"));
404
+ } catch {
405
+ tasks = Object.entries(readTaskConfig(projectRoot)).map(([id, entry]) => taskConfigEntryToRecord(id, entry, "legacy-task-config"));
406
+ }
407
+ const counts = tasks.reduce((acc, task) => {
408
+ const key = typeof task.status === "string" && task.status.length > 0 ? task.status : "open";
409
+ acc[key] = (acc[key] ?? 0) + 1;
410
+ return acc;
411
+ }, {});
412
+ console.log(`=== Project Rig Progress ===
413
+ `);
414
+ console.log(`Total tasks: ${tasks.length}`);
415
+ for (const status of Object.keys(counts).sort())
416
+ console.log(` ${status}: ${counts[status]}`);
417
+ }
418
+ async function taskScope(projectRoot, expandFiles, taskId) {
419
+ const activeTask = taskId || currentTaskId(projectRoot);
420
+ if (!activeTask)
421
+ throw new Error("No active task.");
422
+ const scopes = taskScopePatterns(projectRoot, activeTask);
423
+ if (scopes.length > 0)
424
+ process.stdout.write(`${scopes.join(`
425
+ `)}
426
+ `);
427
+ }
428
+ async function taskRecord(projectRoot, type, text, taskId) {
429
+ const activeTask = taskId || currentTaskId(projectRoot);
430
+ if (!activeTask)
431
+ throw new Error("No active task.");
432
+ const timestamp = new Date().toISOString();
433
+ if (type === "decision") {
434
+ const artifactService = artifacts();
435
+ const filename = "decision-log.md";
436
+ const existingNames = await artifactNames(artifactService, { projectRoot, taskId: activeTask });
437
+ const existing = existingNames.has(filename) ? (await artifactService.readArtifact({
438
+ projectRoot,
439
+ taskId: activeTask,
440
+ filename,
441
+ maxBytes: Number.MAX_SAFE_INTEGER
442
+ })).contents : "";
443
+ const result2 = await artifactService.writeArtifact({
444
+ projectRoot,
445
+ taskId: activeTask,
446
+ filename,
447
+ content: `${existing}
448
+ ### ${timestamp}
449
+
450
+ ${text}
451
+
452
+ `
453
+ });
454
+ console.log(`Decision recorded for ${activeTask}.`);
455
+ return;
456
+ }
457
+ const result = stateStore().recordFailedApproach({ projectRoot, taskId: activeTask, text, timestamp });
458
+ console.log(result.message);
459
+ }
460
+ function taskArtifactDir(projectRoot, taskId) {
461
+ return artifacts().artifactDir({ projectRoot, ...taskId !== undefined ? { taskId } : {} });
462
+ }
463
+ async function taskArtifactWrite(projectRoot, filename, content, taskId) {
464
+ const result = await artifacts().writeArtifact({
465
+ projectRoot,
466
+ filename,
467
+ content,
468
+ ...taskId !== undefined ? { taskId } : {}
469
+ });
470
+ console.log(`Wrote: ${result.path}`);
471
+ }
472
+ async function taskArtifactRead(projectRoot, filename, options = {}) {
473
+ return artifacts().readArtifact({
474
+ projectRoot,
475
+ filename,
476
+ ...options.taskId !== undefined ? { taskId: options.taskId } : {},
477
+ ...options.maxBytes !== undefined ? { maxBytes: options.maxBytes } : {}
478
+ });
479
+ }
480
+ async function taskArtifacts(projectRoot, taskId) {
481
+ const activeTask = taskId || currentTaskId(projectRoot);
482
+ if (!activeTask)
483
+ throw new Error("No active task.");
484
+ const artifactService = artifacts();
485
+ const ref = { projectRoot, taskId: activeTask };
486
+ const artifactDir = artifactService.artifactDir(ref);
487
+ await artifactService.writeArtifact({
488
+ ...ref,
489
+ filename: "changed-files.txt",
490
+ content: `${changedFilesForTask(projectRoot, activeTask, true).join(`
491
+ `)}
492
+ `
493
+ });
494
+ const existingNames = await artifactNames(artifactService, ref);
495
+ if (!existingNames.has("task-result.json")) {
496
+ await artifactService.writeArtifact({
497
+ ...ref,
498
+ filename: "task-result.json",
499
+ content: `${JSON.stringify({ task_id: activeTask, status: "completed", summary: "TODO: Write a one-line summary of what you did", completed_at: new Date().toISOString() }, null, 2)}
500
+ `
501
+ });
502
+ }
503
+ for (const [filename, content] of [
504
+ ["decision-log.md", `# Decision Log: ${activeTask}
505
+
506
+ Record key decisions here using: rig-agent record decision "..."
507
+ `],
508
+ ["next-actions.md", `# Next Actions: ${activeTask}
509
+
510
+ - TODO: Replace this scaffold with real content before completion
511
+ `]
512
+ ]) {
513
+ if (!existingNames.has(filename)) {
514
+ await artifactService.writeArtifact({ ...ref, filename, content });
515
+ }
516
+ }
517
+ console.log(`Artifacts at: ${artifactDir}/`);
518
+ }
519
+ async function artifactNames(artifactService, ref) {
520
+ const entries = await artifactService.listArtifacts(ref);
521
+ return new Set(entries.filter((entry) => entry.kind === "file").map((entry) => basename(entry.path)));
522
+ }
523
+ function taskData() {
524
+ return {
525
+ currentTaskId,
526
+ readTaskConfig,
527
+ readSourceTaskConfig,
528
+ readValidationDescriptions,
529
+ lookupTask,
530
+ taskLookup,
531
+ artifactDirForId,
532
+ taskInfo,
533
+ taskDeps,
534
+ taskStatus,
535
+ taskScope,
536
+ taskRecord,
537
+ taskArtifacts,
538
+ taskArtifactDir,
539
+ taskArtifactWrite,
540
+ taskArtifactRead,
541
+ taskDependencyIds,
542
+ changedFilesForTask,
543
+ pendingFilesForTask
544
+ };
545
+ }
546
+ var RepoChangeSetCap, TaskArtifactsCap, TaskStateStoreCap, TaskSourceConfigProjectionCap;
547
+ var init_task_data = __esm(() => {
548
+ RepoChangeSetCap = defineCapability3(REPO_CHANGE_SET);
549
+ TaskArtifactsCap = defineCapability3(TASK_ARTIFACTS);
550
+ TaskStateStoreCap = defineCapability3(TASK_STATE_STORE);
551
+ TaskSourceConfigProjectionCap = defineCapability3(TASK_SOURCE_CONFIG_PROJECTION);
552
+ });
553
+
554
+ // packages/harness-plugin/src/agent-harness/task-ops.ts
555
+ import { LIFECYCLE_VERIFICATION_SERVICE } from "@rig/contracts";
556
+ import { defineServiceCapability } from "@rig/core/capability";
557
+ import { buildPluginHostContext as buildPluginHostContext2 } from "@rig/core/plugin-host-context";
558
+ async function ensureHostContext2(projectRoot) {
559
+ let cached = hostContextByRoot2.get(projectRoot);
560
+ if (!cached) {
561
+ cached = buildPluginHostContext2(projectRoot);
562
+ hostContextByRoot2.set(projectRoot, cached);
563
+ }
564
+ return cached;
565
+ }
566
+ function taskArtifactDir2(projectRoot, taskId) {
567
+ return taskData().taskArtifactDir(projectRoot, taskId);
568
+ }
569
+ function taskArtifacts2(projectRoot, taskId) {
570
+ return taskData().taskArtifacts(projectRoot, taskId);
571
+ }
572
+ function taskArtifactWrite2(projectRoot, filename, content, taskId) {
573
+ return taskData().taskArtifactWrite(projectRoot, filename, content, taskId);
574
+ }
575
+ function taskDeps2(projectRoot, taskId) {
576
+ return taskData().taskDeps(projectRoot, taskId);
577
+ }
578
+ function taskInfo2(projectRoot, taskId) {
579
+ return taskData().taskInfo(projectRoot, taskId);
580
+ }
581
+ function taskLookup2(projectRoot, id) {
582
+ return taskData().taskLookup(projectRoot, id);
583
+ }
584
+ function taskRecord2(projectRoot, type, text, taskId) {
585
+ return taskData().taskRecord(projectRoot, type, text, taskId);
586
+ }
587
+ function taskScope2(projectRoot, expandFiles, taskId) {
588
+ return taskData().taskScope(projectRoot, expandFiles, taskId);
589
+ }
590
+ function taskStatus2(projectRoot) {
591
+ taskData().taskStatus(projectRoot);
592
+ }
593
+ async function taskValidate(projectRoot, taskId, validatorRegistry) {
594
+ const hostCtx = await ensureHostContext2(projectRoot);
595
+ const verification = hostCtx ? await LifecycleVerificationServiceCap.resolveService(hostCtx.pluginHost) : null;
596
+ const validate = verification ? verification.validate : null;
597
+ if (!validate) {
598
+ throw new Error("task validation capability unavailable: load @rig/lifecycle-plugin (default bundle) before running rig-agent validate.");
599
+ }
600
+ return validate({
601
+ projectRoot,
602
+ ...taskId !== undefined ? { taskId } : {},
603
+ ...validatorRegistry !== undefined ? { validatorRegistry } : hostCtx?.validatorRegistry !== undefined ? { validatorRegistry: hostCtx.validatorRegistry } : {}
604
+ });
605
+ }
606
+ var LifecycleVerificationServiceCap, hostContextByRoot2;
607
+ var init_task_ops = __esm(() => {
608
+ init_task_data();
609
+ LifecycleVerificationServiceCap = defineServiceCapability(LIFECYCLE_VERIFICATION_SERVICE);
610
+ hostContextByRoot2 = new Map;
611
+ });
612
+
613
+ // packages/harness-plugin/src/agent-harness/rig-agent.ts
614
+ var exports_rig_agent = {};
615
+ __export(exports_rig_agent, {
616
+ looksLikeShellInvocation: () => looksLikeShellInvocation
617
+ });
618
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
619
+ import { dirname, resolve as resolve3 } from "path";
620
+ import { readBuildConfig } from "@rig/core/build-time-config";
621
+ import { LIFECYCLE_VERIFICATION_SERVICE as LIFECYCLE_VERIFICATION_SERVICE2, MEMORY } from "@rig/contracts";
622
+ import { defineCapability as defineCapability4, defineServiceCapability as defineServiceCapability2 } from "@rig/core/capability";
623
+ import { buildProjectPluginHost, loadCapabilityForRoot as loadCapabilityForRoot2 } from "@rig/core/capability-loaders";
624
+ import { resolveCheckoutRoot as resolveMonorepoRoot } from "@rig/core/checkout-root";
625
+ import { browserEnvFromContext, loadRuntimeContext, loadRuntimeContextFromEnv } from "@rig/core/runtime-context";
626
+ import { RuntimeEventBus } from "@rig/core/runtime-events";
627
+ function getContext() {
628
+ if (cachedContext !== undefined)
629
+ return cachedContext;
630
+ cachedContext = loadRuntimeContextFromEnv() ?? inferRuntimeContext();
631
+ return cachedContext;
632
+ }
633
+ function getEventBus() {
634
+ if (cachedEventBus !== undefined) {
635
+ return cachedEventBus ?? undefined;
636
+ }
637
+ const ctx = getContext();
638
+ if (!ctx) {
639
+ cachedEventBus = null;
640
+ return;
641
+ }
642
+ const runId = ctx.runtimeId || BAKED_RUNTIME_ID || "";
643
+ cachedEventBus = new RuntimeEventBus({
644
+ projectRoot: ctx.workspaceDir,
645
+ ...runId ? { runId } : {}
646
+ });
647
+ return cachedEventBus;
648
+ }
649
+ function inferRuntimeContext() {
650
+ for (const candidate of runtimeContextCandidates()) {
651
+ if (!candidate || !existsSync3(candidate)) {
652
+ continue;
653
+ }
654
+ try {
655
+ process.env.RIG_RUNTIME_CONTEXT_FILE = candidate;
656
+ return loadRuntimeContext(candidate);
657
+ } catch {}
658
+ }
659
+ return null;
660
+ }
661
+ function runtimeContextCandidates() {
662
+ const cwd = process.cwd();
663
+ const candidates = [
664
+ resolve3(cwd, "..", "runtime-context.json"),
665
+ resolve3(cwd, ".rig", "runtime-context.json")
666
+ ];
667
+ const argv1 = process.argv[1]?.trim();
668
+ if (argv1) {
669
+ candidates.push(resolve3(argv1, "..", "..", "runtime-context.json"));
670
+ }
671
+ if (BAKED_BINARY_PATH) {
672
+ candidates.push(resolve3(BAKED_BINARY_PATH, "..", "..", "runtime-context.json"));
673
+ }
674
+ return Array.from(new Set(candidates));
675
+ }
676
+ function sha256Hex(input) {
677
+ const hasher = new Bun.CryptoHasher("sha256");
678
+ hasher.update(input);
679
+ return hasher.digest("hex");
680
+ }
681
+ function ensureRuntimeKnownHosts(runtimeHome) {
682
+ const sshDir = resolve3(runtimeHome, ".ssh");
683
+ const knownHostsPath = resolve3(sshDir, "known_hosts");
684
+ if (!existsSync3(sshDir)) {
685
+ mkdirSync2(sshDir, { recursive: true });
686
+ }
687
+ const existing = existsSync3(knownHostsPath) ? readFileSync2(knownHostsPath, "utf-8") : "";
688
+ const existingLines = new Set(existing.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
689
+ const missing = GITHUB_KNOWN_HOSTS.filter((line) => !existingLines.has(line));
690
+ if (missing.length === 0) {
691
+ return knownHostsPath;
692
+ }
693
+ try {
694
+ for (const line of missing) {
695
+ existingLines.add(line);
696
+ }
697
+ writeFileSync2(knownHostsPath, `${Array.from(existingLines).join(`
698
+ `)}
699
+ `, { mode: 420 });
700
+ } catch (err) {
701
+ const hint = existsSync3(knownHostsPath) ? "" : " \u2014 known_hosts is missing; git SSH operations may fail";
702
+ console.warn(`[rig-agent] Could not update ${knownHostsPath}: ${err instanceof Error ? err.message : String(err)}${hint}`);
703
+ }
704
+ return knownHostsPath;
705
+ }
706
+ function hydrateRuntimeProcessEnv(ctx) {
707
+ if (!ctx) {
708
+ return;
709
+ }
710
+ const contextFile = process.env.RIG_RUNTIME_CONTEXT_FILE?.trim() || inferRuntimeContextFileFromWorkspace(ctx.workspaceDir);
711
+ if (!contextFile) {
712
+ return;
713
+ }
714
+ process.env.RIG_RUNTIME_CONTEXT_FILE = contextFile;
715
+ const runtimeRoot = dirname(resolve3(contextFile));
716
+ const runtimeHome = resolve3(runtimeRoot, "home");
717
+ const runtimeTmp = resolve3(runtimeRoot, "tmp");
718
+ const runtimeCache = resolve3(runtimeRoot, "cache");
719
+ const runtimeBin = resolve3(runtimeRoot, "bin");
720
+ const runtimeWorkspaceBin = resolve3(ctx.workspaceDir, ".rig", "bin");
721
+ const runtimeTools = resolve3(ctx.workspaceDir, "rig", "tools");
722
+ if (ctx.hostProjectRoot) {
723
+ process.env.PROJECT_RIG_ROOT = ctx.hostProjectRoot;
724
+ }
725
+ process.env.RIG_TASK_ID = ctx.taskId;
726
+ process.env.RIG_TASK_WORKSPACE = ctx.workspaceDir;
727
+ process.env.RIG_STATE_DIR = ctx.stateDir;
728
+ process.env.RIG_LOGS_DIR = ctx.logsDir;
729
+ process.env.RIG_SESSION_FILE = ctx.sessionFile;
730
+ process.env.RIG_RUNTIME_HOME = runtimeRoot;
731
+ if (!process.env.RIG_HOST_PROJECT_ROOT && ctx.hostProjectRoot) {
732
+ process.env.RIG_HOST_PROJECT_ROOT = ctx.hostProjectRoot;
733
+ }
734
+ for (const [key, value] of Object.entries(browserEnvFromContext(ctx.browser))) {
735
+ process.env[key] = value;
736
+ }
737
+ if (existsSync3(runtimeHome)) {
738
+ process.env.HOME = runtimeHome;
739
+ }
740
+ if (existsSync3(runtimeTmp)) {
741
+ process.env.TMPDIR = runtimeTmp;
742
+ }
743
+ if (existsSync3(runtimeCache)) {
744
+ process.env.XDG_CACHE_HOME = runtimeCache;
745
+ }
746
+ const workspaceSecrets = loadDotEnvSecrets(ctx.workspaceDir, process.env);
747
+ const hostWorkspaceSecrets = ctx.hostProjectRoot && ctx.hostProjectRoot !== ctx.workspaceDir ? loadDotEnvSecrets(ctx.hostProjectRoot, process.env) : {};
748
+ const resolvedSecrets = resolveRuntimeSecrets(process.env, {
749
+ ...hostWorkspaceSecrets,
750
+ ...workspaceSecrets
751
+ });
752
+ for (const [key, value] of Object.entries(resolvedSecrets)) {
753
+ if (value && !process.env[key]) {
754
+ process.env[key] = value;
755
+ }
756
+ }
757
+ if (!process.env.GITHUB_TOKEN && process.env.GH_TOKEN) {
758
+ process.env.GITHUB_TOKEN = process.env.GH_TOKEN;
759
+ }
760
+ if (!process.env.GH_TOKEN && process.env.GITHUB_TOKEN) {
761
+ process.env.GH_TOKEN = process.env.GITHUB_TOKEN;
762
+ }
763
+ const currentPath = process.env.PATH || "";
764
+ const pathEntries = currentPath.split(":").filter(Boolean);
765
+ for (const entry of [runtimeBin, runtimeWorkspaceBin, runtimeTools, "/usr/bin", "/bin", "/usr/sbin", "/sbin"]) {
766
+ if (existsSync3(entry) && !pathEntries.includes(entry)) {
767
+ pathEntries.unshift(entry);
768
+ }
769
+ }
770
+ process.env.PATH = pathEntries.join(":");
771
+ if (!process.env.RIG_GIT_BIN) {
772
+ const runtimeGit = resolve3(runtimeBin, "git");
773
+ process.env.RIG_GIT_BIN = existsSync3(runtimeGit) ? runtimeGit : Bun.which("git") || "/usr/bin/git";
774
+ }
775
+ const knownHosts = ensureRuntimeKnownHosts(runtimeHome);
776
+ const agentKey = resolve3(runtimeHome, ".ssh", "rig-agent-key");
777
+ const sshParts = [
778
+ "ssh",
779
+ `-o UserKnownHostsFile="${knownHosts}"`,
780
+ "-o StrictHostKeyChecking=yes",
781
+ "-F /dev/null"
782
+ ];
783
+ if (existsSync3(agentKey)) {
784
+ sshParts.splice(1, 0, `-i "${agentKey}"`, "-o IdentitiesOnly=yes");
785
+ }
786
+ process.env.GIT_SSH_COMMAND = sshParts.join(" ");
787
+ }
788
+ function inferRuntimeContextFileFromWorkspace(workspaceDir) {
789
+ const candidate = resolve3(workspaceDir, "..", "runtime-context.json");
790
+ return existsSync3(candidate) ? candidate : "";
791
+ }
792
+ function parseEnvOrDefault(value, allowed, fallback) {
793
+ if (!value) {
794
+ return fallback;
795
+ }
796
+ return allowed.includes(value) ? value : fallback;
797
+ }
798
+ function loadProfile(projectRoot) {
799
+ const parsed = readHarnessStateJson(projectRoot, AGENT_PROFILE_FILE);
800
+ return {
801
+ ...DEFAULT_AGENT_PROFILE,
802
+ updated_at: typeof parsed?.updated_at === "string" ? parsed.updated_at : new Date().toISOString()
803
+ };
804
+ }
805
+ function showProfile(projectRoot, compact = false) {
806
+ const profile = loadProfile(projectRoot);
807
+ if (compact) {
808
+ console.log(`model=${profile.model} runtime=${profile.runtime} plugin=${profile.agent_plugin}`);
809
+ return;
810
+ }
811
+ console.log("Execution Profile:");
812
+ console.log(` model: ${profile.model}`);
813
+ console.log(` runtime: ${profile.runtime}`);
814
+ console.log(` plugin: ${profile.agent_plugin}`);
815
+ }
816
+ function setProfile(projectRoot, options) {
817
+ const invalid = [options.model, options.runtime, options.plugin, options.preset].filter((value) => typeof value === "string" && value.trim().length > 0 && value.trim() !== "pi");
818
+ if (invalid.length > 0) {
819
+ throw new Error("Only the Pi runtime profile is supported by this Rig substrate.");
820
+ }
821
+ writeHarnessStateJson(projectRoot, AGENT_PROFILE_FILE, {
822
+ ...DEFAULT_AGENT_PROFILE,
823
+ updated_at: new Date().toISOString()
824
+ });
825
+ showProfile(projectRoot, false);
826
+ }
827
+ function loadReviewProfile(projectRoot) {
828
+ const parsed = readHarnessStateJson(projectRoot, REVIEW_PROFILE_FILE);
829
+ const mode = parsed?.mode;
830
+ const provider = parsed?.provider;
831
+ return {
832
+ mode: mode === "off" || mode === "advisory" || mode === "required" ? mode : DEFAULT_REVIEW_MODE,
833
+ provider: provider === "github" ? provider : DEFAULT_REVIEW_PROVIDER,
834
+ updated_at: typeof parsed?.updated_at === "string" ? parsed.updated_at : new Date().toISOString()
835
+ };
836
+ }
837
+ function showReviewProfile(projectRoot) {
838
+ const profile = loadReviewProfile(projectRoot);
839
+ console.log("AI Review Profile:");
840
+ console.log(` mode: ${profile.mode}`);
841
+ console.log(` provider: ${profile.provider}`);
842
+ console.log(` file: ${harnessStateJsonPath(projectRoot, REVIEW_PROFILE_FILE)}`);
843
+ }
844
+ function setReviewProfile(projectRoot, mode, provider) {
845
+ if (mode !== "off" && mode !== "advisory" && mode !== "required") {
846
+ throw new Error(`Invalid mode: ${mode}. Use off|advisory|required.`);
847
+ }
848
+ const resolvedProvider = provider || DEFAULT_REVIEW_PROVIDER;
849
+ if (resolvedProvider !== "github") {
850
+ throw new Error(`Invalid provider: ${resolvedProvider}. Supported: github.`);
851
+ }
852
+ writeHarnessStateJson(projectRoot, REVIEW_PROFILE_FILE, {
853
+ mode,
854
+ provider: resolvedProvider,
855
+ updated_at: new Date().toISOString()
856
+ });
857
+ showReviewProfile(projectRoot);
858
+ }
859
+ async function main() {
860
+ const args = process.argv.slice(2);
861
+ hydrateRuntimeProcessEnv(getContext());
862
+ if (isVersionProbe(args)) {
863
+ await printVersion();
864
+ return;
865
+ }
866
+ if (args[0] === "internal") {
867
+ await runInternal(args.slice(1));
868
+ return;
869
+ }
870
+ const ctx = getContext();
871
+ if (!BAKED_PROJECT_ROOT && !ctx) {
872
+ console.error("[rig-agent] Runtime binary is missing baked task context and no runtime context file found.");
873
+ console.error("[rig-agent] Set RIG_RUNTIME_CONTEXT_FILE or use the compiled host dispatch binary.");
874
+ process.exit(1);
875
+ }
876
+ await verifyRuntimeManifest();
877
+ const commandResult = await runAgentCommand(args);
878
+ if (commandResult !== undefined) {
879
+ process.exit(commandResult);
880
+ }
881
+ if (looksLikeShellInvocation(args)) {
882
+ const code = await runControlledBash(args, { projectRootFallbackDir: import.meta.dir });
883
+ process.exit(code);
884
+ }
885
+ console.error(`[rig-agent] Unknown command: ${args[0] || "(none)"}. Run 'rig-agent help' for usage.`);
886
+ process.exit(1);
887
+ }
888
+ function isVersionProbe(args) {
889
+ if (args.length !== 1) {
890
+ return false;
891
+ }
892
+ return args[0] === "--version" || args[0] === "-v" || args[0] === "version";
893
+ }
894
+ async function printVersion() {
895
+ const probe = await Bun.$`claude --version`.cwd(process.cwd()).env(process.env).quiet().nothrow();
896
+ if (probe.exitCode === 0) {
897
+ const output = probe.stdout.toString().trim();
898
+ if (output) {
899
+ console.log(output);
900
+ return;
901
+ }
902
+ }
903
+ console.log("rig-agent 1.0.0");
904
+ }
905
+ async function runAgentCommand(args) {
906
+ const [command, ...rest] = args;
907
+ if (!command || !TASK_COMMANDS.has(command)) {
908
+ return;
909
+ }
910
+ const ctx = getContext();
911
+ const projectRoot = ctx?.workspaceDir || BAKED_PROJECT_ROOT || "";
912
+ const taskId = ctx?.taskId || BAKED_TASK_ID || "";
913
+ if (!projectRoot) {
914
+ console.error("[rig-agent] No project root baked in.");
915
+ return 1;
916
+ }
917
+ if (!taskId) {
918
+ console.error("[rig-agent] No task ID baked in.");
919
+ return 1;
920
+ }
921
+ try {
922
+ switch (command) {
923
+ case "info":
924
+ await taskInfo2(projectRoot, taskId);
925
+ return 0;
926
+ case "scope":
927
+ await taskScope2(projectRoot, rest.includes("--files"), taskId);
928
+ return 0;
929
+ case "deps":
930
+ await taskDeps2(projectRoot, taskId);
931
+ return 0;
932
+ case "status":
933
+ taskStatus2(projectRoot);
934
+ return 0;
935
+ case "artifacts":
936
+ await taskArtifacts2(projectRoot, taskId);
937
+ return 0;
938
+ case "artifact-dir":
939
+ console.log(taskArtifactDir2(projectRoot, taskId));
940
+ return 0;
941
+ case "project-root":
942
+ console.log(projectRoot);
943
+ return 0;
944
+ case "monorepo-root":
945
+ console.log(resolveMonorepoRoot(projectRoot));
946
+ return 0;
947
+ case "artifact-write": {
948
+ const filename = rest[0];
949
+ if (!filename) {
950
+ console.error(`Usage: rig-agent artifact-write <filename> [--file <path>]
951
+ ` + ` Reads content from stdin (or --file), writes to the active task artifact dir.
952
+ ` + " Example: echo '...' | rig-agent artifact-write collection-audit.md");
953
+ return 1;
954
+ }
955
+ let content;
956
+ const fileIdx = rest.indexOf("--file");
957
+ const inputFile = fileIdx !== -1 ? rest[fileIdx + 1] : undefined;
958
+ if (inputFile) {
959
+ content = readFileSync2(resolve3(projectRoot, inputFile), "utf-8");
960
+ } else {
961
+ const chunks = [];
962
+ for await (const chunk of process.stdin) {
963
+ chunks.push(Buffer.from(chunk));
964
+ }
965
+ content = Buffer.concat(chunks).toString("utf-8");
966
+ }
967
+ await taskArtifactWrite2(projectRoot, filename, content, taskId);
968
+ return 0;
969
+ }
970
+ case "validate": {
971
+ const passed = await taskValidate(projectRoot, taskId);
972
+ return passed ? 0 : 1;
973
+ }
974
+ case "completion-verification":
975
+ case "completition-verification":
976
+ return await runCompletionVerification(projectRoot);
977
+ case "lookup": {
978
+ if (rest.length !== 1) {
979
+ console.error("Usage: rig-agent lookup <task-id-or-source-id>");
980
+ return 1;
981
+ }
982
+ const lookupId = rest[0];
983
+ if (!lookupId) {
984
+ console.error("Usage: rig-agent lookup <task-id-or-source-id>");
985
+ return 1;
986
+ }
987
+ console.log(taskLookup2(projectRoot, lookupId));
988
+ return 0;
989
+ }
990
+ case "record": {
991
+ if (rest.length < 2) {
992
+ console.error("Usage: rig-agent record <decision|failure> <text>");
993
+ return 1;
994
+ }
995
+ const type = rest[0];
996
+ if (type !== "decision" && type !== "failure") {
997
+ console.error("Usage: rig-agent record <decision|failure> <text>");
998
+ return 1;
999
+ }
1000
+ await taskRecord2(projectRoot, type, rest.slice(1).join(" "), taskId);
1001
+ return 0;
1002
+ }
1003
+ case "memory": {
1004
+ const memoryService = await loadCapabilityForRoot2(projectRoot, defineCapability4(MEMORY));
1005
+ if (!memoryService) {
1006
+ console.error("[rig-agent] Shared memory requires the @rig/memory-plugin plugin in rig.config.");
1007
+ return 1;
1008
+ }
1009
+ const eventBus = getEventBus();
1010
+ console.log(await memoryService.executeMemoryCommand({
1011
+ projectRoot,
1012
+ taskId,
1013
+ runtimeContext: ctx,
1014
+ args: rest,
1015
+ ...eventBus ? { eventBus } : {}
1016
+ }));
1017
+ return 0;
1018
+ }
1019
+ case "git": {
1020
+ const capabilityRoot = ctx?.hostProjectRoot || BAKED_PROJECT_ROOT || projectRoot;
1021
+ await runGitCommand(projectRoot, taskId, rest, capabilityRoot);
1022
+ return 0;
1023
+ }
1024
+ case "repo":
1025
+ case "repo-sync":
1026
+ runRepoSyncCommand(projectRoot, taskId, rest);
1027
+ return 0;
1028
+ case "profile":
1029
+ runProfileCommand(projectRoot, rest);
1030
+ return 0;
1031
+ case "review":
1032
+ runReviewCommand(projectRoot, rest);
1033
+ return 0;
1034
+ case "help":
1035
+ printAgentHelp();
1036
+ return 0;
1037
+ default:
1038
+ return;
1039
+ }
1040
+ } catch (error) {
1041
+ console.error(error instanceof Error ? error.message : String(error));
1042
+ return 1;
1043
+ }
1044
+ }
1045
+ async function runGitCommand(projectRoot, bakedTaskId, args, capabilityRoot = projectRoot) {
1046
+ const [sub = "status", ...rest] = args;
1047
+ const task = takeOption(rest, "--task");
1048
+ const tid = task.value || bakedTaskId;
1049
+ const flags = task.rest;
1050
+ const git = await loadLifecycleGit(capabilityRoot);
1051
+ switch (sub) {
1052
+ case "status":
1053
+ git.gitStatus(projectRoot, tid);
1054
+ return;
1055
+ case "changed": {
1056
+ const scoped = flags.includes("--scoped");
1057
+ const files = git.gitChanged(projectRoot, tid, scoped);
1058
+ console.log(files.length > 0 ? files.join(`
1059
+ `) : "(none)");
1060
+ return;
1061
+ }
1062
+ case "preflight": {
1063
+ const strict = flags.includes("--strict");
1064
+ const ok = git.gitPreflight(projectRoot, tid, strict);
1065
+ if (!ok)
1066
+ throw new Error("Git preflight failed.");
1067
+ return;
1068
+ }
1069
+ case "sync-branch":
1070
+ case "ensure-branch":
1071
+ git.gitSyncBranch(projectRoot, tid);
1072
+ return;
1073
+ case "commit": {
1074
+ const target = takeOption(flags, "--target");
1075
+ const message = takeOption(target.rest, "--message");
1076
+ const allowEmpty = message.rest.includes("--allow-empty");
1077
+ const scoped = git.shouldScopeGitCommit(message.rest, Boolean(tid));
1078
+ git.gitCommit({
1079
+ projectRoot,
1080
+ taskId: tid,
1081
+ target: target.value || "monorepo",
1082
+ allowEmpty,
1083
+ scoped,
1084
+ ...message.value ? { message: message.value } : {}
1085
+ });
1086
+ return;
1087
+ }
1088
+ case "snapshot": {
1089
+ const output = takeOption(flags, "--output");
1090
+ const file = git.gitSnapshot(projectRoot, tid, output.value);
1091
+ console.log(`Snapshot written: ${file}`);
1092
+ return;
1093
+ }
1094
+ case "open-pr": {
1095
+ const target = takeOption(flags, "--target");
1096
+ const reviewer = takeOption(target.rest, "--reviewer");
1097
+ const base = takeOption(reviewer.rest, "--base");
1098
+ const title = takeOption(base.rest, "--title");
1099
+ const body = takeOption(title.rest, "--body");
1100
+ const draft = body.rest.includes("--draft");
1101
+ const result = git.gitOpenPr({
1102
+ projectRoot,
1103
+ taskId: tid,
1104
+ ...target.value ? { target: target.value } : {},
1105
+ ...reviewer.value ? { reviewer: reviewer.value } : {},
1106
+ ...base.value ? { base: base.value } : {},
1107
+ ...title.value ? { title: title.value } : {},
1108
+ ...body.value ? { body: body.value } : {},
1109
+ draft
1110
+ });
1111
+ console.log(`PR ready (${result.repoLabel}): ${result.url}`);
1112
+ console.log(`Reviewer assigned: ${result.reviewer} (${result.reviewerSource})`);
1113
+ return;
1114
+ }
1115
+ default:
1116
+ throw new Error(`Unknown git subcommand: ${sub}. Try: status, changed, preflight, sync-branch, commit, snapshot, open-pr`);
1117
+ }
1118
+ }
1119
+ function runRepoSyncCommand(projectRoot, bakedTaskId, args) {
1120
+ const [sub = "ensure", ...rest] = args;
1121
+ const task = takeOption(rest, "--task");
1122
+ const tid = task.value || bakedTaskId;
1123
+ switch (sub) {
1124
+ case "sync":
1125
+ case "ensure":
1126
+ repoEnsure(projectRoot, tid);
1127
+ return;
1128
+ case "pins": {
1129
+ const pins = repoPins(projectRoot, tid);
1130
+ printPins(pins);
1131
+ return;
1132
+ }
1133
+ case "verify": {
1134
+ const ok = repoVerify(projectRoot, tid);
1135
+ if (!ok)
1136
+ throw new Error("Repo pin verification failed.");
1137
+ return;
1138
+ }
1139
+ case "discover": {
1140
+ const pins = repoDiscover(projectRoot, tid);
1141
+ printPins(pins);
1142
+ return;
1143
+ }
1144
+ case "baseline": {
1145
+ const refresh = task.rest.includes("--refresh");
1146
+ const pins = repoBaseline(projectRoot, refresh);
1147
+ printPins(pins);
1148
+ return;
1149
+ }
1150
+ default:
1151
+ throw new Error(`Unknown repo subcommand: ${sub}. Try: sync, ensure, pins, verify, discover, baseline`);
1152
+ }
1153
+ }
1154
+ function runProfileCommand(projectRoot, args) {
1155
+ const [sub = "show", ...rest] = args;
1156
+ if (sub === "show") {
1157
+ showProfile(projectRoot, rest.includes("--compact"));
1158
+ return;
1159
+ }
1160
+ if (sub === "set") {
1161
+ const first = rest[0];
1162
+ if (first === "claude-code" || first === "codex-cli" || first === "codex-app-server") {
1163
+ setProfile(projectRoot, { preset: first });
1164
+ return;
1165
+ }
1166
+ const model = takeOption(rest, "--model");
1167
+ const runtime = takeOption(model.rest, "--runtime");
1168
+ const plugin = takeOption(runtime.rest, "--plugin");
1169
+ setProfile(projectRoot, {
1170
+ ...model.value ? { model: model.value } : {},
1171
+ ...runtime.value ? { runtime: runtime.value } : {},
1172
+ ...plugin.value ? { plugin: plugin.value } : {}
1173
+ });
1174
+ return;
1175
+ }
1176
+ throw new Error(`Unknown profile subcommand: ${sub}. Try: show, set`);
1177
+ }
1178
+ function runReviewCommand(projectRoot, args) {
1179
+ const [sub = "show", ...rest] = args;
1180
+ if (sub === "show") {
1181
+ showReviewProfile(projectRoot);
1182
+ return;
1183
+ }
1184
+ if (sub === "set") {
1185
+ const mode = rest[0];
1186
+ if (!mode) {
1187
+ throw new Error("Usage: rig-agent review set <off|advisory|required> [--provider github]");
1188
+ }
1189
+ const provider = takeOption(rest.slice(1), "--provider");
1190
+ setReviewProfile(projectRoot, mode, provider.value);
1191
+ return;
1192
+ }
1193
+ throw new Error(`Unknown review subcommand: ${sub}. Try: show, set`);
1194
+ }
1195
+ function takeOption(args, option) {
1196
+ const rest = [];
1197
+ let value;
1198
+ for (let i = 0;i < args.length; i += 1) {
1199
+ const current = args[i];
1200
+ if (current === option) {
1201
+ const next = args[i + 1];
1202
+ if (!next || next.startsWith("-")) {
1203
+ throw new Error(`Missing value for ${option}`);
1204
+ }
1205
+ value = next;
1206
+ i += 1;
1207
+ continue;
1208
+ }
1209
+ if (current !== undefined) {
1210
+ rest.push(current);
1211
+ }
1212
+ }
1213
+ return { value, rest };
1214
+ }
1215
+ function printPins(pins) {
1216
+ if (Object.keys(pins).length === 0) {
1217
+ console.log("(none)");
1218
+ return;
1219
+ }
1220
+ for (const [key, value] of Object.entries(pins)) {
1221
+ console.log(`${key} ${value}`);
1222
+ }
1223
+ }
1224
+ function printAgentHelp() {
1225
+ console.log(`rig-agent \u2014 CLI for Project Rig agents
1226
+
1227
+ ORIENTATION:
1228
+ rig-agent info Your task, role, scope, deps \u2014 start here
1229
+ rig-agent scope [--files] Scope globs; --files expands to file list
1230
+ rig-agent deps Read dependency artifacts (decisions, next-actions)
1231
+ rig-agent lookup <id> Validate a task/source ID
1232
+ rig-agent status Epic/task progress overview
1233
+
1234
+ EXECUTION:
1235
+ rig-agent validate Run validation commands for your task
1236
+ rig-agent record decision "..." Record an architectural decision
1237
+ rig-agent record failure "..." Record a failed approach (cross-session only \u2014 not re-read in this session)
1238
+ rig-agent memory observe ... Promote a shared memory immediately
1239
+ rig-agent memory recall [query] Recall relevant shared memories
1240
+ rig-agent git status Task-aware git status
1241
+ rig-agent git changed Changed files (--scoped for scope-filtered)
1242
+ rig-agent git commit Task-aware commit (--target monorepo|project|both)
1243
+ rig-agent git snapshot Capture worktree state
1244
+ rig-agent git sync-branch Ensure task branch exists
1245
+ rig-agent git open-pr Create PR for task changes
1246
+ rig-agent repo sync Ensure monorepo checkout + task repo pins
1247
+ rig-agent profile show Show runtime profile
1248
+ rig-agent review show Show AI review gate settings
1249
+
1250
+ COMPLETION:
1251
+ rig-agent artifacts Scaffold completion artifacts (templates)
1252
+ rig-agent artifact-dir Print absolute artifact directory path
1253
+ rig-agent project-root Print absolute task worktree root
1254
+ rig-agent monorepo-root Print absolute monorepo root in the task worktree
1255
+ rig-agent artifact-write <filename> Write artifact from stdin
1256
+ rig-agent completion-verification Run final validation/review gate
1257
+ rig-agent completition-verification Alias for the same final gate
1258
+
1259
+ WORKFLOW:
1260
+ 1. rig-agent info Understand your assignment
1261
+ 2. rig-agent deps Read what prior tasks decided
1262
+ 3. rig-agent repo sync Align monorepo checkout + repo pins
1263
+ 4. (do your work)
1264
+ 5. rig-agent record decision "chose X because Y"
1265
+ 6. rig-agent validate Check your work
1266
+ 7. rig-agent artifacts Scaffold completion artifacts
1267
+ 8. rig-agent artifact-write collection-audit.md (write custom artifacts)
1268
+ 9. rig-agent completion-verification
1269
+ `);
1270
+ }
1271
+ async function runCompletionVerification(projectRoot) {
1272
+ const host = await buildProjectPluginHost(projectRoot);
1273
+ const verification = host ? await defineServiceCapability2(LIFECYCLE_VERIFICATION_SERVICE2).resolveService(host) : null;
1274
+ if (!verification) {
1275
+ console.error("[rig-agent] Completion verification requires the @rig/lifecycle-plugin plugin in rig.config.");
1276
+ return 1;
1277
+ }
1278
+ const { ok } = await verification.verifyCompletion({ projectRoot });
1279
+ return ok ? 0 : 1;
1280
+ }
1281
+ async function runInternal(args) {
1282
+ const [command = "", ...rest] = args;
1283
+ if (command === "shell") {
1284
+ const code = await runControlledBash(rest, { projectRootFallbackDir: import.meta.dir });
1285
+ process.exit(code);
1286
+ }
1287
+ if (command === "manifest-verify") {
1288
+ await verifyRuntimeManifest();
1289
+ console.log("manifest: ok");
1290
+ return;
1291
+ }
1292
+ throw new Error("Unknown internal command. Use `rig-agent internal shell <bash-args...>` or `rig-agent internal manifest-verify`.");
1293
+ }
1294
+ async function verifyRuntimeManifest() {
1295
+ if (getContext()) {
1296
+ return;
1297
+ }
1298
+ const manifestPath = BAKED_MANIFEST_PATH;
1299
+ if (!manifestPath) {
1300
+ return;
1301
+ }
1302
+ if (!existsSync3(manifestPath)) {
1303
+ throw new Error(`[rig-agent] Runtime manifest missing: ${manifestPath}`);
1304
+ }
1305
+ let manifest;
1306
+ try {
1307
+ manifest = await Bun.file(manifestPath).json();
1308
+ } catch (error) {
1309
+ throw new Error(`[rig-agent] Failed to parse runtime manifest at ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`);
1310
+ }
1311
+ assertMatch("taskId", BAKED_TASK_ID, manifest.taskId);
1312
+ assertMatch("runtimeId", BAKED_RUNTIME_ID, manifest.runtimeId);
1313
+ assertMatch("scopeHash", BAKED_SCOPE_HASH, manifest.scopeHash);
1314
+ const manifestBinaryPath = manifest.binary?.path || BAKED_BINARY_PATH || process.execPath;
1315
+ const expectedHash = manifest.binary?.sha256 || "";
1316
+ if (!manifestBinaryPath || !expectedHash) {
1317
+ throw new Error(`[rig-agent] Runtime manifest is missing binary hash data (${manifestPath}).`);
1318
+ }
1319
+ if (!existsSync3(manifestBinaryPath)) {
1320
+ throw new Error(`[rig-agent] Runtime binary not found at ${manifestBinaryPath}.`);
1321
+ }
1322
+ const actualHash = sha256Hex(readFileSync2(resolve3(manifestBinaryPath)));
1323
+ if (actualHash !== expectedHash) {
1324
+ throw new Error(`[rig-agent] Runtime manifest mismatch for binary hash.
1325
+ ` + `expected=${expectedHash}
1326
+ ` + `actual=${actualHash}
1327
+ ` + `path=${manifestBinaryPath}`);
1328
+ }
1329
+ }
1330
+ function assertMatch(name, expected, actual) {
1331
+ if (!expected && !actual) {
1332
+ return;
1333
+ }
1334
+ if (expected !== (actual || "")) {
1335
+ throw new Error(`[rig-agent] Runtime manifest mismatch for ${name}: expected='${expected}' actual='${actual || ""}'.`);
1336
+ }
1337
+ }
1338
+ var BUILD_CONFIG, BAKED_BINARY_PATH, BAKED_MANIFEST_PATH, BAKED_PROJECT_ROOT, BAKED_RUNTIME_ID, BAKED_TASK_ID, BAKED_SCOPE_HASH, BAKED_INFO_OUTPUT, BAKED_DEPS_OUTPUT, BAKED_STATUS_OUTPUT, BAKED_GIT_BRANCH, BAKED_BASE_COMMIT, cachedContext, cachedEventBus, GITHUB_KNOWN_HOSTS, AGENT_PROFILE_FILE = "agent-profile.json", REVIEW_PROFILE_FILE = "review-profile.json", DEFAULT_AGENT_PROFILE, DEFAULT_REVIEW_MODE, DEFAULT_REVIEW_PROVIDER, TASK_COMMANDS;
1339
+ var init_rig_agent = __esm(() => {
1340
+ init_controlled_bash();
1341
+ init_runtime_secrets();
1342
+ init_git_ops();
1343
+ init_profile_state();
1344
+ init_repo_ops();
1345
+ init_task_ops();
1346
+ BUILD_CONFIG = readBuildConfig();
1347
+ BAKED_BINARY_PATH = BUILD_CONFIG.AGENT_BINARY_PATH ?? "";
1348
+ BAKED_MANIFEST_PATH = BUILD_CONFIG.AGENT_MANIFEST_PATH ?? "";
1349
+ BAKED_PROJECT_ROOT = BUILD_CONFIG.AGENT_PROJECT_ROOT ?? "";
1350
+ BAKED_RUNTIME_ID = BUILD_CONFIG.AGENT_RUNTIME_ID ?? "";
1351
+ BAKED_TASK_ID = BUILD_CONFIG.AGENT_TASK_ID ?? "";
1352
+ BAKED_SCOPE_HASH = BUILD_CONFIG.AGENT_SCOPE_HASH ?? "";
1353
+ BAKED_INFO_OUTPUT = BUILD_CONFIG.AGENT_INFO_OUTPUT ?? "";
1354
+ BAKED_DEPS_OUTPUT = BUILD_CONFIG.AGENT_DEPS_OUTPUT ?? "";
1355
+ BAKED_STATUS_OUTPUT = BUILD_CONFIG.AGENT_STATUS_OUTPUT ?? "";
1356
+ BAKED_GIT_BRANCH = BUILD_CONFIG.AGENT_GIT_BRANCH ?? "";
1357
+ BAKED_BASE_COMMIT = BUILD_CONFIG.AGENT_BASE_COMMIT ?? "";
1358
+ if (BAKED_BINARY_PATH) {
1359
+ const binaryDir = dirname(BAKED_BINARY_PATH);
1360
+ const currentPath = process.env.PATH || "";
1361
+ const pathEntries = currentPath.split(":").filter(Boolean);
1362
+ if (!pathEntries.includes(binaryDir)) {
1363
+ process.env.PATH = currentPath ? `${binaryDir}:${currentPath}` : binaryDir;
1364
+ }
1365
+ }
1366
+ GITHUB_KNOWN_HOSTS = [
1367
+ "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl",
1368
+ "github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=",
1369
+ "github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk="
1370
+ ];
1371
+ DEFAULT_AGENT_PROFILE = { model: "pi", runtime: "pi", agent_plugin: "pi" };
1372
+ DEFAULT_REVIEW_MODE = parseEnvOrDefault(process.env.AI_REVIEW_MODE, ["off", "advisory", "required"], "advisory");
1373
+ DEFAULT_REVIEW_PROVIDER = parseEnvOrDefault(process.env.AI_REVIEW_PROVIDER, ["github"], "github");
1374
+ TASK_COMMANDS = new Set([
1375
+ "info",
1376
+ "scope",
1377
+ "deps",
1378
+ "status",
1379
+ "artifacts",
1380
+ "artifact-dir",
1381
+ "artifact-write",
1382
+ "project-root",
1383
+ "monorepo-root",
1384
+ "validate",
1385
+ "lookup",
1386
+ "record",
1387
+ "help",
1388
+ "completion-verification",
1389
+ "completition-verification",
1390
+ "git",
1391
+ "repo",
1392
+ "repo-sync",
1393
+ "profile",
1394
+ "review",
1395
+ "memory"
1396
+ ]);
1397
+ main().catch((error) => {
1398
+ console.error(error instanceof Error ? error.message : String(error));
1399
+ process.exit(1);
1400
+ });
1401
+ });
1402
+
1403
+ // packages/harness-plugin/src/agent-harness/rig-agent-entrypoint.ts
1404
+ var exports_rig_agent_entrypoint = {};
1405
+ __export(exports_rig_agent_entrypoint, {
1406
+ runRigAgentEntrypoint: () => runRigAgentEntrypoint
1407
+ });
1408
+ import { adopt } from "@rig/core/kernel-entrypoint";
1409
+ async function runRigAgentEntrypoint() {
1410
+ await adopt(undefined, { entrypoint: "rig-agent" });
1411
+ await Promise.resolve().then(() => (init_rig_agent(), exports_rig_agent));
1412
+ }
1413
+ var init_rig_agent_entrypoint = () => {};
1414
+
1415
+ // packages/harness-plugin/src/agent-harness/runtime-snapshot-config.ts
1416
+ import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
1417
+ import { resolve as resolve4 } from "path";
1418
+ function loadRuntimeSnapshotConfig(projectRoot) {
1419
+ const configPath = resolve4(projectRoot, "rig/policy/policy.json");
1420
+ if (!existsSync4(configPath))
1421
+ return { ...DEFAULT_RUNTIME_SNAPSHOT };
1422
+ try {
1423
+ const parsed = JSON.parse(readFileSync3(configPath, "utf8"));
1424
+ const runtimeSnapshot = parsed.runtime_snapshot;
1425
+ if (runtimeSnapshot && typeof runtimeSnapshot === "object" && !Array.isArray(runtimeSnapshot)) {
1426
+ const enabled = runtimeSnapshot.enabled;
1427
+ if (typeof enabled === "boolean")
1428
+ return { enabled };
1429
+ }
1430
+ } catch {
1431
+ return { ...DEFAULT_RUNTIME_SNAPSHOT };
1432
+ }
1433
+ return { ...DEFAULT_RUNTIME_SNAPSHOT };
1434
+ }
1435
+ var DEFAULT_RUNTIME_SNAPSHOT;
1436
+ var init_runtime_snapshot_config = __esm(() => {
1437
+ DEFAULT_RUNTIME_SNAPSHOT = { enabled: true };
1438
+ });
1439
+
1440
+ // packages/harness-plugin/src/agent-harness/agent-wrapper.ts
1441
+ var exports_agent_wrapper = {};
1442
+ __export(exports_agent_wrapper, {
1443
+ startOptionalRuntimeSnapshotSidecar: () => startOptionalRuntimeSnapshotSidecar,
1444
+ shouldBypassProviderSandboxOnPlatform: () => shouldBypassProviderSandboxOnPlatform,
1445
+ runPiRpcProviderFallback: () => runPiRpcProviderFallback,
1446
+ runPiRpcProvider: () => runPiRpcProvider,
1447
+ runAgentWrapper: () => runAgentWrapper,
1448
+ resolveRuntimeHandoffPath: () => resolveRuntimeHandoffPath,
1449
+ resolveProvider: () => resolveProvider,
1450
+ resolveOuterSandboxBypass: () => resolveOuterSandboxBypass,
1451
+ resolveFinalProviderExitCode: () => resolveFinalProviderExitCode,
1452
+ recordSnapshotMissingTaskSourceEvidence: () => recordSnapshotMissingTaskSourceEvidence,
1453
+ recordRuntimeHandoff: () => recordRuntimeHandoff,
1454
+ isTaskClosed: () => isTaskClosed,
1455
+ finalizeRuntimeSnapshot: () => finalizeRuntimeSnapshot,
1456
+ buildProviderArgs: () => buildProviderArgs
1457
+ });
1458
+ import { createRequire } from "module";
1459
+ import { resolve as resolve5 } from "path";
1460
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
1461
+ import { assertPathInsideRoot, safePathSegment, taskRuntimeId } from "@rig/core/safe-identifiers";
1462
+ import {
1463
+ ISOLATION_BACKEND,
1464
+ TASK_SOURCE_REFLECTION,
1465
+ TASK_STATE_STORE as TASK_STATE_STORE2,
1466
+ TASK_TERMINAL_STATE
1467
+ } from "@rig/contracts";
1468
+ import { defineCapability as defineCapability5 } from "@rig/core/capability";
1469
+ import { loadCapabilityForRoot as loadCapabilityForRoot3, requireCapabilityForRoot } from "@rig/core/capability-loaders";
1470
+ function resolveTaskSourceReflection(projectRoot) {
1471
+ let cached = taskSourceReflectionByRoot.get(projectRoot);
1472
+ if (!cached) {
1473
+ cached = loadCapabilityForRoot3(projectRoot, TaskSourceReflectionCap);
1474
+ taskSourceReflectionByRoot.set(projectRoot, cached);
1475
+ }
1476
+ return cached;
1477
+ }
1478
+ function resolveTaskTerminalState(projectRoot) {
1479
+ let cached = taskTerminalStateByRoot.get(projectRoot);
1480
+ if (!cached) {
1481
+ cached = requireCapabilityForRoot(projectRoot, TaskTerminalStateCap, `No TASK_TERMINAL_STATE capability is registered for project root "${projectRoot}". ` + "Install @rig/lifecycle-plugin (it ships in the default bundle) so the agent executor can resolve task terminal state.");
1482
+ taskTerminalStateByRoot.set(projectRoot, cached);
1483
+ }
1484
+ return cached;
1485
+ }
1486
+ function resolveTaskStateStore(projectRoot) {
1487
+ let cached = taskStateStoreByRoot.get(projectRoot);
1488
+ if (!cached) {
1489
+ cached = requireCapabilityForRoot(projectRoot, TaskStateStoreCap2, `No TASK_STATE_STORE capability is registered for project root "${projectRoot}". ` + "Install @rig/tasks-plugin (it ships in the default bundle) so the agent executor can resolve task-state reads.");
1490
+ taskStateStoreByRoot.set(projectRoot, cached);
1491
+ }
1492
+ return cached;
1493
+ }
1494
+ async function finalizeRuntimeSnapshot(snapshotSidecar, providerCommand, exitCode, context) {
1495
+ try {
1496
+ await snapshotSidecar.finalize(providerCommand, exitCode);
1497
+ return { ok: true };
1498
+ } catch (error) {
1499
+ emitWrapperEvent("runtime.snapshot.finalize.failed", {
1500
+ runtimeId: context.runtimeId,
1501
+ taskId: context.taskId,
1502
+ exitCode,
1503
+ error: error instanceof Error ? error.message : String(error)
1504
+ });
1505
+ console.error(`[rig-agent] Snapshot finalize failed for ${context.taskId}: ${error instanceof Error ? error.message : String(error)}`);
1506
+ if (exitCode !== 0) {
1507
+ throw error;
1508
+ }
1509
+ const message = error instanceof Error ? error.message : String(error);
1510
+ return { ok: false, snapshotMissing: true, error: message };
1511
+ }
1512
+ }
1513
+ async function startOptionalRuntimeSnapshotSidecar(runtime, startSidecar) {
1514
+ try {
1515
+ return await startSidecar(runtime, { instanceId: `${runtime.id}-wrapper` });
1516
+ } catch (error) {
1517
+ emitWrapperEvent("runtime.snapshot.start.failed", {
1518
+ runtimeId: runtime.id,
1519
+ taskId: runtime.taskId,
1520
+ error: error instanceof Error ? error.message : String(error)
1521
+ });
1522
+ console.error(`[rig-agent] Runtime snapshotting unavailable for ${runtime.taskId}: ${error instanceof Error ? error.message : String(error)}`);
1523
+ return null;
1524
+ }
1525
+ }
1526
+ async function runAgentWrapper(options = {}) {
1527
+ const projectRoot = resolve5(options.projectRoot || process.env.PROJECT_RIG_ROOT || process.cwd());
1528
+ const argv = options.argv || process.argv.slice(2);
1529
+ if (argv.length === 0 || argv[0] === "--version" || argv[0] === "--help" || argv[0] === "help") {
1530
+ console.log("[rig-agent] dispatch ready");
1531
+ return 0;
1532
+ }
1533
+ const taskId = await resolveTaskId(projectRoot);
1534
+ if (!taskId) {
1535
+ console.error("[rig-agent] No active task ID found (checked env, runtime path, task-state current task).");
1536
+ console.error("[rig-agent] Refusing to run unsandboxed. Ensure task runtime/session injection is active.");
1537
+ return 1;
1538
+ }
1539
+ const provider = resolveProvider();
1540
+ await printTaskContext(projectRoot, taskId);
1541
+ let runtime;
1542
+ let isolationBackend;
1543
+ try {
1544
+ emitWrapperEvent("runtime.provision.started", {
1545
+ projectRoot,
1546
+ taskId,
1547
+ mode: "worktree"
1548
+ });
1549
+ isolationBackend = await requireCapabilityForRoot(projectRoot, defineCapability5(ISOLATION_BACKEND), `No ISOLATION_BACKEND capability is registered for project root "${projectRoot}". ` + "Install @rig/isolation-plugin (it ships in the default bundle) so runtime provisioning can resolve a backend.");
1550
+ const taskRecordReader = await taskRecordReaderFromState(projectRoot);
1551
+ runtime = await isolationBackend.ensureAgentRuntime({
1552
+ projectRoot,
1553
+ id: taskRuntimeId(taskId),
1554
+ taskId,
1555
+ mode: "worktree",
1556
+ provider,
1557
+ ...taskRecordReader ? { taskRecordReader } : {},
1558
+ preserveTaskArtifacts: process.env.RIG_RUN_RESUME === "1" || process.env.RIG_RUNTIME_ARTIFACT_CLEANUP === "preserve"
1559
+ });
1560
+ emitWrapperEvent("runtime.provision.completed", {
1561
+ runtimeId: runtime.id,
1562
+ taskId,
1563
+ workspaceDir: runtime.workspaceDir,
1564
+ sessionDir: runtime.sessionDir,
1565
+ logsDir: runtime.logsDir,
1566
+ stateDir: runtime.stateDir,
1567
+ contextFile: runtime.contextFile,
1568
+ snapshotManaged: true
1569
+ });
1570
+ } catch (error) {
1571
+ emitWrapperEvent("runtime.provision.failed", {
1572
+ taskId,
1573
+ error: error instanceof Error ? error.message : String(error)
1574
+ });
1575
+ console.error(`[rig-agent] Failed to provision runtime: ${error}`);
1576
+ return 1;
1577
+ }
1578
+ try {
1579
+ await waitForDirtyBaselineReady(runtime, taskId);
1580
+ } catch (error) {
1581
+ emitWrapperEvent("runtime.baseline.failed", {
1582
+ runtimeId: runtime.id,
1583
+ taskId,
1584
+ workspaceDir: runtime.workspaceDir,
1585
+ error: error instanceof Error ? error.message : String(error)
1586
+ });
1587
+ console.error(`[rig-agent] Failed to apply selected baseline before provider launch: ${error}`);
1588
+ return 1;
1589
+ }
1590
+ const providerArgs = buildProviderArgs(provider, runtime, argv);
1591
+ const providerCommand = [providerBinary(provider), ...providerArgs];
1592
+ emitWrapperEvent("provider.launch", {
1593
+ provider,
1594
+ runtimeId: runtime.id,
1595
+ taskId,
1596
+ workspaceDir: runtime.workspaceDir,
1597
+ command: providerCommand
1598
+ });
1599
+ const env = await isolationBackend.runtimeEnv(projectRoot, runtime);
1600
+ const bypassOuterRuntimeSandbox = resolveOuterSandboxBypass(provider, process.platform, process.env.RIG_RUNTIME_SANDBOX?.trim());
1601
+ if (provider === "pi") {
1602
+ env.PI_CODING_AGENT_DIR = resolve5(runtime.homeDir, ".pi", "agent");
1603
+ env.PI_CODING_AGENT_SESSION_DIR = runtime.sessionDir;
1604
+ }
1605
+ env.RIG_RUNTIME_SANDBOX = process.env.RIG_RUNTIME_SANDBOX?.trim() || "enforce";
1606
+ const snapshotEnabled = loadRuntimeSnapshotConfig(projectRoot).enabled;
1607
+ const snapshotSidecar = snapshotEnabled ? await startOptionalRuntimeSnapshotSidecar(runtime, (rt, opts) => isolationBackend.startRuntimeSnapshotSidecar(rt, opts)) : null;
1608
+ let exitCode = 1;
1609
+ let snapshotFinalizeResult = { ok: true };
1610
+ try {
1611
+ const command = bypassOuterRuntimeSandbox ? providerCommand : (await isolationBackend.wrapRuntimeSandbox({
1612
+ projectRoot,
1613
+ runtime: {
1614
+ id: runtime.id,
1615
+ mode: runtime.mode,
1616
+ rootDir: runtime.rootDir,
1617
+ workspaceDir: runtime.workspaceDir,
1618
+ binDir: runtime.binDir,
1619
+ homeDir: runtime.homeDir,
1620
+ tmpDir: runtime.tmpDir,
1621
+ cacheDir: runtime.cacheDir,
1622
+ stateDir: runtime.stateDir,
1623
+ sessionDir: runtime.sessionDir,
1624
+ claudeHomeDir: runtime.claudeHomeDir
1625
+ },
1626
+ command: providerCommand
1627
+ })).command;
1628
+ if (isPiRpcArgs(providerArgs)) {
1629
+ const prompt = await readProcessStdin();
1630
+ const runId = process.env.RIG_SERVER_RUN_ID?.trim();
1631
+ exitCode = await runPiRpcProviderFallback({
1632
+ command,
1633
+ cwd: runtime.workspaceDir,
1634
+ env,
1635
+ prompt,
1636
+ ...runId ? { runId } : {},
1637
+ sessionName: runId ? `Rig ${runId}` : `Rig ${runtime.taskId}`
1638
+ });
1639
+ } else {
1640
+ const proc = Bun.spawn(command, {
1641
+ cwd: runtime.workspaceDir,
1642
+ env,
1643
+ stdin: "inherit",
1644
+ stdout: "inherit",
1645
+ stderr: "inherit"
1646
+ });
1647
+ exitCode = await proc.exited;
1648
+ }
1649
+ if (snapshotSidecar) {
1650
+ snapshotFinalizeResult = await finalizeRuntimeSnapshot(snapshotSidecar, providerCommand, exitCode, {
1651
+ runtimeId: runtime.id,
1652
+ taskId
1653
+ });
1654
+ }
1655
+ } catch (error) {
1656
+ if (snapshotSidecar) {
1657
+ await snapshotSidecar.cancel();
1658
+ }
1659
+ throw error;
1660
+ }
1661
+ const serverManagedRun = Boolean(process.env.RIG_SERVER_RUN_ID?.trim());
1662
+ const taskClosed = await isTaskClosed(projectRoot, taskId);
1663
+ const finalExitCode = resolveFinalProviderExitCode({
1664
+ providerExitCode: exitCode,
1665
+ taskClosed,
1666
+ serverManagedRun
1667
+ });
1668
+ const snapshotMissing = !snapshotFinalizeResult.ok;
1669
+ const handoffRequired = exitCode !== 0 || snapshotMissing || !taskClosed && !serverManagedRun;
1670
+ emitWrapperEvent("provider.completed", {
1671
+ provider,
1672
+ runtimeId: runtime.id,
1673
+ taskId,
1674
+ exitCode: finalExitCode,
1675
+ providerExitCode: exitCode,
1676
+ taskClosed,
1677
+ serverManagedRun,
1678
+ handoffRequired,
1679
+ snapshotMissing,
1680
+ ...!snapshotFinalizeResult.ok ? { snapshotFinalizeError: snapshotFinalizeResult.error } : {}
1681
+ });
1682
+ if (handoffRequired) {
1683
+ recordRuntimeHandoff(projectRoot, runtime, taskId, exitCode, {
1684
+ snapshotMissing,
1685
+ snapshotFinalizeError: snapshotFinalizeResult.ok ? null : snapshotFinalizeResult.error
1686
+ });
1687
+ if (!snapshotFinalizeResult.ok) {
1688
+ await recordSnapshotMissingTaskSourceEvidence(projectRoot, taskId, runtime, snapshotFinalizeResult.error);
1689
+ }
1690
+ }
1691
+ return finalExitCode;
1692
+ }
1693
+ function parseJsonRecord(line) {
1694
+ try {
1695
+ const parsed = JSON.parse(line);
1696
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
1697
+ } catch {
1698
+ return null;
1699
+ }
1700
+ }
1701
+ async function readProcessStdin() {
1702
+ if (process.stdin.isTTY)
1703
+ return "";
1704
+ return await new Promise((resolveRead) => {
1705
+ let data = "";
1706
+ process.stdin.setEncoding("utf8");
1707
+ process.stdin.on("data", (chunk) => {
1708
+ data += String(chunk);
1709
+ });
1710
+ process.stdin.on("end", () => resolveRead(data));
1711
+ process.stdin.resume();
1712
+ });
1713
+ }
1714
+ async function pumpReadableLines(stream, onLine) {
1715
+ if (!stream)
1716
+ return;
1717
+ const reader = stream.getReader();
1718
+ const decoder = new TextDecoder;
1719
+ let buffer = "";
1720
+ try {
1721
+ while (true) {
1722
+ const { done, value } = await reader.read();
1723
+ if (done)
1724
+ break;
1725
+ buffer += decoder.decode(value, { stream: true });
1726
+ const parts = buffer.split(/\r?\n/);
1727
+ buffer = parts.pop() ?? "";
1728
+ for (const part of parts)
1729
+ onLine(part);
1730
+ }
1731
+ buffer += decoder.decode();
1732
+ if (buffer)
1733
+ onLine(buffer);
1734
+ } finally {
1735
+ reader.releaseLock();
1736
+ }
1737
+ }
1738
+ function isBlockingPiRpcUiRequest(record) {
1739
+ if (record.type !== "extension_ui_request")
1740
+ return false;
1741
+ return record.method === "select" || record.method === "confirm" || record.method === "input" || record.method === "editor";
1742
+ }
1743
+ function writeRpcCommand(stdin, command) {
1744
+ stdin.write(`${JSON.stringify(command)}
1745
+ `);
1746
+ }
1747
+ function joinUrl(baseUrl, pathname) {
1748
+ return `${baseUrl.replace(/\/+$/, "")}${pathname.startsWith("/") ? pathname : `/${pathname}`}`;
1749
+ }
1750
+ async function readQueuedSteeringFromServer(input) {
1751
+ if (!input.serverUrl || !input.runId)
1752
+ return [];
1753
+ const headers = {};
1754
+ if (input.authToken)
1755
+ headers.authorization = `Bearer ${input.authToken}`;
1756
+ if (input.projectRoot)
1757
+ headers["x-rig-project-root"] = input.projectRoot;
1758
+ const response = await fetch(joinUrl(input.serverUrl, `/api/runs/${encodeURIComponent(input.runId)}/steering?ack=1`), { headers });
1759
+ if (!response.ok) {
1760
+ throw new Error(`steering read rejected (${response.status}) at ${input.serverUrl}`);
1761
+ }
1762
+ const payload = await response.json().catch(() => null);
1763
+ const messages = payload && typeof payload === "object" && !Array.isArray(payload) ? payload.messages : null;
1764
+ return Array.isArray(messages) ? messages.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
1765
+ }
1766
+ function steeringMessageText(entry) {
1767
+ const message = typeof entry.message === "string" ? entry.message.trim() : "";
1768
+ return message || null;
1769
+ }
1770
+ function isPiRpcArgs(args) {
1771
+ return cliOptionValue(args, "--mode") === "rpc";
1772
+ }
1773
+ async function runPiRpcProviderFallback(input) {
1774
+ const stdout = input.stdout ?? process.stdout;
1775
+ const stderr = input.stderr ?? process.stderr;
1776
+ const proc = Bun.spawn(input.command, {
1777
+ cwd: input.cwd,
1778
+ env: input.env,
1779
+ stdin: "pipe",
1780
+ stdout: "pipe",
1781
+ stderr: "pipe"
1782
+ });
1783
+ let sawAgentEnd = false;
1784
+ let promptError = null;
1785
+ let stdinOpen = true;
1786
+ let steeringPollStopped = false;
1787
+ const closeStdin = () => {
1788
+ if (!stdinOpen)
1789
+ return;
1790
+ stdinOpen = false;
1791
+ try {
1792
+ steeringPollStopped = true;
1793
+ proc.stdin.end();
1794
+ } catch {}
1795
+ };
1796
+ const send = (command) => {
1797
+ if (!stdinOpen)
1798
+ return;
1799
+ try {
1800
+ writeRpcCommand(proc.stdin, command);
1801
+ } catch (error) {
1802
+ promptError ??= error instanceof Error ? error.message : String(error);
1803
+ }
1804
+ };
1805
+ const forwardSigterm = () => {
1806
+ try {
1807
+ proc.kill("SIGTERM");
1808
+ } catch {}
1809
+ };
1810
+ process.once("SIGTERM", forwardSigterm);
1811
+ const pollSteering = async () => {
1812
+ const serverUrl = input.env.RIG_SERVER_URL || input.env.RIG_SERVER_BASE_URL;
1813
+ const authToken = input.env.RIG_AUTH_TOKEN || input.env.RIG_SERVER_AUTH_TOKEN;
1814
+ const projectRoot = input.env.PROJECT_RIG_ROOT || input.env.RIG_HOST_PROJECT_ROOT || process.env.PROJECT_RIG_ROOT;
1815
+ let lastReportedPollError = null;
1816
+ while (!steeringPollStopped && stdinOpen) {
1817
+ try {
1818
+ const messages = await readQueuedSteeringFromServer({
1819
+ ...serverUrl ? { serverUrl } : {},
1820
+ ...authToken ? { authToken } : {},
1821
+ ...input.runId ? { runId: input.runId } : {},
1822
+ ...projectRoot ? { projectRoot } : {}
1823
+ });
1824
+ lastReportedPollError = null;
1825
+ for (const message of messages) {
1826
+ const text = steeringMessageText(message);
1827
+ if (!text || !stdinOpen)
1828
+ continue;
1829
+ send({
1830
+ id: typeof message.id === "string" ? `rig_steer_${message.id}` : `rig_steer_${Date.now()}`,
1831
+ type: "prompt",
1832
+ message: text,
1833
+ streamingBehavior: "steer"
1834
+ });
1835
+ emitWrapperEvent("pi.rpc.steering.delivered", {
1836
+ runId: input.runId ?? null,
1837
+ steeringId: typeof message.id === "string" ? message.id : null,
1838
+ actor: typeof message.actor === "string" ? message.actor : "operator",
1839
+ message: text
1840
+ });
1841
+ }
1842
+ } catch (error) {
1843
+ const message = error instanceof Error ? error.message : String(error);
1844
+ if (message !== lastReportedPollError) {
1845
+ lastReportedPollError = message;
1846
+ emitWrapperEvent("pi.rpc.steering.poll.failed", {
1847
+ runId: input.runId ?? null,
1848
+ error: message
1849
+ });
1850
+ }
1851
+ }
1852
+ await sleep(1000);
1853
+ }
1854
+ };
1855
+ const stdoutPump = pumpReadableLines(proc.stdout, (line) => {
1856
+ stdout.write(`${line}
1857
+ `);
1858
+ const record = parseJsonRecord(line.trim());
1859
+ if (!record)
1860
+ return;
1861
+ if (record.type === "agent_end") {
1862
+ sawAgentEnd = true;
1863
+ closeStdin();
1864
+ return;
1865
+ }
1866
+ if (record.type === "response" && record.command === "prompt" && record.success === false) {
1867
+ promptError = typeof record.error === "string" ? record.error : "Pi RPC prompt failed.";
1868
+ closeStdin();
1869
+ return;
1870
+ }
1871
+ if (isBlockingPiRpcUiRequest(record)) {
1872
+ const id = typeof record.id === "string" ? record.id : "";
1873
+ if (id) {
1874
+ send({ type: "extension_ui_response", id, cancelled: true });
1875
+ emitWrapperEvent("pi.rpc.extension_ui.cancelled", {
1876
+ id,
1877
+ method: record.method,
1878
+ reason: "noninteractive Rig worker RPC session"
1879
+ });
1880
+ }
1881
+ }
1882
+ });
1883
+ const stderrPump = pumpReadableLines(proc.stderr, (line) => {
1884
+ stderr.write(`${line}
1885
+ `);
1886
+ });
1887
+ if (input.sessionName?.trim()) {
1888
+ send({ id: "rig_set_session_name", type: "set_session_name", name: input.sessionName.trim() });
1889
+ }
1890
+ const steeringPollPromise = pollSteering();
1891
+ if (input.prompt.trim()) {
1892
+ send({ id: "rig_initial_prompt", type: "prompt", message: input.prompt });
1893
+ emitWrapperEvent("pi.rpc.prompt.sent", {
1894
+ runId: input.runId ?? null,
1895
+ kind: "initial",
1896
+ bytes: Buffer.byteLength(input.prompt)
1897
+ });
1898
+ } else {
1899
+ closeStdin();
1900
+ }
1901
+ const exitCode = await proc.exited;
1902
+ process.off("SIGTERM", forwardSigterm);
1903
+ steeringPollStopped = true;
1904
+ await Promise.all([stdoutPump, stderrPump, steeringPollPromise]);
1905
+ if (promptError) {
1906
+ stderr.write(`[rig-agent] Pi RPC prompt failed: ${promptError}
1907
+ `);
1908
+ return exitCode === 0 ? 1 : exitCode;
1909
+ }
1910
+ if (input.prompt.trim() && !sawAgentEnd && exitCode === 0) {
1911
+ stderr.write(`[rig-agent] Pi RPC exited before emitting agent_end.
1912
+ `);
1913
+ return 1;
1914
+ }
1915
+ return exitCode;
1916
+ }
1917
+ function resolveFinalProviderExitCode(input) {
1918
+ if (input.providerExitCode !== 0) {
1919
+ return input.providerExitCode;
1920
+ }
1921
+ if (input.taskClosed || input.serverManagedRun) {
1922
+ return 0;
1923
+ }
1924
+ return 0;
1925
+ }
1926
+ function shouldBypassProviderSandboxOnPlatform(provider, platform) {
1927
+ if (platform !== "darwin") {
1928
+ return false;
1929
+ }
1930
+ return provider === "pi";
1931
+ }
1932
+ function resolveOuterSandboxBypass(provider, platform, explicitSandboxSetting) {
1933
+ if (explicitSandboxSetting === "enforce")
1934
+ return false;
1935
+ return shouldBypassProviderSandboxOnPlatform(provider, platform);
1936
+ }
1937
+ function buildProviderArgs(_provider, _runtime, argv) {
1938
+ const piArgs = argv.filter((arg) => arg !== "__rig_pi_session_daemon__");
1939
+ const piProvider = cliOptionValue(piArgs, "--provider") || process.env.RIG_PI_PROVIDER?.trim() || "openai-codex";
1940
+ if (!hasCliOption(piArgs, "--provider")) {
1941
+ piArgs.unshift(piProvider);
1942
+ piArgs.unshift("--provider");
1943
+ }
1944
+ const model = cliOptionValue(piArgs, "--model") || process.env.RIG_PI_MODEL?.trim() || "gpt-5.5";
1945
+ if (hasCliOption(piArgs, "--model")) {
1946
+ rewriteCliOptionValue(piArgs, "--model", normalizePiModelForProvider(model, piProvider));
1947
+ } else {
1948
+ piArgs.unshift(normalizePiModelForProvider(model, piProvider));
1949
+ piArgs.unshift("--model");
1950
+ }
1951
+ if (!hasCliOption(piArgs, "--mode")) {
1952
+ piArgs.push("--mode", process.env.RIG_PI_TRANSPORT?.trim() === "print" ? "json" : "rpc");
1953
+ if (process.env.RIG_PI_TRANSPORT?.trim() === "print" && !hasCliOption(piArgs, "--print")) {
1954
+ piArgs.push("--print");
1955
+ }
1956
+ }
1957
+ return piArgs;
1958
+ }
1959
+ function readStringList2(candidate) {
1960
+ return Array.isArray(candidate) ? candidate.filter((entry) => typeof entry === "string") : [];
1961
+ }
1962
+ function firstStringList2(...candidates) {
1963
+ for (const candidate of candidates) {
1964
+ const values = readStringList2(candidate);
1965
+ if (values.length > 0)
1966
+ return values;
1967
+ }
1968
+ return [];
1969
+ }
1970
+ function taskConfigEntryToRecord2(id, entry, source) {
1971
+ const record = entry;
1972
+ return {
1973
+ id,
1974
+ deps: firstStringList2(record.deps, record.dependencies, record.validation_deps, record.validationDeps),
1975
+ status: typeof entry.status === "string" && entry.status.trim().length > 0 ? entry.status : "open",
1976
+ source,
1977
+ ...typeof entry.title === "string" ? { title: entry.title } : {},
1978
+ ...typeof entry.description === "string" ? { description: entry.description } : {},
1979
+ ...typeof entry.acceptance_criteria === "string" ? { acceptanceCriteria: entry.acceptance_criteria } : {},
1980
+ ...typeof record.acceptanceCriteria === "string" ? { acceptanceCriteria: record.acceptanceCriteria } : {},
1981
+ ...Array.isArray(entry.scope) ? { scope: entry.scope } : {},
1982
+ ...Array.isArray(entry.validation) ? { validation: entry.validation } : {},
1983
+ ...typeof entry.role === "string" ? { role: entry.role } : {}
1984
+ };
1985
+ }
1986
+ async function taskRecordReaderFromState(projectRoot) {
1987
+ const store = await resolveTaskStateStore(projectRoot);
1988
+ return {
1989
+ async listTasks() {
1990
+ const sourceRecords = Object.entries(store.readSourceTaskConfig(projectRoot)).map(([id, entry]) => taskConfigEntryToRecord2(id, entry, "source-task-config"));
1991
+ const sourceIds = new Set(sourceRecords.map((task) => task.id));
1992
+ const legacyRecords = Object.entries(store.readTaskConfig(projectRoot)).filter(([id]) => !sourceIds.has(id)).map(([id, entry]) => taskConfigEntryToRecord2(id, entry, "legacy-task-config"));
1993
+ return [...sourceRecords, ...legacyRecords];
1994
+ },
1995
+ async getTask(id) {
1996
+ const sourceEntry = store.readSourceTaskConfig(projectRoot)[id];
1997
+ if (sourceEntry)
1998
+ return taskConfigEntryToRecord2(id, sourceEntry, "source-task-config");
1999
+ const legacyEntry = store.readTaskConfig(projectRoot)[id];
2000
+ return legacyEntry ? taskConfigEntryToRecord2(id, legacyEntry, "legacy-task-config") : null;
2001
+ }
2002
+ };
2003
+ }
2004
+ function resolveProvider() {
2005
+ return "pi";
2006
+ }
2007
+ function hasCliOption(argv, option) {
2008
+ return argv.some((arg) => arg === option || arg.startsWith(`${option}=`));
2009
+ }
2010
+ function cliOptionValue(argv, option) {
2011
+ for (let index = 0;index < argv.length; index += 1) {
2012
+ const arg = argv[index];
2013
+ if (arg === option) {
2014
+ const next = argv[index + 1];
2015
+ return next && !next.startsWith("--") ? next : undefined;
2016
+ }
2017
+ if (arg?.startsWith(`${option}=`)) {
2018
+ return arg.slice(option.length + 1);
2019
+ }
2020
+ }
2021
+ return;
2022
+ }
2023
+ function rewriteCliOptionValue(argv, option, value) {
2024
+ for (let index = 0;index < argv.length; index += 1) {
2025
+ const arg = argv[index];
2026
+ if (arg === option && argv[index + 1] && !argv[index + 1].startsWith("--")) {
2027
+ argv[index + 1] = value;
2028
+ return;
2029
+ }
2030
+ if (arg?.startsWith(`${option}=`)) {
2031
+ argv[index] = `${option}=${value}`;
2032
+ return;
2033
+ }
2034
+ }
2035
+ }
2036
+ function normalizePiModelForProvider(model, provider) {
2037
+ if (provider === "openrouter" && model === "openai-codex/gpt-5.5") {
2038
+ return "openai/gpt-5.5";
2039
+ }
2040
+ return model;
2041
+ }
2042
+ function resolveFromShellPath(binary) {
2043
+ const resolved = Bun.spawnSync(["sh", "-lc", `command -v ${binary}`], {
2044
+ stdout: "pipe",
2045
+ stderr: "ignore",
2046
+ stdin: "ignore",
2047
+ env: process.env
2048
+ });
2049
+ if (resolved.exitCode !== 0)
2050
+ return null;
2051
+ const path = resolved.stdout.toString().trim().split(/\r?\n/)[0]?.trim();
2052
+ return path || null;
2053
+ }
2054
+ function resolveBundledPiBinary() {
2055
+ try {
2056
+ const packageJson = requireFromRuntime.resolve("@oh-my-pi/pi-coding-agent/package.json");
2057
+ const binaryPath = resolve5(packageJson, "..", "dist", "cli.js");
2058
+ return existsSync5(binaryPath) ? binaryPath : null;
2059
+ } catch {
2060
+ return null;
2061
+ }
2062
+ }
2063
+ function providerBinary(_provider) {
2064
+ return process.env.RIG_PI_BINARY?.trim() || resolveBundledPiBinary() || resolveFromShellPath("pi") || Bun.which("pi") || "pi";
2065
+ }
2066
+ function emitWrapperEvent(type, payload) {
2067
+ console.log(`__RIG_WRAPPER_EVENT__${JSON.stringify({ type, payload, at: new Date().toISOString() })}`);
2068
+ }
2069
+ function sleep(ms) {
2070
+ return new Promise((resolveSleep) => setTimeout(resolveSleep, ms));
2071
+ }
2072
+ async function waitForDirtyBaselineReady(runtime, taskId) {
2073
+ const readyFile = process.env.RIG_DIRTY_BASELINE_READY_FILE?.trim();
2074
+ if (process.env.RIG_BASELINE_MODE !== "dirty-snapshot" || !readyFile)
2075
+ return;
2076
+ const timeoutMs = Number.parseInt(process.env.RIG_DIRTY_BASELINE_TIMEOUT_MS ?? "30000", 10);
2077
+ const deadline = Date.now() + (Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : 30000);
2078
+ emitWrapperEvent("runtime.baseline.waiting", {
2079
+ runtimeId: runtime.id,
2080
+ taskId,
2081
+ workspaceDir: runtime.workspaceDir,
2082
+ readyFile
2083
+ });
2084
+ while (!existsSync5(readyFile)) {
2085
+ if (Date.now() >= deadline) {
2086
+ throw new Error(`Timed out waiting for dirty baseline ready file: ${readyFile}`);
2087
+ }
2088
+ await sleep(50);
2089
+ }
2090
+ emitWrapperEvent("runtime.baseline.completed", {
2091
+ runtimeId: runtime.id,
2092
+ taskId,
2093
+ workspaceDir: runtime.workspaceDir,
2094
+ readyFile
2095
+ });
2096
+ }
2097
+ function inferTaskIdFromRuntimePath(path) {
2098
+ if (!path)
2099
+ return "";
2100
+ const match = path.match(/\/\.rig\/runtime\/agents\/task-([^/]+)\/worktree(?:\/|$)/) || path.match(/\/\.worktrees\/([^/]+)(?:\/|$)/);
2101
+ return match?.[1] || "";
2102
+ }
2103
+ function taskIdFromProviderRuntimeEnv() {
2104
+ const explicit = process.env.RIG_TASK_ID?.trim();
2105
+ if (explicit)
2106
+ return explicit;
2107
+ const runtimeId = process.env.RIG_TASK_RUNTIME_ID?.trim();
2108
+ if (runtimeId?.startsWith("task-") && runtimeId.length > "task-".length) {
2109
+ return runtimeId.slice("task-".length);
2110
+ }
2111
+ return inferTaskIdFromRuntimePath(process.env.RIG_TASK_WORKSPACE?.trim()) || inferTaskIdFromRuntimePath(process.cwd());
2112
+ }
2113
+ async function resolveTaskId(projectRoot) {
2114
+ const fromRuntime = taskIdFromProviderRuntimeEnv();
2115
+ if (fromRuntime) {
2116
+ return fromRuntime;
2117
+ }
2118
+ const fromState = (await resolveTaskStateStore(projectRoot)).readCurrentTaskId(projectRoot) ?? "";
2119
+ return fromState;
2120
+ }
2121
+ async function isTaskClosed(projectRoot, taskId) {
2122
+ return (await resolveTaskTerminalState(projectRoot)).isTaskTerminal({ projectRoot, taskId });
2123
+ }
2124
+ async function recordSnapshotMissingTaskSourceEvidence(projectRoot, taskId, runtime, snapshotFinalizeError) {
2125
+ try {
2126
+ const reflection = await resolveTaskSourceReflection(projectRoot);
2127
+ if (!reflection) {
2128
+ throw new Error("task source reflection capability unavailable");
2129
+ }
2130
+ const result = await reflection.reflectTaskSourceStatus({
2131
+ projectRoot,
2132
+ taskId,
2133
+ runId: process.env.RIG_SERVER_RUN_ID || "(unknown)",
2134
+ commentStatus: "snapshot-missing",
2135
+ summary: "Rig runtime completed, but the after-snapshot finalize failed. Closeout evidence is degraded until the runtime workspace is inspected directly.",
2136
+ runtimeWorkspace: runtime.workspaceDir,
2137
+ logsDir: runtime.logsDir,
2138
+ sessionDir: runtime.sessionDir,
2139
+ errorText: snapshotFinalizeError
2140
+ });
2141
+ if (result?.updated) {
2142
+ return;
2143
+ }
2144
+ throw new Error(result ? "no source-aware task source is configured" : "task source update capability unavailable");
2145
+ } catch (error) {
2146
+ console.error(`[rig-agent] Failed to record snapshot-missing evidence for ${taskId}: ${error instanceof Error ? error.message : String(error)}`);
2147
+ }
2148
+ }
2149
+ function resolveRuntimeHandoffPath(hostProjectRoot, taskId, timestampMs = Date.now()) {
2150
+ const handoffDir = resolve5(hostProjectRoot, ".rig/runtime/handoffs");
2151
+ const safeTaskId = safePathSegment(taskId, { fallback: "task", maxLength: 96 });
2152
+ return assertPathInsideRoot(handoffDir, resolve5(handoffDir, `${safeTaskId}-${timestampMs}.json`), "runtime handoff path");
2153
+ }
2154
+ function recordRuntimeHandoff(hostProjectRoot, runtime, taskId, exitCode, options = {}) {
2155
+ const handoffDir = resolve5(hostProjectRoot, ".rig/runtime/handoffs");
2156
+ mkdirSync3(handoffDir, { recursive: true });
2157
+ const handoffPath = resolveRuntimeHandoffPath(hostProjectRoot, taskId);
2158
+ const snapshotMissing = options.snapshotMissing === true;
2159
+ const handoff = {
2160
+ taskId,
2161
+ runtimeId: runtime.id,
2162
+ runtimeMode: runtime.mode,
2163
+ workspaceDir: runtime.workspaceDir,
2164
+ logsDir: runtime.logsDir,
2165
+ sessionDir: runtime.sessionDir,
2166
+ exitCode,
2167
+ degraded: snapshotMissing,
2168
+ snapshotMissing,
2169
+ snapshotFinalizeError: options.snapshotFinalizeError ?? null,
2170
+ recordedAt: new Date().toISOString(),
2171
+ message: snapshotMissing ? "Runtime completed but the after-snapshot finalize failed; closeout evidence is degraded until the runtime workspace is inspected directly." : "Completion verification did not finish in this run. Open or refresh the PR from the runtime workspace for verifier review, or rerun completion verification once the workspace is ready.",
2172
+ nextSteps: snapshotMissing ? [
2173
+ `cd ${runtime.workspaceDir}`,
2174
+ "inspect the runtime workspace directly before relying on closeout evidence",
2175
+ `rig-agent git status --task ${taskId}`
2176
+ ] : [
2177
+ `cd ${runtime.workspaceDir}`,
2178
+ `rig-agent git status --task ${taskId}`,
2179
+ `rig-agent completion-verification`,
2180
+ `rig-agent git open-pr --task ${taskId}`
2181
+ ]
2182
+ };
2183
+ writeFileSync3(handoffPath, `${JSON.stringify(handoff, null, 2)}
2184
+ `, "utf-8");
2185
+ if (snapshotMissing) {
2186
+ console.log(`[rig-agent] Runtime after-snapshot missing for ${taskId}; degraded handoff saved: ${handoffPath}`);
2187
+ console.log(`[rig-agent] Inspect runtime workspace before relying on closeout evidence: ${runtime.workspaceDir}`);
2188
+ } else {
2189
+ console.log(`[rig-agent] Completion verification paused for ${taskId}.`);
2190
+ console.log(`[rig-agent] Runtime handoff saved: ${handoffPath}`);
2191
+ console.log(`[rig-agent] Review and open PR from runtime workspace: ${runtime.workspaceDir}`);
2192
+ }
2193
+ }
2194
+ async function printTaskContext(projectRoot, taskId) {
2195
+ const context = await readTaskContextFromState(projectRoot, taskId);
2196
+ const description = asNonEmptyString(context.description);
2197
+ const acceptanceCriteria = firstNonEmpty(context.acceptanceCriteria, context.acceptance_criteria);
2198
+ if (context.title) {
2199
+ console.log(`[rig-agent] Task ${taskId}: ${context.title}`);
2200
+ } else {
2201
+ console.log(`[rig-agent] Task ${taskId}`);
2202
+ }
2203
+ if (description) {
2204
+ console.log("[rig-agent] Description:");
2205
+ for (const line of description.split(/\r?\n/)) {
2206
+ console.log(`[rig-agent] ${line}`);
2207
+ }
2208
+ } else {
2209
+ console.log("[rig-agent] Description: (not set in task-state/source config)");
2210
+ }
2211
+ if (acceptanceCriteria) {
2212
+ console.log("[rig-agent] Acceptance Criteria:");
2213
+ for (const line of acceptanceCriteria.split(/\r?\n/)) {
2214
+ console.log(`[rig-agent] ${line}`);
2215
+ }
2216
+ }
2217
+ }
2218
+ async function readTaskContextFromState(projectRoot, taskId) {
2219
+ const store = await resolveTaskStateStore(projectRoot);
2220
+ const entry = store.readSourceTaskConfig(projectRoot)[taskId] ?? store.readTaskConfig(projectRoot)[taskId] ?? null;
2221
+ if (!entry)
2222
+ return {};
2223
+ const record = entry;
2224
+ return {
2225
+ title: asNonEmptyString(record.title),
2226
+ description: asNonEmptyString(record.description),
2227
+ acceptance_criteria: asNonEmptyString(record.acceptance_criteria),
2228
+ acceptanceCriteria: asNonEmptyString(record.acceptanceCriteria)
2229
+ };
2230
+ }
2231
+ function asNonEmptyString(value) {
2232
+ return typeof value === "string" ? value.trim() : "";
2233
+ }
2234
+ function firstNonEmpty(...values) {
2235
+ for (const value of values) {
2236
+ if (typeof value === "string" && value.trim()) {
2237
+ return value.trim();
2238
+ }
2239
+ }
2240
+ return "";
2241
+ }
2242
+ var TaskStateStoreCap2, taskStateStoreByRoot, TaskSourceReflectionCap, taskSourceReflectionByRoot, TaskTerminalStateCap, taskTerminalStateByRoot, requireFromRuntime, runPiRpcProvider;
2243
+ var init_agent_wrapper = __esm(() => {
2244
+ init_runtime_snapshot_config();
2245
+ TaskStateStoreCap2 = defineCapability5(TASK_STATE_STORE2);
2246
+ taskStateStoreByRoot = new Map;
2247
+ TaskSourceReflectionCap = defineCapability5(TASK_SOURCE_REFLECTION);
2248
+ taskSourceReflectionByRoot = new Map;
2249
+ TaskTerminalStateCap = defineCapability5(TASK_TERMINAL_STATE);
2250
+ taskTerminalStateByRoot = new Map;
2251
+ requireFromRuntime = createRequire(import.meta.url);
2252
+ runPiRpcProvider = runPiRpcProviderFallback;
2253
+ if (false) {}
2254
+ });
2255
+
2256
+ // packages/harness-plugin/src/tooling/browser-tool-entrypoint.ts
2257
+ var exports_browser_tool_entrypoint = {};
2258
+ import { existsSync as existsSync6, rmSync } from "fs";
2259
+ import { basename as basename2, dirname as dirname2, resolve as resolve6 } from "path";
2260
+ import { loadRuntimeContext as loadRuntimeContext2 } from "@rig/core/runtime-context";
2261
+ function currentCommand() {
2262
+ return basename2(process.argv[1] || "");
2263
+ }
2264
+ function runtimeContextPath() {
2265
+ const explicit = process.env.RIG_RUNTIME_CONTEXT_FILE?.trim();
2266
+ if (explicit) {
2267
+ return explicit;
2268
+ }
2269
+ return resolve6(dirname2(resolve6(process.argv[1] || "")), "..", "runtime-context.json");
2270
+ }
2271
+ function loadBrowserContext() {
2272
+ const contextPath = runtimeContextPath();
2273
+ if (!existsSync6(contextPath)) {
2274
+ throw new Error(`Runtime context file not found for ${currentCommand()}: ${contextPath}`);
2275
+ }
2276
+ const runtimeContext = loadRuntimeContext2(contextPath);
2277
+ if (!runtimeContext.browser?.required) {
2278
+ throw new Error(`No browser contract is configured for ${runtimeContext.taskId}.`);
2279
+ }
2280
+ if (!runtimeContext.hostProjectRoot) {
2281
+ throw new Error(`Runtime browser command ${currentCommand()} requires hostProjectRoot in runtime context.`);
2282
+ }
2283
+ return {
2284
+ browser: runtimeContext.browser,
2285
+ hostProjectRoot: runtimeContext.hostProjectRoot
2286
+ };
2287
+ }
2288
+ async function runConfiguredCommand(command, browser, hostProjectRoot) {
2289
+ if (!command) {
2290
+ throw new Error(`No backing command is configured for ${currentCommand()}.`);
2291
+ }
2292
+ const attachUrl = new URL(browser.effectiveAttachUrl);
2293
+ const child = Bun.spawn({
2294
+ cmd: ["/bin/bash", "-lc", command],
2295
+ cwd: hostProjectRoot,
2296
+ stdin: "inherit",
2297
+ stdout: "inherit",
2298
+ stderr: "inherit",
2299
+ env: {
2300
+ ...process.env,
2301
+ RIG_STATE_DIR: browser.stateDir,
2302
+ T3CODE_STATE_DIR: browser.stateDir,
2303
+ RIG_BROWSER_PROFILE: browser.effectiveProfile,
2304
+ RIG_BROWSER_REMOTE_DEBUGGING_PORT: attachUrl.port,
2305
+ RIG_BROWSER_ATTACH_URL: browser.effectiveAttachUrl
2306
+ }
2307
+ });
2308
+ return await child.exited;
2309
+ }
2310
+ function printAttachInfo(browser, hostProjectRoot) {
2311
+ const payload = {
2312
+ preset: browser.preset,
2313
+ mode: browser.mode,
2314
+ stateDir: browser.stateDir,
2315
+ hostProjectRoot,
2316
+ defaultProfile: browser.defaultProfile,
2317
+ effectiveProfile: browser.effectiveProfile,
2318
+ defaultAttachUrl: browser.defaultAttachUrl,
2319
+ effectiveAttachUrl: browser.effectiveAttachUrl,
2320
+ launchHelper: browser.launchHelper,
2321
+ checkHelper: browser.checkHelper,
2322
+ attachInfoHelper: browser.attachInfoHelper,
2323
+ e2eHelper: browser.e2eHelper,
2324
+ resetProfileHelper: browser.resetProfileHelper,
2325
+ devCommand: browser.devCommand,
2326
+ launchCommand: browser.launchCommand,
2327
+ checkCommand: browser.checkCommand,
2328
+ e2eCommand: browser.e2eCommand
2329
+ };
2330
+ if (process.argv.includes("--json")) {
2331
+ console.log(JSON.stringify(payload, null, 2));
2332
+ return;
2333
+ }
2334
+ console.log("Rig Browser");
2335
+ console.log(` Preset: ${browser.preset}`);
2336
+ console.log(` Mode: ${browser.mode}`);
2337
+ console.log(` State dir: ${browser.stateDir}`);
2338
+ console.log(` Default profile: ${browser.defaultProfile}`);
2339
+ console.log(` Effective profile: ${browser.effectiveProfile}`);
2340
+ console.log(` Default attach URL: ${browser.defaultAttachUrl}`);
2341
+ console.log(` Effective attach URL: ${browser.effectiveAttachUrl}`);
2342
+ console.log(` Launch helper: ${browser.launchHelper}${browser.devCommand ? " [--dev]" : ""}`);
2343
+ console.log(` Check helper: ${browser.checkHelper}`);
2344
+ console.log(` E2E helper: ${browser.e2eHelper}`);
2345
+ console.log(` Reset helper: ${browser.resetProfileHelper}`);
2346
+ }
2347
+ function resetProfile(browser) {
2348
+ const profileRoot = resolve6(browser.stateDir, "browser", "profiles", browser.effectiveProfile);
2349
+ rmSync(profileRoot, { recursive: true, force: true });
2350
+ console.log(`Removed Rig Browser profile: ${profileRoot}`);
2351
+ }
2352
+ async function main2() {
2353
+ const { browser, hostProjectRoot } = loadBrowserContext();
2354
+ const command = currentCommand();
2355
+ if (command === browser.attachInfoHelper) {
2356
+ printAttachInfo(browser, hostProjectRoot);
2357
+ return;
2358
+ }
2359
+ if (command === browser.resetProfileHelper) {
2360
+ resetProfile(browser);
2361
+ return;
2362
+ }
2363
+ if (command === browser.launchHelper) {
2364
+ const launchCommand = process.argv.includes("--dev") ? browser.devCommand : browser.launchCommand;
2365
+ process.exit(await runConfiguredCommand(launchCommand, browser, hostProjectRoot));
2366
+ }
2367
+ if (command === browser.checkHelper) {
2368
+ process.exit(await runConfiguredCommand(browser.checkCommand, browser, hostProjectRoot));
2369
+ }
2370
+ if (command === browser.e2eHelper) {
2371
+ process.exit(await runConfiguredCommand(browser.e2eCommand ?? browser.checkCommand, browser, hostProjectRoot));
2372
+ }
2373
+ throw new Error(`Unknown Rig Browser helper: ${command}`);
2374
+ }
2375
+ var init_browser_tool_entrypoint = __esm(() => {
2376
+ main2().catch((error) => {
2377
+ console.error(error instanceof Error ? error.message : String(error));
2378
+ process.exit(1);
2379
+ });
2380
+ });
2381
+
2382
+ // packages/harness-plugin/src/tooling/claude-router.ts
2383
+ var exports_claude_router = {};
2384
+ __export(exports_claude_router, {
2385
+ writeClaudeRuntimeToolRouterConfig: () => writeClaudeRuntimeToolRouterConfig,
2386
+ runClaudeToolRouterServer: () => runClaudeToolRouterServer,
2387
+ invokeRuntimeTool: () => invokeRuntimeTool,
2388
+ codexRuntimeToolCliArgs: () => codexRuntimeToolCliArgs,
2389
+ claudeRuntimeToolCliArgs: () => claudeRuntimeToolCliArgs,
2390
+ CLAUDE_ROUTER_TOOL_DEFINITIONS: () => CLAUDE_ROUTER_TOOL_DEFINITIONS,
2391
+ CLAUDE_ROUTER_SERVER_NAME: () => CLAUDE_ROUTER_SERVER_NAME,
2392
+ CLAUDE_DISABLED_FILE_TOOLS: () => CLAUDE_DISABLED_FILE_TOOLS
2393
+ });
2394
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, statSync, writeFileSync as writeFileSync4 } from "fs";
2395
+ import { resolve as resolve7 } from "path";
2396
+ import { createInterface } from "readline";
2397
+ function claudeRuntimeToolCliArgs(configPath) {
2398
+ return [
2399
+ "--disallowedTools",
2400
+ CLAUDE_DISABLED_FILE_TOOLS.join(","),
2401
+ "--mcp-config",
2402
+ configPath
2403
+ ];
2404
+ }
2405
+ function buildRuntimeToolRouterServerConfig(options) {
2406
+ return {
2407
+ type: "stdio",
2408
+ command: resolve7(options.binDir, "rig-tool-router"),
2409
+ args: [],
2410
+ env: {
2411
+ RIG_RUNTIME_CONTEXT_FILE: options.contextFile,
2412
+ RIG_RUNTIME_BIN_DIR: options.binDir
2413
+ }
2414
+ };
2415
+ }
2416
+ function escapeTomlString(value) {
2417
+ return value.replaceAll("\\", "\\\\").replaceAll('"', "\\\"");
2418
+ }
2419
+ function tomlString(value) {
2420
+ return `"${escapeTomlString(value)}"`;
2421
+ }
2422
+ function tomlStringArray(values) {
2423
+ return `[${values.map((value) => tomlString(value)).join(", ")}]`;
2424
+ }
2425
+ function tomlInlineTable(entries) {
2426
+ return `{ ${Object.entries(entries).map(([key, value]) => `${key} = ${tomlString(value)}`).join(", ")} }`;
2427
+ }
2428
+ function codexRuntimeToolCliArgs(options) {
2429
+ const serverConfig = buildRuntimeToolRouterServerConfig(options);
2430
+ return [
2431
+ "-a",
2432
+ "never",
2433
+ "-c",
2434
+ `mcp_servers.${CLAUDE_ROUTER_SERVER_NAME}.command=${tomlString(serverConfig.command)}`,
2435
+ "-c",
2436
+ `mcp_servers.${CLAUDE_ROUTER_SERVER_NAME}.args=${tomlStringArray(serverConfig.args)}`,
2437
+ "-c",
2438
+ `mcp_servers.${CLAUDE_ROUTER_SERVER_NAME}.env=${tomlInlineTable(serverConfig.env)}`
2439
+ ];
2440
+ }
2441
+ function writeClaudeRuntimeToolRouterConfig(options) {
2442
+ const configPath = resolve7(options.stateDir, "claude-runtime-tools.mcp.json");
2443
+ mkdirSync4(options.stateDir, { recursive: true });
2444
+ const payload = {
2445
+ mcpServers: {
2446
+ [CLAUDE_ROUTER_SERVER_NAME]: buildRuntimeToolRouterServerConfig(options)
2447
+ }
2448
+ };
2449
+ writeFileSync4(configPath, `${JSON.stringify(payload, null, 2)}
2450
+ `, "utf-8");
2451
+ return configPath;
2452
+ }
2453
+ async function runClaudeToolRouterServer() {
2454
+ const lineReader = createInterface({
2455
+ input: process.stdin,
2456
+ crlfDelay: Infinity
2457
+ });
2458
+ const inFlightToolCalls = new Set;
2459
+ const trackToolCall = (call) => {
2460
+ inFlightToolCalls.add(call);
2461
+ call.finally(() => inFlightToolCalls.delete(call)).catch((err) => {
2462
+ console.warn("[claude-router] in-flight tool call failure:", err);
2463
+ });
2464
+ };
2465
+ for await (const line of lineReader) {
2466
+ const trimmed = line.trim();
2467
+ if (!trimmed) {
2468
+ continue;
2469
+ }
2470
+ let request;
2471
+ try {
2472
+ request = JSON.parse(trimmed);
2473
+ } catch {
2474
+ continue;
2475
+ }
2476
+ if (!request.method) {
2477
+ continue;
2478
+ }
2479
+ if (request.method === "notifications/initialized") {
2480
+ continue;
2481
+ }
2482
+ if (request.method === "initialize") {
2483
+ writeMessage({
2484
+ jsonrpc: "2.0",
2485
+ id: request.id ?? null,
2486
+ result: {
2487
+ protocolVersion: "2024-11-05",
2488
+ capabilities: {
2489
+ tools: {}
2490
+ },
2491
+ serverInfo: {
2492
+ name: CLAUDE_ROUTER_SERVER_NAME,
2493
+ version: ROUTER_VERSION
2494
+ }
2495
+ }
2496
+ });
2497
+ continue;
2498
+ }
2499
+ if (request.method === "ping") {
2500
+ writeMessage({
2501
+ jsonrpc: "2.0",
2502
+ id: request.id ?? null,
2503
+ result: {}
2504
+ });
2505
+ continue;
2506
+ }
2507
+ if (request.method === "tools/list") {
2508
+ writeMessage({
2509
+ jsonrpc: "2.0",
2510
+ id: request.id ?? null,
2511
+ result: {
2512
+ tools: CLAUDE_ROUTER_TOOL_DEFINITIONS
2513
+ }
2514
+ });
2515
+ continue;
2516
+ }
2517
+ if (request.method === "tools/call") {
2518
+ const toolName = typeof request.params?.name === "string" ? request.params.name : "";
2519
+ const args = isRecord(request.params?.arguments) ? request.params.arguments : {};
2520
+ const requestId = request.id ?? null;
2521
+ const toolCall = (async () => {
2522
+ try {
2523
+ const result = await invokeRuntimeTool(toolName, args);
2524
+ writeMessage({
2525
+ jsonrpc: "2.0",
2526
+ id: requestId,
2527
+ result
2528
+ });
2529
+ } catch (error) {
2530
+ writeMessage({
2531
+ jsonrpc: "2.0",
2532
+ id: requestId,
2533
+ error: {
2534
+ code: -32603,
2535
+ message: error instanceof Error ? error.message : String(error)
2536
+ }
2537
+ });
2538
+ }
2539
+ })();
2540
+ trackToolCall(toolCall);
2541
+ continue;
2542
+ }
2543
+ writeMessage({
2544
+ jsonrpc: "2.0",
2545
+ id: request.id ?? null,
2546
+ error: {
2547
+ code: -32601,
2548
+ message: `Unsupported method: ${request.method}`
2549
+ }
2550
+ });
2551
+ }
2552
+ if (inFlightToolCalls.size > 0) {
2553
+ await Promise.allSettled(Array.from(inFlightToolCalls));
2554
+ }
2555
+ }
2556
+ async function invokeRuntimeTool(toolName, args, options = {}) {
2557
+ if (toolName === "shell") {
2558
+ return invokeRuntimeShellTool(args, options);
2559
+ }
2560
+ const invocationEnv = options.env ?? process.env;
2561
+ const binaryPath = resolveRuntimeToolBinary(toolName, invocationEnv);
2562
+ if (!binaryPath) {
2563
+ return {
2564
+ content: [
2565
+ {
2566
+ type: "text",
2567
+ text: `Unknown Rig runtime tool: ${toolName}`
2568
+ }
2569
+ ],
2570
+ isError: true
2571
+ };
2572
+ }
2573
+ const proc = Bun.spawn([binaryPath], {
2574
+ stdin: "pipe",
2575
+ stdout: "pipe",
2576
+ stderr: "pipe",
2577
+ env: invocationEnv
2578
+ });
2579
+ const requestBody = `${JSON.stringify(args)}
2580
+ `;
2581
+ if (proc.stdin) {
2582
+ await proc.stdin.write(requestBody);
2583
+ await proc.stdin.end();
2584
+ }
2585
+ const [exitCode, stdout, stderr] = await Promise.all([
2586
+ proc.exited,
2587
+ readBunProcessPipe(proc.stdout),
2588
+ readBunProcessPipe(proc.stderr)
2589
+ ]);
2590
+ if (exitCode !== 0) {
2591
+ const text = [stdout.trim(), stderr.trim()].filter(Boolean).join(`
2592
+ `) || `Tool ${toolName} exited with code ${exitCode}`;
2593
+ return {
2594
+ content: [{ type: "text", text }],
2595
+ isError: true
2596
+ };
2597
+ }
2598
+ let payload;
2599
+ try {
2600
+ payload = JSON.parse(stdout);
2601
+ } catch {
2602
+ return {
2603
+ content: [{ type: "text", text: stdout.trim() || `(empty output from ${toolName})` }],
2604
+ isError: false
2605
+ };
2606
+ }
2607
+ if (payload.ok === false) {
2608
+ return {
2609
+ content: [{ type: "text", text: String(payload.message ?? `Tool ${toolName} failed`) }],
2610
+ structuredContent: payload,
2611
+ isError: true
2612
+ };
2613
+ }
2614
+ return {
2615
+ content: [{ type: "text", text: renderToolText(toolName, payload) }],
2616
+ structuredContent: payload,
2617
+ isError: false
2618
+ };
2619
+ }
2620
+ async function readBunProcessPipe(pipe) {
2621
+ if (typeof pipe === "number" || !pipe) {
2622
+ return "";
2623
+ }
2624
+ return new Response(pipe).text();
2625
+ }
2626
+ function resolveRuntimeToolBinary(toolName, env) {
2627
+ const binDir = env.RIG_RUNTIME_BIN_DIR?.trim() || "";
2628
+ if (!binDir) {
2629
+ return "";
2630
+ }
2631
+ const mapping = {
2632
+ read: "rig-read",
2633
+ write: "rig-write",
2634
+ edit: "rig-edit",
2635
+ glob: "rig-glob",
2636
+ grep: "rig-grep"
2637
+ };
2638
+ const executable = mapping[toolName];
2639
+ return executable ? resolve7(binDir, executable) : "";
2640
+ }
2641
+ function renderToolText(toolName, payload) {
2642
+ if (toolName === "shell") {
2643
+ const command = typeof payload.command === "string" ? payload.command : "(unknown command)";
2644
+ const stdout = typeof payload.stdout === "string" ? payload.stdout.trim() : "";
2645
+ const stderr = typeof payload.stderr === "string" ? payload.stderr.trim() : "";
2646
+ const exitCode = typeof payload.exit_code === "number" ? payload.exit_code : null;
2647
+ const output = [stdout, stderr].filter(Boolean).join(`
2648
+ `);
2649
+ const summary = exitCode === null ? command : `${command}
2650
+
2651
+ exit_code=${String(exitCode)}`;
2652
+ return output ? `${summary}
2653
+
2654
+ ${output}` : summary;
2655
+ }
2656
+ if (toolName === "read") {
2657
+ const path = typeof payload.path === "string" ? payload.path : "(unknown path)";
2658
+ const content = typeof payload.content === "string" ? payload.content : "";
2659
+ const truncated = payload.truncated === true ? `
2660
+
2661
+ [truncated]` : "";
2662
+ return `${path}
2663
+
2664
+ ${content}${truncated}`;
2665
+ }
2666
+ if (toolName === "glob") {
2667
+ const matches = Array.isArray(payload.matches) ? payload.matches.filter((value) => typeof value === "string") : [];
2668
+ return matches.length > 0 ? matches.join(`
2669
+ `) : "(no matches)";
2670
+ }
2671
+ if (toolName === "grep") {
2672
+ const matches = Array.isArray(payload.matches) ? payload.matches.filter(isRecord) : [];
2673
+ if (matches.length === 0) {
2674
+ return "(no matches)";
2675
+ }
2676
+ return matches.map((match) => `${String(match.path ?? "(unknown)")}:${String(match.line_number ?? "?")}: ${String(match.line ?? "")}`).join(`
2677
+ `);
2678
+ }
2679
+ if (toolName === "write") {
2680
+ return `Wrote ${String(payload.bytes_written ?? 0)} bytes to ${String(payload.path ?? "(unknown path)")}.`;
2681
+ }
2682
+ if (toolName === "edit") {
2683
+ return `Edited ${String(payload.path ?? "(unknown path)")}; replacements: ${String(payload.replacements ?? 0)}.`;
2684
+ }
2685
+ return JSON.stringify(payload, null, 2);
2686
+ }
2687
+ async function invokeRuntimeShellTool(args, options = {}) {
2688
+ const command = typeof args.command === "string" ? args.command.trim() : "";
2689
+ if (!command) {
2690
+ return {
2691
+ content: [{ type: "text", text: "Missing required shell `command` string." }],
2692
+ isError: true
2693
+ };
2694
+ }
2695
+ const invocationEnv = options.env ?? process.env;
2696
+ const shellName = args.shell === "sh" ? "sh" : args.shell === "zsh" ? "zsh" : "bash";
2697
+ const shellBinary = resolveRuntimeShellBinary(shellName, invocationEnv);
2698
+ if (!shellBinary) {
2699
+ return {
2700
+ content: [{ type: "text", text: `Missing Rig runtime shell binary for ${shellName}.` }],
2701
+ isError: true
2702
+ };
2703
+ }
2704
+ const workspaceRoot = resolve7(invocationEnv.RIG_TASK_WORKSPACE?.trim() || process.cwd());
2705
+ const requestedWorkdir = typeof args.workdir === "string" ? args.workdir.trim() : "";
2706
+ const workdir = requestedWorkdir ? resolveWithinWorkspace(workspaceRoot, requestedWorkdir) : workspaceRoot;
2707
+ if (!existsSync7(workdir)) {
2708
+ return {
2709
+ content: [{
2710
+ type: "text",
2711
+ text: `Shell workdir does not exist inside the task workspace: ${requestedWorkdir || "."}`
2712
+ }],
2713
+ isError: true
2714
+ };
2715
+ }
2716
+ try {
2717
+ if (!statSync(workdir).isDirectory()) {
2718
+ return {
2719
+ content: [{
2720
+ type: "text",
2721
+ text: `Shell workdir is not a directory inside the task workspace: ${requestedWorkdir || "."}`
2722
+ }],
2723
+ isError: true
2724
+ };
2725
+ }
2726
+ } catch (error) {
2727
+ return {
2728
+ content: [{
2729
+ type: "text",
2730
+ text: error instanceof Error ? error.message : String(error)
2731
+ }],
2732
+ isError: true
2733
+ };
2734
+ }
2735
+ let proc = null;
2736
+ try {
2737
+ proc = Bun.spawn([shellBinary, shellName === "bash" ? "-lc" : "-c", command], {
2738
+ cwd: workdir,
2739
+ env: invocationEnv,
2740
+ stdout: "pipe",
2741
+ stderr: "pipe"
2742
+ });
2743
+ } catch (error) {
2744
+ return {
2745
+ content: [{
2746
+ type: "text",
2747
+ text: error instanceof Error ? error.message : String(error)
2748
+ }],
2749
+ isError: true
2750
+ };
2751
+ }
2752
+ const [exitCode, stdout, stderr] = await Promise.all([
2753
+ proc.exited,
2754
+ readBunProcessPipe(proc.stdout),
2755
+ readBunProcessPipe(proc.stderr)
2756
+ ]);
2757
+ const payload = {
2758
+ ok: exitCode === 0,
2759
+ shell: shellName,
2760
+ cwd: workdir,
2761
+ command,
2762
+ stdout,
2763
+ stderr,
2764
+ exit_code: exitCode
2765
+ };
2766
+ return {
2767
+ content: [{ type: "text", text: renderToolText("shell", payload) }],
2768
+ structuredContent: payload,
2769
+ isError: exitCode !== 0
2770
+ };
2771
+ }
2772
+ function resolveRuntimeShellBinary(shellName, env) {
2773
+ const binDir = env.RIG_RUNTIME_BIN_DIR?.trim() || "";
2774
+ return binDir ? resolve7(binDir, shellName) : "";
2775
+ }
2776
+ function resolveWithinWorkspace(workspaceRoot, target) {
2777
+ const resolvedTarget = resolve7(workspaceRoot, normalizeWorkspaceRelativeTarget(target));
2778
+ const normalizedWorkspace = workspaceRoot.endsWith("/") ? workspaceRoot : `${workspaceRoot}/`;
2779
+ const normalizedTarget = resolvedTarget.endsWith("/") ? resolvedTarget : `${resolvedTarget}/`;
2780
+ if (resolvedTarget === workspaceRoot || normalizedTarget.startsWith(normalizedWorkspace)) {
2781
+ return resolvedTarget;
2782
+ }
2783
+ throw new Error(`Shell workdir must stay inside the task workspace: ${target}`);
2784
+ }
2785
+ function normalizeWorkspaceRelativeTarget(target) {
2786
+ const trimmed = target.trim();
2787
+ if (!trimmed) {
2788
+ return ".";
2789
+ }
2790
+ if (trimmed === "$MONOREPO_ROOT" || trimmed === "$RIG_TASK_WORKSPACE") {
2791
+ return ".";
2792
+ }
2793
+ if (trimmed.startsWith("$MONOREPO_ROOT/")) {
2794
+ return trimmed.slice("$MONOREPO_ROOT/".length);
2795
+ }
2796
+ if (trimmed.startsWith("$RIG_TASK_WORKSPACE/")) {
2797
+ return trimmed.slice("$RIG_TASK_WORKSPACE/".length);
2798
+ }
2799
+ if (trimmed === "repos/spliter-monorepo") {
2800
+ return ".";
2801
+ }
2802
+ if (trimmed.startsWith("repos/spliter-monorepo/")) {
2803
+ return trimmed.slice("repos/spliter-monorepo/".length);
2804
+ }
2805
+ return trimmed;
2806
+ }
2807
+ function isRecord(value) {
2808
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2809
+ }
2810
+ function writeMessage(payload) {
2811
+ process.stdout.write(`${JSON.stringify(payload)}
2812
+ `);
2813
+ }
2814
+ var CLAUDE_ROUTER_SERVER_NAME = "rig_runtime_tools", CLAUDE_DISABLED_FILE_TOOLS, ROUTER_VERSION = "0.1.0", CLAUDE_ROUTER_TOOL_DEFINITIONS;
2815
+ var init_claude_router = __esm(async () => {
2816
+ CLAUDE_DISABLED_FILE_TOOLS = [
2817
+ "Read",
2818
+ "Edit",
2819
+ "Write",
2820
+ "NotebookEdit",
2821
+ "Glob",
2822
+ "Grep"
2823
+ ];
2824
+ CLAUDE_ROUTER_TOOL_DEFINITIONS = [
2825
+ {
2826
+ name: "read",
2827
+ description: "Read a UTF-8 file from the current Rig task worktree, the outer control-plane repo ($PROJECT_RIG_ROOT), or the host monorepo checkout ($MONOREPO_MAIN_ROOT).",
2828
+ inputSchema: {
2829
+ type: "object",
2830
+ properties: {
2831
+ path: { type: "string", description: "Absolute or workspace-relative file path." },
2832
+ offset: { type: "integer", minimum: 0 },
2833
+ limit: { type: "integer", minimum: 1, maximum: 2097152 }
2834
+ },
2835
+ required: ["path"],
2836
+ additionalProperties: false
2837
+ }
2838
+ },
2839
+ {
2840
+ name: "write",
2841
+ description: "Write UTF-8 content to a file inside the current Rig task workspace only.",
2842
+ inputSchema: {
2843
+ type: "object",
2844
+ properties: {
2845
+ path: { type: "string", description: "Absolute or workspace-relative file path." },
2846
+ content: { type: "string" },
2847
+ create_parents: { type: "boolean" }
2848
+ },
2849
+ required: ["path", "content"],
2850
+ additionalProperties: false
2851
+ }
2852
+ },
2853
+ {
2854
+ name: "edit",
2855
+ description: "Replace one or more exact string occurrences in a UTF-8 file inside the current Rig task workspace only.",
2856
+ inputSchema: {
2857
+ type: "object",
2858
+ properties: {
2859
+ path: { type: "string", description: "Absolute or workspace-relative file path." },
2860
+ old_string: { type: "string" },
2861
+ new_string: { type: "string" },
2862
+ replace_all: { type: "boolean" }
2863
+ },
2864
+ required: ["path", "old_string", "new_string"],
2865
+ additionalProperties: false
2866
+ }
2867
+ },
2868
+ {
2869
+ name: "glob",
2870
+ description: "Search files using a glob pattern across the current task worktree, $PROJECT_RIG_ROOT, or $MONOREPO_MAIN_ROOT.",
2871
+ inputSchema: {
2872
+ type: "object",
2873
+ properties: {
2874
+ pattern: { type: "string" },
2875
+ path: { type: "string", description: "Optional workspace-relative search root." },
2876
+ include_hidden: { type: "boolean" },
2877
+ max_results: { type: "integer", minimum: 1, maximum: 5000 }
2878
+ },
2879
+ required: ["pattern"],
2880
+ additionalProperties: false
2881
+ }
2882
+ },
2883
+ {
2884
+ name: "grep",
2885
+ description: "Search file contents across the current task worktree, $PROJECT_RIG_ROOT, or $MONOREPO_MAIN_ROOT.",
2886
+ inputSchema: {
2887
+ type: "object",
2888
+ properties: {
2889
+ pattern: { type: "string" },
2890
+ path: { type: "string", description: "Optional workspace-relative search root." },
2891
+ literal: { type: "boolean" },
2892
+ include_hidden: { type: "boolean" },
2893
+ max_results: { type: "integer", minimum: 1, maximum: 500 },
2894
+ glob: { type: "string", description: "Optional file glob filter passed through to ripgrep." }
2895
+ },
2896
+ required: ["pattern"],
2897
+ additionalProperties: false
2898
+ }
2899
+ }
2900
+ ];
2901
+ if (false) {}
2902
+ });
2903
+
2904
+ // packages/harness-plugin/src/pi-command.ts
2905
+ var exports_pi_command = {};
2906
+ __export(exports_pi_command, {
2907
+ executePi: () => executePi
2908
+ });
2909
+ import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync5 } from "fs";
2910
+ import { homedir } from "os";
2911
+ import { dirname as dirname3, resolve as resolve8 } from "path";
2912
+ import { CliError, requireNoExtraArgs } from "@rig/std-shared/cli-args";
2913
+ function settingsPath(root) {
2914
+ return resolve8(root, ".pi", "settings.json");
2915
+ }
2916
+ function userSettingsPath() {
2917
+ return resolve8(homedir(), ".pi", "agent", "settings.json");
2918
+ }
2919
+ function readJson(path, fallback) {
2920
+ if (!existsSync8(path))
2921
+ return fallback;
2922
+ try {
2923
+ return JSON.parse(readFileSync4(path, "utf-8"));
2924
+ } catch {
2925
+ return fallback;
2926
+ }
2927
+ }
2928
+ function packageKey(entry) {
2929
+ if (typeof entry === "string")
2930
+ return entry;
2931
+ if (entry && typeof entry === "object" && typeof entry.source === "string") {
2932
+ return entry.source;
2933
+ }
2934
+ return JSON.stringify(entry);
2935
+ }
2936
+ function writeSettings(path, settings) {
2937
+ mkdirSync5(dirname3(path), { recursive: true });
2938
+ writeFileSync5(path, `${JSON.stringify(settings, null, 2)}
2939
+ `, "utf-8");
2940
+ }
2941
+ async function searchNpmForPiExtensions(term) {
2942
+ const query = encodeURIComponent(term ? `${term} pi extension` : "pi extension");
2943
+ const url = `https://registry.npmjs.org/-/v1/search?text=${query}&size=20`;
2944
+ const response = await fetch(url);
2945
+ if (!response.ok) {
2946
+ throw new CliError(`npm registry search failed (${response.status}).`, 2, { hint: "Check network access to registry.npmjs.org, then retry `rig pi search <term>`." });
2947
+ }
2948
+ const payload = await response.json();
2949
+ const results = [];
2950
+ for (const entry of payload.objects ?? []) {
2951
+ const pkg = entry.package;
2952
+ if (!pkg?.name)
2953
+ continue;
2954
+ const keywords = (pkg.keywords ?? []).map((k) => k.toLowerCase());
2955
+ const piLike = pkg.name.startsWith("pi-") || pkg.name.includes("-pi") || keywords.includes("pi") || keywords.includes("pi-extension") || (pkg.description ?? "").toLowerCase().includes("pi extension") || (pkg.description ?? "").toLowerCase().includes("pi coding agent");
2956
+ if (!piLike)
2957
+ continue;
2958
+ results.push({ name: pkg.name, version: pkg.version ?? "", description: pkg.description ?? "" });
2959
+ }
2960
+ return results;
2961
+ }
2962
+ async function executePi(context, args) {
2963
+ const [command = "list", ...rest] = args;
2964
+ const projectSettingsPath = settingsPath(context.projectRoot);
2965
+ const managedRecordPath = resolve8(context.projectRoot, ".rig", "state", "pi-managed-packages.json");
2966
+ switch (command) {
2967
+ case "list": {
2968
+ requireNoExtraArgs(rest, "rig pi list");
2969
+ const project = readJson(projectSettingsPath, {});
2970
+ const managed = new Set(readJson(managedRecordPath, []));
2971
+ const user = readJson(userSettingsPath(), {});
2972
+ const projectPackages = (Array.isArray(project.packages) ? project.packages : []).map((entry) => ({
2973
+ source: packageKey(entry),
2974
+ managedByRigConfig: managed.has(packageKey(entry))
2975
+ }));
2976
+ const userPackages = (Array.isArray(user.packages) ? user.packages : []).map(packageKey);
2977
+ if (context.outputMode === "text") {
2978
+ console.log("Project Pi packages (.pi/settings.json):");
2979
+ if (projectPackages.length === 0)
2980
+ console.log(" (none)");
2981
+ for (const pkg of projectPackages) {
2982
+ console.log(` ${pkg.source}${pkg.managedByRigConfig ? " [from rig.config runtime.pi.packages]" : ""}`);
2983
+ }
2984
+ console.log("User Pi packages (~/.pi/agent/settings.json):");
2985
+ if (userPackages.length === 0)
2986
+ console.log(" (none)");
2987
+ for (const pkg of userPackages)
2988
+ console.log(` ${pkg}`);
2989
+ console.log("Add more: `rig pi add <npm-package>` \xB7 discover: `rig pi search <term>`");
2990
+ }
2991
+ return { ok: true, group: "pi", command, details: { projectPackages, userPackages } };
2992
+ }
2993
+ case "add": {
2994
+ const [source, ...extra] = rest;
2995
+ requireNoExtraArgs(extra, "rig pi add <package-source>");
2996
+ if (!source) {
2997
+ throw new CliError("Usage: rig pi add <package-source> (npm name, name@version, or git URL)", 2);
2998
+ }
2999
+ const settings = readJson(projectSettingsPath, {});
3000
+ const packages = Array.isArray(settings.packages) ? settings.packages : [];
3001
+ if (packages.some((entry) => packageKey(entry) === source)) {
3002
+ throw new CliError(`"${source}" is already in ${projectSettingsPath}.`, 2, { hint: "Run `rig pi list` to see installed extensions." });
3003
+ }
3004
+ writeSettings(projectSettingsPath, { ...settings, packages: [...packages, source] });
3005
+ if (context.outputMode === "text") {
3006
+ console.log(`Added ${source} to ${projectSettingsPath}.`);
3007
+ console.log("Pi installs missing packages automatically at the next session start (local and worker).");
3008
+ }
3009
+ return { ok: true, group: "pi", command, details: { source, settingsPath: projectSettingsPath } };
3010
+ }
3011
+ case "remove": {
3012
+ const [source, ...extra] = rest;
3013
+ requireNoExtraArgs(extra, "rig pi remove <package-source>");
3014
+ if (!source) {
3015
+ throw new CliError("Usage: rig pi remove <package-source>", 2);
3016
+ }
3017
+ const managed = new Set(readJson(managedRecordPath, []));
3018
+ if (managed.has(source)) {
3019
+ throw new CliError(`"${source}" is managed by rig.config.ts (runtime.pi.packages); remove it there instead.`, 2);
3020
+ }
3021
+ const settings = readJson(projectSettingsPath, {});
3022
+ const packages = Array.isArray(settings.packages) ? settings.packages : [];
3023
+ const next = packages.filter((entry) => packageKey(entry) !== source);
3024
+ if (next.length === packages.length) {
3025
+ throw new CliError(`"${source}" is not in ${projectSettingsPath}.`, 2, { hint: "Run `rig pi list` to see what is installed, then `rig pi remove <source>` with an exact entry." });
3026
+ }
3027
+ const nextSettings = { ...settings };
3028
+ if (next.length > 0)
3029
+ nextSettings.packages = next;
3030
+ else
3031
+ delete nextSettings.packages;
3032
+ writeSettings(projectSettingsPath, nextSettings);
3033
+ if (context.outputMode === "text") {
3034
+ console.log(`Removed ${source} from ${projectSettingsPath}.`);
3035
+ }
3036
+ return { ok: true, group: "pi", command, details: { source } };
3037
+ }
3038
+ case "search": {
3039
+ const term = rest.join(" ").trim();
3040
+ const results = await searchNpmForPiExtensions(term);
3041
+ if (context.outputMode === "text") {
3042
+ if (results.length === 0) {
3043
+ console.log(`No Pi extension packages found on npm${term ? ` for "${term}"` : ""}.`);
3044
+ } else {
3045
+ console.log(`Pi extension packages on npm${term ? ` matching "${term}"` : ""}:`);
3046
+ for (const pkg of results) {
3047
+ console.log(` ${pkg.name}@${pkg.version} ${pkg.description.slice(0, 80)}`);
3048
+ }
3049
+ console.log("Install one: `rig pi add <name>`");
3050
+ }
3051
+ }
3052
+ return { ok: true, group: "pi", command, details: { term, results } };
3053
+ }
3054
+ default:
3055
+ throw new CliError(`Unknown pi command: ${command}. Use list|add|remove|search.`, 1, { hint: "Run `rig pi --help` for usage." });
3056
+ }
3057
+ }
3058
+ var init_pi_command = () => {};
3059
+
3060
+ // packages/harness-plugin/src/profile-command.ts
3061
+ var exports_profile_command = {};
3062
+ __export(exports_profile_command, {
3063
+ executeProfile: () => executeProfile
3064
+ });
3065
+ import { CliError as CliError2, requireNoExtraArgs as requireNoExtraArgs2, takeOption as takeOption2 } from "@rig/std-shared/cli-args";
3066
+ import { HARNESS_PROFILE_STATE } from "@rig/contracts";
3067
+ import { defineCapability as defineCapability6 } from "@rig/core/capability";
3068
+ import { loadCapabilityForRoot as loadCapabilityForRoot4 } from "@rig/core/capability-loaders";
3069
+ import { withMutedConsole } from "@rig/std-shared/cli-muted-console";
3070
+ async function profileState(projectRoot) {
3071
+ const service = await loadCapabilityForRoot4(projectRoot, HarnessProfileStateCap);
3072
+ if (!service) {
3073
+ throw new CliError2("Harness profile state capability unavailable: load @rig/harness-plugin (standard bundle).", 2);
3074
+ }
3075
+ return service;
3076
+ }
3077
+ async function showProfile2(projectRoot) {
3078
+ const state = await profileState(projectRoot);
3079
+ const profile = { ...DEFAULT_AGENT_PROFILE2, ...state.readHarnessStateJson(projectRoot, AGENT_PROFILE_FILE2), model: "pi", runtime: "pi", agent_plugin: "pi" };
3080
+ console.log("Execution Profile:");
3081
+ console.log(` model: ${profile.model}`);
3082
+ console.log(` runtime: ${profile.runtime}`);
3083
+ console.log(` plugin: ${profile.agent_plugin}`);
3084
+ }
3085
+ async function setProfile2(projectRoot, options) {
3086
+ const invalid = [options.model, options.runtime, options.plugin, options.preset].filter((value) => typeof value === "string" && value.trim().length > 0 && value.trim() !== "pi");
3087
+ if (invalid.length > 0) {
3088
+ throw new CliError2("Only the Pi runtime profile is supported by this Rig substrate.", 1, {
3089
+ hint: 'Omit --model/--runtime/--plugin/--preset or pass "pi" explicitly.'
3090
+ });
3091
+ }
3092
+ const state = await profileState(projectRoot);
3093
+ state.writeHarnessStateJson(projectRoot, AGENT_PROFILE_FILE2, { ...DEFAULT_AGENT_PROFILE2, updated_at: new Date().toISOString() });
3094
+ await showProfile2(projectRoot);
3095
+ }
3096
+ async function executeProfile(context, args) {
3097
+ const [command = "show", ...rest] = args;
3098
+ switch (command) {
3099
+ case "show":
3100
+ requireNoExtraArgs2(rest, "rig profile show");
3101
+ await withMutedConsole(context.outputMode === "json", () => showProfile2(context.projectRoot));
3102
+ return { ok: true, group: "profile", command };
3103
+ case "set": {
3104
+ let pending = rest;
3105
+ const presetResult = takeOption2(pending, "--preset");
3106
+ pending = presetResult.rest;
3107
+ const modelResult = takeOption2(pending, "--model");
3108
+ pending = modelResult.rest;
3109
+ const runtimeResult = takeOption2(pending, "--runtime");
3110
+ pending = runtimeResult.rest;
3111
+ const pluginResult = takeOption2(pending, "--plugin");
3112
+ pending = pluginResult.rest;
3113
+ requireNoExtraArgs2(pending, "rig profile set [--model ...] [--runtime ...] [--plugin ...]");
3114
+ if (!presetResult.value && !modelResult.value && !runtimeResult.value && !pluginResult.value && rest.length === 0) {
3115
+ throw new CliError2("Provide at least one of --model, --runtime, or --plugin.", 1, {
3116
+ hint: "Example: `rig profile set --model pi`. See current values with `rig profile show`."
3117
+ });
3118
+ }
3119
+ await withMutedConsole(context.outputMode === "json", () => setProfile2(context.projectRoot, {
3120
+ ...modelResult.value !== undefined ? { model: modelResult.value } : {},
3121
+ ...runtimeResult.value !== undefined ? { runtime: runtimeResult.value } : {},
3122
+ ...pluginResult.value !== undefined ? { plugin: pluginResult.value } : {},
3123
+ ...presetResult.value !== undefined ? { preset: presetResult.value } : {}
3124
+ }));
3125
+ return { ok: true, group: "profile", command, details: { lockedTo: "pi" } };
3126
+ }
3127
+ default:
3128
+ throw new CliError2(`Unknown profile command: ${command}`, 1, { hint: "Run `rig profile --help` \u2014 commands are show|set." });
3129
+ }
3130
+ }
3131
+ var HarnessProfileStateCap, DEFAULT_AGENT_PROFILE2, AGENT_PROFILE_FILE2 = "agent-profile.json";
3132
+ var init_profile_command = __esm(() => {
3133
+ HarnessProfileStateCap = defineCapability6(HARNESS_PROFILE_STATE);
3134
+ DEFAULT_AGENT_PROFILE2 = {
3135
+ model: "pi",
3136
+ runtime: "pi",
3137
+ agent_plugin: "pi",
3138
+ updated_at: new Date().toISOString()
3139
+ };
3140
+ });
3141
+
3142
+ // packages/harness-plugin/src/agent-command.ts
3143
+ var exports_agent_command = {};
3144
+ __export(exports_agent_command, {
3145
+ executeAgent: () => executeAgent
3146
+ });
3147
+ import {
3148
+ CliError as CliError3,
3149
+ requireNoExtraArgs as requireNoExtraArgs3,
3150
+ takeFlag,
3151
+ takeOption as takeOption3
3152
+ } from "@rig/std-shared/cli-args";
3153
+ import { agentId } from "@rig/core/safe-identifiers";
3154
+ import { ISOLATION_BACKEND as ISOLATION_BACKEND2, REPO_OPERATIONS_CAPABILITY as REPO_OPERATIONS_CAPABILITY2 } from "@rig/contracts";
3155
+ import { defineCapability as defineCapability7 } from "@rig/core/capability";
3156
+ import { requireCapabilityForRoot as requireCapabilityForRoot2 } from "@rig/core/capability-loaders";
3157
+ import { buildPluginHostContext as buildPluginHostContext3 } from "@rig/core/plugin-host-context";
3158
+ import { withMutedConsole as withMutedConsole2 } from "@rig/std-shared/cli-muted-console";
3159
+ import { parseEnumOption } from "@rig/std-shared/cli-args";
3160
+ async function resolveRepoOperations(projectRoot) {
3161
+ const hostCtx = await buildPluginHostContext3(projectRoot);
3162
+ const repoOps = hostCtx ? await RepoOperationsCap2.resolve(hostCtx.pluginHost) : null;
3163
+ if (!repoOps) {
3164
+ throw new CliError3(`No REPO_OPERATIONS capability is registered for project root "${projectRoot}".`, 2, { hint: "Install @rig/repos-plugin (it ships in the default bundle) before running repo operations." });
3165
+ }
3166
+ return repoOps;
3167
+ }
3168
+ async function resolveIsolationBackend(projectRoot) {
3169
+ return requireCapabilityForRoot2(projectRoot, defineCapability7(ISOLATION_BACKEND2), `No ISOLATION_BACKEND capability is registered for project root "${projectRoot}". ` + MISSING_ISOLATION_BACKEND_HINT);
3170
+ }
3171
+ function splitAtDoubleDash(args) {
3172
+ const separatorIndex = args.indexOf("--");
3173
+ if (separatorIndex === -1) {
3174
+ return { options: args, commandParts: [] };
3175
+ }
3176
+ return {
3177
+ options: args.slice(0, separatorIndex),
3178
+ commandParts: args.slice(separatorIndex + 1)
3179
+ };
3180
+ }
3181
+ async function attachEventBusToProvisionedRuntime(context, workspaceDir) {
3182
+ const previousWorkspace = process.env.RIG_TASK_WORKSPACE;
3183
+ process.env.RIG_TASK_WORKSPACE = workspaceDir;
3184
+ try {
3185
+ await context.eventBus.attachRuntimeWorkspace(context.projectRoot);
3186
+ } finally {
3187
+ if (previousWorkspace === undefined) {
3188
+ delete process.env.RIG_TASK_WORKSPACE;
3189
+ } else {
3190
+ process.env.RIG_TASK_WORKSPACE = previousWorkspace;
3191
+ }
3192
+ }
3193
+ }
3194
+ async function runProjectMainSyncPreflight(context, options) {
3195
+ if (context.dryRun) {
3196
+ if (context.outputMode === "text" && !options.disabled) {
3197
+ console.log("[dry-run] project-rig pre-run sync check");
3198
+ }
3199
+ return;
3200
+ }
3201
+ const repoOps = await resolveRepoOperations(context.projectRoot);
3202
+ const result = await repoOps.ensureProjectMainFreshBeforeRun({
3203
+ projectRoot: context.projectRoot,
3204
+ disabled: options.disabled,
3205
+ runBootstrap: async () => {
3206
+ const bootstrap = await context.runCommand(["bun", "run", "bootstrap"]);
3207
+ if (bootstrap.exitCode !== 0) {
3208
+ throw new CliError3(bootstrap.stderr || bootstrap.stdout || "bun run bootstrap failed during project pre-run sync", bootstrap.exitCode || 1);
3209
+ }
3210
+ }
3211
+ });
3212
+ if (context.outputMode !== "text") {
3213
+ return;
3214
+ }
3215
+ switch (result.status) {
3216
+ case "disabled":
3217
+ console.log("Project pre-run sync skipped (--skip-project-sync).");
3218
+ break;
3219
+ case "skipped_not_main":
3220
+ console.log(`Project pre-run sync skipped (current branch: ${result.branch}).`);
3221
+ break;
3222
+ case "up_to_date":
3223
+ break;
3224
+ case "local_ahead":
3225
+ console.log(`Project pre-run sync skipped (local main ahead by ${result.localAhead} commit(s)).`);
3226
+ break;
3227
+ case "updated":
3228
+ console.log(`Project pre-run sync updated local main from origin/main (+${result.remoteAhead}) and bootstrapped.`);
3229
+ break;
3230
+ }
3231
+ }
3232
+ async function executeAgent(context, args) {
3233
+ const [command = "list", ...rest] = args;
3234
+ const backend = await resolveIsolationBackend(context.projectRoot);
3235
+ switch (command) {
3236
+ case "list": {
3237
+ requireNoExtraArgs3(rest, "rig agent list");
3238
+ const runtimes = await backend.listAgentRuntimes(context.projectRoot);
3239
+ if (context.outputMode === "text") {
3240
+ if (runtimes.length === 0) {
3241
+ console.log("No agent runtimes.");
3242
+ } else {
3243
+ for (const runtime of runtimes) {
3244
+ console.log(`${runtime.id} (${runtime.mode}) workspace=${runtime.workspaceDir} created=${runtime.createdAt}`);
3245
+ }
3246
+ }
3247
+ }
3248
+ return { ok: true, group: "agent", command, details: { runtimes } };
3249
+ }
3250
+ case "prepare": {
3251
+ let pending = rest;
3252
+ const idResult = takeOption3(pending, "--id");
3253
+ pending = idResult.rest;
3254
+ const modeResult = takeOption3(pending, "--mode");
3255
+ pending = modeResult.rest;
3256
+ const taskResult = takeOption3(pending, "--task");
3257
+ pending = taskResult.rest;
3258
+ requireNoExtraArgs3(pending, "rig agent prepare --task <id> [--id <id>] [--mode worktree]");
3259
+ const mode = parseEnumOption(modeResult.value, ["worktree"], { fallback: "worktree", label: "isolation mode" });
3260
+ const id = idResult.value || agentId("agent");
3261
+ const taskId = taskResult.value?.trim();
3262
+ if (!taskId) {
3263
+ throw new CliError3("Usage: rig agent prepare --task <id> [--id <id>] [--mode worktree]");
3264
+ }
3265
+ const runtime = await withMutedConsole2(context.outputMode === "json", () => backend.ensureAgentRuntime({
3266
+ projectRoot: context.projectRoot,
3267
+ id,
3268
+ taskId,
3269
+ mode
3270
+ }));
3271
+ await attachEventBusToProvisionedRuntime(context, runtime.workspaceDir);
3272
+ if (context.outputMode === "text") {
3273
+ console.log(`Prepared runtime ${runtime.id} (${runtime.mode})`);
3274
+ console.log(`Workspace: ${runtime.workspaceDir}`);
3275
+ }
3276
+ return { ok: true, group: "agent", command, details: { runtime } };
3277
+ }
3278
+ case "run": {
3279
+ const { options, commandParts } = splitAtDoubleDash(rest);
3280
+ if (commandParts.length === 0) {
3281
+ throw new CliError3("Usage: rig agent run [--id <id>] [--mode worktree] [--skip-project-sync] -- <command...>");
3282
+ }
3283
+ let pending = options;
3284
+ const idResult = takeOption3(pending, "--id");
3285
+ pending = idResult.rest;
3286
+ const modeResult = takeOption3(pending, "--mode");
3287
+ pending = modeResult.rest;
3288
+ const taskResult = takeOption3(pending, "--task");
3289
+ pending = taskResult.rest;
3290
+ const skipProjectSyncResult = takeFlag(pending, "--skip-project-sync");
3291
+ pending = skipProjectSyncResult.rest;
3292
+ requireNoExtraArgs3(pending, "rig agent run --task <id> [--id <id>] [--mode worktree] [--skip-project-sync] -- <command...>");
3293
+ const mode = parseEnumOption(modeResult.value, ["worktree"], { fallback: "worktree", label: "isolation mode" });
3294
+ const id = idResult.value || agentId("agent-run");
3295
+ const taskId = taskResult.value?.trim();
3296
+ if (!taskId) {
3297
+ throw new CliError3("Usage: rig agent run --task <id> [--id <id>] [--mode worktree] [--skip-project-sync] -- <command...>");
3298
+ }
3299
+ await runProjectMainSyncPreflight(context, { disabled: skipProjectSyncResult.value });
3300
+ try {
3301
+ const runtime = await withMutedConsole2(context.outputMode === "json", () => backend.ensureAgentRuntime({
3302
+ projectRoot: context.projectRoot,
3303
+ id,
3304
+ taskId,
3305
+ mode
3306
+ }));
3307
+ await attachEventBusToProvisionedRuntime(context, runtime.workspaceDir);
3308
+ const result = await backend.runInAgentRuntime({
3309
+ projectRoot: context.projectRoot,
3310
+ runtime,
3311
+ command: commandParts,
3312
+ inheritStdio: context.outputMode === "text"
3313
+ });
3314
+ if (result.exitCode !== 0) {
3315
+ throw new CliError3(`Agent runtime command failed (${result.exitCode}) in ${runtime.id}${result.stderr ? `
3316
+ ${result.stderr.trim()}` : ""}`, result.exitCode);
3317
+ }
3318
+ return {
3319
+ ok: true,
3320
+ group: "agent",
3321
+ command,
3322
+ details: {
3323
+ runtimeId: runtime.id,
3324
+ mode: runtime.mode,
3325
+ command: commandParts,
3326
+ exitCode: result.exitCode,
3327
+ sandboxBackend: result.sandboxBackend,
3328
+ sandboxEnabled: result.sandboxEnabled,
3329
+ stdout: result.stdout,
3330
+ stderr: result.stderr
3331
+ }
3332
+ };
3333
+ } catch (error) {
3334
+ throw error;
3335
+ }
3336
+ }
3337
+ case "cleanup": {
3338
+ let pending = rest;
3339
+ const allResult = takeFlag(pending, "--all");
3340
+ pending = allResult.rest;
3341
+ const idResult = takeOption3(pending, "--id");
3342
+ pending = idResult.rest;
3343
+ requireNoExtraArgs3(pending, "rig agent cleanup (--id <id> | --all)");
3344
+ if (!allResult.value && !idResult.value) {
3345
+ throw new CliError3("Provide --id <id> or --all.", 1, { hint: "Run `rig agent list` to find agent ids." });
3346
+ }
3347
+ const runtimes = await backend.listAgentRuntimes(context.projectRoot);
3348
+ const targets = allResult.value ? runtimes.map((runtime) => runtime.id) : [idResult.value];
3349
+ for (const id of targets) {
3350
+ await backend.cleanupAgentRuntime({
3351
+ projectRoot: context.projectRoot,
3352
+ id
3353
+ });
3354
+ }
3355
+ if (context.outputMode === "text") {
3356
+ console.log(`Cleaned runtimes: ${targets.join(", ")}`);
3357
+ }
3358
+ return {
3359
+ ok: true,
3360
+ group: "agent",
3361
+ command,
3362
+ details: {
3363
+ cleaned: targets,
3364
+ count: targets.length,
3365
+ all: allResult.value
3366
+ }
3367
+ };
3368
+ }
3369
+ default:
3370
+ throw new CliError3(`Unknown agent command: ${command}`, 1, { hint: "Run `rig agent --help` to list agent commands." });
3371
+ }
3372
+ }
3373
+ var MISSING_ISOLATION_BACKEND_HINT = "Install @rig/isolation-plugin (it ships in the default bundle) so runtime provisioning can resolve a backend.", RepoOperationsCap2;
3374
+ var init_agent_command = __esm(() => {
3375
+ RepoOperationsCap2 = defineCapability7(REPO_OPERATIONS_CAPABILITY2);
3376
+ });
3377
+
3378
+ // packages/harness-plugin/src/runtime-instructions.ts
3379
+ function normalizeRuntimeInstructionProvider(_value) {
3380
+ return "pi";
3381
+ }
3382
+ function buildProviderTaskRunInstructionLines(_provider) {
3383
+ return [
3384
+ "Use Pi's built-in `read`, `write`, `edit`, and `bash` tools from the isolated Rig task worktree.",
3385
+ "Keep file writes inside the scoped task workspace unless Rig explicitly tells you a path is host/project metadata.",
3386
+ "Prefer `read`, `write`, and `edit` over shell one-liners whenever those tools fit.",
3387
+ "When shell access is needed, keep commands narrow and bounded; avoid repo-wide searches without an explicit path and output cap."
3388
+ ];
3389
+ }
3390
+ function buildProviderRuntimeContextLines(_provider) {
3391
+ return [
3392
+ "Pi runs from the isolated Rig task worktree with its built-in `read`, `write`, `edit`, and `bash` tools enabled.",
3393
+ "Keep writes scoped to the task workspace unless Rig-provided instructions name an explicit metadata path.",
3394
+ "Prefer Pi file tools over shell one-liners for file reads and edits.",
3395
+ "Keep shell commands narrow and bounded; cap broad searches before widening."
3396
+ ];
3397
+ }
3398
+
3399
+ // packages/harness-plugin/src/service.ts
3400
+ var exports_service = {};
3401
+ __export(exports_service, {
3402
+ svc: () => svc,
3403
+ runtimeInstructionService: () => runtimeInstructionService
3404
+ });
3405
+ var svc, runtimeInstructionService;
3406
+ var init_service = __esm(() => {
3407
+ svc = {
3408
+ normalizeProvider: normalizeRuntimeInstructionProvider,
3409
+ buildTaskRunInstructionLines: buildProviderTaskRunInstructionLines,
3410
+ buildRuntimeContextLines: buildProviderRuntimeContextLines
3411
+ };
3412
+ runtimeInstructionService = svc;
3413
+ });
3414
+
3415
+ // packages/harness-plugin/src/skill-materializer.ts
3416
+ import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync5, readdirSync, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "fs";
3417
+ import { resolve as resolve9 } from "path";
3418
+ function parseFrontmatter(raw) {
3419
+ const m = raw.match(FRONTMATTER_RE);
3420
+ if (!m) {
3421
+ return { meta: {}, body: raw };
3422
+ }
3423
+ const yaml = m[1] ?? "";
3424
+ const body = m[2] ?? "";
3425
+ const meta = {};
3426
+ for (const line of yaml.split(/\r?\n/)) {
3427
+ const trimmed = line.trim();
3428
+ if (!trimmed || trimmed.startsWith("#"))
3429
+ continue;
3430
+ const idx = trimmed.indexOf(":");
3431
+ if (idx === -1)
3432
+ continue;
3433
+ const key = trimmed.slice(0, idx).trim();
3434
+ let value = trimmed.slice(idx + 1).trim();
3435
+ if (typeof value === "string") {
3436
+ const s = value;
3437
+ if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
3438
+ value = s.slice(1, -1);
3439
+ } else if (s === "true")
3440
+ value = true;
3441
+ else if (s === "false")
3442
+ value = false;
3443
+ else if (/^-?\d+$/.test(s))
3444
+ value = parseInt(s, 10);
3445
+ else if (/^-?\d+\.\d+$/.test(s))
3446
+ value = parseFloat(s);
3447
+ }
3448
+ meta[key] = value;
3449
+ }
3450
+ return { meta, body };
3451
+ }
3452
+ function assertValidSkillFrontmatter(path, raw) {
3453
+ const { meta } = parseFrontmatter(raw);
3454
+ if (typeof meta.name !== "string") {
3455
+ throw new Error(`SKILL.md missing required field "name": ${path}`);
3456
+ }
3457
+ }
3458
+ function skillDirName(id) {
3459
+ return id.replace(/[^a-zA-Z0-9._-]+/g, "-");
3460
+ }
3461
+ async function materializeSkills(projectRoot, entries) {
3462
+ const skillsRoot = resolve9(projectRoot, ".pi", "skills");
3463
+ if (existsSync9(skillsRoot)) {
3464
+ for (const name of readdirSync(skillsRoot)) {
3465
+ const dir = resolve9(skillsRoot, name);
3466
+ if (existsSync9(resolve9(dir, MARKER_FILENAME))) {
3467
+ rmSync2(dir, { recursive: true, force: true });
3468
+ }
3469
+ }
3470
+ }
3471
+ const written = [];
3472
+ for (const { pluginName, skill } of entries) {
3473
+ const sourcePath = resolve9(projectRoot, skill.path);
3474
+ if (!existsSync9(sourcePath)) {
3475
+ console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${sourcePath} does not exist`);
3476
+ continue;
3477
+ }
3478
+ let body;
3479
+ try {
3480
+ body = readFileSync5(sourcePath, "utf-8");
3481
+ assertValidSkillFrontmatter(sourcePath, body);
3482
+ } catch (err) {
3483
+ console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${err instanceof Error ? err.message : err}`);
3484
+ continue;
3485
+ }
3486
+ const dir = resolve9(skillsRoot, skillDirName(skill.id));
3487
+ mkdirSync6(dir, { recursive: true });
3488
+ writeFileSync6(resolve9(dir, "SKILL.md"), body, "utf-8");
3489
+ writeFileSync6(resolve9(dir, MARKER_FILENAME), `${JSON.stringify({ plugin: pluginName, skillId: skill.id }, null, 2)}
3490
+ `, "utf-8");
3491
+ written.push({ id: skill.id, pluginName, directory: dir });
3492
+ }
3493
+ return written;
3494
+ }
3495
+ var MARKER_FILENAME = ".rig-plugin", FRONTMATTER_RE;
3496
+ var init_skill_materializer = __esm(() => {
3497
+ FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
3498
+ });
3499
+
3500
+ // packages/harness-plugin/src/pi-settings-materializer.ts
3501
+ import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync7 } from "fs";
3502
+ import { dirname as dirname4, resolve as resolve10 } from "path";
3503
+ function readJson2(path, fallback) {
3504
+ if (!existsSync10(path))
3505
+ return fallback;
3506
+ try {
3507
+ return JSON.parse(readFileSync6(path, "utf-8"));
3508
+ } catch {
3509
+ return fallback;
3510
+ }
3511
+ }
3512
+ function packageKey2(entry) {
3513
+ if (typeof entry === "string")
3514
+ return entry;
3515
+ if (entry && typeof entry === "object" && typeof entry.source === "string") {
3516
+ return entry.source;
3517
+ }
3518
+ return JSON.stringify(entry);
3519
+ }
3520
+ function materializePiPackages(projectRoot, declaredPackages) {
3521
+ const settingsPath2 = resolve10(projectRoot, SETTINGS_RELATIVE_PATH);
3522
+ const managedRecordPath = resolve10(projectRoot, MANAGED_RECORD_RELATIVE_PATH);
3523
+ const settings = readJson2(settingsPath2, {});
3524
+ const previouslyManaged = new Set(readJson2(managedRecordPath, []));
3525
+ const existing = Array.isArray(settings.packages) ? settings.packages : [];
3526
+ const operatorEntries = existing.filter((entry) => !previouslyManaged.has(packageKey2(entry)));
3527
+ const operatorKeys = new Set(operatorEntries.map(packageKey2));
3528
+ const managedToAdd = declaredPackages.filter((pkg) => !operatorKeys.has(pkg));
3529
+ const nextPackages = [...operatorEntries, ...managedToAdd];
3530
+ if (nextPackages.length > 0 || existsSync10(settingsPath2)) {
3531
+ const nextSettings = { ...settings };
3532
+ if (nextPackages.length > 0) {
3533
+ nextSettings.packages = nextPackages;
3534
+ } else {
3535
+ delete nextSettings.packages;
3536
+ }
3537
+ mkdirSync7(dirname4(settingsPath2), { recursive: true });
3538
+ writeFileSync7(settingsPath2, `${JSON.stringify(nextSettings, null, 2)}
3539
+ `, "utf-8");
3540
+ }
3541
+ mkdirSync7(dirname4(managedRecordPath), { recursive: true });
3542
+ writeFileSync7(managedRecordPath, `${JSON.stringify(managedToAdd, null, 2)}
3543
+ `, "utf-8");
3544
+ return { settingsPath: settingsPath2, packages: managedToAdd };
3545
+ }
3546
+ var SETTINGS_RELATIVE_PATH = ".pi/settings.json", MANAGED_RECORD_RELATIVE_PATH = ".rig/state/pi-managed-packages.json";
3547
+ var init_pi_settings_materializer = () => {};
3548
+
3549
+ // packages/harness-plugin/src/session-asset-materializer-service.ts
3550
+ var exports_session_asset_materializer_service = {};
3551
+ __export(exports_session_asset_materializer_service, {
3552
+ sessionAssetMaterializer: () => sessionAssetMaterializer
3553
+ });
3554
+ import { existsSync as existsSync11 } from "fs";
3555
+ import { resolve as resolvePath } from "path";
3556
+ var sessionAssetMaterializer;
3557
+ var init_session_asset_materializer_service = __esm(() => {
3558
+ init_skill_materializer();
3559
+ init_pi_settings_materializer();
3560
+ sessionAssetMaterializer = {
3561
+ async materializeSessionAssets(projectRoot, config) {
3562
+ try {
3563
+ const skillEntries = config.plugins.flatMap((plugin) => (plugin.contributes?.skills ?? []).map((skill) => ({
3564
+ pluginName: plugin.name,
3565
+ skill
3566
+ })));
3567
+ if (skillEntries.length > 0) {
3568
+ await materializeSkills(projectRoot, skillEntries);
3569
+ }
3570
+ } catch (err) {
3571
+ console.warn(`[session-assets] skill materialization failed: ${err instanceof Error ? err.message : err}`);
3572
+ }
3573
+ try {
3574
+ const piPackages = config.runtime?.pi?.packages ?? [];
3575
+ if (piPackages.length > 0 || existsSync11(resolvePath(projectRoot, ".rig/state/pi-managed-packages.json"))) {
3576
+ materializePiPackages(projectRoot, piPackages);
3577
+ }
3578
+ } catch (err) {
3579
+ console.warn(`[session-assets] Pi package materialization failed: ${err instanceof Error ? err.message : err}`);
3580
+ }
3581
+ }
3582
+ };
3583
+ });
3584
+
3585
+ // packages/harness-plugin/src/session-hook-materializer-service.ts
3586
+ var exports_session_hook_materializer_service = {};
3587
+ __export(exports_session_hook_materializer_service, {
3588
+ sessionHookMaterializer: () => sessionHookMaterializer,
3589
+ materializeSessionHookAdapters: () => materializeSessionHookAdapters,
3590
+ materializeHooks: () => materializeHooks,
3591
+ defaultAgentSessionHookAdapters: () => defaultAgentSessionHookAdapters,
3592
+ createPiNoopSessionHookAdapter: () => createPiNoopSessionHookAdapter,
3593
+ createClaudeCodeSessionHookAdapter: () => createClaudeCodeSessionHookAdapter,
3594
+ applyClaudeCodeSessionHooksToSettings: () => applyClaudeCodeSessionHooksToSettings
3595
+ });
3596
+ import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync8 } from "fs";
3597
+ import { dirname as dirname5, resolve as resolve11 } from "path";
3598
+ import { buildTypedHookShimCommand } from "@rig/core/hook-materializer";
3599
+ function matcherToString(matcher) {
3600
+ if (matcher.kind === "all")
3601
+ return;
3602
+ if (matcher.kind === "tool")
3603
+ return matcher.name;
3604
+ return matcher.pattern;
3605
+ }
3606
+ function isPluginOwned(cmd) {
3607
+ return typeof cmd[MARKER_PLUGIN] === "string";
3608
+ }
3609
+ function createPiNoopSessionHookAdapter() {
3610
+ return {
3611
+ id: "pi",
3612
+ materialize() {
3613
+ return {
3614
+ adapterId: "pi",
3615
+ status: "skipped",
3616
+ reason: "Pi sessions do not consume Claude Code settings hooks."
3617
+ };
3618
+ }
3619
+ };
3620
+ }
3621
+ function createClaudeCodeSessionHookAdapter() {
3622
+ return {
3623
+ id: "claude-code",
3624
+ materialize(projectRoot, entries) {
3625
+ return writeClaudeCodeHookSettings(projectRoot, entries);
3626
+ }
3627
+ };
3628
+ }
3629
+ function defaultAgentSessionHookAdapters(env = process.env) {
3630
+ if (env.RIG_AGENT_SESSION_HOOK_ADAPTER === "claude-code") {
3631
+ return [createClaudeCodeSessionHookAdapter()];
3632
+ }
3633
+ if (env.RIG_AGENT_SESSION_HOOK_ADAPTER === "pi" || typeof env.PI_CODING_AGENT_SESSION_DIR === "string" && env.PI_CODING_AGENT_SESSION_DIR.trim().length > 0 || env.RIG_RUN_PROCESS === "1") {
3634
+ return [createPiNoopSessionHookAdapter()];
3635
+ }
3636
+ return [createClaudeCodeSessionHookAdapter()];
3637
+ }
3638
+ function materializeSessionHookAdapters(projectRoot, entries, adapters = defaultAgentSessionHookAdapters()) {
3639
+ return adapters.map((adapter) => adapter.materialize(projectRoot, entries));
3640
+ }
3641
+ function materializeHooks(projectRoot, entries) {
3642
+ const result = createClaudeCodeSessionHookAdapter().materialize(projectRoot, entries);
3643
+ return result.status === "materialized" ? result.path : resolve11(projectRoot, ".claude", "settings.json");
3644
+ }
3645
+ function applyClaudeCodeSessionHooksToSettings(existing, entries, projectRoot, options = {}) {
3646
+ const hooks = typeof existing.hooks === "object" && existing.hooks !== null && !Array.isArray(existing.hooks) ? existing.hooks : {};
3647
+ const replacePluginOwned = options.replacePluginOwned ?? true;
3648
+ if (replacePluginOwned) {
3649
+ for (const event of Object.keys(hooks)) {
3650
+ const groups = hooks[event] ?? [];
3651
+ const cleaned = [];
3652
+ for (const group of groups) {
3653
+ const operatorHooks = group.hooks.filter((h) => !isPluginOwned(h));
3654
+ if (operatorHooks.length > 0) {
3655
+ cleaned.push({ ...group, hooks: operatorHooks });
3656
+ }
3657
+ }
3658
+ if (cleaned.length > 0) {
3659
+ hooks[event] = cleaned;
3660
+ } else {
3661
+ delete hooks[event];
3662
+ }
3663
+ }
3664
+ }
3665
+ const materializedEvents = new Set;
3666
+ for (const { pluginName, hook, typed } of entries) {
3667
+ const command = hook.command ?? (typed ? buildTypedHookShimCommand(pluginName, hook, projectRoot) : undefined);
3668
+ if (!command) {
3669
+ continue;
3670
+ }
3671
+ const event = hook.event;
3672
+ materializedEvents.add(event);
3673
+ const matcherString = matcherToString(hook.matcher);
3674
+ const groups = hooks[event] ??= [];
3675
+ let group = groups.find((g) => g.matcher === matcherString);
3676
+ if (!group) {
3677
+ group = matcherString === undefined ? { hooks: [] } : { matcher: matcherString, hooks: [] };
3678
+ groups.push(group);
3679
+ }
3680
+ const alreadyPresent = group.hooks.some((candidate) => candidate[MARKER_PLUGIN] === pluginName && candidate[MARKER_HOOK_ID] === hook.id);
3681
+ if (alreadyPresent) {
3682
+ continue;
3683
+ }
3684
+ group.hooks.push({
3685
+ type: "command",
3686
+ command,
3687
+ [MARKER_PLUGIN]: pluginName,
3688
+ [MARKER_HOOK_ID]: hook.id
3689
+ });
3690
+ }
3691
+ const next = { ...existing };
3692
+ if (Object.keys(hooks).length > 0) {
3693
+ next.hooks = hooks;
3694
+ } else {
3695
+ delete next.hooks;
3696
+ }
3697
+ return { settings: next, events: [...materializedEvents].sort() };
3698
+ }
3699
+ function writeClaudeCodeHookSettings(projectRoot, entries) {
3700
+ const settingsPath2 = resolve11(projectRoot, ".claude", "settings.json");
3701
+ const existing = existsSync12(settingsPath2) ? safeReadJson(settingsPath2) : {};
3702
+ const { settings, events } = applyClaudeCodeSessionHooksToSettings(existing, entries, projectRoot);
3703
+ mkdirSync8(dirname5(settingsPath2), { recursive: true });
3704
+ writeFileSync8(settingsPath2, `${JSON.stringify(settings, null, 2)}
3705
+ `, "utf-8");
3706
+ return {
3707
+ adapterId: "claude-code",
3708
+ status: "materialized",
3709
+ path: settingsPath2,
3710
+ events
3711
+ };
3712
+ }
3713
+ function safeReadJson(path) {
3714
+ try {
3715
+ return JSON.parse(readFileSync7(path, "utf-8"));
3716
+ } catch {
3717
+ return {};
3718
+ }
3719
+ }
3720
+ var MARKER_PLUGIN = "_rigPlugin", MARKER_HOOK_ID = "_rigHookId", sessionHookMaterializer;
3721
+ var init_session_hook_materializer_service = __esm(() => {
3722
+ sessionHookMaterializer = {
3723
+ materializeSessionHooks(projectRoot, entries) {
3724
+ return materializeSessionHookAdapters(projectRoot, entries, defaultAgentSessionHookAdapters());
3725
+ }
3726
+ };
3727
+ });
3728
+
3729
+ // packages/harness-plugin/src/tooling/embedded-native-assets.ts
3730
+ var embeddedNatives = null;
3731
+
3732
+ // packages/harness-plugin/src/tooling/shell-tools.ts
3733
+ import { chmodSync, copyFileSync, existsSync as existsSync13, mkdirSync as mkdirSync9 } from "fs";
3734
+ import { tmpdir } from "os";
3735
+ import { basename as basename3, dirname as dirname6, resolve as resolve12 } from "path";
3736
+ import { RUNTIME_SHELL_TOOL_NAMES } from "@rig/contracts";
3737
+ import { getNativeExtractor } from "@rig/core/native-extract";
3738
+ function runtimeRigShellFileName() {
3739
+ return `rig-shell${process.platform === "win32" ? ".exe" : ""}`;
3740
+ }
3741
+ async function ensureRigShellBinaryPath(outputPath = sharedNativeShellOutputPath) {
3742
+ const explicitBin = process.env.RIG_NATIVE_SHELL_BIN?.trim();
3743
+ if (explicitBin && existsSync13(explicitBin)) {
3744
+ return explicitBin;
3745
+ }
3746
+ const embedded = extractEmbeddedNative("rig-shell");
3747
+ if (embedded) {
3748
+ return embedded;
3749
+ }
3750
+ const sourcePath = resolveRigShellSourcePath();
3751
+ if (!sourcePath) {
3752
+ const bundledBinary = resolveBundledRigShellBinaryPath();
3753
+ if (bundledBinary) {
3754
+ return bundledBinary;
3755
+ }
3756
+ throw new Error("rig-shell.zig source file not found.");
3757
+ }
3758
+ const zigBinary = Bun.which("zig");
3759
+ if (!zigBinary) {
3760
+ throw new Error("zig is required to build the native Rig shell.");
3761
+ }
3762
+ mkdirSync9(dirname6(outputPath), { recursive: true });
3763
+ const sourceDigest = await sha256File(sourcePath);
3764
+ const buildKey = JSON.stringify({
3765
+ version: 1,
3766
+ zigBinary,
3767
+ platform: process.platform,
3768
+ arch: process.arch,
3769
+ sourcePath,
3770
+ sourceDigest
3771
+ });
3772
+ const manifestPath = nativeBuildManifestPath(outputPath);
3773
+ const needsBuild = !existsSync13(outputPath) || !await hasMatchingNativeBuildManifest(manifestPath, buildKey);
3774
+ if (!needsBuild) {
3775
+ return outputPath;
3776
+ }
3777
+ const build = Bun.spawn([
3778
+ zigBinary,
3779
+ "build-exe",
3780
+ sourcePath,
3781
+ "-O",
3782
+ "ReleaseFast",
3783
+ `-femit-bin=${outputPath}`
3784
+ ], {
3785
+ cwd: dirname6(sourcePath),
3786
+ stdout: "pipe",
3787
+ stderr: "pipe"
3788
+ });
3789
+ const [exitCode, stdout, stderr] = await Promise.all([
3790
+ build.exited,
3791
+ new Response(build.stdout).text(),
3792
+ new Response(build.stderr).text()
3793
+ ]);
3794
+ if (exitCode !== 0 || !existsSync13(outputPath)) {
3795
+ const details = [stderr.trim(), stdout.trim()].filter(Boolean).join(`
3796
+ `);
3797
+ throw new Error(`Failed to build native Rig shell: ${details || `zig exited with code ${exitCode}`}`);
3798
+ }
3799
+ await Bun.write(manifestPath, `${JSON.stringify({ version: 1, buildKey }, null, 2)}
3800
+ `);
3801
+ return outputPath;
3802
+ }
3803
+ async function materializeRigShellBinary(targetDir) {
3804
+ const sourcePath = await ensureRigShellBinaryPath();
3805
+ const targetPath = resolve12(targetDir, runtimeRigShellFileName());
3806
+ mkdirSync9(targetDir, { recursive: true });
3807
+ const sourceDigest = await sha256File(sourcePath);
3808
+ const buildKey = JSON.stringify({
3809
+ version: 1,
3810
+ sourcePath,
3811
+ sourceDigest
3812
+ });
3813
+ const needsCopy = !existsSync13(targetPath) || !await hasMatchingNativeBuildManifest(nativeBuildManifestPath(targetPath), buildKey);
3814
+ if (needsCopy) {
3815
+ copyFileSync(sourcePath, targetPath);
3816
+ chmodSync(targetPath, 493);
3817
+ await Bun.write(nativeBuildManifestPath(targetPath), `${JSON.stringify({ version: 1, buildKey }, null, 2)}
3818
+ `);
3819
+ }
3820
+ return targetPath;
3821
+ }
3822
+ function resolveRigShellSourcePath() {
3823
+ for (const candidate of rigShellSourceCandidates()) {
3824
+ if (candidate && existsSync13(candidate)) {
3825
+ return candidate;
3826
+ }
3827
+ }
3828
+ return null;
3829
+ }
3830
+ function resolveBundledRigShellBinaryPath() {
3831
+ for (const candidate of rigShellBinaryCandidates()) {
3832
+ if (candidate && existsSync13(candidate)) {
3833
+ return candidate;
3834
+ }
3835
+ }
3836
+ return null;
3837
+ }
3838
+ function rigShellSourceCandidates() {
3839
+ const execDir = process.execPath?.trim() ? dirname6(process.execPath.trim()) : "";
3840
+ const cwd = process.cwd()?.trim() || "";
3841
+ const projectRoot = process.env.PROJECT_RIG_ROOT?.trim() || "";
3842
+ const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || "";
3843
+ return [...new Set([
3844
+ process.env.RIG_NATIVE_SHELL_SOURCE?.trim() || "",
3845
+ cwd ? resolve12(cwd, "packages/harness-plugin/native/rig-shell.zig") : "",
3846
+ projectRoot ? resolve12(projectRoot, "packages/harness-plugin/native/rig-shell.zig") : "",
3847
+ hostProjectRoot ? resolve12(hostProjectRoot, "packages/harness-plugin/native/rig-shell.zig") : "",
3848
+ execDir ? resolve12(execDir, "..", "..", "packages/harness-plugin/native/rig-shell.zig") : "",
3849
+ execDir ? resolve12(execDir, "..", "native", "rig-shell.zig") : "",
3850
+ resolve12(import.meta.dir, "../../native/rig-shell.zig")
3851
+ ].filter(Boolean))];
3852
+ }
3853
+ function nativePackageBinaryCandidates(fromDir, fileName) {
3854
+ const candidates = [];
3855
+ let cursor = resolve12(fromDir);
3856
+ for (let index = 0;index < 8; index += 1) {
3857
+ candidates.push(resolve12(cursor, "native", `${process.platform}-${process.arch}`, fileName), resolve12(cursor, "native", `${process.platform}-${process.arch}`, "bin", fileName), resolve12(cursor, "native", fileName), resolve12(cursor, "native", "bin", fileName));
3858
+ const parent = dirname6(cursor);
3859
+ if (parent === cursor)
3860
+ break;
3861
+ cursor = parent;
3862
+ }
3863
+ return candidates;
3864
+ }
3865
+ function rigShellBinaryCandidates() {
3866
+ const execDir = process.execPath?.trim() ? dirname6(process.execPath.trim()) : "";
3867
+ const fileName = runtimeRigShellFileName();
3868
+ return [...new Set([
3869
+ process.env.RIG_NATIVE_SHELL_BIN?.trim() || "",
3870
+ ...nativePackageBinaryCandidates(import.meta.dir, fileName),
3871
+ execDir ? resolve12(execDir, fileName) : "",
3872
+ execDir ? resolve12(execDir, "..", fileName) : "",
3873
+ execDir ? resolve12(execDir, "..", "bin", fileName) : ""
3874
+ ].filter(Boolean))];
3875
+ }
3876
+ function nativeBuildManifestPath(outputPath) {
3877
+ return `${outputPath}.build-manifest.json`;
3878
+ }
3879
+ async function hasMatchingNativeBuildManifest(manifestPath, buildKey) {
3880
+ if (!existsSync13(manifestPath)) {
3881
+ return false;
3882
+ }
3883
+ try {
3884
+ const manifest = await Bun.file(manifestPath).json();
3885
+ return manifest.version === 1 && manifest.buildKey === buildKey;
3886
+ } catch {
3887
+ return false;
3888
+ }
3889
+ }
3890
+ async function sha256File(path) {
3891
+ const hasher = new Bun.CryptoHasher("sha256");
3892
+ hasher.update(await Bun.file(path).arrayBuffer());
3893
+ return hasher.digest("hex");
3894
+ }
3895
+ var extractEmbeddedNative, sharedNativeShellOutputDir, sharedNativeShellOutputPath;
3896
+ var init_shell_tools = __esm(() => {
3897
+ ({ extractEmbeddedNative } = getNativeExtractor(embeddedNatives));
3898
+ sharedNativeShellOutputDir = resolve12(tmpdir(), "rig-native");
3899
+ sharedNativeShellOutputPath = resolve12(sharedNativeShellOutputDir, `rig-shell-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
3900
+ });
3901
+
3902
+ // packages/harness-plugin/src/tooling/browser-tools.ts
3903
+ var exports_browser_tools = {};
3904
+ __export(exports_browser_tools, {
3905
+ runtimeBrowserToolNames: () => runtimeBrowserToolNames,
3906
+ runtimeBrowserToolBinaryName: () => runtimeBrowserToolBinaryName,
3907
+ materializeRuntimeBrowserTools: () => materializeRuntimeBrowserTools
3908
+ });
3909
+ import { existsSync as existsSync14, rmSync as rmSync3, symlinkSync } from "fs";
3910
+ import { resolve as resolve13 } from "path";
3911
+ import { RUNTIME_BROWSER_TOOL_NAMES } from "@rig/contracts";
3912
+ function runtimeBrowserToolBinaryName() {
3913
+ return `rig-browser-tool${process.platform === "win32" ? ".exe" : ""}`;
3914
+ }
3915
+ function runtimeBrowserToolNames() {
3916
+ return [...RUNTIME_BROWSER_TOOL_NAMES];
3917
+ }
3918
+ async function materializeRuntimeBrowserTools(targetDir) {
3919
+ const binaryPath = resolve13(targetDir, runtimeBrowserToolBinaryName());
3920
+ for (const tool of runtimeBrowserToolNames()) {
3921
+ const toolPath = resolve13(targetDir, tool);
3922
+ if (existsSync14(toolPath)) {
3923
+ rmSync3(toolPath, { force: true, recursive: true });
3924
+ }
3925
+ symlinkSync(binaryPath, toolPath);
3926
+ }
3927
+ return binaryPath;
3928
+ }
3929
+ var init_browser_tools = () => {};
3930
+
3931
+ // packages/harness-plugin/src/tooling/file-tools.ts
3932
+ var exports_file_tools = {};
3933
+ __export(exports_file_tools, {
3934
+ runtimeRigToolsFileName: () => runtimeRigToolsFileName,
3935
+ runtimeFileToolNames: () => runtimeFileToolNames,
3936
+ runtimeFileToolBasename: () => runtimeFileToolBasename,
3937
+ materializeRuntimeFileTools: () => materializeRuntimeFileTools,
3938
+ ensureRigToolsBinaryPath: () => ensureRigToolsBinaryPath
3939
+ });
3940
+ import { chmodSync as chmodSync2, copyFileSync as copyFileSync2, existsSync as existsSync15, mkdirSync as mkdirSync10, rmSync as rmSync4, symlinkSync as symlinkSync2 } from "fs";
3941
+ import { tmpdir as tmpdir2 } from "os";
3942
+ import { basename as basename4, dirname as dirname7, resolve as resolve14 } from "path";
3943
+ import { RUNTIME_FILE_TOOL_NAMES } from "@rig/contracts";
3944
+ import { getNativeExtractor as getNativeExtractor2 } from "@rig/core/native-extract";
3945
+ function runtimeRigToolsFileName() {
3946
+ return `rig-tools${process.platform === "win32" ? ".exe" : ""}`;
3947
+ }
3948
+ function runtimeFileToolNames() {
3949
+ return [...RUNTIME_FILE_TOOL_NAMES];
3950
+ }
3951
+ async function ensureRigToolsBinaryPath(outputPath = sharedNativeToolsOutputPath) {
3952
+ const explicitBin = process.env.RIG_NATIVE_TOOLS_BIN?.trim();
3953
+ if (explicitBin && existsSync15(explicitBin)) {
3954
+ return explicitBin;
3955
+ }
3956
+ const embedded = extractEmbeddedNative2("rig-tools");
3957
+ if (embedded) {
3958
+ return embedded;
3959
+ }
3960
+ const sourcePath = resolveRigToolsSourcePath();
3961
+ if (!sourcePath) {
3962
+ const bundledBinary = resolveBundledRigToolsBinaryPath();
3963
+ if (bundledBinary) {
3964
+ return bundledBinary;
3965
+ }
3966
+ throw new Error("rig-tools.zig source file not found.");
3967
+ }
3968
+ const zigBinary = Bun.which("zig");
3969
+ if (!zigBinary) {
3970
+ throw new Error("zig is required to build native Rig file tools.");
3971
+ }
3972
+ mkdirSync10(dirname7(outputPath), { recursive: true });
3973
+ const sourceDigest = await sha256File2(sourcePath);
3974
+ const buildKey = JSON.stringify({
3975
+ version: 1,
3976
+ zigBinary,
3977
+ platform: process.platform,
3978
+ arch: process.arch,
3979
+ sourcePath,
3980
+ sourceDigest
3981
+ });
3982
+ const manifestPath = nativeBuildManifestPath2(outputPath);
3983
+ const needsBuild = !existsSync15(outputPath) || !await hasMatchingNativeBuildManifest2(manifestPath, buildKey);
3984
+ if (!needsBuild) {
3985
+ return outputPath;
3986
+ }
3987
+ const build = Bun.spawn([
3988
+ zigBinary,
3989
+ "build-exe",
3990
+ sourcePath,
3991
+ "-O",
3992
+ "ReleaseFast",
3993
+ `-femit-bin=${outputPath}`
3994
+ ], {
3995
+ cwd: dirname7(sourcePath),
3996
+ stdout: "pipe",
3997
+ stderr: "pipe"
3998
+ });
3999
+ const [exitCode, stdout, stderr] = await Promise.all([
4000
+ build.exited,
4001
+ new Response(build.stdout).text(),
4002
+ new Response(build.stderr).text()
4003
+ ]);
4004
+ if (exitCode !== 0 || !existsSync15(outputPath)) {
4005
+ const details = [stderr.trim(), stdout.trim()].filter(Boolean).join(`
4006
+ `);
4007
+ throw new Error(`Failed to build native Rig file tools: ${details || `zig exited with code ${exitCode}`}`);
4008
+ }
4009
+ await Bun.write(manifestPath, `${JSON.stringify({ version: 1, buildKey }, null, 2)}
4010
+ `);
4011
+ return outputPath;
4012
+ }
4013
+ async function materializeRuntimeFileTools(targetDir) {
4014
+ const sourcePath = await ensureRigToolsBinaryPath();
4015
+ const targetPath = resolve14(targetDir, runtimeRigToolsFileName());
4016
+ mkdirSync10(targetDir, { recursive: true });
4017
+ const sourceDigest = await sha256File2(sourcePath);
4018
+ const buildKey = JSON.stringify({
4019
+ version: 1,
4020
+ sourcePath,
4021
+ sourceDigest
4022
+ });
4023
+ const needsCopy = !existsSync15(targetPath) || !await hasMatchingNativeBuildManifest2(nativeBuildManifestPath2(targetPath), buildKey);
4024
+ if (needsCopy) {
4025
+ copyFileSync2(sourcePath, targetPath);
4026
+ chmodSync2(targetPath, 493);
4027
+ await Bun.write(nativeBuildManifestPath2(targetPath), `${JSON.stringify({ version: 1, buildKey }, null, 2)}
4028
+ `);
4029
+ }
4030
+ for (const tool of runtimeFileToolNames()) {
4031
+ const toolPath = resolve14(targetDir, tool);
4032
+ if (existsSync15(toolPath)) {
4033
+ rmSync4(toolPath, { force: true, recursive: true });
4034
+ }
4035
+ symlinkSync2(targetPath, toolPath);
4036
+ }
4037
+ return targetPath;
4038
+ }
4039
+ function resolveRigToolsSourcePath() {
4040
+ for (const candidate of rigToolsSourceCandidates()) {
4041
+ if (candidate && existsSync15(candidate)) {
4042
+ return candidate;
4043
+ }
4044
+ }
4045
+ return null;
4046
+ }
4047
+ function resolveBundledRigToolsBinaryPath() {
4048
+ for (const candidate of rigToolsBinaryCandidates()) {
4049
+ if (candidate && existsSync15(candidate)) {
4050
+ return candidate;
4051
+ }
4052
+ }
4053
+ return null;
4054
+ }
4055
+ function rigToolsSourceCandidates() {
4056
+ const execDir = process.execPath?.trim() ? dirname7(process.execPath.trim()) : "";
4057
+ const cwd = process.cwd()?.trim() || "";
4058
+ const projectRoot = process.env.PROJECT_RIG_ROOT?.trim() || "";
4059
+ const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || "";
4060
+ return [...new Set([
4061
+ process.env.RIG_NATIVE_TOOLS_SOURCE?.trim() || "",
4062
+ cwd ? resolve14(cwd, "packages/harness-plugin/native/rig-tools.zig") : "",
4063
+ projectRoot ? resolve14(projectRoot, "packages/harness-plugin/native/rig-tools.zig") : "",
4064
+ hostProjectRoot ? resolve14(hostProjectRoot, "packages/harness-plugin/native/rig-tools.zig") : "",
4065
+ execDir ? resolve14(execDir, "..", "..", "packages/harness-plugin/native/rig-tools.zig") : "",
4066
+ execDir ? resolve14(execDir, "..", "native", "rig-tools.zig") : "",
4067
+ resolve14(import.meta.dir, "../../native/rig-tools.zig")
4068
+ ].filter(Boolean))];
4069
+ }
4070
+ function nativePackageBinaryCandidates2(fromDir, fileName) {
4071
+ const candidates = [];
4072
+ let cursor = resolve14(fromDir);
4073
+ for (let index = 0;index < 8; index += 1) {
4074
+ candidates.push(resolve14(cursor, "native", `${process.platform}-${process.arch}`, fileName), resolve14(cursor, "native", `${process.platform}-${process.arch}`, "bin", fileName), resolve14(cursor, "native", fileName), resolve14(cursor, "native", "bin", fileName));
4075
+ const parent = dirname7(cursor);
4076
+ if (parent === cursor)
4077
+ break;
4078
+ cursor = parent;
4079
+ }
4080
+ return candidates;
4081
+ }
4082
+ function rigToolsBinaryCandidates() {
4083
+ const execDir = process.execPath?.trim() ? dirname7(process.execPath.trim()) : "";
4084
+ const fileName = runtimeRigToolsFileName();
4085
+ return [...new Set([
4086
+ process.env.RIG_NATIVE_TOOLS_BIN?.trim() || "",
4087
+ ...nativePackageBinaryCandidates2(import.meta.dir, fileName),
4088
+ execDir ? resolve14(execDir, fileName) : "",
4089
+ execDir ? resolve14(execDir, "..", fileName) : "",
4090
+ execDir ? resolve14(execDir, "..", "bin", fileName) : ""
4091
+ ].filter(Boolean))];
4092
+ }
4093
+ function runtimeFileToolBasename(path) {
4094
+ return basename4(path);
4095
+ }
4096
+ function nativeBuildManifestPath2(outputPath) {
4097
+ return `${outputPath}.build-manifest.json`;
4098
+ }
4099
+ async function hasMatchingNativeBuildManifest2(manifestPath, buildKey) {
4100
+ if (!existsSync15(manifestPath)) {
4101
+ return false;
4102
+ }
4103
+ try {
4104
+ const manifest = await Bun.file(manifestPath).json();
4105
+ return manifest.version === 1 && manifest.buildKey === buildKey;
4106
+ } catch {
4107
+ return false;
4108
+ }
4109
+ }
4110
+ async function sha256File2(path) {
4111
+ const hasher = new Bun.CryptoHasher("sha256");
4112
+ hasher.update(await Bun.file(path).arrayBuffer());
4113
+ return hasher.digest("hex");
4114
+ }
4115
+ var extractEmbeddedNative2, sharedNativeToolsOutputDir, sharedNativeToolsOutputPath;
4116
+ var init_file_tools = __esm(() => {
4117
+ ({ extractEmbeddedNative: extractEmbeddedNative2 } = getNativeExtractor2(embeddedNatives));
4118
+ sharedNativeToolsOutputDir = resolve14(tmpdir2(), "rig-native");
4119
+ sharedNativeToolsOutputPath = resolve14(sharedNativeToolsOutputDir, `rig-tools-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
4120
+ });
4121
+
4122
+ // packages/harness-plugin/src/tooling/gateway.ts
4123
+ var exports_gateway = {};
4124
+ __export(exports_gateway, {
4125
+ runtimeGatewayToolNames: () => runtimeGatewayToolNames,
4126
+ runtimeFileToolNames: () => runtimeFileToolNames,
4127
+ runtimeBrowserToolNames: () => runtimeBrowserToolNames,
4128
+ materializeRuntimeToolGateway: () => materializeRuntimeToolGateway,
4129
+ materializeRuntimeFileTools: () => materializeRuntimeFileTools,
4130
+ materializeRuntimeBrowserTools: () => materializeRuntimeBrowserTools
4131
+ });
4132
+ import { existsSync as existsSync16, rmSync as rmSync5, symlinkSync as symlinkSync3 } from "fs";
4133
+ import { resolve as resolve15 } from "path";
4134
+ import { RUNTIME_SHELL_TOOL_NAMES as RUNTIME_SHELL_TOOL_NAMES2 } from "@rig/contracts";
4135
+ function runtimeGatewayToolNames() {
4136
+ return [...RUNTIME_SHELL_TOOL_NAMES2];
4137
+ }
4138
+ async function materializeRuntimeToolGateway(binDir) {
4139
+ const shellPath = await materializeRigShellBinary(binDir);
4140
+ for (const tool of runtimeGatewayToolNames()) {
4141
+ const toolPath = resolve15(binDir, tool);
4142
+ if (existsSync16(toolPath)) {
4143
+ rmSync5(toolPath, { force: true, recursive: true });
4144
+ }
4145
+ symlinkSync3(shellPath, toolPath);
4146
+ }
4147
+ await materializeRuntimeBrowserTools(binDir);
4148
+ return resolve15(binDir, runtimeRigShellFileName());
4149
+ }
4150
+ var init_gateway = __esm(() => {
4151
+ init_shell_tools();
4152
+ init_browser_tools();
4153
+ init_browser_tools();
4154
+ init_file_tools();
4155
+ });
4156
+
4157
+ // packages/harness-plugin/src/tooling/claude-router-binary.ts
4158
+ var exports_claude_router_binary = {};
4159
+ __export(exports_claude_router_binary, {
4160
+ runtimeClaudeToolRouterFileName: () => runtimeClaudeToolRouterFileName,
4161
+ materializeClaudeToolRouterBinary: () => materializeClaudeToolRouterBinary,
4162
+ ensureClaudeToolRouterBinaryPath: () => ensureClaudeToolRouterBinaryPath
4163
+ });
4164
+ import { chmodSync as chmodSync3, copyFileSync as copyFileSync3, existsSync as existsSync17, mkdirSync as mkdirSync11, statSync as statSync3 } from "fs";
4165
+ import { tmpdir as tmpdir3 } from "os";
4166
+ import { dirname as dirname8, resolve as resolve16 } from "path";
4167
+ import { getNativeExtractor as getNativeExtractor3 } from "@rig/core/native-extract";
4168
+ function runtimeClaudeToolRouterFileName() {
4169
+ return `rig-tool-router${process.platform === "win32" ? ".exe" : ""}`;
4170
+ }
4171
+ async function requireNativeToolchainRuntimeBinaryBuild(_projectRoot) {
4172
+ const { runtimeBinaryBuildService } = await import("@rig/core/native-toolchain/runtime-binary-build");
4173
+ return runtimeBinaryBuildService;
4174
+ }
4175
+ async function ensureClaudeToolRouterBinaryPath(projectRoot, outputPath = sharedRouterOutputPath) {
4176
+ const sourcePath = resolve16(projectRoot, "packages/harness-plugin/src/tooling/claude-router.ts");
4177
+ mkdirSync11(dirname8(outputPath), { recursive: true });
4178
+ const needsBuild = !existsSync17(outputPath) || statSync3(sourcePath).mtimeMs > statSync3(outputPath).mtimeMs;
4179
+ if (!needsBuild) {
4180
+ return outputPath;
4181
+ }
4182
+ const service = await requireNativeToolchainRuntimeBinaryBuild(projectRoot);
4183
+ const engine = service.createRuntimeBinaryBuildEngine({ embeddedNatives });
4184
+ await engine.buildRuntimeBinary({
4185
+ sourcePath: "packages/harness-plugin/src/tooling/claude-router.ts",
4186
+ outputPath,
4187
+ cwd: projectRoot
4188
+ });
4189
+ chmodSync3(outputPath, 493);
4190
+ return outputPath;
4191
+ }
4192
+ async function materializeClaudeToolRouterBinary(projectRoot, targetDir) {
4193
+ if (hasEmbeddedNatives()) {
4194
+ const targetPath2 = resolve16(targetDir, runtimeClaudeToolRouterFileName());
4195
+ const service = await requireNativeToolchainRuntimeBinaryBuild(projectRoot);
4196
+ service.materializeSelfExecRole(targetPath2);
4197
+ return targetPath2;
4198
+ }
4199
+ const sourcePath = await ensureClaudeToolRouterBinaryPath(projectRoot);
4200
+ const targetPath = resolve16(targetDir, runtimeClaudeToolRouterFileName());
4201
+ mkdirSync11(targetDir, { recursive: true });
4202
+ const needsCopy = !existsSync17(targetPath) || statSync3(sourcePath).mtimeMs > statSync3(targetPath).mtimeMs;
4203
+ if (needsCopy) {
4204
+ copyFileSync3(sourcePath, targetPath);
4205
+ chmodSync3(targetPath, 493);
4206
+ }
4207
+ return targetPath;
4208
+ }
4209
+ var hasEmbeddedNatives, sharedRouterOutputDir, sharedRouterOutputPath;
4210
+ var init_claude_router_binary = __esm(() => {
4211
+ ({ hasEmbeddedNatives } = getNativeExtractor3(embeddedNatives));
4212
+ sharedRouterOutputDir = resolve16(tmpdir3(), "rig-native");
4213
+ sharedRouterOutputPath = resolve16(sharedRouterOutputDir, `rig-tool-router-${process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`);
4214
+ });
4215
+
4216
+ // packages/harness-plugin/src/plugin.ts
4217
+ import { definePlugin } from "@rig/core/config";
4218
+ import { defineCapability as defineCapability8 } from "@rig/core/capability";
4219
+ import { AGENT_HARNESS, HARNESS_PROFILE_STATE as HARNESS_PROFILE_STATE2, RUNTIME_INSTRUCTION, RUNTIME_SECRETS, SESSION_ASSET_MATERIALIZER, SESSION_HOOK_MATERIALIZER, TOOL_MATERIALIZER } from "@rig/contracts";
4220
+
4221
+ // packages/harness-plugin/src/model.ts
4222
+ import { Schema } from "effect";
4223
+ var CODEX_REASONING_EFFORT_OPTIONS = ["xhigh", "high", "medium", "low"];
4224
+ var CodexModelOptions = Schema.Struct({
4225
+ reasoningEffort: Schema.optional(Schema.Literals(CODEX_REASONING_EFFORT_OPTIONS)),
4226
+ fastMode: Schema.optional(Schema.Boolean)
4227
+ });
4228
+ var ClaudeModelOptions = Schema.Struct({});
4229
+ var ProviderModelOptions = Schema.Struct({
4230
+ codex: Schema.optional(CodexModelOptions),
4231
+ claude: Schema.optional(ClaudeModelOptions)
4232
+ });
4233
+ var MODEL_OPTIONS_BY_PROVIDER = {
4234
+ codex: [
4235
+ { slug: "gpt-5.4", name: "GPT-5.4" },
4236
+ { slug: "gpt-5.3-codex", name: "GPT-5.3 Codex" },
4237
+ { slug: "gpt-5.3-codex-spark", name: "GPT-5.3 Codex Spark" },
4238
+ { slug: "gpt-5.2-codex", name: "GPT-5.2 Codex" },
4239
+ { slug: "gpt-5.2", name: "GPT-5.2" }
4240
+ ],
4241
+ claude: [
4242
+ { slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" },
4243
+ { slug: "claude-opus-4-1", name: "Claude Opus 4.1" },
4244
+ { slug: "claude-3-7-sonnet-latest", name: "Claude 3.7 Sonnet" }
4245
+ ]
4246
+ };
4247
+ var DEFAULT_MODEL_BY_PROVIDER = {
4248
+ codex: "gpt-5.4",
4249
+ claude: "claude-sonnet-4-6"
4250
+ };
4251
+ var MODEL_SLUG_ALIASES_BY_PROVIDER = {
4252
+ codex: {
4253
+ "5.4": "gpt-5.4",
4254
+ "5.3": "gpt-5.3-codex",
4255
+ "gpt-5.3": "gpt-5.3-codex",
4256
+ "5.3-spark": "gpt-5.3-codex-spark",
4257
+ "gpt-5.3-spark": "gpt-5.3-codex-spark"
4258
+ },
4259
+ claude: {
4260
+ sonnet: "claude-sonnet-4-6",
4261
+ opus: "claude-opus-4-1",
4262
+ "3.7-sonnet": "claude-3-7-sonnet-latest"
4263
+ }
4264
+ };
4265
+ var REASONING_EFFORT_OPTIONS_BY_PROVIDER = {
4266
+ codex: CODEX_REASONING_EFFORT_OPTIONS,
4267
+ claude: []
4268
+ };
4269
+ var DEFAULT_REASONING_EFFORT_BY_PROVIDER = {
4270
+ codex: "high",
4271
+ claude: null
4272
+ };
4273
+
4274
+ // packages/harness-plugin/src/plugin.ts
4275
+ var PROVIDER_PLUGIN_NAME = "@rig/harness-plugin";
4276
+ var DEFAULT_PROVIDER_KIND = "codex";
4277
+ var DEFAULT_RUNTIME_MODE = "full-access";
4278
+ var DEFAULT_PROVIDER_INTERACTION_MODE = "default";
4279
+ var RuntimeInstructionCap = defineCapability8(RUNTIME_INSTRUCTION);
4280
+ var AgentHarnessCap = defineCapability8(AGENT_HARNESS);
4281
+ var HarnessProfileStateCap2 = defineCapability8(HARNESS_PROFILE_STATE2);
4282
+ var RuntimeSecretsCap = defineCapability8(RUNTIME_SECRETS);
4283
+ var SessionAssetMaterializerCap = defineCapability8(SESSION_ASSET_MATERIALIZER);
4284
+ var SessionHookMaterializerCap = defineCapability8(SESSION_HOOK_MATERIALIZER);
4285
+ var ToolMaterializerCap = defineCapability8(TOOL_MATERIALIZER);
4286
+ var PROVIDER_SEED_ENTRYPOINTS = [
4287
+ {
4288
+ id: `${PROVIDER_PLUGIN_NAME}:rig-agent`,
4289
+ basename: "rig-agent",
4290
+ description: "Provider-owned per-runtime Rig agent entrypoint.",
4291
+ run: async (context) => {
4292
+ const args = [...context.argv].slice(2);
4293
+ if (args.length === 0 || args[0] === "--help" || args[0] === "help" || args[0] === "--version" || args[0] === "-V") {
4294
+ console.log("[rig-agent] runtime shim ready");
4295
+ return 0;
4296
+ }
4297
+ const { runRigAgentEntrypoint: runRigAgentEntrypoint2 } = await Promise.resolve().then(() => (init_rig_agent_entrypoint(), exports_rig_agent_entrypoint));
4298
+ await runRigAgentEntrypoint2();
4299
+ }
4300
+ },
4301
+ {
4302
+ id: `${PROVIDER_PLUGIN_NAME}:rig-agent-dispatch`,
4303
+ basename: "rig-agent-dispatch",
4304
+ description: "Provider-owned agent dispatch/provisioning shim.",
4305
+ run: async (context) => {
4306
+ const { runAgentWrapper: runAgentWrapper2 } = await Promise.resolve().then(() => (init_agent_wrapper(), exports_agent_wrapper));
4307
+ const exitCode = await runAgentWrapper2({ argv: [...context.argv].slice(2) });
4308
+ return exitCode;
4309
+ }
4310
+ },
4311
+ {
4312
+ id: `${PROVIDER_PLUGIN_NAME}:rig-browser-tool`,
4313
+ basename: "rig-browser-tool",
4314
+ description: "Provider-owned runtime browser helper shim.",
4315
+ run: async (context) => {
4316
+ const args = [...context.argv].slice(2);
4317
+ if (args.length === 0 || args[0] === "--help" || args[0] === "help" || args[0] === "--version" || args[0] === "-V") {
4318
+ console.log("[rig-browser-tool] runtime shim ready");
4319
+ return 0;
4320
+ }
4321
+ if (context.execPath)
4322
+ process.argv[1] = context.execPath;
4323
+ else if (context.basename)
4324
+ process.argv[1] = context.basename;
4325
+ await Promise.resolve().then(() => (init_browser_tool_entrypoint(), exports_browser_tool_entrypoint));
4326
+ }
4327
+ },
4328
+ {
4329
+ id: `${PROVIDER_PLUGIN_NAME}:rig-tool-router`,
4330
+ basename: "rig-tool-router",
4331
+ description: "Claude-compatible provider tool router sidecar.",
4332
+ run: async () => {
4333
+ const { runClaudeToolRouterServer: runClaudeToolRouterServer2 } = await init_claude_router().then(() => exports_claude_router);
4334
+ await runClaudeToolRouterServer2();
4335
+ }
4336
+ }
4337
+ ];
4338
+ var piCommand = {
4339
+ id: `${PROVIDER_PLUGIN_NAME}:pi`,
4340
+ family: "pi",
4341
+ description: "Inspect Pi/OMP runtime integration.",
4342
+ projectRequired: false,
4343
+ helpDoc: {
4344
+ name: "pi",
4345
+ summary: "Manage Pi extension packages for this project (community extensions from npm/git).",
4346
+ usage: ["rig pi <list|add|remove|search> [args]"],
4347
+ commands: [
4348
+ { command: "list", description: "Show project and user Pi extension packages." },
4349
+ { command: "add <source>", description: "Add an npm/git Pi extension to .pi/settings.json (auto-installs at next session)." },
4350
+ { command: "remove <source>", description: "Remove an operator-added Pi extension." },
4351
+ { command: "search [term]", description: "Discover Pi extension packages on the npm registry." }
4352
+ ],
4353
+ examples: ["rig pi search subagents", "rig pi add pi-subagents", "rig pi list"],
4354
+ next: ["Config-managed extensions: declare `runtime: { pi: { packages: [...] } }` in rig.config.ts \u2014 workers pick them up automatically."],
4355
+ advancedOnly: true
4356
+ },
4357
+ run: async (context, args) => (await Promise.resolve().then(() => (init_pi_command(), exports_pi_command))).executePi(context, [...args])
4358
+ };
4359
+ var profileCommand = {
4360
+ id: `${PROVIDER_PLUGIN_NAME}:profile`,
4361
+ family: "profile",
4362
+ description: "Manage runtime profile settings.",
4363
+ projectRequired: false,
4364
+ helpDoc: {
4365
+ name: "profile",
4366
+ summary: "Runtime profile/model defaults.",
4367
+ usage: ["rig profile <show|set>"],
4368
+ commands: [
4369
+ { command: "show", description: "Show the active execution profile.", primary: true },
4370
+ { command: "set [--model <model>] [--runtime <runtime>] [--plugin <plugin>]", description: "Set model/runtime/plugin profile defaults.", primary: true }
4371
+ ],
4372
+ advancedOnly: true
4373
+ },
4374
+ run: async (context, args) => (await Promise.resolve().then(() => (init_profile_command(), exports_profile_command))).executeProfile(context, [...args])
4375
+ };
4376
+ var agentCommand = {
4377
+ id: `${PROVIDER_PLUGIN_NAME}:agent`,
4378
+ family: "agent",
4379
+ description: "Run agent lifecycle helpers.",
4380
+ projectRequired: true,
4381
+ helpDoc: {
4382
+ name: "agent",
4383
+ summary: "Runtime agent workspace helpers.",
4384
+ usage: ["rig agent <list|prepare|run|cleanup>"],
4385
+ commands: [
4386
+ { command: "list", description: "List prepared agent runtimes.", primary: true },
4387
+ { command: "prepare [--id <id>] [--mode <mode>] [--task <task>]", description: "Prepare an isolated agent runtime workspace.", primary: true },
4388
+ { command: "run [--id <id>] [--mode <mode>] [--task <task>] [--skip-project-sync]", description: "Prepare (if needed) and run an agent in its workspace.", primary: true },
4389
+ { command: "cleanup [--all] [--id <id>]", description: "Remove prepared agent workspaces.", primary: true }
4390
+ ],
4391
+ advancedOnly: true
4392
+ },
4393
+ run: async (context, args) => (await Promise.resolve().then(() => (init_agent_command(), exports_agent_command))).executeAgent(context, [...args])
4394
+ };
4395
+ var providerPlugin = definePlugin({
4396
+ name: PROVIDER_PLUGIN_NAME,
4397
+ version: "0.0.0-alpha.1",
4398
+ effects: {
4399
+ readsFiles: true,
4400
+ writesFiles: true,
4401
+ spawnsProcesses: true,
4402
+ opensNetwork: true,
4403
+ contributesCliCommands: true
4404
+ },
4405
+ contributes: {
4406
+ cliCommands: [piCommand, profileCommand, agentCommand],
4407
+ capabilities: [
4408
+ RuntimeInstructionCap.provide(async () => (await Promise.resolve().then(() => (init_service(), exports_service))).svc, {
4409
+ title: "Agent harness provider instructions",
4410
+ description: "Provide the agent-harness file-tool contract and runtime-context instruction lines."
4411
+ }),
4412
+ RuntimeSecretsCap.provide(async () => (await Promise.resolve().then(() => (init_runtime_secrets(), exports_runtime_secrets))).runtimeSecretsService, {
4413
+ title: "Runtime secrets",
4414
+ description: "Provider-owned runtime/review secret key resolution and baked define materialization."
4415
+ }),
4416
+ HarnessProfileStateCap2.provide(async () => (await Promise.resolve().then(() => (init_profile_state(), exports_profile_state))).harnessProfileStateService, {
4417
+ title: "Harness profile state",
4418
+ description: "Provider-owned execution/review profile state path and JSON persistence."
4419
+ }),
4420
+ AgentHarnessCap.provide(async () => ({
4421
+ resolveAgentWrapperEntrypoint: () => "packages/harness-plugin/src/agent-harness/agent-wrapper.ts",
4422
+ runAgentWrapper: async (input) => {
4423
+ const { runAgentWrapper: runAgentWrapper2 } = await Promise.resolve().then(() => (init_agent_wrapper(), exports_agent_wrapper));
4424
+ return runAgentWrapper2({ argv: [...input.argv] });
4425
+ },
4426
+ runRigAgentEntrypoint: async () => {
4427
+ const { runRigAgentEntrypoint: runRigAgentEntrypoint2 } = await Promise.resolve().then(() => (init_rig_agent_entrypoint(), exports_rig_agent_entrypoint));
4428
+ await runRigAgentEntrypoint2();
4429
+ }
4430
+ }), {
4431
+ title: "Agent harness",
4432
+ description: "Provider-owned Rig agent wrapper and runtime entrypoint service."
4433
+ }),
4434
+ SessionAssetMaterializerCap.provide(async () => (await Promise.resolve().then(() => (init_session_asset_materializer_service(), exports_session_asset_materializer_service))).sessionAssetMaterializer, {
4435
+ title: "Pi session asset materializer",
4436
+ description: "Materialize plugin-contributed Pi skills and config-declared Pi packages into the workspace .pi/ directory."
4437
+ }),
4438
+ SessionHookMaterializerCap.provide(async () => (await Promise.resolve().then(() => (init_session_hook_materializer_service(), exports_session_hook_materializer_service))).sessionHookMaterializer, {
4439
+ title: "Agent session hook materializer",
4440
+ description: "Materialize plugin-contributed hooks into the active provider session host."
4441
+ }),
4442
+ ToolMaterializerCap.provide(async () => {
4443
+ const [gateway, fileTools, claudeRouter, browserTools] = await Promise.all([
4444
+ Promise.resolve().then(() => (init_gateway(), exports_gateway)),
4445
+ Promise.resolve().then(() => (init_file_tools(), exports_file_tools)),
4446
+ Promise.resolve().then(() => (init_claude_router_binary(), exports_claude_router_binary)),
4447
+ Promise.resolve().then(() => (init_browser_tools(), exports_browser_tools))
4448
+ ]);
4449
+ return {
4450
+ materializeRuntimeToolGateway: gateway.materializeRuntimeToolGateway,
4451
+ materializeRuntimeFileTools: fileTools.materializeRuntimeFileTools,
4452
+ materializeClaudeToolRouterBinary: claudeRouter.materializeClaudeToolRouterBinary,
4453
+ materializeRuntimeBrowserTools: browserTools.materializeRuntimeBrowserTools,
4454
+ runtimeBrowserToolBinaryName: browserTools.runtimeBrowserToolBinaryName
4455
+ };
4456
+ }, {
4457
+ title: "Runtime tool materializer",
4458
+ description: "Materializes harness-plugin-owned tool binaries (gateway, file-tools, claude-router, browser-tools) into the runtime bin directory."
4459
+ })
4460
+ ],
4461
+ seedEntrypoints: PROVIDER_SEED_ENTRYPOINTS,
4462
+ config: { defaults: () => ({ runtime: { harness: "pi", mode: "yolo" } }) }
4463
+ }
4464
+ });
4465
+ function createProviderPlugin() {
4466
+ return providerPlugin;
4467
+ }
4468
+ var plugin_default = providerPlugin;
4469
+ export {
4470
+ providerPlugin,
4471
+ plugin_default as default,
4472
+ createProviderPlugin,
4473
+ REASONING_EFFORT_OPTIONS_BY_PROVIDER,
4474
+ ProviderModelOptions,
4475
+ PROVIDER_PLUGIN_NAME,
4476
+ MODEL_SLUG_ALIASES_BY_PROVIDER,
4477
+ MODEL_OPTIONS_BY_PROVIDER,
4478
+ DEFAULT_RUNTIME_MODE,
4479
+ DEFAULT_REASONING_EFFORT_BY_PROVIDER,
4480
+ DEFAULT_PROVIDER_KIND,
4481
+ DEFAULT_PROVIDER_INTERACTION_MODE,
4482
+ DEFAULT_MODEL_BY_PROVIDER,
4483
+ CodexModelOptions,
4484
+ ClaudeModelOptions,
4485
+ CODEX_REASONING_EFFORT_OPTIONS
4486
+ };