@h-rig/cli 0.0.6-alpha.27 → 0.0.6-alpha.28
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/dist/bin/rig.js +1038 -620
- package/dist/src/commands/_cli-format.js +211 -6
- package/dist/src/commands/_connection-state.js +1 -1
- package/dist/src/commands/_doctor-checks.js +3 -3
- package/dist/src/commands/_help-catalog.js +225 -64
- package/dist/src/commands/_operator-view.js +1 -1
- package/dist/src/commands/_pi-frontend.js +1 -1
- package/dist/src/commands/_pi-worker-bridge-extension.js +1 -1
- package/dist/src/commands/_preflight.js +2 -2
- package/dist/src/commands/_server-client.js +1 -1
- package/dist/src/commands/_snapshot-upload.js +1 -1
- package/dist/src/commands/agent.js +7 -7
- package/dist/src/commands/browser.js +4 -4
- package/dist/src/commands/connect.js +5 -4
- package/dist/src/commands/dist.js +4 -4
- package/dist/src/commands/doctor.js +3 -3
- package/dist/src/commands/github.js +1 -1
- package/dist/src/commands/inbox.js +351 -29
- package/dist/src/commands/init.js +3 -3
- package/dist/src/commands/inspect.js +10 -10
- package/dist/src/commands/inspector.js +2 -2
- package/dist/src/commands/plugin.js +3 -3
- package/dist/src/commands/profile-and-review.js +8 -8
- package/dist/src/commands/queue.js +1 -1
- package/dist/src/commands/remote.js +18 -18
- package/dist/src/commands/repo-git-harness.js +4 -4
- package/dist/src/commands/run.js +157 -37
- package/dist/src/commands/server.js +6 -5
- package/dist/src/commands/setup.js +8 -8
- package/dist/src/commands/task-report-bug.js +5 -5
- package/dist/src/commands/task-run-driver.js +1 -1
- package/dist/src/commands/task.js +451 -45
- package/dist/src/commands/test.js +3 -3
- package/dist/src/commands/workspace.js +4 -4
- package/dist/src/commands.js +1038 -620
- package/dist/src/index.js +1038 -620
- package/dist/src/report-bug.js +3 -3
- package/package.json +6 -6
|
@@ -86,17 +86,17 @@ async function executeProfile(context, args) {
|
|
|
86
86
|
const [command = "show", ...rest] = args;
|
|
87
87
|
switch (command) {
|
|
88
88
|
case "show":
|
|
89
|
-
requireNoExtraArgs(rest, "
|
|
89
|
+
requireNoExtraArgs(rest, "rig profile show");
|
|
90
90
|
await withMutedConsole(context.outputMode === "json", () => showProfile(context.projectRoot));
|
|
91
91
|
return { ok: true, group: "profile", command };
|
|
92
92
|
case "set": {
|
|
93
93
|
if (rest.length === 0) {
|
|
94
|
-
throw new CliError2("Usage:
|
|
94
|
+
throw new CliError2("Usage: rig profile set <claude-code|codex-cli|pi> or set [--model ...] [--runtime ...] [--plugin ...]");
|
|
95
95
|
}
|
|
96
96
|
const preset = rest[0];
|
|
97
97
|
if (preset && !preset.startsWith("-")) {
|
|
98
98
|
if (rest.length !== 1) {
|
|
99
|
-
throw new CliError2("Usage:
|
|
99
|
+
throw new CliError2("Usage: rig profile set <claude-code|codex-cli|pi>");
|
|
100
100
|
}
|
|
101
101
|
try {
|
|
102
102
|
await withMutedConsole(context.outputMode === "json", () => setProfile(context.projectRoot, { preset }));
|
|
@@ -112,7 +112,7 @@ async function executeProfile(context, args) {
|
|
|
112
112
|
pending = runtimeResult.rest;
|
|
113
113
|
const pluginResult = takeOption(pending, "--plugin");
|
|
114
114
|
pending = pluginResult.rest;
|
|
115
|
-
requireNoExtraArgs(pending, "
|
|
115
|
+
requireNoExtraArgs(pending, "rig profile set [--model ...] [--runtime ...] [--plugin ...]");
|
|
116
116
|
if (!modelResult.value && !runtimeResult.value && !pluginResult.value) {
|
|
117
117
|
throw new CliError2("Provide at least one of --model, --runtime, or --plugin.");
|
|
118
118
|
}
|
|
@@ -144,21 +144,21 @@ async function executeReview(context, args) {
|
|
|
144
144
|
const [command = "show", ...rest] = args;
|
|
145
145
|
switch (command) {
|
|
146
146
|
case "show":
|
|
147
|
-
requireNoExtraArgs(rest, "
|
|
147
|
+
requireNoExtraArgs(rest, "rig review show");
|
|
148
148
|
await withMutedConsole(context.outputMode === "json", () => showReviewProfile(context.projectRoot));
|
|
149
149
|
return { ok: true, group: "review", command };
|
|
150
150
|
case "set": {
|
|
151
151
|
if (rest.length === 0) {
|
|
152
|
-
throw new CliError2("Usage:
|
|
152
|
+
throw new CliError2("Usage: rig review set <off|advisory|required> [--provider greptile]");
|
|
153
153
|
}
|
|
154
154
|
const mode = rest[0];
|
|
155
155
|
if (!mode) {
|
|
156
|
-
throw new CliError2("Usage:
|
|
156
|
+
throw new CliError2("Usage: rig review set <off|advisory|required> [--provider greptile]");
|
|
157
157
|
}
|
|
158
158
|
let pending = rest.slice(1);
|
|
159
159
|
const providerResult = takeOption(pending, "--provider");
|
|
160
160
|
pending = providerResult.rest;
|
|
161
|
-
requireNoExtraArgs(pending, "
|
|
161
|
+
requireNoExtraArgs(pending, "rig review set <off|advisory|required> [--provider greptile]");
|
|
162
162
|
try {
|
|
163
163
|
await withMutedConsole(context.outputMode === "json", () => {
|
|
164
164
|
return setReviewProfile(context.projectRoot, mode, providerResult.value);
|
|
@@ -151,7 +151,7 @@ async function executeQueue(context, args) {
|
|
|
151
151
|
pending = failFastResult.rest;
|
|
152
152
|
const skipProjectSyncResult = takeFlag(pending, "--skip-project-sync");
|
|
153
153
|
pending = skipProjectSyncResult.rest;
|
|
154
|
-
requireNoExtraArgs(pending, "
|
|
154
|
+
requireNoExtraArgs(pending, "rig queue run [--workers <n>] [--max-tasks <n>] [--action validate|verify|pipeline] [--isolation off|worktree] [--no-runtime-reuse] [--fail-fast] [--skip-project-sync]");
|
|
155
155
|
const workers = parsePositiveInt(workersResult.value, "--workers", 2);
|
|
156
156
|
const maxTasks = parsePositiveInt(maxTasksResult.value, "--max-tasks", 10);
|
|
157
157
|
const action = parseAction(actionResult.value);
|
|
@@ -134,7 +134,7 @@ async function executeRemote(context, args) {
|
|
|
134
134
|
const [subcommand = "list", ...subRest] = rest;
|
|
135
135
|
switch (subcommand) {
|
|
136
136
|
case "list": {
|
|
137
|
-
requireNoExtraArgs(subRest, "
|
|
137
|
+
requireNoExtraArgs(subRest, "rig remote endpoint list");
|
|
138
138
|
const endpoints = listManagedRemoteEndpoints(undefined, context.projectRoot);
|
|
139
139
|
const redactedEndpoints = endpoints.map((endpoint2) => redactRemoteEndpoint(endpoint2));
|
|
140
140
|
if (context.outputMode === "text") {
|
|
@@ -158,7 +158,7 @@ async function executeRemote(context, args) {
|
|
|
158
158
|
pending2 = port.rest;
|
|
159
159
|
const token = takeOption(pending2, "--token");
|
|
160
160
|
pending2 = token.rest;
|
|
161
|
-
requireNoExtraArgs(pending2, "
|
|
161
|
+
requireNoExtraArgs(pending2, "rig remote endpoint add --alias <a> --host <h> --port <n> --token <t>");
|
|
162
162
|
if (!alias.value || !host.value || !token.value || !port.value) {
|
|
163
163
|
throw new CliError2("remote endpoint add requires --alias, --host, --port, and --token.");
|
|
164
164
|
}
|
|
@@ -185,7 +185,7 @@ async function executeRemote(context, args) {
|
|
|
185
185
|
pending2 = port.rest;
|
|
186
186
|
const token = takeOption(pending2, "--token");
|
|
187
187
|
pending2 = token.rest;
|
|
188
|
-
requireNoExtraArgs(pending2, "
|
|
188
|
+
requireNoExtraArgs(pending2, "rig remote endpoint update --id <id> [--alias <a>] [--host <h>] [--port <n>] [--token <t>]");
|
|
189
189
|
if (!endpointId.value && !alias.value) {
|
|
190
190
|
throw new CliError2("remote endpoint update requires --id <id> or --alias <a>.");
|
|
191
191
|
}
|
|
@@ -208,7 +208,7 @@ async function executeRemote(context, args) {
|
|
|
208
208
|
let pending2 = subRest;
|
|
209
209
|
const alias = takeOption(pending2, "--alias");
|
|
210
210
|
pending2 = alias.rest;
|
|
211
|
-
requireNoExtraArgs(pending2, "
|
|
211
|
+
requireNoExtraArgs(pending2, "rig remote endpoint remove --alias <a>");
|
|
212
212
|
if (!alias.value) {
|
|
213
213
|
throw new CliError2("remote endpoint remove requires --alias.");
|
|
214
214
|
}
|
|
@@ -225,7 +225,7 @@ async function executeRemote(context, args) {
|
|
|
225
225
|
let pending2 = subRest;
|
|
226
226
|
const alias = takeOption(pending2, "--alias");
|
|
227
227
|
pending2 = alias.rest;
|
|
228
|
-
requireNoExtraArgs(pending2, "
|
|
228
|
+
requireNoExtraArgs(pending2, "rig remote endpoint test --alias <a>");
|
|
229
229
|
if (!alias.value) {
|
|
230
230
|
throw new CliError2("remote endpoint test requires --alias.");
|
|
231
231
|
}
|
|
@@ -256,7 +256,7 @@ async function executeRemote(context, args) {
|
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
258
|
case "migrate": {
|
|
259
|
-
requireNoExtraArgs(subRest, "
|
|
259
|
+
requireNoExtraArgs(subRest, "rig remote endpoint migrate");
|
|
260
260
|
const result = migrateManagedRemoteEndpoints(context.projectRoot);
|
|
261
261
|
if (context.outputMode === "text") {
|
|
262
262
|
console.log(`Imported ${result.imported} endpoint(s) from ${result.sourcePath}${result.skipped > 0 ? `, skipped ${result.skipped}` : ""}.`);
|
|
@@ -264,7 +264,7 @@ async function executeRemote(context, args) {
|
|
|
264
264
|
return { ok: true, group: "remote", command: "endpoint migrate", details: result };
|
|
265
265
|
}
|
|
266
266
|
case "doctor": {
|
|
267
|
-
requireNoExtraArgs(subRest, "
|
|
267
|
+
requireNoExtraArgs(subRest, "rig remote endpoint doctor");
|
|
268
268
|
const result = doctorManagedRemoteEndpoints(context.projectRoot);
|
|
269
269
|
if (context.outputMode === "text") {
|
|
270
270
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -317,17 +317,17 @@ async function executeRemote(context, args) {
|
|
|
317
317
|
try {
|
|
318
318
|
switch (command) {
|
|
319
319
|
case "test": {
|
|
320
|
-
requireNoExtraArgs(pending, "
|
|
320
|
+
requireNoExtraArgs(pending, "rig remote test [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]");
|
|
321
321
|
const response = await withClient((client) => client.ping());
|
|
322
322
|
return { ok: true, group: "remote", command, details: toDetails(response) };
|
|
323
323
|
}
|
|
324
324
|
case "status": {
|
|
325
|
-
requireNoExtraArgs(pending, "
|
|
325
|
+
requireNoExtraArgs(pending, "rig remote status [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]");
|
|
326
326
|
const response = await withClient((client) => client.getState());
|
|
327
327
|
return { ok: true, group: "remote", command, details: toDetails(response) };
|
|
328
328
|
}
|
|
329
329
|
case "tasks": {
|
|
330
|
-
requireNoExtraArgs(pending, "
|
|
330
|
+
requireNoExtraArgs(pending, "rig remote tasks [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]");
|
|
331
331
|
const response = await withClient((client) => client.getTasks());
|
|
332
332
|
return { ok: true, group: "remote", command, details: toDetails(response) };
|
|
333
333
|
}
|
|
@@ -337,7 +337,7 @@ async function executeRemote(context, args) {
|
|
|
337
337
|
watchPending = secondsResult.rest;
|
|
338
338
|
const eventResult = takeOption(watchPending, "--event");
|
|
339
339
|
watchPending = eventResult.rest;
|
|
340
|
-
requireNoExtraArgs(watchPending, "
|
|
340
|
+
requireNoExtraArgs(watchPending, "rig remote watch [--seconds <n>] [--event <type>] [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]");
|
|
341
341
|
const seconds = parseOptionalPositiveInt(secondsResult.value, "--seconds");
|
|
342
342
|
const eventFilter = eventResult.value || undefined;
|
|
343
343
|
if (context.outputMode === "json" && !seconds) {
|
|
@@ -406,7 +406,7 @@ async function executeRemote(context, args) {
|
|
|
406
406
|
case "stop":
|
|
407
407
|
case "continue":
|
|
408
408
|
case "refresh": {
|
|
409
|
-
requireNoExtraArgs(pending, `
|
|
409
|
+
requireNoExtraArgs(pending, `rig remote ${command} [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]`);
|
|
410
410
|
const response = await withClient(async (client) => {
|
|
411
411
|
switch (command) {
|
|
412
412
|
case "pause":
|
|
@@ -429,7 +429,7 @@ async function executeRemote(context, args) {
|
|
|
429
429
|
let countPending = pending;
|
|
430
430
|
const countResult = takeOption(countPending, "--count");
|
|
431
431
|
countPending = countResult.rest;
|
|
432
|
-
requireNoExtraArgs(countPending, `
|
|
432
|
+
requireNoExtraArgs(countPending, `rig remote ${command} --count <n> [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]`);
|
|
433
433
|
const count = parseRequiredPositiveInt(countResult.value, "--count");
|
|
434
434
|
const response = await withClient(async (client) => command === "add-iterations" ? await client.addIterations(count) : await client.removeIterations(count));
|
|
435
435
|
assertRemoteOperationSuccess(command, response);
|
|
@@ -440,8 +440,8 @@ async function executeRemote(context, args) {
|
|
|
440
440
|
let taskPending = pending;
|
|
441
441
|
const taskResult = takeOption(taskPending, "--task");
|
|
442
442
|
taskPending = taskResult.rest;
|
|
443
|
-
requireNoExtraArgs(taskPending, `
|
|
444
|
-
const taskId = requireTask(taskResult.value, `
|
|
443
|
+
requireNoExtraArgs(taskPending, `rig remote ${command} --task <id> [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]`);
|
|
444
|
+
const taskId = requireTask(taskResult.value, `rig remote ${command} --task <id>`);
|
|
445
445
|
const response = await withClient(async (client) => command === "prompt-preview" ? await client.getPromptPreview(taskId) : await client.getIterationOutput(taskId));
|
|
446
446
|
assertRemoteOperationSuccess(command, response);
|
|
447
447
|
return { ok: true, group: "remote", command, details: toDetails(response) };
|
|
@@ -454,7 +454,7 @@ async function executeRemote(context, args) {
|
|
|
454
454
|
orchestrationPending = maxIterationsResult.rest;
|
|
455
455
|
const directMergeResult = takeFlag(orchestrationPending, "--direct-merge");
|
|
456
456
|
orchestrationPending = directMergeResult.rest;
|
|
457
|
-
requireNoExtraArgs(orchestrationPending, "
|
|
457
|
+
requireNoExtraArgs(orchestrationPending, "rig remote orchestrate-start [--max-workers <n>] [--max-iterations <n>] [--direct-merge]");
|
|
458
458
|
const response = await withClient((client) => client.startOrchestration({
|
|
459
459
|
maxWorkers: parseOptionalPositiveInt(maxWorkersResult.value, "--max-workers"),
|
|
460
460
|
maxIterations: parseOptionalPositiveInt(maxIterationsResult.value, "--max-iterations"),
|
|
@@ -475,8 +475,8 @@ async function executeRemote(context, args) {
|
|
|
475
475
|
let orchestrationPending = pending;
|
|
476
476
|
const idResult = takeOption(orchestrationPending, "--id");
|
|
477
477
|
orchestrationPending = idResult.rest;
|
|
478
|
-
requireNoExtraArgs(orchestrationPending, `
|
|
479
|
-
const orchestrationId = requireTask(idResult.value, `
|
|
478
|
+
requireNoExtraArgs(orchestrationPending, `rig remote ${command} --id <orch-id> [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]`);
|
|
479
|
+
const orchestrationId = requireTask(idResult.value, `rig remote ${command} --id <orch-id> [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]`);
|
|
480
480
|
const response = await withClient(async (client) => {
|
|
481
481
|
switch (command) {
|
|
482
482
|
case "orchestrate-pause":
|
|
@@ -158,13 +158,13 @@ async function executeRepo(context, args) {
|
|
|
158
158
|
switch (command) {
|
|
159
159
|
case "sync": {
|
|
160
160
|
const { value: task, rest: remaining } = takeOption(rest, "--task");
|
|
161
|
-
requireNoExtraArgs(remaining, "
|
|
161
|
+
requireNoExtraArgs(remaining, "rig repo sync [--task <task-id>]");
|
|
162
162
|
withMutedConsole(context.outputMode === "json", () => repoEnsure(context.projectRoot, task || undefined));
|
|
163
163
|
return { ok: true, group: "repo", command, details: { task: task || null } };
|
|
164
164
|
}
|
|
165
165
|
case "reset-baseline": {
|
|
166
166
|
const { value: keepTaskStatusFlag, rest: remaining } = takeFlag(rest, "--keep-task-status");
|
|
167
|
-
requireNoExtraArgs(remaining, "
|
|
167
|
+
requireNoExtraArgs(remaining, "rig repo reset-baseline [--keep-task-status]");
|
|
168
168
|
withMutedConsole(context.outputMode === "json", () => resetBaseline(context.projectRoot, keepTaskStatusFlag));
|
|
169
169
|
return { ok: true, group: "repo", command, details: { keepTaskStatus: keepTaskStatusFlag } };
|
|
170
170
|
}
|
|
@@ -174,7 +174,7 @@ async function executeRepo(context, args) {
|
|
|
174
174
|
}
|
|
175
175
|
async function executeGit(context, args) {
|
|
176
176
|
if (args.length === 0) {
|
|
177
|
-
throw new CliError2("Usage:
|
|
177
|
+
throw new CliError2("Usage: rig git <git-flow args...>");
|
|
178
178
|
}
|
|
179
179
|
await enforceNativeCommandPolicy(context, args, {
|
|
180
180
|
commandPrefix: "rig-agent git",
|
|
@@ -195,7 +195,7 @@ async function executeGit(context, args) {
|
|
|
195
195
|
}
|
|
196
196
|
async function executeHarness(context, args) {
|
|
197
197
|
if (args.length === 0) {
|
|
198
|
-
throw new CliError2("Usage:
|
|
198
|
+
throw new CliError2("Usage: rig harness <harness args...>");
|
|
199
199
|
}
|
|
200
200
|
await enforceNativeCommandPolicy(context, args, {
|
|
201
201
|
commandPrefix: "rig-agent",
|
package/dist/src/commands/run.js
CHANGED
|
@@ -162,7 +162,7 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
162
162
|
const global = readGlobalConnections(options);
|
|
163
163
|
const connection = global.connections[repo.selected];
|
|
164
164
|
if (!connection) {
|
|
165
|
-
throw new CliError2(`Selected Rig
|
|
165
|
+
throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
166
166
|
}
|
|
167
167
|
return { alias: repo.selected, connection };
|
|
168
168
|
}
|
|
@@ -1219,11 +1219,16 @@ async function attachRunOperatorView(context, input) {
|
|
|
1219
1219
|
}
|
|
1220
1220
|
|
|
1221
1221
|
// packages/cli/src/commands/_cli-format.ts
|
|
1222
|
+
import { log, note } from "@clack/prompts";
|
|
1222
1223
|
import pc from "picocolors";
|
|
1223
1224
|
function stringField(record, key, fallback = "") {
|
|
1224
1225
|
const value = record[key];
|
|
1225
1226
|
return typeof value === "string" && value.trim() ? value.trim() : fallback;
|
|
1226
1227
|
}
|
|
1228
|
+
function rawObject(record) {
|
|
1229
|
+
const raw = record.raw;
|
|
1230
|
+
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
1231
|
+
}
|
|
1227
1232
|
function truncate(value, width) {
|
|
1228
1233
|
if (value.length <= width)
|
|
1229
1234
|
return value;
|
|
@@ -1236,19 +1241,66 @@ function pad(value, width) {
|
|
|
1236
1241
|
}
|
|
1237
1242
|
function statusColor(status) {
|
|
1238
1243
|
const normalized = status.toLowerCase();
|
|
1239
|
-
if (["completed", "merged", "closed", "done", "accepted", "pass", "selected"].includes(normalized))
|
|
1244
|
+
if (["completed", "merged", "closed", "done", "accepted", "pass", "selected", "approved"].includes(normalized))
|
|
1240
1245
|
return pc.green;
|
|
1241
|
-
if (["failed", "needs_attention", "needs-attention", "blocked", "error"].includes(normalized))
|
|
1246
|
+
if (["failed", "needs_attention", "needs-attention", "blocked", "error", "rejected"].includes(normalized))
|
|
1242
1247
|
return pc.red;
|
|
1243
1248
|
if (["running", "reviewing", "validating", "in_progress", "in-progress", "remote"].includes(normalized))
|
|
1244
1249
|
return pc.cyan;
|
|
1245
|
-
if (["ready", "open", "queued", "created", "preparing", "local"].includes(normalized))
|
|
1250
|
+
if (["ready", "open", "queued", "created", "preparing", "local", "pending"].includes(normalized))
|
|
1246
1251
|
return pc.yellow;
|
|
1247
1252
|
return pc.dim;
|
|
1248
1253
|
}
|
|
1254
|
+
function compactDate(value) {
|
|
1255
|
+
if (!value.trim())
|
|
1256
|
+
return "";
|
|
1257
|
+
const parsed = Date.parse(value);
|
|
1258
|
+
if (!Number.isFinite(parsed))
|
|
1259
|
+
return value;
|
|
1260
|
+
return new Date(parsed).toISOString().replace("T", " ").replace(/\.\d{3}Z$/, "Z");
|
|
1261
|
+
}
|
|
1262
|
+
function firstString(record, keys, fallback = "") {
|
|
1263
|
+
for (const key of keys) {
|
|
1264
|
+
const value = stringField(record, key);
|
|
1265
|
+
if (value)
|
|
1266
|
+
return value;
|
|
1267
|
+
}
|
|
1268
|
+
return fallback;
|
|
1269
|
+
}
|
|
1270
|
+
function runIdOf(run) {
|
|
1271
|
+
return firstString(run, ["runId", "id"], "(unknown-run)");
|
|
1272
|
+
}
|
|
1273
|
+
function taskIdOf(run) {
|
|
1274
|
+
return firstString(run, ["taskId", "task", "task_id"]);
|
|
1275
|
+
}
|
|
1276
|
+
function runTitleOf(run) {
|
|
1277
|
+
return firstString(run, ["title", "summary", "name"], taskIdOf(run) || "(untitled)");
|
|
1278
|
+
}
|
|
1279
|
+
function shouldUseClackOutput() {
|
|
1280
|
+
return Boolean(process.stdout.isTTY) && process.env.RIG_CLI_PLAIN_HELP !== "1";
|
|
1281
|
+
}
|
|
1282
|
+
function printFormattedOutput(message, options = {}) {
|
|
1283
|
+
if (!shouldUseClackOutput()) {
|
|
1284
|
+
console.log(message);
|
|
1285
|
+
return;
|
|
1286
|
+
}
|
|
1287
|
+
if (options.title)
|
|
1288
|
+
note(message, options.title);
|
|
1289
|
+
else
|
|
1290
|
+
log.message(message);
|
|
1291
|
+
}
|
|
1292
|
+
function formatStatusPill(status) {
|
|
1293
|
+
const label = status || "unknown";
|
|
1294
|
+
return statusColor(label)(`\u25CF ${label}`);
|
|
1295
|
+
}
|
|
1249
1296
|
function formatSection(title, subtitle) {
|
|
1250
1297
|
return `${pc.bold(pc.cyan("\u25C6"))} ${pc.bold(title)}${subtitle ? pc.dim(` \u2014 ${subtitle}`) : ""}`;
|
|
1251
1298
|
}
|
|
1299
|
+
function formatSuccessCard(title, rows = []) {
|
|
1300
|
+
const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${pc.dim("\u2502")} ${pc.dim(key.padEnd(12))} ${value}`);
|
|
1301
|
+
return [formatSection(title), ...body].join(`
|
|
1302
|
+
`);
|
|
1303
|
+
}
|
|
1252
1304
|
function formatNextSteps(steps) {
|
|
1253
1305
|
if (steps.length === 0)
|
|
1254
1306
|
return [];
|
|
@@ -1280,9 +1332,85 @@ function formatRunList(runs, options = {}) {
|
|
|
1280
1332
|
statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
|
|
1281
1333
|
`${row.title}${row.runtime ? pc.dim(` ${row.runtime}`) : ""}`
|
|
1282
1334
|
].join(" "));
|
|
1283
|
-
return [formatSection("Runs", options.source === "server" ? "selected server" : "local state"), header, ...body, "", ...formatNextSteps(["Follow live: `rig run attach <run-id> --follow`", "Details: `rig run show
|
|
1335
|
+
return [formatSection("Runs", options.source === "server" ? "selected server" : "local state"), header, ...body, "", ...formatNextSteps(["Follow live: `rig run attach <run-id> --follow`", "Details: `rig run show <run-id>`"])].join(`
|
|
1336
|
+
`);
|
|
1337
|
+
}
|
|
1338
|
+
function formatRunCard(run, options = {}) {
|
|
1339
|
+
const raw = rawObject(run);
|
|
1340
|
+
const merged = { ...raw, ...run };
|
|
1341
|
+
const runId = runIdOf(merged);
|
|
1342
|
+
const status = firstString(merged, ["status"], "unknown");
|
|
1343
|
+
const taskId = taskIdOf(merged);
|
|
1344
|
+
const title = runTitleOf(merged);
|
|
1345
|
+
const runtime = firstString(merged, ["runtimeAdapter", "runtime", "adapter"]);
|
|
1346
|
+
const mode = firstString(merged, ["runtimeMode", "mode"]);
|
|
1347
|
+
const interaction = firstString(merged, ["interactionMode"]);
|
|
1348
|
+
const created = compactDate(firstString(merged, ["createdAt"]));
|
|
1349
|
+
const started = compactDate(firstString(merged, ["startedAt"]));
|
|
1350
|
+
const updated = compactDate(firstString(merged, ["updatedAt"]));
|
|
1351
|
+
const completed = compactDate(firstString(merged, ["completedAt", "finishedAt"]));
|
|
1352
|
+
const worktree = firstString(merged, ["worktreePath", "cwd", "projectRoot"]);
|
|
1353
|
+
const piSession = merged.piSession && typeof merged.piSession === "object" && !Array.isArray(merged.piSession) ? firstString(merged.piSession, ["sessionId", "id"]) : "";
|
|
1354
|
+
const timeline = Array.isArray(merged.timeline) ? merged.timeline.length : null;
|
|
1355
|
+
const approvals = Array.isArray(merged.approvals) ? merged.approvals.length : null;
|
|
1356
|
+
const inputs = Array.isArray(merged.userInputs) ? merged.userInputs.length : null;
|
|
1357
|
+
const rows = [
|
|
1358
|
+
["run", pc.bold(runId)],
|
|
1359
|
+
["status", formatStatusPill(status)],
|
|
1360
|
+
["task", taskId],
|
|
1361
|
+
["title", title],
|
|
1362
|
+
["runtime", [runtime, mode, interaction].filter(Boolean).join(" \xB7 ")],
|
|
1363
|
+
["created", created],
|
|
1364
|
+
["started", started],
|
|
1365
|
+
["updated", updated],
|
|
1366
|
+
["completed", completed],
|
|
1367
|
+
["worktree", worktree],
|
|
1368
|
+
["pi", piSession],
|
|
1369
|
+
["timeline", timeline],
|
|
1370
|
+
["approvals", approvals],
|
|
1371
|
+
["inputs", inputs]
|
|
1372
|
+
];
|
|
1373
|
+
return [
|
|
1374
|
+
formatSuccessCard(options.title ?? "Run details", rows),
|
|
1375
|
+
"",
|
|
1376
|
+
...formatNextSteps([`Follow live: \`rig run attach ${runId} --follow\``, `Raw payload: \`rig run show ${runId} --raw\``])
|
|
1377
|
+
].join(`
|
|
1378
|
+
`);
|
|
1379
|
+
}
|
|
1380
|
+
function formatRunStatus(summary, options = {}) {
|
|
1381
|
+
const activeRuns = summary.activeRuns ?? [];
|
|
1382
|
+
const recentRuns = summary.recentRuns ?? [];
|
|
1383
|
+
const lines = [formatSection("Run status", options.source === "server" ? "selected server" : "local state")];
|
|
1384
|
+
lines.push("", pc.bold(`Active runs (${activeRuns.length})`));
|
|
1385
|
+
if (activeRuns.length === 0) {
|
|
1386
|
+
lines.push(pc.dim("No active runs."));
|
|
1387
|
+
} else {
|
|
1388
|
+
for (const run of activeRuns) {
|
|
1389
|
+
lines.push(formatRunSummaryLine(run));
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
lines.push("", pc.bold(`Recent runs (${recentRuns.length})`));
|
|
1393
|
+
if (recentRuns.length === 0) {
|
|
1394
|
+
lines.push(pc.dim("No recent terminal runs."));
|
|
1395
|
+
} else {
|
|
1396
|
+
for (const run of recentRuns.slice(0, 10)) {
|
|
1397
|
+
lines.push(formatRunSummaryLine(run));
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
lines.push("", ...formatNextSteps(["Start work: `rig task run --next`", "Attach: `rig run attach <run-id> --follow`", "Details: `rig run show <run-id>`"]));
|
|
1401
|
+
return lines.join(`
|
|
1284
1402
|
`);
|
|
1285
1403
|
}
|
|
1404
|
+
function formatRunSummaryLine(run) {
|
|
1405
|
+
const record = run;
|
|
1406
|
+
const runId = runIdOf(record);
|
|
1407
|
+
const status = firstString(record, ["status"], "unknown");
|
|
1408
|
+
const taskId = taskIdOf(record);
|
|
1409
|
+
const title = runTitleOf(record);
|
|
1410
|
+
const runtime = firstString(record, ["runtimeAdapter", "runtime", "adapter"]);
|
|
1411
|
+
const descriptor = [taskId, title].filter(Boolean).join(" \xB7 ");
|
|
1412
|
+
return `${pc.dim("\u2502")} ${pc.bold(runId)} ${formatStatusPill(status)} ${descriptor}${runtime ? pc.dim(` ${runtime}`) : ""}`;
|
|
1413
|
+
}
|
|
1286
1414
|
|
|
1287
1415
|
// packages/cli/src/commands/run.ts
|
|
1288
1416
|
function normalizeRemoteRunDetails(payload) {
|
|
@@ -1310,9 +1438,6 @@ function runStringField(run, key, fallback = "") {
|
|
|
1310
1438
|
const value = run[key];
|
|
1311
1439
|
return typeof value === "string" && value.trim() ? value : fallback;
|
|
1312
1440
|
}
|
|
1313
|
-
function runDisplayTitle(run) {
|
|
1314
|
-
return runStringField(run, "title", runStringField(run, "taskId", "(untitled)"));
|
|
1315
|
-
}
|
|
1316
1441
|
function buildServerRunStatus(runs) {
|
|
1317
1442
|
const activeRuns = runs.filter((run) => !REMOTE_TERMINAL_RUN_STATUSES.has(runStringField(run, "status").toLowerCase()));
|
|
1318
1443
|
const recentRuns = runs.filter((run) => REMOTE_TERMINAL_RUN_STATUSES.has(runStringField(run, "status").toLowerCase()));
|
|
@@ -1382,10 +1507,10 @@ async function executeRun(context, args) {
|
|
|
1382
1507
|
const runtimeContext = loadRuntimeContextFromEnv2() ?? undefined;
|
|
1383
1508
|
switch (command) {
|
|
1384
1509
|
case "list": {
|
|
1385
|
-
requireNoExtraArgs(rest, "
|
|
1510
|
+
requireNoExtraArgs(rest, "rig run list");
|
|
1386
1511
|
const { runs, source } = await listRunsForSelectedConnection(context, { limit: 100 });
|
|
1387
1512
|
if (context.outputMode === "text") {
|
|
1388
|
-
|
|
1513
|
+
printFormattedOutput(formatRunList(runs, { source }));
|
|
1389
1514
|
}
|
|
1390
1515
|
return { ok: true, group: "run", command, details: { runs, source } };
|
|
1391
1516
|
}
|
|
@@ -1395,7 +1520,7 @@ async function executeRun(context, args) {
|
|
|
1395
1520
|
pending = run.rest;
|
|
1396
1521
|
const purgeArtifacts = takeFlag(pending, "--purge-artifacts");
|
|
1397
1522
|
pending = purgeArtifacts.rest;
|
|
1398
|
-
requireNoExtraArgs(pending, "
|
|
1523
|
+
requireNoExtraArgs(pending, "rig run delete --run <id> [--purge-artifacts]");
|
|
1399
1524
|
if (!run.value) {
|
|
1400
1525
|
throw new CliError2("run delete requires --run <id>.");
|
|
1401
1526
|
}
|
|
@@ -1425,7 +1550,7 @@ async function executeRun(context, args) {
|
|
|
1425
1550
|
pending = keepRuntimes.rest;
|
|
1426
1551
|
const keepQueue = takeFlag(pending, "--keep-queue");
|
|
1427
1552
|
pending = keepQueue.rest;
|
|
1428
|
-
requireNoExtraArgs(pending, "
|
|
1553
|
+
requireNoExtraArgs(pending, "rig run cleanup --all [--keep-artifacts] [--keep-runtimes] [--keep-queue]");
|
|
1429
1554
|
if (!all.value) {
|
|
1430
1555
|
throw new CliError2("run cleanup currently requires --all.");
|
|
1431
1556
|
}
|
|
@@ -1444,20 +1569,25 @@ async function executeRun(context, args) {
|
|
|
1444
1569
|
}
|
|
1445
1570
|
case "show": {
|
|
1446
1571
|
let pending = rest;
|
|
1572
|
+
const rawResult = takeFlag(pending, "--raw");
|
|
1573
|
+
pending = rawResult.rest;
|
|
1447
1574
|
const run = takeOption(pending, "--run");
|
|
1448
1575
|
pending = run.rest;
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1576
|
+
const positionalRunId = pending.length > 0 && pending[0] && !pending[0].startsWith("-") ? pending[0] : undefined;
|
|
1577
|
+
const extra = positionalRunId ? pending.slice(1) : pending;
|
|
1578
|
+
requireNoExtraArgs(extra, "rig run show <id>|--run <id> [--raw]");
|
|
1579
|
+
const runId = run.value ?? positionalRunId;
|
|
1580
|
+
if (!runId) {
|
|
1581
|
+
throw new CliError2("run show requires a run id.");
|
|
1452
1582
|
}
|
|
1453
|
-
const record = readAuthorityRun(context.projectRoot,
|
|
1583
|
+
const record = readAuthorityRun(context.projectRoot, runId) ?? normalizeRemoteRunDetails(await getRunDetailsViaServer(context, runId).catch(() => ({})));
|
|
1454
1584
|
if (!record) {
|
|
1455
|
-
throw new CliError2(`Run not found: ${
|
|
1585
|
+
throw new CliError2(`Run not found: ${runId}`, 2);
|
|
1456
1586
|
}
|
|
1457
1587
|
if (context.outputMode === "text") {
|
|
1458
|
-
|
|
1588
|
+
printFormattedOutput(rawResult.value ? JSON.stringify(record, null, 2) : formatRunCard(record));
|
|
1459
1589
|
}
|
|
1460
|
-
return { ok: true, group: "run", command, details: record };
|
|
1590
|
+
return { ok: true, group: "run", command, details: { ...record, rawOutput: rawResult.value } };
|
|
1461
1591
|
}
|
|
1462
1592
|
case "timeline": {
|
|
1463
1593
|
let pending = rest;
|
|
@@ -1465,7 +1595,7 @@ async function executeRun(context, args) {
|
|
|
1465
1595
|
pending = run.rest;
|
|
1466
1596
|
const follow = takeFlag(pending, "--follow");
|
|
1467
1597
|
pending = follow.rest;
|
|
1468
|
-
requireNoExtraArgs(pending, "
|
|
1598
|
+
requireNoExtraArgs(pending, "rig run timeline --run <id> [--follow]");
|
|
1469
1599
|
if (!run.value) {
|
|
1470
1600
|
throw new CliError2("run timeline requires --run <id>.");
|
|
1471
1601
|
}
|
|
@@ -1502,7 +1632,7 @@ async function executeRun(context, args) {
|
|
|
1502
1632
|
pending = pollMs.rest;
|
|
1503
1633
|
const positionalRunId = pending.length > 0 ? pending[0] : undefined;
|
|
1504
1634
|
const extra = positionalRunId ? pending.slice(1) : pending;
|
|
1505
|
-
requireNoExtraArgs(extra, "
|
|
1635
|
+
requireNoExtraArgs(extra, "rig run attach <run-id>|--run <run-id> [--message <text>] [--once|--follow] [--poll-ms <ms>]");
|
|
1506
1636
|
const runId = runOption.value ?? positionalRunId;
|
|
1507
1637
|
if (!runId) {
|
|
1508
1638
|
throw new CliError2("run attach requires a run id.", 2);
|
|
@@ -1522,7 +1652,7 @@ async function executeRun(context, args) {
|
|
|
1522
1652
|
return { ok: true, group: "run", command, details: { ...attached, steered: attached.steered || steered } };
|
|
1523
1653
|
}
|
|
1524
1654
|
case "status": {
|
|
1525
|
-
requireNoExtraArgs(rest, "
|
|
1655
|
+
requireNoExtraArgs(rest, "rig run status");
|
|
1526
1656
|
if (context.dryRun) {
|
|
1527
1657
|
if (context.outputMode === "text") {
|
|
1528
1658
|
console.log("[dry-run] rig run status");
|
|
@@ -1533,17 +1663,7 @@ async function executeRun(context, args) {
|
|
|
1533
1663
|
const activeRuns = Array.isArray(summary.activeRuns) ? summary.activeRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
|
|
1534
1664
|
const recentRuns = Array.isArray(summary.recentRuns) ? summary.recentRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
|
|
1535
1665
|
if (context.outputMode === "text") {
|
|
1536
|
-
|
|
1537
|
-
for (const run of activeRuns) {
|
|
1538
|
-
console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runStringField(run, "taskId", runDisplayTitle(run))}`);
|
|
1539
|
-
}
|
|
1540
|
-
if (recentRuns.length > 0) {
|
|
1541
|
-
console.log("");
|
|
1542
|
-
console.log("Recent runs:");
|
|
1543
|
-
for (const run of recentRuns) {
|
|
1544
|
-
console.log(`- ${runStringField(run, "runId", "(unknown-run)")} \xB7 ${runStringField(run, "status", "unknown")} \xB7 ${runStringField(run, "taskId", runDisplayTitle(run))}`);
|
|
1545
|
-
}
|
|
1546
|
-
}
|
|
1666
|
+
printFormattedOutput(formatRunStatus({ activeRuns, recentRuns, runs: Array.isArray(summary.runs) ? summary.runs : [...activeRuns, ...recentRuns] }, { source: isRemoteConnectionSelected(context.projectRoot) ? "server" : "local" }));
|
|
1547
1667
|
}
|
|
1548
1668
|
return { ok: true, group: "run", command, details: summary };
|
|
1549
1669
|
}
|
|
@@ -1567,7 +1687,7 @@ async function executeRun(context, args) {
|
|
|
1567
1687
|
pending = pollResult.rest;
|
|
1568
1688
|
const noServerResult = takeFlag(pending, "--no-server");
|
|
1569
1689
|
pending = noServerResult.rest;
|
|
1570
|
-
requireNoExtraArgs(pending, "
|
|
1690
|
+
requireNoExtraArgs(pending, "rig run start [--epic <id>] [--prompt-epic|--no-epic-prompt] [--ws-port <n>] [--server-host <host>] [--server-port <n>] [--poll-ms <n>] [--no-server]");
|
|
1571
1691
|
if (promptEpicResult.value && noEpicPromptResult.value) {
|
|
1572
1692
|
throw new CliError2("Cannot use --prompt-epic and --no-epic-prompt together.");
|
|
1573
1693
|
}
|
|
@@ -1615,7 +1735,7 @@ async function executeRun(context, args) {
|
|
|
1615
1735
|
};
|
|
1616
1736
|
}
|
|
1617
1737
|
case "resume": {
|
|
1618
|
-
requireNoExtraArgs(rest, "
|
|
1738
|
+
requireNoExtraArgs(rest, "rig run resume");
|
|
1619
1739
|
if (context.dryRun) {
|
|
1620
1740
|
if (context.outputMode === "text") {
|
|
1621
1741
|
console.log("[dry-run] rig run resume");
|
|
@@ -1629,7 +1749,7 @@ async function executeRun(context, args) {
|
|
|
1629
1749
|
return { ok: true, group: "run", command, details: resumed };
|
|
1630
1750
|
}
|
|
1631
1751
|
case "restart": {
|
|
1632
|
-
requireNoExtraArgs(rest, "
|
|
1752
|
+
requireNoExtraArgs(rest, "rig run restart");
|
|
1633
1753
|
if (context.dryRun) {
|
|
1634
1754
|
if (context.outputMode === "text") {
|
|
1635
1755
|
console.log("[dry-run] rig run restart");
|
|
@@ -1646,7 +1766,7 @@ async function executeRun(context, args) {
|
|
|
1646
1766
|
const runOption = takeOption(rest, "--run");
|
|
1647
1767
|
const positionalRunId = runOption.rest.length > 0 ? runOption.rest[0] : undefined;
|
|
1648
1768
|
const extra = positionalRunId ? runOption.rest.slice(1) : runOption.rest;
|
|
1649
|
-
requireNoExtraArgs(extra, "
|
|
1769
|
+
requireNoExtraArgs(extra, "rig run stop [<run-id>|--run <id>]");
|
|
1650
1770
|
const runId = runOption.value ?? positionalRunId;
|
|
1651
1771
|
if (context.dryRun) {
|
|
1652
1772
|
return {
|
|
@@ -160,12 +160,13 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
160
160
|
const global = readGlobalConnections(options);
|
|
161
161
|
const connection = global.connections[repo.selected];
|
|
162
162
|
if (!connection) {
|
|
163
|
-
throw new CliError2(`Selected Rig
|
|
163
|
+
throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
164
164
|
}
|
|
165
165
|
return { alias: repo.selected, connection };
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
// packages/cli/src/commands/_cli-format.ts
|
|
169
|
+
import { log, note } from "@clack/prompts";
|
|
169
170
|
import pc from "picocolors";
|
|
170
171
|
function truncate(value, width) {
|
|
171
172
|
if (value.length <= width)
|
|
@@ -179,13 +180,13 @@ function pad(value, width) {
|
|
|
179
180
|
}
|
|
180
181
|
function statusColor(status) {
|
|
181
182
|
const normalized = status.toLowerCase();
|
|
182
|
-
if (["completed", "merged", "closed", "done", "accepted", "pass", "selected"].includes(normalized))
|
|
183
|
+
if (["completed", "merged", "closed", "done", "accepted", "pass", "selected", "approved"].includes(normalized))
|
|
183
184
|
return pc.green;
|
|
184
|
-
if (["failed", "needs_attention", "needs-attention", "blocked", "error"].includes(normalized))
|
|
185
|
+
if (["failed", "needs_attention", "needs-attention", "blocked", "error", "rejected"].includes(normalized))
|
|
185
186
|
return pc.red;
|
|
186
187
|
if (["running", "reviewing", "validating", "in_progress", "in-progress", "remote"].includes(normalized))
|
|
187
188
|
return pc.cyan;
|
|
188
|
-
if (["ready", "open", "queued", "created", "preparing", "local"].includes(normalized))
|
|
189
|
+
if (["ready", "open", "queued", "created", "preparing", "local", "pending"].includes(normalized))
|
|
189
190
|
return pc.yellow;
|
|
190
191
|
return pc.dim;
|
|
191
192
|
}
|
|
@@ -197,7 +198,7 @@ function formatSection(title, subtitle) {
|
|
|
197
198
|
return `${pc.bold(pc.cyan("\u25C6"))} ${pc.bold(title)}${subtitle ? pc.dim(` \u2014 ${subtitle}`) : ""}`;
|
|
198
199
|
}
|
|
199
200
|
function formatSuccessCard(title, rows = []) {
|
|
200
|
-
const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${pc.dim("\u2502")} ${pc.dim(key.padEnd(
|
|
201
|
+
const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${pc.dim("\u2502")} ${pc.dim(key.padEnd(12))} ${value}`);
|
|
201
202
|
return [formatSection(title), ...body].join(`
|
|
202
203
|
`);
|
|
203
204
|
}
|