@h-rig/cli 0.0.6-alpha.90 → 0.0.6-alpha.91

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 (118) hide show
  1. package/README.md +18 -19
  2. package/dist/bin/build-rig-binaries.js +22 -10
  3. package/dist/bin/rig.d.ts +71 -1
  4. package/dist/bin/rig.js +15078 -11169
  5. package/dist/config/rig-default-config.yml +5 -0
  6. package/dist/src/app/drone-ui.d.ts +11 -14
  7. package/dist/src/app/drone-ui.js +70 -86
  8. package/dist/src/commands/_async-ui.d.ts +1 -4
  9. package/dist/src/commands/_async-ui.js +9 -111
  10. package/dist/src/commands/_cli-format.d.ts +16 -9
  11. package/dist/src/commands/_cli-format.js +167 -295
  12. package/dist/src/commands/_connection-state.d.ts +11 -1
  13. package/dist/src/commands/_connection-state.js +50 -5
  14. package/dist/src/commands/_doctor-checks.d.ts +0 -6
  15. package/dist/src/commands/_doctor-checks.js +79 -382
  16. package/dist/src/commands/_help-catalog.d.ts +1 -1
  17. package/dist/src/commands/_help-catalog.js +217 -157
  18. package/dist/src/commands/_inprocess-services.d.ts +33 -0
  19. package/dist/src/commands/_inprocess-services.js +102 -0
  20. package/dist/src/commands/_json-output.js +4 -0
  21. package/dist/src/commands/_lazy-reconcile.d.ts +34 -0
  22. package/dist/src/commands/_lazy-reconcile.js +102 -0
  23. package/dist/src/commands/_paths.js +1 -1
  24. package/dist/src/commands/_pi-frontend.d.ts +18 -10
  25. package/dist/src/commands/_pi-frontend.js +37 -715
  26. package/dist/src/commands/_pi-install.js +18 -36
  27. package/dist/src/commands/_policy.d.ts +1 -1
  28. package/dist/src/commands/_policy.js +56 -15
  29. package/dist/src/commands/_run-bridge.d.ts +114 -0
  30. package/dist/src/commands/_run-bridge.js +387 -0
  31. package/dist/src/commands/_run-diagnostics.d.ts +9 -0
  32. package/dist/src/commands/_run-diagnostics.js +51 -0
  33. package/dist/src/commands/_run-driver-helpers.d.ts +8 -81
  34. package/dist/src/commands/_run-driver-helpers.js +79 -283
  35. package/dist/src/commands/_run-projection.d.ts +50 -0
  36. package/dist/src/commands/_run-projection.js +349 -0
  37. package/dist/src/commands/_run-subcommands.d.ts +3 -0
  38. package/dist/src/commands/_run-subcommands.js +31 -0
  39. package/dist/src/commands/_spinner.js +1 -1
  40. package/dist/src/commands/agent.d.ts +1 -1
  41. package/dist/src/commands/agent.js +8559 -239
  42. package/dist/src/commands/dist.d.ts +1 -1
  43. package/dist/src/commands/dist.js +27 -19
  44. package/dist/src/commands/doctor.d.ts +1 -1
  45. package/dist/src/commands/doctor.js +93 -475
  46. package/dist/src/commands/github.d.ts +1 -1
  47. package/dist/src/commands/github.js +113 -387
  48. package/dist/src/commands/inbox.d.ts +22 -24
  49. package/dist/src/commands/inbox.js +420 -691
  50. package/dist/src/commands/init.d.ts +6 -16
  51. package/dist/src/commands/init.js +334 -971
  52. package/dist/src/commands/inspect.d.ts +19 -2
  53. package/dist/src/commands/inspect.js +644 -610
  54. package/dist/src/commands/pi.d.ts +1 -1
  55. package/dist/src/commands/plugin.d.ts +1 -1
  56. package/dist/src/commands/plugin.js +486 -7
  57. package/dist/src/commands/profile-and-review.d.ts +1 -1
  58. package/dist/src/commands/profile-and-review.js +94 -56
  59. package/dist/src/commands/queue.js +1 -21
  60. package/dist/src/commands/remote.d.ts +1 -1
  61. package/dist/src/commands/remote.js +837 -14
  62. package/dist/src/commands/repo-git-harness.d.ts +1 -1
  63. package/dist/src/commands/repo-git-harness.js +57 -14
  64. package/dist/src/commands/run.d.ts +20 -2
  65. package/dist/src/commands/run.js +17579 -1759
  66. package/dist/src/commands/server.d.ts +2 -6
  67. package/dist/src/commands/server.js +141 -723
  68. package/dist/src/commands/setup.d.ts +1 -1
  69. package/dist/src/commands/setup.js +102 -484
  70. package/dist/src/commands/stats.d.ts +13 -10
  71. package/dist/src/commands/stats.js +689 -761
  72. package/dist/src/commands/task-run-driver.d.ts +50 -88
  73. package/dist/src/commands/task-run-driver.js +116 -2717
  74. package/dist/src/commands/task.d.ts +34 -13
  75. package/dist/src/commands/task.js +668 -2523
  76. package/dist/src/commands/test.d.ts +1 -1
  77. package/dist/src/commands/triage.d.ts +11 -0
  78. package/dist/src/commands/triage.js +227 -0
  79. package/dist/src/commands/workspace.d.ts +1 -1
  80. package/dist/src/commands.d.ts +0 -16
  81. package/dist/src/commands.js +16657 -12250
  82. package/dist/src/index.js +16528 -12497
  83. package/dist/src/launcher.js +4 -0
  84. package/dist/src/operator-cli.d.ts +2 -0
  85. package/dist/src/operator-cli.js +17837 -0
  86. package/dist/src/operator-entry.d.ts +1 -0
  87. package/dist/src/operator-entry.js +3 -0
  88. package/package.json +18 -12
  89. package/dist/src/app/board.d.ts +0 -23
  90. package/dist/src/app/board.js +0 -1786
  91. package/dist/src/app/theme.d.ts +0 -47
  92. package/dist/src/app/theme.js +0 -150
  93. package/dist/src/commands/_authority-runs.d.ts +0 -22
  94. package/dist/src/commands/_authority-runs.js +0 -110
  95. package/dist/src/commands/_operator-surface.d.ts +0 -34
  96. package/dist/src/commands/_operator-surface.js +0 -220
  97. package/dist/src/commands/_operator-view.d.ts +0 -30
  98. package/dist/src/commands/_operator-view.js +0 -1070
  99. package/dist/src/commands/_preflight.d.ts +0 -22
  100. package/dist/src/commands/_preflight.js +0 -540
  101. package/dist/src/commands/_run-replay.d.ts +0 -24
  102. package/dist/src/commands/_run-replay.js +0 -142
  103. package/dist/src/commands/_server-client.d.ts +0 -186
  104. package/dist/src/commands/_server-client.js +0 -681
  105. package/dist/src/commands/_snapshot-upload.d.ts +0 -39
  106. package/dist/src/commands/_snapshot-upload.js +0 -455
  107. package/dist/src/commands/_task-picker.d.ts +0 -9
  108. package/dist/src/commands/_task-picker.js +0 -201
  109. package/dist/src/commands/browser.d.ts +0 -65
  110. package/dist/src/commands/browser.js +0 -1173
  111. package/dist/src/commands/connect.d.ts +0 -7
  112. package/dist/src/commands/connect.js +0 -419
  113. package/dist/src/commands/inspector.d.ts +0 -3
  114. package/dist/src/commands/inspector.js +0 -263
  115. package/dist/src/commands/task-report-bug.d.ts +0 -19
  116. package/dist/src/commands/task-report-bug.js +0 -1281
  117. package/dist/src/report-bug.d.ts +0 -44
  118. package/dist/src/report-bug.js +0 -260
@@ -2,8 +2,8 @@
2
2
  var __require = import.meta.require;
3
3
 
4
4
  // packages/cli/src/commands/_doctor-checks.ts
5
- import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
6
- import { resolve as resolve4 } from "path";
5
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
6
+ import { resolve as resolve3 } from "path";
7
7
 
8
8
  // packages/cli/src/runner.ts
9
9
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
@@ -26,17 +26,7 @@ import { isSupportedBunVersion, MIN_SUPPORTED_BUN_VERSION } from "@rig/runtime/c
26
26
 
27
27
  // packages/cli/src/commands/_connection-state.ts
28
28
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
29
- import { homedir } from "os";
30
29
  import { dirname, resolve } from "path";
31
- function resolveGlobalConnectionsPath(env = process.env) {
32
- const explicit = env.RIG_CONNECTIONS_FILE?.trim();
33
- if (explicit)
34
- return resolve(explicit);
35
- const stateDir = env.RIG_GLOBAL_STATE_DIR?.trim();
36
- if (stateDir)
37
- return resolve(stateDir, "connections.json");
38
- return resolve(homedir(), ".rig", "connections.json");
39
- }
40
30
  function resolveRepoConnectionPath(projectRoot) {
41
31
  return resolve(projectRoot, ".rig", "state", "connection.json");
42
32
  }
@@ -49,40 +39,6 @@ function readJsonFile(path) {
49
39
  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>`." });
50
40
  }
51
41
  }
52
- function writeJsonFile(path, value) {
53
- mkdirSync(dirname(path), { recursive: true });
54
- writeFileSync(path, `${JSON.stringify(value, null, 2)}
55
- `, "utf8");
56
- }
57
- function normalizeConnection(value) {
58
- if (!value || typeof value !== "object" || Array.isArray(value))
59
- return null;
60
- const record = value;
61
- if (record.kind === "local")
62
- return { kind: "local", mode: "auto" };
63
- if (record.kind === "remote" && typeof record.baseUrl === "string" && record.baseUrl.trim()) {
64
- const baseUrl = record.baseUrl.trim().replace(/\/+$/, "");
65
- return { kind: "remote", baseUrl };
66
- }
67
- return null;
68
- }
69
- function readGlobalConnections(options = {}) {
70
- const path = resolveGlobalConnectionsPath(options.env ?? process.env);
71
- const payload = readJsonFile(path);
72
- if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
73
- return { connections: {} };
74
- }
75
- const rawConnections = payload.connections;
76
- const connections = {};
77
- if (rawConnections && typeof rawConnections === "object" && !Array.isArray(rawConnections)) {
78
- for (const [alias, raw] of Object.entries(rawConnections)) {
79
- const connection = normalizeConnection(raw);
80
- if (connection)
81
- connections[alias] = connection;
82
- }
83
- }
84
- return { connections };
85
- }
86
42
  function readRepoConnection(projectRoot) {
87
43
  const payload = readJsonFile(resolveRepoConnectionPath(projectRoot));
88
44
  if (!payload || typeof payload !== "object" || Array.isArray(payload))
@@ -95,242 +51,68 @@ function readRepoConnection(projectRoot) {
95
51
  selected,
96
52
  project: typeof record.project === "string" ? record.project : undefined,
97
53
  linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
98
- serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
54
+ serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined,
55
+ serverProjectRootAlias: typeof record.serverProjectRootAlias === "string" && record.serverProjectRootAlias.trim() ? record.serverProjectRootAlias.trim() : undefined,
56
+ serverProjectRootBaseUrl: typeof record.serverProjectRootBaseUrl === "string" && record.serverProjectRootBaseUrl.trim() ? record.serverProjectRootBaseUrl.trim().replace(/\/+$/, "") : undefined
99
57
  };
100
58
  }
101
- function writeRepoConnection(projectRoot, state) {
102
- writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
103
- }
104
- function resolveSelectedConnection(projectRoot, options = {}) {
105
- const repo = readRepoConnection(projectRoot);
106
- if (!repo)
107
- return null;
108
- if (repo.selected === "local")
109
- return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
110
- const global = readGlobalConnections(options);
111
- const connection = global.connections[repo.selected];
112
- if (!connection) {
113
- throw new CliError(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
114
- }
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 });
122
- }
123
59
 
124
- // packages/cli/src/commands/_server-client.ts
125
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
126
- import { resolve as resolve2 } from "path";
127
- import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
60
+ // packages/cli/src/commands/_inprocess-services.ts
61
+ import {
62
+ beginGitHubDeviceFlow,
63
+ checkGitHubRepoPermissions,
64
+ createGitHubAuthStore,
65
+ listGitHubProjects,
66
+ pollGitHubDeviceFlow,
67
+ resolveGitHubAuthStatus,
68
+ resolveProjectStatusField,
69
+ saveGitHubTokenForProject
70
+ } from "@rig/runtime/control-plane/github/index";
128
71
  var scopedGitHubBearerTokens = new Map;
129
- var serverPhaseListener = null;
130
- function reportServerPhase(label) {
131
- serverPhaseListener?.(label);
132
- }
133
72
  function cleanToken(value) {
134
73
  const trimmed = value?.trim();
135
74
  return trimmed ? trimmed : null;
136
75
  }
137
- function readPrivateRemoteSessionToken(projectRoot) {
138
- const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
139
- if (!existsSync2(path))
140
- return null;
141
- try {
142
- const parsed = JSON.parse(readFileSync2(path, "utf8"));
143
- return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
144
- } catch {
145
- return null;
146
- }
147
- }
148
- function readGitHubBearerTokenForRemote(projectRoot) {
149
- const scopedKey = resolve2(projectRoot);
150
- if (scopedGitHubBearerTokens.has(scopedKey))
151
- return scopedGitHubBearerTokens.get(scopedKey) ?? null;
152
- const privateSession = readPrivateRemoteSessionToken(projectRoot);
153
- if (privateSession)
154
- return privateSession;
155
- return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
76
+ function cleanString(value) {
77
+ return typeof value === "string" && value.trim() ? value.trim() : null;
156
78
  }
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;
166
- }
79
+ function oauthClientId() {
80
+ return cleanToken(process.env.RIG_GITHUB_OAUTH_CLIENT_ID);
167
81
  }
168
- function readLocalConnectionFallbackToken(projectRoot) {
169
- return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
82
+ async function getGitHubAuthStatusInProcess(context) {
83
+ return { ok: true, ...resolveGitHubAuthStatus({ projectRoot: context.projectRoot, oauthConfigured: Boolean(oauthClientId()) }) };
170
84
  }
171
- async function ensureServerForCli(projectRoot) {
172
- try {
173
- const selected = resolveSelectedConnection(projectRoot);
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);
178
- return {
179
- baseUrl: selected.connection.baseUrl,
180
- authToken,
181
- connectionKind: "remote",
182
- serverProjectRoot
183
- };
184
- }
185
- reportServerPhase("Starting local Rig server\u2026");
186
- const connection = await ensureLocalRigServerConnection(projectRoot);
187
- return {
188
- baseUrl: connection.baseUrl,
189
- authToken: connection.authToken ?? readLocalConnectionFallbackToken(projectRoot),
190
- connectionKind: "local",
191
- serverProjectRoot: resolve2(projectRoot)
192
- };
193
- } catch (error) {
194
- if (error instanceof Error) {
195
- throw new CliError(error.message, 1);
196
- }
197
- throw error;
85
+ async function requestGitHubAuthJsonInProcess(context, pathname, init = {}) {
86
+ const method = (init.method ?? "GET").toUpperCase();
87
+ if (pathname === "/api/github/auth/status")
88
+ return getGitHubAuthStatusInProcess(context);
89
+ if (pathname === "/api/github/repo/permissions") {
90
+ return checkGitHubRepoPermissions({ projectRoot: context.projectRoot, oauthConfigured: Boolean(oauthClientId()) });
198
91
  }
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)
92
+ if (pathname === "/api/github/auth/device/start" && method === "POST") {
93
+ const clientId = oauthClientId();
94
+ if (!clientId)
95
+ return { ok: false, oauthConfigured: false, error: "RIG_GITHUB_OAUTH_CLIENT_ID is not configured." };
96
+ const body = init.body ? JSON.parse(String(init.body)) : {};
97
+ return beginGitHubDeviceFlow({
98
+ projectRoot: context.projectRoot,
99
+ clientId,
100
+ scope: cleanString(body.scope) ?? undefined,
101
+ selectedRepo: cleanString(body.repoSlug)
208
102
  });
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
103
  }
222
- }
223
- function mergeHeaders(headers, authToken) {
224
- const merged = new Headers(headers);
225
- if (authToken) {
226
- merged.set("authorization", `Bearer ${authToken}`);
104
+ if (pathname === "/api/github/auth/device/poll" && method === "POST") {
105
+ const clientId = oauthClientId();
106
+ if (!clientId)
107
+ return { ok: false, oauthConfigured: false, error: "RIG_GITHUB_OAUTH_CLIENT_ID is not configured." };
108
+ const body = init.body ? JSON.parse(String(init.body)) : {};
109
+ const pollId = cleanString(body.pollId);
110
+ if (!pollId)
111
+ return { ok: false, status: "error", error: "pollId is required" };
112
+ return pollGitHubDeviceFlow({ projectRoot: context.projectRoot, clientId, pollId, selectedRepo: cleanString(body.repoSlug) });
227
113
  }
228
- return merged;
114
+ throw new Error(`No in-process GitHub auth API for ${method} ${pathname}`);
229
115
  }
230
- function diagnosticMessage(payload) {
231
- if (!payload || typeof payload !== "object" || Array.isArray(payload))
232
- return null;
233
- const record = payload;
234
- const diagnostics = Array.isArray(record.diagnostics) ? record.diagnostics : [];
235
- const messages = diagnostics.flatMap((entry) => {
236
- if (!entry || typeof entry !== "object" || Array.isArray(entry))
237
- return [];
238
- const diagnostic = entry;
239
- const kind = typeof diagnostic.kind === "string" ? diagnostic.kind : "task-source";
240
- const message = typeof diagnostic.message === "string" ? diagnostic.message : null;
241
- return message ? [`${kind}: ${message}`] : [];
242
- });
243
- return messages.length > 0 ? messages.join("; ") : null;
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
- }
287
- async function requestServerJson(context, pathname, init = {}) {
288
- const server = await ensureServerForCli(context.projectRoot);
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
- }
304
- const text = await response.text();
305
- const payload = text.trim().length > 0 ? (() => {
306
- try {
307
- return JSON.parse(text);
308
- } catch {
309
- return null;
310
- }
311
- })() : null;
312
- if (!response.ok) {
313
- const diagnostics = diagnosticMessage(payload);
314
- const rawDetail = diagnostics ?? (text || response.statusText);
315
- const detail = diagnostics ? rawDetail : rawDetail.split(`
316
- `).map((line) => line.trim()).find((line) => line.length > 0)?.slice(0, 200) ?? response.statusText;
317
- const failure = await buildServerFailureContext(context.projectRoot, server);
318
- throw new CliError(`Rig server request failed (${response.status}): ${detail}
319
- ${failure.contextLine}`, 1, { hint: failure.hint });
320
- }
321
- return payload;
322
- }
323
- var RESUMABLE_RUN_STATUSES = new Set([
324
- "created",
325
- "preparing",
326
- "running",
327
- "validating",
328
- "reviewing",
329
- "stopped",
330
- "failed",
331
- "needs-attention",
332
- "needs_attention"
333
- ]);
334
116
 
335
117
  // packages/cli/src/commands/_parsers.ts
336
118
  async function loadRigConfigOrNull(projectRoot) {
@@ -343,11 +125,10 @@ async function loadRigConfigOrNull(projectRoot) {
343
125
  }
344
126
 
345
127
  // packages/cli/src/commands/_pi-install.ts
346
- import { existsSync as existsSync3, readFileSync as readFileSync3, rmSync } from "fs";
347
- import { homedir as homedir2 } from "os";
348
- import { resolve as resolve3 } from "path";
128
+ import { existsSync as existsSync2 } from "fs";
129
+ import { homedir } from "os";
130
+ import { resolve as resolve2 } from "path";
349
131
  var PI_RIG_PACKAGE_NAME = "@h-rig/pi-rig";
350
- var LEGACY_PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
351
132
  async function defaultCommandRunner(command, options = {}) {
352
133
  const proc = Bun.spawn(command, { cwd: options.cwd, stdout: "pipe", stderr: "pipe" });
353
134
  const [stdout, stderr, exitCode] = await Promise.all([
@@ -358,15 +139,15 @@ async function defaultCommandRunner(command, options = {}) {
358
139
  return { exitCode, stdout, stderr };
359
140
  }
360
141
  function resolvePiRigExtensionPath(homeDir) {
361
- return resolve3(homeDir, ".pi", "agent", "extensions", "pi-rig");
142
+ return resolve2(homeDir, ".pi", "agent", "extensions", "pi-rig");
362
143
  }
363
144
  function resolvePiHomeDir(inputHomeDir) {
364
- return inputHomeDir ?? process.env.RIG_PI_HOME_DIR?.trim() ?? homedir2();
145
+ return inputHomeDir ?? process.env.RIG_PI_HOME_DIR?.trim() ?? homedir();
365
146
  }
366
147
  function piListContainsPiRig(output) {
367
148
  return output.split(/\r?\n/).some((line) => {
368
149
  const normalized = line.trim();
369
- return normalized.includes(PI_RIG_PACKAGE_NAME) || normalized.includes(LEGACY_PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
150
+ return normalized.includes(PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
370
151
  });
371
152
  }
372
153
  async function safeRun(runner, command, options) {
@@ -386,27 +167,25 @@ async function checkPiRigInstall(input = {}) {
386
167
  piRig: { ok: true, label: "pi-rig global extension", detail: extensionPath }
387
168
  };
388
169
  }
389
- const exists = input.exists ?? existsSync3;
390
170
  const runner = input.commandRunner ?? defaultCommandRunner;
391
171
  const piResult = await safeRun(runner, ["pi", "--version"]);
392
172
  const piListResult = piResult.exitCode === 0 ? await safeRun(runner, ["pi", "list"]) : { exitCode: 1, stdout: "", stderr: "" };
393
- const listedPiRig = piListResult.exitCode === 0 && piListContainsPiRig(`${piListResult.stdout}
173
+ const hasPiRig = piListResult.exitCode === 0 && piListContainsPiRig(`${piListResult.stdout}
394
174
  ${piListResult.stderr}`);
395
- const legacyBridge = exists(resolve3(extensionPath, "index.ts"));
396
- const hasPiRig = listedPiRig;
175
+ const hasLegacyBridgeScaffold = !hasPiRig && (input.exists ?? existsSync2)(extensionPath);
397
176
  return {
398
177
  extensionPath,
399
178
  pi: {
400
179
  ok: piResult.exitCode === 0,
401
180
  label: "pi",
402
181
  detail: (piResult.stdout || piResult.stderr).trim() || undefined,
403
- hint: piResult.exitCode === 0 ? undefined : "Install Pi or run `rig init --yes` to install/update the Pi runtime."
182
+ hint: piResult.exitCode === 0 ? undefined : "Install Pi/OMP manually or set RIG_PI_INSTALL_COMMAND before verifying with bare `rig` / Cockpit \u2192 Doctor."
404
183
  },
405
184
  piRig: {
406
185
  ok: hasPiRig,
407
186
  label: "pi-rig global extension",
408
- detail: hasPiRig ? piListResult.stdout.trim() || PI_RIG_PACKAGE_NAME : legacyBridge ? `${extensionPath} (legacy bridge; reinstall required)` : undefined,
409
- hint: hasPiRig ? undefined : "Run `rig init --yes` to install/enable the global pi-rig package with `pi install`."
187
+ detail: hasPiRig ? piListResult.stdout.trim() || PI_RIG_PACKAGE_NAME : hasLegacyBridgeScaffold ? `legacy bridge scaffold at ${extensionPath}` : undefined,
188
+ hint: hasPiRig ? undefined : `Install the Rig OMP extension with \`pi install ${PI_RIG_PACKAGE_NAME}\`, then verify with bare \`rig\` / Cockpit \u2192 Doctor.`
410
189
  }
411
190
  };
412
191
  }
@@ -434,31 +213,14 @@ function isAuthenticated(payload) {
434
213
  const record = payload;
435
214
  return record.signedIn === true || record.authenticated === true || record.status === "authenticated" || record.ok === true && typeof record.login === "string" && record.login.trim().length > 0;
436
215
  }
437
- function repoSlugFromConfig(config) {
438
- const project = config?.project;
439
- if (project && typeof project === "object" && !Array.isArray(project)) {
440
- const record = project;
441
- if (typeof record.repo === "string" && /^([^/\s]+)\/([^/\s]+)$/.test(record.repo))
442
- return record.repo;
443
- if (typeof record.name === "string" && /^([^/\s]+)\/([^/\s]+)$/.test(record.name))
444
- return record.name;
445
- }
446
- const taskSource = config?.taskSource;
447
- if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
448
- const source = taskSource;
449
- if (typeof source.owner === "string" && typeof source.repo === "string")
450
- return `${source.owner}/${source.repo}`;
451
- }
452
- return null;
453
- }
454
216
  function loadFallbackConfig(projectRoot) {
455
217
  const candidates = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
456
218
  for (const name of candidates) {
457
- const path = resolve4(projectRoot, name);
458
- if (!existsSync4(path))
219
+ const path = resolve3(projectRoot, name);
220
+ if (!existsSync3(path))
459
221
  continue;
460
222
  try {
461
- const source = readFileSync4(path, "utf8");
223
+ const source = readFileSync2(path, "utf8");
462
224
  if (name.endsWith(".json"))
463
225
  return JSON.parse(source);
464
226
  const owner = source.match(/owner\s*:\s*["']([^"']+)["']/)?.[1];
@@ -477,14 +239,11 @@ function loadFallbackConfig(projectRoot) {
477
239
  }
478
240
  return null;
479
241
  }
480
- function projectStatusSlug(projectRoot, config) {
481
- return readRepoConnection(projectRoot)?.project ?? repoSlugFromConfig(config);
482
- }
483
242
  function githubProjectsCheck(config) {
484
243
  const github = config?.github;
485
244
  const projects = github?.projects;
486
245
  if (!projects?.enabled) {
487
- return check("github-projects", "GitHub Projects status sync", "warn", "disabled or not configured", "Run `rig init --github-project <project>` or configure github.projects when Project status sync should be authoritative.");
246
+ return check("github-projects", "GitHub Projects status sync", "warn", "disabled or not configured", "Current OMP flow does not require GitHub Projects status sync; configure github.projects manually when Project status sync should be authoritative.");
488
247
  }
489
248
  if (projects.projectId && projects.statusFieldId) {
490
249
  return check("github-projects", "GitHub Projects status sync", "pass", `project ${projects.projectId}`);
@@ -509,16 +268,6 @@ function permissionAllowsPr(payload) {
509
268
  }
510
269
  return null;
511
270
  }
512
- function labelsReady(payload) {
513
- if (!payload || typeof payload !== "object" || Array.isArray(payload))
514
- return null;
515
- const record = payload;
516
- if (record.ok === true || record.ready === true || record.labelsReady === true)
517
- return true;
518
- if (record.ok === false || record.ready === false || record.labelsReady === false)
519
- return false;
520
- return null;
521
- }
522
271
  function prMergeCheck(config) {
523
272
  const pr = config?.pr;
524
273
  const merge = config?.merge;
@@ -532,7 +281,7 @@ async function runRigDoctorChecks(options) {
532
281
  const checks = [];
533
282
  const which = options.which ?? ((binary) => Bun.which(binary));
534
283
  const bunVersion = options.bunVersion ?? Bun.version;
535
- const request = options.requestJson ?? ((pathname, init) => requestServerJson({ projectRoot }, pathname, init));
284
+ const request = options.requestJson ?? ((pathname, init) => requestGitHubAuthJsonInProcess({ projectRoot }, pathname, init));
536
285
  const loadConfig = options.loadConfig ?? loadRigConfigOrNull;
537
286
  const progress = options.onProgress ?? (() => {});
538
287
  progress("Checking local toolchain\u2026");
@@ -540,78 +289,26 @@ async function runRigDoctorChecks(options) {
540
289
  progress("Loading rig.config\u2026");
541
290
  const loadedConfig = await loadConfig(projectRoot).catch(() => null);
542
291
  const config = loadedConfig ?? loadFallbackConfig(projectRoot);
543
- const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync4(resolve4(projectRoot, name)));
544
- checks.push(config ? check("config", "rig.config loadable", "pass") : check("config", "rig.config loadable", hasConfigFile ? "fail" : "fail", hasConfigFile ? "config file exists but failed to load" : "missing rig.config.ts/json", "Run `rig init` or fix the config error."));
292
+ const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync3(resolve3(projectRoot, name)));
293
+ checks.push(config ? check("config", "rig.config loadable", "pass") : check("config", "rig.config loadable", hasConfigFile ? "fail" : "fail", hasConfigFile ? "config file exists but failed to load" : "missing rig.config.ts/json", "Create/fix rig.config.ts or use the OMP cockpit Start tab to scaffold one."));
545
294
  const taskSourceKind = config?.taskSource?.kind;
546
295
  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."));
547
296
  const repo = readRepoConnection(projectRoot);
548
- 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>`."));
549
- const selected = (() => {
550
- try {
551
- return resolveSelectedConnection(projectRoot);
552
- } catch {
553
- return null;
554
- }
555
- })();
556
- 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));
557
- let server = null;
297
+ checks.push(repo ? check("project-link", "repo selected for local setup", repo.project ? "pass" : "warn", `${repo.selected}${repo.project ? ` -> ${repo.project}` : ""}`, "Run `rig init --repo owner/repo` if this project should use GitHub Issues.") : check("project-link", "repo selected for local setup", "warn", "missing .rig/state/connection.json", "Current UX can run without this compatibility file; `rig init` recreates it for GitHub-backed projects."));
558
298
  try {
559
- progress("Connecting to the selected Rig server\u2026");
560
- server = await (options.resolveServer ?? ensureServerForCli)(projectRoot);
561
- checks.push(check("server", "Rig server reachable", "pass", `${server.connectionKind} ${server.baseUrl}`));
299
+ progress("Checking GitHub auth\u2026");
300
+ const auth = await request("/api/github/auth/status");
301
+ 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>`."));
562
302
  } catch (error) {
563
- checks.push(check("server", "Rig server reachable", "fail", errorMessage(error), "Start the local Rig server or fix the selected remote connection."));
303
+ checks.push(check("github-auth", "GitHub auth", "fail", errorMessage(error), "Authenticate GitHub through Rig."));
564
304
  }
565
- if (server || options.requestJson) {
566
- try {
567
- progress("Checking server status\u2026");
568
- const status = await request("/api/server/status");
569
- checks.push(check("server-status", "server project status", "pass", JSON.stringify(status).slice(0, 180)));
570
- } catch (error) {
571
- checks.push(check("server-status", "server project status", "fail", errorMessage(error), "Run `rig doctor` after the selected server is reachable."));
572
- }
573
- try {
574
- progress("Checking GitHub auth\u2026");
575
- const auth = await request("/api/github/auth/status");
576
- 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>`."));
577
- } catch (error) {
578
- checks.push(check("github-auth", "GitHub auth", "fail", errorMessage(error), "Authenticate GitHub through Rig and ensure the server exposes auth status."));
579
- }
580
- try {
581
- progress("Checking GitHub repo permissions\u2026");
582
- const permissions = await request("/api/github/repo/permissions");
583
- const allowed = permissionAllowsPr(permissions);
584
- 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."));
585
- } catch (error) {
586
- 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."));
587
- }
588
- try {
589
- progress("Checking GitHub issue labels\u2026");
590
- const labels = await request("/api/workspace/task-labels");
591
- const ready = labelsReady(labels);
592
- 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."));
593
- } catch (error) {
594
- checks.push(check("task-labels", "GitHub issue labels", "warn", errorMessage(error), "Run `rig init`/`rig doctor` after label setup is wired on the server."));
595
- }
596
- try {
597
- progress("Checking task projection\u2026");
598
- const projection = await request("/api/workspace/task-projection");
599
- checks.push(check("task-projection", "task projection", "pass", JSON.stringify(projection).slice(0, 180)));
600
- } catch (error) {
601
- checks.push(check("task-projection", "task projection", "warn", errorMessage(error), "Refresh task projection with `rig task list` or fix the task source."));
602
- }
603
- const slug = projectStatusSlug(projectRoot, config);
604
- if (slug) {
605
- try {
606
- progress("Checking server project checkout\u2026");
607
- const project = await request(`/api/projects/${encodeURIComponent(slug)}`);
608
- checks.push(check("remote-checkout", "server project checkout", "pass", JSON.stringify(project).slice(0, 180)));
609
- } catch (error) {
610
- checks.push(check("remote-checkout", "server project checkout", "warn", errorMessage(error), "Run `rig init --yes --repo owner/repo` to register/link the server project checkout."));
611
- }
612
- } else {
613
- checks.push(check("remote-checkout", "server project checkout", "warn", "repo slug unknown", "Set project.repo or run `rig init --repo owner/repo`."));
614
- }
305
+ try {
306
+ progress("Checking GitHub repo permissions\u2026");
307
+ const permissions = await request("/api/github/repo/permissions");
308
+ const allowed = permissionAllowsPr(permissions);
309
+ 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."));
310
+ } catch (error) {
311
+ checks.push(check("github-repo-permissions", "GitHub repo PR permissions", "warn", errorMessage(error), "Ensure the token can open PRs."));
615
312
  }
616
313
  if (taskSourceKind === "github-issues") {
617
314
  checks.push(check("gh", "gh CLI fallback", which("gh") ? "pass" : "warn", which("gh") ?? undefined, "Install gh for local/dev GitHub fallback operations."));
@@ -625,7 +322,7 @@ async function runRigDoctorChecks(options) {
625
322
  hint: errorMessage(error)
626
323
  }]);
627
324
  for (const pi of piChecks) {
628
- checks.push(check(pi.label === "pi" ? "pi" : "pi-rig", pi.label, pi.ok ? "pass" : "warn", pi.detail, pi.hint ?? (pi.ok ? undefined : "Run `rig init --yes` to install/update Pi and enable pi-rig.")));
325
+ checks.push(check(pi.label === "pi" ? "pi" : "pi-rig", pi.label, pi.ok ? "pass" : "warn", pi.detail, pi.hint ?? (pi.ok ? undefined : "Install Pi/OMP and the Rig extension, then use bare `rig` or Cockpit \u2192 Doctor to verify.")));
629
326
  }
630
327
  return checks;
631
328
  }
@@ -37,7 +37,7 @@ export declare function listHelpGroups(): string[];
37
37
  * unknown-command error can suggest the canonical `rig <group> <cmd>`
38
38
  * spelling. Primary groups win ties (ALL_GROUPS is primary-first).
39
39
  */
40
- export declare function suggestGroupCommandForWord(word: string): string | null;
40
+ export declare function suggestGroupCommandForWord(word: string, liveGroups?: ReadonlySet<string>): string | null;
41
41
  export type TopLevelLaunchState = {
42
42
  /** True when the cwd resolves to an initialized Rig project. */
43
43
  projectInitialized?: boolean;