@h-rig/cli 0.0.6-alpha.7 → 0.0.6-alpha.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/rig.js +4507 -1506
  3. package/dist/src/commands/_async-ui.js +152 -0
  4. package/dist/src/commands/_authority-runs.js +2 -3
  5. package/dist/src/commands/_cli-format.js +369 -0
  6. package/dist/src/commands/_connection-state.js +30 -11
  7. package/dist/src/commands/_doctor-checks.js +177 -43
  8. package/dist/src/commands/_help-catalog.js +485 -0
  9. package/dist/src/commands/_json-output.js +56 -0
  10. package/dist/src/commands/_operator-surface.js +220 -0
  11. package/dist/src/commands/_operator-view.js +595 -72
  12. package/dist/src/commands/_parsers.js +18 -11
  13. package/dist/src/commands/_pi-frontend.js +411 -0
  14. package/dist/src/commands/_pi-install.js +4 -3
  15. package/dist/src/commands/_policy.js +12 -5
  16. package/dist/src/commands/_preflight.js +187 -127
  17. package/dist/src/commands/_run-driver-helpers.js +75 -22
  18. package/dist/src/commands/_run-replay.js +142 -0
  19. package/dist/src/commands/_server-client.js +343 -60
  20. package/dist/src/commands/_snapshot-upload.js +160 -38
  21. package/dist/src/commands/_spinner.js +65 -0
  22. package/dist/src/commands/_task-picker.js +44 -16
  23. package/dist/src/commands/agent.js +39 -20
  24. package/dist/src/commands/browser.js +28 -21
  25. package/dist/src/commands/connect.js +146 -33
  26. package/dist/src/commands/dist.js +19 -12
  27. package/dist/src/commands/doctor.js +304 -44
  28. package/dist/src/commands/github.js +301 -52
  29. package/dist/src/commands/inbox.js +679 -72
  30. package/dist/src/commands/init.js +622 -118
  31. package/dist/src/commands/inspect.js +515 -32
  32. package/dist/src/commands/inspector.js +20 -13
  33. package/dist/src/commands/pi.js +177 -0
  34. package/dist/src/commands/plugin.js +95 -27
  35. package/dist/src/commands/profile-and-review.js +26 -19
  36. package/dist/src/commands/queue.js +32 -12
  37. package/dist/src/commands/remote.js +43 -36
  38. package/dist/src/commands/repo-git-harness.js +22 -15
  39. package/dist/src/commands/run.js +1162 -158
  40. package/dist/src/commands/server.js +373 -56
  41. package/dist/src/commands/setup.js +316 -62
  42. package/dist/src/commands/stats.js +1030 -0
  43. package/dist/src/commands/task-report-bug.js +29 -22
  44. package/dist/src/commands/task-run-driver.js +862 -129
  45. package/dist/src/commands/task.js +1423 -311
  46. package/dist/src/commands/test.js +15 -8
  47. package/dist/src/commands/workspace.js +18 -11
  48. package/dist/src/commands.js +4446 -1499
  49. package/dist/src/index.js +4502 -1504
  50. package/dist/src/launcher.js +77 -13
  51. package/dist/src/report-bug.js +3 -3
  52. package/dist/src/runner.js +16 -22
  53. package/package.json +10 -5
@@ -7,12 +7,19 @@ import { resolve as resolve4 } from "path";
7
7
 
8
8
  // packages/cli/src/runner.ts
9
9
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
10
- import { CliError } from "@rig/runtime/control-plane/errors";
10
+ import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
11
11
  import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
12
- import { PluginManager } from "@rig/runtime/control-plane/runtime/plugins";
13
- import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/context";
14
12
  import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
15
- import { CliError as CliError2 } from "@rig/runtime/control-plane/errors";
13
+
14
+ class CliError extends RuntimeCliError {
15
+ hint;
16
+ constructor(message, exitCode = 1, options = {}) {
17
+ super(message, exitCode);
18
+ if (options.hint?.trim()) {
19
+ this.hint = options.hint.trim();
20
+ }
21
+ }
22
+ }
16
23
 
17
24
  // packages/cli/src/commands/_doctor-checks.ts
18
25
  import { isSupportedBunVersion, MIN_SUPPORTED_BUN_VERSION } from "@rig/runtime/control-plane/setup-version";
@@ -39,9 +46,14 @@ function readJsonFile(path) {
39
46
  try {
40
47
  return JSON.parse(readFileSync(path, "utf8"));
41
48
  } catch (error) {
42
- throw new CliError2(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1);
49
+ throw new CliError(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1, { hint: "Fix or delete that file, then re-select a server with `rig server use <alias|local>`." });
43
50
  }
44
51
  }
52
+ function writeJsonFile(path, value) {
53
+ mkdirSync(dirname(path), { recursive: true });
54
+ writeFileSync(path, `${JSON.stringify(value, null, 2)}
55
+ `, "utf8");
56
+ }
45
57
  function normalizeConnection(value) {
46
58
  if (!value || typeof value !== "object" || Array.isArray(value))
47
59
  return null;
@@ -82,29 +94,42 @@ function readRepoConnection(projectRoot) {
82
94
  return {
83
95
  selected,
84
96
  project: typeof record.project === "string" ? record.project : undefined,
85
- linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
97
+ linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
98
+ serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
86
99
  };
87
100
  }
101
+ function writeRepoConnection(projectRoot, state) {
102
+ writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
103
+ }
88
104
  function resolveSelectedConnection(projectRoot, options = {}) {
89
105
  const repo = readRepoConnection(projectRoot);
90
106
  if (!repo)
91
107
  return null;
92
108
  if (repo.selected === "local")
93
- return { alias: "local", connection: { kind: "local", mode: "auto" } };
109
+ return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
94
110
  const global = readGlobalConnections(options);
95
111
  const connection = global.connections[repo.selected];
96
112
  if (!connection) {
97
- throw new CliError2(`Selected Rig connection "${repo.selected}" was not found. Run \`rig connect list\` or \`rig connect use local\`.`, 1);
113
+ throw new CliError(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
98
114
  }
99
- return { alias: repo.selected, connection };
115
+ return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
116
+ }
117
+ function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
118
+ const repo = readRepoConnection(projectRoot);
119
+ if (!repo)
120
+ return;
121
+ writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
100
122
  }
101
123
 
102
124
  // packages/cli/src/commands/_server-client.ts
103
- import { spawnSync } from "child_process";
104
125
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
105
126
  import { resolve as resolve2 } from "path";
106
127
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
107
- var cachedGitHubBearerToken;
128
+ var scopedGitHubBearerTokens = new Map;
129
+ var serverPhaseListener = null;
130
+ function reportServerPhase(label) {
131
+ serverPhaseListener?.(label);
132
+ }
108
133
  function cleanToken(value) {
109
134
  const trimmed = value?.trim();
110
135
  return trimmed ? trimmed : null;
@@ -121,49 +146,80 @@ function readPrivateRemoteSessionToken(projectRoot) {
121
146
  }
122
147
  }
123
148
  function readGitHubBearerTokenForRemote(projectRoot) {
124
- if (cachedGitHubBearerToken !== undefined)
125
- return cachedGitHubBearerToken;
149
+ const scopedKey = resolve2(projectRoot);
150
+ if (scopedGitHubBearerTokens.has(scopedKey))
151
+ return scopedGitHubBearerTokens.get(scopedKey) ?? null;
126
152
  const privateSession = readPrivateRemoteSessionToken(projectRoot);
127
- if (privateSession) {
128
- cachedGitHubBearerToken = privateSession;
129
- return cachedGitHubBearerToken;
130
- }
131
- const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
132
- if (envToken) {
133
- cachedGitHubBearerToken = envToken;
134
- return cachedGitHubBearerToken;
153
+ if (privateSession)
154
+ return privateSession;
155
+ return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
156
+ }
157
+ function readStoredGitHubAuthToken(projectRoot) {
158
+ const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
159
+ if (!existsSync2(path))
160
+ return null;
161
+ try {
162
+ const parsed = JSON.parse(readFileSync2(path, "utf8"));
163
+ return cleanToken(typeof parsed.token === "string" ? parsed.token : undefined);
164
+ } catch {
165
+ return null;
135
166
  }
136
- const result = spawnSync("gh", ["auth", "token"], {
137
- encoding: "utf8",
138
- timeout: 5000,
139
- stdio: ["ignore", "pipe", "ignore"]
140
- });
141
- cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
142
- return cachedGitHubBearerToken;
167
+ }
168
+ function readLocalConnectionFallbackToken(projectRoot) {
169
+ return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
143
170
  }
144
171
  async function ensureServerForCli(projectRoot) {
145
172
  try {
146
173
  const selected = resolveSelectedConnection(projectRoot);
147
174
  if (selected?.connection.kind === "remote") {
175
+ reportServerPhase(`Connecting to ${selected.alias}\u2026`);
176
+ const authToken = readGitHubBearerTokenForRemote(projectRoot);
177
+ const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
148
178
  return {
149
179
  baseUrl: selected.connection.baseUrl,
150
- authToken: readGitHubBearerTokenForRemote(projectRoot),
151
- connectionKind: "remote"
180
+ authToken,
181
+ connectionKind: "remote",
182
+ serverProjectRoot
152
183
  };
153
184
  }
185
+ reportServerPhase("Starting local Rig server\u2026");
154
186
  const connection = await ensureLocalRigServerConnection(projectRoot);
155
187
  return {
156
188
  baseUrl: connection.baseUrl,
157
- authToken: connection.authToken,
158
- connectionKind: "local"
189
+ authToken: connection.authToken ?? readLocalConnectionFallbackToken(projectRoot),
190
+ connectionKind: "local",
191
+ serverProjectRoot: resolve2(projectRoot)
159
192
  };
160
193
  } catch (error) {
161
194
  if (error instanceof Error) {
162
- throw new CliError2(error.message, 1);
195
+ throw new CliError(error.message, 1);
163
196
  }
164
197
  throw error;
165
198
  }
166
199
  }
200
+ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
201
+ const repo = readRepoConnection(projectRoot);
202
+ const slug = repo?.project?.trim();
203
+ if (!slug)
204
+ return null;
205
+ try {
206
+ const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
207
+ headers: mergeHeaders(undefined, authToken)
208
+ });
209
+ if (!response.ok)
210
+ return null;
211
+ const payload = await response.json();
212
+ const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
213
+ const checkouts = Array.isArray(project?.checkouts) ? project.checkouts : [];
214
+ const latestCheckout = [...checkouts].reverse().find((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.path === "string"));
215
+ const path = typeof latestCheckout?.path === "string" && latestCheckout.path.trim() ? latestCheckout.path.trim() : null;
216
+ if (path)
217
+ writeRepoServerProjectRoot(projectRoot, path);
218
+ return path;
219
+ } catch {
220
+ return null;
221
+ }
222
+ }
167
223
  function mergeHeaders(headers, authToken) {
168
224
  const merged = new Headers(headers);
169
225
  if (authToken) {
@@ -186,12 +242,65 @@ function diagnosticMessage(payload) {
186
242
  });
187
243
  return messages.length > 0 ? messages.join("; ") : null;
188
244
  }
245
+ var serverReachabilityCache = new Map;
246
+ async function probeServerReachability(baseUrl, authToken) {
247
+ try {
248
+ const response = await fetch(`${baseUrl.replace(/\/+$/, "")}/api/server/status`, {
249
+ headers: mergeHeaders(undefined, authToken),
250
+ signal: AbortSignal.timeout(1500)
251
+ });
252
+ return response.ok;
253
+ } catch {
254
+ return false;
255
+ }
256
+ }
257
+ function cachedServerReachability(projectRoot, baseUrl, authToken) {
258
+ const key = resolve2(projectRoot);
259
+ const cached = serverReachabilityCache.get(key);
260
+ if (cached)
261
+ return cached;
262
+ const probe = probeServerReachability(baseUrl, authToken);
263
+ serverReachabilityCache.set(key, probe);
264
+ return probe;
265
+ }
266
+ function describeSelectedServer(projectRoot, server) {
267
+ try {
268
+ const selected = resolveSelectedConnection(projectRoot);
269
+ if (selected) {
270
+ return {
271
+ alias: selected.alias,
272
+ target: selected.connection.kind === "remote" ? selected.connection.baseUrl : server.baseUrl
273
+ };
274
+ }
275
+ } catch {}
276
+ return { alias: server.connectionKind === "remote" ? "remote" : "local", target: server.baseUrl };
277
+ }
278
+ async function buildServerFailureContext(projectRoot, server) {
279
+ const { alias, target } = describeSelectedServer(projectRoot, server);
280
+ const reachable = await cachedServerReachability(projectRoot, server.baseUrl, server.authToken);
281
+ const reachability = reachable ? "server is reachable" : "server is unreachable";
282
+ return {
283
+ contextLine: `Currently connected to: ${alias} at ${target} (${reachability}).`,
284
+ hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
285
+ };
286
+ }
189
287
  async function requestServerJson(context, pathname, init = {}) {
190
288
  const server = await ensureServerForCli(context.projectRoot);
191
- const response = await fetch(`${server.baseUrl}${pathname}`, {
192
- ...init,
193
- headers: mergeHeaders(init.headers, server.authToken)
194
- });
289
+ const headers = mergeHeaders(init.headers, server.authToken);
290
+ if (server.serverProjectRoot)
291
+ headers.set("x-rig-project-root", server.serverProjectRoot);
292
+ reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
293
+ let response;
294
+ try {
295
+ response = await fetch(`${server.baseUrl}${pathname}`, {
296
+ ...init,
297
+ headers
298
+ });
299
+ } catch (error) {
300
+ const failure = await buildServerFailureContext(context.projectRoot, server);
301
+ throw new CliError(`Rig server request failed: ${error instanceof Error ? error.message : String(error)}
302
+ ${failure.contextLine}`, 1, { hint: failure.hint });
303
+ }
195
304
  const text = await response.text();
196
305
  const payload = text.trim().length > 0 ? (() => {
197
306
  try {
@@ -203,10 +312,23 @@ async function requestServerJson(context, pathname, init = {}) {
203
312
  if (!response.ok) {
204
313
  const diagnostics = diagnosticMessage(payload);
205
314
  const detail = diagnostics ?? (text || response.statusText);
206
- throw new CliError2(`Rig server request failed (${response.status}): ${detail}`, 1);
315
+ const failure = await buildServerFailureContext(context.projectRoot, server);
316
+ throw new CliError(`Rig server request failed (${response.status}): ${detail}
317
+ ${failure.contextLine}`, 1, { hint: failure.hint });
207
318
  }
208
319
  return payload;
209
320
  }
321
+ var RESUMABLE_RUN_STATUSES = new Set([
322
+ "created",
323
+ "preparing",
324
+ "running",
325
+ "validating",
326
+ "reviewing",
327
+ "stopped",
328
+ "failed",
329
+ "needs-attention",
330
+ "needs_attention"
331
+ ]);
210
332
 
211
333
  // packages/cli/src/commands/_parsers.ts
212
334
  async function loadRigConfigOrNull(projectRoot) {
@@ -222,7 +344,8 @@ async function loadRigConfigOrNull(projectRoot) {
222
344
  import { existsSync as existsSync3, readFileSync as readFileSync3, rmSync } from "fs";
223
345
  import { homedir as homedir2 } from "os";
224
346
  import { resolve as resolve3 } from "path";
225
- var PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
347
+ var PI_RIG_PACKAGE_NAME = "@h-rig/pi-rig";
348
+ var LEGACY_PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
226
349
  async function defaultCommandRunner(command, options = {}) {
227
350
  const proc = Bun.spawn(command, { cwd: options.cwd, stdout: "pipe", stderr: "pipe" });
228
351
  const [stdout, stderr, exitCode] = await Promise.all([
@@ -241,7 +364,7 @@ function resolvePiHomeDir(inputHomeDir) {
241
364
  function piListContainsPiRig(output) {
242
365
  return output.split(/\r?\n/).some((line) => {
243
366
  const normalized = line.trim();
244
- return normalized.includes(PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
367
+ return normalized.includes(PI_RIG_PACKAGE_NAME) || normalized.includes(LEGACY_PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
245
368
  });
246
369
  }
247
370
  async function safeRun(runner, command, options) {
@@ -409,7 +532,10 @@ async function runRigDoctorChecks(options) {
409
532
  const bunVersion = options.bunVersion ?? Bun.version;
410
533
  const request = options.requestJson ?? ((pathname, init) => requestServerJson({ projectRoot }, pathname, init));
411
534
  const loadConfig = options.loadConfig ?? loadRigConfigOrNull;
535
+ const progress = options.onProgress ?? (() => {});
536
+ progress("Checking local toolchain\u2026");
412
537
  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`)."));
538
+ progress("Loading rig.config\u2026");
413
539
  const loadedConfig = await loadConfig(projectRoot).catch(() => null);
414
540
  const config = loadedConfig ?? loadFallbackConfig(projectRoot);
415
541
  const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync4(resolve4(projectRoot, name)));
@@ -417,7 +543,7 @@ async function runRigDoctorChecks(options) {
417
543
  const taskSourceKind = config?.taskSource?.kind;
418
544
  checks.push(taskSourceKind ? check("task-source", "task source configured", "pass", taskSourceKind) : check("task-source", "task source configured", "fail", "missing taskSource", "Configure taskSource in rig.config.ts."));
419
545
  const repo = readRepoConnection(projectRoot);
420
- checks.push(repo ? check("project-link", "repo selected Rig connection", repo.project ? "pass" : "warn", `${repo.selected}${repo.project ? ` -> ${repo.project}` : ""}`, "Run `rig init --yes --repo owner/repo` to link this checkout to a GitHub repo slug.") : check("project-link", "repo selected Rig connection", "fail", "missing .rig/state/connection.json", "Run `rig init` or `rig connect use <alias|local>`."));
546
+ checks.push(repo ? check("project-link", "repo selected Rig server", repo.project ? "pass" : "warn", `${repo.selected}${repo.project ? ` -> ${repo.project}` : ""}`, "Run `rig init --yes --repo owner/repo` to link this checkout to a GitHub repo slug.") : check("project-link", "repo selected Rig server", "fail", "missing .rig/state/connection.json", "Run `rig init` or `rig server use <alias|local>`."));
421
547
  const selected = (() => {
422
548
  try {
423
549
  return resolveSelectedConnection(projectRoot);
@@ -425,9 +551,10 @@ async function runRigDoctorChecks(options) {
425
551
  return null;
426
552
  }
427
553
  })();
428
- checks.push(selected ? check("connection", "selected server connection", "pass", selected.connection.kind === "remote" ? selected.connection.baseUrl : "local auto") : check("connection", "selected server connection", repo ? "fail" : "warn", repo ? "selected alias is missing" : "will auto-start local server", repo ? "Run `rig connect list` and `rig connect use <alias|local>`." : undefined));
554
+ 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));
429
555
  let server = null;
430
556
  try {
557
+ progress("Connecting to the selected Rig server\u2026");
431
558
  server = await (options.resolveServer ?? ensureServerForCli)(projectRoot);
432
559
  checks.push(check("server", "Rig server reachable", "pass", `${server.connectionKind} ${server.baseUrl}`));
433
560
  } catch (error) {
@@ -435,18 +562,21 @@ async function runRigDoctorChecks(options) {
435
562
  }
436
563
  if (server || options.requestJson) {
437
564
  try {
565
+ progress("Checking server status\u2026");
438
566
  const status = await request("/api/server/status");
439
567
  checks.push(check("server-status", "server project status", "pass", JSON.stringify(status).slice(0, 180)));
440
568
  } catch (error) {
441
569
  checks.push(check("server-status", "server project status", "fail", errorMessage(error), "Run `rig doctor` after the selected server is reachable."));
442
570
  }
443
571
  try {
572
+ progress("Checking GitHub auth\u2026");
444
573
  const auth = await request("/api/github/auth/status");
445
574
  checks.push(isAuthenticated(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>`."));
446
575
  } catch (error) {
447
576
  checks.push(check("github-auth", "GitHub auth", "fail", errorMessage(error), "Authenticate GitHub through Rig and ensure the server exposes auth status."));
448
577
  }
449
578
  try {
579
+ progress("Checking GitHub repo permissions\u2026");
450
580
  const permissions = await request("/api/github/repo/permissions");
451
581
  const allowed = permissionAllowsPr(permissions);
452
582
  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."));
@@ -454,6 +584,7 @@ async function runRigDoctorChecks(options) {
454
584
  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."));
455
585
  }
456
586
  try {
587
+ progress("Checking GitHub issue labels\u2026");
457
588
  const labels = await request("/api/workspace/task-labels");
458
589
  const ready = labelsReady(labels);
459
590
  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."));
@@ -461,6 +592,7 @@ async function runRigDoctorChecks(options) {
461
592
  checks.push(check("task-labels", "GitHub issue labels", "warn", errorMessage(error), "Run `rig init`/`rig doctor` after label setup is wired on the server."));
462
593
  }
463
594
  try {
595
+ progress("Checking task projection\u2026");
464
596
  const projection = await request("/api/workspace/task-projection");
465
597
  checks.push(check("task-projection", "task projection", "pass", JSON.stringify(projection).slice(0, 180)));
466
598
  } catch (error) {
@@ -469,6 +601,7 @@ async function runRigDoctorChecks(options) {
469
601
  const slug = projectStatusSlug(projectRoot, config);
470
602
  if (slug) {
471
603
  try {
604
+ progress("Checking server project checkout\u2026");
472
605
  const project = await request(`/api/projects/${encodeURIComponent(slug)}`);
473
606
  checks.push(check("remote-checkout", "server project checkout", "pass", JSON.stringify(project).slice(0, 180)));
474
607
  } catch (error) {
@@ -483,6 +616,7 @@ async function runRigDoctorChecks(options) {
483
616
  }
484
617
  checks.push(githubProjectsCheck(config));
485
618
  checks.push(prMergeCheck(config));
619
+ progress("Checking Pi installation\u2026");
486
620
  const piChecks = await (options.piChecks ?? (() => buildPiSetupChecks()))().catch((error) => [{
487
621
  ok: false,
488
622
  label: "pi/pi-rig checks",
@@ -508,7 +642,7 @@ function countDoctorFailures(checks) {
508
642
  function throwIfDoctorFailed(checks) {
509
643
  const failures = countDoctorFailures(checks);
510
644
  if (failures > 0) {
511
- throw new CliError2(`Doctor failed (${failures} failing check${failures === 1 ? "" : "s"}).`, 1);
645
+ throw new CliError(`Doctor failed (${failures} failing check${failures === 1 ? "" : "s"}).`, 1);
512
646
  }
513
647
  }
514
648
  export {