@h-rig/cli 0.0.6-alpha.67 → 0.0.6-alpha.69

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}`, {
@@ -459,6 +471,17 @@ async function getRunTimelineViaServer(context, runId, options = {}) {
459
471
  const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
460
472
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { entries: [] };
461
473
  }
474
+ var RESUMABLE_RUN_STATUSES = new Set([
475
+ "created",
476
+ "preparing",
477
+ "running",
478
+ "validating",
479
+ "reviewing",
480
+ "stopped",
481
+ "failed",
482
+ "needs-attention",
483
+ "needs_attention"
484
+ ]);
462
485
  async function stopRunViaServer(context, runId) {
463
486
  const payload = await requestServerJson(context, "/api/runs/stop", {
464
487
  method: "POST",
@@ -1025,6 +1048,127 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
1025
1048
  return Number.isFinite(index) ? tasks[index] ?? null : null;
1026
1049
  }
1027
1050
 
1051
+ // packages/cli/src/commands/_async-ui.ts
1052
+ import pc from "picocolors";
1053
+
1054
+ // packages/cli/src/commands/_spinner.ts
1055
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1056
+ function createTtySpinner(input) {
1057
+ const output = input.output ?? process.stdout;
1058
+ const isTty = output.isTTY === true;
1059
+ const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
1060
+ let label = input.label;
1061
+ let frame = 0;
1062
+ let paused = false;
1063
+ let stopped = false;
1064
+ let lastPrintedLabel = "";
1065
+ const render = () => {
1066
+ if (stopped || paused)
1067
+ return;
1068
+ if (!isTty) {
1069
+ if (label !== lastPrintedLabel) {
1070
+ output.write(`${label}
1071
+ `);
1072
+ lastPrintedLabel = label;
1073
+ }
1074
+ return;
1075
+ }
1076
+ frame = (frame + 1) % frames.length;
1077
+ const glyph = frames[frame] ?? frames[0] ?? "";
1078
+ output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
1079
+ };
1080
+ const clearLine = () => {
1081
+ if (isTty)
1082
+ output.write("\r\x1B[2K");
1083
+ };
1084
+ render();
1085
+ const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
1086
+ return {
1087
+ setLabel(next) {
1088
+ label = next;
1089
+ render();
1090
+ },
1091
+ pause() {
1092
+ paused = true;
1093
+ clearLine();
1094
+ },
1095
+ resume() {
1096
+ if (stopped)
1097
+ return;
1098
+ paused = false;
1099
+ render();
1100
+ },
1101
+ stop(finalLine) {
1102
+ if (stopped)
1103
+ return;
1104
+ stopped = true;
1105
+ if (timer)
1106
+ clearInterval(timer);
1107
+ clearLine();
1108
+ if (finalLine)
1109
+ output.write(`${finalLine}
1110
+ `);
1111
+ }
1112
+ };
1113
+ }
1114
+
1115
+ // packages/cli/src/commands/_async-ui.ts
1116
+ var CLACK_SPINNER_FRAMES = ["\u25D2", "\u25D0", "\u25D3", "\u25D1"];
1117
+ var DONE_SYMBOL = pc.green("\u25C7");
1118
+ var FAIL_SYMBOL = pc.red("\u25A0");
1119
+ var activeUpdate = null;
1120
+ async function withSpinner(label, work, options = {}) {
1121
+ if (options.outputMode === "json") {
1122
+ return work(() => {});
1123
+ }
1124
+ if (activeUpdate) {
1125
+ const outer = activeUpdate;
1126
+ outer(label);
1127
+ return work(outer);
1128
+ }
1129
+ const output = options.output ?? process.stderr;
1130
+ const isTty = output.isTTY === true;
1131
+ let lastLabel = label;
1132
+ if (!isTty) {
1133
+ output.write(`${label}
1134
+ `);
1135
+ const update2 = (next) => {
1136
+ lastLabel = next;
1137
+ };
1138
+ activeUpdate = update2;
1139
+ const previousListener2 = setServerPhaseListener(update2);
1140
+ try {
1141
+ return await work(update2);
1142
+ } finally {
1143
+ activeUpdate = null;
1144
+ setServerPhaseListener(previousListener2);
1145
+ }
1146
+ }
1147
+ const spinner = createTtySpinner({
1148
+ label,
1149
+ output,
1150
+ frames: CLACK_SPINNER_FRAMES,
1151
+ styleFrame: (frame) => pc.magenta(frame)
1152
+ });
1153
+ const update = (next) => {
1154
+ lastLabel = next;
1155
+ spinner.setLabel(next);
1156
+ };
1157
+ activeUpdate = update;
1158
+ const previousListener = setServerPhaseListener(update);
1159
+ try {
1160
+ const result = await work(update);
1161
+ spinner.stop(options.doneLabel ? `${DONE_SYMBOL} ${options.doneLabel}` : undefined);
1162
+ return result;
1163
+ } catch (error) {
1164
+ spinner.stop(`${FAIL_SYMBOL} ${lastLabel}`);
1165
+ throw error;
1166
+ } finally {
1167
+ activeUpdate = null;
1168
+ setServerPhaseListener(previousListener);
1169
+ }
1170
+ }
1171
+
1028
1172
  // packages/cli/src/commands/_pi-frontend.ts
1029
1173
  import { mkdtempSync, rmSync } from "fs";
1030
1174
  import { tmpdir } from "os";
@@ -1072,7 +1216,12 @@ async function attachRunBundledPiFrontend(context, input) {
1072
1216
  };
1073
1217
  let detached = false;
1074
1218
  try {
1075
- await runPiMain([], {
1219
+ await runPiMain([
1220
+ "--no-extensions",
1221
+ "--no-skills",
1222
+ "--no-prompt-templates",
1223
+ "--no-context-files"
1224
+ ], {
1076
1225
  extensionFactories: [piRigExtensionFactory]
1077
1226
  });
1078
1227
  detached = true;
@@ -1137,8 +1286,9 @@ async function readOperatorSnapshot(context, runId, options = {}) {
1137
1286
  }
1138
1287
  async function attachRunOperatorView(context, input) {
1139
1288
  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()));
1289
+ const attachMessage = input.message?.trim();
1290
+ if (attachMessage) {
1291
+ await withSpinner("Queueing steering message\u2026", () => sendRunPiPromptViaServer(context, input.runId, attachMessage, "steer").catch(() => steerRunViaServer(context, input.runId, attachMessage)), { outputMode: context.outputMode });
1142
1292
  steered = true;
1143
1293
  }
1144
1294
  if (input.follow && !input.once && input.interactive !== false && context.outputMode === "text" && Boolean(process.stdin.isTTY && process.stdout.isTTY)) {
@@ -1148,7 +1298,7 @@ async function attachRunOperatorView(context, input) {
1148
1298
  });
1149
1299
  }
1150
1300
  const surface = createOperatorSurface({ interactive: input.interactive !== false });
1151
- let snapshot = await readOperatorSnapshot(context, input.runId);
1301
+ let snapshot = await withSpinner(`Connecting to run ${input.runId}\u2026`, () => readOperatorSnapshot(context, input.runId), { outputMode: context.outputMode });
1152
1302
  if (context.outputMode === "text") {
1153
1303
  surface.renderSnapshot(snapshot);
1154
1304
  surface.renderTimeline(snapshot.timeline);
@@ -1188,7 +1338,7 @@ async function attachRunOperatorView(context, input) {
1188
1338
 
1189
1339
  // packages/cli/src/commands/_cli-format.ts
1190
1340
  import { log, note } from "@clack/prompts";
1191
- import pc from "picocolors";
1341
+ import pc2 from "picocolors";
1192
1342
  function stringField(record, key, fallback = "") {
1193
1343
  const value = record[key];
1194
1344
  return typeof value === "string" && value.trim() ? value.trim() : fallback;
@@ -1218,14 +1368,14 @@ function pad(value, width) {
1218
1368
  function statusColor(status) {
1219
1369
  const normalized = status.toLowerCase();
1220
1370
  if (["completed", "merged", "closed", "done", "accepted", "pass", "selected", "approved"].includes(normalized))
1221
- return pc.green;
1371
+ return pc2.green;
1222
1372
  if (["failed", "needs_attention", "needs-attention", "blocked", "error", "rejected"].includes(normalized))
1223
- return pc.red;
1373
+ return pc2.red;
1224
1374
  if (["running", "reviewing", "validating", "in_progress", "in-progress", "remote"].includes(normalized))
1225
- return pc.cyan;
1375
+ return pc2.cyan;
1226
1376
  if (["ready", "open", "queued", "created", "preparing", "local", "pending"].includes(normalized))
1227
- return pc.yellow;
1228
- return pc.dim;
1377
+ return pc2.yellow;
1378
+ return pc2.dim;
1229
1379
  }
1230
1380
  function compactValue(value) {
1231
1381
  if (value === null || value === undefined)
@@ -1256,17 +1406,17 @@ function formatStatusPill(status) {
1256
1406
  return statusColor(label)(`\u25CF ${label}`);
1257
1407
  }
1258
1408
  function formatSection(title, subtitle) {
1259
- return `${pc.bold(pc.cyan("\u25C6"))} ${pc.bold(title)}${subtitle ? pc.dim(` \u2014 ${subtitle}`) : ""}`;
1409
+ return `${pc2.bold(pc2.cyan("\u25C6"))} ${pc2.bold(title)}${subtitle ? pc2.dim(` \u2014 ${subtitle}`) : ""}`;
1260
1410
  }
1261
1411
  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}`);
1412
+ 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
1413
  return [formatSection(title), ...body].join(`
1264
1414
  `);
1265
1415
  }
1266
1416
  function formatNextSteps(steps) {
1267
1417
  if (steps.length === 0)
1268
1418
  return [];
1269
- return [pc.bold("Next"), ...steps.map((step) => `${pc.dim("\u203A")} ${step}`)];
1419
+ return [pc2.bold("Next"), ...steps.map((step) => `${pc2.dim("\u203A")} ${step}`)];
1270
1420
  }
1271
1421
  function formatTaskList(tasks, options = {}) {
1272
1422
  if (options.raw)
@@ -1286,12 +1436,12 @@ function formatTaskList(tasks, options = {}) {
1286
1436
  });
1287
1437
  const idWidth = Math.min(18, Math.max(4, ...rows.map((row) => row.id.length)));
1288
1438
  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")}`;
1439
+ const header = `${pc2.bold(pad("TASK", idWidth))} ${pc2.bold(pad("STATUS", statusWidth))} ${pc2.bold("TITLE")}`;
1290
1440
  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}`) : "";
1441
+ const labels = row.labels.length > 0 ? pc2.dim(` ${row.labels.slice(0, 4).map((label) => `#${label}`).join(" ")}`) : "";
1442
+ const source = row.source ? pc2.dim(` ${row.source}`) : "";
1293
1443
  return [
1294
- pc.bold(pad(truncate(row.id, idWidth), idWidth)),
1444
+ pc2.bold(pad(truncate(row.id, idWidth), idWidth)),
1295
1445
  statusColor(row.status)(pad(truncate(row.status, statusWidth), statusWidth)),
1296
1446
  `${row.title}${labels}${source}`
1297
1447
  ].join(" ");
@@ -1312,7 +1462,7 @@ function formatTaskCard(task, options = {}) {
1312
1462
  const readiness = compactValue(task.readiness ?? raw.readiness);
1313
1463
  const validators = compactValue(task.validators ?? raw.validators ?? task.validation ?? raw.validation);
1314
1464
  const rows = [
1315
- ["task", pc.bold(id)],
1465
+ ["task", pc2.bold(id)],
1316
1466
  ["status", formatStatusPill(status)],
1317
1467
  ["title", title],
1318
1468
  ["source", source],
@@ -1334,12 +1484,12 @@ function formatTaskDetails(task) {
1334
1484
  return formatTaskCard(task, { title: "Task details" });
1335
1485
  }
1336
1486
  function formatSubmittedRun(input) {
1337
- const rows = [["run", pc.bold(input.runId)]];
1487
+ const rows = [["run", pc2.bold(input.runId)]];
1338
1488
  if (input.task) {
1339
1489
  const id = stringField(input.task, "id", "<unknown>");
1340
1490
  const status = stringField(input.task, "status", "unknown");
1341
1491
  const title = stringField(input.task, "title", "Untitled task");
1342
- rows.push(["task", `${pc.bold(id)} ${formatStatusPill(status)} ${title}`]);
1492
+ rows.push(["task", `${pc2.bold(id)} ${formatStatusPill(status)} ${title}`]);
1343
1493
  }
1344
1494
  const runtime = [input.runtimeAdapter || "pi", input.runtimeMode || "full-access", input.interactionMode || "default"].filter(Boolean).join(" \xB7 ");
1345
1495
  rows.push(["runtime", runtime]);
@@ -1395,7 +1545,7 @@ async function printPendingInboxFooter(context) {
1395
1545
 
1396
1546
  // packages/cli/src/commands/_help-catalog.ts
1397
1547
  import { intro, log as log2, note as note2, outro } from "@clack/prompts";
1398
- import pc2 from "picocolors";
1548
+ import pc3 from "picocolors";
1399
1549
  var TOP_LEVEL_SECTIONS = [
1400
1550
  {
1401
1551
  title: "Start here",
@@ -1677,13 +1827,13 @@ var ADVANCED_GROUPS = [
1677
1827
  ];
1678
1828
  var ALL_GROUPS = [...PRIMARY_GROUPS, ...ADVANCED_GROUPS];
1679
1829
  function heading(title) {
1680
- return pc2.bold(pc2.cyan(title));
1830
+ return pc3.bold(pc3.cyan(title));
1681
1831
  }
1682
1832
  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);
1833
+ const m = (s) => pc3.bold(pc3.magenta(s));
1834
+ const c = (s) => pc3.bold(pc3.cyan(s));
1835
+ const y = (s) => pc3.yellow(s);
1836
+ const d = (s) => pc3.dim(s);
1687
1837
  const lines = [
1688
1838
  m(" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ") + d(" \u2591\u2592\u2593\u2588 "),
1689
1839
  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 +1842,7 @@ function renderRigBanner(version) {
1692
1842
  y(" \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D") + d(" \u2592\u2591"),
1693
1843
  y(" \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D "),
1694
1844
  "",
1695
- ` ${c("\u25E2\u25E4")} ${pc2.bold("the control rig for autonomous coding agents")} ${m("//")} ${d("you are the operator")}`,
1845
+ ` ${c("\u25E2\u25E4")} ${pc3.bold("the control rig for autonomous coding agents")} ${m("//")} ${d("you are the operator")}`,
1696
1846
  version ? ` ${d(`v${version} \xB7 jack in: rig task run --next`)}` : ` ${d("jack in: rig task run --next")}`
1697
1847
  ];
1698
1848
  return lines.join(`
@@ -1700,7 +1850,7 @@ function renderRigBanner(version) {
1700
1850
  }
1701
1851
  function commandLine(command, description) {
1702
1852
  const commandColumn = command.length >= 38 ? `${command} ` : command.padEnd(38);
1703
- return `${pc2.dim("\u2502")} ${pc2.bold(commandColumn)} ${description}`;
1853
+ return `${pc3.dim("\u2502")} ${pc3.bold(commandColumn)} ${description}`;
1704
1854
  }
1705
1855
  function renderCommandBlock(commands) {
1706
1856
  return commands.map((entry) => commandLine(entry.command, entry.description)).join(`
@@ -1710,37 +1860,37 @@ function renderGroup(group) {
1710
1860
  const lines = [
1711
1861
  `${heading(`rig ${group.name}`)} \u2014 ${group.summary}`,
1712
1862
  "",
1713
- pc2.bold("Usage"),
1863
+ pc3.bold("Usage"),
1714
1864
  ...group.usage.map((line) => ` ${line}`),
1715
1865
  "",
1716
- pc2.bold("Commands"),
1866
+ pc3.bold("Commands"),
1717
1867
  ...group.commands.map((entry) => commandLine(entry.command, entry.description))
1718
1868
  ];
1719
1869
  if (group.examples?.length) {
1720
- lines.push("", pc2.bold("Examples"), ...group.examples.map((line) => ` ${pc2.dim("$")} ${line}`));
1870
+ lines.push("", pc3.bold("Examples"), ...group.examples.map((line) => ` ${pc3.dim("$")} ${line}`));
1721
1871
  }
1722
1872
  if (group.next?.length) {
1723
- lines.push("", pc2.bold("Next steps"), ...group.next.map((line) => ` ${pc2.dim("\u203A")} ${line}`));
1873
+ lines.push("", pc3.bold("Next steps"), ...group.next.map((line) => ` ${pc3.dim("\u203A")} ${line}`));
1724
1874
  }
1725
1875
  if (group.advanced?.length) {
1726
- lines.push("", pc2.bold("Compatibility / advanced"), ...group.advanced.map((line) => ` ${pc2.dim("\u203A")} ${line}`));
1876
+ lines.push("", pc3.bold("Compatibility / advanced"), ...group.advanced.map((line) => ` ${pc3.dim("\u203A")} ${line}`));
1727
1877
  }
1728
1878
  return lines.join(`
1729
1879
  `);
1730
1880
  }
1731
1881
  function renderTopLevelHelp() {
1732
1882
  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."),
1883
+ `${heading("rig")} ${pc3.dim("\u2014 server-owned task/run control plane for Pi-backed engineering work")}`,
1884
+ pc3.dim("Current path: select a server, choose a task, submit a run, attach with native Pi, clear inbox gates."),
1735
1885
  "",
1736
1886
  ...TOP_LEVEL_SECTIONS.flatMap((section) => [
1737
- `${pc2.bold(pc2.magenta(`\u25C7 ${section.title}`))} \u2014 ${pc2.dim(section.subtitle)}`,
1887
+ `${pc3.bold(pc3.magenta(`\u25C7 ${section.title}`))} \u2014 ${pc3.dim(section.subtitle)}`,
1738
1888
  renderCommandBlock(section.commands),
1739
1889
  ""
1740
1890
  ]),
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."),
1891
+ 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
1892
  "",
1743
- pc2.bold("Global options"),
1893
+ pc3.bold("Global options"),
1744
1894
  commandLine("--project <path>", "Use a project root instead of auto-discovery."),
1745
1895
  commandLine("--json", "Emit structured output for scripts/agents."),
1746
1896
  commandLine("--dry-run", "Print the command plan without mutating state.")
@@ -1979,7 +2129,7 @@ async function executeTask(context, args, options) {
1979
2129
  pending = rawResult.rest;
1980
2130
  const { filters, rest: remaining } = parseTaskFilters(pending);
1981
2131
  requireNoExtraArgs(remaining, "rig task list [--raw] [--assignee <login|me|@me>] [--state open|closed] [--status <status>] [--limit <n>]");
1982
- const tasks = await listWorkspaceTasksViaServer(context, filters);
2132
+ const tasks = await withSpinner("Reading tasks from server\u2026", () => listWorkspaceTasksViaServer(context, filters), { outputMode: context.outputMode });
1983
2133
  if (context.outputMode === "text") {
1984
2134
  const renderedTasks = rawResult.value ? tasks.map((task) => summarizeTask(task, { raw: true })) : tasks.map((task) => summarizeTask(task));
1985
2135
  printFormattedOutput(formatTaskList(renderedTasks, { raw: rawResult.value }));
@@ -2003,7 +2153,7 @@ async function executeTask(context, args, options) {
2003
2153
  const taskId3 = normalizeTaskRunTaskId(taskOption.value ?? positional);
2004
2154
  if (!taskId3)
2005
2155
  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);
2156
+ const task = await withSpinner(`Reading task ${taskId3} from server\u2026`, () => getWorkspaceTaskViaServer(context, taskId3), { outputMode: context.outputMode });
2007
2157
  if (!task)
2008
2158
  throw new CliError(`Task not found: ${taskId3}`, 3, { hint: "Run `rig task list` to see available tasks." });
2009
2159
  const summary = summarizeTask(task, { raw: true });
@@ -2015,7 +2165,7 @@ async function executeTask(context, args, options) {
2015
2165
  case "next": {
2016
2166
  const { filters, rest: remaining } = parseTaskFilters(rest);
2017
2167
  requireNoExtraArgs(remaining, "rig task next [--assignee <login|me|@me>] [--state open|closed] [--status <status>] [--limit <n>]");
2018
- const selected = await selectNextWorkspaceTaskViaServer(context, filters);
2168
+ const selected = await withSpinner("Selecting next ready task\u2026", () => selectNextWorkspaceTaskViaServer(context, filters), { outputMode: context.outputMode });
2019
2169
  if (context.outputMode === "text") {
2020
2170
  if (selected.task) {
2021
2171
  printFormattedOutput(formatTaskCard(summarizeTask(selected.task, { raw: true }), { title: "Selected task", selected: true }));
@@ -2165,7 +2315,7 @@ async function executeTask(context, args, options) {
2165
2315
  let selectedTask = null;
2166
2316
  let selectedTaskId = normalizeTaskRunTaskId(taskResult.value) ?? positionalTaskId;
2167
2317
  if (nextResult.value) {
2168
- const selected = await selectNextWorkspaceTaskViaServer(context, filterResult.filters);
2318
+ const selected = await withSpinner("Selecting next ready task\u2026", () => selectNextWorkspaceTaskViaServer(context, filterResult.filters), { outputMode: context.outputMode });
2169
2319
  selectedTask = selected.task;
2170
2320
  selectedTaskId = selected.task ? readTaskId(selected.task) : null;
2171
2321
  if (!selectedTaskId) {
@@ -2176,7 +2326,7 @@ async function executeTask(context, args, options) {
2176
2326
  if (context.outputMode !== "text" || !process.stdin.isTTY || !process.stdout.isTTY) {
2177
2327
  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
2328
  }
2179
- const tasks = await listWorkspaceTasksViaServer(context, filterResult.filters);
2329
+ const tasks = await withSpinner("Reading tasks from server\u2026", () => listWorkspaceTasksViaServer(context, filterResult.filters), { outputMode: context.outputMode });
2180
2330
  selectedTask = await selectTaskWithTextPicker(tasks);
2181
2331
  selectedTaskId = selectedTask ? readTaskId(selectedTask) : null;
2182
2332
  if (!selectedTaskId) {
@@ -2186,13 +2336,13 @@ async function executeTask(context, args, options) {
2186
2336
  await runProjectMainSyncPreflight(context, { disabled: skipProjectSyncResult.value });
2187
2337
  const projectDefaults = await loadTaskRunProjectDefaults(context.projectRoot);
2188
2338
  const runtimeAdapter = normalizeRuntimeAdapter(runtimeAdapterResult.value ?? projectDefaults.runtimeAdapter);
2189
- await runFastTaskRunPreflight(context, {
2339
+ await withSpinner("Running task-run preflight\u2026", () => runFastTaskRunPreflight(context, {
2190
2340
  taskId: selectedTaskId,
2191
2341
  runtimeAdapter
2192
- });
2342
+ }), { outputMode: context.outputMode });
2193
2343
  const dirtyBaseline = await resolveDirtyBaselineForTaskRun(context, dirtyBaselineResult.value);
2194
2344
  const prMode = noPrResult.value ? "off" : normalizePrMode(prResult.value) ?? projectDefaults.prMode;
2195
- const submitted = await submitTaskRunViaServer(context, {
2345
+ const submitted = await withSpinner("Dispatching run\u2026", () => submitTaskRunViaServer(context, {
2196
2346
  runId: context.runId,
2197
2347
  taskId: selectedTaskId ?? undefined,
2198
2348
  title: titleResult.value ?? undefined,
@@ -2203,7 +2353,7 @@ async function executeTask(context, args, options) {
2203
2353
  initialPrompt: initialPromptResult.value ?? undefined,
2204
2354
  baselineMode: dirtyBaseline.mode,
2205
2355
  prMode
2206
- });
2356
+ }), { outputMode: context.outputMode });
2207
2357
  let attachDetails = null;
2208
2358
  if (!detachResult.value && context.outputMode === "text") {
2209
2359
  printFormattedOutput(formatSubmittedRun({