@h-rig/cli 0.0.6-alpha.90 → 0.0.6-alpha.92
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.
- package/README.md +18 -19
- package/dist/bin/build-rig-binaries.js +22 -10
- package/dist/bin/rig.d.ts +71 -1
- package/dist/bin/rig.js +15078 -11169
- package/dist/config/rig-default-config.yml +5 -0
- package/dist/src/app/drone-ui.d.ts +11 -14
- package/dist/src/app/drone-ui.js +70 -86
- package/dist/src/commands/_async-ui.d.ts +1 -4
- package/dist/src/commands/_async-ui.js +9 -111
- package/dist/src/commands/_cli-format.d.ts +16 -9
- package/dist/src/commands/_cli-format.js +167 -295
- package/dist/src/commands/_connection-state.d.ts +11 -1
- package/dist/src/commands/_connection-state.js +50 -5
- package/dist/src/commands/_doctor-checks.d.ts +0 -6
- package/dist/src/commands/_doctor-checks.js +79 -382
- package/dist/src/commands/_help-catalog.d.ts +1 -1
- package/dist/src/commands/_help-catalog.js +217 -157
- package/dist/src/commands/_inprocess-services.d.ts +33 -0
- package/dist/src/commands/_inprocess-services.js +102 -0
- package/dist/src/commands/_json-output.js +4 -0
- package/dist/src/commands/_lazy-reconcile.d.ts +34 -0
- package/dist/src/commands/_lazy-reconcile.js +102 -0
- package/dist/src/commands/_paths.js +1 -1
- package/dist/src/commands/_pi-frontend.d.ts +18 -10
- package/dist/src/commands/_pi-frontend.js +37 -715
- package/dist/src/commands/_pi-install.js +18 -36
- package/dist/src/commands/_policy.d.ts +1 -1
- package/dist/src/commands/_policy.js +56 -15
- package/dist/src/commands/_run-bridge.d.ts +114 -0
- package/dist/src/commands/_run-bridge.js +387 -0
- package/dist/src/commands/_run-diagnostics.d.ts +9 -0
- package/dist/src/commands/_run-diagnostics.js +51 -0
- package/dist/src/commands/_run-driver-helpers.d.ts +8 -81
- package/dist/src/commands/_run-driver-helpers.js +79 -283
- package/dist/src/commands/_run-projection.d.ts +50 -0
- package/dist/src/commands/_run-projection.js +349 -0
- package/dist/src/commands/_run-subcommands.d.ts +3 -0
- package/dist/src/commands/_run-subcommands.js +31 -0
- package/dist/src/commands/_spinner.js +1 -1
- package/dist/src/commands/agent.d.ts +1 -1
- package/dist/src/commands/agent.js +8559 -239
- package/dist/src/commands/dist.d.ts +1 -1
- package/dist/src/commands/dist.js +27 -19
- package/dist/src/commands/doctor.d.ts +1 -1
- package/dist/src/commands/doctor.js +93 -475
- package/dist/src/commands/github.d.ts +1 -1
- package/dist/src/commands/github.js +113 -387
- package/dist/src/commands/inbox.d.ts +22 -24
- package/dist/src/commands/inbox.js +420 -691
- package/dist/src/commands/init.d.ts +6 -16
- package/dist/src/commands/init.js +334 -971
- package/dist/src/commands/inspect.d.ts +19 -2
- package/dist/src/commands/inspect.js +644 -610
- package/dist/src/commands/pi.d.ts +1 -1
- package/dist/src/commands/plugin.d.ts +1 -1
- package/dist/src/commands/plugin.js +486 -7
- package/dist/src/commands/profile-and-review.d.ts +1 -1
- package/dist/src/commands/profile-and-review.js +94 -56
- package/dist/src/commands/queue.js +1 -21
- package/dist/src/commands/remote.d.ts +1 -1
- package/dist/src/commands/remote.js +837 -14
- package/dist/src/commands/repo-git-harness.d.ts +1 -1
- package/dist/src/commands/repo-git-harness.js +57 -14
- package/dist/src/commands/run.d.ts +20 -2
- package/dist/src/commands/run.js +17579 -1759
- package/dist/src/commands/server.d.ts +2 -6
- package/dist/src/commands/server.js +141 -723
- package/dist/src/commands/setup.d.ts +1 -1
- package/dist/src/commands/setup.js +102 -484
- package/dist/src/commands/stats.d.ts +13 -10
- package/dist/src/commands/stats.js +689 -761
- package/dist/src/commands/task-run-driver.d.ts +50 -88
- package/dist/src/commands/task-run-driver.js +116 -2717
- package/dist/src/commands/task.d.ts +34 -13
- package/dist/src/commands/task.js +668 -2523
- package/dist/src/commands/test.d.ts +1 -1
- package/dist/src/commands/triage.d.ts +11 -0
- package/dist/src/commands/triage.js +227 -0
- package/dist/src/commands/workspace.d.ts +1 -1
- package/dist/src/commands.d.ts +0 -16
- package/dist/src/commands.js +16657 -12250
- package/dist/src/index.js +16528 -12497
- package/dist/src/launcher.js +4 -0
- package/dist/src/operator-cli.d.ts +2 -0
- package/dist/src/operator-cli.js +17837 -0
- package/dist/src/operator-entry.d.ts +1 -0
- package/dist/src/operator-entry.js +3 -0
- package/package.json +18 -12
- package/dist/src/app/board.d.ts +0 -23
- package/dist/src/app/board.js +0 -1786
- package/dist/src/app/theme.d.ts +0 -47
- package/dist/src/app/theme.js +0 -150
- package/dist/src/commands/_authority-runs.d.ts +0 -22
- package/dist/src/commands/_authority-runs.js +0 -110
- package/dist/src/commands/_operator-surface.d.ts +0 -34
- package/dist/src/commands/_operator-surface.js +0 -220
- package/dist/src/commands/_operator-view.d.ts +0 -30
- package/dist/src/commands/_operator-view.js +0 -1070
- package/dist/src/commands/_preflight.d.ts +0 -22
- package/dist/src/commands/_preflight.js +0 -540
- package/dist/src/commands/_run-replay.d.ts +0 -24
- package/dist/src/commands/_run-replay.js +0 -142
- package/dist/src/commands/_server-client.d.ts +0 -186
- package/dist/src/commands/_server-client.js +0 -681
- package/dist/src/commands/_snapshot-upload.d.ts +0 -39
- package/dist/src/commands/_snapshot-upload.js +0 -455
- package/dist/src/commands/_task-picker.d.ts +0 -9
- package/dist/src/commands/_task-picker.js +0 -201
- package/dist/src/commands/browser.d.ts +0 -65
- package/dist/src/commands/browser.js +0 -1173
- package/dist/src/commands/connect.d.ts +0 -7
- package/dist/src/commands/connect.js +0 -419
- package/dist/src/commands/inspector.d.ts +0 -3
- package/dist/src/commands/inspector.js +0 -263
- package/dist/src/commands/task-report-bug.d.ts +0 -19
- package/dist/src/commands/task-report-bug.js +0 -1281
- package/dist/src/report-bug.d.ts +0 -44
- package/dist/src/report-bug.js +0 -260
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/cli/src/commands/inspect.ts
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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";
|
|
@@ -52,675 +57,704 @@ Usage: ${usage}`);
|
|
|
52
57
|
return taskId;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
// packages/cli/src/commands/
|
|
56
|
-
import
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
function resolveRepoConnectionPath(projectRoot) {
|
|
85
|
-
return resolve(projectRoot, ".rig", "state", "connection.json");
|
|
86
|
-
}
|
|
87
|
-
function readJsonFile(path) {
|
|
88
|
-
if (!existsSync(path))
|
|
89
|
-
return null;
|
|
90
|
-
try {
|
|
91
|
-
return JSON.parse(readFileSync(path, "utf8"));
|
|
92
|
-
} catch (error) {
|
|
93
|
-
throw new CliError(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1, { hint: "Fix or delete that file, then re-select a server with `rig server use <alias|local>`." });
|
|
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;
|
|
94
88
|
}
|
|
89
|
+
return fallback;
|
|
95
90
|
}
|
|
96
|
-
function
|
|
97
|
-
|
|
98
|
-
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
99
|
-
`, "utf8");
|
|
91
|
+
function runIdOf(run) {
|
|
92
|
+
return firstString(run, ["runId", "id"], "(unknown-run)");
|
|
100
93
|
}
|
|
101
|
-
function
|
|
102
|
-
|
|
103
|
-
return null;
|
|
104
|
-
const record = value;
|
|
105
|
-
if (record.kind === "local")
|
|
106
|
-
return { kind: "local", mode: "auto" };
|
|
107
|
-
if (record.kind === "remote" && typeof record.baseUrl === "string" && record.baseUrl.trim()) {
|
|
108
|
-
const baseUrl = record.baseUrl.trim().replace(/\/+$/, "");
|
|
109
|
-
return { kind: "remote", baseUrl };
|
|
110
|
-
}
|
|
111
|
-
return null;
|
|
94
|
+
function taskIdOf(run) {
|
|
95
|
+
return firstString(run, ["taskId", "task", "task_id"]);
|
|
112
96
|
}
|
|
113
|
-
function
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
+
`);
|
|
127
118
|
}
|
|
128
|
-
|
|
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
|
+
`);
|
|
129
132
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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";
|
|
137
|
+
import {
|
|
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) {
|
|
138
162
|
return {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
|
143
176
|
};
|
|
144
177
|
}
|
|
145
|
-
function
|
|
146
|
-
|
|
178
|
+
function isRecord(value) {
|
|
179
|
+
return typeof value === "object" && value !== null;
|
|
147
180
|
}
|
|
148
|
-
function
|
|
149
|
-
|
|
150
|
-
|
|
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 {
|
|
151
188
|
return null;
|
|
152
|
-
if (repo.selected === "local")
|
|
153
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
|
|
154
|
-
const global = readGlobalConnections(options);
|
|
155
|
-
const connection = global.connections[repo.selected];
|
|
156
|
-
if (!connection) {
|
|
157
|
-
throw new CliError(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
158
189
|
}
|
|
159
|
-
|
|
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;
|
|
197
|
+
}
|
|
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;
|
|
207
|
+
}
|
|
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
|
|
219
|
+
};
|
|
220
|
+
}
|
|
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);
|
|
160
257
|
}
|
|
161
|
-
function
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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))];
|
|
166
266
|
}
|
|
167
267
|
|
|
168
|
-
// packages/cli/src/commands/
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
function setServerPhaseListener(listener) {
|
|
172
|
-
const previous = serverPhaseListener;
|
|
173
|
-
serverPhaseListener = listener;
|
|
174
|
-
return previous;
|
|
175
|
-
}
|
|
176
|
-
function reportServerPhase(label) {
|
|
177
|
-
serverPhaseListener?.(label);
|
|
178
|
-
}
|
|
179
|
-
function cleanToken(value) {
|
|
180
|
-
const trimmed = value?.trim();
|
|
181
|
-
return trimmed ? trimmed : null;
|
|
182
|
-
}
|
|
183
|
-
function readPrivateRemoteSessionToken(projectRoot) {
|
|
184
|
-
const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
|
|
185
|
-
if (!existsSync2(path))
|
|
268
|
+
// packages/cli/src/commands/_run-diagnostics.ts
|
|
269
|
+
function normalizeString(value) {
|
|
270
|
+
if (typeof value !== "string")
|
|
186
271
|
return null;
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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")
|
|
191
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);
|
|
192
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);
|
|
193
314
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (privateSession)
|
|
200
|
-
return privateSession;
|
|
201
|
-
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
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;
|
|
202
320
|
}
|
|
203
|
-
function
|
|
204
|
-
|
|
205
|
-
if (!existsSync2(path))
|
|
321
|
+
function newestSessionFile(sessionDir) {
|
|
322
|
+
if (!sessionDir || !existsSync2(sessionDir))
|
|
206
323
|
return null;
|
|
207
324
|
try {
|
|
208
|
-
const
|
|
209
|
-
return
|
|
325
|
+
const files = readdirSync2(sessionDir).filter((file) => file.endsWith(".jsonl")).sort().reverse();
|
|
326
|
+
return files[0] ? resolve2(sessionDir, files[0]) : null;
|
|
210
327
|
} catch {
|
|
211
328
|
return null;
|
|
212
329
|
}
|
|
213
330
|
}
|
|
214
|
-
function
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
331
|
+
function readSessionRunEntries(sessionPath) {
|
|
332
|
+
if (!sessionPath || !existsSync2(sessionPath))
|
|
333
|
+
return [];
|
|
334
|
+
let raw;
|
|
218
335
|
try {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
return {
|
|
234
|
-
baseUrl: connection.baseUrl,
|
|
235
|
-
authToken: connection.authToken ?? readLocalConnectionFallbackToken(projectRoot),
|
|
236
|
-
connectionKind: "local",
|
|
237
|
-
serverProjectRoot: resolve2(projectRoot)
|
|
238
|
-
};
|
|
239
|
-
} catch (error) {
|
|
240
|
-
if (error instanceof Error) {
|
|
241
|
-
throw new CliError(error.message, 1);
|
|
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;
|
|
242
350
|
}
|
|
243
|
-
|
|
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
|
+
});
|
|
244
358
|
}
|
|
359
|
+
return entries;
|
|
245
360
|
}
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
const
|
|
249
|
-
|
|
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)
|
|
250
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 = [];
|
|
251
433
|
try {
|
|
252
|
-
|
|
253
|
-
headers: mergeHeaders(undefined, authToken)
|
|
254
|
-
});
|
|
255
|
-
if (!response.ok)
|
|
256
|
-
return null;
|
|
257
|
-
const payload = await response.json();
|
|
258
|
-
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
259
|
-
const checkouts = Array.isArray(project?.checkouts) ? project.checkouts : [];
|
|
260
|
-
const latestCheckout = [...checkouts].reverse().find((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.path === "string"));
|
|
261
|
-
const path = typeof latestCheckout?.path === "string" && latestCheckout.path.trim() ? latestCheckout.path.trim() : null;
|
|
262
|
-
if (path)
|
|
263
|
-
writeRepoServerProjectRoot(projectRoot, path);
|
|
264
|
-
return path;
|
|
434
|
+
live = await listActiveRunCollab(filter);
|
|
265
435
|
} catch {
|
|
266
|
-
|
|
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 = [];
|
|
267
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" });
|
|
457
|
+
}
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
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;
|
|
268
469
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
+
}
|
|
273
500
|
}
|
|
274
|
-
return
|
|
501
|
+
return null;
|
|
275
502
|
}
|
|
276
|
-
function
|
|
277
|
-
if (
|
|
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)
|
|
278
510
|
return null;
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
283
|
-
return [];
|
|
284
|
-
const diagnostic = entry;
|
|
285
|
-
const kind = typeof diagnostic.kind === "string" ? diagnostic.kind : "task-source";
|
|
286
|
-
const message = typeof diagnostic.message === "string" ? diagnostic.message : null;
|
|
287
|
-
return message ? [`${kind}: ${message}`] : [];
|
|
288
|
-
});
|
|
289
|
-
return messages.length > 0 ? messages.join("; ") : null;
|
|
290
|
-
}
|
|
291
|
-
var serverReachabilityCache = new Map;
|
|
292
|
-
async function probeServerReachability(baseUrl, authToken) {
|
|
511
|
+
const direct = firstString2(record, ["line", "message", "text", "content", "output", "summary", "detail"]);
|
|
512
|
+
if (direct)
|
|
513
|
+
return direct;
|
|
293
514
|
try {
|
|
294
|
-
|
|
295
|
-
headers: mergeHeaders(undefined, authToken),
|
|
296
|
-
signal: AbortSignal.timeout(1500)
|
|
297
|
-
});
|
|
298
|
-
return response.ok;
|
|
515
|
+
return JSON.stringify(record);
|
|
299
516
|
} catch {
|
|
300
|
-
return
|
|
517
|
+
return String(record);
|
|
301
518
|
}
|
|
302
519
|
}
|
|
303
|
-
function
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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);
|
|
320
549
|
}
|
|
321
|
-
}
|
|
322
|
-
return
|
|
550
|
+
}
|
|
551
|
+
return lines;
|
|
323
552
|
}
|
|
324
|
-
|
|
325
|
-
const { alias, target } = describeSelectedServer(projectRoot, server);
|
|
326
|
-
const reachable = await cachedServerReachability(projectRoot, server.baseUrl, server.authToken);
|
|
327
|
-
const reachability = reachable ? "server is reachable" : "server is unreachable";
|
|
553
|
+
function toRunLike(run) {
|
|
328
554
|
return {
|
|
329
|
-
|
|
330
|
-
|
|
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
|
|
331
571
|
};
|
|
332
572
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
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."
|
|
344
587
|
});
|
|
345
|
-
} catch (error) {
|
|
346
|
-
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
347
|
-
throw new CliError(`Rig server request failed: ${error instanceof Error ? error.message : String(error)}
|
|
348
|
-
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
349
588
|
}
|
|
350
|
-
const
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
|
|
384
|
-
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { entries: [] };
|
|
385
|
-
}
|
|
386
|
-
var RESUMABLE_RUN_STATUSES = new Set([
|
|
387
|
-
"created",
|
|
388
|
-
"preparing",
|
|
389
|
-
"running",
|
|
390
|
-
"validating",
|
|
391
|
-
"reviewing",
|
|
392
|
-
"stopped",
|
|
393
|
-
"failed",
|
|
394
|
-
"needs-attention",
|
|
395
|
-
"needs_attention"
|
|
396
|
-
]);
|
|
397
|
-
|
|
398
|
-
// packages/cli/src/commands/_async-ui.ts
|
|
399
|
-
import pc from "picocolors";
|
|
400
|
-
|
|
401
|
-
// packages/cli/src/commands/_spinner.ts
|
|
402
|
-
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
403
|
-
function createTtySpinner(input) {
|
|
404
|
-
const output = input.output ?? process.stdout;
|
|
405
|
-
const isTty = output.isTTY === true;
|
|
406
|
-
const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
|
|
407
|
-
let label = input.label;
|
|
408
|
-
let frame = 0;
|
|
409
|
-
let paused = false;
|
|
410
|
-
let stopped = false;
|
|
411
|
-
let lastPrintedLabel = "";
|
|
412
|
-
const render = () => {
|
|
413
|
-
if (stopped || paused)
|
|
414
|
-
return;
|
|
415
|
-
if (!isTty) {
|
|
416
|
-
if (label !== lastPrintedLabel) {
|
|
417
|
-
output.write(`${label}
|
|
418
|
-
`);
|
|
419
|
-
lastPrintedLabel = label;
|
|
420
|
-
}
|
|
421
|
-
return;
|
|
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]`);
|
|
422
622
|
}
|
|
423
|
-
|
|
424
|
-
const glyph = frames[frame] ?? frames[0] ?? "";
|
|
425
|
-
output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
|
|
426
|
-
};
|
|
427
|
-
const clearLine = () => {
|
|
428
|
-
if (isTty)
|
|
429
|
-
output.write("\r\x1B[2K");
|
|
430
|
-
};
|
|
431
|
-
render();
|
|
432
|
-
const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
|
|
623
|
+
}
|
|
433
624
|
return {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
}
|
|
438
|
-
pause() {
|
|
439
|
-
paused = true;
|
|
440
|
-
clearLine();
|
|
441
|
-
},
|
|
442
|
-
resume() {
|
|
443
|
-
if (stopped)
|
|
444
|
-
return;
|
|
445
|
-
paused = false;
|
|
446
|
-
render();
|
|
447
|
-
},
|
|
448
|
-
stop(finalLine) {
|
|
449
|
-
if (stopped)
|
|
450
|
-
return;
|
|
451
|
-
stopped = true;
|
|
452
|
-
if (timer)
|
|
453
|
-
clearInterval(timer);
|
|
454
|
-
clearLine();
|
|
455
|
-
if (finalLine)
|
|
456
|
-
output.write(`${finalLine}
|
|
457
|
-
`);
|
|
458
|
-
}
|
|
625
|
+
ok: true,
|
|
626
|
+
group: "inspect",
|
|
627
|
+
command: "artifact",
|
|
628
|
+
details: { taskId, file: filename, ...preview }
|
|
459
629
|
};
|
|
460
630
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
const
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
"
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
"
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
"
|
|
512
|
-
"
|
|
513
|
-
|
|
514
|
-
"
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
];
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
return `(${blade})${eye}(${blade})`;
|
|
526
|
-
}
|
|
527
|
-
var MICRO_DRONE_FRAMES = Array.from({ length: 12 }, (_, index) => microDroneFrame(index));
|
|
528
|
-
function renderMicroDroneFrame(tick) {
|
|
529
|
-
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
530
|
-
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
531
|
-
return `${ink4("(")}${cyan(blade)}${ink4(")")}${bold(accent(eye))}${ink4("(")}${cyan(blade)}${ink4(")")}`;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
// packages/cli/src/commands/_async-ui.ts
|
|
535
|
-
var DONE_SYMBOL = pc.green("\u25C7");
|
|
536
|
-
var FAIL_SYMBOL = pc.red("\u25A0");
|
|
537
|
-
var activeUpdate = null;
|
|
538
|
-
async function withSpinner(label, work, options = {}) {
|
|
539
|
-
if (options.outputMode === "json") {
|
|
540
|
-
return work(() => {});
|
|
541
|
-
}
|
|
542
|
-
if (activeUpdate) {
|
|
543
|
-
const outer = activeUpdate;
|
|
544
|
-
outer(label);
|
|
545
|
-
return work(outer);
|
|
546
|
-
}
|
|
547
|
-
const output = options.output ?? process.stderr;
|
|
548
|
-
const isTty = output.isTTY === true;
|
|
549
|
-
let lastLabel = label;
|
|
550
|
-
if (!isTty) {
|
|
551
|
-
output.write(`${label}
|
|
552
|
-
`);
|
|
553
|
-
const update2 = (next) => {
|
|
554
|
-
lastLabel = next;
|
|
555
|
-
};
|
|
556
|
-
activeUpdate = update2;
|
|
557
|
-
const previousListener2 = setServerPhaseListener(update2);
|
|
558
|
-
try {
|
|
559
|
-
return await work(update2);
|
|
560
|
-
} finally {
|
|
561
|
-
activeUpdate = null;
|
|
562
|
-
setServerPhaseListener(previousListener2);
|
|
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}` : ""}`);
|
|
563
695
|
}
|
|
564
696
|
}
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
const
|
|
572
|
-
lastLabel = next;
|
|
573
|
-
spinner.setLabel(next);
|
|
574
|
-
};
|
|
575
|
-
activeUpdate = update;
|
|
576
|
-
const previousListener = setServerPhaseListener(update);
|
|
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;
|
|
577
704
|
try {
|
|
578
|
-
const
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
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);
|
|
587
726
|
}
|
|
727
|
+
return { ok: true, group: "inspect", command: "failures", details: { taskId, count: failures.length } };
|
|
588
728
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
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 = {}) {
|
|
592
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
|
+
}
|
|
593
739
|
switch (command) {
|
|
594
|
-
case "logs":
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
const page = await getRunLogsViaServer(context, serverRun.runId, { limit: 500 });
|
|
607
|
-
return { runId: serverRun.runId, page };
|
|
608
|
-
}, { outputMode: context.outputMode });
|
|
609
|
-
if (!fallback) {
|
|
610
|
-
throw new CliError(`No runs found for ${requiredTask} (local or on the selected server).`, 1, { hint: "Start one with `rig task run --task <id>`, or check `rig run list`." });
|
|
611
|
-
}
|
|
612
|
-
const entries = Array.isArray(fallback.page.entries) ? fallback.page.entries : [];
|
|
613
|
-
if (context.outputMode === "text") {
|
|
614
|
-
for (const entry of entries) {
|
|
615
|
-
const record = entry && typeof entry === "object" ? entry : {};
|
|
616
|
-
const title = String(record.title ?? "");
|
|
617
|
-
const detail = String(record.detail ?? "");
|
|
618
|
-
console.log([title, detail].filter(Boolean).join(" \u2014 "));
|
|
619
|
-
}
|
|
620
|
-
if (entries.length === 0)
|
|
621
|
-
console.log(`(no log entries for run ${fallback.runId})`);
|
|
622
|
-
}
|
|
623
|
-
return { ok: true, group: "inspect", command, details: { task: requiredTask, runId: fallback.runId, source: "server", entries } };
|
|
624
|
-
}
|
|
625
|
-
const logsPath = resolve3(resolveAuthorityRunDir(context.projectRoot, latestRun.runId), "logs.jsonl");
|
|
626
|
-
if (!existsSync3(logsPath)) {
|
|
627
|
-
throw new CliError(`No logs found for run ${latestRun.runId}.`, 1, { hint: `Try \`rig run show ${latestRun.runId}\` or \`rig run replay ${latestRun.runId}\`.` });
|
|
628
|
-
}
|
|
629
|
-
await context.runCommand(["cat", logsPath]);
|
|
630
|
-
return { ok: true, group: "inspect", command, details: { task: requiredTask, runId: latestRun.runId } };
|
|
631
|
-
}
|
|
632
|
-
case "artifacts": {
|
|
633
|
-
const { value: task, rest: remaining } = takeOption(rest, "--task");
|
|
634
|
-
requireNoExtraArgs(remaining, "rig inspect artifacts --task <task-id>");
|
|
635
|
-
const requiredTask = requireTask(task, "rig inspect artifacts --task <task-id>");
|
|
636
|
-
const artifactRoot = resolveTaskArtifactDirs(context.projectRoot, requiredTask).find((path) => existsSync3(path));
|
|
637
|
-
if (!artifactRoot) {
|
|
638
|
-
throw new CliError(`No artifacts found for ${requiredTask}.`, 1, { hint: "Artifacts appear after a run completes; check `rig run list` for run state." });
|
|
639
|
-
}
|
|
640
|
-
await context.runCommand(["ls", "-la", artifactRoot]);
|
|
641
|
-
return { ok: true, group: "inspect", command, details: { task: requiredTask } };
|
|
642
|
-
}
|
|
643
|
-
case "artifact": {
|
|
644
|
-
let previewPending = rest;
|
|
645
|
-
const task = takeOption(previewPending, "--task");
|
|
646
|
-
previewPending = task.rest;
|
|
647
|
-
const file = takeOption(previewPending, "--file");
|
|
648
|
-
previewPending = file.rest;
|
|
649
|
-
requireNoExtraArgs(previewPending, "rig inspect artifact --task <task-id> --file <name>");
|
|
650
|
-
const requiredTask = requireTask(task.value, "rig inspect artifact --task <task-id> --file <name>");
|
|
651
|
-
if (!file.value) {
|
|
652
|
-
throw new CliError("Missing --file for rig inspect artifact.", 1, { hint: "List artifact files first: `rig inspect artifacts --task <id>`, then pass one with --file." });
|
|
653
|
-
}
|
|
654
|
-
const preview = readTaskArtifactPreview(context.projectRoot, requiredTask, file.value);
|
|
655
|
-
if (context.outputMode === "text") {
|
|
656
|
-
console.log(preview.contents);
|
|
657
|
-
if (preview.truncated) {
|
|
658
|
-
console.log(`
|
|
659
|
-
[preview truncated at ${preview.maxBytes} bytes of ${preview.sizeBytes}]`);
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
return {
|
|
663
|
-
ok: true,
|
|
664
|
-
group: "inspect",
|
|
665
|
-
command,
|
|
666
|
-
details: {
|
|
667
|
-
task: requiredTask,
|
|
668
|
-
fileName: file.value,
|
|
669
|
-
path: preview.path,
|
|
670
|
-
sizeBytes: preview.sizeBytes,
|
|
671
|
-
truncated: preview.truncated,
|
|
672
|
-
maxBytes: preview.maxBytes,
|
|
673
|
-
contents: context.outputMode === "json" ? preview.contents : null
|
|
674
|
-
}
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
case "diff": {
|
|
678
|
-
const { value: task, rest: remaining } = takeOption(rest, "--task");
|
|
679
|
-
requireNoExtraArgs(remaining, "rig inspect diff [--task <task-id>]");
|
|
680
|
-
if (task) {
|
|
681
|
-
const files = await withSpinner(`Computing changed files for ${task}\u2026`, async () => changedFilesForTask(context.projectRoot, task, false), { outputMode: context.outputMode });
|
|
682
|
-
for (const file of files) {
|
|
683
|
-
console.log(file);
|
|
684
|
-
}
|
|
685
|
-
} else {
|
|
686
|
-
await context.runCommand(["git", "diff", "--stat"]);
|
|
687
|
-
}
|
|
688
|
-
return { ok: true, group: "inspect", command, details: { task: task || null } };
|
|
689
|
-
}
|
|
690
|
-
case "failures": {
|
|
691
|
-
requireNoExtraArgs(rest, "rig inspect failures");
|
|
692
|
-
const failed = resolveHarnessPaths(context.projectRoot).failedApproachesPath;
|
|
693
|
-
if (!existsSync3(failed)) {
|
|
694
|
-
console.log("No failures recorded.");
|
|
695
|
-
} else {
|
|
696
|
-
process.stdout.write(readFileSync3(failed, "utf-8"));
|
|
697
|
-
}
|
|
698
|
-
return { ok: true, group: "inspect", command };
|
|
699
|
-
}
|
|
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);
|
|
700
752
|
case "graph":
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
throw new CliError(result.stderr || result.stdout || "Failed to inspect graph");
|
|
707
|
-
}
|
|
708
|
-
process.stdout.write(result.stdout);
|
|
709
|
-
}
|
|
710
|
-
return { ok: true, group: "inspect", command };
|
|
711
|
-
case "audit": {
|
|
712
|
-
requireNoExtraArgs(rest, "rig inspect audit");
|
|
713
|
-
const auditPath = resolve3(resolveHarnessPaths(context.projectRoot).logsDir, "audit.jsonl");
|
|
714
|
-
if (!existsSync3(auditPath)) {
|
|
715
|
-
console.log("No audit log found.");
|
|
716
|
-
} else {
|
|
717
|
-
const lines = readFileSync3(auditPath, "utf-8").split(/\r?\n/).filter(Boolean).slice(-20);
|
|
718
|
-
for (const line of lines) {
|
|
719
|
-
console.log(line);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
return { ok: true, group: "inspect", command };
|
|
723
|
-
}
|
|
753
|
+
return executeGraph(context, rest, deps);
|
|
754
|
+
case "failures":
|
|
755
|
+
return executeFailures(context, rest, deps);
|
|
756
|
+
case "audit":
|
|
757
|
+
return executeAudit(rest);
|
|
724
758
|
default:
|
|
725
759
|
throw new CliError(`Unknown inspect command: ${command}`, 1, { hint: "Run `rig inspect --help` to list inspect commands." });
|
|
726
760
|
}
|