@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.
@@ -2740,6 +2740,15 @@ import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
2740
2740
  import { resolve as resolve10 } from "path";
2741
2741
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
2742
2742
  var scopedGitHubBearerTokens = new Map;
2743
+ var serverPhaseListener = null;
2744
+ function setServerPhaseListener(listener) {
2745
+ const previous = serverPhaseListener;
2746
+ serverPhaseListener = listener;
2747
+ return previous;
2748
+ }
2749
+ function reportServerPhase(label) {
2750
+ serverPhaseListener?.(label);
2751
+ }
2743
2752
  function cleanToken(value) {
2744
2753
  const trimmed = value?.trim();
2745
2754
  return trimmed ? trimmed : null;
@@ -2786,6 +2795,7 @@ async function ensureServerForCli(projectRoot) {
2786
2795
  try {
2787
2796
  const selected = resolveSelectedConnection(projectRoot);
2788
2797
  if (selected?.connection.kind === "remote") {
2798
+ reportServerPhase(`Connecting to ${selected.alias}\u2026`);
2789
2799
  const authToken = readGitHubBearerTokenForRemote(projectRoot);
2790
2800
  const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
2791
2801
  return {
@@ -2795,6 +2805,7 @@ async function ensureServerForCli(projectRoot) {
2795
2805
  serverProjectRoot
2796
2806
  };
2797
2807
  }
2808
+ reportServerPhase("Starting local Rig server\u2026");
2798
2809
  const connection = await ensureLocalRigServerConnection(projectRoot);
2799
2810
  return {
2800
2811
  baseUrl: connection.baseUrl,
@@ -2911,6 +2922,7 @@ async function requestServerJson(context, pathname, init = {}) {
2911
2922
  const headers = mergeHeaders(init.headers, server.authToken);
2912
2923
  if (server.serverProjectRoot)
2913
2924
  headers.set("x-rig-project-root", server.serverProjectRoot);
2925
+ reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
2914
2926
  let response;
2915
2927
  try {
2916
2928
  response = await fetch(`${server.baseUrl}${pathname}`, {
@@ -3088,6 +3100,38 @@ async function updateWorkspaceTaskViaServer(context, input) {
3088
3100
  });
3089
3101
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { ok: true };
3090
3102
  }
3103
+ var RESUMABLE_RUN_STATUSES = new Set([
3104
+ "created",
3105
+ "preparing",
3106
+ "running",
3107
+ "validating",
3108
+ "reviewing",
3109
+ "stopped",
3110
+ "failed",
3111
+ "needs-attention",
3112
+ "needs_attention"
3113
+ ]);
3114
+ async function resumeRunViaServer(context, runId, options) {
3115
+ let targetRunId = runId?.trim() || null;
3116
+ if (!targetRunId) {
3117
+ const candidates = (await listRunsViaServer(context)).filter((run) => RESUMABLE_RUN_STATUSES.has(String(run.status ?? ""))).sort((left, right) => String(right.updatedAt ?? "").localeCompare(String(left.updatedAt ?? "")));
3118
+ targetRunId = typeof candidates[0]?.runId === "string" ? candidates[0].runId : null;
3119
+ }
3120
+ if (!targetRunId) {
3121
+ throw new CliError(options.restart ? "No run is available to restart." : "No resumable run is available.", 2, { hint: "List runs with `rig run list`, then pass an explicit id: `rig run resume <run-id>`." });
3122
+ }
3123
+ const payload = await requestServerJson(context, "/api/runs/resume", {
3124
+ method: "POST",
3125
+ headers: { "content-type": "application/json" },
3126
+ body: JSON.stringify({ runId: targetRunId, createdAt: new Date().toISOString(), restart: options.restart })
3127
+ });
3128
+ const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
3129
+ if (record.ok === false) {
3130
+ const message = typeof record.error === "string" && record.error.trim() ? record.error : "run resume failed";
3131
+ throw new CliError(`${options.restart ? "restart" : "resume"} failed for ${targetRunId}: ${message}`, 1);
3132
+ }
3133
+ return { ok: true, runId: targetRunId, ...record };
3134
+ }
3091
3135
  async function stopRunViaServer(context, runId) {
3092
3136
  const payload = await requestServerJson(context, "/api/runs/stop", {
3093
3137
  method: "POST",
@@ -4431,6 +4475,127 @@ function formatConnectionStatus(selected, connections) {
4431
4475
  `);
4432
4476
  }
4433
4477
 
4478
+ // packages/cli/src/commands/_async-ui.ts
4479
+ import pc4 from "picocolors";
4480
+
4481
+ // packages/cli/src/commands/_spinner.ts
4482
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
4483
+ function createTtySpinner(input) {
4484
+ const output = input.output ?? process.stdout;
4485
+ const isTty = output.isTTY === true;
4486
+ const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
4487
+ let label = input.label;
4488
+ let frame = 0;
4489
+ let paused = false;
4490
+ let stopped = false;
4491
+ let lastPrintedLabel = "";
4492
+ const render = () => {
4493
+ if (stopped || paused)
4494
+ return;
4495
+ if (!isTty) {
4496
+ if (label !== lastPrintedLabel) {
4497
+ output.write(`${label}
4498
+ `);
4499
+ lastPrintedLabel = label;
4500
+ }
4501
+ return;
4502
+ }
4503
+ frame = (frame + 1) % frames.length;
4504
+ const glyph = frames[frame] ?? frames[0] ?? "";
4505
+ output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
4506
+ };
4507
+ const clearLine = () => {
4508
+ if (isTty)
4509
+ output.write("\r\x1B[2K");
4510
+ };
4511
+ render();
4512
+ const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
4513
+ return {
4514
+ setLabel(next) {
4515
+ label = next;
4516
+ render();
4517
+ },
4518
+ pause() {
4519
+ paused = true;
4520
+ clearLine();
4521
+ },
4522
+ resume() {
4523
+ if (stopped)
4524
+ return;
4525
+ paused = false;
4526
+ render();
4527
+ },
4528
+ stop(finalLine) {
4529
+ if (stopped)
4530
+ return;
4531
+ stopped = true;
4532
+ if (timer)
4533
+ clearInterval(timer);
4534
+ clearLine();
4535
+ if (finalLine)
4536
+ output.write(`${finalLine}
4537
+ `);
4538
+ }
4539
+ };
4540
+ }
4541
+
4542
+ // packages/cli/src/commands/_async-ui.ts
4543
+ var CLACK_SPINNER_FRAMES = ["\u25D2", "\u25D0", "\u25D3", "\u25D1"];
4544
+ var DONE_SYMBOL = pc4.green("\u25C7");
4545
+ var FAIL_SYMBOL = pc4.red("\u25A0");
4546
+ var activeUpdate = null;
4547
+ async function withSpinner(label, work, options = {}) {
4548
+ if (options.outputMode === "json") {
4549
+ return work(() => {});
4550
+ }
4551
+ if (activeUpdate) {
4552
+ const outer = activeUpdate;
4553
+ outer(label);
4554
+ return work(outer);
4555
+ }
4556
+ const output = options.output ?? process.stderr;
4557
+ const isTty = output.isTTY === true;
4558
+ let lastLabel = label;
4559
+ if (!isTty) {
4560
+ output.write(`${label}
4561
+ `);
4562
+ const update2 = (next) => {
4563
+ lastLabel = next;
4564
+ };
4565
+ activeUpdate = update2;
4566
+ const previousListener2 = setServerPhaseListener(update2);
4567
+ try {
4568
+ return await work(update2);
4569
+ } finally {
4570
+ activeUpdate = null;
4571
+ setServerPhaseListener(previousListener2);
4572
+ }
4573
+ }
4574
+ const spinner2 = createTtySpinner({
4575
+ label,
4576
+ output,
4577
+ frames: CLACK_SPINNER_FRAMES,
4578
+ styleFrame: (frame) => pc4.magenta(frame)
4579
+ });
4580
+ const update = (next) => {
4581
+ lastLabel = next;
4582
+ spinner2.setLabel(next);
4583
+ };
4584
+ activeUpdate = update;
4585
+ const previousListener = setServerPhaseListener(update);
4586
+ try {
4587
+ const result = await work(update);
4588
+ spinner2.stop(options.doneLabel ? `${DONE_SYMBOL} ${options.doneLabel}` : undefined);
4589
+ return result;
4590
+ } catch (error) {
4591
+ spinner2.stop(`${FAIL_SYMBOL} ${lastLabel}`);
4592
+ throw error;
4593
+ } finally {
4594
+ activeUpdate = null;
4595
+ setServerPhaseListener(previousListener);
4596
+ }
4597
+ }
4598
+
4434
4599
  // packages/cli/src/commands/inbox.ts
4435
4600
  async function listInboxRecords(context, kind, filters) {
4436
4601
  const params = new URLSearchParams;
@@ -4535,7 +4700,7 @@ async function executeInbox(context, args) {
4535
4700
  const task = takeOption(pending, "--task");
4536
4701
  pending = task.rest;
4537
4702
  requireNoExtraArgs(pending, "rig inbox approvals [--run <id>] [--task <id>]");
4538
- const approvals = await listInboxRecords(context, "approvals", { run: run.value, task: task.value });
4703
+ const approvals = await withSpinner("Reading approvals from server\u2026", () => listInboxRecords(context, "approvals", { run: run.value, task: task.value }), { outputMode: context.outputMode });
4539
4704
  renderList(context, "approvals", approvals);
4540
4705
  return { ok: true, group: "inbox", command, details: { approvals } };
4541
4706
  }
@@ -4546,7 +4711,7 @@ async function executeInbox(context, args) {
4546
4711
  const task = takeOption(pending, "--task");
4547
4712
  pending = task.rest;
4548
4713
  requireNoExtraArgs(pending, "rig inbox inputs [--run <id>] [--task <id>]");
4549
- const requests = await listInboxRecords(context, "inputs", { run: run.value, task: task.value });
4714
+ const requests = await withSpinner("Reading input requests from server\u2026", () => listInboxRecords(context, "inputs", { run: run.value, task: task.value }), { outputMode: context.outputMode });
4550
4715
  renderList(context, "inputs", requests);
4551
4716
  return { ok: true, group: "inbox", command, details: { requests } };
4552
4717
  }
@@ -4567,7 +4732,7 @@ async function executeInbox(context, args) {
4567
4732
  if (decision.value !== "approve" && decision.value !== "reject") {
4568
4733
  throw new CliError("decision must be approve or reject.", 1, { hint: "Re-run as `rig inbox approve --run <id> --request <id> --decision approve|reject`." });
4569
4734
  }
4570
- const result = await requestServerJson(context, "/api/inbox/approvals/resolve", {
4735
+ const result = await withSpinner(`Resolving approval ${request.value}\u2026`, () => requestServerJson(context, "/api/inbox/approvals/resolve", {
4571
4736
  method: "POST",
4572
4737
  headers: { "content-type": "application/json" },
4573
4738
  body: JSON.stringify({
@@ -4576,7 +4741,7 @@ async function executeInbox(context, args) {
4576
4741
  decision: decision.value,
4577
4742
  note: note4.value ?? null
4578
4743
  })
4579
- });
4744
+ }), { outputMode: context.outputMode });
4580
4745
  return { ok: true, group: "inbox", command, details: { result } };
4581
4746
  }
4582
4747
  case "respond": {
@@ -4610,7 +4775,7 @@ async function executeInbox(context, args) {
4610
4775
  const [key, ...restValue] = entry.split("=");
4611
4776
  return [key, restValue.join("=")];
4612
4777
  }));
4613
- const result = await requestServerJson(context, "/api/inbox/inputs/respond", {
4778
+ const result = await withSpinner(`Sending response for ${request.value}\u2026`, () => requestServerJson(context, "/api/inbox/inputs/respond", {
4614
4779
  method: "POST",
4615
4780
  headers: { "content-type": "application/json" },
4616
4781
  body: JSON.stringify({
@@ -4618,7 +4783,7 @@ async function executeInbox(context, args) {
4618
4783
  requestId: request.value,
4619
4784
  answers: parsedAnswers
4620
4785
  })
4621
- });
4786
+ }), { outputMode: context.outputMode });
4622
4787
  return { ok: true, group: "inbox", command, details: { result } };
4623
4788
  }
4624
4789
  case "watch": {
@@ -5035,7 +5200,10 @@ async function runRigDoctorChecks(options) {
5035
5200
  const bunVersion = options.bunVersion ?? Bun.version;
5036
5201
  const request = options.requestJson ?? ((pathname, init) => requestServerJson({ projectRoot }, pathname, init));
5037
5202
  const loadConfig = options.loadConfig ?? loadRigConfigOrNull;
5203
+ const progress = options.onProgress ?? (() => {});
5204
+ progress("Checking local toolchain\u2026");
5038
5205
  checks.push(check("bun", `bun >= ${MIN_SUPPORTED_BUN_VERSION}`, isSupportedBunVersion(bunVersion) ? "pass" : "fail", `found ${bunVersion}`, `Install Bun ${MIN_SUPPORTED_BUN_VERSION} or newer.`), check("git", "git", which("git") ? "pass" : "fail", which("git") ?? undefined, "Install git and ensure it is on PATH."), check("jq", "jq", which("jq") ? "pass" : "warn", which("jq") ?? undefined, "Install jq (for example `brew install jq`)."));
5206
+ progress("Loading rig.config\u2026");
5039
5207
  const loadedConfig = await loadConfig(projectRoot).catch(() => null);
5040
5208
  const config = loadedConfig ?? loadFallbackConfig(projectRoot);
5041
5209
  const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync10(resolve16(projectRoot, name)));
@@ -5054,6 +5222,7 @@ async function runRigDoctorChecks(options) {
5054
5222
  checks.push(selected ? check("connection", "selected server connection", "pass", selected.connection.kind === "remote" ? selected.connection.baseUrl : "local auto") : check("connection", "selected server", repo ? "fail" : "warn", repo ? "selected alias is missing" : "will auto-start local server", repo ? "Run `rig server list` and `rig server use <alias|local>`." : undefined));
5055
5223
  let server = null;
5056
5224
  try {
5225
+ progress("Connecting to the selected Rig server\u2026");
5057
5226
  server = await (options.resolveServer ?? ensureServerForCli)(projectRoot);
5058
5227
  checks.push(check("server", "Rig server reachable", "pass", `${server.connectionKind} ${server.baseUrl}`));
5059
5228
  } catch (error) {
@@ -5061,18 +5230,21 @@ async function runRigDoctorChecks(options) {
5061
5230
  }
5062
5231
  if (server || options.requestJson) {
5063
5232
  try {
5233
+ progress("Checking server status\u2026");
5064
5234
  const status = await request("/api/server/status");
5065
5235
  checks.push(check("server-status", "server project status", "pass", JSON.stringify(status).slice(0, 180)));
5066
5236
  } catch (error) {
5067
5237
  checks.push(check("server-status", "server project status", "fail", errorMessage(error), "Run `rig doctor` after the selected server is reachable."));
5068
5238
  }
5069
5239
  try {
5240
+ progress("Checking GitHub auth\u2026");
5070
5241
  const auth = await request("/api/github/auth/status");
5071
5242
  checks.push(isAuthenticated2(auth) ? check("github-auth", "GitHub auth", "pass") : check("github-auth", "GitHub auth", "fail", "not authenticated", "Run `rig github auth import-gh` or `rig github auth token --token <token>`."));
5072
5243
  } catch (error) {
5073
5244
  checks.push(check("github-auth", "GitHub auth", "fail", errorMessage(error), "Authenticate GitHub through Rig and ensure the server exposes auth status."));
5074
5245
  }
5075
5246
  try {
5247
+ progress("Checking GitHub repo permissions\u2026");
5076
5248
  const permissions = await request("/api/github/repo/permissions");
5077
5249
  const allowed = permissionAllowsPr2(permissions);
5078
5250
  checks.push(allowed === true ? check("github-repo-permissions", "GitHub repo PR permissions", "pass", JSON.stringify(permissions).slice(0, 180)) : allowed === false ? check("github-repo-permissions", "GitHub repo PR permissions", "fail", JSON.stringify(permissions).slice(0, 180), "Grant the selected GitHub token permission to push branches, open PRs, and merge according to repo rules.") : check("github-repo-permissions", "GitHub repo PR permissions", "warn", JSON.stringify(permissions).slice(0, 180), "Confirm the selected token can push branches and open PRs."));
@@ -5080,6 +5252,7 @@ async function runRigDoctorChecks(options) {
5080
5252
  checks.push(check("github-repo-permissions", "GitHub repo PR permissions", "warn", errorMessage(error), "Ensure the server exposes repo permission checks and the token can open PRs."));
5081
5253
  }
5082
5254
  try {
5255
+ progress("Checking GitHub issue labels\u2026");
5083
5256
  const labels = await request("/api/workspace/task-labels");
5084
5257
  const ready = labelsReady(labels);
5085
5258
  checks.push(ready === false ? check("task-labels", "GitHub issue labels", "fail", JSON.stringify(labels).slice(0, 180), "Let Rig create required labels or create the configured lifecycle labels manually.") : check("task-labels", "GitHub issue labels", ready === true ? "pass" : "warn", JSON.stringify(labels).slice(0, 180), "Confirm required Rig lifecycle labels exist."));
@@ -5087,6 +5260,7 @@ async function runRigDoctorChecks(options) {
5087
5260
  checks.push(check("task-labels", "GitHub issue labels", "warn", errorMessage(error), "Run `rig init`/`rig doctor` after label setup is wired on the server."));
5088
5261
  }
5089
5262
  try {
5263
+ progress("Checking task projection\u2026");
5090
5264
  const projection = await request("/api/workspace/task-projection");
5091
5265
  checks.push(check("task-projection", "task projection", "pass", JSON.stringify(projection).slice(0, 180)));
5092
5266
  } catch (error) {
@@ -5095,6 +5269,7 @@ async function runRigDoctorChecks(options) {
5095
5269
  const slug = projectStatusSlug(projectRoot, config);
5096
5270
  if (slug) {
5097
5271
  try {
5272
+ progress("Checking server project checkout\u2026");
5098
5273
  const project = await request(`/api/projects/${encodeURIComponent(slug)}`);
5099
5274
  checks.push(check("remote-checkout", "server project checkout", "pass", JSON.stringify(project).slice(0, 180)));
5100
5275
  } catch (error) {
@@ -5109,6 +5284,7 @@ async function runRigDoctorChecks(options) {
5109
5284
  }
5110
5285
  checks.push(githubProjectsCheck(config));
5111
5286
  checks.push(prMergeCheck(config));
5287
+ progress("Checking Pi installation\u2026");
5112
5288
  const piChecks = await (options.piChecks ?? (() => buildPiSetupChecks()))().catch((error) => [{
5113
5289
  ok: false,
5114
5290
  label: "pi/pi-rig checks",
@@ -6031,7 +6207,7 @@ async function executeGithub(context, args) {
6031
6207
  case "status": {
6032
6208
  if (rest.length > 0)
6033
6209
  throw new CliError("Usage: rig github auth status", 1);
6034
- const status = await getGitHubAuthStatusViaServer(context);
6210
+ const status = await withSpinner("Checking GitHub auth on the server\u2026", () => getGitHubAuthStatusViaServer(context), { outputMode: context.outputMode });
6035
6211
  printPayload(context, status, `GitHub auth: ${status.authenticated ? "authenticated" : "unauthenticated"}`);
6036
6212
  return { ok: true, group: "github", command: "auth status", details: status };
6037
6213
  }
@@ -6042,14 +6218,15 @@ async function executeGithub(context, args) {
6042
6218
  const token = parsed.value?.trim();
6043
6219
  if (!token)
6044
6220
  throw new CliError("Missing --token value.", 1, { hint: "Re-run as `rig github auth token --token <token>`." });
6045
- const result = await postGitHubTokenViaServer(context, token);
6221
+ const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, token), { outputMode: context.outputMode });
6046
6222
  printPayload(context, result, "GitHub token stored on the selected Rig server.");
6047
6223
  return { ok: true, group: "github", command: "auth token", details: result };
6048
6224
  }
6049
6225
  case "import-gh": {
6050
6226
  if (rest.length > 0)
6051
6227
  throw new CliError("Usage: rig github auth import-gh", 1);
6052
- const result = await postGitHubTokenViaServer(context, readGhToken());
6228
+ const importedToken = readGhToken();
6229
+ const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, importedToken), { outputMode: context.outputMode });
6053
6230
  printPayload(context, result, "GitHub token imported from gh and stored on the selected Rig server.");
6054
6231
  return { ok: true, group: "github", command: "auth import-gh", details: result };
6055
6232
  }
@@ -6062,7 +6239,7 @@ async function executeGithub(context, args) {
6062
6239
  init_runner();
6063
6240
  async function executeDoctor(context, args) {
6064
6241
  requireNoExtraArgs(args, "rig doctor");
6065
- const checks = await runRigDoctorChecks({ projectRoot: context.projectRoot });
6242
+ const checks = await withSpinner("Running doctor checks\u2026", (update) => runRigDoctorChecks({ projectRoot: context.projectRoot, onProgress: update }), { outputMode: context.outputMode });
6066
6243
  if (context.outputMode === "text") {
6067
6244
  console.log(formatDoctorChecks(checks));
6068
6245
  }
@@ -6369,13 +6546,19 @@ async function executeInspect(context, args) {
6369
6546
  const requiredTask = requireTask(task, "rig inspect logs --task <task-id>");
6370
6547
  const latestRun = listAuthorityRuns(context.projectRoot).map((entry) => readAuthorityRun3(context.projectRoot, entry.runId)).filter((run) => Boolean(run)).filter((run) => run.taskId === requiredTask).sort((left, right) => String(right.updatedAt ?? "").localeCompare(String(left.updatedAt ?? "")))[0];
6371
6548
  if (!latestRun) {
6372
- const serverRuns = await listRunsViaServer(context, { limit: 200 }).catch(() => []);
6373
- const serverRun = serverRuns.filter((run) => String(run.taskId ?? "") === requiredTask).sort((left, right) => String(right.updatedAt ?? "").localeCompare(String(left.updatedAt ?? "")))[0];
6374
- if (!serverRun || typeof serverRun.runId !== "string") {
6549
+ const fallback = await withSpinner(`Finding runs for ${requiredTask} on the server\u2026`, async (update) => {
6550
+ const serverRuns = await listRunsViaServer(context, { limit: 200 }).catch(() => []);
6551
+ const serverRun = serverRuns.filter((run) => String(run.taskId ?? "") === requiredTask).sort((left, right) => String(right.updatedAt ?? "").localeCompare(String(left.updatedAt ?? "")))[0];
6552
+ if (!serverRun || typeof serverRun.runId !== "string")
6553
+ return null;
6554
+ update(`Reading logs for run ${serverRun.runId}\u2026`);
6555
+ const page = await getRunLogsViaServer(context, serverRun.runId, { limit: 500 });
6556
+ return { runId: serverRun.runId, page };
6557
+ }, { outputMode: context.outputMode });
6558
+ if (!fallback) {
6375
6559
  throw new CliError(`No runs found for ${requiredTask} (local or on the selected server).`, 1, { hint: "Start one with `rig task run --task <id>`, or check `rig run list`." });
6376
6560
  }
6377
- const page = await getRunLogsViaServer(context, serverRun.runId, { limit: 500 });
6378
- const entries = Array.isArray(page.entries) ? page.entries : [];
6561
+ const entries = Array.isArray(fallback.page.entries) ? fallback.page.entries : [];
6379
6562
  if (context.outputMode === "text") {
6380
6563
  for (const entry of entries) {
6381
6564
  const record = entry && typeof entry === "object" ? entry : {};
@@ -6384,9 +6567,9 @@ async function executeInspect(context, args) {
6384
6567
  console.log([title, detail].filter(Boolean).join(" \u2014 "));
6385
6568
  }
6386
6569
  if (entries.length === 0)
6387
- console.log(`(no log entries for run ${serverRun.runId})`);
6570
+ console.log(`(no log entries for run ${fallback.runId})`);
6388
6571
  }
6389
- return { ok: true, group: "inspect", command, details: { task: requiredTask, runId: serverRun.runId, source: "server", entries } };
6572
+ return { ok: true, group: "inspect", command, details: { task: requiredTask, runId: fallback.runId, source: "server", entries } };
6390
6573
  }
6391
6574
  const logsPath = resolve19(resolveAuthorityRunDir2(context.projectRoot, latestRun.runId), "logs.jsonl");
6392
6575
  if (!existsSync12(logsPath)) {
@@ -6444,7 +6627,7 @@ async function executeInspect(context, args) {
6444
6627
  const { value: task, rest: remaining } = takeOption(rest, "--task");
6445
6628
  requireNoExtraArgs(remaining, "rig inspect diff [--task <task-id>]");
6446
6629
  if (task) {
6447
- const files = changedFilesForTask(context.projectRoot, task, false);
6630
+ const files = await withSpinner(`Computing changed files for ${task}\u2026`, async () => changedFilesForTask(context.projectRoot, task, false), { outputMode: context.outputMode });
6448
6631
  for (const file of files) {
6449
6632
  console.log(file);
6450
6633
  }
@@ -7125,8 +7308,6 @@ import {
7125
7308
  deleteRunState,
7126
7309
  listOpenEpics,
7127
7310
  resolveDefaultEpic,
7128
- runResume,
7129
- runRestart,
7130
7311
  runStatus,
7131
7312
  runStop,
7132
7313
  startRun,
@@ -7532,7 +7713,12 @@ async function attachRunBundledPiFrontend(context, input) {
7532
7713
  };
7533
7714
  let detached = false;
7534
7715
  try {
7535
- await runPiMain([], {
7716
+ await runPiMain([
7717
+ "--no-extensions",
7718
+ "--no-skills",
7719
+ "--no-prompt-templates",
7720
+ "--no-context-files"
7721
+ ], {
7536
7722
  extensionFactories: [piRigExtensionFactory]
7537
7723
  });
7538
7724
  detached = true;
@@ -7597,8 +7783,9 @@ async function readOperatorSnapshot(context, runId, options = {}) {
7597
7783
  }
7598
7784
  async function attachRunOperatorView(context, input) {
7599
7785
  let steered = false;
7600
- if (input.message?.trim()) {
7601
- await sendRunPiPromptViaServer(context, input.runId, input.message.trim(), "steer").catch(() => steerRunViaServer(context, input.runId, input.message.trim()));
7786
+ const attachMessage = input.message?.trim();
7787
+ if (attachMessage) {
7788
+ await withSpinner("Queueing steering message\u2026", () => sendRunPiPromptViaServer(context, input.runId, attachMessage, "steer").catch(() => steerRunViaServer(context, input.runId, attachMessage)), { outputMode: context.outputMode });
7602
7789
  steered = true;
7603
7790
  }
7604
7791
  if (input.follow && !input.once && input.interactive !== false && context.outputMode === "text" && Boolean(process.stdin.isTTY && process.stdout.isTTY)) {
@@ -7608,7 +7795,7 @@ async function attachRunOperatorView(context, input) {
7608
7795
  });
7609
7796
  }
7610
7797
  const surface = createOperatorSurface({ interactive: input.interactive !== false });
7611
- let snapshot = await readOperatorSnapshot(context, input.runId);
7798
+ let snapshot = await withSpinner(`Connecting to run ${input.runId}\u2026`, () => readOperatorSnapshot(context, input.runId), { outputMode: context.outputMode });
7612
7799
  if (context.outputMode === "text") {
7613
7800
  surface.renderSnapshot(snapshot);
7614
7801
  surface.renderTimeline(snapshot.timeline);
@@ -7739,7 +7926,7 @@ async function executeRun(context, args) {
7739
7926
  switch (command) {
7740
7927
  case "list": {
7741
7928
  requireNoExtraArgs(rest, "rig run list");
7742
- const { runs, source } = await listRunsForSelectedConnection(context, { limit: 100 });
7929
+ const { runs, source } = isRemoteConnectionSelected(context.projectRoot) ? await withSpinner("Reading runs from server\u2026", () => listRunsForSelectedConnection(context, { limit: 100 }), { outputMode: context.outputMode }) : await listRunsForSelectedConnection(context, { limit: 100 });
7743
7930
  if (context.outputMode === "text") {
7744
7931
  printFormattedOutput(formatRunList(runs, { source }));
7745
7932
  await printPendingInboxFooter(context);
@@ -7812,7 +7999,7 @@ async function executeRun(context, args) {
7812
7999
  if (!runId) {
7813
8000
  throw new CliError("run show requires a run id.", 1, { hint: "Run `rig run list` to find run ids, then `rig run show <run-id>`." });
7814
8001
  }
7815
- const record = readAuthorityRun5(context.projectRoot, runId) ?? normalizeRemoteRunDetails(await getRunDetailsViaServer(context, runId).catch(() => ({})));
8002
+ const record = readAuthorityRun5(context.projectRoot, runId) ?? normalizeRemoteRunDetails(await withSpinner(`Reading run ${runId} from server\u2026`, () => getRunDetailsViaServer(context, runId).catch(() => ({})), { outputMode: context.outputMode }));
7816
8003
  if (!record) {
7817
8004
  throw new CliError(`Run not found: ${runId}`, 2, { hint: "Run `rig run list` to see recorded runs." });
7818
8005
  }
@@ -7833,7 +8020,8 @@ async function executeRun(context, args) {
7833
8020
  }
7834
8021
  const renderer = createPiRunStreamRenderer();
7835
8022
  let cursor = null;
7836
- const page = await getRunTimelineViaServer(context, run.value, { limit: 500 });
8023
+ const timelineRunId = run.value;
8024
+ const page = await withSpinner(`Reading timeline for ${timelineRunId}\u2026`, () => getRunTimelineViaServer(context, timelineRunId, { limit: 500 }), { outputMode: context.outputMode });
7837
8025
  const events = Array.isArray(page.entries) ? page.entries.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
7838
8026
  cursor = typeof page.nextCursor === "string" ? page.nextCursor : null;
7839
8027
  if (context.outputMode === "text") {
@@ -7910,8 +8098,9 @@ async function executeRun(context, args) {
7910
8098
  throw new CliError("run attach requires a run id.", 2, { hint: "Run `rig run list` to find run ids, then `rig run attach <run-id> --follow`." });
7911
8099
  }
7912
8100
  let steered = false;
7913
- if (messageOption.value?.trim()) {
7914
- await steerRunViaServer(context, runId, messageOption.value.trim());
8101
+ const steerMessage = messageOption.value?.trim();
8102
+ if (steerMessage) {
8103
+ await withSpinner("Queueing steering message\u2026", () => steerRunViaServer(context, runId, steerMessage), { outputMode: context.outputMode });
7915
8104
  steered = true;
7916
8105
  }
7917
8106
  const attached = await attachRunOperatorView(context, {
@@ -7931,7 +8120,7 @@ async function executeRun(context, args) {
7931
8120
  }
7932
8121
  return { ok: true, group: "run", command };
7933
8122
  }
7934
- const summary = isRemoteConnectionSelected(context.projectRoot) ? buildServerRunStatus(await listRunsViaServer(context, { limit: 100 })) : runStatus(context.projectRoot, runtimeContext);
8123
+ const summary = isRemoteConnectionSelected(context.projectRoot) ? buildServerRunStatus(await withSpinner("Reading run status from server\u2026", () => listRunsViaServer(context, { limit: 100 }), { outputMode: context.outputMode })) : runStatus(context.projectRoot, runtimeContext);
7935
8124
  const activeRuns = Array.isArray(summary.activeRuns) ? summary.activeRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
7936
8125
  const recentRuns = Array.isArray(summary.recentRuns) ? summary.recentRuns.filter((run) => Boolean(run && typeof run === "object" && !Array.isArray(run))) : [];
7937
8126
  if (context.outputMode === "text") {
@@ -8020,7 +8209,7 @@ async function executeRun(context, args) {
8020
8209
  }
8021
8210
  return { ok: true, group: "run", command };
8022
8211
  }
8023
- const resumed = await runResume(context.projectRoot, runtimeContext, targetRunId);
8212
+ const resumed = await withSpinner(targetRunId ? `Resuming run ${targetRunId}\u2026` : "Resuming latest resumable run\u2026", () => resumeRunViaServer(context, targetRunId, { restart: false }), { outputMode: context.outputMode });
8024
8213
  if (context.outputMode === "text") {
8025
8214
  console.log(`Resumed run: ${resumed.runId}`);
8026
8215
  }
@@ -8039,7 +8228,7 @@ async function executeRun(context, args) {
8039
8228
  }
8040
8229
  return { ok: true, group: "run", command };
8041
8230
  }
8042
- const restarted = await runRestart(context.projectRoot, runtimeContext, targetRunId);
8231
+ const restarted = await withSpinner(targetRunId ? `Restarting run ${targetRunId}\u2026` : "Restarting latest run\u2026", () => resumeRunViaServer(context, targetRunId, { restart: true }), { outputMode: context.outputMode });
8043
8232
  if (context.outputMode === "text") {
8044
8233
  console.log(`Restarted run: ${restarted.runId}`);
8045
8234
  }
@@ -8066,7 +8255,8 @@ async function executeRun(context, args) {
8066
8255
  }
8067
8256
  return { ok: true, group: "run", command, details: { runId, dryRun: true } };
8068
8257
  }
8069
- await steerRunViaServer(context, runId, message2.trim());
8258
+ const trimmedMessage = message2.trim();
8259
+ await withSpinner("Queueing steering message\u2026", () => steerRunViaServer(context, runId, trimmedMessage), { outputMode: context.outputMode });
8070
8260
  if (context.outputMode === "text") {
8071
8261
  console.log(`Steering message queued for ${runId}.`);
8072
8262
  }
@@ -8087,7 +8277,7 @@ async function executeRun(context, args) {
8087
8277
  };
8088
8278
  }
8089
8279
  if (runId) {
8090
- const stopped = await stopRunViaServer(context, runId);
8280
+ const stopped = await withSpinner(`Requesting stop for ${runId}\u2026`, () => stopRunViaServer(context, runId), { outputMode: context.outputMode });
8091
8281
  if (context.outputMode === "text")
8092
8282
  console.log(`Stop requested: ${runId}`);
8093
8283
  return { ok: true, group: "run", command, details: stopped };
@@ -8333,12 +8523,12 @@ async function executeServer(context, args, options) {
8333
8523
 
8334
8524
  // packages/cli/src/commands/stats.ts
8335
8525
  init_runner();
8336
- import pc5 from "picocolors";
8526
+ import pc6 from "picocolors";
8337
8527
  import { computeRigStats } from "@rig/runtime/control-plane/native/run-stats";
8338
8528
 
8339
8529
  // packages/cli/src/commands/_help-catalog.ts
8340
8530
  import { intro as intro3, log as log4, note as note4, outro as outro3 } from "@clack/prompts";
8341
- import pc4 from "picocolors";
8531
+ import pc5 from "picocolors";
8342
8532
  var TOP_LEVEL_SECTIONS = [
8343
8533
  {
8344
8534
  title: "Start here",
@@ -8626,13 +8816,13 @@ var ADVANCED_COMMANDS = [
8626
8816
  ];
8627
8817
  var ALL_GROUPS = [...PRIMARY_GROUPS, ...ADVANCED_GROUPS];
8628
8818
  function heading(title) {
8629
- return pc4.bold(pc4.cyan(title));
8819
+ return pc5.bold(pc5.cyan(title));
8630
8820
  }
8631
8821
  function renderRigBanner(version) {
8632
- const m = (s) => pc4.bold(pc4.magenta(s));
8633
- const c = (s) => pc4.bold(pc4.cyan(s));
8634
- const y = (s) => pc4.yellow(s);
8635
- const d = (s) => pc4.dim(s);
8822
+ const m = (s) => pc5.bold(pc5.magenta(s));
8823
+ const c = (s) => pc5.bold(pc5.cyan(s));
8824
+ const y = (s) => pc5.yellow(s);
8825
+ const d = (s) => pc5.dim(s);
8636
8826
  const lines = [
8637
8827
  m(" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ") + d(" \u2591\u2592\u2593\u2588 "),
8638
8828
  m(" \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D ") + d("\u2593\u2592\u2591"),
@@ -8641,7 +8831,7 @@ function renderRigBanner(version) {
8641
8831
  y(" \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D") + d(" \u2592\u2591"),
8642
8832
  y(" \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D "),
8643
8833
  "",
8644
- ` ${c("\u25E2\u25E4")} ${pc4.bold("the control rig for autonomous coding agents")} ${m("//")} ${d("you are the operator")}`,
8834
+ ` ${c("\u25E2\u25E4")} ${pc5.bold("the control rig for autonomous coding agents")} ${m("//")} ${d("you are the operator")}`,
8645
8835
  version ? ` ${d(`v${version} \xB7 jack in: rig task run --next`)}` : ` ${d("jack in: rig task run --next")}`
8646
8836
  ];
8647
8837
  return lines.join(`
@@ -8649,7 +8839,7 @@ function renderRigBanner(version) {
8649
8839
  }
8650
8840
  function commandLine(command, description) {
8651
8841
  const commandColumn = command.length >= 38 ? `${command} ` : command.padEnd(38);
8652
- return `${pc4.dim("\u2502")} ${pc4.bold(commandColumn)} ${description}`;
8842
+ return `${pc5.dim("\u2502")} ${pc5.bold(commandColumn)} ${description}`;
8653
8843
  }
8654
8844
  function renderCommandBlock(commands) {
8655
8845
  return commands.map((entry) => commandLine(entry.command, entry.description)).join(`
@@ -8659,37 +8849,37 @@ function renderGroup(group) {
8659
8849
  const lines = [
8660
8850
  `${heading(`rig ${group.name}`)} \u2014 ${group.summary}`,
8661
8851
  "",
8662
- pc4.bold("Usage"),
8852
+ pc5.bold("Usage"),
8663
8853
  ...group.usage.map((line) => ` ${line}`),
8664
8854
  "",
8665
- pc4.bold("Commands"),
8855
+ pc5.bold("Commands"),
8666
8856
  ...group.commands.map((entry) => commandLine(entry.command, entry.description))
8667
8857
  ];
8668
8858
  if (group.examples?.length) {
8669
- lines.push("", pc4.bold("Examples"), ...group.examples.map((line) => ` ${pc4.dim("$")} ${line}`));
8859
+ lines.push("", pc5.bold("Examples"), ...group.examples.map((line) => ` ${pc5.dim("$")} ${line}`));
8670
8860
  }
8671
8861
  if (group.next?.length) {
8672
- lines.push("", pc4.bold("Next steps"), ...group.next.map((line) => ` ${pc4.dim("\u203A")} ${line}`));
8862
+ lines.push("", pc5.bold("Next steps"), ...group.next.map((line) => ` ${pc5.dim("\u203A")} ${line}`));
8673
8863
  }
8674
8864
  if (group.advanced?.length) {
8675
- lines.push("", pc4.bold("Compatibility / advanced"), ...group.advanced.map((line) => ` ${pc4.dim("\u203A")} ${line}`));
8865
+ lines.push("", pc5.bold("Compatibility / advanced"), ...group.advanced.map((line) => ` ${pc5.dim("\u203A")} ${line}`));
8676
8866
  }
8677
8867
  return lines.join(`
8678
8868
  `);
8679
8869
  }
8680
8870
  function renderTopLevelHelp() {
8681
8871
  return [
8682
- `${heading("rig")} ${pc4.dim("\u2014 server-owned task/run control plane for Pi-backed engineering work")}`,
8683
- pc4.dim("Current path: select a server, choose a task, submit a run, attach with native Pi, clear inbox gates."),
8872
+ `${heading("rig")} ${pc5.dim("\u2014 server-owned task/run control plane for Pi-backed engineering work")}`,
8873
+ pc5.dim("Current path: select a server, choose a task, submit a run, attach with native Pi, clear inbox gates."),
8684
8874
  "",
8685
8875
  ...TOP_LEVEL_SECTIONS.flatMap((section) => [
8686
- `${pc4.bold(pc4.magenta(`\u25C7 ${section.title}`))} \u2014 ${pc4.dim(section.subtitle)}`,
8876
+ `${pc5.bold(pc5.magenta(`\u25C7 ${section.title}`))} \u2014 ${pc5.dim(section.subtitle)}`,
8687
8877
  renderCommandBlock(section.commands),
8688
8878
  ""
8689
8879
  ]),
8690
- pc4.dim("More: `rig help --advanced` for dev/compatibility commands; `rig <group> --help` for rich per-group help; `rig --version` for the installed version."),
8880
+ pc5.dim("More: `rig help --advanced` for dev/compatibility commands; `rig <group> --help` for rich per-group help; `rig --version` for the installed version."),
8691
8881
  "",
8692
- pc4.bold("Global options"),
8882
+ pc5.bold("Global options"),
8693
8883
  commandLine("--project <path>", "Use a project root instead of auto-discovery."),
8694
8884
  commandLine("--json", "Emit structured output for scripts/agents."),
8695
8885
  commandLine("--dry-run", "Print the command plan without mutating state.")
@@ -8700,16 +8890,16 @@ function renderAdvancedHelp() {
8700
8890
  return [
8701
8891
  `${heading("rig advanced")} \u2014 compatibility, diagnostics, and internal surfaces`,
8702
8892
  "",
8703
- pc4.bold("Primary groups"),
8893
+ pc5.bold("Primary groups"),
8704
8894
  " init, server, task, run, inbox, repo, plugin, inspect, stats, doctor, github",
8705
8895
  "",
8706
- pc4.bold("Advanced commands"),
8896
+ pc5.bold("Advanced commands"),
8707
8897
  ...ADVANCED_COMMANDS.map((entry) => commandLine(entry.command, entry.description)),
8708
8898
  "",
8709
- pc4.bold("Advanced groups"),
8899
+ pc5.bold("Advanced groups"),
8710
8900
  ...ADVANCED_GROUPS.map((group) => commandLine(group.name, group.summary)),
8711
8901
  "",
8712
- pc4.dim("All groups remain callable. Prefer `rig server`, `rig task`, `rig run`, and `rig inbox` for day-to-day work.")
8902
+ pc5.dim("All groups remain callable. Prefer `rig server`, `rig task`, `rig run`, and `rig inbox` for day-to-day work.")
8713
8903
  ].join(`
8714
8904
  `);
8715
8905
  }
@@ -8857,11 +9047,11 @@ function formatStatsReport(stats) {
8857
9047
  const keyWidth = Math.max(...rows.map(([key]) => key.length));
8858
9048
  const lines = [
8859
9049
  formatSection("Fleet stats", window),
8860
- ...rows.map(([key, value]) => `${pc5.dim("\u2502")} ${pc5.dim(key.padEnd(keyWidth + 2))} ${value}`)
9050
+ ...rows.map(([key, value]) => `${pc6.dim("\u2502")} ${pc6.dim(key.padEnd(keyWidth + 2))} ${value}`)
8861
9051
  ];
8862
9052
  const otherStatuses = Object.entries(stats.statusCounts).filter(([status]) => !["completed", "failed", "needs-attention"].includes(status)).sort(([, left], [, right]) => right - left);
8863
9053
  if (otherStatuses.length > 0) {
8864
- lines.push(`${pc5.dim("\u2502")} ${pc5.dim("other".padEnd(keyWidth + 2))} ${otherStatuses.map(([status, count]) => `${status}:${count}`).join(" ")}`);
9054
+ lines.push(`${pc6.dim("\u2502")} ${pc6.dim("other".padEnd(keyWidth + 2))} ${otherStatuses.map(([status, count]) => `${status}:${count}`).join(" ")}`);
8865
9055
  }
8866
9056
  lines.push("", ...formatNextSteps([
8867
9057
  "Inspect a run: `rig run list` then `rig run show <run-id>`",
@@ -8880,7 +9070,8 @@ async function executeStats(context, args) {
8880
9070
  const sinceResult = takeOption(pending, "--since");
8881
9071
  requireNoExtraArgs(sinceResult.rest, "rig stats [show] [--since <7d|30d|ISO date>]");
8882
9072
  const since = parseSinceOption(sinceResult.value);
8883
- const stats = isRemoteConnectionSelected(context.projectRoot) ? await requestServerJson(context, `/api/stats${since ? `?since=${encodeURIComponent(since.toISOString())}` : ""}`) : computeRigStats(context.projectRoot, { since });
9073
+ const remoteStats = isRemoteConnectionSelected(context.projectRoot);
9074
+ const stats = await withSpinner(remoteStats ? "Computing fleet stats on the server\u2026" : "Scanning local run state\u2026", async () => remoteStats ? await requestServerJson(context, `/api/stats${since ? `?since=${encodeURIComponent(since.toISOString())}` : ""}`) : computeRigStats(context.projectRoot, { since }), { outputMode: context.outputMode });
8884
9075
  if (context.outputMode === "text") {
8885
9076
  printFormattedOutput(formatStatsReport(stats));
8886
9077
  }
@@ -9135,7 +9326,7 @@ async function executeTask(context, args, options) {
9135
9326
  pending = rawResult.rest;
9136
9327
  const { filters, rest: remaining } = parseTaskFilters(pending);
9137
9328
  requireNoExtraArgs(remaining, "rig task list [--raw] [--assignee <login|me|@me>] [--state open|closed] [--status <status>] [--limit <n>]");
9138
- const tasks = await listWorkspaceTasksViaServer(context, filters);
9329
+ const tasks = await withSpinner("Reading tasks from server\u2026", () => listWorkspaceTasksViaServer(context, filters), { outputMode: context.outputMode });
9139
9330
  if (context.outputMode === "text") {
9140
9331
  const renderedTasks = rawResult.value ? tasks.map((task) => summarizeTask(task, { raw: true })) : tasks.map((task) => summarizeTask(task));
9141
9332
  printFormattedOutput(formatTaskList(renderedTasks, { raw: rawResult.value }));
@@ -9159,7 +9350,7 @@ async function executeTask(context, args, options) {
9159
9350
  const taskId3 = normalizeTaskRunTaskId(taskOption.value ?? positional);
9160
9351
  if (!taskId3)
9161
9352
  throw new CliError("task show requires a task id.", 2, { hint: "Run `rig task list` to find ids, then `rig task show <id>`." });
9162
- const task = await getWorkspaceTaskViaServer(context, taskId3);
9353
+ const task = await withSpinner(`Reading task ${taskId3} from server\u2026`, () => getWorkspaceTaskViaServer(context, taskId3), { outputMode: context.outputMode });
9163
9354
  if (!task)
9164
9355
  throw new CliError(`Task not found: ${taskId3}`, 3, { hint: "Run `rig task list` to see available tasks." });
9165
9356
  const summary = summarizeTask(task, { raw: true });
@@ -9171,7 +9362,7 @@ async function executeTask(context, args, options) {
9171
9362
  case "next": {
9172
9363
  const { filters, rest: remaining } = parseTaskFilters(rest);
9173
9364
  requireNoExtraArgs(remaining, "rig task next [--assignee <login|me|@me>] [--state open|closed] [--status <status>] [--limit <n>]");
9174
- const selected = await selectNextWorkspaceTaskViaServer(context, filters);
9365
+ const selected = await withSpinner("Selecting next ready task\u2026", () => selectNextWorkspaceTaskViaServer(context, filters), { outputMode: context.outputMode });
9175
9366
  if (context.outputMode === "text") {
9176
9367
  if (selected.task) {
9177
9368
  printFormattedOutput(formatTaskCard(summarizeTask(selected.task, { raw: true }), { title: "Selected task", selected: true }));
@@ -9321,7 +9512,7 @@ async function executeTask(context, args, options) {
9321
9512
  let selectedTask = null;
9322
9513
  let selectedTaskId = normalizeTaskRunTaskId(taskResult.value) ?? positionalTaskId;
9323
9514
  if (nextResult.value) {
9324
- const selected = await selectNextWorkspaceTaskViaServer(context, filterResult.filters);
9515
+ const selected = await withSpinner("Selecting next ready task\u2026", () => selectNextWorkspaceTaskViaServer(context, filterResult.filters), { outputMode: context.outputMode });
9325
9516
  selectedTask = selected.task;
9326
9517
  selectedTaskId = selected.task ? readTaskId(selected.task) : null;
9327
9518
  if (!selectedTaskId) {
@@ -9332,7 +9523,7 @@ async function executeTask(context, args, options) {
9332
9523
  if (context.outputMode !== "text" || !process.stdin.isTTY || !process.stdout.isTTY) {
9333
9524
  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);
9334
9525
  }
9335
- const tasks = await listWorkspaceTasksViaServer(context, filterResult.filters);
9526
+ const tasks = await withSpinner("Reading tasks from server\u2026", () => listWorkspaceTasksViaServer(context, filterResult.filters), { outputMode: context.outputMode });
9336
9527
  selectedTask = await selectTaskWithTextPicker(tasks);
9337
9528
  selectedTaskId = selectedTask ? readTaskId(selectedTask) : null;
9338
9529
  if (!selectedTaskId) {
@@ -9342,13 +9533,13 @@ async function executeTask(context, args, options) {
9342
9533
  await runProjectMainSyncPreflight(context, { disabled: skipProjectSyncResult.value });
9343
9534
  const projectDefaults = await loadTaskRunProjectDefaults(context.projectRoot);
9344
9535
  const runtimeAdapter = normalizeRuntimeAdapter(runtimeAdapterResult.value ?? projectDefaults.runtimeAdapter);
9345
- await runFastTaskRunPreflight(context, {
9536
+ await withSpinner("Running task-run preflight\u2026", () => runFastTaskRunPreflight(context, {
9346
9537
  taskId: selectedTaskId,
9347
9538
  runtimeAdapter
9348
- });
9539
+ }), { outputMode: context.outputMode });
9349
9540
  const dirtyBaseline = await resolveDirtyBaselineForTaskRun(context, dirtyBaselineResult.value);
9350
9541
  const prMode = noPrResult.value ? "off" : normalizePrMode(prResult.value) ?? projectDefaults.prMode;
9351
- const submitted = await submitTaskRunViaServer(context, {
9542
+ const submitted = await withSpinner("Dispatching run\u2026", () => submitTaskRunViaServer(context, {
9352
9543
  runId: context.runId,
9353
9544
  taskId: selectedTaskId ?? undefined,
9354
9545
  title: titleResult.value ?? undefined,
@@ -9359,7 +9550,7 @@ async function executeTask(context, args, options) {
9359
9550
  initialPrompt: initialPromptResult.value ?? undefined,
9360
9551
  baselineMode: dirtyBaseline.mode,
9361
9552
  prMode
9362
- });
9553
+ }), { outputMode: context.outputMode });
9363
9554
  let attachDetails = null;
9364
9555
  if (!detachResult.value && context.outputMode === "text") {
9365
9556
  printFormattedOutput(formatSubmittedRun({
@@ -11537,7 +11728,7 @@ async function executeSetup(context, args) {
11537
11728
  case "check":
11538
11729
  requireNoExtraArgs(rest, `rig setup ${command}`);
11539
11730
  {
11540
- const checks = await withMutedConsole(context.outputMode === "json", () => runSetupCheck(context.projectRoot));
11731
+ const checks = await withMutedConsole(context.outputMode === "json", () => runSetupCheck(context.projectRoot, context.outputMode));
11541
11732
  return { ok: true, group: "setup", command, details: { checks, failures: countDoctorFailures(checks) } };
11542
11733
  }
11543
11734
  case "setup":
@@ -11546,7 +11737,7 @@ async function executeSetup(context, args) {
11546
11737
  return { ok: true, group: "setup", command };
11547
11738
  case "preflight":
11548
11739
  requireNoExtraArgs(rest, "rig setup preflight");
11549
- await withMutedConsole(context.outputMode === "json", () => runSetupPreflight(context.projectRoot));
11740
+ await withMutedConsole(context.outputMode === "json", () => runSetupPreflight(context.projectRoot, context.outputMode));
11550
11741
  return { ok: true, group: "setup", command };
11551
11742
  default:
11552
11743
  throw new CliError(`Unknown setup command: ${command}`, 1, { hint: "Run `rig setup --help` \u2014 commands are bootstrap|check|preflight." });
@@ -11567,8 +11758,8 @@ function runSetupInit(projectRoot) {
11567
11758
  }
11568
11759
  console.log("Harness directories ready.");
11569
11760
  }
11570
- async function runSetupCheck(projectRoot) {
11571
- const doctorChecks = await runRigDoctorChecks({ projectRoot });
11761
+ async function runSetupCheck(projectRoot, outputMode = "text") {
11762
+ const doctorChecks = await withSpinner("Running setup checks\u2026", (update) => runRigDoctorChecks({ projectRoot, onProgress: update }), { outputMode });
11572
11763
  console.log(formatDoctorChecks(doctorChecks));
11573
11764
  const failures = countDoctorFailures(doctorChecks);
11574
11765
  if (failures > 0) {
@@ -11576,8 +11767,8 @@ async function runSetupCheck(projectRoot) {
11576
11767
  }
11577
11768
  return doctorChecks;
11578
11769
  }
11579
- async function runSetupPreflight(projectRoot) {
11580
- await runSetupCheck(projectRoot);
11770
+ async function runSetupPreflight(projectRoot, outputMode = "text") {
11771
+ await runSetupCheck(projectRoot, outputMode);
11581
11772
  const validationRoot = resolve23(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
11582
11773
  if (existsSync15(validationRoot)) {
11583
11774
  const validators = readdirSync3(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());