@h-rig/cli 0.0.6-alpha.94 → 0.0.6-alpha.96
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 +6 -27
- package/bin/rig.js +16 -0
- package/package.json +14 -40
- package/dist/bin/build-rig-binaries.d.ts +0 -2
- package/dist/bin/build-rig-binaries.js +0 -119
- package/dist/bin/rig.d.ts +0 -72
- package/dist/bin/rig.js +0 -17855
- package/dist/config/rig-default-config.yml +0 -5
- package/dist/src/app/drone-ui.d.ts +0 -34
- package/dist/src/app/drone-ui.js +0 -278
- package/dist/src/commands/_async-ui.d.ts +0 -10
- package/dist/src/commands/_async-ui.js +0 -121
- package/dist/src/commands/_cli-format.d.ts +0 -56
- package/dist/src/commands/_cli-format.js +0 -319
- package/dist/src/commands/_connection-state.d.ts +0 -54
- package/dist/src/commands/_connection-state.js +0 -187
- package/dist/src/commands/_doctor-checks.d.ts +0 -46
- package/dist/src/commands/_doctor-checks.js +0 -352
- package/dist/src/commands/_help-catalog.d.ts +0 -51
- package/dist/src/commands/_help-catalog.js +0 -502
- package/dist/src/commands/_inprocess-services.d.ts +0 -33
- package/dist/src/commands/_inprocess-services.js +0 -102
- package/dist/src/commands/_json-output.d.ts +0 -11
- package/dist/src/commands/_json-output.js +0 -60
- package/dist/src/commands/_lazy-reconcile.d.ts +0 -34
- package/dist/src/commands/_lazy-reconcile.js +0 -102
- package/dist/src/commands/_parsers.d.ts +0 -15
- package/dist/src/commands/_parsers.js +0 -114
- package/dist/src/commands/_paths.d.ts +0 -11
- package/dist/src/commands/_paths.js +0 -50
- package/dist/src/commands/_pi-frontend.d.ts +0 -35
- package/dist/src/commands/_pi-frontend.js +0 -64
- package/dist/src/commands/_pi-install.d.ts +0 -42
- package/dist/src/commands/_pi-install.js +0 -167
- package/dist/src/commands/_policy.d.ts +0 -8
- package/dist/src/commands/_policy.js +0 -127
- package/dist/src/commands/_probes.d.ts +0 -1
- package/dist/src/commands/_probes.js +0 -13
- package/dist/src/commands/_run-bridge.d.ts +0 -114
- package/dist/src/commands/_run-bridge.js +0 -387
- package/dist/src/commands/_run-diagnostics.d.ts +0 -9
- package/dist/src/commands/_run-diagnostics.js +0 -51
- package/dist/src/commands/_run-driver-helpers.d.ts +0 -26
- package/dist/src/commands/_run-driver-helpers.js +0 -138
- package/dist/src/commands/_run-projection.d.ts +0 -50
- package/dist/src/commands/_run-projection.js +0 -349
- package/dist/src/commands/_run-subcommands.d.ts +0 -3
- package/dist/src/commands/_run-subcommands.js +0 -31
- package/dist/src/commands/_spinner.d.ts +0 -25
- package/dist/src/commands/_spinner.js +0 -65
- package/dist/src/commands/agent.d.ts +0 -3
- package/dist/src/commands/agent.js +0 -8837
- package/dist/src/commands/dist.d.ts +0 -28
- package/dist/src/commands/dist.js +0 -417
- package/dist/src/commands/doctor.d.ts +0 -3
- package/dist/src/commands/doctor.js +0 -480
- package/dist/src/commands/github.d.ts +0 -3
- package/dist/src/commands/github.js +0 -342
- package/dist/src/commands/inbox.d.ts +0 -28
- package/dist/src/commands/inbox.js +0 -579
- package/dist/src/commands/init.d.ts +0 -64
- package/dist/src/commands/init.js +0 -1541
- package/dist/src/commands/inspect.d.ts +0 -20
- package/dist/src/commands/inspect.js +0 -764
- package/dist/src/commands/pi.d.ts +0 -3
- package/dist/src/commands/pi.js +0 -177
- package/dist/src/commands/plugin.d.ts +0 -16
- package/dist/src/commands/plugin.js +0 -714
- package/dist/src/commands/profile-and-review.d.ts +0 -4
- package/dist/src/commands/profile-and-review.js +0 -223
- package/dist/src/commands/queue.d.ts +0 -3
- package/dist/src/commands/queue.js +0 -197
- package/dist/src/commands/remote.d.ts +0 -3
- package/dist/src/commands/remote.js +0 -1337
- package/dist/src/commands/repo-git-harness.d.ts +0 -5
- package/dist/src/commands/repo-git-harness.js +0 -271
- package/dist/src/commands/run.d.ts +0 -21
- package/dist/src/commands/run.js +0 -17847
- package/dist/src/commands/server.d.ts +0 -3
- package/dist/src/commands/server.js +0 -249
- package/dist/src/commands/setup.d.ts +0 -16
- package/dist/src/commands/setup.js +0 -644
- package/dist/src/commands/stats.d.ts +0 -15
- package/dist/src/commands/stats.js +0 -979
- package/dist/src/commands/task-run-driver.d.ts +0 -94
- package/dist/src/commands/task-run-driver.js +0 -203
- package/dist/src/commands/task.d.ts +0 -35
- package/dist/src/commands/task.js +0 -818
- package/dist/src/commands/test.d.ts +0 -3
- package/dist/src/commands/test.js +0 -46
- package/dist/src/commands/triage.d.ts +0 -11
- package/dist/src/commands/triage.js +0 -227
- package/dist/src/commands/workspace.d.ts +0 -3
- package/dist/src/commands/workspace.js +0 -130
- package/dist/src/commands.d.ts +0 -13
- package/dist/src/commands.js +0 -17979
- package/dist/src/index.d.ts +0 -4
- package/dist/src/index.js +0 -17991
- package/dist/src/launcher.d.ts +0 -61
- package/dist/src/launcher.js +0 -199
- package/dist/src/operator-cli.d.ts +0 -2
- package/dist/src/operator-cli.js +0 -17847
- package/dist/src/operator-entry.d.ts +0 -1
- package/dist/src/operator-entry.js +0 -3
- package/dist/src/runner.d.ts +0 -47
- package/dist/src/runner.js +0 -267
- package/dist/src/withMutedConsole.d.ts +0 -2
- package/dist/src/withMutedConsole.js +0 -42
|
@@ -1,579 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// packages/cli/src/commands/inbox.ts
|
|
3
|
-
import { Duration, Effect, Stream } from "effect";
|
|
4
|
-
|
|
5
|
-
// packages/cli/src/runner.ts
|
|
6
|
-
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
7
|
-
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
8
|
-
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
9
|
-
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
10
|
-
|
|
11
|
-
class CliError extends RuntimeCliError {
|
|
12
|
-
hint;
|
|
13
|
-
constructor(message, exitCode = 1, options = {}) {
|
|
14
|
-
super(message, exitCode);
|
|
15
|
-
if (options.hint?.trim()) {
|
|
16
|
-
this.hint = options.hint.trim();
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
function takeOption(args, option) {
|
|
21
|
-
const rest = [];
|
|
22
|
-
let value;
|
|
23
|
-
for (let index = 0;index < args.length; index += 1) {
|
|
24
|
-
const current = args[index];
|
|
25
|
-
if (current === option) {
|
|
26
|
-
const next = args[index + 1];
|
|
27
|
-
if (!next || next.startsWith("-")) {
|
|
28
|
-
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
29
|
-
}
|
|
30
|
-
value = next;
|
|
31
|
-
index += 1;
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
if (current !== undefined) {
|
|
35
|
-
rest.push(current);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return { value, rest };
|
|
39
|
-
}
|
|
40
|
-
function requireNoExtraArgs(args, usage) {
|
|
41
|
-
if (args.length > 0) {
|
|
42
|
-
throw new CliError(`Unexpected arguments: ${args.join(" ")}
|
|
43
|
-
Usage: ${usage}`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// packages/cli/src/commands/inbox.ts
|
|
48
|
-
import { localRunChanges } from "@rig/runtime/control-plane/run-discovery-stream";
|
|
49
|
-
|
|
50
|
-
// packages/cli/src/commands/_cli-format.ts
|
|
51
|
-
import pc from "picocolors";
|
|
52
|
-
var dim = pc.dim;
|
|
53
|
-
var faintBar = pc.dim("\u2502");
|
|
54
|
-
var accent = pc.cyan;
|
|
55
|
-
function statusColor(status) {
|
|
56
|
-
const normalized = status.trim().toLowerCase();
|
|
57
|
-
if (["done", "completed", "ready", "healthy", "open", "approved"].includes(normalized))
|
|
58
|
-
return pc.green;
|
|
59
|
-
if (["failed", "error", "blocked", "rejected", "stopped"].includes(normalized))
|
|
60
|
-
return pc.red;
|
|
61
|
-
if (["running", "in_progress", "in-progress", "active", "booting"].includes(normalized))
|
|
62
|
-
return pc.cyan;
|
|
63
|
-
if (["pending", "queued", "created", "local"].includes(normalized))
|
|
64
|
-
return pc.yellow;
|
|
65
|
-
return pc.dim;
|
|
66
|
-
}
|
|
67
|
-
function firstString(record, keys, fallback = "") {
|
|
68
|
-
for (const key of keys) {
|
|
69
|
-
const value = record[key];
|
|
70
|
-
if (typeof value === "string" && value.trim())
|
|
71
|
-
return value;
|
|
72
|
-
}
|
|
73
|
-
return fallback;
|
|
74
|
-
}
|
|
75
|
-
function requestIdOf(entry) {
|
|
76
|
-
return firstString(entry, ["requestId", "id", "approvalId", "inputId"], "(unknown-request)");
|
|
77
|
-
}
|
|
78
|
-
function printFormattedOutput(message) {
|
|
79
|
-
console.log(message);
|
|
80
|
-
}
|
|
81
|
-
function formatStatusPill(status) {
|
|
82
|
-
const label = status || "unknown";
|
|
83
|
-
return statusColor(label)(`\u25CF ${label}`);
|
|
84
|
-
}
|
|
85
|
-
function formatSection(title, subtitle) {
|
|
86
|
-
return `${pc.bold(accent("\u25C6"))} ${pc.bold(title)}${subtitle ? dim(` \u2014 ${subtitle}`) : ""}`;
|
|
87
|
-
}
|
|
88
|
-
function formatNextSteps(steps) {
|
|
89
|
-
if (steps.length === 0)
|
|
90
|
-
return [];
|
|
91
|
-
return [pc.bold("Next"), ...steps.map((step) => `${accent("\u203A")} ${step}`)];
|
|
92
|
-
}
|
|
93
|
-
function formatLegacyAutomationSurface() {
|
|
94
|
-
return [];
|
|
95
|
-
}
|
|
96
|
-
function formatInboxList(kind, entries) {
|
|
97
|
-
const title = kind === "approvals" ? "Pending approvals" : "Pending user input";
|
|
98
|
-
if (entries.length === 0) {
|
|
99
|
-
return [
|
|
100
|
-
formatSection(title, "empty"),
|
|
101
|
-
dim(kind === "approvals" ? "No pending approvals." : "No pending user-input requests."),
|
|
102
|
-
"",
|
|
103
|
-
...formatLegacyAutomationSurface()
|
|
104
|
-
].join(`
|
|
105
|
-
`);
|
|
106
|
-
}
|
|
107
|
-
const lines = [formatSection(title, `${entries.length}`)];
|
|
108
|
-
for (const record of entries) {
|
|
109
|
-
const runId = firstString(record, ["runId"], "(unknown-run)");
|
|
110
|
-
const taskId = firstString(record, ["taskId"], "");
|
|
111
|
-
const status = firstString(record, ["status"], "pending");
|
|
112
|
-
const prompt = firstString(record, ["prompt", "message", "reason", "title", "summary"], kind === "approvals" ? "Approval requested" : "Input requested");
|
|
113
|
-
lines.push(`${faintBar} ${pc.bold(requestIdOf(record))} ${formatStatusPill(status)} ${prompt}`);
|
|
114
|
-
lines.push(`${faintBar} ${dim("run".padEnd(12))} ${runId}${taskId ? dim(` task ${taskId}`) : ""}`);
|
|
115
|
-
}
|
|
116
|
-
lines.push("", ...formatLegacyAutomationSurface(), ...formatNextSteps(kind === "approvals" ? ["Resolve: `rig inbox approve --run <run-id> --request <request-id> --decision approve|reject`"] : ["Reply: `rig inbox answer --run <run-id> --request <request-id> --text ...`"]));
|
|
117
|
-
return lines.join(`
|
|
118
|
-
`);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// packages/cli/src/commands/_run-projection.ts
|
|
122
|
-
import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
|
|
123
|
-
import { resolve as resolve2 } from "path";
|
|
124
|
-
import {
|
|
125
|
-
foldRunSessionEntries,
|
|
126
|
-
sessionIdFromSessionFile as sessionIdFromSessionFile2
|
|
127
|
-
} from "@rig/contracts";
|
|
128
|
-
import { listAgentRuntimes as listAgentRuntimes2 } from "@rig/runtime/control-plane/runtime/isolation";
|
|
129
|
-
|
|
130
|
-
// packages/cli/src/commands/_run-bridge.ts
|
|
131
|
-
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
132
|
-
import { dirname, resolve } from "path";
|
|
133
|
-
import { CUSTOM_TYPE_FOR, sessionIdFromSessionFile } from "@rig/contracts";
|
|
134
|
-
import { createPluginHost } from "@rig/core";
|
|
135
|
-
import { loadConfig } from "@rig/core/load-config";
|
|
136
|
-
import { resolveOwnerNamespaceKey, resolveRegistryBaseUrl, resolveRegistrySecret, resolveSelectedRemote } from "@rig/runtime/control-plane/remote";
|
|
137
|
-
import { listAgentRuntimes } from "@rig/runtime/control-plane/runtime/isolation";
|
|
138
|
-
import { createRegistryClient } from "@rig/relay-registry";
|
|
139
|
-
import {
|
|
140
|
-
listActiveCollabSessions as ompListActiveCollabSessions
|
|
141
|
-
} from "@oh-my-pi/pi-coding-agent/collab/api";
|
|
142
|
-
function registrySecret(env = process.env) {
|
|
143
|
-
return resolveRegistrySecret(process.cwd(), env) ?? null;
|
|
144
|
-
}
|
|
145
|
-
function registryBaseUrl(env = process.env) {
|
|
146
|
-
return resolveRegistryBaseUrl(process.cwd(), env);
|
|
147
|
-
}
|
|
148
|
-
function collabFromRegistryEntry(entry) {
|
|
149
|
-
return {
|
|
150
|
-
sessionId: entry.roomId,
|
|
151
|
-
sessionPath: "",
|
|
152
|
-
cwd: "",
|
|
153
|
-
title: entry.title,
|
|
154
|
-
joinLink: entry.joinLink,
|
|
155
|
-
webLink: entry.webLink,
|
|
156
|
-
relayUrl: entry.relayUrl,
|
|
157
|
-
owner: entry.owner,
|
|
158
|
-
selectedRepo: entry.repo,
|
|
159
|
-
startedAt: entry.startedAt,
|
|
160
|
-
updatedAt: entry.heartbeatAt,
|
|
161
|
-
...entry.pid === undefined ? {} : { pid: entry.pid },
|
|
162
|
-
stale: entry.stale
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
function isRecord(value) {
|
|
166
|
-
return typeof value === "object" && value !== null;
|
|
167
|
-
}
|
|
168
|
-
function readLocalRunCollab(runtime) {
|
|
169
|
-
if (!runtime.sessionDir || !existsSync(runtime.sessionDir))
|
|
170
|
-
return null;
|
|
171
|
-
let files;
|
|
172
|
-
try {
|
|
173
|
-
files = readdirSync(runtime.sessionDir).filter((f) => f.endsWith(".jsonl")).sort().reverse();
|
|
174
|
-
} catch {
|
|
175
|
-
return null;
|
|
176
|
-
}
|
|
177
|
-
for (const file of files) {
|
|
178
|
-
let lines;
|
|
179
|
-
try {
|
|
180
|
-
lines = readFileSync(resolve(runtime.sessionDir, file), "utf8").split(`
|
|
181
|
-
`);
|
|
182
|
-
} catch {
|
|
183
|
-
continue;
|
|
184
|
-
}
|
|
185
|
-
let host = null;
|
|
186
|
-
for (const line of lines) {
|
|
187
|
-
if (!line.includes("collab-host-started"))
|
|
188
|
-
continue;
|
|
189
|
-
let entry;
|
|
190
|
-
try {
|
|
191
|
-
entry = JSON.parse(line);
|
|
192
|
-
} catch {
|
|
193
|
-
continue;
|
|
194
|
-
}
|
|
195
|
-
if (!isRecord(entry) || entry.customType !== CUSTOM_TYPE_FOR["timeline-entry"] || !isRecord(entry.data))
|
|
196
|
-
continue;
|
|
197
|
-
const payload = isRecord(entry.data.payload) ? entry.data.payload : entry.data;
|
|
198
|
-
if (payload.type !== "collab-host-started")
|
|
199
|
-
continue;
|
|
200
|
-
host = {
|
|
201
|
-
roomId: typeof payload.roomId === "string" ? payload.roomId : undefined,
|
|
202
|
-
joinLink: typeof payload.joinLink === "string" ? payload.joinLink : undefined,
|
|
203
|
-
webLink: typeof payload.webLink === "string" ? payload.webLink : undefined,
|
|
204
|
-
relayUrl: typeof payload.relayUrl === "string" ? payload.relayUrl : undefined,
|
|
205
|
-
at: typeof entry.data.at === "string" ? entry.data.at : undefined
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
if (!host?.joinLink)
|
|
209
|
-
continue;
|
|
210
|
-
const at = host.at ?? "";
|
|
211
|
-
const sessionId = host.roomId ?? sessionIdFromSessionFile(resolve(runtime.sessionDir, file)) ?? runtime.id;
|
|
212
|
-
return {
|
|
213
|
-
sessionId,
|
|
214
|
-
sessionPath: resolve(runtime.sessionDir, file),
|
|
215
|
-
cwd: runtime.workspaceDir,
|
|
216
|
-
joinLink: host.joinLink,
|
|
217
|
-
webLink: host.webLink ?? "",
|
|
218
|
-
relayUrl: host.relayUrl ?? "",
|
|
219
|
-
title: runtime.taskId ? `[${runtime.taskId}] Rig run ${sessionId}` : `Rig run ${sessionId}`,
|
|
220
|
-
startedAt: at,
|
|
221
|
-
updatedAt: at,
|
|
222
|
-
stale: false
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
return null;
|
|
226
|
-
}
|
|
227
|
-
async function listLocalRunCollabSessions(projectRoot) {
|
|
228
|
-
let runtimes;
|
|
229
|
-
try {
|
|
230
|
-
runtimes = await listAgentRuntimes(projectRoot);
|
|
231
|
-
} catch {
|
|
232
|
-
return [];
|
|
233
|
-
}
|
|
234
|
-
const out = [];
|
|
235
|
-
for (const runtime of runtimes) {
|
|
236
|
-
const collab = readLocalRunCollab(runtime);
|
|
237
|
-
if (collab)
|
|
238
|
-
out.push(collab);
|
|
239
|
-
}
|
|
240
|
-
return out;
|
|
241
|
-
}
|
|
242
|
-
async function listActiveRunCollab(filter) {
|
|
243
|
-
return defaultListActiveCollabSessions(filter);
|
|
244
|
-
}
|
|
245
|
-
async function defaultListActiveCollabSessions(filter) {
|
|
246
|
-
const projectRoot = process.cwd();
|
|
247
|
-
const local = await listLocalRunCollabSessions(projectRoot);
|
|
248
|
-
const namespaceKey = filter.namespaceKey ?? resolveOwnerNamespaceKey(projectRoot);
|
|
249
|
-
const secret = registrySecret();
|
|
250
|
-
const remote = namespaceKey && secret ? (await createRegistryClient({ baseUrl: registryBaseUrl(), namespaceKey, secret }).listRoomsByOwner(filter)).map(collabFromRegistryEntry) : await ompListActiveCollabSessions(filter);
|
|
251
|
-
const seen = new Set(local.map((c) => c.sessionId));
|
|
252
|
-
return [...local, ...remote.filter((c) => !seen.has(c.sessionId))];
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// packages/cli/src/commands/_run-diagnostics.ts
|
|
256
|
-
function normalizeString(value) {
|
|
257
|
-
if (typeof value !== "string")
|
|
258
|
-
return null;
|
|
259
|
-
const normalized = value.replace(/\s+/g, " ").trim();
|
|
260
|
-
return normalized.length > 0 ? normalized : null;
|
|
261
|
-
}
|
|
262
|
-
function isGenericRunFailure(value) {
|
|
263
|
-
const text = normalizeString(value);
|
|
264
|
-
return Boolean(text && /^Task run failed \([^)]*\)$/i.test(text));
|
|
265
|
-
}
|
|
266
|
-
function appendCandidate(candidates, value) {
|
|
267
|
-
const text = normalizeString(value);
|
|
268
|
-
if (text && !candidates.includes(text))
|
|
269
|
-
candidates.push(text);
|
|
270
|
-
}
|
|
271
|
-
function categorizeUsefulRunError(lines) {
|
|
272
|
-
const taskSourceFailure = lines.find((line) => /failed to update task source/i.test(line));
|
|
273
|
-
if (taskSourceFailure)
|
|
274
|
-
return `Task source update failed: ${taskSourceFailure}`;
|
|
275
|
-
const moduleFailure = lines.find((line) => /cannot find module/i.test(line));
|
|
276
|
-
if (moduleFailure)
|
|
277
|
-
return `Runtime module resolution failed: ${moduleFailure}`;
|
|
278
|
-
const providerFailure = lines.find((line) => /no api key found|unauthorized|authentication failed|invalid api key/i.test(line));
|
|
279
|
-
if (providerFailure)
|
|
280
|
-
return `Provider authentication failed: ${providerFailure}`;
|
|
281
|
-
return null;
|
|
282
|
-
}
|
|
283
|
-
function summarizeUsefulRunError(projection) {
|
|
284
|
-
if (projection.status !== "failed")
|
|
285
|
-
return null;
|
|
286
|
-
const candidates = [];
|
|
287
|
-
for (const anomaly of projection.anomalies) {
|
|
288
|
-
appendCandidate(candidates, `Journal anomaly (${anomaly.kind}): ${anomaly.detail}`);
|
|
289
|
-
}
|
|
290
|
-
for (const phase of projection.closeoutPhases) {
|
|
291
|
-
if (phase.outcome === "failed")
|
|
292
|
-
appendCandidate(candidates, phase.detail);
|
|
293
|
-
}
|
|
294
|
-
for (const entry of projection.statusHistory) {
|
|
295
|
-
appendCandidate(candidates, entry.reason);
|
|
296
|
-
}
|
|
297
|
-
appendCandidate(candidates, projection.record.statusDetail);
|
|
298
|
-
appendCandidate(candidates, projection.record.errorText);
|
|
299
|
-
const nonGeneric = candidates.filter((candidate) => !isGenericRunFailure(candidate));
|
|
300
|
-
return categorizeUsefulRunError(nonGeneric) ?? nonGeneric.at(-1) ?? normalizeString(projection.record.errorText);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// packages/cli/src/commands/_run-projection.ts
|
|
304
|
-
var EMPTY_PROJECTION = foldRunSessionEntries([], "");
|
|
305
|
-
function stringOrNull(value) {
|
|
306
|
-
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
307
|
-
}
|
|
308
|
-
function newestSessionFile(sessionDir) {
|
|
309
|
-
if (!sessionDir || !existsSync2(sessionDir))
|
|
310
|
-
return null;
|
|
311
|
-
try {
|
|
312
|
-
const files = readdirSync2(sessionDir).filter((file) => file.endsWith(".jsonl")).sort().reverse();
|
|
313
|
-
return files[0] ? resolve2(sessionDir, files[0]) : null;
|
|
314
|
-
} catch {
|
|
315
|
-
return null;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
function readSessionRunEntries(sessionPath) {
|
|
319
|
-
if (!sessionPath || !existsSync2(sessionPath))
|
|
320
|
-
return [];
|
|
321
|
-
let raw;
|
|
322
|
-
try {
|
|
323
|
-
raw = readFileSync2(sessionPath, "utf8");
|
|
324
|
-
} catch {
|
|
325
|
-
return [];
|
|
326
|
-
}
|
|
327
|
-
const entries = [];
|
|
328
|
-
for (const line of raw.split(`
|
|
329
|
-
`)) {
|
|
330
|
-
if (!line.trim())
|
|
331
|
-
continue;
|
|
332
|
-
let parsed;
|
|
333
|
-
try {
|
|
334
|
-
parsed = JSON.parse(line);
|
|
335
|
-
} catch {
|
|
336
|
-
continue;
|
|
337
|
-
}
|
|
338
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
339
|
-
continue;
|
|
340
|
-
entries.push({
|
|
341
|
-
type: "type" in parsed && typeof parsed.type === "string" ? parsed.type : "",
|
|
342
|
-
..."customType" in parsed && typeof parsed.customType === "string" ? { customType: parsed.customType } : {},
|
|
343
|
-
..."data" in parsed ? { data: parsed.data } : {}
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
return entries;
|
|
347
|
-
}
|
|
348
|
-
function recordFromProjection(runId, projection, presence) {
|
|
349
|
-
const record = projection.record;
|
|
350
|
-
const status = projection.status ?? (presence.stale ? "stale" : presence.live ? "running" : "unknown");
|
|
351
|
-
const taskId = stringOrNull(record.taskId) ?? presence.fallbackTaskId ?? null;
|
|
352
|
-
const title = stringOrNull(record.title) ?? stringOrNull(presence.title) ?? (taskId ? `Run ${taskId}` : `Rig run ${runId}`);
|
|
353
|
-
return {
|
|
354
|
-
runId,
|
|
355
|
-
taskId,
|
|
356
|
-
title,
|
|
357
|
-
status,
|
|
358
|
-
source: presence.source,
|
|
359
|
-
live: presence.live,
|
|
360
|
-
stale: presence.stale,
|
|
361
|
-
startedAt: stringOrNull(record.startedAt) ?? presence.startedAt ?? null,
|
|
362
|
-
updatedAt: stringOrNull(record.updatedAt) ?? presence.updatedAt ?? projection.lastEventAt ?? null,
|
|
363
|
-
completedAt: stringOrNull(record.completedAt),
|
|
364
|
-
joinLink: presence.joinLink ?? null,
|
|
365
|
-
webLink: presence.webLink ?? null,
|
|
366
|
-
relayUrl: presence.relayUrl ?? null,
|
|
367
|
-
sessionPath: stringOrNull(record.sessionPath) ?? presence.sessionPath ?? null,
|
|
368
|
-
prUrl: stringOrNull(record.prUrl),
|
|
369
|
-
worktreePath: stringOrNull(record.worktreePath),
|
|
370
|
-
pendingApprovals: projection.pendingApprovals.length,
|
|
371
|
-
pendingInputs: projection.pendingUserInputs.length,
|
|
372
|
-
steeringCount: projection.steeringCount,
|
|
373
|
-
stallCount: projection.stallCount,
|
|
374
|
-
errorSummary: summarizeUsefulRunError(projection),
|
|
375
|
-
projection
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
function recordFromLiveCollab(collab) {
|
|
379
|
-
const runId = collab.sessionId;
|
|
380
|
-
const sessionPath = stringOrNull(collab.sessionPath);
|
|
381
|
-
const projection = sessionPath ? foldRunSessionEntries(readSessionRunEntries(sessionPath), runId) : EMPTY_PROJECTION;
|
|
382
|
-
return recordFromProjection(runId, projection, {
|
|
383
|
-
source: sessionPath ? "local" : "remote",
|
|
384
|
-
live: !collab.stale,
|
|
385
|
-
stale: Boolean(collab.stale),
|
|
386
|
-
title: collab.title,
|
|
387
|
-
joinLink: stringOrNull(collab.joinLink),
|
|
388
|
-
webLink: stringOrNull(collab.webLink),
|
|
389
|
-
relayUrl: stringOrNull(collab.relayUrl),
|
|
390
|
-
sessionPath,
|
|
391
|
-
startedAt: stringOrNull(collab.startedAt),
|
|
392
|
-
updatedAt: stringOrNull(collab.updatedAt)
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
function recordFromRuntime(runtime) {
|
|
396
|
-
const sessionPath = newestSessionFile(runtime.sessionDir ?? "");
|
|
397
|
-
if (!sessionPath)
|
|
398
|
-
return null;
|
|
399
|
-
const projection = foldRunSessionEntries(readSessionRunEntries(sessionPath), runtime.id);
|
|
400
|
-
if (projection.lastSeq === 0)
|
|
401
|
-
return null;
|
|
402
|
-
return recordFromProjection(sessionIdFromSessionFile2(sessionPath) ?? runtime.id, projection, {
|
|
403
|
-
source: "local",
|
|
404
|
-
live: false,
|
|
405
|
-
stale: false,
|
|
406
|
-
sessionPath,
|
|
407
|
-
fallbackTaskId: stringOrNull(runtime.taskId)
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
function sortByRecency(records) {
|
|
411
|
-
return [...records].sort((a, b) => {
|
|
412
|
-
const at = Date.parse(b.updatedAt ?? b.startedAt ?? "") || 0;
|
|
413
|
-
const bt = Date.parse(a.updatedAt ?? a.startedAt ?? "") || 0;
|
|
414
|
-
return at - bt;
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
async function listRunProjections(projectRoot, filter = {}) {
|
|
418
|
-
const byRunId = new Map;
|
|
419
|
-
let live = [];
|
|
420
|
-
try {
|
|
421
|
-
live = await listActiveRunCollab(filter);
|
|
422
|
-
} catch {
|
|
423
|
-
live = [];
|
|
424
|
-
}
|
|
425
|
-
for (const collab of live) {
|
|
426
|
-
const record = recordFromLiveCollab(collab);
|
|
427
|
-
byRunId.set(record.runId, record);
|
|
428
|
-
}
|
|
429
|
-
let runtimes = [];
|
|
430
|
-
try {
|
|
431
|
-
runtimes = await listAgentRuntimes2(projectRoot);
|
|
432
|
-
} catch {
|
|
433
|
-
runtimes = [];
|
|
434
|
-
}
|
|
435
|
-
for (const runtime of runtimes) {
|
|
436
|
-
const record = recordFromRuntime(runtime);
|
|
437
|
-
if (!record)
|
|
438
|
-
continue;
|
|
439
|
-
const sessionId = sessionIdFromSessionFile2(record.sessionPath);
|
|
440
|
-
const liveMatch = sessionId ? byRunId.get(sessionId) : undefined;
|
|
441
|
-
if (liveMatch) {
|
|
442
|
-
if (liveMatch.source === "remote" || !liveMatch.sessionPath) {
|
|
443
|
-
byRunId.set(liveMatch.runId, { ...liveMatch, sessionPath: record.sessionPath, source: "local" });
|
|
444
|
-
}
|
|
445
|
-
continue;
|
|
446
|
-
}
|
|
447
|
-
if (byRunId.has(runtime.id))
|
|
448
|
-
continue;
|
|
449
|
-
byRunId.set(record.runId, record);
|
|
450
|
-
}
|
|
451
|
-
return sortByRecency([...byRunId.values()]);
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// packages/cli/src/commands/inbox.ts
|
|
455
|
-
function promptFromPayload(payload, fallback) {
|
|
456
|
-
if (payload && typeof payload === "object") {
|
|
457
|
-
const record = payload;
|
|
458
|
-
for (const key of ["title", "message", "reason", "prompt", "summary"]) {
|
|
459
|
-
const value = record[key];
|
|
460
|
-
if (typeof value === "string" && value.trim().length > 0)
|
|
461
|
-
return value.trim();
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
return fallback;
|
|
465
|
-
}
|
|
466
|
-
function recordsFromRun(run, kind) {
|
|
467
|
-
const pending = kind === "approvals" ? run.projection.pendingApprovals : run.projection.pendingUserInputs;
|
|
468
|
-
return pending.map((request) => ({
|
|
469
|
-
runId: run.runId,
|
|
470
|
-
taskId: run.taskId,
|
|
471
|
-
requestId: request.requestId,
|
|
472
|
-
status: "pending",
|
|
473
|
-
prompt: promptFromPayload(request.payload, kind === "approvals" ? "Approval requested" : "Input requested"),
|
|
474
|
-
requestedAt: request.requestedAt,
|
|
475
|
-
payload: request.payload
|
|
476
|
-
}));
|
|
477
|
-
}
|
|
478
|
-
async function listInboxRecords(context, kind, filters = {}, deps = {}) {
|
|
479
|
-
const runs = await (deps.listRuns ?? ((root) => listRunProjections(root)))(context.projectRoot);
|
|
480
|
-
const out = [];
|
|
481
|
-
for (const run of runs) {
|
|
482
|
-
if (filters.run && run.runId !== filters.run)
|
|
483
|
-
continue;
|
|
484
|
-
if (filters.task && run.taskId !== filters.task)
|
|
485
|
-
continue;
|
|
486
|
-
out.push(...recordsFromRun(run, kind));
|
|
487
|
-
}
|
|
488
|
-
return out;
|
|
489
|
-
}
|
|
490
|
-
async function readPendingInboxCounts(context) {
|
|
491
|
-
try {
|
|
492
|
-
const [approvals, inputs] = await Promise.all([
|
|
493
|
-
listInboxRecords(context, "approvals"),
|
|
494
|
-
listInboxRecords(context, "inputs")
|
|
495
|
-
]);
|
|
496
|
-
return { approvals: approvals.length, inputs: inputs.length };
|
|
497
|
-
} catch {
|
|
498
|
-
return null;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
function resolveRequiresAttach(runId, verb) {
|
|
502
|
-
const target = runId ?? "<run-id>";
|
|
503
|
-
throw new CliError(`rig inbox ${verb} cannot deliver a resolution into a live worker from a one-shot command.`, 2, { hint: `Attach to resolve interactively: rig run attach ${target}` });
|
|
504
|
-
}
|
|
505
|
-
async function readInboxSnapshot(context, filters, deps) {
|
|
506
|
-
const [approvals, inputs] = await Promise.all([
|
|
507
|
-
listInboxRecords(context, "approvals", filters, deps),
|
|
508
|
-
listInboxRecords(context, "inputs", filters, deps)
|
|
509
|
-
]);
|
|
510
|
-
return { approvals, inputs };
|
|
511
|
-
}
|
|
512
|
-
function renderInboxSnapshot(snapshot) {
|
|
513
|
-
console.clear();
|
|
514
|
-
console.log(`rig inbox \u2014 watching (Ctrl-C to stop) \u2014 ${new Date().toLocaleTimeString()}`);
|
|
515
|
-
printFormattedOutput(formatInboxList("approvals", snapshot.approvals.map((entry) => ({ ...entry }))));
|
|
516
|
-
printFormattedOutput(formatInboxList("inputs", snapshot.inputs.map((entry) => ({ ...entry }))));
|
|
517
|
-
if (snapshot.approvals.length === 0 && snapshot.inputs.length === 0)
|
|
518
|
-
console.log("Nothing pending.");
|
|
519
|
-
}
|
|
520
|
-
async function watchInbox(context, filters, deps) {
|
|
521
|
-
const snapshot = await readInboxSnapshot(context, filters, deps);
|
|
522
|
-
if (context.outputMode !== "text") {
|
|
523
|
-
return { ok: true, group: "inbox", command: "watch", details: snapshot };
|
|
524
|
-
}
|
|
525
|
-
renderInboxSnapshot(snapshot);
|
|
526
|
-
await Effect.runPromise(localRunChanges(context.projectRoot).pipe(Stream.debounce(Duration.millis(500)), Stream.runForEach(() => Effect.promise(async () => {
|
|
527
|
-
renderInboxSnapshot(await readInboxSnapshot(context, filters, deps));
|
|
528
|
-
}))));
|
|
529
|
-
return { ok: true, group: "inbox", command: "watch", details: snapshot };
|
|
530
|
-
}
|
|
531
|
-
async function executeInbox(context, args, deps = {}) {
|
|
532
|
-
const [command = "approvals", ...rest] = args;
|
|
533
|
-
const text = context.outputMode === "text";
|
|
534
|
-
switch (command) {
|
|
535
|
-
case "approvals":
|
|
536
|
-
case "inputs": {
|
|
537
|
-
const run = takeOption(rest, "--run");
|
|
538
|
-
const task = takeOption(run.rest, "--task");
|
|
539
|
-
requireNoExtraArgs(task.rest, `rig inbox ${command} [--run <id>] [--task <id>]`);
|
|
540
|
-
const kind = command === "approvals" ? "approvals" : "inputs";
|
|
541
|
-
const filters = {
|
|
542
|
-
...run.value ? { run: run.value } : {},
|
|
543
|
-
...task.value ? { task: task.value } : {}
|
|
544
|
-
};
|
|
545
|
-
const entries = await listInboxRecords(context, kind, filters, deps);
|
|
546
|
-
if (text)
|
|
547
|
-
printFormattedOutput(formatInboxList(kind, entries.map((entry) => ({ ...entry }))));
|
|
548
|
-
return { ok: true, group: "inbox", command, details: { entries } };
|
|
549
|
-
}
|
|
550
|
-
case "approve": {
|
|
551
|
-
const run = takeOption(rest, "--run");
|
|
552
|
-
resolveRequiresAttach(run.value, "approve");
|
|
553
|
-
break;
|
|
554
|
-
}
|
|
555
|
-
case "respond": {
|
|
556
|
-
const run = takeOption(rest, "--run");
|
|
557
|
-
resolveRequiresAttach(run.value, "respond");
|
|
558
|
-
break;
|
|
559
|
-
}
|
|
560
|
-
case "watch": {
|
|
561
|
-
const run = takeOption(rest, "--run");
|
|
562
|
-
const task = takeOption(run.rest, "--task");
|
|
563
|
-
requireNoExtraArgs(task.rest, "rig inbox watch [--run <id>] [--task <id>]");
|
|
564
|
-
const filters = {
|
|
565
|
-
...run.value ? { run: run.value } : {},
|
|
566
|
-
...task.value ? { task: task.value } : {}
|
|
567
|
-
};
|
|
568
|
-
return watchInbox(context, filters, deps);
|
|
569
|
-
}
|
|
570
|
-
default:
|
|
571
|
-
throw new CliError(`Unknown inbox command: ${command}`, 1, { hint: "Run `rig inbox --help` to list inbox commands." });
|
|
572
|
-
}
|
|
573
|
-
return { ok: true, group: "inbox", command };
|
|
574
|
-
}
|
|
575
|
-
export {
|
|
576
|
-
readPendingInboxCounts,
|
|
577
|
-
listInboxRecords,
|
|
578
|
-
executeInbox
|
|
579
|
-
};
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { type RunnerContext } from "../runner";
|
|
2
|
-
import { buildRigInitConfigSource, type RigInitConfigInput } from "@rig/core";
|
|
3
|
-
import type { CommandOutcome } from "@rig/runtime";
|
|
4
|
-
export { buildRigInitConfigSource };
|
|
5
|
-
export type { RigInitConfigInput };
|
|
6
|
-
type InitAuthMethod = "gh" | "token" | "device" | "skip";
|
|
7
|
-
type InitControlPlaneOptions = {
|
|
8
|
-
demo?: boolean;
|
|
9
|
-
repoSlug?: string;
|
|
10
|
-
githubToken?: string;
|
|
11
|
-
githubAuthMethod?: InitAuthMethod;
|
|
12
|
-
githubProject?: "off" | string;
|
|
13
|
-
githubProjectStatusField?: string;
|
|
14
|
-
githubProjectStatuses?: Record<string, string>;
|
|
15
|
-
yes?: boolean;
|
|
16
|
-
repair?: boolean;
|
|
17
|
-
privateStateOnly?: boolean;
|
|
18
|
-
server?: "local" | "remote";
|
|
19
|
-
remoteAlias?: string;
|
|
20
|
-
remoteHost?: string;
|
|
21
|
-
remotePort?: number;
|
|
22
|
-
remoteCheckout?: string;
|
|
23
|
-
};
|
|
24
|
-
type InitPromptAdapter = {
|
|
25
|
-
intro?: (message: string) => void;
|
|
26
|
-
outro?: (message: string) => void;
|
|
27
|
-
cancel?: (message: string) => void;
|
|
28
|
-
isCancel: (value: unknown) => boolean;
|
|
29
|
-
text: (options: {
|
|
30
|
-
message: string;
|
|
31
|
-
placeholder?: string;
|
|
32
|
-
initialValue?: string;
|
|
33
|
-
defaultValue?: string;
|
|
34
|
-
}) => Promise<unknown>;
|
|
35
|
-
select: (options: {
|
|
36
|
-
message: string;
|
|
37
|
-
options: Array<{
|
|
38
|
-
value: string;
|
|
39
|
-
label: string;
|
|
40
|
-
hint?: string;
|
|
41
|
-
}>;
|
|
42
|
-
initialValue?: string;
|
|
43
|
-
}) => Promise<unknown>;
|
|
44
|
-
confirm?: (options: {
|
|
45
|
-
message: string;
|
|
46
|
-
initialValue?: boolean;
|
|
47
|
-
}) => Promise<unknown>;
|
|
48
|
-
};
|
|
49
|
-
export declare const DEMO_TASKS_RELATIVE_DIR = ".rig/demo-tasks";
|
|
50
|
-
/**
|
|
51
|
-
* The three sample tasks `rig init --demo` seeds. Shapes match what the
|
|
52
|
-
* standard plugin's files task source reads: one JSON object per file with
|
|
53
|
-
* id/title/body/status/labels (see packages/standard-plugin/src/files-source.ts).
|
|
54
|
-
*/
|
|
55
|
-
export declare const DEMO_TASKS: ReadonlyArray<Record<string, unknown>>;
|
|
56
|
-
/**
|
|
57
|
-
* `rig init --demo` — zero-GitHub, offline demo project: files task source
|
|
58
|
-
* pointing at .rig/demo-tasks/ with three seeded sample tasks, so an
|
|
59
|
-
* operator can see the full run lifecycle in minutes. Non-interactive and
|
|
60
|
-
* idempotent: an existing rig.config is left untouched unless --repair.
|
|
61
|
-
*/
|
|
62
|
-
export declare function runDemoInit(context: RunnerContext, options: InitControlPlaneOptions): CommandOutcome;
|
|
63
|
-
export declare function runInteractiveControlPlaneInit(context: RunnerContext, prompts: InitPromptAdapter): Promise<CommandOutcome>;
|
|
64
|
-
export declare function executeInit(context: RunnerContext, args: string[]): Promise<CommandOutcome>;
|