@h-rig/cli 0.0.6-alpha.90 → 0.0.6-alpha.92
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.
- package/README.md +18 -19
- package/dist/bin/build-rig-binaries.js +22 -10
- package/dist/bin/rig.d.ts +71 -1
- package/dist/bin/rig.js +15078 -11169
- package/dist/config/rig-default-config.yml +5 -0
- package/dist/src/app/drone-ui.d.ts +11 -14
- package/dist/src/app/drone-ui.js +70 -86
- package/dist/src/commands/_async-ui.d.ts +1 -4
- package/dist/src/commands/_async-ui.js +9 -111
- package/dist/src/commands/_cli-format.d.ts +16 -9
- package/dist/src/commands/_cli-format.js +167 -295
- package/dist/src/commands/_connection-state.d.ts +11 -1
- package/dist/src/commands/_connection-state.js +50 -5
- package/dist/src/commands/_doctor-checks.d.ts +0 -6
- package/dist/src/commands/_doctor-checks.js +79 -382
- package/dist/src/commands/_help-catalog.d.ts +1 -1
- package/dist/src/commands/_help-catalog.js +217 -157
- package/dist/src/commands/_inprocess-services.d.ts +33 -0
- package/dist/src/commands/_inprocess-services.js +102 -0
- package/dist/src/commands/_json-output.js +4 -0
- package/dist/src/commands/_lazy-reconcile.d.ts +34 -0
- package/dist/src/commands/_lazy-reconcile.js +102 -0
- package/dist/src/commands/_paths.js +1 -1
- package/dist/src/commands/_pi-frontend.d.ts +18 -10
- package/dist/src/commands/_pi-frontend.js +37 -715
- package/dist/src/commands/_pi-install.js +18 -36
- package/dist/src/commands/_policy.d.ts +1 -1
- package/dist/src/commands/_policy.js +56 -15
- package/dist/src/commands/_run-bridge.d.ts +114 -0
- package/dist/src/commands/_run-bridge.js +387 -0
- package/dist/src/commands/_run-diagnostics.d.ts +9 -0
- package/dist/src/commands/_run-diagnostics.js +51 -0
- package/dist/src/commands/_run-driver-helpers.d.ts +8 -81
- package/dist/src/commands/_run-driver-helpers.js +79 -283
- package/dist/src/commands/_run-projection.d.ts +50 -0
- package/dist/src/commands/_run-projection.js +349 -0
- package/dist/src/commands/_run-subcommands.d.ts +3 -0
- package/dist/src/commands/_run-subcommands.js +31 -0
- package/dist/src/commands/_spinner.js +1 -1
- package/dist/src/commands/agent.d.ts +1 -1
- package/dist/src/commands/agent.js +8559 -239
- package/dist/src/commands/dist.d.ts +1 -1
- package/dist/src/commands/dist.js +27 -19
- package/dist/src/commands/doctor.d.ts +1 -1
- package/dist/src/commands/doctor.js +93 -475
- package/dist/src/commands/github.d.ts +1 -1
- package/dist/src/commands/github.js +113 -387
- package/dist/src/commands/inbox.d.ts +22 -24
- package/dist/src/commands/inbox.js +420 -691
- package/dist/src/commands/init.d.ts +6 -16
- package/dist/src/commands/init.js +334 -971
- package/dist/src/commands/inspect.d.ts +19 -2
- package/dist/src/commands/inspect.js +644 -610
- package/dist/src/commands/pi.d.ts +1 -1
- package/dist/src/commands/plugin.d.ts +1 -1
- package/dist/src/commands/plugin.js +486 -7
- package/dist/src/commands/profile-and-review.d.ts +1 -1
- package/dist/src/commands/profile-and-review.js +94 -56
- package/dist/src/commands/queue.js +1 -21
- package/dist/src/commands/remote.d.ts +1 -1
- package/dist/src/commands/remote.js +837 -14
- package/dist/src/commands/repo-git-harness.d.ts +1 -1
- package/dist/src/commands/repo-git-harness.js +57 -14
- package/dist/src/commands/run.d.ts +20 -2
- package/dist/src/commands/run.js +17579 -1759
- package/dist/src/commands/server.d.ts +2 -6
- package/dist/src/commands/server.js +141 -723
- package/dist/src/commands/setup.d.ts +1 -1
- package/dist/src/commands/setup.js +102 -484
- package/dist/src/commands/stats.d.ts +13 -10
- package/dist/src/commands/stats.js +689 -761
- package/dist/src/commands/task-run-driver.d.ts +50 -88
- package/dist/src/commands/task-run-driver.js +116 -2717
- package/dist/src/commands/task.d.ts +34 -13
- package/dist/src/commands/task.js +668 -2523
- package/dist/src/commands/test.d.ts +1 -1
- package/dist/src/commands/triage.d.ts +11 -0
- package/dist/src/commands/triage.js +227 -0
- package/dist/src/commands/workspace.d.ts +1 -1
- package/dist/src/commands.d.ts +0 -16
- package/dist/src/commands.js +16657 -12250
- package/dist/src/index.js +16528 -12497
- package/dist/src/launcher.js +4 -0
- package/dist/src/operator-cli.d.ts +2 -0
- package/dist/src/operator-cli.js +17837 -0
- package/dist/src/operator-entry.d.ts +1 -0
- package/dist/src/operator-entry.js +3 -0
- package/package.json +18 -12
- package/dist/src/app/board.d.ts +0 -23
- package/dist/src/app/board.js +0 -1786
- package/dist/src/app/theme.d.ts +0 -47
- package/dist/src/app/theme.js +0 -150
- package/dist/src/commands/_authority-runs.d.ts +0 -22
- package/dist/src/commands/_authority-runs.js +0 -110
- package/dist/src/commands/_operator-surface.d.ts +0 -34
- package/dist/src/commands/_operator-surface.js +0 -220
- package/dist/src/commands/_operator-view.d.ts +0 -30
- package/dist/src/commands/_operator-view.js +0 -1070
- package/dist/src/commands/_preflight.d.ts +0 -22
- package/dist/src/commands/_preflight.js +0 -540
- package/dist/src/commands/_run-replay.d.ts +0 -24
- package/dist/src/commands/_run-replay.js +0 -142
- package/dist/src/commands/_server-client.d.ts +0 -186
- package/dist/src/commands/_server-client.js +0 -681
- package/dist/src/commands/_snapshot-upload.d.ts +0 -39
- package/dist/src/commands/_snapshot-upload.js +0 -455
- package/dist/src/commands/_task-picker.d.ts +0 -9
- package/dist/src/commands/_task-picker.js +0 -201
- package/dist/src/commands/browser.d.ts +0 -65
- package/dist/src/commands/browser.js +0 -1173
- package/dist/src/commands/connect.d.ts +0 -7
- package/dist/src/commands/connect.js +0 -419
- package/dist/src/commands/inspector.d.ts +0 -3
- package/dist/src/commands/inspector.js +0 -263
- package/dist/src/commands/task-report-bug.d.ts +0 -19
- package/dist/src/commands/task-report-bug.js +0 -1281
- package/dist/src/report-bug.d.ts +0 -44
- 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/setup.ts
|
|
5
|
-
import { existsSync as
|
|
6
|
-
import { resolve as
|
|
5
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readdirSync, writeFileSync as writeFileSync2 } from "fs";
|
|
6
|
+
import { resolve as resolve5 } from "path";
|
|
7
7
|
|
|
8
8
|
// packages/cli/src/runner.ts
|
|
9
9
|
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
@@ -85,7 +85,7 @@ async function loadRigConfigOrNull(projectRoot) {
|
|
|
85
85
|
|
|
86
86
|
// packages/cli/src/commands/_paths.ts
|
|
87
87
|
import { resolve } from "path";
|
|
88
|
-
import { resolveMonorepoRoot } from "@rig/runtime/
|
|
88
|
+
import { resolveMonorepoRoot } from "@rig/runtime/layout";
|
|
89
89
|
function resolveControlPlaneMonorepoRoot(projectRoot) {
|
|
90
90
|
return resolveMonorepoRoot(projectRoot);
|
|
91
91
|
}
|
|
@@ -106,11 +106,10 @@ function resolveControlPlaneDefinitionRoot(projectRoot) {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
// packages/cli/src/commands/_pi-install.ts
|
|
109
|
-
import { existsSync
|
|
109
|
+
import { existsSync } from "fs";
|
|
110
110
|
import { homedir } from "os";
|
|
111
111
|
import { resolve as resolve2 } from "path";
|
|
112
112
|
var PI_RIG_PACKAGE_NAME = "@h-rig/pi-rig";
|
|
113
|
-
var LEGACY_PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
|
|
114
113
|
async function defaultCommandRunner(command, options = {}) {
|
|
115
114
|
const proc = Bun.spawn(command, { cwd: options.cwd, stdout: "pipe", stderr: "pipe" });
|
|
116
115
|
const [stdout, stderr, exitCode] = await Promise.all([
|
|
@@ -129,7 +128,7 @@ function resolvePiHomeDir(inputHomeDir) {
|
|
|
129
128
|
function piListContainsPiRig(output) {
|
|
130
129
|
return output.split(/\r?\n/).some((line) => {
|
|
131
130
|
const normalized = line.trim();
|
|
132
|
-
return normalized.includes(PI_RIG_PACKAGE_NAME) ||
|
|
131
|
+
return normalized.includes(PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
|
|
133
132
|
});
|
|
134
133
|
}
|
|
135
134
|
async function safeRun(runner, command, options) {
|
|
@@ -149,27 +148,25 @@ async function checkPiRigInstall(input = {}) {
|
|
|
149
148
|
piRig: { ok: true, label: "pi-rig global extension", detail: extensionPath }
|
|
150
149
|
};
|
|
151
150
|
}
|
|
152
|
-
const exists = input.exists ?? existsSync;
|
|
153
151
|
const runner = input.commandRunner ?? defaultCommandRunner;
|
|
154
152
|
const piResult = await safeRun(runner, ["pi", "--version"]);
|
|
155
153
|
const piListResult = piResult.exitCode === 0 ? await safeRun(runner, ["pi", "list"]) : { exitCode: 1, stdout: "", stderr: "" };
|
|
156
|
-
const
|
|
154
|
+
const hasPiRig = piListResult.exitCode === 0 && piListContainsPiRig(`${piListResult.stdout}
|
|
157
155
|
${piListResult.stderr}`);
|
|
158
|
-
const
|
|
159
|
-
const hasPiRig = listedPiRig;
|
|
156
|
+
const hasLegacyBridgeScaffold = !hasPiRig && (input.exists ?? existsSync)(extensionPath);
|
|
160
157
|
return {
|
|
161
158
|
extensionPath,
|
|
162
159
|
pi: {
|
|
163
160
|
ok: piResult.exitCode === 0,
|
|
164
161
|
label: "pi",
|
|
165
162
|
detail: (piResult.stdout || piResult.stderr).trim() || undefined,
|
|
166
|
-
hint: piResult.exitCode === 0 ? undefined : "Install Pi or
|
|
163
|
+
hint: piResult.exitCode === 0 ? undefined : "Install Pi/OMP manually or set RIG_PI_INSTALL_COMMAND before verifying with bare `rig` / Cockpit \u2192 Doctor."
|
|
167
164
|
},
|
|
168
165
|
piRig: {
|
|
169
166
|
ok: hasPiRig,
|
|
170
167
|
label: "pi-rig global extension",
|
|
171
|
-
detail: hasPiRig ? piListResult.stdout.trim() || PI_RIG_PACKAGE_NAME :
|
|
172
|
-
hint: hasPiRig ? undefined :
|
|
168
|
+
detail: hasPiRig ? piListResult.stdout.trim() || PI_RIG_PACKAGE_NAME : hasLegacyBridgeScaffold ? `legacy bridge scaffold at ${extensionPath}` : undefined,
|
|
169
|
+
hint: hasPiRig ? undefined : `Install the Rig OMP extension with \`pi install ${PI_RIG_PACKAGE_NAME}\`, then verify with bare \`rig\` / Cockpit \u2192 Doctor.`
|
|
173
170
|
}
|
|
174
171
|
};
|
|
175
172
|
}
|
|
@@ -179,23 +176,13 @@ async function buildPiSetupChecks(input = {}) {
|
|
|
179
176
|
}
|
|
180
177
|
|
|
181
178
|
// packages/cli/src/commands/_doctor-checks.ts
|
|
182
|
-
import { existsSync as
|
|
183
|
-
import { resolve as
|
|
179
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
180
|
+
import { resolve as resolve4 } from "path";
|
|
184
181
|
import { isSupportedBunVersion, MIN_SUPPORTED_BUN_VERSION } from "@rig/runtime/control-plane/setup-version";
|
|
185
182
|
|
|
186
183
|
// packages/cli/src/commands/_connection-state.ts
|
|
187
|
-
import { existsSync as existsSync2, mkdirSync, readFileSync
|
|
188
|
-
import { homedir as homedir2 } from "os";
|
|
184
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
189
185
|
import { dirname, resolve as resolve3 } from "path";
|
|
190
|
-
function resolveGlobalConnectionsPath(env = process.env) {
|
|
191
|
-
const explicit = env.RIG_CONNECTIONS_FILE?.trim();
|
|
192
|
-
if (explicit)
|
|
193
|
-
return resolve3(explicit);
|
|
194
|
-
const stateDir = env.RIG_GLOBAL_STATE_DIR?.trim();
|
|
195
|
-
if (stateDir)
|
|
196
|
-
return resolve3(stateDir, "connections.json");
|
|
197
|
-
return resolve3(homedir2(), ".rig", "connections.json");
|
|
198
|
-
}
|
|
199
186
|
function resolveRepoConnectionPath(projectRoot) {
|
|
200
187
|
return resolve3(projectRoot, ".rig", "state", "connection.json");
|
|
201
188
|
}
|
|
@@ -203,45 +190,11 @@ function readJsonFile(path) {
|
|
|
203
190
|
if (!existsSync2(path))
|
|
204
191
|
return null;
|
|
205
192
|
try {
|
|
206
|
-
return JSON.parse(
|
|
193
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
207
194
|
} catch (error) {
|
|
208
195
|
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>`." });
|
|
209
196
|
}
|
|
210
197
|
}
|
|
211
|
-
function writeJsonFile(path, value) {
|
|
212
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
213
|
-
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
214
|
-
`, "utf8");
|
|
215
|
-
}
|
|
216
|
-
function normalizeConnection(value) {
|
|
217
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
218
|
-
return null;
|
|
219
|
-
const record = value;
|
|
220
|
-
if (record.kind === "local")
|
|
221
|
-
return { kind: "local", mode: "auto" };
|
|
222
|
-
if (record.kind === "remote" && typeof record.baseUrl === "string" && record.baseUrl.trim()) {
|
|
223
|
-
const baseUrl = record.baseUrl.trim().replace(/\/+$/, "");
|
|
224
|
-
return { kind: "remote", baseUrl };
|
|
225
|
-
}
|
|
226
|
-
return null;
|
|
227
|
-
}
|
|
228
|
-
function readGlobalConnections(options = {}) {
|
|
229
|
-
const path = resolveGlobalConnectionsPath(options.env ?? process.env);
|
|
230
|
-
const payload = readJsonFile(path);
|
|
231
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
232
|
-
return { connections: {} };
|
|
233
|
-
}
|
|
234
|
-
const rawConnections = payload.connections;
|
|
235
|
-
const connections = {};
|
|
236
|
-
if (rawConnections && typeof rawConnections === "object" && !Array.isArray(rawConnections)) {
|
|
237
|
-
for (const [alias, raw] of Object.entries(rawConnections)) {
|
|
238
|
-
const connection = normalizeConnection(raw);
|
|
239
|
-
if (connection)
|
|
240
|
-
connections[alias] = connection;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
return { connections };
|
|
244
|
-
}
|
|
245
198
|
function readRepoConnection(projectRoot) {
|
|
246
199
|
const payload = readJsonFile(resolveRepoConnectionPath(projectRoot));
|
|
247
200
|
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
@@ -254,247 +207,68 @@ function readRepoConnection(projectRoot) {
|
|
|
254
207
|
selected,
|
|
255
208
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
256
209
|
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
257
|
-
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
210
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined,
|
|
211
|
+
serverProjectRootAlias: typeof record.serverProjectRootAlias === "string" && record.serverProjectRootAlias.trim() ? record.serverProjectRootAlias.trim() : undefined,
|
|
212
|
+
serverProjectRootBaseUrl: typeof record.serverProjectRootBaseUrl === "string" && record.serverProjectRootBaseUrl.trim() ? record.serverProjectRootBaseUrl.trim().replace(/\/+$/, "") : undefined
|
|
258
213
|
};
|
|
259
214
|
}
|
|
260
|
-
function writeRepoConnection(projectRoot, state) {
|
|
261
|
-
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
262
|
-
}
|
|
263
|
-
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
264
|
-
const repo = readRepoConnection(projectRoot);
|
|
265
|
-
if (!repo)
|
|
266
|
-
return null;
|
|
267
|
-
if (repo.selected === "local")
|
|
268
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
|
|
269
|
-
const global = readGlobalConnections(options);
|
|
270
|
-
const connection = global.connections[repo.selected];
|
|
271
|
-
if (!connection) {
|
|
272
|
-
throw new CliError(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
273
|
-
}
|
|
274
|
-
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
275
|
-
}
|
|
276
|
-
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
277
|
-
const repo = readRepoConnection(projectRoot);
|
|
278
|
-
if (!repo)
|
|
279
|
-
return;
|
|
280
|
-
writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
|
|
281
|
-
}
|
|
282
215
|
|
|
283
|
-
// packages/cli/src/commands/
|
|
284
|
-
import {
|
|
285
|
-
|
|
286
|
-
|
|
216
|
+
// packages/cli/src/commands/_inprocess-services.ts
|
|
217
|
+
import {
|
|
218
|
+
beginGitHubDeviceFlow,
|
|
219
|
+
checkGitHubRepoPermissions,
|
|
220
|
+
createGitHubAuthStore,
|
|
221
|
+
listGitHubProjects,
|
|
222
|
+
pollGitHubDeviceFlow,
|
|
223
|
+
resolveGitHubAuthStatus,
|
|
224
|
+
resolveProjectStatusField,
|
|
225
|
+
saveGitHubTokenForProject
|
|
226
|
+
} from "@rig/runtime/control-plane/github/index";
|
|
287
227
|
var scopedGitHubBearerTokens = new Map;
|
|
288
|
-
var serverPhaseListener = null;
|
|
289
|
-
function setServerPhaseListener(listener) {
|
|
290
|
-
const previous = serverPhaseListener;
|
|
291
|
-
serverPhaseListener = listener;
|
|
292
|
-
return previous;
|
|
293
|
-
}
|
|
294
|
-
function reportServerPhase(label) {
|
|
295
|
-
serverPhaseListener?.(label);
|
|
296
|
-
}
|
|
297
228
|
function cleanToken(value) {
|
|
298
229
|
const trimmed = value?.trim();
|
|
299
230
|
return trimmed ? trimmed : null;
|
|
300
231
|
}
|
|
301
|
-
function
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if (
|
|
315
|
-
return
|
|
316
|
-
|
|
317
|
-
if (
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
return cleanToken(typeof parsed.token === "string" ? parsed.token : undefined);
|
|
328
|
-
} catch {
|
|
329
|
-
return null;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
function readLocalConnectionFallbackToken(projectRoot) {
|
|
333
|
-
return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
|
|
334
|
-
}
|
|
335
|
-
async function ensureServerForCli(projectRoot) {
|
|
336
|
-
try {
|
|
337
|
-
const selected = resolveSelectedConnection(projectRoot);
|
|
338
|
-
if (selected?.connection.kind === "remote") {
|
|
339
|
-
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
340
|
-
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
341
|
-
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
342
|
-
return {
|
|
343
|
-
baseUrl: selected.connection.baseUrl,
|
|
344
|
-
authToken,
|
|
345
|
-
connectionKind: "remote",
|
|
346
|
-
serverProjectRoot
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
reportServerPhase("Starting local Rig server\u2026");
|
|
350
|
-
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
351
|
-
return {
|
|
352
|
-
baseUrl: connection.baseUrl,
|
|
353
|
-
authToken: connection.authToken ?? readLocalConnectionFallbackToken(projectRoot),
|
|
354
|
-
connectionKind: "local",
|
|
355
|
-
serverProjectRoot: resolve4(projectRoot)
|
|
356
|
-
};
|
|
357
|
-
} catch (error) {
|
|
358
|
-
if (error instanceof Error) {
|
|
359
|
-
throw new CliError(error.message, 1);
|
|
360
|
-
}
|
|
361
|
-
throw error;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
365
|
-
const repo = readRepoConnection(projectRoot);
|
|
366
|
-
const slug = repo?.project?.trim();
|
|
367
|
-
if (!slug)
|
|
368
|
-
return null;
|
|
369
|
-
try {
|
|
370
|
-
const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
|
|
371
|
-
headers: mergeHeaders(undefined, authToken)
|
|
232
|
+
function cleanString(value) {
|
|
233
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
234
|
+
}
|
|
235
|
+
function oauthClientId() {
|
|
236
|
+
return cleanToken(process.env.RIG_GITHUB_OAUTH_CLIENT_ID);
|
|
237
|
+
}
|
|
238
|
+
async function getGitHubAuthStatusInProcess(context) {
|
|
239
|
+
return { ok: true, ...resolveGitHubAuthStatus({ projectRoot: context.projectRoot, oauthConfigured: Boolean(oauthClientId()) }) };
|
|
240
|
+
}
|
|
241
|
+
async function requestGitHubAuthJsonInProcess(context, pathname, init = {}) {
|
|
242
|
+
const method = (init.method ?? "GET").toUpperCase();
|
|
243
|
+
if (pathname === "/api/github/auth/status")
|
|
244
|
+
return getGitHubAuthStatusInProcess(context);
|
|
245
|
+
if (pathname === "/api/github/repo/permissions") {
|
|
246
|
+
return checkGitHubRepoPermissions({ projectRoot: context.projectRoot, oauthConfigured: Boolean(oauthClientId()) });
|
|
247
|
+
}
|
|
248
|
+
if (pathname === "/api/github/auth/device/start" && method === "POST") {
|
|
249
|
+
const clientId = oauthClientId();
|
|
250
|
+
if (!clientId)
|
|
251
|
+
return { ok: false, oauthConfigured: false, error: "RIG_GITHUB_OAUTH_CLIENT_ID is not configured." };
|
|
252
|
+
const body = init.body ? JSON.parse(String(init.body)) : {};
|
|
253
|
+
return beginGitHubDeviceFlow({
|
|
254
|
+
projectRoot: context.projectRoot,
|
|
255
|
+
clientId,
|
|
256
|
+
scope: cleanString(body.scope) ?? undefined,
|
|
257
|
+
selectedRepo: cleanString(body.repoSlug)
|
|
372
258
|
});
|
|
373
|
-
if (!response.ok)
|
|
374
|
-
return null;
|
|
375
|
-
const payload = await response.json();
|
|
376
|
-
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
377
|
-
const checkouts = Array.isArray(project?.checkouts) ? project.checkouts : [];
|
|
378
|
-
const latestCheckout = [...checkouts].reverse().find((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.path === "string"));
|
|
379
|
-
const path = typeof latestCheckout?.path === "string" && latestCheckout.path.trim() ? latestCheckout.path.trim() : null;
|
|
380
|
-
if (path)
|
|
381
|
-
writeRepoServerProjectRoot(projectRoot, path);
|
|
382
|
-
return path;
|
|
383
|
-
} catch {
|
|
384
|
-
return null;
|
|
385
259
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
260
|
+
if (pathname === "/api/github/auth/device/poll" && method === "POST") {
|
|
261
|
+
const clientId = oauthClientId();
|
|
262
|
+
if (!clientId)
|
|
263
|
+
return { ok: false, oauthConfigured: false, error: "RIG_GITHUB_OAUTH_CLIENT_ID is not configured." };
|
|
264
|
+
const body = init.body ? JSON.parse(String(init.body)) : {};
|
|
265
|
+
const pollId = cleanString(body.pollId);
|
|
266
|
+
if (!pollId)
|
|
267
|
+
return { ok: false, status: "error", error: "pollId is required" };
|
|
268
|
+
return pollGitHubDeviceFlow({ projectRoot: context.projectRoot, clientId, pollId, selectedRepo: cleanString(body.repoSlug) });
|
|
391
269
|
}
|
|
392
|
-
|
|
270
|
+
throw new Error(`No in-process GitHub auth API for ${method} ${pathname}`);
|
|
393
271
|
}
|
|
394
|
-
function diagnosticMessage(payload) {
|
|
395
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
396
|
-
return null;
|
|
397
|
-
const record = payload;
|
|
398
|
-
const diagnostics = Array.isArray(record.diagnostics) ? record.diagnostics : [];
|
|
399
|
-
const messages = diagnostics.flatMap((entry) => {
|
|
400
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
401
|
-
return [];
|
|
402
|
-
const diagnostic = entry;
|
|
403
|
-
const kind = typeof diagnostic.kind === "string" ? diagnostic.kind : "task-source";
|
|
404
|
-
const message = typeof diagnostic.message === "string" ? diagnostic.message : null;
|
|
405
|
-
return message ? [`${kind}: ${message}`] : [];
|
|
406
|
-
});
|
|
407
|
-
return messages.length > 0 ? messages.join("; ") : null;
|
|
408
|
-
}
|
|
409
|
-
var serverReachabilityCache = new Map;
|
|
410
|
-
async function probeServerReachability(baseUrl, authToken) {
|
|
411
|
-
try {
|
|
412
|
-
const response = await fetch(`${baseUrl.replace(/\/+$/, "")}/api/server/status`, {
|
|
413
|
-
headers: mergeHeaders(undefined, authToken),
|
|
414
|
-
signal: AbortSignal.timeout(1500)
|
|
415
|
-
});
|
|
416
|
-
return response.ok;
|
|
417
|
-
} catch {
|
|
418
|
-
return false;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
function cachedServerReachability(projectRoot, baseUrl, authToken) {
|
|
422
|
-
const key = resolve4(projectRoot);
|
|
423
|
-
const cached = serverReachabilityCache.get(key);
|
|
424
|
-
if (cached)
|
|
425
|
-
return cached;
|
|
426
|
-
const probe = probeServerReachability(baseUrl, authToken);
|
|
427
|
-
serverReachabilityCache.set(key, probe);
|
|
428
|
-
return probe;
|
|
429
|
-
}
|
|
430
|
-
function describeSelectedServer(projectRoot, server) {
|
|
431
|
-
try {
|
|
432
|
-
const selected = resolveSelectedConnection(projectRoot);
|
|
433
|
-
if (selected) {
|
|
434
|
-
return {
|
|
435
|
-
alias: selected.alias,
|
|
436
|
-
target: selected.connection.kind === "remote" ? selected.connection.baseUrl : server.baseUrl
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
} catch {}
|
|
440
|
-
return { alias: server.connectionKind === "remote" ? "remote" : "local", target: server.baseUrl };
|
|
441
|
-
}
|
|
442
|
-
async function buildServerFailureContext(projectRoot, server) {
|
|
443
|
-
const { alias, target } = describeSelectedServer(projectRoot, server);
|
|
444
|
-
const reachable = await cachedServerReachability(projectRoot, server.baseUrl, server.authToken);
|
|
445
|
-
const reachability = reachable ? "server is reachable" : "server is unreachable";
|
|
446
|
-
return {
|
|
447
|
-
contextLine: `Currently connected to: ${alias} at ${target} (${reachability}).`,
|
|
448
|
-
hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
async function requestServerJson(context, pathname, init = {}) {
|
|
452
|
-
const server = await ensureServerForCli(context.projectRoot);
|
|
453
|
-
const headers = mergeHeaders(init.headers, server.authToken);
|
|
454
|
-
if (server.serverProjectRoot)
|
|
455
|
-
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
456
|
-
reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
|
|
457
|
-
let response;
|
|
458
|
-
try {
|
|
459
|
-
response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
460
|
-
...init,
|
|
461
|
-
headers
|
|
462
|
-
});
|
|
463
|
-
} catch (error) {
|
|
464
|
-
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
465
|
-
throw new CliError(`Rig server request failed: ${error instanceof Error ? error.message : String(error)}
|
|
466
|
-
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
467
|
-
}
|
|
468
|
-
const text = await response.text();
|
|
469
|
-
const payload = text.trim().length > 0 ? (() => {
|
|
470
|
-
try {
|
|
471
|
-
return JSON.parse(text);
|
|
472
|
-
} catch {
|
|
473
|
-
return null;
|
|
474
|
-
}
|
|
475
|
-
})() : null;
|
|
476
|
-
if (!response.ok) {
|
|
477
|
-
const diagnostics = diagnosticMessage(payload);
|
|
478
|
-
const rawDetail = diagnostics ?? (text || response.statusText);
|
|
479
|
-
const detail = diagnostics ? rawDetail : rawDetail.split(`
|
|
480
|
-
`).map((line) => line.trim()).find((line) => line.length > 0)?.slice(0, 200) ?? response.statusText;
|
|
481
|
-
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
482
|
-
throw new CliError(`Rig server request failed (${response.status}): ${detail}
|
|
483
|
-
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
484
|
-
}
|
|
485
|
-
return payload;
|
|
486
|
-
}
|
|
487
|
-
var RESUMABLE_RUN_STATUSES = new Set([
|
|
488
|
-
"created",
|
|
489
|
-
"preparing",
|
|
490
|
-
"running",
|
|
491
|
-
"validating",
|
|
492
|
-
"reviewing",
|
|
493
|
-
"stopped",
|
|
494
|
-
"failed",
|
|
495
|
-
"needs-attention",
|
|
496
|
-
"needs_attention"
|
|
497
|
-
]);
|
|
498
272
|
|
|
499
273
|
// packages/cli/src/commands/_doctor-checks.ts
|
|
500
274
|
function check(id, label, status, detail, remediation) {
|
|
@@ -515,31 +289,14 @@ function isAuthenticated(payload) {
|
|
|
515
289
|
const record = payload;
|
|
516
290
|
return record.signedIn === true || record.authenticated === true || record.status === "authenticated" || record.ok === true && typeof record.login === "string" && record.login.trim().length > 0;
|
|
517
291
|
}
|
|
518
|
-
function repoSlugFromConfig(config) {
|
|
519
|
-
const project = config?.project;
|
|
520
|
-
if (project && typeof project === "object" && !Array.isArray(project)) {
|
|
521
|
-
const record = project;
|
|
522
|
-
if (typeof record.repo === "string" && /^([^/\s]+)\/([^/\s]+)$/.test(record.repo))
|
|
523
|
-
return record.repo;
|
|
524
|
-
if (typeof record.name === "string" && /^([^/\s]+)\/([^/\s]+)$/.test(record.name))
|
|
525
|
-
return record.name;
|
|
526
|
-
}
|
|
527
|
-
const taskSource = config?.taskSource;
|
|
528
|
-
if (taskSource && typeof taskSource === "object" && !Array.isArray(taskSource)) {
|
|
529
|
-
const source = taskSource;
|
|
530
|
-
if (typeof source.owner === "string" && typeof source.repo === "string")
|
|
531
|
-
return `${source.owner}/${source.repo}`;
|
|
532
|
-
}
|
|
533
|
-
return null;
|
|
534
|
-
}
|
|
535
292
|
function loadFallbackConfig(projectRoot) {
|
|
536
293
|
const candidates = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
|
|
537
294
|
for (const name of candidates) {
|
|
538
|
-
const path =
|
|
539
|
-
if (!
|
|
295
|
+
const path = resolve4(projectRoot, name);
|
|
296
|
+
if (!existsSync3(path))
|
|
540
297
|
continue;
|
|
541
298
|
try {
|
|
542
|
-
const source =
|
|
299
|
+
const source = readFileSync2(path, "utf8");
|
|
543
300
|
if (name.endsWith(".json"))
|
|
544
301
|
return JSON.parse(source);
|
|
545
302
|
const owner = source.match(/owner\s*:\s*["']([^"']+)["']/)?.[1];
|
|
@@ -558,14 +315,11 @@ function loadFallbackConfig(projectRoot) {
|
|
|
558
315
|
}
|
|
559
316
|
return null;
|
|
560
317
|
}
|
|
561
|
-
function projectStatusSlug(projectRoot, config) {
|
|
562
|
-
return readRepoConnection(projectRoot)?.project ?? repoSlugFromConfig(config);
|
|
563
|
-
}
|
|
564
318
|
function githubProjectsCheck(config) {
|
|
565
319
|
const github = config?.github;
|
|
566
320
|
const projects = github?.projects;
|
|
567
321
|
if (!projects?.enabled) {
|
|
568
|
-
return check("github-projects", "GitHub Projects status sync", "warn", "disabled or not configured", "
|
|
322
|
+
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.");
|
|
569
323
|
}
|
|
570
324
|
if (projects.projectId && projects.statusFieldId) {
|
|
571
325
|
return check("github-projects", "GitHub Projects status sync", "pass", `project ${projects.projectId}`);
|
|
@@ -590,16 +344,6 @@ function permissionAllowsPr(payload) {
|
|
|
590
344
|
}
|
|
591
345
|
return null;
|
|
592
346
|
}
|
|
593
|
-
function labelsReady(payload) {
|
|
594
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
595
|
-
return null;
|
|
596
|
-
const record = payload;
|
|
597
|
-
if (record.ok === true || record.ready === true || record.labelsReady === true)
|
|
598
|
-
return true;
|
|
599
|
-
if (record.ok === false || record.ready === false || record.labelsReady === false)
|
|
600
|
-
return false;
|
|
601
|
-
return null;
|
|
602
|
-
}
|
|
603
347
|
function prMergeCheck(config) {
|
|
604
348
|
const pr = config?.pr;
|
|
605
349
|
const merge = config?.merge;
|
|
@@ -613,7 +357,7 @@ async function runRigDoctorChecks(options) {
|
|
|
613
357
|
const checks = [];
|
|
614
358
|
const which = options.which ?? ((binary) => Bun.which(binary));
|
|
615
359
|
const bunVersion = options.bunVersion ?? Bun.version;
|
|
616
|
-
const request = options.requestJson ?? ((pathname, init) =>
|
|
360
|
+
const request = options.requestJson ?? ((pathname, init) => requestGitHubAuthJsonInProcess({ projectRoot }, pathname, init));
|
|
617
361
|
const loadConfig = options.loadConfig ?? loadRigConfigOrNull;
|
|
618
362
|
const progress = options.onProgress ?? (() => {});
|
|
619
363
|
progress("Checking local toolchain\u2026");
|
|
@@ -621,78 +365,26 @@ async function runRigDoctorChecks(options) {
|
|
|
621
365
|
progress("Loading rig.config\u2026");
|
|
622
366
|
const loadedConfig = await loadConfig(projectRoot).catch(() => null);
|
|
623
367
|
const config = loadedConfig ?? loadFallbackConfig(projectRoot);
|
|
624
|
-
const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) =>
|
|
625
|
-
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", "
|
|
368
|
+
const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync3(resolve4(projectRoot, name)));
|
|
369
|
+
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."));
|
|
626
370
|
const taskSourceKind = config?.taskSource?.kind;
|
|
627
371
|
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."));
|
|
628
372
|
const repo = readRepoConnection(projectRoot);
|
|
629
|
-
checks.push(repo ? check("project-link", "repo selected
|
|
630
|
-
const selected = (() => {
|
|
631
|
-
try {
|
|
632
|
-
return resolveSelectedConnection(projectRoot);
|
|
633
|
-
} catch {
|
|
634
|
-
return null;
|
|
635
|
-
}
|
|
636
|
-
})();
|
|
637
|
-
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));
|
|
638
|
-
let server = null;
|
|
373
|
+
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."));
|
|
639
374
|
try {
|
|
640
|
-
progress("
|
|
641
|
-
|
|
642
|
-
checks.push(check("
|
|
375
|
+
progress("Checking GitHub auth\u2026");
|
|
376
|
+
const auth = await request("/api/github/auth/status");
|
|
377
|
+
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>`."));
|
|
643
378
|
} catch (error) {
|
|
644
|
-
checks.push(check("
|
|
379
|
+
checks.push(check("github-auth", "GitHub auth", "fail", errorMessage(error), "Authenticate GitHub through Rig."));
|
|
645
380
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
}
|
|
654
|
-
try {
|
|
655
|
-
progress("Checking GitHub auth\u2026");
|
|
656
|
-
const auth = await request("/api/github/auth/status");
|
|
657
|
-
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>`."));
|
|
658
|
-
} catch (error) {
|
|
659
|
-
checks.push(check("github-auth", "GitHub auth", "fail", errorMessage(error), "Authenticate GitHub through Rig and ensure the server exposes auth status."));
|
|
660
|
-
}
|
|
661
|
-
try {
|
|
662
|
-
progress("Checking GitHub repo permissions\u2026");
|
|
663
|
-
const permissions = await request("/api/github/repo/permissions");
|
|
664
|
-
const allowed = permissionAllowsPr(permissions);
|
|
665
|
-
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."));
|
|
666
|
-
} catch (error) {
|
|
667
|
-
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."));
|
|
668
|
-
}
|
|
669
|
-
try {
|
|
670
|
-
progress("Checking GitHub issue labels\u2026");
|
|
671
|
-
const labels = await request("/api/workspace/task-labels");
|
|
672
|
-
const ready = labelsReady(labels);
|
|
673
|
-
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."));
|
|
674
|
-
} catch (error) {
|
|
675
|
-
checks.push(check("task-labels", "GitHub issue labels", "warn", errorMessage(error), "Run `rig init`/`rig doctor` after label setup is wired on the server."));
|
|
676
|
-
}
|
|
677
|
-
try {
|
|
678
|
-
progress("Checking task projection\u2026");
|
|
679
|
-
const projection = await request("/api/workspace/task-projection");
|
|
680
|
-
checks.push(check("task-projection", "task projection", "pass", JSON.stringify(projection).slice(0, 180)));
|
|
681
|
-
} catch (error) {
|
|
682
|
-
checks.push(check("task-projection", "task projection", "warn", errorMessage(error), "Refresh task projection with `rig task list` or fix the task source."));
|
|
683
|
-
}
|
|
684
|
-
const slug = projectStatusSlug(projectRoot, config);
|
|
685
|
-
if (slug) {
|
|
686
|
-
try {
|
|
687
|
-
progress("Checking server project checkout\u2026");
|
|
688
|
-
const project = await request(`/api/projects/${encodeURIComponent(slug)}`);
|
|
689
|
-
checks.push(check("remote-checkout", "server project checkout", "pass", JSON.stringify(project).slice(0, 180)));
|
|
690
|
-
} catch (error) {
|
|
691
|
-
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."));
|
|
692
|
-
}
|
|
693
|
-
} else {
|
|
694
|
-
checks.push(check("remote-checkout", "server project checkout", "warn", "repo slug unknown", "Set project.repo or run `rig init --repo owner/repo`."));
|
|
695
|
-
}
|
|
381
|
+
try {
|
|
382
|
+
progress("Checking GitHub repo permissions\u2026");
|
|
383
|
+
const permissions = await request("/api/github/repo/permissions");
|
|
384
|
+
const allowed = permissionAllowsPr(permissions);
|
|
385
|
+
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."));
|
|
386
|
+
} catch (error) {
|
|
387
|
+
checks.push(check("github-repo-permissions", "GitHub repo PR permissions", "warn", errorMessage(error), "Ensure the token can open PRs."));
|
|
696
388
|
}
|
|
697
389
|
if (taskSourceKind === "github-issues") {
|
|
698
390
|
checks.push(check("gh", "gh CLI fallback", which("gh") ? "pass" : "warn", which("gh") ?? undefined, "Install gh for local/dev GitHub fallback operations."));
|
|
@@ -706,7 +398,7 @@ async function runRigDoctorChecks(options) {
|
|
|
706
398
|
hint: errorMessage(error)
|
|
707
399
|
}]);
|
|
708
400
|
for (const pi of piChecks) {
|
|
709
|
-
checks.push(check(pi.label === "pi" ? "pi" : "pi-rig", pi.label, pi.ok ? "pass" : "warn", pi.detail, pi.hint ?? (pi.ok ? undefined : "
|
|
401
|
+
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.")));
|
|
710
402
|
}
|
|
711
403
|
return checks;
|
|
712
404
|
}
|
|
@@ -757,7 +449,7 @@ function createTtySpinner(input) {
|
|
|
757
449
|
output.write("\r\x1B[2K");
|
|
758
450
|
};
|
|
759
451
|
render();
|
|
760
|
-
const timer = isTty ? setInterval(render, input.intervalMs ??
|
|
452
|
+
const timer = isTty ? setInterval(render, input.intervalMs ?? 16) : null;
|
|
761
453
|
return {
|
|
762
454
|
setLabel(next) {
|
|
763
455
|
label = next;
|
|
@@ -787,90 +479,20 @@ function createTtySpinner(input) {
|
|
|
787
479
|
};
|
|
788
480
|
}
|
|
789
481
|
|
|
790
|
-
// packages/cli/src/app/theme.ts
|
|
791
|
-
var RIG_PALETTE = {
|
|
792
|
-
ink: "#f2f3f6",
|
|
793
|
-
ink2: "#aeb0ba",
|
|
794
|
-
ink3: "#6c6e79",
|
|
795
|
-
ink4: "#44464f",
|
|
796
|
-
accent: "#ccff4d",
|
|
797
|
-
accentDim: "#a9d63f",
|
|
798
|
-
cyan: "#56d8ff",
|
|
799
|
-
red: "#ff5d5d",
|
|
800
|
-
yellow: "#ffd24d"
|
|
801
|
-
};
|
|
802
|
-
function hexToRgb(hex) {
|
|
803
|
-
const value = hex.replace("#", "");
|
|
804
|
-
return [
|
|
805
|
-
Number.parseInt(value.slice(0, 2), 16),
|
|
806
|
-
Number.parseInt(value.slice(2, 4), 16),
|
|
807
|
-
Number.parseInt(value.slice(4, 6), 16)
|
|
808
|
-
];
|
|
809
|
-
}
|
|
810
|
-
function fg(hex) {
|
|
811
|
-
const [r, g, b] = hexToRgb(hex);
|
|
812
|
-
return (text) => `\x1B[38;2;${r};${g};${b}m${text}\x1B[39m`;
|
|
813
|
-
}
|
|
814
|
-
var ink = fg(RIG_PALETTE.ink);
|
|
815
|
-
var ink2 = fg(RIG_PALETTE.ink2);
|
|
816
|
-
var ink3 = fg(RIG_PALETTE.ink3);
|
|
817
|
-
var ink4 = fg(RIG_PALETTE.ink4);
|
|
818
|
-
var accent = fg(RIG_PALETTE.accent);
|
|
819
|
-
var accentDim = fg(RIG_PALETTE.accentDim);
|
|
820
|
-
var cyan = fg(RIG_PALETTE.cyan);
|
|
821
|
-
var red = fg(RIG_PALETTE.red);
|
|
822
|
-
var yellow = fg(RIG_PALETTE.yellow);
|
|
823
|
-
function bold(text) {
|
|
824
|
-
return `\x1B[1m${text}\x1B[22m`;
|
|
825
|
-
}
|
|
826
|
-
var DRONE_ART = [
|
|
827
|
-
" .-=-. .-=-. ",
|
|
828
|
-
" ( !!! ) ( !!! ) ",
|
|
829
|
-
" '-=-'._ _.'-=-' ",
|
|
830
|
-
" '._ _.' ",
|
|
831
|
-
" '=$$$$$$$=.' ",
|
|
832
|
-
" =$$$$$$$$$$$= ",
|
|
833
|
-
" $$$@@@@@@@@@@$$$ ",
|
|
834
|
-
" $$$@@ @@$$$ ",
|
|
835
|
-
" $$@ ? @$$$ ",
|
|
836
|
-
" $$$@ '-' @$$$ ",
|
|
837
|
-
" $$$@@ @@$$$ ",
|
|
838
|
-
" $$$@@@@@@@@@@$$$ ",
|
|
839
|
-
" =$$$$$$$$$$$= ",
|
|
840
|
-
" '=$$$$$$$=.' ",
|
|
841
|
-
" _.' '._ ",
|
|
842
|
-
" .-=-.' '.-=-. ",
|
|
843
|
-
" ( !!! ) ( !!! ) ",
|
|
844
|
-
" '-=-' '-=-' "
|
|
845
|
-
];
|
|
846
|
-
var EYE_FRAMES = ["@", "o", "."];
|
|
847
|
-
var DRONE_WIDTH = DRONE_ART[0].length;
|
|
848
|
-
var DRONE_HEIGHT = DRONE_ART.length;
|
|
849
|
-
var MICRO_BLADES = ["---", "\\\\\\", "|||", "///"];
|
|
850
|
-
function microDroneFrame(tick) {
|
|
851
|
-
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
852
|
-
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
853
|
-
return `(${blade})${eye}(${blade})`;
|
|
854
|
-
}
|
|
855
|
-
var MICRO_DRONE_FRAMES = Array.from({ length: 12 }, (_, index) => microDroneFrame(index));
|
|
856
|
-
function renderMicroDroneFrame(tick) {
|
|
857
|
-
const blade = MICRO_BLADES[tick % MICRO_BLADES.length];
|
|
858
|
-
const eye = EYE_FRAMES[Math.floor(tick / 2) % EYE_FRAMES.length];
|
|
859
|
-
return `${ink4("(")}${cyan(blade)}${ink4(")")}${bold(accent(eye))}${ink4("(")}${cyan(blade)}${ink4(")")}`;
|
|
860
|
-
}
|
|
861
|
-
|
|
862
482
|
// packages/cli/src/commands/_async-ui.ts
|
|
483
|
+
var FRAMES = ["\u25D0", "\u25D3", "\u25D1", "\u25D2"];
|
|
863
484
|
var DONE_SYMBOL = pc.green("\u25C7");
|
|
864
485
|
var FAIL_SYMBOL = pc.red("\u25A0");
|
|
865
486
|
var activeUpdate = null;
|
|
866
487
|
async function withSpinner(label, work, options = {}) {
|
|
867
488
|
if (options.outputMode === "json") {
|
|
868
|
-
return work(() => {
|
|
489
|
+
return work(() => {
|
|
490
|
+
return;
|
|
491
|
+
});
|
|
869
492
|
}
|
|
870
493
|
if (activeUpdate) {
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
return work(outer);
|
|
494
|
+
activeUpdate(label);
|
|
495
|
+
return work(activeUpdate);
|
|
874
496
|
}
|
|
875
497
|
const output = options.output ?? process.stderr;
|
|
876
498
|
const isTty = output.isTTY === true;
|
|
@@ -882,26 +504,23 @@ async function withSpinner(label, work, options = {}) {
|
|
|
882
504
|
lastLabel = next;
|
|
883
505
|
};
|
|
884
506
|
activeUpdate = update2;
|
|
885
|
-
const previousListener2 = setServerPhaseListener(update2);
|
|
886
507
|
try {
|
|
887
508
|
return await work(update2);
|
|
888
509
|
} finally {
|
|
889
510
|
activeUpdate = null;
|
|
890
|
-
setServerPhaseListener(previousListener2);
|
|
891
511
|
}
|
|
892
512
|
}
|
|
893
513
|
const spinner = createTtySpinner({
|
|
894
514
|
label,
|
|
895
515
|
output,
|
|
896
|
-
frames:
|
|
897
|
-
styleFrame: (frame) =>
|
|
516
|
+
frames: FRAMES,
|
|
517
|
+
styleFrame: (frame) => pc.cyan(frame)
|
|
898
518
|
});
|
|
899
519
|
const update = (next) => {
|
|
900
520
|
lastLabel = next;
|
|
901
521
|
spinner.setLabel(next);
|
|
902
522
|
};
|
|
903
523
|
activeUpdate = update;
|
|
904
|
-
const previousListener = setServerPhaseListener(update);
|
|
905
524
|
try {
|
|
906
525
|
const result = await work(update);
|
|
907
526
|
spinner.stop(options.doneLabel ? `${DONE_SYMBOL} ${options.doneLabel}` : undefined);
|
|
@@ -911,7 +530,6 @@ async function withSpinner(label, work, options = {}) {
|
|
|
911
530
|
throw error;
|
|
912
531
|
} finally {
|
|
913
532
|
activeUpdate = null;
|
|
914
|
-
setServerPhaseListener(previousListener);
|
|
915
533
|
}
|
|
916
534
|
}
|
|
917
535
|
|
|
@@ -983,8 +601,8 @@ function runSetupInit(projectRoot) {
|
|
|
983
601
|
mkdirSync2(stateDir, { recursive: true });
|
|
984
602
|
mkdirSync2(logsDir, { recursive: true });
|
|
985
603
|
mkdirSync2(artifactsDir, { recursive: true });
|
|
986
|
-
const failuresPath =
|
|
987
|
-
if (!
|
|
604
|
+
const failuresPath = resolve5(stateDir, "failed_approaches.md");
|
|
605
|
+
if (!existsSync4(failuresPath)) {
|
|
988
606
|
writeFileSync2(failuresPath, `# Failed Approaches
|
|
989
607
|
|
|
990
608
|
`, "utf-8");
|
|
@@ -996,24 +614,24 @@ async function runSetupCheck(projectRoot, outputMode = "text") {
|
|
|
996
614
|
console.log(formatDoctorChecks(doctorChecks));
|
|
997
615
|
const failures = countDoctorFailures(doctorChecks);
|
|
998
616
|
if (failures > 0) {
|
|
999
|
-
throw new CliError(`Setup check failed (${failures} failing doctor check${failures === 1 ? "" : "s"}).`, 1, { hint: "
|
|
617
|
+
throw new CliError(`Setup check failed (${failures} failing doctor check${failures === 1 ? "" : "s"}).`, 1, { hint: "Legacy setup diagnostics failed; for current UX run bare `rig` and open Cockpit \u2192 Doctor for remediation details." });
|
|
1000
618
|
}
|
|
1001
619
|
return doctorChecks;
|
|
1002
620
|
}
|
|
1003
621
|
async function runSetupPreflight(projectRoot, outputMode = "text") {
|
|
1004
622
|
await runSetupCheck(projectRoot, outputMode);
|
|
1005
|
-
const validationRoot =
|
|
1006
|
-
if (
|
|
623
|
+
const validationRoot = resolve5(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
|
|
624
|
+
if (existsSync4(validationRoot)) {
|
|
1007
625
|
const validators = readdirSync(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|
|
1008
626
|
for (const validator of validators) {
|
|
1009
|
-
const script =
|
|
1010
|
-
if (
|
|
627
|
+
const script = resolve5(validationRoot, validator.name, "validate.sh");
|
|
628
|
+
if (existsSync4(script)) {
|
|
1011
629
|
console.log(`OK: validator script ${script}`);
|
|
1012
630
|
}
|
|
1013
631
|
}
|
|
1014
632
|
}
|
|
1015
|
-
const hooksRoot =
|
|
1016
|
-
if (
|
|
633
|
+
const hooksRoot = resolve5(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
|
|
634
|
+
if (existsSync4(hooksRoot)) {
|
|
1017
635
|
const hooks = readdirSync(hooksRoot).filter((name) => name.endsWith(".sh"));
|
|
1018
636
|
for (const hook of hooks) {
|
|
1019
637
|
console.log(`OK: hook ${hook}`);
|