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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/bin/rig-agent-dispatch.d.ts +2 -0
  2. package/dist/bin/rig-agent-dispatch.js +863 -0
  3. package/dist/src/agent-harness/agent-mode.d.ts +1 -0
  4. package/dist/src/agent-harness/agent-mode.js +48 -0
  5. package/dist/src/agent-harness/agent-wrapper.d.ts +53 -0
  6. package/dist/src/agent-harness/agent-wrapper.js +916 -0
  7. package/dist/src/agent-harness/controlled-bash.d.ts +3 -0
  8. package/dist/src/agent-harness/controlled-bash.js +45 -0
  9. package/dist/src/agent-harness/git-ops.d.ts +2 -0
  10. package/dist/src/agent-harness/git-ops.js +27 -0
  11. package/dist/src/agent-harness/repo-ops.d.ts +8 -0
  12. package/dist/src/agent-harness/repo-ops.js +471 -0
  13. package/dist/src/agent-harness/rig-agent-entrypoint.d.ts +1 -0
  14. package/dist/src/agent-harness/rig-agent-entrypoint.js +1277 -0
  15. package/dist/src/agent-harness/rig-agent.d.ts +2 -0
  16. package/dist/src/agent-harness/rig-agent.js +1244 -0
  17. package/dist/src/agent-harness/runtime-snapshot-config.d.ts +2 -0
  18. package/dist/src/agent-harness/runtime-snapshot-config.js +25 -0
  19. package/dist/src/agent-harness/task-data.d.ts +2 -0
  20. package/dist/src/agent-harness/task-data.js +12 -0
  21. package/dist/src/agent-harness/task-ops.d.ts +10 -0
  22. package/dist/src/agent-harness/task-ops.js +53 -0
  23. package/dist/src/index.js +3366 -16
  24. package/dist/src/pi-settings-materializer.d.ts +10 -0
  25. package/dist/src/pi-settings-materializer.js +52 -0
  26. package/dist/src/plugin.d.ts +9 -2
  27. package/dist/src/plugin.js +3360 -8
  28. package/dist/src/service.d.ts +1 -1
  29. package/dist/src/session-asset-materializer-service.d.ts +13 -0
  30. package/dist/src/session-asset-materializer-service.js +124 -0
  31. package/dist/src/skill-materializer.d.ts +25 -0
  32. package/dist/src/skill-materializer.js +46 -0
  33. package/dist/src/tooling/binary-build-worker.d.ts +1 -0
  34. package/dist/src/tooling/binary-build-worker.js +323 -0
  35. package/dist/src/tooling/browser-tool-entrypoint.d.ts +2 -0
  36. package/dist/src/tooling/browser-tool-entrypoint.js +125 -0
  37. package/dist/src/tooling/browser-tools.d.ts +3 -0
  38. package/dist/src/tooling/browser-tools.js +27 -0
  39. package/dist/src/tooling/claude-router-binary.d.ts +3 -0
  40. package/dist/src/tooling/claude-router-binary.js +381 -0
  41. package/dist/src/tooling/claude-router.d.ts +22 -0
  42. package/dist/src/tooling/claude-router.js +524 -0
  43. package/dist/src/tooling/embedded-native-assets.d.ts +7 -0
  44. package/dist/src/tooling/embedded-native-assets.js +6 -0
  45. package/dist/src/tooling/file-tools.d.ts +5 -0
  46. package/dist/src/tooling/file-tools.js +224 -0
  47. package/dist/src/tooling/gateway.d.ts +4 -0
  48. package/dist/src/tooling/gateway.js +430 -0
  49. package/dist/src/tooling/native-extract.d.ts +2 -0
  50. package/dist/src/tooling/native-extract.js +44 -0
  51. package/dist/src/tooling/runtime-binary-build.d.ts +88 -0
  52. package/dist/src/tooling/runtime-binary-build.js +480 -0
  53. package/dist/src/tooling/shell-tools.d.ts +5 -0
  54. package/dist/src/tooling/shell-tools.js +217 -0
  55. package/native/darwin-arm64/rig-shell +0 -0
  56. package/native/darwin-arm64/rig-shell.build-manifest.json +4 -0
  57. package/native/darwin-arm64/rig-tools +0 -0
  58. package/native/darwin-arm64/rig-tools.build-manifest.json +4 -0
  59. package/native/darwin-x64/rig-shell +0 -0
  60. package/native/darwin-x64/rig-tools +0 -0
  61. package/native/linux-arm64/rig-shell +0 -0
  62. package/native/linux-arm64/rig-tools +0 -0
  63. package/native/linux-x64/rig-shell +0 -0
  64. package/native/linux-x64/rig-tools +0 -0
  65. package/native/win32-x64/rig-shell.exe +0 -0
  66. package/native/win32-x64/rig-tools.exe +0 -0
  67. package/package.json +54 -5
  68. package/dist/src/claude-stream-records.d.ts +0 -24
  69. package/dist/src/claude-stream-records.js +0 -158
  70. package/dist/src/codex-app-server.d.ts +0 -16
  71. package/dist/src/codex-app-server.js +0 -548
  72. package/dist/src/codex-exec-records.d.ts +0 -27
  73. package/dist/src/codex-exec-records.js +0 -203
@@ -0,0 +1,1244 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+
4
+ // packages/provider-plugin/src/agent-harness/rig-agent.ts
5
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
6
+ import { dirname as dirname2, resolve as resolve3 } from "path";
7
+ import { readBuildConfig } from "@rig/core/build-time-config";
8
+
9
+ // packages/provider-plugin/src/agent-harness/controlled-bash.ts
10
+ import { existsSync } from "fs";
11
+ import { resolve } from "path";
12
+ import { resolveRigLayout } from "@rig/core/layout";
13
+ function controlledBashCandidates(projectRoot) {
14
+ const layout = resolveRigLayout(projectRoot);
15
+ const candidates = [
16
+ process.env.RIG_CONTROLLED_BASH_BIN?.trim() || "",
17
+ resolve(layout.binDir, "controlled-bash"),
18
+ Bun.which("controlled-bash") || ""
19
+ ];
20
+ return candidates.filter((candidate) => Boolean(candidate));
21
+ }
22
+ function resolveControlledBash(projectRoot) {
23
+ for (const candidate of controlledBashCandidates(projectRoot)) {
24
+ if (existsSync(candidate))
25
+ return candidate;
26
+ }
27
+ return null;
28
+ }
29
+ async function runControlledBash(args, options) {
30
+ 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;
31
+ const controlled = resolveControlledBash(projectRoot);
32
+ if (!controlled) {
33
+ console.error("[rig-agent] controlled-bash entrypoint unavailable; refusing to run an unguarded shell.");
34
+ return 126;
35
+ }
36
+ const command = [controlled, ...args];
37
+ const child = Bun.spawn(command, {
38
+ stdin: "inherit",
39
+ stdout: "inherit",
40
+ stderr: "inherit",
41
+ cwd: process.cwd(),
42
+ env: {
43
+ ...process.env,
44
+ PROJECT_RIG_ROOT: projectRoot,
45
+ RIG_BASH_ACTIVE: "1"
46
+ }
47
+ });
48
+ return await child.exited;
49
+ }
50
+
51
+ // packages/provider-plugin/src/agent-harness/rig-agent.ts
52
+ import { COMPLETION_VERIFICATION_CAPABILITY, MEMORY } from "@rig/contracts";
53
+ import { defineCapability as defineCapability4 } from "@rig/core/capability";
54
+ import { buildProjectPluginHost, loadCapabilityForRoot as loadCapabilityForRoot2 } from "@rig/core/capability-loaders";
55
+ import { resolveCheckoutRoot as resolveMonorepoRoot } from "@rig/core/checkout-root";
56
+
57
+ // packages/provider-plugin/src/agent-harness/agent-mode.ts
58
+ function looksLikeShellInvocation(args, mode = process.env.RIG_AGENT_MODE) {
59
+ if (mode === "shell") {
60
+ return true;
61
+ }
62
+ if (mode === "agent") {
63
+ return false;
64
+ }
65
+ if (args.length === 0) {
66
+ return false;
67
+ }
68
+ const first = args[0];
69
+ if (!first) {
70
+ return false;
71
+ }
72
+ const bashLikeFlags = new Set([
73
+ "-c",
74
+ "-lc",
75
+ "-l",
76
+ "-i",
77
+ "-s",
78
+ "--login",
79
+ "--noprofile",
80
+ "--norc",
81
+ "--posix",
82
+ "--rcfile",
83
+ "--init-file",
84
+ "--restricted",
85
+ "--debug",
86
+ "--debugger",
87
+ "--verbose",
88
+ "--wordexp",
89
+ "--dump-strings",
90
+ "--dump-po-strings",
91
+ "--help"
92
+ ]);
93
+ if (bashLikeFlags.has(first)) {
94
+ return true;
95
+ }
96
+ if (!first.startsWith("-")) {
97
+ return first.endsWith(".sh");
98
+ }
99
+ return false;
100
+ }
101
+
102
+ // packages/provider-plugin/src/agent-harness/rig-agent.ts
103
+ import { browserEnvFromContext, loadRuntimeContext as loadRuntimeContext2, loadRuntimeContextFromEnv } from "@rig/core/runtime-context";
104
+ import { loadDotEnvSecrets, resolveRuntimeSecrets } from "@rig/core/baked-secrets";
105
+ import { RuntimeEventBus } from "@rig/core/runtime-events";
106
+
107
+ // packages/provider-plugin/src/agent-harness/git-ops.ts
108
+ import { LIFECYCLE_GIT_AGENT } from "@rig/contracts";
109
+ import { defineCapability } from "@rig/core/capability";
110
+ import { buildPluginHostContext } from "@rig/core/plugin-host-context";
111
+ import { loadCapabilityForRoot } from "@rig/core/capability-loaders";
112
+ var LifecycleGitAgentCap = defineCapability(LIFECYCLE_GIT_AGENT);
113
+ var hostContextByRoot = new Map;
114
+ async function ensureHostContext(projectRoot) {
115
+ let cached = hostContextByRoot.get(projectRoot);
116
+ if (!cached) {
117
+ cached = buildPluginHostContext(projectRoot);
118
+ hostContextByRoot.set(projectRoot, cached);
119
+ }
120
+ await cached;
121
+ }
122
+ async function loadLifecycleGit(projectRoot) {
123
+ await ensureHostContext(projectRoot);
124
+ const git = await loadCapabilityForRoot(projectRoot, LifecycleGitAgentCap);
125
+ if (!git) {
126
+ throw new Error("lifecycle git capability unavailable: load @rig/bundle-default-lifecycle (default bundle) before running rig-agent git commands.");
127
+ }
128
+ return git;
129
+ }
130
+
131
+ // packages/provider-plugin/src/agent-harness/rig-agent.ts
132
+ import {
133
+ setProfile,
134
+ setReviewProfile,
135
+ showProfile,
136
+ showReviewProfile
137
+ } from "@rig/core/profile-ops";
138
+
139
+ // packages/provider-plugin/src/agent-harness/repo-ops.ts
140
+ import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "fs";
141
+ import { basename, dirname, resolve as resolve2 } from "path";
142
+ import { loadRuntimeContext } from "@rig/core/runtime-context";
143
+ import {
144
+ MANAGED_REPO_SERVICE_CAPABILITY,
145
+ TASK_DATA_SERVICE_CAPABILITY
146
+ } from "@rig/contracts";
147
+ import { defineCapability as defineCapability2 } from "@rig/core/capability";
148
+ import { getInstalledCapability, requireInstalledCapability } from "@rig/core/capability-loaders";
149
+ import { resolveHarnessPaths } from "@rig/core/harness-paths";
150
+ var ManagedRepoCap = defineCapability2(MANAGED_REPO_SERVICE_CAPABILITY);
151
+ var getManagedRepoService = () => getInstalledCapability(ManagedRepoCap);
152
+ var TaskDataCap = defineCapability2(TASK_DATA_SERVICE_CAPABILITY);
153
+ var taskData = () => requireInstalledCapability(TaskDataCap, "task-data capability unavailable: load @rig/task-sources-plugin (default bundle) before resolving task repos.");
154
+ function runCapture(command, cwd, env) {
155
+ const result = Bun.spawnSync(command, {
156
+ cwd,
157
+ env: env ? { ...process.env, ...env } : process.env,
158
+ stdout: "pipe",
159
+ stderr: "pipe",
160
+ stdin: "ignore"
161
+ });
162
+ return {
163
+ exitCode: result.exitCode,
164
+ stdout: result.stdout.toString(),
165
+ stderr: result.stderr.toString()
166
+ };
167
+ }
168
+ function readJsonFile(path, fallback) {
169
+ if (!existsSync2(path))
170
+ return fallback;
171
+ try {
172
+ return JSON.parse(readFileSync(path, "utf8"));
173
+ } catch {
174
+ return fallback;
175
+ }
176
+ }
177
+ function nowIso() {
178
+ return new Date().toISOString();
179
+ }
180
+ function managedRepoEntries() {
181
+ return getManagedRepoService()?.listManagedRepoEntries() ?? [];
182
+ }
183
+ function requireManagedRepoService() {
184
+ const service = getManagedRepoService();
185
+ if (!service) {
186
+ throw new Error("managed-repo service not installed: configure @rig/repos-plugin in rig.config to use managed-repo operations.");
187
+ }
188
+ return service;
189
+ }
190
+ function primaryManagedRepoId() {
191
+ const entries = managedRepoEntries();
192
+ return entries.length > 0 ? entries[0].id : null;
193
+ }
194
+ function primaryManagedRepoAlias() {
195
+ const entries = managedRepoEntries();
196
+ return entries.length > 0 ? entries[0].alias : null;
197
+ }
198
+ function repoEnsure(projectRoot, taskId) {
199
+ const monorepo = ensureMonorepoReady(projectRoot);
200
+ const resolvedTask = taskId || taskData().currentTaskId(projectRoot);
201
+ if (!resolvedTask) {
202
+ if (monorepo) {
203
+ const alias = primaryManagedRepoAlias();
204
+ if (alias) {
205
+ persistBaselinePins(projectRoot, { [alias]: monorepo.headCommit });
206
+ }
207
+ }
208
+ console.log("No active task. Refreshed baseline repo pins.");
209
+ return;
210
+ }
211
+ const pins = resolvedPins(projectRoot, resolvedTask);
212
+ applyPins(projectRoot, pins);
213
+ verifyPins(projectRoot, pins);
214
+ }
215
+ function repoPins(projectRoot, taskId) {
216
+ const resolvedTask = taskId || taskData().currentTaskId(projectRoot);
217
+ if (!resolvedTask) {
218
+ return {};
219
+ }
220
+ return resolvedPins(projectRoot, resolvedTask);
221
+ }
222
+ function repoVerify(projectRoot, taskId) {
223
+ const resolvedTask = taskId || taskData().currentTaskId(projectRoot);
224
+ if (!resolvedTask) {
225
+ console.log("No active task. Nothing to verify.");
226
+ return true;
227
+ }
228
+ const pins = resolvedPins(projectRoot, resolvedTask);
229
+ return verifyPins(projectRoot, pins);
230
+ }
231
+ function repoDiscover(projectRoot, taskId) {
232
+ const resolvedTask = taskId || taskData().currentTaskId(projectRoot);
233
+ if (!resolvedTask) {
234
+ return {};
235
+ }
236
+ const explicit = explicitPins(projectRoot, resolvedTask);
237
+ if (Object.keys(explicit).length > 0) {
238
+ return explicit;
239
+ }
240
+ return discoverPins(projectRoot, resolvedTask);
241
+ }
242
+ function repoBaseline(projectRoot, refresh = false) {
243
+ const paths = resolveRepoDiscoveryPaths(projectRoot);
244
+ if (!refresh && existsSync2(paths.baseRepoPinsPath)) {
245
+ const baseline = readJsonFile(paths.baseRepoPinsPath, { recorded_at: nowIso(), repos: {} });
246
+ return baseline.repos || {};
247
+ }
248
+ const id = primaryManagedRepoId();
249
+ if (!id) {
250
+ return persistBaselinePins(projectRoot, {});
251
+ }
252
+ const synced = requireManagedRepoService().syncManagedRepo(projectRoot, id);
253
+ const alias = primaryManagedRepoAlias() ?? id;
254
+ return persistBaselinePins(projectRoot, { [alias]: synced.headCommit });
255
+ }
256
+ function ensureMonorepoReady(projectRoot) {
257
+ const id = primaryManagedRepoId();
258
+ if (!id) {
259
+ return null;
260
+ }
261
+ const synced = requireManagedRepoService().syncManagedRepo(projectRoot, id);
262
+ const sha = synced.headCommit.slice(0, 7);
263
+ console.log(`Monorepo ready: ${synced.layout.alias}@${sha}`);
264
+ return synced;
265
+ }
266
+ function persistBaselinePins(projectRoot, repos) {
267
+ const paths = resolveRepoDiscoveryPaths(projectRoot);
268
+ mkdirSync(resolve2(paths.baseRepoPinsPath, ".."), { recursive: true });
269
+ writeFileSync(paths.baseRepoPinsPath, `${JSON.stringify({ recorded_at: nowIso(), repos }, null, 2)}
270
+ `, "utf-8");
271
+ return repos;
272
+ }
273
+ function resolvedPins(projectRoot, taskId) {
274
+ const explicit = explicitPins(projectRoot, taskId);
275
+ if (Object.keys(explicit).length > 0) {
276
+ return explicit;
277
+ }
278
+ return discoverPins(projectRoot, taskId);
279
+ }
280
+ function explicitPins(projectRoot, taskId) {
281
+ const repoPins2 = readRepoDiscoveryTaskConfig(projectRoot)[taskId]?.repo_pins || {};
282
+ const normalized = {};
283
+ const validAliases = new Set(managedRepoEntries().map((e) => e.alias));
284
+ for (const [key, value] of Object.entries(repoPins2)) {
285
+ if (!value) {
286
+ continue;
287
+ }
288
+ if (validAliases.size > 0 && !validAliases.has(key)) {
289
+ throw new Error(`Unsupported repo pin key for ${taskId}: ${key}. Known aliases: ${[...validAliases].join(", ") || "(none registered)"}`);
290
+ }
291
+ const existing = normalized[key];
292
+ if (existing && existing !== value) {
293
+ throw new Error(`Conflicting explicit repo pins for ${key}: ${existing} vs ${value}`);
294
+ }
295
+ normalized[key] = value;
296
+ }
297
+ return normalized;
298
+ }
299
+ function taskDependencies(projectRoot, taskId) {
300
+ return taskData().taskDependencyIds(projectRoot, taskId);
301
+ }
302
+ function discoverPins(projectRoot, taskId) {
303
+ const deps = taskDependencies(projectRoot, taskId);
304
+ if (deps.length === 0) {
305
+ return repoBaseline(projectRoot, true);
306
+ }
307
+ const paths = resolveRepoDiscoveryPaths(projectRoot);
308
+ const state = readJsonFile(paths.taskRepoCommitsPath, {});
309
+ const pinKeys = managedRepoEntries().map((e) => e.alias);
310
+ if (pinKeys.length === 0) {
311
+ return {};
312
+ }
313
+ const discovered = {};
314
+ for (const key of pinKeys) {
315
+ const commits = new Set;
316
+ for (const dep of deps) {
317
+ const fromState = state[dep]?.repos?.[key];
318
+ if (fromState) {
319
+ commits.add(fromState);
320
+ }
321
+ const fromArtifact = readPinFromArtifact(projectRoot, dep, key);
322
+ if (fromArtifact) {
323
+ commits.add(fromArtifact);
324
+ }
325
+ }
326
+ if (commits.size > 1) {
327
+ const values = [...commits].join(`
328
+ - `);
329
+ throw new Error(`Conflicting discovered pins for ${key} from dependency graph of ${taskId}:
330
+ - ${values}`);
331
+ }
332
+ if (commits.size === 1) {
333
+ discovered[key] = [...commits][0];
334
+ }
335
+ }
336
+ return discovered;
337
+ }
338
+ function readRepoDiscoveryTaskConfig(projectRoot) {
339
+ try {
340
+ return taskData().readSourceTaskConfig(projectRoot);
341
+ } catch {
342
+ return taskData().readTaskConfig(projectRoot);
343
+ }
344
+ }
345
+ function resolveRepoDiscoveryPaths(projectRoot) {
346
+ const monorepoRoot = requireManagedRepoService().resolveMonorepoRepoLayout(projectRoot).checkoutRoot;
347
+ const explicitHostProjectRoot = (process.env.RIG_HOST_PROJECT_ROOT || "").trim();
348
+ const normalizedProjectRoot = resolve2(projectRoot);
349
+ const hostProjectRoot = explicitHostProjectRoot && shouldUseHostProjectStateRoot(normalizedProjectRoot) ? explicitHostProjectRoot : normalizedProjectRoot;
350
+ const stateDir = resolve2(hostProjectRoot, ".rig", "state");
351
+ return {
352
+ monorepoRoot,
353
+ taskRepoCommitsPath: resolve2(stateDir, "task-repo-commits.json"),
354
+ baseRepoPinsPath: resolve2(stateDir, "base-repo-pins.json")
355
+ };
356
+ }
357
+ function shouldUseHostProjectStateRoot(projectRoot) {
358
+ const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
359
+ if (runtimeWorkspace && resolve2(runtimeWorkspace) === projectRoot) {
360
+ return true;
361
+ }
362
+ return basename(dirname(projectRoot)) === ".worktrees";
363
+ }
364
+ function readPinFromArtifact(projectRoot, depTask, repoKey) {
365
+ const snapshot = resolve2(taskData().artifactDirForId(projectRoot, depTask), "git-state.txt");
366
+ if (!existsSync2(snapshot)) {
367
+ return "";
368
+ }
369
+ const content = readFileSync(snapshot, "utf-8");
370
+ const chunk = content.split(/\r?\n/);
371
+ let inSection = false;
372
+ for (const line of chunk) {
373
+ if (line.startsWith("## ")) {
374
+ inSection = line.startsWith(`## ${repoKey}`);
375
+ continue;
376
+ }
377
+ if (!inSection) {
378
+ continue;
379
+ }
380
+ if (line.startsWith("head:")) {
381
+ return line.replace(/^head:\s*/, "").trim();
382
+ }
383
+ }
384
+ return "";
385
+ }
386
+ function repoPath(projectRoot, key) {
387
+ const managed = getManagedRepoService()?.resolveManagedRepoLayoutByAlias(projectRoot, key) ?? null;
388
+ if (managed) {
389
+ return managed.checkoutRoot;
390
+ }
391
+ return key.startsWith("/") ? key : resolve2(projectRoot, key);
392
+ }
393
+ function applyPins(projectRoot, pins) {
394
+ for (const [key, commit] of Object.entries(pins)) {
395
+ const path = repoPath(projectRoot, key);
396
+ if (!existsSync2(resolve2(path, ".git"))) {
397
+ throw new Error(`Repo for pin not available: ${key} (${path})`);
398
+ }
399
+ let hasCommit = runGitCapture(["git", "-C", path, "cat-file", "-e", `${commit}^{commit}`], projectRoot).exitCode === 0;
400
+ if (!hasCommit) {
401
+ runGitCapture(["git", "-C", path, "fetch", "--all", "--tags", "--prune"], projectRoot);
402
+ hasCommit = runGitCapture(["git", "-C", path, "cat-file", "-e", `${commit}^{commit}`], projectRoot).exitCode === 0;
403
+ }
404
+ if (!hasCommit) {
405
+ throw new Error(`Commit not found for ${key}: ${commit}`);
406
+ }
407
+ const current = runGitCapture(["git", "-C", path, "rev-parse", "HEAD"], projectRoot).stdout.trim();
408
+ if (current === commit) {
409
+ console.log(`Repo pin: ${key} already at ${commit}`);
410
+ continue;
411
+ }
412
+ const branch = runGitCapture(["git", "-C", path, "rev-parse", "--abbrev-ref", "HEAD"], projectRoot).stdout.trim();
413
+ const checkout = branch.startsWith("rig/") ? runGitCapture(["git", "-C", path, "reset", "--hard", commit], projectRoot) : runGitCapture(["git", "-C", path, "checkout", "--detach", commit], projectRoot);
414
+ if (checkout.exitCode !== 0) {
415
+ throw new Error(`Failed to apply repo pin ${key} -> ${commit}:
416
+ ${checkout.stderr || checkout.stdout}`);
417
+ }
418
+ console.log(`Repo pin: ${key} -> ${commit}`);
419
+ }
420
+ }
421
+ function verifyPins(projectRoot, pins) {
422
+ let ok = true;
423
+ for (const [key, expected] of Object.entries(pins)) {
424
+ const path = repoPath(projectRoot, key);
425
+ if (!existsSync2(resolve2(path, ".git"))) {
426
+ console.error(`ERROR: repo missing during pin verification: ${key}`);
427
+ ok = false;
428
+ continue;
429
+ }
430
+ const current = runGitCapture(["git", "-C", path, "rev-parse", "HEAD"], projectRoot).stdout.trim();
431
+ if (current === expected) {
432
+ console.log(`Repo verify: ${key} at ${current}`);
433
+ } else {
434
+ console.error(`ERROR: repo pin mismatch for ${key}: expected ${expected}, got ${current}`);
435
+ ok = false;
436
+ }
437
+ }
438
+ return ok;
439
+ }
440
+ function runGitCapture(command, projectRoot) {
441
+ return runCapture(command, projectRoot, resolveRuntimeGitEnv());
442
+ }
443
+ function resolveRuntimeGitEnv() {
444
+ if (process.env.GIT_SSH_COMMAND?.trim()) {
445
+ return {
446
+ HOME: process.env.HOME ?? "",
447
+ GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND
448
+ };
449
+ }
450
+ const runtimeRoot = process.env.RIG_RUNTIME_HOME?.trim() || (process.env.RIG_RUNTIME_CONTEXT_FILE?.trim() ? resolve2(process.env.RIG_RUNTIME_CONTEXT_FILE, "..") : inferRuntimeRootFromWorkspace(process.cwd()));
451
+ const runtimeHome = runtimeRoot ? resolve2(runtimeRoot, "home") : process.env.HOME?.trim() || "";
452
+ if (!runtimeHome) {
453
+ return;
454
+ }
455
+ const knownHostsPath = resolve2(runtimeHome, ".ssh", "known_hosts");
456
+ if (!existsSync2(knownHostsPath)) {
457
+ return { HOME: runtimeHome };
458
+ }
459
+ const agentSshKey = resolve2(runtimeHome, ".ssh", "rig-agent-key");
460
+ const sshParts = [
461
+ "ssh",
462
+ `-o UserKnownHostsFile="${knownHostsPath}"`,
463
+ "-o StrictHostKeyChecking=yes",
464
+ "-F /dev/null"
465
+ ];
466
+ if (existsSync2(agentSshKey)) {
467
+ sshParts.splice(1, 0, `-i "${agentSshKey}"`, "-o IdentitiesOnly=yes");
468
+ }
469
+ return {
470
+ HOME: runtimeHome,
471
+ GIT_SSH_COMMAND: sshParts.join(" ")
472
+ };
473
+ }
474
+ function inferRuntimeRootFromWorkspace(cwd) {
475
+ const contextPath = findRuntimeContextFile(cwd);
476
+ if (!contextPath || !existsSync2(contextPath)) {
477
+ return "";
478
+ }
479
+ try {
480
+ loadRuntimeContext(contextPath);
481
+ return resolve2(contextPath, "..");
482
+ } catch {
483
+ return "";
484
+ }
485
+ }
486
+ function findRuntimeContextFile(startPath) {
487
+ let current = resolve2(startPath);
488
+ while (true) {
489
+ const candidate = resolve2(current, "runtime-context.json");
490
+ if (existsSync2(candidate)) {
491
+ return candidate;
492
+ }
493
+ const parent = resolve2(current, "..");
494
+ if (parent === current) {
495
+ return "";
496
+ }
497
+ current = parent;
498
+ }
499
+ }
500
+
501
+ // packages/provider-plugin/src/agent-harness/task-data.ts
502
+ import { TASK_DATA_SERVICE_CAPABILITY as TASK_DATA_SERVICE_CAPABILITY2 } from "@rig/contracts";
503
+ import { defineCapability as defineCapability3 } from "@rig/core/capability";
504
+ import { requireInstalledCapability as requireInstalledCapability2 } from "@rig/core/capability-loaders";
505
+ var TaskDataCap2 = defineCapability3(TASK_DATA_SERVICE_CAPABILITY2);
506
+ function taskData2() {
507
+ return requireInstalledCapability2(TaskDataCap2, "task-data capability unavailable: load @rig/task-sources-plugin (default bundle) before running the provider agent harness.");
508
+ }
509
+
510
+ // packages/provider-plugin/src/agent-harness/task-ops.ts
511
+ function taskArtifactDir(projectRoot, taskId) {
512
+ return taskData2().taskArtifactDir(projectRoot, taskId);
513
+ }
514
+ function taskArtifacts(projectRoot, taskId) {
515
+ taskData2().taskArtifacts(projectRoot, taskId);
516
+ }
517
+ function taskArtifactWrite(projectRoot, filename, content, taskId) {
518
+ taskData2().taskArtifactWrite(projectRoot, filename, content, taskId);
519
+ }
520
+ function taskDeps(projectRoot, taskId) {
521
+ return taskData2().taskDeps(projectRoot, taskId);
522
+ }
523
+ function taskInfo(projectRoot, taskId) {
524
+ return taskData2().taskInfo(projectRoot, taskId);
525
+ }
526
+ function taskLookup(projectRoot, id) {
527
+ return taskData2().taskLookup(projectRoot, id);
528
+ }
529
+ function taskRecord(projectRoot, type, text, taskId) {
530
+ taskData2().taskRecord(projectRoot, type, text, taskId);
531
+ }
532
+ function taskScope(projectRoot, expandFiles, taskId) {
533
+ return taskData2().taskScope(projectRoot, expandFiles, taskId);
534
+ }
535
+ function taskStatus(projectRoot) {
536
+ taskData2().taskStatus(projectRoot);
537
+ }
538
+ function taskValidate(projectRoot, taskId, validatorRegistry) {
539
+ return taskData2().taskValidate(projectRoot, taskId, validatorRegistry);
540
+ }
541
+
542
+ // packages/provider-plugin/src/agent-harness/rig-agent.ts
543
+ var BUILD_CONFIG = readBuildConfig();
544
+ var BAKED_BINARY_PATH = BUILD_CONFIG.AGENT_BINARY_PATH ?? "";
545
+ var BAKED_MANIFEST_PATH = BUILD_CONFIG.AGENT_MANIFEST_PATH ?? "";
546
+ var BAKED_PROJECT_ROOT = BUILD_CONFIG.AGENT_PROJECT_ROOT ?? "";
547
+ var BAKED_RUNTIME_ID = BUILD_CONFIG.AGENT_RUNTIME_ID ?? "";
548
+ var BAKED_TASK_ID = BUILD_CONFIG.AGENT_TASK_ID ?? "";
549
+ var BAKED_SCOPE_HASH = BUILD_CONFIG.AGENT_SCOPE_HASH ?? "";
550
+ var BAKED_INFO_OUTPUT = BUILD_CONFIG.AGENT_INFO_OUTPUT ?? "";
551
+ var BAKED_DEPS_OUTPUT = BUILD_CONFIG.AGENT_DEPS_OUTPUT ?? "";
552
+ var BAKED_STATUS_OUTPUT = BUILD_CONFIG.AGENT_STATUS_OUTPUT ?? "";
553
+ var BAKED_GIT_BRANCH = BUILD_CONFIG.AGENT_GIT_BRANCH ?? "";
554
+ var BAKED_BASE_COMMIT = BUILD_CONFIG.AGENT_BASE_COMMIT ?? "";
555
+ if (BAKED_BINARY_PATH) {
556
+ const binaryDir = dirname2(BAKED_BINARY_PATH);
557
+ const currentPath = process.env.PATH || "";
558
+ const pathEntries = currentPath.split(":").filter(Boolean);
559
+ if (!pathEntries.includes(binaryDir)) {
560
+ process.env.PATH = currentPath ? `${binaryDir}:${currentPath}` : binaryDir;
561
+ }
562
+ }
563
+ var cachedContext;
564
+ var cachedEventBus;
565
+ function getContext() {
566
+ if (cachedContext !== undefined)
567
+ return cachedContext;
568
+ cachedContext = loadRuntimeContextFromEnv() ?? inferRuntimeContext();
569
+ return cachedContext;
570
+ }
571
+ function getEventBus() {
572
+ if (cachedEventBus !== undefined) {
573
+ return cachedEventBus ?? undefined;
574
+ }
575
+ const ctx = getContext();
576
+ if (!ctx) {
577
+ cachedEventBus = null;
578
+ return;
579
+ }
580
+ const runId = ctx.runtimeId || BAKED_RUNTIME_ID || "";
581
+ cachedEventBus = new RuntimeEventBus({
582
+ projectRoot: ctx.workspaceDir,
583
+ ...runId ? { runId } : {}
584
+ });
585
+ return cachedEventBus;
586
+ }
587
+ function inferRuntimeContext() {
588
+ for (const candidate of runtimeContextCandidates()) {
589
+ if (!candidate || !existsSync3(candidate)) {
590
+ continue;
591
+ }
592
+ try {
593
+ process.env.RIG_RUNTIME_CONTEXT_FILE = candidate;
594
+ return loadRuntimeContext2(candidate);
595
+ } catch {}
596
+ }
597
+ return null;
598
+ }
599
+ function runtimeContextCandidates() {
600
+ const cwd = process.cwd();
601
+ const candidates = [
602
+ resolve3(cwd, "..", "runtime-context.json"),
603
+ resolve3(cwd, ".rig", "runtime-context.json")
604
+ ];
605
+ const argv1 = process.argv[1]?.trim();
606
+ if (argv1) {
607
+ candidates.push(resolve3(argv1, "..", "..", "runtime-context.json"));
608
+ }
609
+ if (BAKED_BINARY_PATH) {
610
+ candidates.push(resolve3(BAKED_BINARY_PATH, "..", "..", "runtime-context.json"));
611
+ }
612
+ return Array.from(new Set(candidates));
613
+ }
614
+ function sha256Hex(input) {
615
+ const hasher = new Bun.CryptoHasher("sha256");
616
+ hasher.update(input);
617
+ return hasher.digest("hex");
618
+ }
619
+ var GITHUB_KNOWN_HOSTS = [
620
+ "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl",
621
+ "github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=",
622
+ "github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk="
623
+ ];
624
+ function ensureRuntimeKnownHosts(runtimeHome) {
625
+ const sshDir = resolve3(runtimeHome, ".ssh");
626
+ const knownHostsPath = resolve3(sshDir, "known_hosts");
627
+ if (!existsSync3(sshDir)) {
628
+ mkdirSync2(sshDir, { recursive: true });
629
+ }
630
+ const existing = existsSync3(knownHostsPath) ? readFileSync2(knownHostsPath, "utf-8") : "";
631
+ const existingLines = new Set(existing.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
632
+ const missing = GITHUB_KNOWN_HOSTS.filter((line) => !existingLines.has(line));
633
+ if (missing.length === 0) {
634
+ return knownHostsPath;
635
+ }
636
+ try {
637
+ for (const line of missing) {
638
+ existingLines.add(line);
639
+ }
640
+ writeFileSync2(knownHostsPath, `${Array.from(existingLines).join(`
641
+ `)}
642
+ `, { mode: 420 });
643
+ } catch (err) {
644
+ const hint = existsSync3(knownHostsPath) ? "" : " \u2014 known_hosts is missing; git SSH operations may fail";
645
+ console.warn(`[rig-agent] Could not update ${knownHostsPath}: ${err instanceof Error ? err.message : String(err)}${hint}`);
646
+ }
647
+ return knownHostsPath;
648
+ }
649
+ function hydrateRuntimeProcessEnv(ctx) {
650
+ if (!ctx) {
651
+ return;
652
+ }
653
+ const contextFile = process.env.RIG_RUNTIME_CONTEXT_FILE?.trim() || inferRuntimeContextFileFromWorkspace(ctx.workspaceDir);
654
+ if (!contextFile) {
655
+ return;
656
+ }
657
+ process.env.RIG_RUNTIME_CONTEXT_FILE = contextFile;
658
+ const runtimeRoot = dirname2(resolve3(contextFile));
659
+ const runtimeHome = resolve3(runtimeRoot, "home");
660
+ const runtimeTmp = resolve3(runtimeRoot, "tmp");
661
+ const runtimeCache = resolve3(runtimeRoot, "cache");
662
+ const runtimeBin = resolve3(runtimeRoot, "bin");
663
+ const runtimeWorkspaceBin = resolve3(ctx.workspaceDir, ".rig", "bin");
664
+ const runtimeTools = resolve3(ctx.workspaceDir, "rig", "tools");
665
+ if (ctx.hostProjectRoot) {
666
+ process.env.PROJECT_RIG_ROOT = ctx.hostProjectRoot;
667
+ }
668
+ process.env.RIG_TASK_ID = ctx.taskId;
669
+ process.env.RIG_TASK_WORKSPACE = ctx.workspaceDir;
670
+ process.env.RIG_STATE_DIR = ctx.stateDir;
671
+ process.env.RIG_LOGS_DIR = ctx.logsDir;
672
+ process.env.RIG_SESSION_FILE = ctx.sessionFile;
673
+ process.env.RIG_RUNTIME_HOME = runtimeRoot;
674
+ if (!process.env.RIG_HOST_PROJECT_ROOT && ctx.hostProjectRoot) {
675
+ process.env.RIG_HOST_PROJECT_ROOT = ctx.hostProjectRoot;
676
+ }
677
+ for (const [key, value] of Object.entries(browserEnvFromContext(ctx.browser))) {
678
+ process.env[key] = value;
679
+ }
680
+ if (existsSync3(runtimeHome)) {
681
+ process.env.HOME = runtimeHome;
682
+ }
683
+ if (existsSync3(runtimeTmp)) {
684
+ process.env.TMPDIR = runtimeTmp;
685
+ }
686
+ if (existsSync3(runtimeCache)) {
687
+ process.env.XDG_CACHE_HOME = runtimeCache;
688
+ }
689
+ const workspaceSecrets = loadDotEnvSecrets(ctx.workspaceDir, process.env);
690
+ const hostWorkspaceSecrets = ctx.hostProjectRoot && ctx.hostProjectRoot !== ctx.workspaceDir ? loadDotEnvSecrets(ctx.hostProjectRoot, process.env) : {};
691
+ const resolvedSecrets = resolveRuntimeSecrets(process.env, {
692
+ ...hostWorkspaceSecrets,
693
+ ...workspaceSecrets
694
+ });
695
+ for (const [key, value] of Object.entries(resolvedSecrets)) {
696
+ if (value && !process.env[key]) {
697
+ process.env[key] = value;
698
+ }
699
+ }
700
+ if (!process.env.GITHUB_TOKEN && process.env.GH_TOKEN) {
701
+ process.env.GITHUB_TOKEN = process.env.GH_TOKEN;
702
+ }
703
+ if (!process.env.GH_TOKEN && process.env.GITHUB_TOKEN) {
704
+ process.env.GH_TOKEN = process.env.GITHUB_TOKEN;
705
+ }
706
+ if (!process.env.GREPTILE_GITHUB_TOKEN && process.env.GITHUB_TOKEN) {
707
+ process.env.GREPTILE_GITHUB_TOKEN = process.env.GITHUB_TOKEN;
708
+ }
709
+ const currentPath = process.env.PATH || "";
710
+ const pathEntries = currentPath.split(":").filter(Boolean);
711
+ for (const entry of [runtimeBin, runtimeWorkspaceBin, runtimeTools, "/usr/bin", "/bin", "/usr/sbin", "/sbin"]) {
712
+ if (existsSync3(entry) && !pathEntries.includes(entry)) {
713
+ pathEntries.unshift(entry);
714
+ }
715
+ }
716
+ process.env.PATH = pathEntries.join(":");
717
+ if (!process.env.RIG_GIT_BIN) {
718
+ const runtimeGit = resolve3(runtimeBin, "git");
719
+ process.env.RIG_GIT_BIN = existsSync3(runtimeGit) ? runtimeGit : Bun.which("git") || "/usr/bin/git";
720
+ }
721
+ const knownHosts = ensureRuntimeKnownHosts(runtimeHome);
722
+ const agentKey = resolve3(runtimeHome, ".ssh", "rig-agent-key");
723
+ const sshParts = [
724
+ "ssh",
725
+ `-o UserKnownHostsFile="${knownHosts}"`,
726
+ "-o StrictHostKeyChecking=yes",
727
+ "-F /dev/null"
728
+ ];
729
+ if (existsSync3(agentKey)) {
730
+ sshParts.splice(1, 0, `-i "${agentKey}"`, "-o IdentitiesOnly=yes");
731
+ }
732
+ process.env.GIT_SSH_COMMAND = sshParts.join(" ");
733
+ }
734
+ function inferRuntimeContextFileFromWorkspace(workspaceDir) {
735
+ const candidate = resolve3(workspaceDir, "..", "runtime-context.json");
736
+ return existsSync3(candidate) ? candidate : "";
737
+ }
738
+ async function main() {
739
+ const args = process.argv.slice(2);
740
+ hydrateRuntimeProcessEnv(getContext());
741
+ if (isVersionProbe(args)) {
742
+ await printVersion();
743
+ return;
744
+ }
745
+ if (args[0] === "internal") {
746
+ await runInternal(args.slice(1));
747
+ return;
748
+ }
749
+ const ctx = getContext();
750
+ if (!BAKED_PROJECT_ROOT && !ctx) {
751
+ console.error("[rig-agent] Runtime binary is missing baked task context and no runtime context file found.");
752
+ console.error("[rig-agent] Set RIG_RUNTIME_CONTEXT_FILE or use the compiled host dispatch binary.");
753
+ process.exit(1);
754
+ }
755
+ await verifyRuntimeManifest();
756
+ const commandResult = await runAgentCommand(args);
757
+ if (commandResult !== undefined) {
758
+ process.exit(commandResult);
759
+ }
760
+ if (looksLikeShellInvocation(args)) {
761
+ const code = await runControlledBash(args, { projectRootFallbackDir: import.meta.dir });
762
+ process.exit(code);
763
+ }
764
+ console.error(`[rig-agent] Unknown command: ${args[0] || "(none)"}. Run 'rig-agent help' for usage.`);
765
+ process.exit(1);
766
+ }
767
+ function isVersionProbe(args) {
768
+ if (args.length !== 1) {
769
+ return false;
770
+ }
771
+ return args[0] === "--version" || args[0] === "-v" || args[0] === "version";
772
+ }
773
+ async function printVersion() {
774
+ const probe = await Bun.$`claude --version`.cwd(process.cwd()).env(process.env).quiet().nothrow();
775
+ if (probe.exitCode === 0) {
776
+ const output = probe.stdout.toString().trim();
777
+ if (output) {
778
+ console.log(output);
779
+ return;
780
+ }
781
+ }
782
+ console.log("rig-agent 1.0.0");
783
+ }
784
+ var TASK_COMMANDS = new Set([
785
+ "info",
786
+ "scope",
787
+ "deps",
788
+ "status",
789
+ "artifacts",
790
+ "artifact-dir",
791
+ "artifact-write",
792
+ "project-root",
793
+ "monorepo-root",
794
+ "validate",
795
+ "lookup",
796
+ "record",
797
+ "help",
798
+ "completion-verification",
799
+ "completition-verification",
800
+ "git",
801
+ "repo",
802
+ "repo-sync",
803
+ "profile",
804
+ "review",
805
+ "memory"
806
+ ]);
807
+ async function runAgentCommand(args) {
808
+ const [command, ...rest] = args;
809
+ if (!command || !TASK_COMMANDS.has(command)) {
810
+ return;
811
+ }
812
+ const ctx = getContext();
813
+ const projectRoot = ctx?.workspaceDir || BAKED_PROJECT_ROOT || "";
814
+ const taskId = ctx?.taskId || BAKED_TASK_ID || "";
815
+ if (!projectRoot) {
816
+ console.error("[rig-agent] No project root baked in.");
817
+ return 1;
818
+ }
819
+ if (!taskId) {
820
+ console.error("[rig-agent] No task ID baked in.");
821
+ return 1;
822
+ }
823
+ try {
824
+ switch (command) {
825
+ case "info":
826
+ await taskInfo(projectRoot, taskId);
827
+ return 0;
828
+ case "scope":
829
+ await taskScope(projectRoot, rest.includes("--files"), taskId);
830
+ return 0;
831
+ case "deps":
832
+ await taskDeps(projectRoot, taskId);
833
+ return 0;
834
+ case "status":
835
+ taskStatus(projectRoot);
836
+ return 0;
837
+ case "artifacts":
838
+ taskArtifacts(projectRoot, taskId);
839
+ return 0;
840
+ case "artifact-dir":
841
+ console.log(taskArtifactDir(projectRoot, taskId));
842
+ return 0;
843
+ case "project-root":
844
+ console.log(projectRoot);
845
+ return 0;
846
+ case "monorepo-root":
847
+ console.log(resolveMonorepoRoot(projectRoot));
848
+ return 0;
849
+ case "artifact-write": {
850
+ const filename = rest[0];
851
+ if (!filename) {
852
+ console.error(`Usage: rig-agent artifact-write <filename> [--file <path>]
853
+ ` + ` Reads content from stdin (or --file), writes to the active task artifact dir.
854
+ ` + " Example: echo '...' | rig-agent artifact-write collection-audit.md");
855
+ return 1;
856
+ }
857
+ let content;
858
+ const fileIdx = rest.indexOf("--file");
859
+ const inputFile = fileIdx !== -1 ? rest[fileIdx + 1] : undefined;
860
+ if (inputFile) {
861
+ content = readFileSync2(resolve3(projectRoot, inputFile), "utf-8");
862
+ } else {
863
+ const chunks = [];
864
+ for await (const chunk of process.stdin) {
865
+ chunks.push(Buffer.from(chunk));
866
+ }
867
+ content = Buffer.concat(chunks).toString("utf-8");
868
+ }
869
+ taskArtifactWrite(projectRoot, filename, content, taskId);
870
+ return 0;
871
+ }
872
+ case "validate": {
873
+ const passed = await taskValidate(projectRoot, taskId);
874
+ return passed ? 0 : 1;
875
+ }
876
+ case "completion-verification":
877
+ case "completition-verification":
878
+ return await runCompletionVerification(projectRoot);
879
+ case "lookup": {
880
+ if (rest.length !== 1) {
881
+ console.error("Usage: rig-agent lookup <beads-id>");
882
+ return 1;
883
+ }
884
+ const lookupId = rest[0];
885
+ if (!lookupId) {
886
+ console.error("Usage: rig-agent lookup <beads-id>");
887
+ return 1;
888
+ }
889
+ console.log(taskLookup(projectRoot, lookupId));
890
+ return 0;
891
+ }
892
+ case "record": {
893
+ if (rest.length < 2) {
894
+ console.error("Usage: rig-agent record <decision|failure> <text>");
895
+ return 1;
896
+ }
897
+ const type = rest[0];
898
+ if (type !== "decision" && type !== "failure") {
899
+ console.error("Usage: rig-agent record <decision|failure> <text>");
900
+ return 1;
901
+ }
902
+ taskRecord(projectRoot, type, rest.slice(1).join(" "), taskId);
903
+ return 0;
904
+ }
905
+ case "memory": {
906
+ const memoryService = await loadCapabilityForRoot2(projectRoot, defineCapability4(MEMORY));
907
+ if (!memoryService) {
908
+ console.error("[rig-agent] Shared memory requires the @rig/memory-plugin plugin in rig.config.");
909
+ return 1;
910
+ }
911
+ const eventBus = getEventBus();
912
+ console.log(await memoryService.executeMemoryCommand({
913
+ projectRoot,
914
+ taskId,
915
+ runtimeContext: ctx,
916
+ args: rest,
917
+ ...eventBus ? { eventBus } : {}
918
+ }));
919
+ return 0;
920
+ }
921
+ case "git":
922
+ await runGitCommand(projectRoot, taskId, rest);
923
+ return 0;
924
+ case "repo":
925
+ case "repo-sync":
926
+ runRepoSyncCommand(projectRoot, taskId, rest);
927
+ return 0;
928
+ case "profile":
929
+ runProfileCommand(projectRoot, rest);
930
+ return 0;
931
+ case "review":
932
+ runReviewCommand(projectRoot, rest);
933
+ return 0;
934
+ case "help":
935
+ printAgentHelp();
936
+ return 0;
937
+ default:
938
+ return;
939
+ }
940
+ } catch (error) {
941
+ console.error(error instanceof Error ? error.message : String(error));
942
+ return 1;
943
+ }
944
+ }
945
+ async function runGitCommand(projectRoot, bakedTaskId, args) {
946
+ const [sub = "status", ...rest] = args;
947
+ const task = takeOption(rest, "--task");
948
+ const tid = task.value || bakedTaskId;
949
+ const flags = task.rest;
950
+ const git = await loadLifecycleGit(projectRoot);
951
+ switch (sub) {
952
+ case "status":
953
+ git.gitStatus(projectRoot, tid);
954
+ return;
955
+ case "changed": {
956
+ const scoped = flags.includes("--scoped");
957
+ const files = git.gitChanged(projectRoot, tid, scoped);
958
+ console.log(files.length > 0 ? files.join(`
959
+ `) : "(none)");
960
+ return;
961
+ }
962
+ case "preflight": {
963
+ const strict = flags.includes("--strict");
964
+ const ok = git.gitPreflight(projectRoot, tid, strict);
965
+ if (!ok)
966
+ throw new Error("Git preflight failed.");
967
+ return;
968
+ }
969
+ case "sync-branch":
970
+ case "ensure-branch":
971
+ git.gitSyncBranch(projectRoot, tid);
972
+ return;
973
+ case "commit": {
974
+ const target = takeOption(flags, "--target");
975
+ const message = takeOption(target.rest, "--message");
976
+ const allowEmpty = message.rest.includes("--allow-empty");
977
+ const scoped = git.shouldScopeGitCommit(message.rest, Boolean(tid));
978
+ git.gitCommit({
979
+ projectRoot,
980
+ taskId: tid,
981
+ target: target.value || "monorepo",
982
+ allowEmpty,
983
+ scoped,
984
+ ...message.value ? { message: message.value } : {}
985
+ });
986
+ return;
987
+ }
988
+ case "snapshot": {
989
+ const output = takeOption(flags, "--output");
990
+ const file = git.gitSnapshot(projectRoot, tid, output.value);
991
+ console.log(`Snapshot written: ${file}`);
992
+ return;
993
+ }
994
+ case "open-pr": {
995
+ const target = takeOption(flags, "--target");
996
+ const reviewer = takeOption(target.rest, "--reviewer");
997
+ const base = takeOption(reviewer.rest, "--base");
998
+ const title = takeOption(base.rest, "--title");
999
+ const body = takeOption(title.rest, "--body");
1000
+ const draft = body.rest.includes("--draft");
1001
+ const result = git.gitOpenPr({
1002
+ projectRoot,
1003
+ taskId: tid,
1004
+ ...target.value ? { target: target.value } : {},
1005
+ ...reviewer.value ? { reviewer: reviewer.value } : {},
1006
+ ...base.value ? { base: base.value } : {},
1007
+ ...title.value ? { title: title.value } : {},
1008
+ ...body.value ? { body: body.value } : {},
1009
+ draft
1010
+ });
1011
+ console.log(`PR ready (${result.repoLabel}): ${result.url}`);
1012
+ console.log(`Reviewer assigned: ${result.reviewer} (${result.reviewerSource})`);
1013
+ return;
1014
+ }
1015
+ default:
1016
+ throw new Error(`Unknown git subcommand: ${sub}. Try: status, changed, preflight, sync-branch, commit, snapshot, open-pr`);
1017
+ }
1018
+ }
1019
+ function runRepoSyncCommand(projectRoot, bakedTaskId, args) {
1020
+ const [sub = "ensure", ...rest] = args;
1021
+ const task = takeOption(rest, "--task");
1022
+ const tid = task.value || bakedTaskId;
1023
+ switch (sub) {
1024
+ case "sync":
1025
+ case "ensure":
1026
+ repoEnsure(projectRoot, tid);
1027
+ return;
1028
+ case "pins": {
1029
+ const pins = repoPins(projectRoot, tid);
1030
+ printPins(pins);
1031
+ return;
1032
+ }
1033
+ case "verify": {
1034
+ const ok = repoVerify(projectRoot, tid);
1035
+ if (!ok)
1036
+ throw new Error("Repo pin verification failed.");
1037
+ return;
1038
+ }
1039
+ case "discover": {
1040
+ const pins = repoDiscover(projectRoot, tid);
1041
+ printPins(pins);
1042
+ return;
1043
+ }
1044
+ case "baseline": {
1045
+ const refresh = task.rest.includes("--refresh");
1046
+ const pins = repoBaseline(projectRoot, refresh);
1047
+ printPins(pins);
1048
+ return;
1049
+ }
1050
+ default:
1051
+ throw new Error(`Unknown repo subcommand: ${sub}. Try: sync, ensure, pins, verify, discover, baseline`);
1052
+ }
1053
+ }
1054
+ function runProfileCommand(projectRoot, args) {
1055
+ const [sub = "show", ...rest] = args;
1056
+ if (sub === "show") {
1057
+ showProfile(projectRoot, rest.includes("--compact"));
1058
+ return;
1059
+ }
1060
+ if (sub === "set") {
1061
+ const first = rest[0];
1062
+ if (first === "claude-code" || first === "codex-cli" || first === "codex-app-server") {
1063
+ setProfile(projectRoot, { preset: first });
1064
+ return;
1065
+ }
1066
+ const model = takeOption(rest, "--model");
1067
+ const runtime = takeOption(model.rest, "--runtime");
1068
+ const plugin = takeOption(runtime.rest, "--plugin");
1069
+ setProfile(projectRoot, {
1070
+ ...model.value ? { model: model.value } : {},
1071
+ ...runtime.value ? { runtime: runtime.value } : {},
1072
+ ...plugin.value ? { plugin: plugin.value } : {}
1073
+ });
1074
+ return;
1075
+ }
1076
+ throw new Error(`Unknown profile subcommand: ${sub}. Try: show, set`);
1077
+ }
1078
+ function runReviewCommand(projectRoot, args) {
1079
+ const [sub = "show", ...rest] = args;
1080
+ if (sub === "show") {
1081
+ showReviewProfile(projectRoot);
1082
+ return;
1083
+ }
1084
+ if (sub === "set") {
1085
+ const mode = rest[0];
1086
+ if (!mode) {
1087
+ throw new Error("Usage: rig-agent review set <off|advisory|required> [--provider github|greptile]");
1088
+ }
1089
+ const provider = takeOption(rest.slice(1), "--provider");
1090
+ setReviewProfile(projectRoot, mode, provider.value);
1091
+ return;
1092
+ }
1093
+ throw new Error(`Unknown review subcommand: ${sub}. Try: show, set`);
1094
+ }
1095
+ function takeOption(args, option) {
1096
+ const rest = [];
1097
+ let value;
1098
+ for (let i = 0;i < args.length; i += 1) {
1099
+ const current = args[i];
1100
+ if (current === option) {
1101
+ const next = args[i + 1];
1102
+ if (!next || next.startsWith("-")) {
1103
+ throw new Error(`Missing value for ${option}`);
1104
+ }
1105
+ value = next;
1106
+ i += 1;
1107
+ continue;
1108
+ }
1109
+ if (current !== undefined) {
1110
+ rest.push(current);
1111
+ }
1112
+ }
1113
+ return { value, rest };
1114
+ }
1115
+ function printPins(pins) {
1116
+ if (Object.keys(pins).length === 0) {
1117
+ console.log("(none)");
1118
+ return;
1119
+ }
1120
+ for (const [key, value] of Object.entries(pins)) {
1121
+ console.log(`${key} ${value}`);
1122
+ }
1123
+ }
1124
+ function printAgentHelp() {
1125
+ console.log(`rig-agent \u2014 CLI for Project Rig agents
1126
+
1127
+ ORIENTATION:
1128
+ rig-agent info Your task, role, scope, deps \u2014 start here
1129
+ rig-agent scope [--files] Scope globs; --files expands to file list
1130
+ rig-agent deps Read dependency artifacts (decisions, next-actions)
1131
+ rig-agent lookup <id> Validate a beads task ID
1132
+ rig-agent status Epic/task progress overview
1133
+
1134
+ EXECUTION:
1135
+ rig-agent validate Run validation commands for your task
1136
+ rig-agent record decision "..." Record an architectural decision
1137
+ rig-agent record failure "..." Record a failed approach (cross-session only \u2014 not re-read in this session)
1138
+ rig-agent memory observe ... Promote a shared memory immediately
1139
+ rig-agent memory recall [query] Recall relevant shared memories
1140
+ rig-agent git status Task-aware git status
1141
+ rig-agent git changed Changed files (--scoped for scope-filtered)
1142
+ rig-agent git commit Task-aware commit (--target monorepo|project|both)
1143
+ rig-agent git snapshot Capture worktree state
1144
+ rig-agent git sync-branch Ensure task branch exists
1145
+ rig-agent git open-pr Create PR for task changes
1146
+ rig-agent repo sync Ensure monorepo checkout + task repo pins
1147
+ rig-agent profile show Show runtime profile
1148
+ rig-agent review show Show AI review gate settings
1149
+
1150
+ COMPLETION:
1151
+ rig-agent artifacts Scaffold completion artifacts (templates)
1152
+ rig-agent artifact-dir Print absolute artifact directory path
1153
+ rig-agent project-root Print absolute task worktree root
1154
+ rig-agent monorepo-root Print absolute monorepo root in the task worktree
1155
+ rig-agent artifact-write <filename> Write artifact from stdin
1156
+ rig-agent completion-verification Run final validation/review gate
1157
+ rig-agent completition-verification Alias for the same final gate
1158
+
1159
+ WORKFLOW:
1160
+ 1. rig-agent info Understand your assignment
1161
+ 2. rig-agent deps Read what prior tasks decided
1162
+ 3. rig-agent repo sync Align monorepo checkout + repo pins
1163
+ 4. (do your work)
1164
+ 5. rig-agent record decision "chose X because Y"
1165
+ 6. rig-agent validate Check your work
1166
+ 7. rig-agent artifacts Scaffold completion artifacts
1167
+ 8. rig-agent artifact-write collection-audit.md (write custom artifacts)
1168
+ 9. rig-agent completion-verification
1169
+ `);
1170
+ }
1171
+ async function runCompletionVerification(projectRoot) {
1172
+ const host = await buildProjectPluginHost(projectRoot);
1173
+ const run = host ? await defineCapability4(COMPLETION_VERIFICATION_CAPABILITY).resolve(host) : null;
1174
+ if (!run) {
1175
+ console.error("[rig-agent] Completion verification requires the @rig/bundle-default-lifecycle plugin in rig.config.");
1176
+ return 1;
1177
+ }
1178
+ const { ok } = await run({ projectRoot });
1179
+ return ok ? 0 : 1;
1180
+ }
1181
+ async function runInternal(args) {
1182
+ const [command = "", ...rest] = args;
1183
+ if (command === "shell") {
1184
+ const code = await runControlledBash(rest, { projectRootFallbackDir: import.meta.dir });
1185
+ process.exit(code);
1186
+ }
1187
+ if (command === "manifest-verify") {
1188
+ await verifyRuntimeManifest();
1189
+ console.log("manifest: ok");
1190
+ return;
1191
+ }
1192
+ throw new Error("Unknown internal command. Use `rig-agent internal shell <bash-args...>` or `rig-agent internal manifest-verify`.");
1193
+ }
1194
+ async function verifyRuntimeManifest() {
1195
+ if (getContext()) {
1196
+ return;
1197
+ }
1198
+ const manifestPath = BAKED_MANIFEST_PATH;
1199
+ if (!manifestPath) {
1200
+ return;
1201
+ }
1202
+ if (!existsSync3(manifestPath)) {
1203
+ throw new Error(`[rig-agent] Runtime manifest missing: ${manifestPath}`);
1204
+ }
1205
+ let manifest;
1206
+ try {
1207
+ manifest = await Bun.file(manifestPath).json();
1208
+ } catch (error) {
1209
+ throw new Error(`[rig-agent] Failed to parse runtime manifest at ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`);
1210
+ }
1211
+ assertMatch("taskId", BAKED_TASK_ID, manifest.taskId);
1212
+ assertMatch("runtimeId", BAKED_RUNTIME_ID, manifest.runtimeId);
1213
+ assertMatch("scopeHash", BAKED_SCOPE_HASH, manifest.scopeHash);
1214
+ const manifestBinaryPath = manifest.binary?.path || BAKED_BINARY_PATH || process.execPath;
1215
+ const expectedHash = manifest.binary?.sha256 || "";
1216
+ if (!manifestBinaryPath || !expectedHash) {
1217
+ throw new Error(`[rig-agent] Runtime manifest is missing binary hash data (${manifestPath}).`);
1218
+ }
1219
+ if (!existsSync3(manifestBinaryPath)) {
1220
+ throw new Error(`[rig-agent] Runtime binary not found at ${manifestBinaryPath}.`);
1221
+ }
1222
+ const actualHash = sha256Hex(readFileSync2(resolve3(manifestBinaryPath)));
1223
+ if (actualHash !== expectedHash) {
1224
+ throw new Error(`[rig-agent] Runtime manifest mismatch for binary hash.
1225
+ ` + `expected=${expectedHash}
1226
+ ` + `actual=${actualHash}
1227
+ ` + `path=${manifestBinaryPath}`);
1228
+ }
1229
+ }
1230
+ function assertMatch(name, expected, actual) {
1231
+ if (!expected && !actual) {
1232
+ return;
1233
+ }
1234
+ if (expected !== (actual || "")) {
1235
+ throw new Error(`[rig-agent] Runtime manifest mismatch for ${name}: expected='${expected}' actual='${actual || ""}'.`);
1236
+ }
1237
+ }
1238
+ main().catch((error) => {
1239
+ console.error(error instanceof Error ? error.message : String(error));
1240
+ process.exit(1);
1241
+ });
1242
+ export {
1243
+ looksLikeShellInvocation
1244
+ };