@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.
Files changed (38) hide show
  1. package/dist/bin/rig.js +1038 -620
  2. package/dist/src/commands/_cli-format.js +211 -6
  3. package/dist/src/commands/_connection-state.js +1 -1
  4. package/dist/src/commands/_doctor-checks.js +3 -3
  5. package/dist/src/commands/_help-catalog.js +225 -64
  6. package/dist/src/commands/_operator-view.js +1 -1
  7. package/dist/src/commands/_pi-frontend.js +1 -1
  8. package/dist/src/commands/_pi-worker-bridge-extension.js +1 -1
  9. package/dist/src/commands/_preflight.js +2 -2
  10. package/dist/src/commands/_server-client.js +1 -1
  11. package/dist/src/commands/_snapshot-upload.js +1 -1
  12. package/dist/src/commands/agent.js +7 -7
  13. package/dist/src/commands/browser.js +4 -4
  14. package/dist/src/commands/connect.js +5 -4
  15. package/dist/src/commands/dist.js +4 -4
  16. package/dist/src/commands/doctor.js +3 -3
  17. package/dist/src/commands/github.js +1 -1
  18. package/dist/src/commands/inbox.js +351 -29
  19. package/dist/src/commands/init.js +3 -3
  20. package/dist/src/commands/inspect.js +10 -10
  21. package/dist/src/commands/inspector.js +2 -2
  22. package/dist/src/commands/plugin.js +3 -3
  23. package/dist/src/commands/profile-and-review.js +8 -8
  24. package/dist/src/commands/queue.js +1 -1
  25. package/dist/src/commands/remote.js +18 -18
  26. package/dist/src/commands/repo-git-harness.js +4 -4
  27. package/dist/src/commands/run.js +157 -37
  28. package/dist/src/commands/server.js +6 -5
  29. package/dist/src/commands/setup.js +8 -8
  30. package/dist/src/commands/task-report-bug.js +5 -5
  31. package/dist/src/commands/task-run-driver.js +1 -1
  32. package/dist/src/commands/task.js +451 -45
  33. package/dist/src/commands/test.js +3 -3
  34. package/dist/src/commands/workspace.js +4 -4
  35. package/dist/src/commands.js +1038 -620
  36. package/dist/src/index.js +1038 -620
  37. package/dist/src/report-bug.js +3 -3
  38. 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, "bun run rig profile show");
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: bun run rig profile set <claude-code|codex-cli|pi> or set [--model ...] [--runtime ...] [--plugin ...]");
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: bun run rig profile set <claude-code|codex-cli|pi>");
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, "bun run rig profile set [--model ...] [--runtime ...] [--plugin ...]");
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, "bun run rig review show");
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: bun run rig review set <off|advisory|required> [--provider greptile]");
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: bun run rig review set <off|advisory|required> [--provider greptile]");
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, "bun run rig review set <off|advisory|required> [--provider greptile]");
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, "bun run rig queue run [--workers <n>] [--max-tasks <n>] [--action validate|verify|pipeline] [--isolation off|worktree] [--no-runtime-reuse] [--fail-fast] [--skip-project-sync]");
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, "bun run rig remote endpoint list");
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, "bun run rig remote endpoint add --alias <a> --host <h> --port <n> --token <t>");
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, "bun run rig remote endpoint update --id <id> [--alias <a>] [--host <h>] [--port <n>] [--token <t>]");
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, "bun run rig remote endpoint remove --alias <a>");
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, "bun run rig remote endpoint test --alias <a>");
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, "bun run rig remote endpoint migrate");
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, "bun run rig remote endpoint doctor");
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, "bun run rig remote test [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]");
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, "bun run rig remote status [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]");
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, "bun run rig remote tasks [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]");
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, "bun run rig remote watch [--seconds <n>] [--event <type>] [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]");
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, `bun run rig remote ${command} [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]`);
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, `bun run rig remote ${command} --count <n> [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]`);
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, `bun run rig remote ${command} --task <id> [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]`);
444
- const taskId = requireTask(taskResult.value, `bun run rig remote ${command} --task <id>`);
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, "bun run rig remote orchestrate-start [--max-workers <n>] [--max-iterations <n>] [--direct-merge]");
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, `bun run rig remote ${command} --id <orch-id> [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]`);
479
- const orchestrationId = requireTask(idResult.value, `bun run rig remote ${command} --id <orch-id> [--remote <alias>] [--host <host>] [--port <n>] [--token <token>]`);
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, "bun run rig repo sync [--task <beads-id>]");
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, "bun run rig repo reset-baseline [--keep-task-status]");
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: bun run rig git <git-flow args...>");
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: bun run rig harness <harness args...>");
198
+ throw new CliError2("Usage: rig harness <harness args...>");
199
199
  }
200
200
  await enforceNativeCommandPolicy(context, args, {
201
201
  commandPrefix: "rig-agent",
@@ -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 connection "${repo.selected}" was not found. Run \`rig connect list\` or \`rig connect use local\`.`, 1);
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 --run <run-id>`"])].join(`
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, "bun run rig run list");
1510
+ requireNoExtraArgs(rest, "rig run list");
1386
1511
  const { runs, source } = await listRunsForSelectedConnection(context, { limit: 100 });
1387
1512
  if (context.outputMode === "text") {
1388
- console.log(formatRunList(runs, { source }));
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, "bun run rig run delete --run <id> [--purge-artifacts]");
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, "bun run rig run cleanup --all [--keep-artifacts] [--keep-runtimes] [--keep-queue]");
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
- requireNoExtraArgs(pending, "bun run rig run show --run <id>");
1450
- if (!run.value) {
1451
- throw new CliError2("run show requires --run <id>.");
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, run.value) ?? normalizeRemoteRunDetails(await getRunDetailsViaServer(context, run.value).catch(() => ({})));
1583
+ const record = readAuthorityRun(context.projectRoot, runId) ?? normalizeRemoteRunDetails(await getRunDetailsViaServer(context, runId).catch(() => ({})));
1454
1584
  if (!record) {
1455
- throw new CliError2(`Run not found: ${run.value}`, 2);
1585
+ throw new CliError2(`Run not found: ${runId}`, 2);
1456
1586
  }
1457
1587
  if (context.outputMode === "text") {
1458
- console.log(JSON.stringify(record, null, 2));
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, "bun run rig run timeline --run <id> [--follow]");
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, "bun run rig run attach <run-id>|--run <run-id> [--message <text>] [--once|--follow] [--poll-ms <ms>]");
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, "bun run rig run status");
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
- console.log(`Active runs: ${activeRuns.length}`);
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, "bun run rig run start [--epic <id>] [--prompt-epic|--no-epic-prompt] [--ws-port <n>] [--server-host <host>] [--server-port <n>] [--poll-ms <n>] [--no-server]");
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, "bun run rig run resume");
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, "bun run rig run restart");
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, "bun run rig run stop [<run-id>|--run <id>]");
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 connection "${repo.selected}" was not found. Run \`rig connect list\` or \`rig connect use local\`.`, 1);
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(9))} ${value}`);
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
  }