@h-rig/cli 0.0.6-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +30 -0
  2. package/dist/bin/build-rig-binaries.js +107 -0
  3. package/dist/bin/rig.js +9330 -0
  4. package/dist/src/commands/_authority-runs.js +110 -0
  5. package/dist/src/commands/_connection-state.js +123 -0
  6. package/dist/src/commands/_doctor-checks.js +501 -0
  7. package/dist/src/commands/_operator-view.js +322 -0
  8. package/dist/src/commands/_parsers.js +107 -0
  9. package/dist/src/commands/_paths.js +50 -0
  10. package/dist/src/commands/_pi-install.js +184 -0
  11. package/dist/src/commands/_policy.js +79 -0
  12. package/dist/src/commands/_preflight.js +460 -0
  13. package/dist/src/commands/_probes.js +13 -0
  14. package/dist/src/commands/_run-driver-helpers.js +289 -0
  15. package/dist/src/commands/_server-client.js +364 -0
  16. package/dist/src/commands/_snapshot-upload.js +313 -0
  17. package/dist/src/commands/_task-picker.js +48 -0
  18. package/dist/src/commands/agent.js +497 -0
  19. package/dist/src/commands/browser.js +890 -0
  20. package/dist/src/commands/connect.js +180 -0
  21. package/dist/src/commands/dist.js +402 -0
  22. package/dist/src/commands/doctor.js +511 -0
  23. package/dist/src/commands/github.js +276 -0
  24. package/dist/src/commands/inbox.js +160 -0
  25. package/dist/src/commands/init.js +1254 -0
  26. package/dist/src/commands/inspect.js +174 -0
  27. package/dist/src/commands/inspector.js +256 -0
  28. package/dist/src/commands/plugin.js +167 -0
  29. package/dist/src/commands/profile-and-review.js +178 -0
  30. package/dist/src/commands/queue.js +197 -0
  31. package/dist/src/commands/remote.js +507 -0
  32. package/dist/src/commands/repo-git-harness.js +221 -0
  33. package/dist/src/commands/run.js +753 -0
  34. package/dist/src/commands/server.js +368 -0
  35. package/dist/src/commands/setup.js +681 -0
  36. package/dist/src/commands/task-report-bug.js +1083 -0
  37. package/dist/src/commands/task-run-driver.js +1933 -0
  38. package/dist/src/commands/task.js +1325 -0
  39. package/dist/src/commands/test.js +39 -0
  40. package/dist/src/commands/workspace.js +123 -0
  41. package/dist/src/commands.js +9012 -0
  42. package/dist/src/index.js +9348 -0
  43. package/dist/src/launcher.js +131 -0
  44. package/dist/src/report-bug.js +260 -0
  45. package/dist/src/runner.js +272 -0
  46. package/dist/src/withMutedConsole.js +42 -0
  47. package/package.json +31 -0
@@ -0,0 +1,497 @@
1
+ // @bun
2
+ // packages/cli/src/commands/agent.ts
3
+ import { resolve as resolve2 } from "path";
4
+
5
+ // packages/cli/src/runner.ts
6
+ import { EventBus } from "@rig/runtime/control-plane/runtime/events";
7
+ import { CliError } from "@rig/runtime/control-plane/errors";
8
+ import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
9
+ import { PluginManager } from "@rig/runtime/control-plane/runtime/plugins";
10
+ import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/context";
11
+ import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
12
+ import { CliError as CliError2 } from "@rig/runtime/control-plane/errors";
13
+ function takeFlag(args, flag) {
14
+ const rest = [];
15
+ let value = false;
16
+ for (const arg of args) {
17
+ if (arg === flag) {
18
+ value = true;
19
+ continue;
20
+ }
21
+ rest.push(arg);
22
+ }
23
+ return { value, rest };
24
+ }
25
+ function takeOption(args, option) {
26
+ const rest = [];
27
+ let value;
28
+ for (let index = 0;index < args.length; index += 1) {
29
+ const current = args[index];
30
+ if (current === option) {
31
+ const next = args[index + 1];
32
+ if (!next || next.startsWith("-")) {
33
+ throw new CliError(`Missing value for ${option}`);
34
+ }
35
+ value = next;
36
+ index += 1;
37
+ continue;
38
+ }
39
+ if (current !== undefined) {
40
+ rest.push(current);
41
+ }
42
+ }
43
+ return { value, rest };
44
+ }
45
+ function requireNoExtraArgs(args, usage) {
46
+ if (args.length > 0) {
47
+ throw new CliError(`Unexpected arguments: ${args.join(" ")}
48
+ Usage: ${usage}`);
49
+ }
50
+ }
51
+
52
+ // packages/cli/src/commands/agent.ts
53
+ import {
54
+ agentId,
55
+ cleanupAgentRuntime,
56
+ ensureAgentRuntime,
57
+ listAgentRuntimes,
58
+ runInAgentRuntime
59
+ } from "@rig/runtime/control-plane/runtime/isolation";
60
+
61
+ // packages/cli/src/commands/_authority-runs.ts
62
+ import { existsSync } from "fs";
63
+ import { resolve } from "path";
64
+ import {
65
+ readAuthorityRun,
66
+ readJsonlFile,
67
+ resolveAuthorityRunDir,
68
+ writeJsonFile
69
+ } from "@rig/runtime/control-plane/authority-files";
70
+
71
+ // packages/cli/src/commands/_paths.ts
72
+ import { resolveMonorepoRoot } from "@rig/runtime/control-plane/native/utils";
73
+ function resolveControlPlaneMonorepoRoot(projectRoot) {
74
+ return resolveMonorepoRoot(projectRoot);
75
+ }
76
+
77
+ // packages/cli/src/commands/_authority-runs.ts
78
+ var RIG_WORKSPACE_ID = "rig-local-workspace";
79
+ function normalizeRuntimeAdapter(value) {
80
+ const normalized = value?.trim().toLowerCase();
81
+ if (!normalized) {
82
+ return "pi";
83
+ }
84
+ if (normalized === "codex" || normalized === "codex-cli" || normalized === "codex-app-server" || normalized === "gpt-codex") {
85
+ return "codex";
86
+ }
87
+ if (normalized === "pi" || normalized === "rig-pi" || normalized === "@rig/pi") {
88
+ return "pi";
89
+ }
90
+ return "claude-code";
91
+ }
92
+ function readLatestBeadRecord(projectRoot, taskId) {
93
+ const issuesPath = resolve(resolveControlPlaneMonorepoRoot(projectRoot), ".beads", "issues.jsonl");
94
+ if (!existsSync(issuesPath)) {
95
+ return null;
96
+ }
97
+ let latest = null;
98
+ for (const issue of readJsonlFile(issuesPath)) {
99
+ if (!issue || typeof issue !== "object") {
100
+ continue;
101
+ }
102
+ const record = issue;
103
+ if (record.id === taskId) {
104
+ latest = record;
105
+ }
106
+ }
107
+ return latest;
108
+ }
109
+ function resolveTaskTitleForAuthorityRun(projectRoot, taskId) {
110
+ try {
111
+ const record = readLatestBeadRecord(projectRoot, taskId);
112
+ const title = record && typeof record.title === "string" ? record.title.trim() : "";
113
+ if (title) {
114
+ return title;
115
+ }
116
+ } catch {}
117
+ return null;
118
+ }
119
+ function upsertAgentAuthorityRun(projectRoot, input) {
120
+ const current = readAuthorityRun(projectRoot, input.runId);
121
+ const existing = current;
122
+ const createdAt = existing?.createdAt ?? input.createdAt;
123
+ const runtimeMode = typeof existing?.runtimeMode === "string" ? existing.runtimeMode : "full-access";
124
+ const interactionMode = typeof existing?.interactionMode === "string" ? existing.interactionMode : "default";
125
+ const runMode = typeof existing?.runMode === "string" ? existing.runMode : "autonomous";
126
+ const runtimeAdapter = normalizeRuntimeAdapter(input.runtimeAdapter ?? existing?.runtimeAdapter ?? "claude-code");
127
+ const title = resolveTaskTitleForAuthorityRun(projectRoot, input.taskId) ?? input.taskId;
128
+ const next = {
129
+ runId: input.runId,
130
+ projectRoot,
131
+ workspaceId: existing?.workspaceId ?? RIG_WORKSPACE_ID,
132
+ taskId: input.taskId,
133
+ threadId: existing?.threadId ?? null,
134
+ mode: "local",
135
+ runtimeAdapter,
136
+ status: input.status,
137
+ createdAt,
138
+ startedAt: input.startedAt ?? existing?.startedAt ?? null,
139
+ completedAt: input.completedAt ?? existing?.completedAt ?? null,
140
+ endpointId: existing?.endpointId ?? null,
141
+ hostId: existing?.hostId ?? null,
142
+ worktreePath: input.worktreePath ?? existing?.worktreePath ?? null,
143
+ artifactRoot: input.artifactRoot ?? existing?.artifactRoot ?? null,
144
+ logRoot: input.logRoot ?? existing?.logRoot ?? null,
145
+ sessionPath: input.sessionPath ?? existing?.sessionPath ?? null,
146
+ sessionLogPath: input.sessionLogPath ?? existing?.sessionLogPath ?? null,
147
+ pid: input.pid ?? existing?.pid ?? null,
148
+ updatedAt: input.createdAt,
149
+ title,
150
+ model: typeof existing?.model === "string" ? existing.model : null,
151
+ runtimeMode,
152
+ interactionMode,
153
+ runMode,
154
+ initialPrompt: typeof existing?.initialPrompt === "string" ? existing.initialPrompt : null
155
+ };
156
+ if (input.errorText !== undefined) {
157
+ next.errorText = input.errorText;
158
+ } else if ("errorText" in next) {
159
+ delete next.errorText;
160
+ }
161
+ writeJsonFile(resolve(resolveAuthorityRunDir(projectRoot, input.runId), "run.json"), next);
162
+ return next;
163
+ }
164
+
165
+ // packages/cli/src/withMutedConsole.ts
166
+ function isPromise(value) {
167
+ if (typeof value !== "object" && typeof value !== "function") {
168
+ return false;
169
+ }
170
+ return value !== null && typeof value.then === "function";
171
+ }
172
+ function withMutedConsole(mute, fn) {
173
+ if (!mute) {
174
+ return fn();
175
+ }
176
+ const originalLog = console.log;
177
+ const originalWarn = console.warn;
178
+ const originalInfo = console.info;
179
+ const restore = () => {
180
+ console.log = originalLog;
181
+ console.warn = originalWarn;
182
+ console.info = originalInfo;
183
+ };
184
+ console.log = () => {};
185
+ console.warn = () => {};
186
+ console.info = () => {};
187
+ try {
188
+ const result = fn();
189
+ if (isPromise(result)) {
190
+ return result.finally(restore);
191
+ }
192
+ restore();
193
+ return result;
194
+ } catch (error) {
195
+ restore();
196
+ throw error;
197
+ } finally {
198
+ if (console.log === originalLog) {
199
+ restore();
200
+ }
201
+ }
202
+ }
203
+
204
+ // packages/cli/src/commands/_parsers.ts
205
+ function parseIsolationMode(value, allowOff) {
206
+ if (!value) {
207
+ return "worktree";
208
+ }
209
+ if (value === "worktree") {
210
+ return value;
211
+ }
212
+ if (allowOff && value === "off") {
213
+ return value;
214
+ }
215
+ throw new CliError2(`Invalid isolation mode: ${value}. Use ${allowOff ? "off|" : ""}worktree.`);
216
+ }
217
+
218
+ // packages/cli/src/commands/_preflight.ts
219
+ import { ensureProjectMainFreshBeforeRun } from "@rig/runtime/control-plane/project-main-pre-run-sync";
220
+
221
+ // packages/cli/src/commands/_server-client.ts
222
+ import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
223
+
224
+ // packages/cli/src/commands/_preflight.ts
225
+ async function runProjectMainSyncPreflight(context, options) {
226
+ if (context.dryRun) {
227
+ if (context.outputMode === "text" && !options.disabled) {
228
+ console.log("[dry-run] project-rig pre-run sync check");
229
+ }
230
+ return;
231
+ }
232
+ const result = await ensureProjectMainFreshBeforeRun({
233
+ projectRoot: context.projectRoot,
234
+ disabled: options.disabled,
235
+ runBootstrap: async () => {
236
+ const bootstrap = await context.runCommand(["bun", "run", "bootstrap"]);
237
+ if (bootstrap.exitCode !== 0) {
238
+ throw new CliError2(bootstrap.stderr || bootstrap.stdout || "bun run bootstrap failed during project pre-run sync", bootstrap.exitCode || 1);
239
+ }
240
+ }
241
+ });
242
+ if (context.outputMode !== "text") {
243
+ return;
244
+ }
245
+ switch (result.status) {
246
+ case "disabled":
247
+ console.log("Project pre-run sync skipped (--skip-project-sync).");
248
+ break;
249
+ case "skipped_not_main":
250
+ console.log(`Project pre-run sync skipped (current branch: ${result.branch}).`);
251
+ break;
252
+ case "up_to_date":
253
+ break;
254
+ case "local_ahead":
255
+ console.log(`Project pre-run sync skipped (local main ahead by ${result.localAhead} commit(s)).`);
256
+ break;
257
+ case "updated":
258
+ console.log(`Project pre-run sync updated local main from origin/main (+${result.remoteAhead}) and bootstrapped.`);
259
+ break;
260
+ }
261
+ }
262
+
263
+ // packages/cli/src/commands/agent.ts
264
+ function splitAtDoubleDash(args) {
265
+ const separatorIndex = args.indexOf("--");
266
+ if (separatorIndex === -1) {
267
+ return { options: args, commandParts: [] };
268
+ }
269
+ return {
270
+ options: args.slice(0, separatorIndex),
271
+ commandParts: args.slice(separatorIndex + 1)
272
+ };
273
+ }
274
+ async function attachEventBusToProvisionedRuntime(context, workspaceDir) {
275
+ const previousWorkspace = process.env.RIG_TASK_WORKSPACE;
276
+ process.env.RIG_TASK_WORKSPACE = workspaceDir;
277
+ try {
278
+ await context.eventBus.attachRuntimeWorkspace(context.projectRoot);
279
+ } finally {
280
+ if (previousWorkspace === undefined) {
281
+ delete process.env.RIG_TASK_WORKSPACE;
282
+ } else {
283
+ process.env.RIG_TASK_WORKSPACE = previousWorkspace;
284
+ }
285
+ }
286
+ }
287
+ async function executeAgent(context, args) {
288
+ const [command = "list", ...rest] = args;
289
+ switch (command) {
290
+ case "list": {
291
+ requireNoExtraArgs(rest, "bun run rig agent list");
292
+ const runtimes = await listAgentRuntimes(context.projectRoot);
293
+ if (context.outputMode === "text") {
294
+ if (runtimes.length === 0) {
295
+ console.log("No agent runtimes.");
296
+ } else {
297
+ for (const runtime of runtimes) {
298
+ console.log(`${runtime.id} (${runtime.mode}) workspace=${runtime.workspaceDir} created=${runtime.createdAt}`);
299
+ }
300
+ }
301
+ }
302
+ return { ok: true, group: "agent", command, details: { runtimes } };
303
+ }
304
+ case "prepare": {
305
+ let pending = rest;
306
+ const idResult = takeOption(pending, "--id");
307
+ pending = idResult.rest;
308
+ const modeResult = takeOption(pending, "--mode");
309
+ pending = modeResult.rest;
310
+ const taskResult = takeOption(pending, "--task");
311
+ pending = taskResult.rest;
312
+ requireNoExtraArgs(pending, "bun run rig agent prepare --task <id> [--id <id>] [--mode worktree]");
313
+ const mode = parseIsolationMode(modeResult.value, false);
314
+ const id = idResult.value || agentId("agent");
315
+ const taskId = taskResult.value?.trim();
316
+ if (!taskId) {
317
+ throw new CliError2("Usage: bun run rig agent prepare --task <id> [--id <id>] [--mode worktree]");
318
+ }
319
+ const runtime = await withMutedConsole(context.outputMode === "json", () => ensureAgentRuntime({
320
+ projectRoot: context.projectRoot,
321
+ id,
322
+ taskId,
323
+ mode
324
+ }));
325
+ await attachEventBusToProvisionedRuntime(context, runtime.workspaceDir);
326
+ if (context.outputMode === "text") {
327
+ console.log(`Prepared runtime ${runtime.id} (${runtime.mode})`);
328
+ console.log(`Workspace: ${runtime.workspaceDir}`);
329
+ }
330
+ return { ok: true, group: "agent", command, details: { runtime } };
331
+ }
332
+ case "run": {
333
+ const { options, commandParts } = splitAtDoubleDash(rest);
334
+ if (commandParts.length === 0) {
335
+ throw new CliError2("Usage: bun run rig agent run [--id <id>] [--mode worktree] [--skip-project-sync] -- <command...>");
336
+ }
337
+ let pending = options;
338
+ const idResult = takeOption(pending, "--id");
339
+ pending = idResult.rest;
340
+ const modeResult = takeOption(pending, "--mode");
341
+ pending = modeResult.rest;
342
+ const taskResult = takeOption(pending, "--task");
343
+ pending = taskResult.rest;
344
+ const skipProjectSyncResult = takeFlag(pending, "--skip-project-sync");
345
+ pending = skipProjectSyncResult.rest;
346
+ requireNoExtraArgs(pending, "bun run rig agent run --task <id> [--id <id>] [--mode worktree] [--skip-project-sync] -- <command...>");
347
+ const mode = parseIsolationMode(modeResult.value, false);
348
+ const id = idResult.value || agentId("agent-run");
349
+ const taskId = taskResult.value?.trim();
350
+ if (!taskId) {
351
+ throw new CliError2("Usage: bun run rig agent run --task <id> [--id <id>] [--mode worktree] [--skip-project-sync] -- <command...>");
352
+ }
353
+ await runProjectMainSyncPreflight(context, { disabled: skipProjectSyncResult.value });
354
+ const createdAt = new Date().toISOString();
355
+ upsertAgentAuthorityRun(context.projectRoot, {
356
+ runId: id,
357
+ taskId,
358
+ createdAt,
359
+ runtimeAdapter: process.env.RIG_RUNTIME_ADAPTER || "claude-code",
360
+ status: "preparing",
361
+ startedAt: createdAt
362
+ });
363
+ try {
364
+ const runtime = await withMutedConsole(context.outputMode === "json", () => ensureAgentRuntime({
365
+ projectRoot: context.projectRoot,
366
+ id,
367
+ taskId,
368
+ mode
369
+ }));
370
+ await attachEventBusToProvisionedRuntime(context, runtime.workspaceDir);
371
+ const runningAt = new Date().toISOString();
372
+ upsertAgentAuthorityRun(context.projectRoot, {
373
+ runId: runtime.id,
374
+ taskId,
375
+ createdAt: runningAt,
376
+ runtimeAdapter: process.env.RIG_RUNTIME_ADAPTER || "claude-code",
377
+ status: "running",
378
+ startedAt: createdAt,
379
+ worktreePath: runtime.workspaceDir,
380
+ artifactRoot: resolve2(runtime.workspaceDir, "artifacts", taskId),
381
+ logRoot: runtime.logsDir,
382
+ sessionPath: resolve2(runtime.sessionDir, "session.json"),
383
+ sessionLogPath: resolve2(runtime.logsDir, "agent-stdout.log"),
384
+ pid: process.pid
385
+ });
386
+ const result = await runInAgentRuntime({
387
+ projectRoot: context.projectRoot,
388
+ runtime,
389
+ command: commandParts,
390
+ inheritStdio: context.outputMode === "text"
391
+ });
392
+ if (result.exitCode !== 0) {
393
+ const failedAt = new Date().toISOString();
394
+ upsertAgentAuthorityRun(context.projectRoot, {
395
+ runId: runtime.id,
396
+ taskId,
397
+ createdAt: failedAt,
398
+ runtimeAdapter: process.env.RIG_RUNTIME_ADAPTER || "claude-code",
399
+ status: "failed",
400
+ startedAt: createdAt,
401
+ completedAt: failedAt,
402
+ worktreePath: runtime.workspaceDir,
403
+ artifactRoot: resolve2(runtime.workspaceDir, "artifacts", taskId),
404
+ logRoot: runtime.logsDir,
405
+ sessionPath: resolve2(runtime.sessionDir, "session.json"),
406
+ sessionLogPath: resolve2(runtime.logsDir, "agent-stdout.log"),
407
+ pid: process.pid,
408
+ errorText: result.stderr ? result.stderr.trim() : `Agent runtime command failed (${result.exitCode})`
409
+ });
410
+ throw new CliError2(`Agent runtime command failed (${result.exitCode}) in ${runtime.id}${result.stderr ? `
411
+ ${result.stderr.trim()}` : ""}`, result.exitCode);
412
+ }
413
+ const completedAt = new Date().toISOString();
414
+ upsertAgentAuthorityRun(context.projectRoot, {
415
+ runId: runtime.id,
416
+ taskId,
417
+ createdAt: completedAt,
418
+ runtimeAdapter: process.env.RIG_RUNTIME_ADAPTER || "claude-code",
419
+ status: "completed",
420
+ startedAt: createdAt,
421
+ completedAt,
422
+ worktreePath: runtime.workspaceDir,
423
+ artifactRoot: resolve2(runtime.workspaceDir, "artifacts", taskId),
424
+ logRoot: runtime.logsDir,
425
+ sessionPath: resolve2(runtime.sessionDir, "session.json"),
426
+ sessionLogPath: resolve2(runtime.logsDir, "agent-stdout.log"),
427
+ pid: process.pid
428
+ });
429
+ return {
430
+ ok: true,
431
+ group: "agent",
432
+ command,
433
+ details: {
434
+ runtimeId: runtime.id,
435
+ mode: runtime.mode,
436
+ command: commandParts,
437
+ exitCode: result.exitCode,
438
+ sandboxBackend: result.sandboxBackend,
439
+ sandboxEnabled: result.sandboxEnabled,
440
+ stdout: result.stdout,
441
+ stderr: result.stderr
442
+ }
443
+ };
444
+ } catch (error) {
445
+ const failedAt = new Date().toISOString();
446
+ upsertAgentAuthorityRun(context.projectRoot, {
447
+ runId: id,
448
+ taskId,
449
+ createdAt: failedAt,
450
+ runtimeAdapter: process.env.RIG_RUNTIME_ADAPTER || "claude-code",
451
+ status: "failed",
452
+ startedAt: createdAt,
453
+ completedAt: failedAt,
454
+ errorText: error instanceof Error ? error.message : String(error)
455
+ });
456
+ throw error;
457
+ }
458
+ }
459
+ case "cleanup": {
460
+ let pending = rest;
461
+ const allResult = takeFlag(pending, "--all");
462
+ pending = allResult.rest;
463
+ const idResult = takeOption(pending, "--id");
464
+ pending = idResult.rest;
465
+ requireNoExtraArgs(pending, "bun run rig agent cleanup (--id <id> | --all)");
466
+ if (!allResult.value && !idResult.value) {
467
+ throw new CliError2("Provide --id <id> or --all.");
468
+ }
469
+ const runtimes = await listAgentRuntimes(context.projectRoot);
470
+ const targets = allResult.value ? runtimes.map((runtime) => runtime.id) : [idResult.value];
471
+ for (const id of targets) {
472
+ await cleanupAgentRuntime({
473
+ projectRoot: context.projectRoot,
474
+ id
475
+ });
476
+ }
477
+ if (context.outputMode === "text") {
478
+ console.log(`Cleaned runtimes: ${targets.join(", ")}`);
479
+ }
480
+ return {
481
+ ok: true,
482
+ group: "agent",
483
+ command,
484
+ details: {
485
+ cleaned: targets,
486
+ count: targets.length,
487
+ all: allResult.value
488
+ }
489
+ };
490
+ }
491
+ default:
492
+ throw new CliError2(`Unknown agent command: ${command}`);
493
+ }
494
+ }
495
+ export {
496
+ executeAgent
497
+ };