@h-rig/cli 0.0.6-alpha.66 → 0.0.6-alpha.68

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.
@@ -213,6 +213,15 @@ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
213
213
  import { resolve as resolve2 } from "path";
214
214
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
215
215
  var scopedGitHubBearerTokens = new Map;
216
+ var serverPhaseListener = null;
217
+ function setServerPhaseListener(listener) {
218
+ const previous = serverPhaseListener;
219
+ serverPhaseListener = listener;
220
+ return previous;
221
+ }
222
+ function reportServerPhase(label) {
223
+ serverPhaseListener?.(label);
224
+ }
216
225
  function cleanToken(value) {
217
226
  const trimmed = value?.trim();
218
227
  return trimmed ? trimmed : null;
@@ -255,6 +264,7 @@ async function ensureServerForCli(projectRoot) {
255
264
  try {
256
265
  const selected = resolveSelectedConnection(projectRoot);
257
266
  if (selected?.connection.kind === "remote") {
267
+ reportServerPhase(`Connecting to ${selected.alias}\u2026`);
258
268
  const authToken = readGitHubBearerTokenForRemote(projectRoot);
259
269
  const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
260
270
  return {
@@ -264,6 +274,7 @@ async function ensureServerForCli(projectRoot) {
264
274
  serverProjectRoot
265
275
  };
266
276
  }
277
+ reportServerPhase("Starting local Rig server\u2026");
267
278
  const connection = await ensureLocalRigServerConnection(projectRoot);
268
279
  return {
269
280
  baseUrl: connection.baseUrl,
@@ -380,6 +391,7 @@ async function requestServerJson(context, pathname, init = {}) {
380
391
  const headers = mergeHeaders(init.headers, server.authToken);
381
392
  if (server.serverProjectRoot)
382
393
  headers.set("x-rig-project-root", server.serverProjectRoot);
394
+ reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
383
395
  let response;
384
396
  try {
385
397
  response = await fetch(`${server.baseUrl}${pathname}`, {
@@ -1025,6 +1037,127 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
1025
1037
  return Number.isFinite(index) ? tasks[index] ?? null : null;
1026
1038
  }
1027
1039
 
1040
+ // packages/cli/src/commands/_async-ui.ts
1041
+ import pc from "picocolors";
1042
+
1043
+ // packages/cli/src/commands/_spinner.ts
1044
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1045
+ function createTtySpinner(input) {
1046
+ const output = input.output ?? process.stdout;
1047
+ const isTty = output.isTTY === true;
1048
+ const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
1049
+ let label = input.label;
1050
+ let frame = 0;
1051
+ let paused = false;
1052
+ let stopped = false;
1053
+ let lastPrintedLabel = "";
1054
+ const render = () => {
1055
+ if (stopped || paused)
1056
+ return;
1057
+ if (!isTty) {
1058
+ if (label !== lastPrintedLabel) {
1059
+ output.write(`${label}
1060
+ `);
1061
+ lastPrintedLabel = label;
1062
+ }
1063
+ return;
1064
+ }
1065
+ frame = (frame + 1) % frames.length;
1066
+ const glyph = frames[frame] ?? frames[0] ?? "";
1067
+ output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
1068
+ };
1069
+ const clearLine = () => {
1070
+ if (isTty)
1071
+ output.write("\r\x1B[2K");
1072
+ };
1073
+ render();
1074
+ const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
1075
+ return {
1076
+ setLabel(next) {
1077
+ label = next;
1078
+ render();
1079
+ },
1080
+ pause() {
1081
+ paused = true;
1082
+ clearLine();
1083
+ },
1084
+ resume() {
1085
+ if (stopped)
1086
+ return;
1087
+ paused = false;
1088
+ render();
1089
+ },
1090
+ stop(finalLine) {
1091
+ if (stopped)
1092
+ return;
1093
+ stopped = true;
1094
+ if (timer)
1095
+ clearInterval(timer);
1096
+ clearLine();
1097
+ if (finalLine)
1098
+ output.write(`${finalLine}
1099
+ `);
1100
+ }
1101
+ };
1102
+ }
1103
+
1104
+ // packages/cli/src/commands/_async-ui.ts
1105
+ var CLACK_SPINNER_FRAMES = ["\u25D2", "\u25D0", "\u25D3", "\u25D1"];
1106
+ var DONE_SYMBOL = pc.green("\u25C7");
1107
+ var FAIL_SYMBOL = pc.red("\u25A0");
1108
+ var activeUpdate = null;
1109
+ async function withSpinner(label, work, options = {}) {
1110
+ if (options.outputMode === "json") {
1111
+ return work(() => {});
1112
+ }
1113
+ if (activeUpdate) {
1114
+ const outer = activeUpdate;
1115
+ outer(label);
1116
+ return work(outer);
1117
+ }
1118
+ const output = options.output ?? process.stderr;
1119
+ const isTty = output.isTTY === true;
1120
+ let lastLabel = label;
1121
+ if (!isTty) {
1122
+ output.write(`${label}
1123
+ `);
1124
+ const update2 = (next) => {
1125
+ lastLabel = next;
1126
+ };
1127
+ activeUpdate = update2;
1128
+ const previousListener2 = setServerPhaseListener(update2);
1129
+ try {
1130
+ return await work(update2);
1131
+ } finally {
1132
+ activeUpdate = null;
1133
+ setServerPhaseListener(previousListener2);
1134
+ }
1135
+ }
1136
+ const spinner = createTtySpinner({
1137
+ label,
1138
+ output,
1139
+ frames: CLACK_SPINNER_FRAMES,
1140
+ styleFrame: (frame) => pc.magenta(frame)
1141
+ });
1142
+ const update = (next) => {
1143
+ lastLabel = next;
1144
+ spinner.setLabel(next);
1145
+ };
1146
+ activeUpdate = update;
1147
+ const previousListener = setServerPhaseListener(update);
1148
+ try {
1149
+ const result = await work(update);
1150
+ spinner.stop(options.doneLabel ? `${DONE_SYMBOL} ${options.doneLabel}` : undefined);
1151
+ return result;
1152
+ } catch (error) {
1153
+ spinner.stop(`${FAIL_SYMBOL} ${lastLabel}`);
1154
+ throw error;
1155
+ } finally {
1156
+ activeUpdate = null;
1157
+ setServerPhaseListener(previousListener);
1158
+ }
1159
+ }
1160
+
1028
1161
  // packages/cli/src/commands/_pi-frontend.ts
1029
1162
  import { mkdtempSync, rmSync } from "fs";
1030
1163
  import { tmpdir } from "os";
@@ -1072,7 +1205,12 @@ async function attachRunBundledPiFrontend(context, input) {
1072
1205
  };
1073
1206
  let detached = false;
1074
1207
  try {
1075
- await runPiMain([], {
1208
+ await runPiMain([
1209
+ "--no-extensions",
1210
+ "--no-skills",
1211
+ "--no-prompt-templates",
1212
+ "--no-context-files"
1213
+ ], {
1076
1214
  extensionFactories: [piRigExtensionFactory]
1077
1215
  });
1078
1216
  detached = true;
@@ -1137,8 +1275,9 @@ async function readOperatorSnapshot(context, runId, options = {}) {
1137
1275
  }
1138
1276
  async function attachRunOperatorView(context, input) {
1139
1277
  let steered = false;
1140
- if (input.message?.trim()) {
1141
- await sendRunPiPromptViaServer(context, input.runId, input.message.trim(), "steer").catch(() => steerRunViaServer(context, input.runId, input.message.trim()));
1278
+ const attachMessage = input.message?.trim();
1279
+ if (attachMessage) {
1280
+ await withSpinner("Queueing steering message\u2026", () => sendRunPiPromptViaServer(context, input.runId, attachMessage, "steer").catch(() => steerRunViaServer(context, input.runId, attachMessage)), { outputMode: context.outputMode });
1142
1281
  steered = true;
1143
1282
  }
1144
1283
  if (input.follow && !input.once && input.interactive !== false && context.outputMode === "text" && Boolean(process.stdin.isTTY && process.stdout.isTTY)) {
@@ -1148,7 +1287,7 @@ async function attachRunOperatorView(context, input) {
1148
1287
  });
1149
1288
  }
1150
1289
  const surface = createOperatorSurface({ interactive: input.interactive !== false });
1151
- let snapshot = await readOperatorSnapshot(context, input.runId);
1290
+ let snapshot = await withSpinner(`Connecting to run ${input.runId}\u2026`, () => readOperatorSnapshot(context, input.runId), { outputMode: context.outputMode });
1152
1291
  if (context.outputMode === "text") {
1153
1292
  surface.renderSnapshot(snapshot);
1154
1293
  surface.renderTimeline(snapshot.timeline);
@@ -1188,7 +1327,7 @@ async function attachRunOperatorView(context, input) {
1188
1327
 
1189
1328
  // packages/cli/src/commands/_cli-format.ts
1190
1329
  import { log, note } from "@clack/prompts";
1191
- import pc from "picocolors";
1330
+ import pc2 from "picocolors";
1192
1331
  function stringField(record, key, fallback = "") {
1193
1332
  const value = record[key];
1194
1333
  return typeof value === "string" && value.trim() ? value.trim() : fallback;
@@ -1218,14 +1357,14 @@ function pad(value, width) {
1218
1357
  function statusColor(status) {
1219
1358
  const normalized = status.toLowerCase();
1220
1359
  if (["completed", "merged", "closed", "done", "accepted", "pass", "selected", "approved"].includes(normalized))
1221
- return pc.green;
1360
+ return pc2.green;
1222
1361
  if (["failed", "needs_attention", "needs-attention", "blocked", "error", "rejected"].includes(normalized))
1223
- return pc.red;
1362
+ return pc2.red;
1224
1363
  if (["running", "reviewing", "validating", "in_progress", "in-progress", "remote"].includes(normalized))
1225
- return pc.cyan;
1364
+ return pc2.cyan;
1226
1365
  if (["ready", "open", "queued", "created", "preparing", "local", "pending"].includes(normalized))
1227
- return pc.yellow;
1228
- return pc.dim;
1366
+ return pc2.yellow;
1367
+ return pc2.dim;
1229
1368
  }
1230
1369
  function compactValue(value) {
1231
1370
  if (value === null || value === undefined)
@@ -1256,17 +1395,17 @@ function formatStatusPill(status) {
1256
1395
  return statusColor(label)(`\u25CF ${label}`);
1257
1396
  }
1258
1397
  function formatSection(title, subtitle) {
1259
- return `${pc.bold(pc.cyan("\u25C6"))} ${pc.bold(title)}${subtitle ? pc.dim(` \u2014 ${subtitle}`) : ""}`;
1398
+ return `${pc2.bold(pc2.cyan("\u25C6"))} ${pc2.bold(title)}${subtitle ? pc2.dim(` \u2014 ${subtitle}`) : ""}`;
1260
1399
  }
1261
1400
  function formatSuccessCard(title, rows = []) {
1262
- 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}`);
1401
+ const body = rows.filter(([, value]) => value !== undefined && value !== null && String(value).length > 0).map(([key, value]) => `${pc2.dim("\u2502")} ${pc2.dim(key.padEnd(12))} ${value}`);
1263
1402
  return [formatSection(title), ...body].join(`
1264
1403
  `);
1265
1404
  }
1266
1405
  function formatNextSteps(steps) {
1267
1406
  if (steps.length === 0)
1268
1407
  return [];
1269
- return [pc.bold("Next"), ...steps.map((step) => `${pc.dim("\u203A")} ${step}`)];
1408
+ return [pc2.bold("Next"), ...steps.map((step) => `${pc2.dim("\u203A")} ${step}`)];
1270
1409
  }
1271
1410
  function formatTaskList(tasks, options = {}) {
1272
1411
  if (options.raw)
@@ -1286,12 +1425,12 @@ function formatTaskList(tasks, options = {}) {
1286
1425
  });
1287
1426
  const idWidth = Math.min(18, Math.max(4, ...rows.map((row) => row.id.length)));
1288
1427
  const statusWidth = Math.min(16, Math.max(6, ...rows.map((row) => row.status.length)));
1289
- const header = `${pc.bold(pad("TASK", idWidth))} ${pc.bold(pad("STATUS", statusWidth))} ${pc.bold("TITLE")}`;
1428
+ const header = `${pc2.bold(pad("TASK", idWidth))} ${pc2.bold(pad("STATUS", statusWidth))} ${pc2.bold("TITLE")}`;
1290
1429
  const body = rows.map((row) => {
1291
- const labels = row.labels.length > 0 ? pc.dim(` ${row.labels.slice(0, 4).map((label) => `#${label}`).join(" ")}`) : "";
1292
- const source = row.source ? pc.dim(` ${row.source}`) : "";
1430
+ const labels = row.labels.length > 0 ? pc2.dim(` ${row.labels.slice(0, 4).map((label) => `#${label}`).join(" ")}`) : "";
1431
+ const source = row.source ? pc2.dim(` ${row.source}`) : "";
1293
1432
  return [
1294
- pc.bold(pad(truncate(row.id, idWidth), idWidth)),
1433
+ pc2.bold(pad(truncate(row.id, idWidth), idWidth)),
1295
1434
  statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
1296
1435
  `${row.title}${labels}${source}`
1297
1436
  ].join(" ");
@@ -1312,7 +1451,7 @@ function formatTaskCard(task, options = {}) {
1312
1451
  const readiness = compactValue(task.readiness ?? raw.readiness);
1313
1452
  const validators = compactValue(task.validators ?? raw.validators ?? task.validation ?? raw.validation);
1314
1453
  const rows = [
1315
- ["task", pc.bold(id)],
1454
+ ["task", pc2.bold(id)],
1316
1455
  ["status", formatStatusPill(status)],
1317
1456
  ["title", title],
1318
1457
  ["source", source],
@@ -1334,12 +1473,12 @@ function formatTaskDetails(task) {
1334
1473
  return formatTaskCard(task, { title: "Task details" });
1335
1474
  }
1336
1475
  function formatSubmittedRun(input) {
1337
- const rows = [["run", pc.bold(input.runId)]];
1476
+ const rows = [["run", pc2.bold(input.runId)]];
1338
1477
  if (input.task) {
1339
1478
  const id = stringField(input.task, "id", "<unknown>");
1340
1479
  const status = stringField(input.task, "status", "unknown");
1341
1480
  const title = stringField(input.task, "title", "Untitled task");
1342
- rows.push(["task", `${pc.bold(id)} ${formatStatusPill(status)} ${title}`]);
1481
+ rows.push(["task", `${pc2.bold(id)} ${formatStatusPill(status)} ${title}`]);
1343
1482
  }
1344
1483
  const runtime = [input.runtimeAdapter || "pi", input.runtimeMode || "full-access", input.interactionMode || "default"].filter(Boolean).join(" \xB7 ");
1345
1484
  rows.push(["runtime", runtime]);
@@ -1395,7 +1534,7 @@ async function printPendingInboxFooter(context) {
1395
1534
 
1396
1535
  // packages/cli/src/commands/_help-catalog.ts
1397
1536
  import { intro, log as log2, note as note2, outro } from "@clack/prompts";
1398
- import pc2 from "picocolors";
1537
+ import pc3 from "picocolors";
1399
1538
  var TOP_LEVEL_SECTIONS = [
1400
1539
  {
1401
1540
  title: "Start here",
@@ -1677,13 +1816,13 @@ var ADVANCED_GROUPS = [
1677
1816
  ];
1678
1817
  var ALL_GROUPS = [...PRIMARY_GROUPS, ...ADVANCED_GROUPS];
1679
1818
  function heading(title) {
1680
- return pc2.bold(pc2.cyan(title));
1819
+ return pc3.bold(pc3.cyan(title));
1681
1820
  }
1682
1821
  function renderRigBanner(version) {
1683
- const m = (s) => pc2.bold(pc2.magenta(s));
1684
- const c = (s) => pc2.bold(pc2.cyan(s));
1685
- const y = (s) => pc2.yellow(s);
1686
- const d = (s) => pc2.dim(s);
1822
+ const m = (s) => pc3.bold(pc3.magenta(s));
1823
+ const c = (s) => pc3.bold(pc3.cyan(s));
1824
+ const y = (s) => pc3.yellow(s);
1825
+ const d = (s) => pc3.dim(s);
1687
1826
  const lines = [
1688
1827
  m(" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ") + d(" \u2591\u2592\u2593\u2588 "),
1689
1828
  m(" \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D ") + d("\u2593\u2592\u2591"),
@@ -1692,7 +1831,7 @@ function renderRigBanner(version) {
1692
1831
  y(" \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D") + d(" \u2592\u2591"),
1693
1832
  y(" \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D "),
1694
1833
  "",
1695
- ` ${c("\u25E2\u25E4")} ${pc2.bold("the control rig for autonomous coding agents")} ${m("//")} ${d("you are the operator")}`,
1834
+ ` ${c("\u25E2\u25E4")} ${pc3.bold("the control rig for autonomous coding agents")} ${m("//")} ${d("you are the operator")}`,
1696
1835
  version ? ` ${d(`v${version} \xB7 jack in: rig task run --next`)}` : ` ${d("jack in: rig task run --next")}`
1697
1836
  ];
1698
1837
  return lines.join(`
@@ -1700,7 +1839,7 @@ function renderRigBanner(version) {
1700
1839
  }
1701
1840
  function commandLine(command, description) {
1702
1841
  const commandColumn = command.length >= 38 ? `${command} ` : command.padEnd(38);
1703
- return `${pc2.dim("\u2502")} ${pc2.bold(commandColumn)} ${description}`;
1842
+ return `${pc3.dim("\u2502")} ${pc3.bold(commandColumn)} ${description}`;
1704
1843
  }
1705
1844
  function renderCommandBlock(commands) {
1706
1845
  return commands.map((entry) => commandLine(entry.command, entry.description)).join(`
@@ -1710,37 +1849,37 @@ function renderGroup(group) {
1710
1849
  const lines = [
1711
1850
  `${heading(`rig ${group.name}`)} \u2014 ${group.summary}`,
1712
1851
  "",
1713
- pc2.bold("Usage"),
1852
+ pc3.bold("Usage"),
1714
1853
  ...group.usage.map((line) => ` ${line}`),
1715
1854
  "",
1716
- pc2.bold("Commands"),
1855
+ pc3.bold("Commands"),
1717
1856
  ...group.commands.map((entry) => commandLine(entry.command, entry.description))
1718
1857
  ];
1719
1858
  if (group.examples?.length) {
1720
- lines.push("", pc2.bold("Examples"), ...group.examples.map((line) => ` ${pc2.dim("$")} ${line}`));
1859
+ lines.push("", pc3.bold("Examples"), ...group.examples.map((line) => ` ${pc3.dim("$")} ${line}`));
1721
1860
  }
1722
1861
  if (group.next?.length) {
1723
- lines.push("", pc2.bold("Next steps"), ...group.next.map((line) => ` ${pc2.dim("\u203A")} ${line}`));
1862
+ lines.push("", pc3.bold("Next steps"), ...group.next.map((line) => ` ${pc3.dim("\u203A")} ${line}`));
1724
1863
  }
1725
1864
  if (group.advanced?.length) {
1726
- lines.push("", pc2.bold("Compatibility / advanced"), ...group.advanced.map((line) => ` ${pc2.dim("\u203A")} ${line}`));
1865
+ lines.push("", pc3.bold("Compatibility / advanced"), ...group.advanced.map((line) => ` ${pc3.dim("\u203A")} ${line}`));
1727
1866
  }
1728
1867
  return lines.join(`
1729
1868
  `);
1730
1869
  }
1731
1870
  function renderTopLevelHelp() {
1732
1871
  return [
1733
- `${heading("rig")} ${pc2.dim("\u2014 server-owned task/run control plane for Pi-backed engineering work")}`,
1734
- pc2.dim("Current path: select a server, choose a task, submit a run, attach with native Pi, clear inbox gates."),
1872
+ `${heading("rig")} ${pc3.dim("\u2014 server-owned task/run control plane for Pi-backed engineering work")}`,
1873
+ pc3.dim("Current path: select a server, choose a task, submit a run, attach with native Pi, clear inbox gates."),
1735
1874
  "",
1736
1875
  ...TOP_LEVEL_SECTIONS.flatMap((section) => [
1737
- `${pc2.bold(pc2.magenta(`\u25C7 ${section.title}`))} \u2014 ${pc2.dim(section.subtitle)}`,
1876
+ `${pc3.bold(pc3.magenta(`\u25C7 ${section.title}`))} \u2014 ${pc3.dim(section.subtitle)}`,
1738
1877
  renderCommandBlock(section.commands),
1739
1878
  ""
1740
1879
  ]),
1741
- pc2.dim("More: `rig help --advanced` for dev/compatibility commands; `rig <group> --help` for rich per-group help; `rig --version` for the installed version."),
1880
+ pc3.dim("More: `rig help --advanced` for dev/compatibility commands; `rig <group> --help` for rich per-group help; `rig --version` for the installed version."),
1742
1881
  "",
1743
- pc2.bold("Global options"),
1882
+ pc3.bold("Global options"),
1744
1883
  commandLine("--project <path>", "Use a project root instead of auto-discovery."),
1745
1884
  commandLine("--json", "Emit structured output for scripts/agents."),
1746
1885
  commandLine("--dry-run", "Print the command plan without mutating state.")
@@ -1979,7 +2118,7 @@ async function executeTask(context, args, options) {
1979
2118
  pending = rawResult.rest;
1980
2119
  const { filters, rest: remaining } = parseTaskFilters(pending);
1981
2120
  requireNoExtraArgs(remaining, "rig task list [--raw] [--assignee <login|me|@me>] [--state open|closed] [--status <status>] [--limit <n>]");
1982
- const tasks = await listWorkspaceTasksViaServer(context, filters);
2121
+ const tasks = await withSpinner("Reading tasks from server\u2026", () => listWorkspaceTasksViaServer(context, filters), { outputMode: context.outputMode });
1983
2122
  if (context.outputMode === "text") {
1984
2123
  const renderedTasks = rawResult.value ? tasks.map((task) => summarizeTask(task, { raw: true })) : tasks.map((task) => summarizeTask(task));
1985
2124
  printFormattedOutput(formatTaskList(renderedTasks, { raw: rawResult.value }));
@@ -2003,7 +2142,7 @@ async function executeTask(context, args, options) {
2003
2142
  const taskId3 = normalizeTaskRunTaskId(taskOption.value ?? positional);
2004
2143
  if (!taskId3)
2005
2144
  throw new CliError("task show requires a task id.", 2, { hint: "Run `rig task list` to find ids, then `rig task show <id>`." });
2006
- const task = await getWorkspaceTaskViaServer(context, taskId3);
2145
+ const task = await withSpinner(`Reading task ${taskId3} from server\u2026`, () => getWorkspaceTaskViaServer(context, taskId3), { outputMode: context.outputMode });
2007
2146
  if (!task)
2008
2147
  throw new CliError(`Task not found: ${taskId3}`, 3, { hint: "Run `rig task list` to see available tasks." });
2009
2148
  const summary = summarizeTask(task, { raw: true });
@@ -2015,7 +2154,7 @@ async function executeTask(context, args, options) {
2015
2154
  case "next": {
2016
2155
  const { filters, rest: remaining } = parseTaskFilters(rest);
2017
2156
  requireNoExtraArgs(remaining, "rig task next [--assignee <login|me|@me>] [--state open|closed] [--status <status>] [--limit <n>]");
2018
- const selected = await selectNextWorkspaceTaskViaServer(context, filters);
2157
+ const selected = await withSpinner("Selecting next ready task\u2026", () => selectNextWorkspaceTaskViaServer(context, filters), { outputMode: context.outputMode });
2019
2158
  if (context.outputMode === "text") {
2020
2159
  if (selected.task) {
2021
2160
  printFormattedOutput(formatTaskCard(summarizeTask(selected.task, { raw: true }), { title: "Selected task", selected: true }));
@@ -2165,7 +2304,7 @@ async function executeTask(context, args, options) {
2165
2304
  let selectedTask = null;
2166
2305
  let selectedTaskId = normalizeTaskRunTaskId(taskResult.value) ?? positionalTaskId;
2167
2306
  if (nextResult.value) {
2168
- const selected = await selectNextWorkspaceTaskViaServer(context, filterResult.filters);
2307
+ const selected = await withSpinner("Selecting next ready task\u2026", () => selectNextWorkspaceTaskViaServer(context, filterResult.filters), { outputMode: context.outputMode });
2169
2308
  selectedTask = selected.task;
2170
2309
  selectedTaskId = selected.task ? readTaskId(selected.task) : null;
2171
2310
  if (!selectedTaskId) {
@@ -2176,7 +2315,7 @@ async function executeTask(context, args, options) {
2176
2315
  if (context.outputMode !== "text" || !process.stdin.isTTY || !process.stdout.isTTY) {
2177
2316
  throw new CliError("task run requires an interactive terminal to pick a task; pass --next, --task <id>, or --initial-prompt/--title for an ad hoc run.", 2);
2178
2317
  }
2179
- const tasks = await listWorkspaceTasksViaServer(context, filterResult.filters);
2318
+ const tasks = await withSpinner("Reading tasks from server\u2026", () => listWorkspaceTasksViaServer(context, filterResult.filters), { outputMode: context.outputMode });
2180
2319
  selectedTask = await selectTaskWithTextPicker(tasks);
2181
2320
  selectedTaskId = selectedTask ? readTaskId(selectedTask) : null;
2182
2321
  if (!selectedTaskId) {
@@ -2186,13 +2325,13 @@ async function executeTask(context, args, options) {
2186
2325
  await runProjectMainSyncPreflight(context, { disabled: skipProjectSyncResult.value });
2187
2326
  const projectDefaults = await loadTaskRunProjectDefaults(context.projectRoot);
2188
2327
  const runtimeAdapter = normalizeRuntimeAdapter(runtimeAdapterResult.value ?? projectDefaults.runtimeAdapter);
2189
- await runFastTaskRunPreflight(context, {
2328
+ await withSpinner("Running task-run preflight\u2026", () => runFastTaskRunPreflight(context, {
2190
2329
  taskId: selectedTaskId,
2191
2330
  runtimeAdapter
2192
- });
2331
+ }), { outputMode: context.outputMode });
2193
2332
  const dirtyBaseline = await resolveDirtyBaselineForTaskRun(context, dirtyBaselineResult.value);
2194
2333
  const prMode = noPrResult.value ? "off" : normalizePrMode(prResult.value) ?? projectDefaults.prMode;
2195
- const submitted = await submitTaskRunViaServer(context, {
2334
+ const submitted = await withSpinner("Dispatching run\u2026", () => submitTaskRunViaServer(context, {
2196
2335
  runId: context.runId,
2197
2336
  taskId: selectedTaskId ?? undefined,
2198
2337
  title: titleResult.value ?? undefined,
@@ -2203,7 +2342,7 @@ async function executeTask(context, args, options) {
2203
2342
  initialPrompt: initialPromptResult.value ?? undefined,
2204
2343
  baselineMode: dirtyBaseline.mode,
2205
2344
  prMode
2206
- });
2345
+ }), { outputMode: context.outputMode });
2207
2346
  let attachDetails = null;
2208
2347
  if (!detachResult.value && context.outputMode === "text") {
2209
2348
  printFormattedOutput(formatSubmittedRun({