@h-rig/cli 0.0.6-alpha.9 → 0.0.6-alpha.91

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 (116) hide show
  1. package/README.md +18 -19
  2. package/dist/bin/build-rig-binaries.d.ts +2 -0
  3. package/dist/bin/build-rig-binaries.js +22 -10
  4. package/dist/bin/rig.d.ts +72 -0
  5. package/dist/bin/rig.js +15637 -7344
  6. package/dist/config/rig-default-config.yml +5 -0
  7. package/dist/src/app/drone-ui.d.ts +34 -0
  8. package/dist/src/app/drone-ui.js +278 -0
  9. package/dist/src/commands/_async-ui.d.ts +10 -0
  10. package/dist/src/commands/_async-ui.js +121 -0
  11. package/dist/src/commands/_cli-format.d.ts +56 -0
  12. package/dist/src/commands/_cli-format.js +319 -0
  13. package/dist/src/commands/_connection-state.d.ts +54 -0
  14. package/dist/src/commands/_connection-state.js +75 -11
  15. package/dist/src/commands/_doctor-checks.d.ts +46 -0
  16. package/dist/src/commands/_doctor-checks.js +100 -267
  17. package/dist/src/commands/_help-catalog.d.ts +51 -0
  18. package/dist/src/commands/_help-catalog.js +502 -0
  19. package/dist/src/commands/_inprocess-services.d.ts +33 -0
  20. package/dist/src/commands/_inprocess-services.js +102 -0
  21. package/dist/src/commands/_json-output.d.ts +11 -0
  22. package/dist/src/commands/_json-output.js +60 -0
  23. package/dist/src/commands/_lazy-reconcile.d.ts +34 -0
  24. package/dist/src/commands/_lazy-reconcile.js +102 -0
  25. package/dist/src/commands/_parsers.d.ts +15 -0
  26. package/dist/src/commands/_parsers.js +18 -11
  27. package/dist/src/commands/_paths.d.ts +11 -0
  28. package/dist/src/commands/_paths.js +1 -1
  29. package/dist/src/commands/_pi-frontend.d.ts +35 -0
  30. package/dist/src/commands/_pi-frontend.js +64 -0
  31. package/dist/src/commands/_pi-install.d.ts +42 -0
  32. package/dist/src/commands/_pi-install.js +19 -36
  33. package/dist/src/commands/_policy.d.ts +8 -0
  34. package/dist/src/commands/_policy.js +67 -19
  35. package/dist/src/commands/_probes.d.ts +1 -0
  36. package/dist/src/commands/_run-bridge.d.ts +114 -0
  37. package/dist/src/commands/_run-bridge.js +387 -0
  38. package/dist/src/commands/_run-diagnostics.d.ts +9 -0
  39. package/dist/src/commands/_run-diagnostics.js +51 -0
  40. package/dist/src/commands/_run-driver-helpers.d.ts +26 -0
  41. package/dist/src/commands/_run-driver-helpers.js +79 -230
  42. package/dist/src/commands/_run-projection.d.ts +50 -0
  43. package/dist/src/commands/_run-projection.js +349 -0
  44. package/dist/src/commands/_run-subcommands.d.ts +3 -0
  45. package/dist/src/commands/_run-subcommands.js +31 -0
  46. package/dist/src/commands/_spinner.d.ts +25 -0
  47. package/dist/src/commands/_spinner.js +65 -0
  48. package/dist/src/commands/agent.d.ts +3 -0
  49. package/dist/src/commands/agent.js +8575 -236
  50. package/dist/src/commands/dist.d.ts +28 -0
  51. package/dist/src/commands/dist.js +44 -29
  52. package/dist/src/commands/doctor.d.ts +3 -0
  53. package/dist/src/commands/doctor.js +219 -268
  54. package/dist/src/commands/github.d.ts +3 -0
  55. package/dist/src/commands/github.js +236 -188
  56. package/dist/src/commands/inbox.d.ts +28 -0
  57. package/dist/src/commands/inbox.js +530 -111
  58. package/dist/src/commands/init.d.ts +64 -0
  59. package/dist/src/commands/init.js +912 -705
  60. package/dist/src/commands/inspect.d.ts +20 -0
  61. package/dist/src/commands/inspect.js +709 -119
  62. package/dist/src/commands/pi.d.ts +3 -0
  63. package/dist/src/commands/pi.js +177 -0
  64. package/dist/src/commands/plugin.d.ts +16 -0
  65. package/dist/src/commands/plugin.js +576 -29
  66. package/dist/src/commands/profile-and-review.d.ts +4 -0
  67. package/dist/src/commands/profile-and-review.js +112 -67
  68. package/dist/src/commands/queue.d.ts +3 -0
  69. package/dist/src/commands/queue.js +20 -20
  70. package/dist/src/commands/remote.d.ts +3 -0
  71. package/dist/src/commands/remote.js +880 -50
  72. package/dist/src/commands/repo-git-harness.d.ts +5 -0
  73. package/dist/src/commands/repo-git-harness.js +78 -28
  74. package/dist/src/commands/run.d.ts +21 -0
  75. package/dist/src/commands/run.js +17701 -661
  76. package/dist/src/commands/server.d.ts +3 -0
  77. package/dist/src/commands/server.js +166 -303
  78. package/dist/src/commands/setup.d.ts +16 -0
  79. package/dist/src/commands/setup.js +244 -299
  80. package/dist/src/commands/stats.d.ts +15 -0
  81. package/dist/src/commands/stats.js +979 -0
  82. package/dist/src/commands/task-run-driver.d.ts +94 -0
  83. package/dist/src/commands/task-run-driver.js +116 -1961
  84. package/dist/src/commands/task.d.ts +35 -0
  85. package/dist/src/commands/task.js +676 -1201
  86. package/dist/src/commands/test.d.ts +3 -0
  87. package/dist/src/commands/test.js +15 -8
  88. package/dist/src/commands/triage.d.ts +11 -0
  89. package/dist/src/commands/triage.js +227 -0
  90. package/dist/src/commands/workspace.d.ts +3 -0
  91. package/dist/src/commands/workspace.js +18 -11
  92. package/dist/src/commands.d.ts +13 -0
  93. package/dist/src/commands.js +16792 -8055
  94. package/dist/src/index.d.ts +4 -0
  95. package/dist/src/index.js +16862 -8450
  96. package/dist/src/launcher.d.ts +61 -0
  97. package/dist/src/launcher.js +81 -13
  98. package/dist/src/operator-cli.d.ts +2 -0
  99. package/dist/src/operator-cli.js +17837 -0
  100. package/dist/src/operator-entry.d.ts +1 -0
  101. package/dist/src/operator-entry.js +3 -0
  102. package/dist/src/runner.d.ts +47 -0
  103. package/dist/src/runner.js +16 -22
  104. package/dist/src/withMutedConsole.d.ts +2 -0
  105. package/package.json +21 -8
  106. package/dist/src/commands/_authority-runs.js +0 -111
  107. package/dist/src/commands/_operator-view.js +0 -340
  108. package/dist/src/commands/_preflight.js +0 -478
  109. package/dist/src/commands/_server-client.js +0 -382
  110. package/dist/src/commands/_snapshot-upload.js +0 -331
  111. package/dist/src/commands/_task-picker.js +0 -48
  112. package/dist/src/commands/browser.js +0 -890
  113. package/dist/src/commands/connect.js +0 -180
  114. package/dist/src/commands/inspector.js +0 -256
  115. package/dist/src/commands/task-report-bug.js +0 -1083
  116. package/dist/src/report-bug.js +0 -260
@@ -1,16 +1,28 @@
1
1
  // @bun
2
2
  // packages/cli/src/commands/inspect.ts
3
- import { existsSync, readFileSync } from "fs";
4
- import { resolve } from "path";
3
+ import { RIG_RUN_LOG_ENTRY } from "@rig/contracts";
4
+ import {
5
+ changedFilesForTask,
6
+ taskArtifactRead,
7
+ taskArtifacts,
8
+ taskDeps
9
+ } from "@rig/runtime/control-plane/native/task-ops";
5
10
 
6
11
  // packages/cli/src/runner.ts
7
12
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
8
- import { CliError } from "@rig/runtime/control-plane/errors";
13
+ import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
9
14
  import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
10
- import { PluginManager } from "@rig/runtime/control-plane/runtime/plugins";
11
- import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/context";
12
15
  import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
13
- import { CliError as CliError2 } from "@rig/runtime/control-plane/errors";
16
+
17
+ class CliError extends RuntimeCliError {
18
+ hint;
19
+ constructor(message, exitCode = 1, options = {}) {
20
+ super(message, exitCode);
21
+ if (options.hint?.trim()) {
22
+ this.hint = options.hint.trim();
23
+ }
24
+ }
25
+ }
14
26
  function takeOption(args, option) {
15
27
  const rest = [];
16
28
  let value;
@@ -19,7 +31,7 @@ function takeOption(args, option) {
19
31
  if (current === option) {
20
32
  const next = args[index + 1];
21
33
  if (!next || next.startsWith("-")) {
22
- throw new CliError(`Missing value for ${option}`);
34
+ throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
23
35
  }
24
36
  value = next;
25
37
  index += 1;
@@ -45,128 +57,706 @@ Usage: ${usage}`);
45
57
  return taskId;
46
58
  }
47
59
 
48
- // packages/cli/src/commands/inspect.ts
60
+ // packages/cli/src/commands/_cli-format.ts
61
+ import pc from "picocolors";
62
+ var dim = pc.dim;
63
+ var faintBar = pc.dim("\u2502");
64
+ var accent = pc.cyan;
65
+ function truncate(value, width) {
66
+ return value.length <= width ? value : `${value.slice(0, Math.max(0, width - 1))}\u2026`;
67
+ }
68
+ function pad(value, width) {
69
+ return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
70
+ }
71
+ function statusColor(status) {
72
+ const normalized = status.trim().toLowerCase();
73
+ if (["done", "completed", "ready", "healthy", "open", "approved"].includes(normalized))
74
+ return pc.green;
75
+ if (["failed", "error", "blocked", "rejected", "stopped"].includes(normalized))
76
+ return pc.red;
77
+ if (["running", "in_progress", "in-progress", "active", "booting"].includes(normalized))
78
+ return pc.cyan;
79
+ if (["pending", "queued", "created", "local"].includes(normalized))
80
+ return pc.yellow;
81
+ return pc.dim;
82
+ }
83
+ function firstString(record, keys, fallback = "") {
84
+ for (const key of keys) {
85
+ const value = record[key];
86
+ if (typeof value === "string" && value.trim())
87
+ return value;
88
+ }
89
+ return fallback;
90
+ }
91
+ function runIdOf(run) {
92
+ return firstString(run, ["runId", "id"], "(unknown-run)");
93
+ }
94
+ function taskIdOf(run) {
95
+ return firstString(run, ["taskId", "task", "task_id"]);
96
+ }
97
+ function runTitleOf(run) {
98
+ return firstString(run, ["title", "summary", "name"], taskIdOf(run) || "(untitled)");
99
+ }
100
+ function printFormattedOutput(message) {
101
+ console.log(message);
102
+ }
103
+ function formatSection(title, subtitle) {
104
+ return `${pc.bold(accent("\u25C6"))} ${pc.bold(title)}${subtitle ? dim(` \u2014 ${subtitle}`) : ""}`;
105
+ }
106
+ function formatLegacyAutomationSurface() {
107
+ return [];
108
+ }
109
+ function formatRunList(runs, options = {}) {
110
+ if (runs.length === 0) {
111
+ return [
112
+ formatSection("Runs", "none recorded"),
113
+ options.source === "server" ? dim("No runs recorded on the selected server.") : dim("No runs recorded in local state."),
114
+ "",
115
+ ...formatLegacyAutomationSurface()
116
+ ].join(`
117
+ `);
118
+ }
119
+ const body = runs.map((run) => {
120
+ const row = run;
121
+ const runId = runIdOf(row);
122
+ const status = firstString(row, ["status"], "unknown");
123
+ const runtime = firstString(row, ["runtime", "runtimeAdapter"], "");
124
+ return [
125
+ pc.bold(runId),
126
+ statusColor(status)(pad(truncate(status, 12), 12)),
127
+ `${runTitleOf(row)}${runtime ? dim(` ${runtime}`) : ""}`
128
+ ].join(" ");
129
+ });
130
+ return [formatSection("Runs", options.source === "server" ? "selected server" : "local state"), ...body, "", ...formatLegacyAutomationSurface()].join(`
131
+ `);
132
+ }
133
+
134
+ // packages/cli/src/commands/_run-projection.ts
135
+ import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
136
+ import { resolve as resolve2 } from "path";
49
137
  import {
50
- listAuthorityRuns,
51
- readAuthorityRun,
52
- resolveAuthorityRunDir,
53
- resolveTaskArtifactDirs
54
- } from "@rig/runtime/control-plane/authority-files";
55
- import { changedFilesForTask } from "@rig/runtime/control-plane/native/task-ops";
56
- import { resolveHarnessPaths, resolveMonorepoRoot, runCapture } from "@rig/runtime/control-plane/native/utils";
57
- import { readTaskArtifactPreview } from "@rig/runtime/control-plane/native/workspace-ops";
58
- async function executeInspect(context, args) {
59
- const [command = "failures", ...rest] = args;
60
- switch (command) {
61
- case "logs": {
62
- const { value: task, rest: remaining } = takeOption(rest, "--task");
63
- requireNoExtraArgs(remaining, "bun run rig inspect logs --task <beads-id>");
64
- const requiredTask = requireTask(task, "bun run rig inspect logs --task <beads-id>");
65
- const latestRun = listAuthorityRuns(context.projectRoot).map((entry) => readAuthorityRun(context.projectRoot, entry.runId)).filter((run) => Boolean(run)).filter((run) => run.taskId === requiredTask).sort((left, right) => String(right.updatedAt ?? "").localeCompare(String(left.updatedAt ?? "")))[0];
66
- if (!latestRun) {
67
- throw new CliError2(`No runs found for ${requiredTask}.`);
68
- }
69
- const logsPath = resolve(resolveAuthorityRunDir(context.projectRoot, latestRun.runId), "logs.jsonl");
70
- if (!existsSync(logsPath)) {
71
- throw new CliError2(`No logs found for run ${latestRun.runId}.`);
72
- }
73
- await context.runCommand(["cat", logsPath]);
74
- return { ok: true, group: "inspect", command, details: { task: requiredTask, runId: latestRun.runId } };
75
- }
76
- case "artifacts": {
77
- const { value: task, rest: remaining } = takeOption(rest, "--task");
78
- requireNoExtraArgs(remaining, "bun run rig inspect artifacts --task <beads-id>");
79
- const requiredTask = requireTask(task, "bun run rig inspect artifacts --task <beads-id>");
80
- const artifactRoot = resolveTaskArtifactDirs(context.projectRoot, requiredTask).find((path) => existsSync(path));
81
- if (!artifactRoot) {
82
- throw new CliError2(`No artifacts found for ${requiredTask}.`);
83
- }
84
- await context.runCommand(["ls", "-la", artifactRoot]);
85
- return { ok: true, group: "inspect", command, details: { task: requiredTask } };
138
+ foldRunSessionEntries,
139
+ sessionIdFromSessionFile as sessionIdFromSessionFile2
140
+ } from "@rig/contracts";
141
+ import { listAgentRuntimes as listAgentRuntimes2 } from "@rig/runtime/control-plane/runtime/isolation";
142
+
143
+ // packages/cli/src/commands/_run-bridge.ts
144
+ import { existsSync, readdirSync, readFileSync } from "fs";
145
+ import { dirname, resolve } from "path";
146
+ import { CUSTOM_TYPE_FOR, sessionIdFromSessionFile } from "@rig/contracts";
147
+ import { createPluginHost } from "@rig/core";
148
+ import { loadConfig } from "@rig/core/load-config";
149
+ import { resolveOwnerNamespaceKey, resolveRegistryBaseUrl, resolveRegistrySecret, resolveSelectedRemote } from "@rig/runtime/control-plane/remote";
150
+ import { listAgentRuntimes } from "@rig/runtime/control-plane/runtime/isolation";
151
+ import { createRegistryClient } from "@rig/relay-registry";
152
+ import {
153
+ listActiveCollabSessions as ompListActiveCollabSessions
154
+ } from "@oh-my-pi/pi-coding-agent/collab/api";
155
+ function registrySecret(env = process.env) {
156
+ return resolveRegistrySecret(process.cwd(), env) ?? null;
157
+ }
158
+ function registryBaseUrl(env = process.env) {
159
+ return resolveRegistryBaseUrl(process.cwd(), env);
160
+ }
161
+ function collabFromRegistryEntry(entry) {
162
+ return {
163
+ sessionId: entry.roomId,
164
+ sessionPath: "",
165
+ cwd: "",
166
+ title: entry.title,
167
+ joinLink: entry.joinLink,
168
+ webLink: entry.webLink,
169
+ relayUrl: entry.relayUrl,
170
+ owner: entry.owner,
171
+ selectedRepo: entry.repo,
172
+ startedAt: entry.startedAt,
173
+ updatedAt: entry.heartbeatAt,
174
+ ...entry.pid === undefined ? {} : { pid: entry.pid },
175
+ stale: entry.stale
176
+ };
177
+ }
178
+ function isRecord(value) {
179
+ return typeof value === "object" && value !== null;
180
+ }
181
+ function readLocalRunCollab(runtime) {
182
+ if (!runtime.sessionDir || !existsSync(runtime.sessionDir))
183
+ return null;
184
+ let files;
185
+ try {
186
+ files = readdirSync(runtime.sessionDir).filter((f) => f.endsWith(".jsonl")).sort().reverse();
187
+ } catch {
188
+ return null;
189
+ }
190
+ for (const file of files) {
191
+ let lines;
192
+ try {
193
+ lines = readFileSync(resolve(runtime.sessionDir, file), "utf8").split(`
194
+ `);
195
+ } catch {
196
+ continue;
86
197
  }
87
- case "artifact": {
88
- let previewPending = rest;
89
- const task = takeOption(previewPending, "--task");
90
- previewPending = task.rest;
91
- const file = takeOption(previewPending, "--file");
92
- previewPending = file.rest;
93
- requireNoExtraArgs(previewPending, "bun run rig inspect artifact --task <beads-id> --file <name>");
94
- const requiredTask = requireTask(task.value, "bun run rig inspect artifact --task <beads-id> --file <name>");
95
- if (!file.value) {
96
- throw new CliError2("Missing --file for rig inspect artifact.");
198
+ let host = null;
199
+ for (const line of lines) {
200
+ if (!line.includes("collab-host-started"))
201
+ continue;
202
+ let entry;
203
+ try {
204
+ entry = JSON.parse(line);
205
+ } catch {
206
+ continue;
97
207
  }
98
- const preview = readTaskArtifactPreview(context.projectRoot, requiredTask, file.value);
99
- if (context.outputMode === "text") {
100
- console.log(preview.contents);
101
- if (preview.truncated) {
102
- console.log(`
103
- [preview truncated at ${preview.maxBytes} bytes of ${preview.sizeBytes}]`);
104
- }
105
- }
106
- return {
107
- ok: true,
108
- group: "inspect",
109
- command,
110
- details: {
111
- task: requiredTask,
112
- fileName: file.value,
113
- path: preview.path,
114
- sizeBytes: preview.sizeBytes,
115
- truncated: preview.truncated,
116
- maxBytes: preview.maxBytes,
117
- contents: context.outputMode === "json" ? preview.contents : null
118
- }
208
+ if (!isRecord(entry) || entry.customType !== CUSTOM_TYPE_FOR["timeline-entry"] || !isRecord(entry.data))
209
+ continue;
210
+ const payload = isRecord(entry.data.payload) ? entry.data.payload : entry.data;
211
+ if (payload.type !== "collab-host-started")
212
+ continue;
213
+ host = {
214
+ roomId: typeof payload.roomId === "string" ? payload.roomId : undefined,
215
+ joinLink: typeof payload.joinLink === "string" ? payload.joinLink : undefined,
216
+ webLink: typeof payload.webLink === "string" ? payload.webLink : undefined,
217
+ relayUrl: typeof payload.relayUrl === "string" ? payload.relayUrl : undefined,
218
+ at: typeof entry.data.at === "string" ? entry.data.at : undefined
119
219
  };
120
220
  }
121
- case "diff": {
122
- const { value: task, rest: remaining } = takeOption(rest, "--task");
123
- requireNoExtraArgs(remaining, "bun run rig inspect diff [--task <beads-id>]");
124
- if (task) {
125
- const files = changedFilesForTask(context.projectRoot, task, false);
126
- for (const file of files) {
127
- console.log(file);
128
- }
129
- } else {
130
- await context.runCommand(["git", "diff", "--stat"]);
131
- }
132
- return { ok: true, group: "inspect", command, details: { task: task || null } };
221
+ if (!host?.joinLink)
222
+ continue;
223
+ const at = host.at ?? "";
224
+ const sessionId = host.roomId ?? sessionIdFromSessionFile(resolve(runtime.sessionDir, file)) ?? runtime.id;
225
+ return {
226
+ sessionId,
227
+ sessionPath: resolve(runtime.sessionDir, file),
228
+ cwd: runtime.workspaceDir,
229
+ joinLink: host.joinLink,
230
+ webLink: host.webLink ?? "",
231
+ relayUrl: host.relayUrl ?? "",
232
+ title: runtime.taskId ? `[${runtime.taskId}] Rig run ${sessionId}` : `Rig run ${sessionId}`,
233
+ startedAt: at,
234
+ updatedAt: at,
235
+ stale: false
236
+ };
237
+ }
238
+ return null;
239
+ }
240
+ async function listLocalRunCollabSessions(projectRoot) {
241
+ let runtimes;
242
+ try {
243
+ runtimes = await listAgentRuntimes(projectRoot);
244
+ } catch {
245
+ return [];
246
+ }
247
+ const out = [];
248
+ for (const runtime of runtimes) {
249
+ const collab = readLocalRunCollab(runtime);
250
+ if (collab)
251
+ out.push(collab);
252
+ }
253
+ return out;
254
+ }
255
+ async function listActiveRunCollab(filter) {
256
+ return defaultListActiveCollabSessions(filter);
257
+ }
258
+ async function defaultListActiveCollabSessions(filter) {
259
+ const projectRoot = process.cwd();
260
+ const local = await listLocalRunCollabSessions(projectRoot);
261
+ const namespaceKey = filter.namespaceKey ?? resolveOwnerNamespaceKey(projectRoot);
262
+ const secret = registrySecret();
263
+ const remote = namespaceKey && secret ? (await createRegistryClient({ baseUrl: registryBaseUrl(), namespaceKey, secret }).listRoomsByOwner(filter)).map(collabFromRegistryEntry) : await ompListActiveCollabSessions(filter);
264
+ const seen = new Set(local.map((c) => c.sessionId));
265
+ return [...local, ...remote.filter((c) => !seen.has(c.sessionId))];
266
+ }
267
+
268
+ // packages/cli/src/commands/_run-diagnostics.ts
269
+ function normalizeString(value) {
270
+ if (typeof value !== "string")
271
+ return null;
272
+ const normalized = value.replace(/\s+/g, " ").trim();
273
+ return normalized.length > 0 ? normalized : null;
274
+ }
275
+ function isGenericRunFailure(value) {
276
+ const text = normalizeString(value);
277
+ return Boolean(text && /^Task run failed \([^)]*\)$/i.test(text));
278
+ }
279
+ function appendCandidate(candidates, value) {
280
+ const text = normalizeString(value);
281
+ if (text && !candidates.includes(text))
282
+ candidates.push(text);
283
+ }
284
+ function categorizeUsefulRunError(lines) {
285
+ const taskSourceFailure = lines.find((line) => /failed to update task source/i.test(line));
286
+ if (taskSourceFailure)
287
+ return `Task source update failed: ${taskSourceFailure}`;
288
+ const moduleFailure = lines.find((line) => /cannot find module/i.test(line));
289
+ if (moduleFailure)
290
+ return `Runtime module resolution failed: ${moduleFailure}`;
291
+ const providerFailure = lines.find((line) => /no api key found|unauthorized|authentication failed|invalid api key/i.test(line));
292
+ if (providerFailure)
293
+ return `Provider authentication failed: ${providerFailure}`;
294
+ return null;
295
+ }
296
+ function summarizeUsefulRunError(projection) {
297
+ if (projection.status !== "failed")
298
+ return null;
299
+ const candidates = [];
300
+ for (const anomaly of projection.anomalies) {
301
+ appendCandidate(candidates, `Journal anomaly (${anomaly.kind}): ${anomaly.detail}`);
302
+ }
303
+ for (const phase of projection.closeoutPhases) {
304
+ if (phase.outcome === "failed")
305
+ appendCandidate(candidates, phase.detail);
306
+ }
307
+ for (const entry of projection.statusHistory) {
308
+ appendCandidate(candidates, entry.reason);
309
+ }
310
+ appendCandidate(candidates, projection.record.statusDetail);
311
+ appendCandidate(candidates, projection.record.errorText);
312
+ const nonGeneric = candidates.filter((candidate) => !isGenericRunFailure(candidate));
313
+ return categorizeUsefulRunError(nonGeneric) ?? nonGeneric.at(-1) ?? normalizeString(projection.record.errorText);
314
+ }
315
+
316
+ // packages/cli/src/commands/_run-projection.ts
317
+ var EMPTY_PROJECTION = foldRunSessionEntries([], "");
318
+ function stringOrNull(value) {
319
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
320
+ }
321
+ function newestSessionFile(sessionDir) {
322
+ if (!sessionDir || !existsSync2(sessionDir))
323
+ return null;
324
+ try {
325
+ const files = readdirSync2(sessionDir).filter((file) => file.endsWith(".jsonl")).sort().reverse();
326
+ return files[0] ? resolve2(sessionDir, files[0]) : null;
327
+ } catch {
328
+ return null;
329
+ }
330
+ }
331
+ function readSessionRunEntries(sessionPath) {
332
+ if (!sessionPath || !existsSync2(sessionPath))
333
+ return [];
334
+ let raw;
335
+ try {
336
+ raw = readFileSync2(sessionPath, "utf8");
337
+ } catch {
338
+ return [];
339
+ }
340
+ const entries = [];
341
+ for (const line of raw.split(`
342
+ `)) {
343
+ if (!line.trim())
344
+ continue;
345
+ let parsed;
346
+ try {
347
+ parsed = JSON.parse(line);
348
+ } catch {
349
+ continue;
133
350
  }
134
- case "failures": {
135
- requireNoExtraArgs(rest, "bun run rig inspect failures");
136
- const failed = resolveHarnessPaths(context.projectRoot).failedApproachesPath;
137
- if (!existsSync(failed)) {
138
- console.log("No failures recorded.");
139
- } else {
140
- process.stdout.write(readFileSync(failed, "utf-8"));
351
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
352
+ continue;
353
+ entries.push({
354
+ type: "type" in parsed && typeof parsed.type === "string" ? parsed.type : "",
355
+ ..."customType" in parsed && typeof parsed.customType === "string" ? { customType: parsed.customType } : {},
356
+ ..."data" in parsed ? { data: parsed.data } : {}
357
+ });
358
+ }
359
+ return entries;
360
+ }
361
+ function recordFromProjection(runId, projection, presence) {
362
+ const record = projection.record;
363
+ const status = projection.status ?? (presence.stale ? "stale" : presence.live ? "running" : "unknown");
364
+ const taskId = stringOrNull(record.taskId) ?? presence.fallbackTaskId ?? null;
365
+ const title = stringOrNull(record.title) ?? stringOrNull(presence.title) ?? (taskId ? `Run ${taskId}` : `Rig run ${runId}`);
366
+ return {
367
+ runId,
368
+ taskId,
369
+ title,
370
+ status,
371
+ source: presence.source,
372
+ live: presence.live,
373
+ stale: presence.stale,
374
+ startedAt: stringOrNull(record.startedAt) ?? presence.startedAt ?? null,
375
+ updatedAt: stringOrNull(record.updatedAt) ?? presence.updatedAt ?? projection.lastEventAt ?? null,
376
+ completedAt: stringOrNull(record.completedAt),
377
+ joinLink: presence.joinLink ?? null,
378
+ webLink: presence.webLink ?? null,
379
+ relayUrl: presence.relayUrl ?? null,
380
+ sessionPath: stringOrNull(record.sessionPath) ?? presence.sessionPath ?? null,
381
+ prUrl: stringOrNull(record.prUrl),
382
+ worktreePath: stringOrNull(record.worktreePath),
383
+ pendingApprovals: projection.pendingApprovals.length,
384
+ pendingInputs: projection.pendingUserInputs.length,
385
+ steeringCount: projection.steeringCount,
386
+ stallCount: projection.stallCount,
387
+ errorSummary: summarizeUsefulRunError(projection),
388
+ projection
389
+ };
390
+ }
391
+ function recordFromLiveCollab(collab) {
392
+ const runId = collab.sessionId;
393
+ const sessionPath = stringOrNull(collab.sessionPath);
394
+ const projection = sessionPath ? foldRunSessionEntries(readSessionRunEntries(sessionPath), runId) : EMPTY_PROJECTION;
395
+ return recordFromProjection(runId, projection, {
396
+ source: sessionPath ? "local" : "remote",
397
+ live: !collab.stale,
398
+ stale: Boolean(collab.stale),
399
+ title: collab.title,
400
+ joinLink: stringOrNull(collab.joinLink),
401
+ webLink: stringOrNull(collab.webLink),
402
+ relayUrl: stringOrNull(collab.relayUrl),
403
+ sessionPath,
404
+ startedAt: stringOrNull(collab.startedAt),
405
+ updatedAt: stringOrNull(collab.updatedAt)
406
+ });
407
+ }
408
+ function recordFromRuntime(runtime) {
409
+ const sessionPath = newestSessionFile(runtime.sessionDir ?? "");
410
+ if (!sessionPath)
411
+ return null;
412
+ const projection = foldRunSessionEntries(readSessionRunEntries(sessionPath), runtime.id);
413
+ if (projection.lastSeq === 0)
414
+ return null;
415
+ return recordFromProjection(sessionIdFromSessionFile2(sessionPath) ?? runtime.id, projection, {
416
+ source: "local",
417
+ live: false,
418
+ stale: false,
419
+ sessionPath,
420
+ fallbackTaskId: stringOrNull(runtime.taskId)
421
+ });
422
+ }
423
+ function sortByRecency(records) {
424
+ return [...records].sort((a, b) => {
425
+ const at = Date.parse(b.updatedAt ?? b.startedAt ?? "") || 0;
426
+ const bt = Date.parse(a.updatedAt ?? a.startedAt ?? "") || 0;
427
+ return at - bt;
428
+ });
429
+ }
430
+ async function listRunProjections(projectRoot, filter = {}) {
431
+ const byRunId = new Map;
432
+ let live = [];
433
+ try {
434
+ live = await listActiveRunCollab(filter);
435
+ } catch {
436
+ live = [];
437
+ }
438
+ for (const collab of live) {
439
+ const record = recordFromLiveCollab(collab);
440
+ byRunId.set(record.runId, record);
441
+ }
442
+ let runtimes = [];
443
+ try {
444
+ runtimes = await listAgentRuntimes2(projectRoot);
445
+ } catch {
446
+ runtimes = [];
447
+ }
448
+ for (const runtime of runtimes) {
449
+ const record = recordFromRuntime(runtime);
450
+ if (!record)
451
+ continue;
452
+ const sessionId = sessionIdFromSessionFile2(record.sessionPath);
453
+ const liveMatch = sessionId ? byRunId.get(sessionId) : undefined;
454
+ if (liveMatch) {
455
+ if (liveMatch.source === "remote" || !liveMatch.sessionPath) {
456
+ byRunId.set(liveMatch.runId, { ...liveMatch, sessionPath: record.sessionPath, source: "local" });
141
457
  }
142
- return { ok: true, group: "inspect", command };
458
+ continue;
143
459
  }
144
- case "graph":
145
- requireNoExtraArgs(rest, "bun run rig inspect graph");
146
- {
147
- const monorepoRoot = resolveMonorepoRoot(context.projectRoot);
148
- const result = runCapture(["br", "--no-db", "list", "--pretty"], monorepoRoot);
149
- if (result.exitCode !== 0) {
150
- throw new CliError2(result.stderr || result.stdout || "Failed to inspect graph");
151
- }
152
- process.stdout.write(result.stdout);
153
- }
154
- return { ok: true, group: "inspect", command };
155
- case "audit": {
156
- requireNoExtraArgs(rest, "bun run rig inspect audit");
157
- const auditPath = resolve(resolveHarnessPaths(context.projectRoot).logsDir, "audit.jsonl");
158
- if (!existsSync(auditPath)) {
159
- console.log("No audit log found.");
160
- } else {
161
- const lines = readFileSync(auditPath, "utf-8").split(/\r?\n/).filter(Boolean).slice(-20);
162
- for (const line of lines) {
163
- console.log(line);
164
- }
165
- }
166
- return { ok: true, group: "inspect", command };
460
+ if (byRunId.has(runtime.id))
461
+ continue;
462
+ byRunId.set(record.runId, record);
463
+ }
464
+ return sortByRecency([...byRunId.values()]);
465
+ }
466
+ async function getRunProjection(projectRoot, runId, filter = {}) {
467
+ const runs = await listRunProjections(projectRoot, filter);
468
+ return runs.find((run) => run.runId === runId) ?? runs.find((run) => run.runId.startsWith(runId)) ?? runs.find((run) => run.taskId === runId) ?? null;
469
+ }
470
+
471
+ // packages/cli/src/commands/inspect.ts
472
+ var INSPECT_USAGE = "rig inspect <logs|artifact|artifacts|run-logs|runs|failures|graph|audit|diff>";
473
+ function printInspectHelp() {
474
+ console.log([
475
+ `Usage: ${INSPECT_USAGE}`,
476
+ "",
477
+ "Commands:",
478
+ " logs --task <id> Print log lines from the latest projected run for a task.",
479
+ " artifact --task <id> --file <name>",
480
+ " Preview a single task artifact.",
481
+ " artifacts --task <id> List task artifacts.",
482
+ " run-logs --run <id> Print log lines from a run journal.",
483
+ " runs List all projected runs.",
484
+ " diff --task <id> List files changed by a task.",
485
+ " graph [--task <id>] Print the task dependency graph.",
486
+ " failures --task <id> Summarize failed runs, closeout failures, and journal anomalies.",
487
+ " audit Controlled-command audit is not readable yet in this CLI."
488
+ ].join(`
489
+ `));
490
+ }
491
+ function asRecord(value) {
492
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
493
+ }
494
+ function firstString2(record, keys) {
495
+ for (const key of keys) {
496
+ const value = record[key];
497
+ if (typeof value === "string" && value.trim().length > 0) {
498
+ return value;
499
+ }
500
+ }
501
+ return null;
502
+ }
503
+ function stringifyLogPayload(value) {
504
+ if (typeof value === "string")
505
+ return value;
506
+ if (typeof value === "number" || typeof value === "boolean")
507
+ return String(value);
508
+ const record = asRecord(value);
509
+ if (!record)
510
+ return null;
511
+ const direct = firstString2(record, ["line", "message", "text", "content", "output", "summary", "detail"]);
512
+ if (direct)
513
+ return direct;
514
+ try {
515
+ return JSON.stringify(record);
516
+ } catch {
517
+ return String(record);
518
+ }
519
+ }
520
+ function logLineFromValue(value) {
521
+ const record = asRecord(value);
522
+ if (!record)
523
+ return stringifyLogPayload(value);
524
+ const direct = firstString2(record, ["line", "message", "text", "content", "output", "summary", "detail"]);
525
+ if (direct)
526
+ return direct;
527
+ if ("payload" in record)
528
+ return stringifyLogPayload(record.payload);
529
+ if ("data" in record)
530
+ return stringifyLogPayload(record.data);
531
+ return stringifyLogPayload(record);
532
+ }
533
+ function logLineFromSessionEntry(entry) {
534
+ if (entry.type !== "custom" || entry.customType !== RIG_RUN_LOG_ENTRY)
535
+ return null;
536
+ return logLineFromValue(entry.data);
537
+ }
538
+ function logLinesFromProjection(projection) {
539
+ const projected = projection;
540
+ const lines = [];
541
+ for (const key of ["logs", "logEntries", "journalLogs", "runLogs"]) {
542
+ const entries = projected[key];
543
+ if (!Array.isArray(entries))
544
+ continue;
545
+ for (const entry of entries) {
546
+ const line = logLineFromValue(entry);
547
+ if (line !== null)
548
+ lines.push(line);
549
+ }
550
+ }
551
+ return lines;
552
+ }
553
+ function toRunLike(run) {
554
+ return {
555
+ runId: run.runId,
556
+ taskId: run.taskId,
557
+ title: run.title,
558
+ status: run.status,
559
+ source: run.source,
560
+ live: run.live,
561
+ stale: run.stale,
562
+ startedAt: run.startedAt,
563
+ updatedAt: run.updatedAt,
564
+ completedAt: run.completedAt,
565
+ joinLink: run.joinLink,
566
+ prUrl: run.prUrl,
567
+ pendingApprovals: run.pendingApprovals,
568
+ pendingInputs: run.pendingInputs,
569
+ steeringCount: run.steeringCount,
570
+ stallCount: run.stallCount
571
+ };
572
+ }
573
+ function requireRunId(value, usage) {
574
+ if (!value || !value.trim()) {
575
+ throw new CliError(`${usage} requires a run id.`, 2, { hint: "Run `rig inspect runs` to find run ids." });
576
+ }
577
+ return value.trim();
578
+ }
579
+ async function executeLogs(context, args, deps) {
580
+ const taskResult = takeOption(args, "--task");
581
+ requireNoExtraArgs(taskResult.rest, "rig inspect logs --task <id>");
582
+ const taskId = requireTask(taskResult.value, "rig inspect logs --task <id>");
583
+ const projection = await (deps.getRunProjection ?? getRunProjection)(context.projectRoot, taskId);
584
+ if (!projection) {
585
+ throw new CliError(`No projected runs found for task ${taskId}.`, 1, {
586
+ hint: "Run `rig run list` to confirm the run journal is discoverable."
587
+ });
588
+ }
589
+ const projectedLines = logLinesFromProjection(projection.projection);
590
+ const sessionLines = projectedLines.length > 0 ? [] : (deps.readSessionRunEntries ?? readSessionRunEntries)(projection.sessionPath).map(logLineFromSessionEntry).filter((line) => line !== null);
591
+ const lines = projectedLines.length > 0 ? projectedLines : sessionLines;
592
+ if (context.outputMode === "json") {
593
+ console.log(JSON.stringify({ taskId, runId: projection.runId, lines }, null, 2));
594
+ } else if (lines.length === 0) {
595
+ console.log(`No log entries found for task ${taskId}.`);
596
+ } else {
597
+ for (const line of lines)
598
+ console.log(line);
599
+ }
600
+ return { ok: true, group: "inspect", command: "logs", details: { taskId, runId: projection.runId, count: lines.length } };
601
+ }
602
+ async function executeArtifact(context, args, deps) {
603
+ const taskResult = takeOption(args, "--task");
604
+ const fileResult = takeOption(taskResult.rest, "--file");
605
+ requireNoExtraArgs(fileResult.rest, "rig inspect artifact --task <id> --file <name>");
606
+ const taskId = requireTask(taskResult.value, "rig inspect artifact --task <id> --file <name>");
607
+ const filename = fileResult.value?.trim();
608
+ if (!filename) {
609
+ throw new CliError("rig inspect artifact --task <id> --file <name> requires an artifact file name.", 2);
610
+ }
611
+ const preview = await (deps.taskArtifactRead ?? taskArtifactRead)(context.projectRoot, filename, {
612
+ taskId,
613
+ maxBytes: 64 * 1024
614
+ });
615
+ if (context.outputMode === "json") {
616
+ console.log(JSON.stringify({ taskId, file: filename, ...preview }, null, 2));
617
+ } else {
618
+ console.log(preview.contents);
619
+ if (preview.truncated) {
620
+ console.log(`
621
+ [truncated at ${preview.maxBytes} bytes; artifact is ${preview.sizeBytes} bytes]`);
167
622
  }
623
+ }
624
+ return {
625
+ ok: true,
626
+ group: "inspect",
627
+ command: "artifact",
628
+ details: { taskId, file: filename, ...preview }
629
+ };
630
+ }
631
+ async function executeRunLogs(context, args, deps) {
632
+ const runResult = takeOption(args, "--run");
633
+ requireNoExtraArgs(runResult.rest, "rig inspect run-logs --run <id>");
634
+ const runId = requireRunId(runResult.value, "rig inspect run-logs --run <id>");
635
+ const projection = await (deps.getRunProjection ?? getRunProjection)(context.projectRoot, runId);
636
+ if (!projection) {
637
+ throw new CliError(`Run not found: ${runId}`, 2, { hint: "Run `rig inspect runs` to see runs." });
638
+ }
639
+ const sessionLines = (deps.readSessionRunEntries ?? readSessionRunEntries)(projection.sessionPath).map(logLineFromSessionEntry).filter((line) => line !== null);
640
+ const lines = sessionLines.length > 0 ? sessionLines : logLinesFromProjection(projection.projection);
641
+ if (context.outputMode === "json") {
642
+ console.log(JSON.stringify({ runId: projection.runId, taskId: projection.taskId, lines }, null, 2));
643
+ } else if (lines.length === 0) {
644
+ console.log(`No log entries found for run ${projection.runId}.`);
645
+ } else {
646
+ for (const line of lines)
647
+ console.log(line);
648
+ }
649
+ return { ok: true, group: "inspect", command: "run-logs", details: { runId: projection.runId, taskId: projection.taskId, count: lines.length } };
650
+ }
651
+ async function executeRuns(context, args, deps) {
652
+ requireNoExtraArgs(args, "rig inspect runs");
653
+ const runs = await (deps.listRunProjections ?? listRunProjections)(context.projectRoot);
654
+ const formatted = runs.map(toRunLike);
655
+ if (context.outputMode === "text") {
656
+ printFormattedOutput(formatRunList(formatted));
657
+ }
658
+ return { ok: true, group: "inspect", command: "runs", details: { runs: formatted } };
659
+ }
660
+ async function executeArtifacts(context, args, deps) {
661
+ const taskResult = takeOption(args, "--task");
662
+ requireNoExtraArgs(taskResult.rest, "rig inspect artifacts --task <id>");
663
+ const taskId = requireTask(taskResult.value, "rig inspect artifacts --task <id>");
664
+ await (deps.taskArtifacts ?? taskArtifacts)(context.projectRoot, taskId);
665
+ return { ok: true, group: "inspect", command: "artifacts", details: { taskId } };
666
+ }
667
+ async function executeDiff(context, args, deps) {
668
+ const taskResult = takeOption(args, "--task");
669
+ requireNoExtraArgs(taskResult.rest, "rig inspect diff --task <id>");
670
+ const taskId = requireTask(taskResult.value, "rig inspect diff --task <id>");
671
+ const files = (deps.changedFilesForTask ?? changedFilesForTask)(context.projectRoot, taskId, true);
672
+ if (context.outputMode === "json") {
673
+ console.log(JSON.stringify({ taskId, files }, null, 2));
674
+ } else {
675
+ for (const file of files)
676
+ console.log(file);
677
+ }
678
+ return { ok: true, group: "inspect", command: "diff", details: { taskId, files } };
679
+ }
680
+ async function executeGraph(context, args, deps) {
681
+ const taskResult = takeOption(args, "--task");
682
+ requireNoExtraArgs(taskResult.rest, "rig inspect graph [--task <id>]");
683
+ await (deps.taskDeps ?? taskDeps)(context.projectRoot, taskResult.value);
684
+ return { ok: true, group: "inspect", command: "graph", details: { taskId: taskResult.value ?? null } };
685
+ }
686
+ function summarizeProjectionFailures(run) {
687
+ const failures = [];
688
+ const projection = run.projection;
689
+ if (run.status === "failed" || projection.status === "failed") {
690
+ failures.push(`${run.runId}: run status failed`);
691
+ }
692
+ for (const phase of projection.closeoutPhases) {
693
+ if (phase.outcome === "failed") {
694
+ failures.push(`${run.runId}: closeout ${phase.phase} failed${phase.detail ? ` \u2014 ${phase.detail}` : ""}`);
695
+ }
696
+ }
697
+ for (const anomaly of projection.anomalies) {
698
+ failures.push(`${run.runId}: anomaly ${anomaly.kind}${anomaly.detail ? ` \u2014 ${anomaly.detail}` : ""}`);
699
+ }
700
+ return failures;
701
+ }
702
+ async function runsForTask(context, taskId, deps) {
703
+ const listRuns = deps.listRunProjections ?? listRunProjections;
704
+ try {
705
+ const runs = await listRuns(context.projectRoot);
706
+ const filtered = runs.filter((run2) => run2.taskId === taskId || run2.runId === taskId);
707
+ if (filtered.length > 0)
708
+ return filtered;
709
+ } catch {}
710
+ const run = await (deps.getRunProjection ?? getRunProjection)(context.projectRoot, taskId);
711
+ return run ? [run] : [];
712
+ }
713
+ async function executeFailures(context, args, deps) {
714
+ const taskResult = takeOption(args, "--task");
715
+ requireNoExtraArgs(taskResult.rest, "rig inspect failures --task <id>");
716
+ const taskId = requireTask(taskResult.value, "rig inspect failures --task <id>");
717
+ const runs = await runsForTask(context, taskId, deps);
718
+ const failures = runs.flatMap(summarizeProjectionFailures);
719
+ if (context.outputMode === "json") {
720
+ console.log(JSON.stringify({ taskId, failures }, null, 2));
721
+ } else if (failures.length === 0) {
722
+ console.log(`No failures recorded for task ${taskId}.`);
723
+ } else {
724
+ for (const failure of failures)
725
+ console.log(failure);
726
+ }
727
+ return { ok: true, group: "inspect", command: "failures", details: { taskId, count: failures.length } };
728
+ }
729
+ function executeAudit(args) {
730
+ requireNoExtraArgs(args, "rig inspect audit");
731
+ throw new CliError("rig inspect audit cannot read the controlled-command audit trail yet: current code only writes audit JSONL and exposes no supported reader API.", 2, { hint: "Use the OMP session history for operator audit context until a controlled-bash audit reader is added." });
732
+ }
733
+ async function executeInspect(context, args, deps = {}) {
734
+ const [command = "failures", ...rest] = args;
735
+ if (command === "--help" || command === "-h" || command === "help") {
736
+ printInspectHelp();
737
+ return { ok: true, group: "inspect", command: "help" };
738
+ }
739
+ switch (command) {
740
+ case "logs":
741
+ return executeLogs(context, rest, deps);
742
+ case "artifact":
743
+ return executeArtifact(context, rest, deps);
744
+ case "artifacts":
745
+ return executeArtifacts(context, rest, deps);
746
+ case "run-logs":
747
+ return executeRunLogs(context, rest, deps);
748
+ case "runs":
749
+ return executeRuns(context, rest, deps);
750
+ case "diff":
751
+ return executeDiff(context, rest, deps);
752
+ case "graph":
753
+ return executeGraph(context, rest, deps);
754
+ case "failures":
755
+ return executeFailures(context, rest, deps);
756
+ case "audit":
757
+ return executeAudit(rest);
168
758
  default:
169
- throw new CliError2(`Unknown inspect command: ${command}`);
759
+ throw new CliError(`Unknown inspect command: ${command}`, 1, { hint: "Run `rig inspect --help` to list inspect commands." });
170
760
  }
171
761
  }
172
762
  export {