@h-rig/cli 0.0.6-alpha.88 → 0.0.6-alpha.89
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/dist/bin/rig.js +1159 -292
- package/dist/src/app/board.js +462 -48
- package/dist/src/app-opentui/adapters/doctor.js +458 -46
- package/dist/src/app-opentui/adapters/family.js +670 -147
- package/dist/src/app-opentui/adapters/fleet.js +477 -46
- package/dist/src/app-opentui/adapters/inbox.js +477 -46
- package/dist/src/app-opentui/adapters/init.js +497 -74
- package/dist/src/app-opentui/adapters/inspect.js +477 -46
- package/dist/src/app-opentui/adapters/pi-attach.js +484 -53
- package/dist/src/app-opentui/adapters/run-detail.js +477 -46
- package/dist/src/app-opentui/adapters/server.d.ts +26 -0
- package/dist/src/app-opentui/adapters/server.js +676 -59
- package/dist/src/app-opentui/adapters/tasks.js +539 -81
- package/dist/src/app-opentui/autocomplete.js +4 -2
- package/dist/src/app-opentui/bootstrap.js +1155 -288
- package/dist/src/app-opentui/command-palette.js +37 -10
- package/dist/src/app-opentui/index.js +566 -89
- package/dist/src/app-opentui/intent.js +33 -8
- package/dist/src/app-opentui/keymap.js +43 -29
- package/dist/src/app-opentui/pi-host-child.js +465 -53
- package/dist/src/app-opentui/react/App.js +104 -44
- package/dist/src/app-opentui/react/ChromeHost.js +16 -4
- package/dist/src/app-opentui/react/launch.js +555 -88
- package/dist/src/app-opentui/react/nav.js +1 -1
- package/dist/src/app-opentui/registry.js +1062 -237
- package/dist/src/app-opentui/remote-link.d.ts +10 -0
- package/dist/src/app-opentui/remote-link.js +47 -0
- package/dist/src/app-opentui/runtime.js +566 -89
- package/dist/src/app-opentui/scenes/doctor.js +1 -1
- package/dist/src/app-opentui/scenes/error.js +50 -4
- package/dist/src/app-opentui/scenes/family.js +60 -6
- package/dist/src/app-opentui/scenes/fleet.js +65 -13
- package/dist/src/app-opentui/scenes/help.js +4 -2
- package/dist/src/app-opentui/scenes/init.js +12 -12
- package/dist/src/app-opentui/scenes/main.js +7 -7
- package/dist/src/app-opentui/scenes/server.js +83 -11
- package/dist/src/app-opentui/scenes/tasks.js +79 -16
- package/dist/src/app-opentui/state.js +25 -5
- package/dist/src/app-opentui/surface-catalog.js +4 -2
- package/dist/src/app-opentui/types.d.ts +1 -1
- package/dist/src/commands/_cli-format.d.ts +10 -1
- package/dist/src/commands/_cli-format.js +5 -2
- 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.js +458 -46
- package/dist/src/commands/_help-catalog.js +4 -2
- package/dist/src/commands/_json-output.js +4 -0
- package/dist/src/commands/_operator-view.js +465 -53
- package/dist/src/commands/_pi-frontend.js +465 -53
- package/dist/src/commands/_preflight.js +509 -72
- package/dist/src/commands/_server-client.d.ts +33 -0
- package/dist/src/commands/_server-client.js +477 -46
- package/dist/src/commands/_server-events.js +446 -41
- package/dist/src/commands/_snapshot-upload.js +460 -48
- package/dist/src/commands/connect.js +620 -15
- package/dist/src/commands/doctor.js +458 -46
- package/dist/src/commands/github.js +462 -50
- package/dist/src/commands/inbox.js +458 -46
- package/dist/src/commands/init.js +497 -74
- package/dist/src/commands/inspect.js +458 -46
- package/dist/src/commands/run.js +465 -53
- package/dist/src/commands/server.js +647 -163
- package/dist/src/commands/setup.js +463 -51
- package/dist/src/commands/stats.js +462 -48
- package/dist/src/commands/task-run-driver.js +464 -52
- package/dist/src/commands/task.js +520 -81
- package/dist/src/commands.js +670 -147
- package/dist/src/index.js +674 -147
- package/dist/src/launcher.js +4 -0
- package/package.json +8 -8
|
@@ -215,7 +215,8 @@ __export(exports__connection_state, {
|
|
|
215
215
|
resolveGlobalConnectionsPath: () => resolveGlobalConnectionsPath,
|
|
216
216
|
readRepoConnection: () => readRepoConnection,
|
|
217
217
|
readGlobalConnections: () => readGlobalConnections,
|
|
218
|
-
isRemoteConnectionSelected: () => isRemoteConnectionSelected
|
|
218
|
+
isRemoteConnectionSelected: () => isRemoteConnectionSelected,
|
|
219
|
+
clearRepoServerProjectRoot: () => clearRepoServerProjectRoot
|
|
219
220
|
});
|
|
220
221
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
221
222
|
import { homedir } from "os";
|
|
@@ -299,12 +300,28 @@ function readRepoConnection(projectRoot) {
|
|
|
299
300
|
selected,
|
|
300
301
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
301
302
|
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
302
|
-
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
303
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined,
|
|
304
|
+
serverProjectRootAlias: typeof record.serverProjectRootAlias === "string" && record.serverProjectRootAlias.trim() ? record.serverProjectRootAlias.trim() : undefined,
|
|
305
|
+
serverProjectRootBaseUrl: typeof record.serverProjectRootBaseUrl === "string" && record.serverProjectRootBaseUrl.trim() ? record.serverProjectRootBaseUrl.trim().replace(/\/+$/, "") : undefined
|
|
303
306
|
};
|
|
304
307
|
}
|
|
305
308
|
function writeRepoConnection(projectRoot, state) {
|
|
306
309
|
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
307
310
|
}
|
|
311
|
+
function rootAllowedForSelection(repo, connection) {
|
|
312
|
+
const root = repo.serverProjectRoot?.trim();
|
|
313
|
+
if (!root)
|
|
314
|
+
return;
|
|
315
|
+
if (connection.kind === "remote") {
|
|
316
|
+
if (repo.serverProjectRootAlias !== repo.selected)
|
|
317
|
+
return;
|
|
318
|
+
if (repo.serverProjectRootBaseUrl !== connection.baseUrl)
|
|
319
|
+
return;
|
|
320
|
+
} else if (repo.serverProjectRootAlias && repo.serverProjectRootAlias !== repo.selected) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
return root;
|
|
324
|
+
}
|
|
308
325
|
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
309
326
|
const repo = readRepoConnection(projectRoot);
|
|
310
327
|
if (!repo)
|
|
@@ -316,13 +333,41 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
316
333
|
if (!connection) {
|
|
317
334
|
throw new CliError(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
318
335
|
}
|
|
319
|
-
return { alias: repo.selected, connection, serverProjectRoot: repo
|
|
336
|
+
return { alias: repo.selected, connection, serverProjectRoot: rootAllowedForSelection(repo, connection) };
|
|
320
337
|
}
|
|
321
|
-
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
338
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot, metadata = {}) {
|
|
322
339
|
const repo = readRepoConnection(projectRoot);
|
|
323
340
|
if (!repo)
|
|
324
341
|
return;
|
|
325
|
-
|
|
342
|
+
let inferred = metadata;
|
|
343
|
+
if (!inferred.alias || !inferred.baseUrl) {
|
|
344
|
+
try {
|
|
345
|
+
const selected = resolveSelectedConnection(projectRoot);
|
|
346
|
+
if (selected?.connection.kind === "remote") {
|
|
347
|
+
inferred = {
|
|
348
|
+
alias: inferred.alias ?? selected.alias,
|
|
349
|
+
baseUrl: inferred.baseUrl ?? selected.connection.baseUrl
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
} catch {}
|
|
353
|
+
}
|
|
354
|
+
writeRepoConnection(projectRoot, {
|
|
355
|
+
...repo,
|
|
356
|
+
...metadata.project ? { project: metadata.project } : {},
|
|
357
|
+
serverProjectRoot,
|
|
358
|
+
...inferred.alias ? { serverProjectRootAlias: inferred.alias } : {},
|
|
359
|
+
...inferred.baseUrl ? { serverProjectRootBaseUrl: inferred.baseUrl.replace(/\/+$/, "") } : {}
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
function clearRepoServerProjectRoot(projectRoot) {
|
|
363
|
+
const repo = readRepoConnection(projectRoot);
|
|
364
|
+
if (!repo)
|
|
365
|
+
return;
|
|
366
|
+
writeRepoConnection(projectRoot, {
|
|
367
|
+
selected: repo.selected,
|
|
368
|
+
...repo.project ? { project: repo.project } : {},
|
|
369
|
+
...repo.linkedAt ? { linkedAt: repo.linkedAt } : {}
|
|
370
|
+
});
|
|
326
371
|
}
|
|
327
372
|
function isRemoteConnectionSelected(projectRoot) {
|
|
328
373
|
return resolveSelectedConnection(projectRoot)?.connection.kind === "remote";
|
|
@@ -349,12 +394,16 @@ __export(exports__server_client, {
|
|
|
349
394
|
respondRunPiExtensionUiViaServer: () => respondRunPiExtensionUiViaServer,
|
|
350
395
|
resolveServerConnectionLabel: () => resolveServerConnectionLabel,
|
|
351
396
|
requestServerJson: () => requestServerJson,
|
|
397
|
+
repairRemoteProjectRootLink: () => repairRemoteProjectRootLink,
|
|
352
398
|
registerProjectViaServer: () => registerProjectViaServer,
|
|
353
399
|
prepareRemoteCheckoutViaServer: () => prepareRemoteCheckoutViaServer,
|
|
354
400
|
postGitHubTokenViaServer: () => postGitHubTokenViaServer,
|
|
401
|
+
normalizeRepoSlug: () => normalizeRepoSlug,
|
|
355
402
|
listWorkspaceTasksViaServer: () => listWorkspaceTasksViaServer,
|
|
356
403
|
listRunsViaServer: () => listRunsViaServer,
|
|
357
404
|
listGitHubProjectsViaServer: () => listGitHubProjectsViaServer,
|
|
405
|
+
isRemoteProjectRootLinkError: () => isRemoteProjectRootLinkError,
|
|
406
|
+
inspectRemoteProjectLink: () => inspectRemoteProjectLink,
|
|
358
407
|
getWorkspaceTaskViaServer: () => getWorkspaceTaskViaServer,
|
|
359
408
|
getRunTimelineViaServer: () => getRunTimelineViaServer,
|
|
360
409
|
getRunPiStatusViaServer: () => getRunPiStatusViaServer,
|
|
@@ -366,13 +415,15 @@ __export(exports__server_client, {
|
|
|
366
415
|
getRunDetailsViaServer: () => getRunDetailsViaServer,
|
|
367
416
|
getGitHubProjectStatusFieldViaServer: () => getGitHubProjectStatusFieldViaServer,
|
|
368
417
|
getGitHubAuthStatusViaServer: () => getGitHubAuthStatusViaServer,
|
|
418
|
+
formatRemoteProjectLinkHint: () => formatRemoteProjectLinkHint,
|
|
369
419
|
ensureTaskLabelsViaServer: () => ensureTaskLabelsViaServer,
|
|
370
420
|
ensureServerForCli: () => ensureServerForCli,
|
|
421
|
+
ensureRemoteProjectRootLink: () => ensureRemoteProjectRootLink,
|
|
371
422
|
buildRunPiEventsWebSocketUrl: () => buildRunPiEventsWebSocketUrl,
|
|
372
423
|
abortRunPiViaServer: () => abortRunPiViaServer
|
|
373
424
|
});
|
|
374
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
375
|
-
import { resolve as resolve2 } from "path";
|
|
425
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
426
|
+
import { dirname as dirname2, isAbsolute, resolve as resolve2 } from "path";
|
|
376
427
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
377
428
|
function setServerPhaseListener(listener) {
|
|
378
429
|
const previous = serverPhaseListener;
|
|
@@ -418,11 +469,10 @@ function readStoredGitHubAuthToken(projectRoot) {
|
|
|
418
469
|
const parsed = readRemoteAuthState(projectRoot);
|
|
419
470
|
return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
|
|
420
471
|
}
|
|
421
|
-
function
|
|
422
|
-
|
|
423
|
-
const slug = repo?.project?.trim();
|
|
424
|
-
if (!slug || !/^[^/]+\/[^/]+$/.test(slug))
|
|
472
|
+
function inferRemoteServerProjectRootCandidateFromAuthState(projectRoot, repoSlug) {
|
|
473
|
+
if (!/^[^/]+\/[^/]+$/.test(repoSlug))
|
|
425
474
|
return null;
|
|
475
|
+
const repo = readRepoConnection(projectRoot);
|
|
426
476
|
const auth = readRemoteAuthState(projectRoot);
|
|
427
477
|
const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
|
|
428
478
|
const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
|
|
@@ -431,25 +481,426 @@ function inferRemoteServerProjectRootFromAuthState(projectRoot) {
|
|
|
431
481
|
const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
|
|
432
482
|
if (!checkoutBaseDir)
|
|
433
483
|
return null;
|
|
434
|
-
|
|
435
|
-
writeRepoServerProjectRoot(projectRoot, inferred);
|
|
436
|
-
return inferred;
|
|
484
|
+
return `${checkoutBaseDir.replace(/\/+$/, "")}/${repoSlug}`;
|
|
437
485
|
}
|
|
438
486
|
function readLocalConnectionFallbackToken(projectRoot) {
|
|
439
487
|
return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
|
|
440
488
|
}
|
|
489
|
+
function normalizeRepoSlug(value) {
|
|
490
|
+
const slug = value?.trim();
|
|
491
|
+
return slug && /^[^/\s]+\/[^/\s]+$/.test(slug) ? slug : null;
|
|
492
|
+
}
|
|
493
|
+
function readProjectLinkSlug(projectRoot) {
|
|
494
|
+
const path = resolve2(projectRoot, ".rig", "state", "project-link.json");
|
|
495
|
+
if (!existsSync2(path))
|
|
496
|
+
return null;
|
|
497
|
+
try {
|
|
498
|
+
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
499
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
500
|
+
return null;
|
|
501
|
+
return normalizeRepoSlug(typeof parsed.repoSlug === "string" ? String(parsed.repoSlug) : null);
|
|
502
|
+
} catch {
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
function writeProjectLinkConnection(projectRoot, repoSlug, alias) {
|
|
507
|
+
const path = resolve2(projectRoot, ".rig", "state", "project-link.json");
|
|
508
|
+
mkdirSync2(dirname2(path), { recursive: true });
|
|
509
|
+
writeFileSync2(path, `${JSON.stringify({ repoSlug, connection: alias, linkedAt: new Date().toISOString() }, null, 2)}
|
|
510
|
+
`, "utf8");
|
|
511
|
+
}
|
|
512
|
+
function remoteLinkRepairCommand(repoSlug) {
|
|
513
|
+
return repoSlug ? `rig server repair-link --repo ${repoSlug}` : "rig server repair-link --repo owner/repo";
|
|
514
|
+
}
|
|
515
|
+
function isRemoteProjectRootLinkError(error) {
|
|
516
|
+
const text = error instanceof Error ? error.message : String(error ?? "");
|
|
517
|
+
return /no server-host project root link|remote project(?:-root)? link|x-rig-project-root|serverProjectRoot/i.test(text);
|
|
518
|
+
}
|
|
519
|
+
function formatRemoteProjectLinkHint(resolution) {
|
|
520
|
+
const repair = remoteLinkRepairCommand(resolution.repoSlug);
|
|
521
|
+
if (resolution.status === "auth_required") {
|
|
522
|
+
return `Authenticate the selected remote${resolution.alias ? ` (${resolution.alias})` : ""}, then run \`${repair}\`. Use \`rig github auth import-gh\` or \`rig init --repair --server remote --github-auth device${resolution.repoSlug ? ` --repo ${resolution.repoSlug}` : ""}\`.`;
|
|
523
|
+
}
|
|
524
|
+
if (resolution.status === "missing_project") {
|
|
525
|
+
return `Record the repo slug, then run \`${repair}\` (or \`rig init --repo owner/repo --server remote --github-auth device\`).`;
|
|
526
|
+
}
|
|
527
|
+
if (resolution.status === "not_remote")
|
|
528
|
+
return "Select a remote server with `rig server use <alias>` before repairing a remote project link.";
|
|
529
|
+
return `Run \`${repair}\` to backfill or prepare a server-host checkout for the selected remote${resolution.alias ? ` (${resolution.alias})` : ""}.`;
|
|
530
|
+
}
|
|
531
|
+
function remoteProjectLinkFailure(input) {
|
|
532
|
+
const partial = {
|
|
533
|
+
status: input.status,
|
|
534
|
+
alias: input.alias,
|
|
535
|
+
baseUrl: input.baseUrl,
|
|
536
|
+
repoSlug: input.repoSlug
|
|
537
|
+
};
|
|
538
|
+
return {
|
|
539
|
+
ok: false,
|
|
540
|
+
...input,
|
|
541
|
+
hint: formatRemoteProjectLinkHint(partial),
|
|
542
|
+
next: remoteLinkRepairCommand(input.repoSlug)
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
function remoteProjectLinkSuccess(input) {
|
|
546
|
+
return {
|
|
547
|
+
ok: true,
|
|
548
|
+
status: input.status,
|
|
549
|
+
alias: input.alias,
|
|
550
|
+
baseUrl: input.baseUrl,
|
|
551
|
+
repoSlug: input.repoSlug,
|
|
552
|
+
serverProjectRoot: input.serverProjectRoot,
|
|
553
|
+
source: input.source,
|
|
554
|
+
prepared: input.prepared ?? input.status === "prepared",
|
|
555
|
+
validated: input.validated ?? false,
|
|
556
|
+
message: input.message ?? `Remote project link ready for ${input.repoSlug}.`,
|
|
557
|
+
hint: "Remote-scoped task/run/status requests will send x-rig-project-root for this server-host checkout.",
|
|
558
|
+
next: "rig task list"
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
function localCheckoutPathCandidate(projectRoot, candidate) {
|
|
562
|
+
try {
|
|
563
|
+
const local = resolve2(projectRoot);
|
|
564
|
+
const resolved = resolve2(candidate);
|
|
565
|
+
return resolved === local || resolved.startsWith(`${local}/`);
|
|
566
|
+
} catch {
|
|
567
|
+
return false;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
async function requestRemoteProjectLinkJson(baseUrl, pathname, authToken, init = {}) {
|
|
571
|
+
const requestUrl = new URL(`${baseUrl}${pathname}`);
|
|
572
|
+
if (authToken && queryAuthFallbackEnabled())
|
|
573
|
+
requestUrl.searchParams.set("rt", authToken);
|
|
574
|
+
const response = await fetch(requestUrl, {
|
|
575
|
+
...init,
|
|
576
|
+
headers: mergeHeaders(init.headers, authToken)
|
|
577
|
+
});
|
|
578
|
+
const text = await response.text();
|
|
579
|
+
const payload = text.trim().length > 0 ? (() => {
|
|
580
|
+
try {
|
|
581
|
+
return JSON.parse(text);
|
|
582
|
+
} catch {
|
|
583
|
+
return null;
|
|
584
|
+
}
|
|
585
|
+
})() : null;
|
|
586
|
+
return { ok: response.ok, status: response.status, payload, text };
|
|
587
|
+
}
|
|
588
|
+
function payloadError(payload, fallback) {
|
|
589
|
+
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
590
|
+
const record = payload;
|
|
591
|
+
const value = record.error ?? record.message ?? record.reason;
|
|
592
|
+
if (typeof value === "string" && value.trim())
|
|
593
|
+
return value.trim();
|
|
594
|
+
}
|
|
595
|
+
return fallback;
|
|
596
|
+
}
|
|
597
|
+
function checkoutPathsFromProjectPayload(payload) {
|
|
598
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
599
|
+
return [];
|
|
600
|
+
const project = payload.project;
|
|
601
|
+
if (!project || typeof project !== "object" || Array.isArray(project))
|
|
602
|
+
return [];
|
|
603
|
+
const checkouts = project.checkouts;
|
|
604
|
+
if (!Array.isArray(checkouts))
|
|
605
|
+
return [];
|
|
606
|
+
return [...checkouts].reverse().flatMap((entry) => {
|
|
607
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
608
|
+
return [];
|
|
609
|
+
const path = entry.path;
|
|
610
|
+
return typeof path === "string" && path.trim() ? [path.trim()] : [];
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
function checkoutPathFromPreparePayload(payload) {
|
|
614
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
615
|
+
return null;
|
|
616
|
+
const checkout = payload.checkout;
|
|
617
|
+
if (!checkout || typeof checkout !== "object" || Array.isArray(checkout))
|
|
618
|
+
return null;
|
|
619
|
+
const path = checkout.path;
|
|
620
|
+
return typeof path === "string" && path.trim() ? path.trim() : null;
|
|
621
|
+
}
|
|
622
|
+
async function validateAndPersistRemoteRoot(input) {
|
|
623
|
+
const candidate = input.candidate.trim();
|
|
624
|
+
if (!candidate || !isAbsolute(candidate)) {
|
|
625
|
+
return remoteProjectLinkFailure({
|
|
626
|
+
status: "invalid_root",
|
|
627
|
+
alias: input.alias,
|
|
628
|
+
baseUrl: input.baseUrl,
|
|
629
|
+
repoSlug: input.repoSlug,
|
|
630
|
+
message: `Remote project root candidate is not an absolute server-host path: ${candidate || "(empty)"}.`
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
if (localCheckoutPathCandidate(input.projectRoot, candidate)) {
|
|
634
|
+
return remoteProjectLinkFailure({
|
|
635
|
+
status: "invalid_root",
|
|
636
|
+
alias: input.alias,
|
|
637
|
+
baseUrl: input.baseUrl,
|
|
638
|
+
repoSlug: input.repoSlug,
|
|
639
|
+
message: `Refusing to use local checkout path ${candidate} as a remote server project root.`
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
let response;
|
|
643
|
+
try {
|
|
644
|
+
response = await requestRemoteProjectLinkJson(input.baseUrl, "/api/server/project-root", input.authToken, {
|
|
645
|
+
method: "POST",
|
|
646
|
+
headers: { "content-type": "application/json" },
|
|
647
|
+
body: JSON.stringify({ projectRoot: candidate })
|
|
648
|
+
});
|
|
649
|
+
} catch (error) {
|
|
650
|
+
return remoteProjectLinkFailure({
|
|
651
|
+
status: "error",
|
|
652
|
+
alias: input.alias,
|
|
653
|
+
baseUrl: input.baseUrl,
|
|
654
|
+
repoSlug: input.repoSlug,
|
|
655
|
+
message: `Could not validate remote project root ${candidate}: ${error instanceof Error ? error.message : String(error)}`
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
if (response.status === 401 || response.status === 403) {
|
|
659
|
+
return remoteProjectLinkFailure({
|
|
660
|
+
status: "auth_required",
|
|
661
|
+
alias: input.alias,
|
|
662
|
+
baseUrl: input.baseUrl,
|
|
663
|
+
repoSlug: input.repoSlug,
|
|
664
|
+
statusCode: response.status,
|
|
665
|
+
message: `Remote server ${input.alias} requires authentication before validating project root ${candidate}.`
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
if (!response.ok) {
|
|
669
|
+
return remoteProjectLinkFailure({
|
|
670
|
+
status: "invalid_root",
|
|
671
|
+
alias: input.alias,
|
|
672
|
+
baseUrl: input.baseUrl,
|
|
673
|
+
repoSlug: input.repoSlug,
|
|
674
|
+
statusCode: response.status,
|
|
675
|
+
message: `Remote server rejected project root ${candidate} (${response.status}): ${payloadError(response.payload, response.text || "project-root validation failed")}`
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
const record = response.payload && typeof response.payload === "object" && !Array.isArray(response.payload) ? response.payload : {};
|
|
679
|
+
if (record.ok !== true) {
|
|
680
|
+
return remoteProjectLinkFailure({
|
|
681
|
+
status: "invalid_root",
|
|
682
|
+
alias: input.alias,
|
|
683
|
+
baseUrl: input.baseUrl,
|
|
684
|
+
repoSlug: input.repoSlug,
|
|
685
|
+
message: `Remote server did not accept project root ${candidate}: ${payloadError(response.payload, "project-root validation failed")}`
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
const accepted = typeof record.projectRoot === "string" && record.projectRoot.trim() ? record.projectRoot.trim() : typeof record.requestedProjectRoot === "string" && record.requestedProjectRoot.trim() ? record.requestedProjectRoot.trim() : candidate;
|
|
689
|
+
writeRepoServerProjectRoot(input.projectRoot, accepted, { alias: input.alias, baseUrl: input.baseUrl, project: input.repoSlug });
|
|
690
|
+
writeProjectLinkConnection(input.projectRoot, input.repoSlug, input.alias);
|
|
691
|
+
const status = input.status ?? (input.prepared ? "prepared" : "backfilled");
|
|
692
|
+
return remoteProjectLinkSuccess({
|
|
693
|
+
status,
|
|
694
|
+
alias: input.alias,
|
|
695
|
+
baseUrl: input.baseUrl,
|
|
696
|
+
repoSlug: input.repoSlug,
|
|
697
|
+
serverProjectRoot: accepted,
|
|
698
|
+
source: input.source,
|
|
699
|
+
prepared: input.prepared,
|
|
700
|
+
validated: true,
|
|
701
|
+
message: status === "ready" ? `Remote project link already points to ${accepted} and was validated on ${input.alias}.` : input.prepared ? `Prepared and linked remote checkout ${accepted} for ${input.repoSlug}.` : `Backfilled remote checkout ${accepted} for ${input.repoSlug}.`
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
async function ensureRemoteProjectRootLink(projectRoot, options = {}) {
|
|
705
|
+
let selected;
|
|
706
|
+
try {
|
|
707
|
+
selected = resolveSelectedConnection(projectRoot);
|
|
708
|
+
} catch (error) {
|
|
709
|
+
return remoteProjectLinkFailure({ status: "error", message: error instanceof Error ? error.message : String(error) });
|
|
710
|
+
}
|
|
711
|
+
if (!selected || selected.connection.kind !== "remote") {
|
|
712
|
+
return remoteProjectLinkFailure({ status: "not_remote", message: "No remote Rig server is selected for this repo." });
|
|
713
|
+
}
|
|
714
|
+
const repo = readRepoConnection(projectRoot);
|
|
715
|
+
const explicitRepoRequested = options.repoSlug !== undefined;
|
|
716
|
+
const explicitRepoSlug = explicitRepoRequested ? normalizeRepoSlug(options.repoSlug) : null;
|
|
717
|
+
const repoProjectSlug = normalizeRepoSlug(repo?.project);
|
|
718
|
+
const repoSlug = explicitRepoSlug ?? repoProjectSlug ?? readProjectLinkSlug(projectRoot);
|
|
719
|
+
const alias = selected.alias;
|
|
720
|
+
const baseUrl = selected.connection.baseUrl;
|
|
721
|
+
const authToken = options.authToken === undefined ? readGitHubBearerTokenForRemote(projectRoot) : options.authToken;
|
|
722
|
+
const mode = options.mode ?? "backfill-only";
|
|
723
|
+
if (explicitRepoRequested && !explicitRepoSlug) {
|
|
724
|
+
return remoteProjectLinkFailure({
|
|
725
|
+
status: "missing_project",
|
|
726
|
+
alias,
|
|
727
|
+
baseUrl,
|
|
728
|
+
message: `Invalid --repo value ${JSON.stringify(options.repoSlug)}. Expected owner/repo.`
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
if (!repoSlug) {
|
|
732
|
+
return remoteProjectLinkFailure({
|
|
733
|
+
status: "missing_project",
|
|
734
|
+
alias,
|
|
735
|
+
baseUrl,
|
|
736
|
+
message: `Remote server ${alias} is selected, but this checkout has no GitHub repo slug recorded.`
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
const skippedCandidates = [];
|
|
740
|
+
const storedRoot = selected.serverProjectRoot?.trim() || null;
|
|
741
|
+
const storedRootMatchesResolvedRepo = repoProjectSlug === repoSlug;
|
|
742
|
+
if (storedRoot && storedRootMatchesResolvedRepo) {
|
|
743
|
+
if (localCheckoutPathCandidate(projectRoot, storedRoot)) {
|
|
744
|
+
clearRepoServerProjectRoot(projectRoot);
|
|
745
|
+
skippedCandidates.push(storedRoot);
|
|
746
|
+
} else {
|
|
747
|
+
const storedResult = await validateAndPersistRemoteRoot({
|
|
748
|
+
projectRoot,
|
|
749
|
+
alias,
|
|
750
|
+
baseUrl,
|
|
751
|
+
authToken,
|
|
752
|
+
repoSlug,
|
|
753
|
+
candidate: storedRoot,
|
|
754
|
+
source: "stored",
|
|
755
|
+
status: "ready"
|
|
756
|
+
});
|
|
757
|
+
if (storedResult.ok || storedResult.status === "auth_required" || storedResult.status === "error")
|
|
758
|
+
return storedResult;
|
|
759
|
+
clearRepoServerProjectRoot(projectRoot);
|
|
760
|
+
skippedCandidates.push(storedRoot);
|
|
761
|
+
}
|
|
762
|
+
} else if (storedRoot) {
|
|
763
|
+
skippedCandidates.push(storedRoot);
|
|
764
|
+
}
|
|
765
|
+
const authCandidate = inferRemoteServerProjectRootCandidateFromAuthState(projectRoot, repoSlug);
|
|
766
|
+
if (authCandidate) {
|
|
767
|
+
const authResult = await validateAndPersistRemoteRoot({ projectRoot, alias, baseUrl, authToken, repoSlug, candidate: authCandidate, source: "auth-state" });
|
|
768
|
+
if (authResult.ok || authResult.status === "auth_required")
|
|
769
|
+
return authResult;
|
|
770
|
+
}
|
|
771
|
+
let registryResponse;
|
|
772
|
+
try {
|
|
773
|
+
registryResponse = await requestRemoteProjectLinkJson(baseUrl, `/api/projects/${encodeURIComponent(repoSlug)}`, authToken);
|
|
774
|
+
} catch (error) {
|
|
775
|
+
return remoteProjectLinkFailure({
|
|
776
|
+
status: "error",
|
|
777
|
+
alias,
|
|
778
|
+
baseUrl,
|
|
779
|
+
repoSlug,
|
|
780
|
+
message: `Could not read remote project registry for ${repoSlug} on ${alias}: ${error instanceof Error ? error.message : String(error)}`
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
if (registryResponse.status === 401 || registryResponse.status === 403) {
|
|
784
|
+
return remoteProjectLinkFailure({
|
|
785
|
+
status: "auth_required",
|
|
786
|
+
alias,
|
|
787
|
+
baseUrl,
|
|
788
|
+
repoSlug,
|
|
789
|
+
statusCode: registryResponse.status,
|
|
790
|
+
message: `Remote server ${alias} requires authentication before reading the ${repoSlug} project registry.`
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
if (registryResponse.ok) {
|
|
794
|
+
const candidates = checkoutPathsFromProjectPayload(registryResponse.payload);
|
|
795
|
+
for (const candidate of candidates) {
|
|
796
|
+
const result = await validateAndPersistRemoteRoot({ projectRoot, alias, baseUrl, authToken, repoSlug, candidate, source: "registry" });
|
|
797
|
+
if (result.ok || result.status === "auth_required")
|
|
798
|
+
return result;
|
|
799
|
+
skippedCandidates.push(candidate);
|
|
800
|
+
}
|
|
801
|
+
if (mode === "backfill-only") {
|
|
802
|
+
return remoteProjectLinkFailure({
|
|
803
|
+
status: candidates.length > 0 ? "invalid_root" : "no_server_checkout",
|
|
804
|
+
alias,
|
|
805
|
+
baseUrl,
|
|
806
|
+
repoSlug,
|
|
807
|
+
message: candidates.length > 0 ? `Remote registry has checkout candidates for ${repoSlug}, but none validated for ${alias}.` : `Remote registry has ${repoSlug}, but no server checkout path is linked yet.`,
|
|
808
|
+
skippedCandidates
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
} else if (registryResponse.status === 404) {
|
|
812
|
+
if (mode === "backfill-only") {
|
|
813
|
+
return remoteProjectLinkFailure({
|
|
814
|
+
status: "project_not_registered",
|
|
815
|
+
alias,
|
|
816
|
+
baseUrl,
|
|
817
|
+
repoSlug,
|
|
818
|
+
statusCode: registryResponse.status,
|
|
819
|
+
message: `Remote server ${alias} has no registered project record for ${repoSlug}.`
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
} else {
|
|
823
|
+
return remoteProjectLinkFailure({
|
|
824
|
+
status: "error",
|
|
825
|
+
alias,
|
|
826
|
+
baseUrl,
|
|
827
|
+
repoSlug,
|
|
828
|
+
statusCode: registryResponse.status,
|
|
829
|
+
message: `Could not backfill ${repoSlug} from remote registry (${registryResponse.status}): ${payloadError(registryResponse.payload, registryResponse.text || "registry lookup failed")}`,
|
|
830
|
+
skippedCandidates
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
let prepareResponse;
|
|
834
|
+
try {
|
|
835
|
+
prepareResponse = await requestRemoteProjectLinkJson(baseUrl, `/api/projects/${encodeURIComponent(repoSlug)}/prepare-checkout`, authToken, {
|
|
836
|
+
method: "POST",
|
|
837
|
+
headers: { "content-type": "application/json" },
|
|
838
|
+
body: JSON.stringify({ checkout: { kind: "managed-clone" }, repoUrl: `https://github.com/${repoSlug}.git` })
|
|
839
|
+
});
|
|
840
|
+
} catch (error) {
|
|
841
|
+
return remoteProjectLinkFailure({
|
|
842
|
+
status: "error",
|
|
843
|
+
alias,
|
|
844
|
+
baseUrl,
|
|
845
|
+
repoSlug,
|
|
846
|
+
message: `Could not prepare remote checkout for ${repoSlug} on ${alias}: ${error instanceof Error ? error.message : String(error)}`
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
if (prepareResponse.status === 401 || prepareResponse.status === 403) {
|
|
850
|
+
return remoteProjectLinkFailure({
|
|
851
|
+
status: "auth_required",
|
|
852
|
+
alias,
|
|
853
|
+
baseUrl,
|
|
854
|
+
repoSlug,
|
|
855
|
+
statusCode: prepareResponse.status,
|
|
856
|
+
message: `Remote server ${alias} requires authentication before preparing ${repoSlug}.`
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
if (!prepareResponse.ok) {
|
|
860
|
+
return remoteProjectLinkFailure({
|
|
861
|
+
status: "error",
|
|
862
|
+
alias,
|
|
863
|
+
baseUrl,
|
|
864
|
+
repoSlug,
|
|
865
|
+
statusCode: prepareResponse.status,
|
|
866
|
+
message: `Remote checkout prepare failed for ${repoSlug} (${prepareResponse.status}): ${payloadError(prepareResponse.payload, prepareResponse.text || "prepare-checkout failed")}`,
|
|
867
|
+
skippedCandidates
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
const preparedPath = checkoutPathFromPreparePayload(prepareResponse.payload);
|
|
871
|
+
if (!preparedPath) {
|
|
872
|
+
return remoteProjectLinkFailure({
|
|
873
|
+
status: "invalid_root",
|
|
874
|
+
alias,
|
|
875
|
+
baseUrl,
|
|
876
|
+
repoSlug,
|
|
877
|
+
message: `Remote checkout prepare for ${repoSlug} did not return a checkout.path.`,
|
|
878
|
+
skippedCandidates
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
return validateAndPersistRemoteRoot({ projectRoot, alias, baseUrl, authToken, repoSlug, candidate: preparedPath, source: "prepare", prepared: true });
|
|
882
|
+
}
|
|
883
|
+
async function inspectRemoteProjectLink(projectRoot) {
|
|
884
|
+
return ensureRemoteProjectRootLink(projectRoot, { mode: "backfill-only" });
|
|
885
|
+
}
|
|
886
|
+
async function repairRemoteProjectRootLink(context, options = {}) {
|
|
887
|
+
const resolution = await ensureRemoteProjectRootLink(context.projectRoot, { mode: options.mode ?? "prepare-if-missing", repoSlug: options.repoSlug });
|
|
888
|
+
if (!resolution.ok)
|
|
889
|
+
throw new CliError(resolution.message, 1, { hint: resolution.hint });
|
|
890
|
+
return resolution;
|
|
891
|
+
}
|
|
441
892
|
async function ensureServerForCli(projectRoot) {
|
|
442
893
|
try {
|
|
443
894
|
const selected = resolveSelectedConnection(projectRoot);
|
|
444
895
|
if (selected?.connection.kind === "remote") {
|
|
445
896
|
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
446
897
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
447
|
-
const
|
|
898
|
+
const link = await ensureRemoteProjectRootLink(projectRoot, { mode: "backfill-only", authToken });
|
|
448
899
|
return {
|
|
449
900
|
baseUrl: selected.connection.baseUrl,
|
|
450
901
|
authToken,
|
|
451
902
|
connectionKind: "remote",
|
|
452
|
-
serverProjectRoot
|
|
903
|
+
serverProjectRoot: link.ok ? link.serverProjectRoot ?? null : null
|
|
453
904
|
};
|
|
454
905
|
}
|
|
455
906
|
reportServerPhase("Starting local Rig server\u2026");
|
|
@@ -467,32 +918,6 @@ async function ensureServerForCli(projectRoot) {
|
|
|
467
918
|
throw error;
|
|
468
919
|
}
|
|
469
920
|
}
|
|
470
|
-
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
471
|
-
const repo = readRepoConnection(projectRoot);
|
|
472
|
-
const slug = repo?.project?.trim();
|
|
473
|
-
if (!slug)
|
|
474
|
-
return null;
|
|
475
|
-
try {
|
|
476
|
-
const url = new URL(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`);
|
|
477
|
-
if (authToken && queryAuthFallbackEnabled())
|
|
478
|
-
url.searchParams.set("rt", authToken);
|
|
479
|
-
const response = await fetch(url, {
|
|
480
|
-
headers: mergeHeaders(undefined, authToken)
|
|
481
|
-
});
|
|
482
|
-
if (!response.ok)
|
|
483
|
-
return null;
|
|
484
|
-
const payload = await response.json();
|
|
485
|
-
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
486
|
-
const checkouts = Array.isArray(project?.checkouts) ? project.checkouts : [];
|
|
487
|
-
const latestCheckout = [...checkouts].reverse().find((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.path === "string"));
|
|
488
|
-
const path = typeof latestCheckout?.path === "string" && latestCheckout.path.trim() ? latestCheckout.path.trim() : null;
|
|
489
|
-
if (path)
|
|
490
|
-
writeRepoServerProjectRoot(projectRoot, path);
|
|
491
|
-
return path;
|
|
492
|
-
} catch {
|
|
493
|
-
return null;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
921
|
function appendTaskFilterParams(url, filters) {
|
|
497
922
|
if (filters.assignee)
|
|
498
923
|
url.searchParams.set("assignee", filters.assignee);
|
|
@@ -593,13 +1018,20 @@ function canUseRemoteWithoutProjectRoot(pathname) {
|
|
|
593
1018
|
async function requestServerJson(context, pathname, init = {}) {
|
|
594
1019
|
const server = await ensureServerForCli(context.projectRoot);
|
|
595
1020
|
const requestUrl = new URL(`${server.baseUrl}${pathname}`);
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
1021
|
+
let scopedServerProjectRoot = server.serverProjectRoot;
|
|
1022
|
+
if (server.connectionKind === "remote" && !scopedServerProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
|
|
1023
|
+
const link = await ensureRemoteProjectRootLink(context.projectRoot, { mode: "backfill-only", authToken: server.authToken });
|
|
1024
|
+
if (link.ok && link.serverProjectRoot) {
|
|
1025
|
+
scopedServerProjectRoot = link.serverProjectRoot;
|
|
1026
|
+
} else {
|
|
1027
|
+
const repo = readRepoConnection(context.projectRoot);
|
|
1028
|
+
const target = link.alias && link.baseUrl ? `${link.alias} (${link.baseUrl})` : server.baseUrl;
|
|
1029
|
+
throw new CliError(`Remote server ${target} is selected for ${link.repoSlug ?? repo?.project ?? "this repo"}, but this checkout has no server-host project root link. ${link.message}`, 1, { hint: link.hint });
|
|
1030
|
+
}
|
|
599
1031
|
}
|
|
600
1032
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
601
|
-
if (
|
|
602
|
-
headers.set("x-rig-project-root",
|
|
1033
|
+
if (scopedServerProjectRoot)
|
|
1034
|
+
headers.set("x-rig-project-root", scopedServerProjectRoot);
|
|
603
1035
|
if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
|
|
604
1036
|
requestUrl.searchParams.set("rt", server.authToken);
|
|
605
1037
|
}
|
|
@@ -1644,12 +2076,13 @@ var init__help_catalog = __esm(() => {
|
|
|
1644
2076
|
{
|
|
1645
2077
|
name: "server",
|
|
1646
2078
|
summary: "Choose, inspect, and start the Rig server that owns tasks and runs.",
|
|
1647
|
-
usage: ["rig server <status|list|add|use|start> [options]"],
|
|
2079
|
+
usage: ["rig server <status|list|add|use|repair-link|start> [options]"],
|
|
1648
2080
|
commands: [
|
|
1649
|
-
{ command: "status", description: "Show the selected server for this repo.", primary: true },
|
|
2081
|
+
{ command: "status", description: "Show the selected server and remote project-root link for this repo.", primary: true },
|
|
1650
2082
|
{ command: "use local", description: "Switch this repo to the local Rig server.", primary: true },
|
|
1651
2083
|
{ command: "add <alias> <url>", description: "Save a remote Rig server URL.", primary: true },
|
|
1652
2084
|
{ command: "use <alias>", description: "Select a saved remote server alias.", primary: true },
|
|
2085
|
+
{ command: "repair-link [--prepare|--backfill-only] [--repo owner/repo]", description: "Backfill or prepare the selected remote's server-host checkout link.", primary: true },
|
|
1653
2086
|
{ command: "list", description: "List saved local/remote server aliases.", primary: true },
|
|
1654
2087
|
{ command: "start [--host <host>] [--port <n>]", description: "Start a local rig-server process." }
|
|
1655
2088
|
],
|
|
@@ -1657,6 +2090,7 @@ var init__help_catalog = __esm(() => {
|
|
|
1657
2090
|
"rig server status",
|
|
1658
2091
|
"rig server add prod https://where.rig-does.work",
|
|
1659
2092
|
"rig server use prod",
|
|
2093
|
+
"rig server repair-link --repo owner/repo",
|
|
1660
2094
|
"rig server use local",
|
|
1661
2095
|
"rig server start --port 3773"
|
|
1662
2096
|
],
|
|
@@ -2367,7 +2801,7 @@ function resolveControlPlaneDefinitionRoot(projectRoot) {
|
|
|
2367
2801
|
var init__paths = () => {};
|
|
2368
2802
|
|
|
2369
2803
|
// packages/cli/src/report-bug.ts
|
|
2370
|
-
import { copyFileSync, existsSync as existsSync5, mkdirSync as
|
|
2804
|
+
import { copyFileSync, existsSync as existsSync5, mkdirSync as mkdirSync3, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
2371
2805
|
import { basename as basename2, extname, join, resolve as resolve7 } from "path";
|
|
2372
2806
|
function slugifyBugTitle(value) {
|
|
2373
2807
|
const slug = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80).replace(/-+$/g, "");
|
|
@@ -2406,8 +2840,8 @@ function createBugReportFiles(input) {
|
|
|
2406
2840
|
}
|
|
2407
2841
|
rmSync2(reportDir, { recursive: true, force: true });
|
|
2408
2842
|
}
|
|
2409
|
-
|
|
2410
|
-
|
|
2843
|
+
mkdirSync3(assetDir, { recursive: true });
|
|
2844
|
+
mkdirSync3(screenshotDir, { recursive: true });
|
|
2411
2845
|
const copiedScreenshots = copyEvidenceFiles(input.projectRoot, screenshotDir, input.screenshots ?? [], "screenshot");
|
|
2412
2846
|
const copiedAssets = copyEvidenceFiles(input.projectRoot, assetDir, input.assets ?? [], "asset");
|
|
2413
2847
|
const manifestAssets = [
|
|
@@ -2437,15 +2871,15 @@ function createBugReportFiles(input) {
|
|
|
2437
2871
|
platform: process.platform,
|
|
2438
2872
|
arch: process.arch
|
|
2439
2873
|
};
|
|
2440
|
-
|
|
2441
|
-
|
|
2874
|
+
writeFileSync3(join(assetDir, "README.md"), buildAssetReadme(input.title), "utf8");
|
|
2875
|
+
writeFileSync3(join(screenshotDir, "README.md"), buildScreenshotReadme(input.title), "utf8");
|
|
2442
2876
|
if (browserPath && browser) {
|
|
2443
|
-
|
|
2877
|
+
writeFileSync3(browserPath, `${JSON.stringify(browser, null, 2)}
|
|
2444
2878
|
`, "utf8");
|
|
2445
2879
|
}
|
|
2446
|
-
|
|
2880
|
+
writeFileSync3(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
2447
2881
|
`, "utf8");
|
|
2448
|
-
|
|
2882
|
+
writeFileSync3(taskPath, buildBugReportMarkdown(input, browser, copiedScreenshots, copiedAssets), "utf8");
|
|
2449
2883
|
return {
|
|
2450
2884
|
slug,
|
|
2451
2885
|
reportDir,
|
|
@@ -2622,7 +3056,7 @@ function formatAssetMarkdown(name, path) {
|
|
|
2622
3056
|
var init_report_bug = () => {};
|
|
2623
3057
|
|
|
2624
3058
|
// packages/cli/src/commands/task-report-bug.ts
|
|
2625
|
-
import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as
|
|
3059
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
2626
3060
|
import { resolve as resolve8 } from "path";
|
|
2627
3061
|
import pc2 from "picocolors";
|
|
2628
3062
|
import {
|
|
@@ -2984,7 +3418,7 @@ function appendTaskConfigEntryPreservingText(taskConfigPath, issueId, entry) {
|
|
|
2984
3418
|
`).map((line) => ` ${line}`).join(`
|
|
2985
3419
|
`);
|
|
2986
3420
|
if (!trimmed || trimmed === "{}") {
|
|
2987
|
-
|
|
3421
|
+
writeFileSync4(taskConfigPath, `{
|
|
2988
3422
|
${serializedEntry}
|
|
2989
3423
|
}
|
|
2990
3424
|
`, "utf8");
|
|
@@ -3000,7 +3434,7 @@ ${serializedEntry}
|
|
|
3000
3434
|
throw new CliError(`Invalid trailing content in task config: ${taskConfigPath}`, 1, { hint: "Remove the trailing content so the file is a single JSON object, then retry." });
|
|
3001
3435
|
}
|
|
3002
3436
|
const comma = before.trim() === "{" ? "" : ",";
|
|
3003
|
-
|
|
3437
|
+
writeFileSync4(taskConfigPath, `${before}${comma}
|
|
3004
3438
|
${serializedEntry}
|
|
3005
3439
|
}
|
|
3006
3440
|
`, "utf8");
|
|
@@ -3385,7 +3819,7 @@ var init_task_report_bug = __esm(() => {
|
|
|
3385
3819
|
});
|
|
3386
3820
|
|
|
3387
3821
|
// packages/cli/src/commands/browser.ts
|
|
3388
|
-
import { mkdirSync as
|
|
3822
|
+
import { mkdirSync as mkdirSync4, rmSync as rmSync3 } from "fs";
|
|
3389
3823
|
import { resolve as resolve9 } from "path";
|
|
3390
3824
|
import { spawn } from "child_process";
|
|
3391
3825
|
import { emitKeypressEvents } from "readline";
|
|
@@ -3963,7 +4397,7 @@ function readBrowserDemoCommandLine(command) {
|
|
|
3963
4397
|
}
|
|
3964
4398
|
async function launchBrowserDemo(runtime) {
|
|
3965
4399
|
rmSync3(resolve9(runtime.browserDir, runtime.stateDir), { recursive: true, force: true });
|
|
3966
|
-
|
|
4400
|
+
mkdirSync4(resolve9(runtime.browserDir, runtime.stateDir), { recursive: true });
|
|
3967
4401
|
const launcherPath = resolve9(runtime.browserDir, "scripts/electron-launcher.mjs");
|
|
3968
4402
|
const launcher = await import(pathToFileURL(launcherPath).href);
|
|
3969
4403
|
const electronPath = await launcher.resolveElectronPath();
|
|
@@ -4312,7 +4746,7 @@ var init_profile_and_review = __esm(() => {
|
|
|
4312
4746
|
});
|
|
4313
4747
|
|
|
4314
4748
|
// packages/cli/src/commands/_policy.ts
|
|
4315
|
-
import { appendFileSync, mkdirSync as
|
|
4749
|
+
import { appendFileSync, mkdirSync as mkdirSync5 } from "fs";
|
|
4316
4750
|
import { resolve as resolve10 } from "path";
|
|
4317
4751
|
import { evaluate as evaluate2, loadPolicy as loadPolicy2, resolveAction as resolveAction2 } from "@rig/runtime/control-plane/runtime/guard";
|
|
4318
4752
|
import { resolveHarnessPaths } from "@rig/runtime/control-plane/native/utils";
|
|
@@ -4329,7 +4763,7 @@ function appendControlledBashAudit(context, mode, command, args, matchedRuleIds,
|
|
|
4329
4763
|
}
|
|
4330
4764
|
const logsDir = resolveHarnessPaths(context.projectRoot).logsDir;
|
|
4331
4765
|
const logFile = resolve10(logsDir, "controlled-bash.jsonl");
|
|
4332
|
-
|
|
4766
|
+
mkdirSync5(logsDir, { recursive: true });
|
|
4333
4767
|
const payload = {
|
|
4334
4768
|
timestamp: new Date().toISOString(),
|
|
4335
4769
|
mode,
|
|
@@ -4623,9 +5057,9 @@ var exports_pi = {};
|
|
|
4623
5057
|
__export(exports_pi, {
|
|
4624
5058
|
executePi: () => executePi
|
|
4625
5059
|
});
|
|
4626
|
-
import { existsSync as existsSync8, mkdirSync as
|
|
5060
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
4627
5061
|
import { homedir as homedir4 } from "os";
|
|
4628
|
-
import { dirname as
|
|
5062
|
+
import { dirname as dirname3, resolve as resolve12 } from "path";
|
|
4629
5063
|
function settingsPath(root) {
|
|
4630
5064
|
return resolve12(root, ".pi", "settings.json");
|
|
4631
5065
|
}
|
|
@@ -4650,8 +5084,8 @@ function packageKey(entry) {
|
|
|
4650
5084
|
return JSON.stringify(entry);
|
|
4651
5085
|
}
|
|
4652
5086
|
function writeSettings(path, settings) {
|
|
4653
|
-
|
|
4654
|
-
|
|
5087
|
+
mkdirSync6(dirname3(path), { recursive: true });
|
|
5088
|
+
writeFileSync5(path, `${JSON.stringify(settings, null, 2)}
|
|
4655
5089
|
`, "utf-8");
|
|
4656
5090
|
}
|
|
4657
5091
|
async function searchNpmForPiExtensions(term) {
|
|
@@ -4834,6 +5268,14 @@ function permissionAllowsPr2(payload) {
|
|
|
4834
5268
|
function isNotFoundError(error) {
|
|
4835
5269
|
return /\b(404|not found)\b/i.test(message(error));
|
|
4836
5270
|
}
|
|
5271
|
+
function isLoopbackBaseUrl(baseUrl) {
|
|
5272
|
+
try {
|
|
5273
|
+
const host = new URL(baseUrl).hostname.toLowerCase();
|
|
5274
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
|
|
5275
|
+
} catch {
|
|
5276
|
+
return false;
|
|
5277
|
+
}
|
|
5278
|
+
}
|
|
4837
5279
|
function projectCheckoutReady(payload) {
|
|
4838
5280
|
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
4839
5281
|
return null;
|
|
@@ -4888,25 +5330,37 @@ async function runFastTaskRunPreflight(context, options = {}) {
|
|
|
4888
5330
|
}
|
|
4889
5331
|
const repo = readRepoConnection(context.projectRoot);
|
|
4890
5332
|
const remoteWithoutProjectLink = selectedServer?.connectionKind === "remote" && !repo?.project;
|
|
4891
|
-
|
|
5333
|
+
let remoteRootBlocked = false;
|
|
5334
|
+
checks.push(repo ? preflightCheck("project-link", "project linked to selected server", repo.project ? "pass" : remoteWithoutProjectLink ? "fail" : "warn", `${repo.selected}${repo.project ? ` -> ${repo.project}` : " (missing project link)"}`, remoteWithoutProjectLink ? "Run `rig server repair-link --repo owner/repo` or `rig init --repo owner/repo --server remote` to restore the remote project link." : "Run `rig init --yes --repo owner/repo` to record the GitHub repo slug.") : preflightCheck("project-link", "project linked to selected server", legacyServerCompatibility ? "warn" : "fail", "missing .rig/state/connection.json", "Run `rig init` or `rig server use <alias|local>`."));
|
|
5335
|
+
if (selectedServer?.connectionKind === "remote" && repo?.project && !selectedServer.serverProjectRoot) {
|
|
5336
|
+
const link = await ensureRemoteProjectRootLink(context.projectRoot, { mode: "backfill-only", authToken: selectedServer.authToken });
|
|
5337
|
+
const loopbackDevRemote = !selectedServer.authToken && isLoopbackBaseUrl(selectedServer.baseUrl);
|
|
5338
|
+
checks.push(preflightCheck("remote-project-root-link", "remote server checkout/root linked", link.ok ? "pass" : loopbackDevRemote ? "warn" : "fail", link.ok ? `${link.repoSlug} -> ${link.serverProjectRoot}` : link.message, link.ok ? undefined : loopbackDevRemote ? "Loopback development remotes may continue without x-rig-project-root; production remotes must run `rig server repair-link`." : link.hint));
|
|
5339
|
+
remoteRootBlocked = !link.ok && !loopbackDevRemote;
|
|
5340
|
+
}
|
|
4892
5341
|
try {
|
|
4893
5342
|
const auth = await request("/api/github/auth/status");
|
|
4894
5343
|
checks.push(isAuthenticated2(auth) ? preflightCheck("github-auth", "GitHub auth valid", "pass") : preflightCheck("github-auth", "GitHub auth valid", legacyServerCompatibility ? "warn" : "fail", "not authenticated", "Run `rig github auth import-gh` or `rig github auth token --token <token>`."));
|
|
4895
5344
|
} catch (error) {
|
|
4896
5345
|
checks.push(preflightCheck("github-auth", "GitHub auth valid", legacyServerCompatibility ? "warn" : "fail", message(error), "Fix GitHub auth on the selected Rig server."));
|
|
4897
5346
|
}
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
5347
|
+
if (!remoteRootBlocked) {
|
|
5348
|
+
try {
|
|
5349
|
+
const projection = await request("/api/workspace/task-projection");
|
|
5350
|
+
checks.push(preflightCheck("task-projection", "task projection ready", "pass", JSON.stringify(projection).slice(0, 120)));
|
|
5351
|
+
} catch (error) {
|
|
5352
|
+
checks.push(preflightCheck("task-projection", "task projection ready", "warn", message(error), "Refresh task projection with `rig task list` before launching."));
|
|
5353
|
+
}
|
|
5354
|
+
try {
|
|
5355
|
+
const permissions = await request("/api/github/repo/permissions");
|
|
5356
|
+
const allowed = permissionAllowsPr2(permissions);
|
|
5357
|
+
checks.push(allowed === false ? preflightCheck("github-repo-permissions", "GitHub PR permissions", "fail", JSON.stringify(permissions).slice(0, 120), "Grant the selected GitHub token permission to push branches and open PRs.") : preflightCheck("github-repo-permissions", "GitHub PR permissions", allowed === true ? "pass" : "warn", JSON.stringify(permissions).slice(0, 120), "Confirm the selected token can push branches and open PRs."));
|
|
5358
|
+
} catch (error) {
|
|
5359
|
+
checks.push(preflightCheck("github-repo-permissions", "GitHub PR permissions", "warn", message(error), "Ensure the selected token can push branches and open PRs."));
|
|
5360
|
+
}
|
|
5361
|
+
} else {
|
|
5362
|
+
checks.push(preflightCheck("task-projection", "task projection ready", "warn", "skipped until remote project-root link is repaired", "Run `rig server repair-link`, then retry."));
|
|
5363
|
+
checks.push(preflightCheck("github-repo-permissions", "GitHub PR permissions", "warn", "skipped until remote project-root link is repaired", "Run `rig server repair-link`, then retry."));
|
|
4910
5364
|
}
|
|
4911
5365
|
if (repo?.project) {
|
|
4912
5366
|
try {
|
|
@@ -4918,19 +5372,24 @@ async function runFastTaskRunPreflight(context, options = {}) {
|
|
|
4918
5372
|
}
|
|
4919
5373
|
}
|
|
4920
5374
|
if (taskId) {
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
5375
|
+
if (!remoteRootBlocked) {
|
|
5376
|
+
try {
|
|
5377
|
+
const tasks = await request(`/api/workspace/tasks?limit=200&refresh=1`);
|
|
5378
|
+
const found = Array.isArray(tasks) && tasks.some((task) => taskMatchesId(task, taskId));
|
|
5379
|
+
checks.push(found ? preflightCheck("issue", "task/issue accessible", "pass", taskId) : preflightCheck("issue", "task/issue accessible", legacyServerCompatibility ? "warn" : "fail", taskId, "Confirm the issue exists and matches the configured task filters."));
|
|
5380
|
+
} catch (error) {
|
|
5381
|
+
checks.push(preflightCheck("issue", "task/issue accessible", legacyServerCompatibility ? "warn" : "fail", message(error), "Fix the task source before launching a run."));
|
|
5382
|
+
}
|
|
5383
|
+
try {
|
|
5384
|
+
const runs = await request("/api/runs?limit=200");
|
|
5385
|
+
const duplicate = activeDuplicateRun(runs, taskId);
|
|
5386
|
+
checks.push(duplicate ? preflightCheck("duplicate-active-run", "one active run per task", "fail", String(duplicate.runId ?? taskId), "Attach to or stop the existing run before starting another one for this task.") : preflightCheck("duplicate-active-run", "one active run per task", "pass", taskId));
|
|
5387
|
+
} catch (error) {
|
|
5388
|
+
checks.push(preflightCheck("duplicate-active-run", "one active run per task", "warn", message(error), "Could not list active runs; the server will still reject conflicting runs if configured."));
|
|
5389
|
+
}
|
|
5390
|
+
} else {
|
|
5391
|
+
checks.push(preflightCheck("issue", "task/issue accessible", "fail", "skipped until remote project-root link is repaired", "Run `rig server repair-link`, then retry."));
|
|
5392
|
+
checks.push(preflightCheck("duplicate-active-run", "one active run per task", "warn", "skipped until remote project-root link is repaired", "Run `rig server repair-link`, then retry."));
|
|
4934
5393
|
}
|
|
4935
5394
|
}
|
|
4936
5395
|
if ((options.runtimeAdapter ?? "pi") === "pi") {
|
|
@@ -5411,7 +5870,7 @@ import {
|
|
|
5411
5870
|
chmodSync,
|
|
5412
5871
|
copyFileSync as copyFileSync2,
|
|
5413
5872
|
existsSync as existsSync10,
|
|
5414
|
-
mkdirSync as
|
|
5873
|
+
mkdirSync as mkdirSync7,
|
|
5415
5874
|
readdirSync,
|
|
5416
5875
|
readlinkSync,
|
|
5417
5876
|
rmSync as rmSync4,
|
|
@@ -5516,7 +5975,7 @@ async function executeDist(context, args) {
|
|
|
5516
5975
|
requireNoExtraArgs(pending, "rig dist install [--scope user|system] [--path <dir>]");
|
|
5517
5976
|
const scope = parseInstallScope(scopeResult.value);
|
|
5518
5977
|
const installDir = resolveInstallDir(scope, pathResult.value);
|
|
5519
|
-
|
|
5978
|
+
mkdirSync7(installDir, { recursive: true });
|
|
5520
5979
|
let source = await findLatestDistBinary(context.projectRoot);
|
|
5521
5980
|
let buildDir = null;
|
|
5522
5981
|
if (!source) {
|
|
@@ -5571,7 +6030,7 @@ async function executeDist(context, args) {
|
|
|
5571
6030
|
const fp = await computeRuntimeImageFingerprint(context.projectRoot);
|
|
5572
6031
|
const currentId = computeRuntimeImageId(fp);
|
|
5573
6032
|
const imagesDir = resolve15(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "images");
|
|
5574
|
-
|
|
6033
|
+
mkdirSync7(imagesDir, { recursive: true });
|
|
5575
6034
|
let pruned = 0;
|
|
5576
6035
|
for (const entry of readdirSync(imagesDir, { withFileTypes: true })) {
|
|
5577
6036
|
if (entry.isDirectory() && entry.name !== currentId) {
|
|
@@ -5583,9 +6042,9 @@ async function executeDist(context, args) {
|
|
|
5583
6042
|
console.log(`Pruned ${pruned} stale image(s).`);
|
|
5584
6043
|
}
|
|
5585
6044
|
const imageDir = resolve15(imagesDir, currentId);
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
6045
|
+
mkdirSync7(resolve15(imageDir, "bin/hooks"), { recursive: true });
|
|
6046
|
+
mkdirSync7(resolve15(imageDir, "bin/plugins"), { recursive: true });
|
|
6047
|
+
mkdirSync7(resolve15(imageDir, "bin/validators"), { recursive: true });
|
|
5589
6048
|
const hookNames = [
|
|
5590
6049
|
"scope-guard",
|
|
5591
6050
|
"import-guard",
|
|
@@ -5610,8 +6069,8 @@ async function executeDist(context, args) {
|
|
|
5610
6069
|
const binPluginsDir = resolve15(resolveControlPlaneHostBinDir(context.projectRoot), "plugins");
|
|
5611
6070
|
const validatorsRoot = resolve15(hostProjectRoot, "packages/runtime/src/control-plane/validators");
|
|
5612
6071
|
const binValidatorsDir = resolve15(resolveControlPlaneHostBinDir(context.projectRoot), "validators");
|
|
5613
|
-
|
|
5614
|
-
|
|
6072
|
+
mkdirSync7(binPluginsDir, { recursive: true });
|
|
6073
|
+
mkdirSync7(binValidatorsDir, { recursive: true });
|
|
5615
6074
|
if (existsSync10(pluginsDir)) {
|
|
5616
6075
|
for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
|
|
5617
6076
|
const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
@@ -6050,16 +6509,19 @@ function formatConnectionList(connections) {
|
|
|
6050
6509
|
return [formatSection("Rig servers", `${rows.length} available`), `${pc4.bold(pad("ALIAS", aliasWidth))} ${pc4.bold("KIND")} ${pc4.bold("TARGET")}`, ...lines, "", ...formatNextSteps(["Select one: `rig server use <alias|local>`"])].join(`
|
|
6051
6510
|
`);
|
|
6052
6511
|
}
|
|
6053
|
-
function formatConnectionStatus(selected, connections) {
|
|
6512
|
+
function formatConnectionStatus(selected, connections, repo, remoteProjectLink) {
|
|
6054
6513
|
const connection = selected === "local" ? { kind: "local", mode: "auto" } : connections[selected];
|
|
6055
6514
|
const target = !connection ? "not configured" : connection.kind === "remote" ? connection.baseUrl : "local";
|
|
6515
|
+
const rootLabel = remoteProjectLink ? remoteProjectLink.ok ? `ready \xB7 ${remoteProjectLink.serverProjectRoot ?? repo?.serverProjectRoot ?? "linked"}` : `${remoteProjectLink.status ?? "needs repair"} \xB7 ${remoteProjectLink.hint ?? remoteProjectLink.message ?? "run rig server repair-link"}` : repo?.serverProjectRoot ? repo.serverProjectRoot : "not required";
|
|
6056
6516
|
return [
|
|
6057
6517
|
formatSection("Rig server", "selected for this repo"),
|
|
6058
6518
|
`${themeFaint("\u2502")} ${themeDim("selected ")} ${pc4.bold(selected)}`,
|
|
6059
6519
|
`${themeFaint("\u2502")} ${themeDim("kind ")} ${formatStatusPill(connection?.kind ?? "unknown")}`,
|
|
6060
6520
|
`${themeFaint("\u2502")} ${themeDim("target ")} ${target ?? "not configured"}`,
|
|
6521
|
+
...repo?.project ? [`${themeFaint("\u2502")} ${themeDim("project ")} ${repo.project}`] : [],
|
|
6522
|
+
...connection?.kind === "remote" ? [`${themeFaint("\u2502")} ${themeDim("root ")} ${rootLabel}`] : [],
|
|
6061
6523
|
"",
|
|
6062
|
-
...formatNextSteps(["Change: `rig server use <alias|local>`", "List saved servers: `rig server list`"])
|
|
6524
|
+
...formatNextSteps(remoteProjectLink && !remoteProjectLink.ok ? ["Repair remote link: `rig server repair-link`", "Authenticate first if needed: `rig github auth import-gh`"] : ["Change: `rig server use <alias|local>`", "List saved servers: `rig server list`"])
|
|
6063
6525
|
].join(`
|
|
6064
6526
|
`);
|
|
6065
6527
|
}
|
|
@@ -6350,7 +6812,7 @@ var init_inbox = __esm(() => {
|
|
|
6350
6812
|
|
|
6351
6813
|
// packages/cli/src/commands/_snapshot-upload.ts
|
|
6352
6814
|
import { mkdir, readdir, readFile, writeFile } from "fs/promises";
|
|
6353
|
-
import { dirname as
|
|
6815
|
+
import { dirname as dirname4, resolve as resolve16, relative, sep } from "path";
|
|
6354
6816
|
function toPosixPath(path) {
|
|
6355
6817
|
return path.split(sep).join("/");
|
|
6356
6818
|
}
|
|
@@ -6451,7 +6913,7 @@ __export(exports_init, {
|
|
|
6451
6913
|
DEMO_TASKS_RELATIVE_DIR: () => DEMO_TASKS_RELATIVE_DIR,
|
|
6452
6914
|
DEMO_TASKS: () => DEMO_TASKS
|
|
6453
6915
|
});
|
|
6454
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync11, mkdirSync as
|
|
6916
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
6455
6917
|
import { spawnSync } from "child_process";
|
|
6456
6918
|
import { basename as basename3, resolve as resolve17 } from "path";
|
|
6457
6919
|
import { buildRigInitConfigSource } from "@rig/core";
|
|
@@ -6475,14 +6937,14 @@ function parseRepoSlug(value) {
|
|
|
6475
6937
|
}
|
|
6476
6938
|
function ensureRigPrivateDirs(projectRoot) {
|
|
6477
6939
|
const rigDir = resolve17(projectRoot, ".rig");
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6940
|
+
mkdirSync8(resolve17(rigDir, "state"), { recursive: true });
|
|
6941
|
+
mkdirSync8(resolve17(rigDir, "logs"), { recursive: true });
|
|
6942
|
+
mkdirSync8(resolve17(rigDir, "runs"), { recursive: true });
|
|
6943
|
+
mkdirSync8(resolve17(rigDir, "tmp"), { recursive: true });
|
|
6944
|
+
mkdirSync8(resolve17(projectRoot, "artifacts"), { recursive: true });
|
|
6483
6945
|
const taskConfigPath = resolve17(rigDir, "task-config.json");
|
|
6484
6946
|
if (!existsSync11(taskConfigPath))
|
|
6485
|
-
|
|
6947
|
+
writeFileSync6(taskConfigPath, `{}
|
|
6486
6948
|
`, "utf-8");
|
|
6487
6949
|
}
|
|
6488
6950
|
function ensureGitignoreEntries(projectRoot) {
|
|
@@ -6510,7 +6972,7 @@ function ensureRigConfigPackageDependencies(projectRoot) {
|
|
|
6510
6972
|
...existsSync11(path) ? existing : { name: "rig-project", private: true },
|
|
6511
6973
|
devDependencies
|
|
6512
6974
|
};
|
|
6513
|
-
|
|
6975
|
+
writeFileSync6(path, `${JSON.stringify(next, null, 2)}
|
|
6514
6976
|
`, "utf8");
|
|
6515
6977
|
}
|
|
6516
6978
|
function applyGitHubProjectConfig(source, options) {
|
|
@@ -6536,9 +6998,9 @@ function checkoutForInit(projectRoot, serverKind, strategy) {
|
|
|
6536
6998
|
const selected = strategy ?? { kind: "managed-clone" };
|
|
6537
6999
|
switch (selected.kind) {
|
|
6538
7000
|
case "managed-clone":
|
|
6539
|
-
return { kind: "managed-clone"
|
|
7001
|
+
return { kind: "managed-clone" };
|
|
6540
7002
|
case "current-ref":
|
|
6541
|
-
return { kind: "current-ref",
|
|
7003
|
+
return { kind: "current-ref", ...selected.ref ? { ref: selected.ref } : {} };
|
|
6542
7004
|
case "uploaded-snapshot":
|
|
6543
7005
|
return { kind: "uploaded-snapshot", path: projectRoot, source: "local-working-tree" };
|
|
6544
7006
|
case "existing-path":
|
|
@@ -6791,7 +7253,7 @@ function remoteGitHubAuthMetadata(payload) {
|
|
|
6791
7253
|
};
|
|
6792
7254
|
}
|
|
6793
7255
|
function writeRemoteGitHubAuthState(projectRoot, input) {
|
|
6794
|
-
|
|
7256
|
+
writeFileSync6(resolve17(projectRoot, ".rig", "state", "github-auth.json"), `${JSON.stringify({
|
|
6795
7257
|
authenticated: true,
|
|
6796
7258
|
source: input.source,
|
|
6797
7259
|
storedOnServer: true,
|
|
@@ -6839,7 +7301,7 @@ function runLocalFilesInit(context, options) {
|
|
|
6839
7301
|
console.log("rig.config already exists; leaving it unchanged. Pass --repair to rewrite it.");
|
|
6840
7302
|
} else {
|
|
6841
7303
|
const projectName = basename3(projectRoot) || "rig-project";
|
|
6842
|
-
|
|
7304
|
+
writeFileSync6(configTsPath, buildRigInitConfigSource({
|
|
6843
7305
|
projectName,
|
|
6844
7306
|
taskSource: { kind: "files", path: "tasks" },
|
|
6845
7307
|
useStandardPlugin: true
|
|
@@ -6848,8 +7310,8 @@ function runLocalFilesInit(context, options) {
|
|
|
6848
7310
|
ensureRigConfigPackageDependencies(projectRoot);
|
|
6849
7311
|
const tasksDir = resolve17(projectRoot, "tasks");
|
|
6850
7312
|
if (!existsSync11(tasksDir)) {
|
|
6851
|
-
|
|
6852
|
-
|
|
7313
|
+
mkdirSync8(tasksDir, { recursive: true });
|
|
7314
|
+
writeFileSync6(resolve17(tasksDir, "T-1.json"), `${JSON.stringify({ id: "T-1", title: "My first Rig task", body: "Describe the change you want an agent to make." }, null, 2)}
|
|
6853
7315
|
`, "utf-8");
|
|
6854
7316
|
}
|
|
6855
7317
|
if (context.outputMode !== "json") {
|
|
@@ -6873,7 +7335,7 @@ function runDemoInit(context, options) {
|
|
|
6873
7335
|
console.log("rig.config already exists; leaving it unchanged. Pass --repair to rewrite it for the demo.");
|
|
6874
7336
|
}
|
|
6875
7337
|
} else {
|
|
6876
|
-
|
|
7338
|
+
writeFileSync6(configTsPath, buildRigInitConfigSource({
|
|
6877
7339
|
projectName: basename3(projectRoot) || "rig-demo",
|
|
6878
7340
|
taskSource: { kind: "files", path: DEMO_TASKS_RELATIVE_DIR },
|
|
6879
7341
|
useStandardPlugin: true
|
|
@@ -6882,14 +7344,14 @@ function runDemoInit(context, options) {
|
|
|
6882
7344
|
}
|
|
6883
7345
|
ensureRigConfigPackageDependencies(projectRoot);
|
|
6884
7346
|
const demoTasksDir = resolve17(projectRoot, DEMO_TASKS_RELATIVE_DIR);
|
|
6885
|
-
|
|
7347
|
+
mkdirSync8(demoTasksDir, { recursive: true });
|
|
6886
7348
|
const taskIds = [];
|
|
6887
7349
|
for (const task of DEMO_TASKS) {
|
|
6888
7350
|
const id = String(task.id);
|
|
6889
7351
|
taskIds.push(id);
|
|
6890
7352
|
const taskPath = resolve17(demoTasksDir, `${id}.json`);
|
|
6891
7353
|
if (!existsSync11(taskPath)) {
|
|
6892
|
-
|
|
7354
|
+
writeFileSync6(taskPath, `${JSON.stringify(task, null, 2)}
|
|
6893
7355
|
`, "utf-8");
|
|
6894
7356
|
}
|
|
6895
7357
|
}
|
|
@@ -6917,21 +7379,32 @@ function runDemoInit(context, options) {
|
|
|
6917
7379
|
}
|
|
6918
7380
|
async function runControlPlaneInit(context, options) {
|
|
6919
7381
|
const projectRoot = context.projectRoot;
|
|
6920
|
-
const
|
|
7382
|
+
const existingRepoConnection = readRepoConnection(projectRoot);
|
|
7383
|
+
const selectedConnection = (() => {
|
|
7384
|
+
try {
|
|
7385
|
+
return resolveSelectedConnection(projectRoot);
|
|
7386
|
+
} catch {
|
|
7387
|
+
return null;
|
|
7388
|
+
}
|
|
7389
|
+
})();
|
|
7390
|
+
const selectedRemote = selectedConnection?.connection.kind === "remote" ? { alias: selectedConnection.alias, connection: selectedConnection.connection } : null;
|
|
7391
|
+
const detectedSlug = options.repoSlug ?? existingRepoConnection?.project ?? detectOriginRepoSlug(projectRoot);
|
|
7392
|
+
const serverKind = options.server ?? (selectedRemote ? "remote" : "local");
|
|
6921
7393
|
if (!detectedSlug) {
|
|
6922
7394
|
const authMethod2 = options.githubAuthMethod ?? (options.githubToken ? "token" : "skip");
|
|
6923
|
-
if (
|
|
7395
|
+
if (serverKind === "local" && authMethod2 === "skip") {
|
|
6924
7396
|
return runLocalFilesInit(context, options);
|
|
6925
7397
|
}
|
|
6926
7398
|
throw new CliError("Could not detect GitHub repo slug from origin. Pass --repo owner/repo \u2014 or run `rig init --yes --server local --github-auth skip` for a local files-source project without GitHub.", 1);
|
|
6927
7399
|
}
|
|
6928
7400
|
const repo = parseRepoSlug(detectedSlug);
|
|
6929
|
-
const
|
|
6930
|
-
const
|
|
7401
|
+
const connectionAlias = options.connectionAlias ?? (serverKind === "local" ? "local" : selectedRemote?.alias ?? "remote");
|
|
7402
|
+
const selectedRemoteUrl = selectedRemote && (!options.connectionAlias || options.connectionAlias === selectedRemote.alias) ? selectedRemote.connection.baseUrl : undefined;
|
|
7403
|
+
const remoteUrl = serverKind === "remote" ? (options.remoteUrl ?? selectedRemoteUrl)?.replace(/\/+$/, "") : undefined;
|
|
6931
7404
|
if (serverKind === "remote") {
|
|
6932
|
-
if (!
|
|
6933
|
-
throw new CliError("Missing --remote-url for --server remote.", 1, { hint: "Re-run as `rig init --server remote --remote-url https://your-rig-server
|
|
6934
|
-
upsertGlobalConnection(connectionAlias, { kind: "remote", baseUrl:
|
|
7405
|
+
if (!remoteUrl)
|
|
7406
|
+
throw new CliError("Missing --remote-url for --server remote.", 1, { hint: "Re-run as `rig init --server remote --remote-url https://your-rig-server`, or first select a saved remote with `rig server use <alias>`." });
|
|
7407
|
+
upsertGlobalConnection(connectionAlias, { kind: "remote", baseUrl: remoteUrl });
|
|
6935
7408
|
}
|
|
6936
7409
|
writeRepoConnection(projectRoot, {
|
|
6937
7410
|
selected: connectionAlias,
|
|
@@ -6954,11 +7427,11 @@ async function runControlPlaneInit(context, options) {
|
|
|
6954
7427
|
taskSource: { kind: "github-issues", owner: repo.owner, repo: repo.repo },
|
|
6955
7428
|
useStandardPlugin: true
|
|
6956
7429
|
}), options);
|
|
6957
|
-
|
|
7430
|
+
writeFileSync6(configTsPath, source, "utf-8");
|
|
6958
7431
|
}
|
|
6959
7432
|
ensureRigConfigPackageDependencies(projectRoot);
|
|
6960
7433
|
}
|
|
6961
|
-
|
|
7434
|
+
writeFileSync6(resolve17(projectRoot, ".rig", "state", "project-link.json"), `${JSON.stringify({ repoSlug: repo.slug, connection: connectionAlias, linkedAt: new Date().toISOString() }, null, 2)}
|
|
6962
7435
|
`, "utf8");
|
|
6963
7436
|
const checkout = checkoutForInit(projectRoot, serverKind, options.remoteCheckout);
|
|
6964
7437
|
let uploadedSnapshot = null;
|
|
@@ -6973,7 +7446,7 @@ async function runControlPlaneInit(context, options) {
|
|
|
6973
7446
|
let githubAuth = null;
|
|
6974
7447
|
let deviceAuth = null;
|
|
6975
7448
|
const authMethod = options.githubAuthMethod ?? (options.githubToken ? "token" : "skip");
|
|
6976
|
-
const remoteGhTokenWarning = serverKind === "remote" && authMethod === "gh" ? `This sends a GitHub token from this machine to ${
|
|
7449
|
+
const remoteGhTokenWarning = serverKind === "remote" && authMethod === "gh" ? `This sends a GitHub token from this machine to ${remoteUrl ?? "the remote Rig server"}.` : null;
|
|
6977
7450
|
if (remoteGhTokenWarning && !options.yes) {
|
|
6978
7451
|
throw new CliError(`${remoteGhTokenWarning} Re-run with --yes to confirm this explicit token transfer.`, 1);
|
|
6979
7452
|
}
|
|
@@ -7353,8 +7826,8 @@ var init_init = __esm(() => {
|
|
|
7353
7826
|
|
|
7354
7827
|
// packages/cli/src/commands/github.ts
|
|
7355
7828
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
7356
|
-
import { mkdirSync as
|
|
7357
|
-
import { dirname as
|
|
7829
|
+
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
7830
|
+
import { dirname as dirname5, resolve as resolve18 } from "path";
|
|
7358
7831
|
function printPayload(context, payload, fallback) {
|
|
7359
7832
|
if (context.outputMode === "json")
|
|
7360
7833
|
console.log(JSON.stringify(payload, null, 2));
|
|
@@ -7393,8 +7866,8 @@ function persistRemoteAuthSession(context, source, result, fallbackToken) {
|
|
|
7393
7866
|
return;
|
|
7394
7867
|
const repo = readRepoConnection(context.projectRoot);
|
|
7395
7868
|
const path = resolve18(context.projectRoot, ".rig", "state", "github-auth.json");
|
|
7396
|
-
|
|
7397
|
-
|
|
7869
|
+
mkdirSync9(dirname5(path), { recursive: true });
|
|
7870
|
+
writeFileSync7(path, `${JSON.stringify({
|
|
7398
7871
|
authenticated: true,
|
|
7399
7872
|
source,
|
|
7400
7873
|
storedOnServer: true,
|
|
@@ -8905,7 +9378,7 @@ __export(exports__pi_frontend, {
|
|
|
8905
9378
|
buildOperatorPiEnv: () => buildOperatorPiEnv,
|
|
8906
9379
|
attachRunBundledPiFrontend: () => attachRunBundledPiFrontend
|
|
8907
9380
|
});
|
|
8908
|
-
import { existsSync as existsSync14, mkdirSync as
|
|
9381
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync10, mkdtempSync, readFileSync as readFileSync10, rmSync as rmSync5, writeFileSync as writeFileSync8 } from "fs";
|
|
8909
9382
|
import { homedir as homedir6, tmpdir } from "os";
|
|
8910
9383
|
import { join as join3 } from "path";
|
|
8911
9384
|
import { main as runPiMain } from "@earendil-works/pi-coding-agent";
|
|
@@ -8957,7 +9430,7 @@ function statusFromRunDetails(run) {
|
|
|
8957
9430
|
async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
8958
9431
|
const server = await ensureServerForCli(context.projectRoot);
|
|
8959
9432
|
const localCwd = join3(homedir6(), ".rig", "drones", runId.slice(0, 8));
|
|
8960
|
-
|
|
9433
|
+
mkdirSync10(localCwd, { recursive: true });
|
|
8961
9434
|
trustDroneCwd(localCwd);
|
|
8962
9435
|
installRigPiTheme();
|
|
8963
9436
|
let sessionFileArg = [];
|
|
@@ -8979,7 +9452,7 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
8979
9452
|
return line;
|
|
8980
9453
|
}).join(`
|
|
8981
9454
|
`);
|
|
8982
|
-
|
|
9455
|
+
writeFileSync8(localSessionPath, content);
|
|
8983
9456
|
sessionFileArg = ["--session", localSessionPath];
|
|
8984
9457
|
}
|
|
8985
9458
|
} catch {}
|
|
@@ -8995,12 +9468,12 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
8995
9468
|
function trustDroneCwd(localCwd) {
|
|
8996
9469
|
try {
|
|
8997
9470
|
const agentDir = join3(homedir6(), ".pi", "agent");
|
|
8998
|
-
|
|
9471
|
+
mkdirSync10(agentDir, { recursive: true });
|
|
8999
9472
|
const trustPath = join3(agentDir, "trust.json");
|
|
9000
9473
|
const store = existsSync14(trustPath) ? JSON.parse(readFileSync10(trustPath, "utf8")) : {};
|
|
9001
9474
|
if (store[localCwd] !== true) {
|
|
9002
9475
|
store[localCwd] = true;
|
|
9003
|
-
|
|
9476
|
+
writeFileSync8(trustPath, `${JSON.stringify(store, null, "\t")}
|
|
9004
9477
|
`);
|
|
9005
9478
|
}
|
|
9006
9479
|
} catch {}
|
|
@@ -9008,12 +9481,12 @@ function trustDroneCwd(localCwd) {
|
|
|
9008
9481
|
function installRigPiTheme() {
|
|
9009
9482
|
try {
|
|
9010
9483
|
const themesDir = join3(homedir6(), ".pi", "agent", "themes");
|
|
9011
|
-
|
|
9484
|
+
mkdirSync10(themesDir, { recursive: true });
|
|
9012
9485
|
const themePath = join3(themesDir, "rig.json");
|
|
9013
9486
|
const next = `${JSON.stringify(RIG_PI_THEME, null, "\t")}
|
|
9014
9487
|
`;
|
|
9015
9488
|
if (!existsSync14(themePath) || readFileSync10(themePath, "utf8") !== next) {
|
|
9016
|
-
|
|
9489
|
+
writeFileSync8(themePath, next);
|
|
9017
9490
|
}
|
|
9018
9491
|
} catch {}
|
|
9019
9492
|
}
|
|
@@ -9797,13 +10270,46 @@ function parseConnection(alias, value, options) {
|
|
|
9797
10270
|
}
|
|
9798
10271
|
return { kind: "remote", baseUrl: parsed.toString().replace(/\/+$/, "") };
|
|
9799
10272
|
}
|
|
9800
|
-
function printJsonOrText(context,
|
|
9801
|
-
if (context.outputMode
|
|
9802
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
9803
|
-
} else {
|
|
10273
|
+
function printJsonOrText(context, _payload, text2) {
|
|
10274
|
+
if (context.outputMode !== "json") {
|
|
9804
10275
|
console.log(text2);
|
|
9805
10276
|
}
|
|
9806
10277
|
}
|
|
10278
|
+
function formatRemoteProjectLinkText(result) {
|
|
10279
|
+
return formatSuccessCard(result.ok ? "Remote project link ready" : "Remote project link needs repair", [
|
|
10280
|
+
["selected", result.alias ?? "remote"],
|
|
10281
|
+
["target", result.baseUrl ?? "unknown"],
|
|
10282
|
+
["repo", result.repoSlug ?? "owner/repo"],
|
|
10283
|
+
["status", result.status],
|
|
10284
|
+
...result.serverProjectRoot ? [["server root", result.serverProjectRoot]] : [],
|
|
10285
|
+
["next", result.ok ? result.next ?? "rig task list" : result.hint]
|
|
10286
|
+
]);
|
|
10287
|
+
}
|
|
10288
|
+
function parseRepairLinkArgs(rest, usage) {
|
|
10289
|
+
let repoSlug;
|
|
10290
|
+
let mode = "prepare-if-missing";
|
|
10291
|
+
const pending = [...rest];
|
|
10292
|
+
while (pending.length > 0) {
|
|
10293
|
+
const token = pending.shift();
|
|
10294
|
+
if (token === "--repo") {
|
|
10295
|
+
const value = pending.shift()?.trim();
|
|
10296
|
+
if (!value)
|
|
10297
|
+
throw new CliError(`Missing --repo value. Usage: ${usage}`, 1);
|
|
10298
|
+
const normalized = normalizeRepoSlug(value);
|
|
10299
|
+
if (!normalized)
|
|
10300
|
+
throw new CliError(`Invalid --repo value: ${value}`, 1, { hint: "Use the canonical owner/repo slug, e.g. `--repo humanity-org/humanwork`." });
|
|
10301
|
+
repoSlug = normalized;
|
|
10302
|
+
} else if (token === "--backfill-only") {
|
|
10303
|
+
mode = "backfill-only";
|
|
10304
|
+
} else if (token === "--prepare") {
|
|
10305
|
+
mode = "prepare-if-missing";
|
|
10306
|
+
} else {
|
|
10307
|
+
throw new CliError(`Unexpected argument: ${String(token)}
|
|
10308
|
+
Usage: ${usage}`, 1);
|
|
10309
|
+
}
|
|
10310
|
+
}
|
|
10311
|
+
return { repoSlug, mode };
|
|
10312
|
+
}
|
|
9807
10313
|
async function promptForConnectionAlias(context) {
|
|
9808
10314
|
const state = readGlobalConnections();
|
|
9809
10315
|
const repo = readRepoConnection(context.projectRoot);
|
|
@@ -9857,37 +10363,67 @@ async function executeConnectionCommand(context, args, options) {
|
|
|
9857
10363
|
}
|
|
9858
10364
|
if (!alias)
|
|
9859
10365
|
throw new CliError(`Missing alias. Usage: ${usageName(options)} use <alias|local>`, 1);
|
|
10366
|
+
let selectedConnection = { kind: "local", mode: "auto" };
|
|
9860
10367
|
if (alias !== "local") {
|
|
9861
10368
|
const state = readGlobalConnections();
|
|
9862
|
-
|
|
10369
|
+
const connection = state.connections[alias];
|
|
10370
|
+
if (!connection)
|
|
9863
10371
|
throw new CliError(`Unknown Rig server: ${alias}`, 1, { hint: "Run `rig server list` to see saved aliases, or save one with `rig server add <alias> <url>`." });
|
|
10372
|
+
selectedConnection = connection;
|
|
9864
10373
|
}
|
|
9865
10374
|
const previousRepo = readRepoConnection(context.projectRoot);
|
|
10375
|
+
const preserveRemoteRoot = Boolean(previousRepo?.serverProjectRoot && previousRepo.selected === alias && selectedConnection.kind === "remote" && previousRepo.serverProjectRootAlias === alias && previousRepo.serverProjectRootBaseUrl === selectedConnection.baseUrl);
|
|
9866
10376
|
const repoState = {
|
|
9867
10377
|
selected: alias,
|
|
9868
10378
|
...previousRepo?.project ? { project: previousRepo.project } : {},
|
|
9869
10379
|
linkedAt: new Date().toISOString(),
|
|
9870
|
-
...
|
|
10380
|
+
...preserveRemoteRoot ? {
|
|
10381
|
+
serverProjectRoot: previousRepo.serverProjectRoot,
|
|
10382
|
+
serverProjectRootAlias: previousRepo.serverProjectRootAlias,
|
|
10383
|
+
serverProjectRootBaseUrl: previousRepo.serverProjectRootBaseUrl
|
|
10384
|
+
} : {}
|
|
9871
10385
|
};
|
|
9872
10386
|
writeRepoConnection(context.projectRoot, repoState);
|
|
9873
|
-
|
|
10387
|
+
const remoteProjectLink = alias !== "local" ? await ensureRemoteProjectRootLink(context.projectRoot, { mode: "backfill-only" }).catch((error) => ({
|
|
10388
|
+
ok: false,
|
|
10389
|
+
status: "error",
|
|
10390
|
+
message: error instanceof Error ? error.message : String(error),
|
|
10391
|
+
hint: "Run `rig server repair-link` after authenticating the selected remote."
|
|
10392
|
+
})) : null;
|
|
10393
|
+
const latestRepo = readRepoConnection(context.projectRoot);
|
|
10394
|
+
const details = { selected: latestRepo?.selected ?? alias, repo: latestRepo, remoteProjectLink };
|
|
10395
|
+
printJsonOrText(context, details, formatSuccessCard("Rig server selected", [
|
|
9874
10396
|
["selected", alias],
|
|
9875
10397
|
["scope", "this repo"],
|
|
9876
|
-
["
|
|
10398
|
+
...remoteProjectLink ? [["remote link", remoteProjectLink.ok ? `ready (${remoteProjectLink.serverProjectRoot ?? "linked"})` : `${remoteProjectLink.status}: ${remoteProjectLink.hint}`]] : [],
|
|
10399
|
+
["next", remoteProjectLink && !remoteProjectLink.ok ? "rig server repair-link" : "rig task list"]
|
|
9877
10400
|
]));
|
|
9878
|
-
return { ok: true, group: options.group, command: "use", details
|
|
10401
|
+
return { ok: true, group: options.group, command: "use", details };
|
|
10402
|
+
}
|
|
10403
|
+
case "repair-link": {
|
|
10404
|
+
const parsed = parseRepairLinkArgs(rest, `${usageName(options)} repair-link [--prepare|--backfill-only] [--repo owner/repo]`);
|
|
10405
|
+
const result = await repairRemoteProjectRootLink(context, parsed);
|
|
10406
|
+
printJsonOrText(context, result, formatRemoteProjectLinkText(result));
|
|
10407
|
+
return { ok: true, group: options.group, command: "repair-link", details: result };
|
|
9879
10408
|
}
|
|
9880
10409
|
case "status": {
|
|
9881
10410
|
requireNoExtraArgs(rest, `${usageName(options)} status`);
|
|
9882
10411
|
const repo = readRepoConnection(context.projectRoot);
|
|
9883
10412
|
const global = readGlobalConnections();
|
|
9884
|
-
const
|
|
9885
|
-
|
|
10413
|
+
const remoteProjectLink = repo?.selected && repo.selected !== "local" ? await ensureRemoteProjectRootLink(context.projectRoot, { mode: "backfill-only" }).catch((error) => ({
|
|
10414
|
+
ok: false,
|
|
10415
|
+
status: "error",
|
|
10416
|
+
message: error instanceof Error ? error.message : String(error),
|
|
10417
|
+
hint: "Run `rig server repair-link` after authenticating the selected remote."
|
|
10418
|
+
})) : null;
|
|
10419
|
+
const latestRepo = readRepoConnection(context.projectRoot) ?? repo;
|
|
10420
|
+
const details = { selected: latestRepo?.selected ?? "local", repo: latestRepo, connections: global.connections, remoteProjectLink };
|
|
10421
|
+
printJsonOrText(context, details, formatConnectionStatus(details.selected, global.connections, latestRepo ?? null, remoteProjectLink));
|
|
9886
10422
|
return { ok: true, group: options.group, command: "status", details };
|
|
9887
10423
|
}
|
|
9888
10424
|
default:
|
|
9889
10425
|
throw new CliError(`Unknown ${options.group} command: ${String(command)}
|
|
9890
|
-
Usage: ${usageName(options)} <list|add|use|status>`, 1);
|
|
10426
|
+
Usage: ${usageName(options)} <list|add|use|status|repair-link>`, 1);
|
|
9891
10427
|
}
|
|
9892
10428
|
}
|
|
9893
10429
|
var init_connect = __esm(() => {
|
|
@@ -9895,13 +10431,14 @@ var init_connect = __esm(() => {
|
|
|
9895
10431
|
init_runner();
|
|
9896
10432
|
init__connection_state();
|
|
9897
10433
|
init__cli_format();
|
|
10434
|
+
init__server_client();
|
|
9898
10435
|
});
|
|
9899
10436
|
|
|
9900
10437
|
// packages/cli/src/commands/server.ts
|
|
9901
10438
|
import { resolveRigServerCommand } from "@rig/runtime/local-server";
|
|
9902
10439
|
async function executeServer(context, args, options) {
|
|
9903
10440
|
const [command = "status", ...rest] = args;
|
|
9904
|
-
if (["status", "list", "add", "use"].includes(command)) {
|
|
10441
|
+
if (["status", "list", "add", "use", "repair-link"].includes(command)) {
|
|
9905
10442
|
return executeConnectionCommand(context, [command, ...rest], { group: "server", interactiveUse: true });
|
|
9906
10443
|
}
|
|
9907
10444
|
switch (command) {
|
|
@@ -10688,7 +11225,7 @@ var init_task = __esm(() => {
|
|
|
10688
11225
|
});
|
|
10689
11226
|
|
|
10690
11227
|
// packages/cli/src/commands/task-run-driver.ts
|
|
10691
|
-
import { copyFileSync as copyFileSync3, existsSync as existsSync15, mkdirSync as
|
|
11228
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync15, mkdirSync as mkdirSync11, readFileSync as readFileSync12, statSync as statSync2, writeFileSync as writeFileSync9 } from "fs";
|
|
10692
11229
|
import { resolve as resolve23 } from "path";
|
|
10693
11230
|
import { spawn as spawn2, spawnSync as spawnSync4 } from "child_process";
|
|
10694
11231
|
import { createInterface as createLineInterface } from "readline";
|
|
@@ -10791,7 +11328,7 @@ function copyUntrackedDirtyFiles(sourceRoot, targetRoot) {
|
|
|
10791
11328
|
try {
|
|
10792
11329
|
if (!statSync2(sourcePath).isFile())
|
|
10793
11330
|
continue;
|
|
10794
|
-
|
|
11331
|
+
mkdirSync11(resolve23(targetPath, ".."), { recursive: true });
|
|
10795
11332
|
copyFileSync3(sourcePath, targetPath);
|
|
10796
11333
|
copied += 1;
|
|
10797
11334
|
} catch {}
|
|
@@ -11662,8 +12199,8 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
11662
12199
|
artifactPath: planningClassification.planningRequired ? planningArtifactPath : null,
|
|
11663
12200
|
classifiedAt: new Date().toISOString()
|
|
11664
12201
|
};
|
|
11665
|
-
|
|
11666
|
-
|
|
12202
|
+
mkdirSync11(resolve23(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
|
|
12203
|
+
writeFileSync9(resolve23(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
|
|
11667
12204
|
`, "utf8");
|
|
11668
12205
|
patchAuthorityRun(context.projectRoot, input.runId, { planning: persistedPlanning });
|
|
11669
12206
|
prompt = `${prompt}
|
|
@@ -11810,8 +12347,8 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
11810
12347
|
const dirty = applyDirtyBaselineSnapshot({ sourceRoot: context.projectRoot, targetRoot: latestRuntimeWorkspace });
|
|
11811
12348
|
const readyFile = childEnv.RIG_DIRTY_BASELINE_READY_FILE;
|
|
11812
12349
|
if (readyFile) {
|
|
11813
|
-
|
|
11814
|
-
|
|
12350
|
+
mkdirSync11(resolve23(readyFile, ".."), { recursive: true });
|
|
12351
|
+
writeFileSync9(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
|
|
11815
12352
|
`, "utf8");
|
|
11816
12353
|
}
|
|
11817
12354
|
appendRunLog(context.projectRoot, input.runId, {
|
|
@@ -12757,7 +13294,7 @@ var init_test = __esm(() => {
|
|
|
12757
13294
|
});
|
|
12758
13295
|
|
|
12759
13296
|
// packages/cli/src/commands/setup.ts
|
|
12760
|
-
import { existsSync as existsSync16, mkdirSync as
|
|
13297
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync12, readdirSync as readdirSync3, writeFileSync as writeFileSync10 } from "fs";
|
|
12761
13298
|
import { resolve as resolve24 } from "path";
|
|
12762
13299
|
import { createPluginHost } from "@rig/core";
|
|
12763
13300
|
import {
|
|
@@ -12812,12 +13349,12 @@ function runSetupInit(projectRoot) {
|
|
|
12812
13349
|
const stateDir = resolveControlPlaneHostStateDir(projectRoot);
|
|
12813
13350
|
const logsDir = resolveControlPlaneHostLogsDir(projectRoot);
|
|
12814
13351
|
const artifactsDir = resolveControlPlaneArtifactsDir(projectRoot);
|
|
12815
|
-
|
|
12816
|
-
|
|
12817
|
-
|
|
13352
|
+
mkdirSync12(stateDir, { recursive: true });
|
|
13353
|
+
mkdirSync12(logsDir, { recursive: true });
|
|
13354
|
+
mkdirSync12(artifactsDir, { recursive: true });
|
|
12818
13355
|
const failuresPath = resolve24(stateDir, "failed_approaches.md");
|
|
12819
13356
|
if (!existsSync16(failuresPath)) {
|
|
12820
|
-
|
|
13357
|
+
writeFileSync10(failuresPath, `# Failed Approaches
|
|
12821
13358
|
|
|
12822
13359
|
`, "utf-8");
|
|
12823
13360
|
}
|
|
@@ -16007,6 +16544,7 @@ async function stopRunFromDetail(ctx, runId) {
|
|
|
16007
16544
|
}
|
|
16008
16545
|
|
|
16009
16546
|
// packages/cli/src/app-opentui/adapters/server.ts
|
|
16547
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
16010
16548
|
var SERVER_PROBE_TIMEOUT_MS = Number(process.env.RIG_SERVER_PROBE_TIMEOUT_MS) || 5000;
|
|
16011
16549
|
function withTimeout(promise, ms, label) {
|
|
16012
16550
|
return new Promise((resolve28, reject) => {
|
|
@@ -16044,11 +16582,128 @@ function startLocalRequested(ctx) {
|
|
|
16044
16582
|
const action = intent.action;
|
|
16045
16583
|
return action?.payload?.startLocal === true;
|
|
16046
16584
|
}
|
|
16585
|
+
async function serverAliases(projectRoot) {
|
|
16586
|
+
const { readGlobalConnections: readGlobalConnections2, readRepoConnection: readRepoConnection2 } = await Promise.resolve().then(() => (init__connection_state(), exports__connection_state));
|
|
16587
|
+
const selected = readRepoConnection2(projectRoot)?.selected ?? "local";
|
|
16588
|
+
const global = readGlobalConnections2();
|
|
16589
|
+
const aliases = [{ alias: "local", kind: "local", selected: selected === "local" }];
|
|
16590
|
+
for (const [alias, connection] of Object.entries(global.connections)) {
|
|
16591
|
+
aliases.push({
|
|
16592
|
+
alias,
|
|
16593
|
+
kind: connection.kind,
|
|
16594
|
+
...connection.kind === "remote" ? { baseUrl: connection.baseUrl } : {},
|
|
16595
|
+
selected: alias === selected
|
|
16596
|
+
});
|
|
16597
|
+
}
|
|
16598
|
+
return aliases;
|
|
16599
|
+
}
|
|
16600
|
+
function firstString2(parts, offset = 0) {
|
|
16601
|
+
return parts.slice(offset).find((part) => part.trim() && !part.startsWith("-"))?.trim();
|
|
16602
|
+
}
|
|
16603
|
+
function normalizeUrl(value) {
|
|
16604
|
+
const trimmed = value?.trim().replace(/\/+$/, "");
|
|
16605
|
+
if (!trimmed)
|
|
16606
|
+
return;
|
|
16607
|
+
return /^https?:\/\//i.test(trimmed) ? trimmed : undefined;
|
|
16608
|
+
}
|
|
16609
|
+
async function useLocalServerFromApp(ctx) {
|
|
16610
|
+
const label = "Selecting local server";
|
|
16611
|
+
emitStarted(ctx, label);
|
|
16612
|
+
try {
|
|
16613
|
+
const projectRoot = projectRootOf(ctx);
|
|
16614
|
+
const { readRepoConnection: readRepoConnection2, writeRepoConnection: writeRepoConnection2 } = await Promise.resolve().then(() => (init__connection_state(), exports__connection_state));
|
|
16615
|
+
const previous = readRepoConnection2(projectRoot);
|
|
16616
|
+
writeRepoConnection2(projectRoot, {
|
|
16617
|
+
selected: "local",
|
|
16618
|
+
...previous?.project ? { project: previous.project } : {},
|
|
16619
|
+
linkedAt: new Date().toISOString()
|
|
16620
|
+
});
|
|
16621
|
+
emitCompleted(ctx, label, { selected: "local" });
|
|
16622
|
+
return refreshServerStatus(ctx);
|
|
16623
|
+
} catch (error) {
|
|
16624
|
+
emitFailed(ctx, label, error);
|
|
16625
|
+
throw error;
|
|
16626
|
+
}
|
|
16627
|
+
}
|
|
16628
|
+
async function useRemoteServerFromApp(ctx, alias) {
|
|
16629
|
+
const label = alias ? `Selecting remote ${alias}` : "Selecting remote server";
|
|
16630
|
+
emitStarted(ctx, label);
|
|
16631
|
+
try {
|
|
16632
|
+
const cleanAlias = alias?.trim();
|
|
16633
|
+
if (!cleanAlias)
|
|
16634
|
+
throw new Error("Enter a saved remote alias, or add one with: add remote \u2192 <alias> <https-url>.");
|
|
16635
|
+
const projectRoot = projectRootOf(ctx);
|
|
16636
|
+
const { readGlobalConnections: readGlobalConnections2, readRepoConnection: readRepoConnection2, writeRepoConnection: writeRepoConnection2 } = await Promise.resolve().then(() => (init__connection_state(), exports__connection_state));
|
|
16637
|
+
const connection = readGlobalConnections2().connections[cleanAlias];
|
|
16638
|
+
if (!connection)
|
|
16639
|
+
throw new Error(`Remote alias ${cleanAlias} is not saved yet. Use add remote first.`);
|
|
16640
|
+
if (connection.kind !== "remote")
|
|
16641
|
+
throw new Error(`${cleanAlias} is not a remote server alias.`);
|
|
16642
|
+
const previous = readRepoConnection2(projectRoot);
|
|
16643
|
+
writeRepoConnection2(projectRoot, {
|
|
16644
|
+
selected: cleanAlias,
|
|
16645
|
+
...previous?.project ? { project: previous.project } : {},
|
|
16646
|
+
linkedAt: new Date().toISOString()
|
|
16647
|
+
});
|
|
16648
|
+
emitCompleted(ctx, label, { selected: cleanAlias, baseUrl: connection.baseUrl });
|
|
16649
|
+
return refreshServerStatus(ctx);
|
|
16650
|
+
} catch (error) {
|
|
16651
|
+
emitFailed(ctx, label, error);
|
|
16652
|
+
throw error;
|
|
16653
|
+
}
|
|
16654
|
+
}
|
|
16655
|
+
async function addRemoteServerFromApp(ctx, args) {
|
|
16656
|
+
const label = "Adding remote server";
|
|
16657
|
+
emitStarted(ctx, label);
|
|
16658
|
+
try {
|
|
16659
|
+
const alias = firstString2(args, 2);
|
|
16660
|
+
const url = normalizeUrl(firstString2(args, alias ? args.indexOf(alias) + 1 : 3));
|
|
16661
|
+
if (!alias || !url)
|
|
16662
|
+
throw new Error("Add remote expects: <alias> <https-url>. Example: prod https://rig.example.com");
|
|
16663
|
+
const projectRoot = projectRootOf(ctx);
|
|
16664
|
+
const { readRepoConnection: readRepoConnection2, upsertGlobalConnection: upsertGlobalConnection2, writeRepoConnection: writeRepoConnection2 } = await Promise.resolve().then(() => (init__connection_state(), exports__connection_state));
|
|
16665
|
+
upsertGlobalConnection2(alias, { kind: "remote", baseUrl: url });
|
|
16666
|
+
const previous = readRepoConnection2(projectRoot);
|
|
16667
|
+
writeRepoConnection2(projectRoot, {
|
|
16668
|
+
selected: alias,
|
|
16669
|
+
...previous?.project ? { project: previous.project } : {},
|
|
16670
|
+
linkedAt: new Date().toISOString()
|
|
16671
|
+
});
|
|
16672
|
+
emitCompleted(ctx, label, { alias, baseUrl: url });
|
|
16673
|
+
return refreshServerStatus(ctx);
|
|
16674
|
+
} catch (error) {
|
|
16675
|
+
emitFailed(ctx, label, error);
|
|
16676
|
+
throw error;
|
|
16677
|
+
}
|
|
16678
|
+
}
|
|
16679
|
+
async function importGitHubAuthFromGhApp(ctx) {
|
|
16680
|
+
const label = "Importing GitHub auth";
|
|
16681
|
+
emitStarted(ctx, label);
|
|
16682
|
+
try {
|
|
16683
|
+
const projectRoot = projectRootOf(ctx);
|
|
16684
|
+
const token = spawnSync5("gh", ["auth", "token"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 1e4 }).stdout.trim();
|
|
16685
|
+
if (!token)
|
|
16686
|
+
throw new Error("Could not read GitHub token from gh. Sign in with gh auth login, then retry import auth.");
|
|
16687
|
+
const runtime = await runtimeOf(ctx);
|
|
16688
|
+
const { postGitHubTokenViaServer: postGitHubTokenViaServer2, setGitHubBearerTokenForCurrentProcess: setGitHubBearerTokenForCurrentProcess2 } = await Promise.resolve().then(() => (init__server_client(), exports__server_client));
|
|
16689
|
+
const { readRepoConnection: readRepoConnection2 } = await Promise.resolve().then(() => (init__connection_state(), exports__connection_state));
|
|
16690
|
+
const selectedRepo = readRepoConnection2(projectRoot)?.project;
|
|
16691
|
+
const payload = await postGitHubTokenViaServer2(runtime, token, selectedRepo ? { selectedRepo } : {});
|
|
16692
|
+
const apiSessionToken = payload && typeof payload === "object" && !Array.isArray(payload) ? payload.apiSessionToken : undefined;
|
|
16693
|
+
setGitHubBearerTokenForCurrentProcess2(typeof apiSessionToken === "string" ? apiSessionToken : token, projectRoot);
|
|
16694
|
+
emitCompleted(ctx, label, { selectedRepo: selectedRepo ?? null });
|
|
16695
|
+
return refreshServerStatus(ctx);
|
|
16696
|
+
} catch (error) {
|
|
16697
|
+
emitFailed(ctx, label, error);
|
|
16698
|
+
throw error;
|
|
16699
|
+
}
|
|
16700
|
+
}
|
|
16047
16701
|
async function startLocalServerFromApp(ctx) {
|
|
16048
16702
|
const label = "Starting local server";
|
|
16049
16703
|
emitStarted(ctx, label);
|
|
16050
16704
|
patchData(ctx, {
|
|
16051
16705
|
lastIntent: undefined,
|
|
16706
|
+
remoteProjectLink: undefined,
|
|
16052
16707
|
server: { label: "starting local server", reachable: false, error: "spawning local rig-server (detached)\u2026" }
|
|
16053
16708
|
});
|
|
16054
16709
|
try {
|
|
@@ -16073,32 +16728,61 @@ async function startLocalServerFromApp(ctx) {
|
|
|
16073
16728
|
reachable: false,
|
|
16074
16729
|
error: error instanceof Error ? error.message : String(error)
|
|
16075
16730
|
};
|
|
16076
|
-
patchData(ctx, { server: state, lastRefreshError: state.error });
|
|
16731
|
+
patchData(ctx, { server: state, remoteProjectLink: undefined, lastRefreshError: state.error });
|
|
16077
16732
|
patchFooter(ctx, { server: "unavailable" });
|
|
16078
|
-
emitCompleted(ctx, label, {
|
|
16733
|
+
emitCompleted(ctx, label, { serverLabel: state.label, reachable: false, error: state.error });
|
|
16079
16734
|
return state;
|
|
16080
16735
|
}
|
|
16081
16736
|
}
|
|
16737
|
+
async function repairRemoteProjectRootLinkFromApp(ctx) {
|
|
16738
|
+
const label = "Repairing remote project link";
|
|
16739
|
+
emitStarted(ctx, label);
|
|
16740
|
+
try {
|
|
16741
|
+
const projectRoot = projectRootOf(ctx);
|
|
16742
|
+
const { ensureRemoteProjectRootLink: ensureRemoteProjectRootLink2 } = await Promise.resolve().then(() => (init__server_client(), exports__server_client));
|
|
16743
|
+
emitProgress(ctx, label, "backfilling or preparing server-host checkout");
|
|
16744
|
+
const result = await ensureRemoteProjectRootLink2(projectRoot, { mode: "prepare-if-missing" });
|
|
16745
|
+
patchData(ctx, { remoteProjectLink: result, server: { label: result.alias ?? "remote", baseUrl: result.baseUrl, kind: "remote", reachable: result.status !== "not_remote", remoteProjectLink: result } });
|
|
16746
|
+
patchFooter(ctx, { server: result.alias ?? "remote", message: `remote link ${result.status}` });
|
|
16747
|
+
if (!result.ok) {
|
|
16748
|
+
const error = new Error(result.message);
|
|
16749
|
+
error.hint = result.hint;
|
|
16750
|
+
patchData(ctx, { lastRefreshError: result.message });
|
|
16751
|
+
throw error;
|
|
16752
|
+
}
|
|
16753
|
+
emitCompleted(ctx, label, { repoSlug: result.repoSlug, serverProjectRoot: result.serverProjectRoot, status: result.status });
|
|
16754
|
+
return result;
|
|
16755
|
+
} catch (error) {
|
|
16756
|
+
const message2 = error instanceof Error ? error.message : String(error);
|
|
16757
|
+
const existing = ctx.getState().data?.remoteProjectLink;
|
|
16758
|
+
const remoteProjectLink = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : { ok: false, status: "error", message: message2 };
|
|
16759
|
+
patchData(ctx, { lastRefreshError: message2, remoteProjectLink });
|
|
16760
|
+
emitCompleted(ctx, label, { ok: false, error: message2, remoteProjectLink });
|
|
16761
|
+
throw error;
|
|
16762
|
+
}
|
|
16763
|
+
}
|
|
16082
16764
|
async function refreshServerStatus(ctx) {
|
|
16083
16765
|
if (startLocalRequested(ctx)) {
|
|
16084
16766
|
return startLocalServerFromApp(ctx);
|
|
16085
16767
|
}
|
|
16086
16768
|
const label = "Checking server";
|
|
16087
16769
|
emitStarted(ctx, label);
|
|
16088
|
-
patchData(ctx, { server: { label: "checking selected server", reachable: false, error: "checking selected server\u2026" } });
|
|
16770
|
+
patchData(ctx, { server: { label: "checking selected server", reachable: false, error: "checking selected server\u2026" }, remoteProjectLink: undefined });
|
|
16089
16771
|
const started = Date.now();
|
|
16090
16772
|
try {
|
|
16091
|
-
const { ensureServerForCli: ensureServerForCli2, requestServerJson: requestServerJson2, resolveServerConnectionLabel: resolveServerConnectionLabel2 } = await Promise.resolve().then(() => (init__server_client(), exports__server_client));
|
|
16773
|
+
const { ensureRemoteProjectRootLink: ensureRemoteProjectRootLink2, ensureServerForCli: ensureServerForCli2, requestServerJson: requestServerJson2, resolveServerConnectionLabel: resolveServerConnectionLabel2 } = await Promise.resolve().then(() => (init__server_client(), exports__server_client));
|
|
16092
16774
|
const projectRoot = projectRootOf(ctx);
|
|
16775
|
+
const aliases = await serverAliases(projectRoot);
|
|
16093
16776
|
emitProgress(ctx, label, "resolving selected server");
|
|
16094
16777
|
const [connectionLabel, server] = await Promise.all([
|
|
16095
16778
|
resolveServerConnectionLabel2(projectRoot),
|
|
16096
16779
|
withTimeout(ensureServerForCli2(projectRoot), 5000, "server connection")
|
|
16097
16780
|
]);
|
|
16098
16781
|
emitProgress(ctx, label, "requesting server status", { baseUrl: server.baseUrl, kind: server.connectionKind });
|
|
16099
|
-
const [status, auth] = await Promise.all([
|
|
16782
|
+
const [status, auth, remoteProjectLink] = await Promise.all([
|
|
16100
16783
|
withRetry("server status", () => withTimeout(requestServerJson2({ projectRoot }, "/api/server/status"), SERVER_PROBE_TIMEOUT_MS, "server status")).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) })),
|
|
16101
|
-
withRetry("github auth status", () => withTimeout(requestServerJson2({ projectRoot }, "/api/github/auth/status"), SERVER_PROBE_TIMEOUT_MS, "github auth status")).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) }))
|
|
16784
|
+
withRetry("github auth status", () => withTimeout(requestServerJson2({ projectRoot }, "/api/github/auth/status"), SERVER_PROBE_TIMEOUT_MS, "github auth status")).catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) })),
|
|
16785
|
+
server.connectionKind === "remote" ? withTimeout(ensureRemoteProjectRootLink2(projectRoot, { mode: "backfill-only", authToken: server.authToken }), SERVER_PROBE_TIMEOUT_MS, "remote project link").catch((error) => ({ ok: false, status: "error", message: error instanceof Error ? error.message : String(error) })) : Promise.resolve(null)
|
|
16102
16786
|
]);
|
|
16103
16787
|
const state = {
|
|
16104
16788
|
label: connectionLabel,
|
|
@@ -16107,22 +16791,25 @@ async function refreshServerStatus(ctx) {
|
|
|
16107
16791
|
reachable: true,
|
|
16108
16792
|
latencyMs: Date.now() - started,
|
|
16109
16793
|
status: status && typeof status === "object" && !Array.isArray(status) ? status : {},
|
|
16110
|
-
auth: auth && typeof auth === "object" && !Array.isArray(auth) ? auth : {}
|
|
16794
|
+
auth: auth && typeof auth === "object" && !Array.isArray(auth) ? auth : {},
|
|
16795
|
+
aliases,
|
|
16796
|
+
...remoteProjectLink && typeof remoteProjectLink === "object" && !Array.isArray(remoteProjectLink) ? { remoteProjectLink } : {}
|
|
16111
16797
|
};
|
|
16112
|
-
patchData(ctx, { server: state });
|
|
16798
|
+
patchData(ctx, { server: state, remoteProjectLink: state.remoteProjectLink });
|
|
16113
16799
|
patchFooter(ctx, { server: connectionLabel, latency: `${state.latencyMs}ms` });
|
|
16114
|
-
emitCompleted(ctx, label, {
|
|
16800
|
+
emitCompleted(ctx, label, { serverLabel: connectionLabel, latencyMs: state.latencyMs });
|
|
16115
16801
|
return state;
|
|
16116
16802
|
} catch (error) {
|
|
16117
16803
|
const state = {
|
|
16118
16804
|
label: "server unavailable",
|
|
16119
16805
|
reachable: false,
|
|
16120
16806
|
latencyMs: Date.now() - started,
|
|
16807
|
+
aliases: await serverAliases(projectRootOf(ctx)).catch(() => []),
|
|
16121
16808
|
error: error instanceof Error ? error.message : String(error)
|
|
16122
16809
|
};
|
|
16123
|
-
patchData(ctx, { server: state });
|
|
16810
|
+
patchData(ctx, { server: state, remoteProjectLink: undefined });
|
|
16124
16811
|
patchFooter(ctx, { server: "unavailable" });
|
|
16125
|
-
emitCompleted(ctx, label, {
|
|
16812
|
+
emitCompleted(ctx, label, { serverLabel: state.label, reachable: false, error: state.error });
|
|
16126
16813
|
return state;
|
|
16127
16814
|
}
|
|
16128
16815
|
}
|
|
@@ -16992,7 +17679,7 @@ function withSelectable(line2, item) {
|
|
|
16992
17679
|
var DOCTOR_ACTIONS = [
|
|
16993
17680
|
{ detail: "run diagnostics now", item: { id: "run", label: "run", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "run diagnostics" } },
|
|
16994
17681
|
{ detail: "open server controls", item: { id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Open server controls" } }, message: "open server controls" } },
|
|
16995
|
-
{ detail: "repair project/server/auth link", item: { id: "repair", label: "repair", intent: { scene: "
|
|
17682
|
+
{ detail: "repair project/server/auth link", item: { id: "repair", label: "repair", intent: { scene: "init", argv: ["init", "--repair", "--yes"], action: { kind: "init-start", label: "Repair project link" } }, message: "repair project link natively" } },
|
|
16996
17683
|
{ detail: "open tasks", item: { id: "tasks", label: "tasks", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Open tasks" } }, message: "open tasks" } }
|
|
16997
17684
|
];
|
|
16998
17685
|
function checks(state) {
|
|
@@ -17065,6 +17752,48 @@ function renderDoctorScene(state, layout) {
|
|
|
17065
17752
|
});
|
|
17066
17753
|
}
|
|
17067
17754
|
|
|
17755
|
+
// packages/cli/src/app-opentui/remote-link.ts
|
|
17756
|
+
var REPAIRABLE_REMOTE_LINK_STATUSES = new Set([
|
|
17757
|
+
"auth_required",
|
|
17758
|
+
"project_not_registered",
|
|
17759
|
+
"no_server_checkout",
|
|
17760
|
+
"invalid_root",
|
|
17761
|
+
"needs_prepare",
|
|
17762
|
+
"error"
|
|
17763
|
+
]);
|
|
17764
|
+
function remoteProjectLinkError(message2) {
|
|
17765
|
+
return /no server-host project root link|remote project(?:-root)? link|x-rig-project-root|serverProjectRoot/i.test(message2 ?? "");
|
|
17766
|
+
}
|
|
17767
|
+
function serverRecordForRemoteLink(state) {
|
|
17768
|
+
const server = state.data.server;
|
|
17769
|
+
return server && typeof server === "object" && !Array.isArray(server) ? server : null;
|
|
17770
|
+
}
|
|
17771
|
+
function remoteProjectLinkState(state) {
|
|
17772
|
+
const serverRecord = serverRecordForRemoteLink(state);
|
|
17773
|
+
if (!serverRecord || serverRecord.kind !== "remote")
|
|
17774
|
+
return null;
|
|
17775
|
+
const link = serverRecord.remoteProjectLink;
|
|
17776
|
+
if (link && typeof link === "object" && !Array.isArray(link))
|
|
17777
|
+
return link;
|
|
17778
|
+
const direct = state.data.remoteProjectLink;
|
|
17779
|
+
if (direct && typeof direct === "object" && !Array.isArray(direct))
|
|
17780
|
+
return direct;
|
|
17781
|
+
return null;
|
|
17782
|
+
}
|
|
17783
|
+
function shouldOfferRemoteLinkRepair(state, message2) {
|
|
17784
|
+
const link = remoteProjectLinkState(state);
|
|
17785
|
+
if (link) {
|
|
17786
|
+
if (link.ok === true)
|
|
17787
|
+
return false;
|
|
17788
|
+
const status = link.status ?? "";
|
|
17789
|
+
return REPAIRABLE_REMOTE_LINK_STATUSES.has(status);
|
|
17790
|
+
}
|
|
17791
|
+
const serverRecord = serverRecordForRemoteLink(state);
|
|
17792
|
+
if (serverRecord && serverRecord.kind !== "remote")
|
|
17793
|
+
return false;
|
|
17794
|
+
return remoteProjectLinkError(message2 ?? state.error?.message);
|
|
17795
|
+
}
|
|
17796
|
+
|
|
17068
17797
|
// packages/cli/src/app-opentui/fleet-stats.ts
|
|
17069
17798
|
var ACTIVE_STATUSES = new Set([
|
|
17070
17799
|
"running",
|
|
@@ -18912,13 +19641,18 @@ function overviewBody(state, family, snap, layout) {
|
|
|
18912
19641
|
function familyRecoveryRows(state, family, errorMessage2) {
|
|
18913
19642
|
const selected = Math.max(0, state.selection.index);
|
|
18914
19643
|
const intro = errorMessage2 ? line(`\u2717 couldn't load ${family || "this family"} \u2014 ${errorMessage2}`, { fg: RIG_UI.red, bold: true }) : line(`No data for ${family || "this family"} yet.`, { fg: RIG_UI.ink2 });
|
|
18915
|
-
|
|
19644
|
+
const repairRemote = shouldOfferRemoteLinkRepair(state, errorMessage2);
|
|
19645
|
+
const rows = [
|
|
18916
19646
|
intro,
|
|
18917
|
-
blank()
|
|
18918
|
-
selectableDeckRow({ label: "retry", detail: `reload ${family || "the family"}`, index: 0, active: selected === 0 }, { id: "family-retry", label: "retry", intent: { scene: "family", argv: [family], action: { kind: "refresh", label: `Reload ${family}`, payload: { family } } }, message: "reload this family" }),
|
|
18919
|
-
selectableDeckRow({ label: "cockpit", detail: "back to the project cockpit", index: 1, active: selected === 1 }, { id: "family-home", label: "cockpit", intent: { scene: "main", argv: [], action: { kind: "refresh", label: "Home" } }, message: "back to the cockpit" }),
|
|
18920
|
-
selectableDeckRow({ label: "doctor", detail: "diagnose project/setup", index: 2, active: selected === 2 }, { id: "family-doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "diagnose setup" })
|
|
19647
|
+
blank()
|
|
18921
19648
|
];
|
|
19649
|
+
let index = 0;
|
|
19650
|
+
if (repairRemote) {
|
|
19651
|
+
rows.push(selectableDeckRow({ label: "repair link", detail: "backfill/prepare selected remote checkout link", index, active: selected === index }, { id: "family-repair-link", label: "repair link", intent: { scene: "server", argv: ["server", "repair-link"], action: { kind: "remote-link-repair", label: "Repair remote link", payload: { returnScene: "family", family } } }, message: "repair remote project link" }));
|
|
19652
|
+
index += 1;
|
|
19653
|
+
}
|
|
19654
|
+
rows.push(selectableDeckRow({ label: "retry", detail: `reload ${family || "the family"}`, index, active: selected === index }, { id: "family-retry", label: "retry", intent: { scene: "family", argv: [family], action: { kind: "refresh", label: `Reload ${family}`, payload: { family } } }, message: "reload this family" }), selectableDeckRow({ label: "cockpit", detail: "back to the project cockpit", index: index + 1, active: selected === index + 1 }, { id: "family-home", label: "cockpit", intent: { scene: "main", argv: [], action: { kind: "refresh", label: "Home" } }, message: "back to the cockpit" }), selectableDeckRow({ label: "doctor", detail: "diagnose project/setup", index: index + 2, active: selected === index + 2 }, { id: "family-doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "diagnose setup" }));
|
|
19655
|
+
return rows;
|
|
18922
19656
|
}
|
|
18923
19657
|
function renderFamilyScene(state, layout) {
|
|
18924
19658
|
const family = typeof state.data.familyName === "string" ? state.data.familyName : "";
|
|
@@ -18927,9 +19661,16 @@ function renderFamilyScene(state, layout) {
|
|
|
18927
19661
|
const loading = state.status === "loading" && !snap;
|
|
18928
19662
|
const errorMessage2 = state.error?.message ?? lastRefreshError(state) ?? undefined;
|
|
18929
19663
|
const probeFailed = snap ? snap.state.ran === false && Boolean(state.error) : Boolean(state.error);
|
|
19664
|
+
const selected = Math.max(0, state.selection.index);
|
|
18930
19665
|
const body = [
|
|
18931
19666
|
...loading ? loadingRows(family || "family", state.tick) : snap ? [
|
|
18932
|
-
...probeFailed && errorMessage2 ? [
|
|
19667
|
+
...probeFailed && errorMessage2 ? [
|
|
19668
|
+
...errorBanner(errorMessage2),
|
|
19669
|
+
...shouldOfferRemoteLinkRepair(state, errorMessage2) ? [
|
|
19670
|
+
selectableDeckRow({ label: "repair link", detail: "backfill/prepare selected remote checkout link", index: 0, active: selected === 0 }, { id: "family-repair-link", label: "repair link", intent: { scene: "server", argv: ["server", "repair-link"], action: { kind: "remote-link-repair", label: "Repair remote link", payload: { returnScene: "family", family } } }, message: "repair remote project link" })
|
|
19671
|
+
] : [],
|
|
19672
|
+
blank()
|
|
19673
|
+
] : [],
|
|
18933
19674
|
...current.subId ? formView(state, family, snap, current).lines : overviewBody(state, family, snap, layout)
|
|
18934
19675
|
] : familyRecoveryRows(state, family, errorMessage2)
|
|
18935
19676
|
];
|
|
@@ -19076,12 +19817,12 @@ function sortTasks2(tasks, spec) {
|
|
|
19076
19817
|
}
|
|
19077
19818
|
|
|
19078
19819
|
// packages/cli/src/app-opentui/scenes/fleet.ts
|
|
19079
|
-
var
|
|
19820
|
+
var BASE_FLEET_RECOVERY_ITEMS = [
|
|
19080
19821
|
{ id: "tasks", label: "tasks", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Open tasks" } }, message: "open tasks and dispatch work" },
|
|
19081
|
-
{ id: "repair", label: "repair", intent: { scene: "command", argv: ["init", "--repair"], action: { kind: "command-run", label: "Repair project link" } }, message: "repair project/server/auth link" },
|
|
19082
19822
|
{ id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Open server controls" } }, message: "server controls" },
|
|
19083
19823
|
{ id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "diagnose project" }
|
|
19084
19824
|
];
|
|
19825
|
+
var FLEET_REPAIR_LINK_ITEM = { id: "repair-link", label: "repair link", intent: { scene: "server", argv: ["server", "repair-link"], action: { kind: "remote-link-repair", label: "Repair remote link", payload: { returnScene: "fleet" } } }, message: "backfill or prepare remote project link" };
|
|
19085
19826
|
var COL2 = {
|
|
19086
19827
|
glyph: 1,
|
|
19087
19828
|
runId: 8,
|
|
@@ -19246,33 +19987,43 @@ function runRow(width, run, active, optimistic) {
|
|
|
19246
19987
|
const item = runSelectableItem(run);
|
|
19247
19988
|
return item ? withSelectable(row, item) : row;
|
|
19248
19989
|
}
|
|
19249
|
-
var
|
|
19990
|
+
var BASE_RECOVERY_DECKS = [
|
|
19250
19991
|
{ label: "tasks", detail: "open tasks and dispatch work" },
|
|
19251
|
-
{ label: "repair", detail: "repair project/server/auth link" },
|
|
19252
19992
|
{ label: "server", detail: "open server controls" },
|
|
19253
19993
|
{ label: "doctor", detail: "diagnose project" }
|
|
19254
19994
|
];
|
|
19255
|
-
function
|
|
19995
|
+
function fleetRecoveryItems(state) {
|
|
19996
|
+
if (!shouldOfferRemoteLinkRepair(state))
|
|
19997
|
+
return BASE_FLEET_RECOVERY_ITEMS;
|
|
19998
|
+
return [BASE_FLEET_RECOVERY_ITEMS[0], FLEET_REPAIR_LINK_ITEM, ...BASE_FLEET_RECOVERY_ITEMS.slice(1)];
|
|
19999
|
+
}
|
|
20000
|
+
function fleetRecoveryDecks(state) {
|
|
20001
|
+
if (!shouldOfferRemoteLinkRepair(state))
|
|
20002
|
+
return BASE_RECOVERY_DECKS;
|
|
20003
|
+
return [BASE_RECOVERY_DECKS[0], { label: "repair link", detail: "backfill/prepare remote project-root link" }, ...BASE_RECOVERY_DECKS.slice(1)];
|
|
20004
|
+
}
|
|
20005
|
+
function recoveryRows(state, selected, reason) {
|
|
20006
|
+
const items = fleetRecoveryItems(state);
|
|
19256
20007
|
return [
|
|
19257
20008
|
...reason ? [line(reason, { fg: RIG_UI.yellow }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
19258
20009
|
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
19259
|
-
...
|
|
20010
|
+
...fleetRecoveryDecks(state).map((deck, index) => selectableDeckRow({ ...deck, index, active: selected === index }, items[index]))
|
|
19260
20011
|
];
|
|
19261
20012
|
}
|
|
19262
|
-
function emptyRows(query, total, selected) {
|
|
20013
|
+
function emptyRows(state, query, total, selected) {
|
|
19263
20014
|
if (!query.trim() && total === 0)
|
|
19264
|
-
return recoveryRows(selected, "No runs yet.");
|
|
20015
|
+
return recoveryRows(state, selected, "No runs yet.");
|
|
19265
20016
|
if (query.trim() && total > 0) {
|
|
19266
20017
|
return [
|
|
19267
|
-
...recoveryRows(selected, `No matching runs for ${JSON.stringify(query)} (${total} total).`)
|
|
20018
|
+
...recoveryRows(state, selected, `No matching runs for ${JSON.stringify(query)} (${total} total).`)
|
|
19268
20019
|
];
|
|
19269
20020
|
}
|
|
19270
|
-
return recoveryRows(selected, "No runs are visible with this filter.");
|
|
20021
|
+
return recoveryRows(state, selected, "No runs are visible with this filter.");
|
|
19271
20022
|
}
|
|
19272
20023
|
function degradedRows(state, selected) {
|
|
19273
20024
|
if (!state.error)
|
|
19274
20025
|
return [];
|
|
19275
|
-
return recoveryRows(selected, state.error.message);
|
|
20026
|
+
return recoveryRows(state, selected, state.error.message);
|
|
19276
20027
|
}
|
|
19277
20028
|
function renderFleetScene(state, layout) {
|
|
19278
20029
|
const width = panelWidth4(layout);
|
|
@@ -19282,7 +20033,7 @@ function renderFleetScene(state, layout) {
|
|
|
19282
20033
|
const runs = sortRuns(filterRunsForSearch(allRuns, query), spec);
|
|
19283
20034
|
const selectedRun = typeof state.data.selectedRunId === "string" && runs.some((run) => run.runId === state.data.selectedRunId) ? state.data.selectedRunId : runs[0]?.runId;
|
|
19284
20035
|
const selectedIndex = Math.max(0, runs.findIndex((run) => run.runId === selectedRun));
|
|
19285
|
-
const recoveryIndex = Math.max(0, Math.min(
|
|
20036
|
+
const recoveryIndex = Math.max(0, Math.min(fleetRecoveryItems(state).length - 1, state.selection.index));
|
|
19286
20037
|
const optimistic = optimisticStatuses(state);
|
|
19287
20038
|
const updatedAgo = updatedAgoLabel(state);
|
|
19288
20039
|
const panelTop = 0;
|
|
@@ -19314,7 +20065,7 @@ function renderFleetScene(state, layout) {
|
|
|
19314
20065
|
...runs.map((run, index) => runRow(contentWidth, run, index === selectedIndex, optimistic.get(run.runId)))
|
|
19315
20066
|
] : state.error ? degradedRows(state, recoveryIndex) : loading ? loadingRows("runs", state.tick) : [
|
|
19316
20067
|
...query.trim() ? [line(searchSummary("runs", query, runs.length, allRuns.length), { fg: RIG_UI.ink4 }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
19317
|
-
...emptyRows(query, allRuns.length, recoveryIndex)
|
|
20068
|
+
...emptyRows(state, query, allRuns.length, recoveryIndex)
|
|
19318
20069
|
]
|
|
19319
20070
|
];
|
|
19320
20071
|
return makeSceneFrame({
|
|
@@ -19869,19 +20620,19 @@ function renderInboxScene(state, layout) {
|
|
|
19869
20620
|
}
|
|
19870
20621
|
|
|
19871
20622
|
// packages/cli/src/app-opentui/scenes/init.ts
|
|
19872
|
-
var STEP_CONFIG_RUN = { id: "step-config", label: "run
|
|
20623
|
+
var STEP_CONFIG_RUN = { id: "step-config", label: "run init", intent: { scene: "init", argv: ["init", "--yes"], action: { kind: "init-start", label: "Run init" } }, message: "initialize without embedded CLI prompts" };
|
|
19873
20624
|
var STEP_SERVER = { id: "step-server", label: "select server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Choose server" } }, message: "select local or remote server" };
|
|
19874
|
-
var STEP_AUTH = { id: "step-auth", label: "connect GitHub", intent: { scene: "
|
|
19875
|
-
var STEP_TASKS = { id: "step-tasks", label: "
|
|
20625
|
+
var STEP_AUTH = { id: "step-auth", label: "connect GitHub", intent: { scene: "server", argv: ["github", "auth", "status"], action: { kind: "refresh", label: "Open GitHub auth" } }, message: "open native server/auth controls" };
|
|
20626
|
+
var STEP_TASKS = { id: "step-tasks", label: "repair task source", intent: { scene: "init", argv: ["init", "--repair", "--yes"], action: { kind: "init-start", label: "Repair task source" } }, message: "repair generated task-source config without embedded CLI prompts" };
|
|
19876
20627
|
var SETUP_STEPS = [
|
|
19877
|
-
{ id: "config", label: "Project config", detail: "rig.config + private state", done: (s) => s.configured, cta: "Run
|
|
20628
|
+
{ id: "config", label: "Project config", detail: "rig.config + private state", done: (s) => s.configured, cta: "Run init", item: STEP_CONFIG_RUN },
|
|
19878
20629
|
{ id: "server", label: "Server target", detail: "local or remote, reachable", done: (s) => s.serverReachable, cta: "Choose a server", item: STEP_SERVER },
|
|
19879
20630
|
{ id: "auth", label: "GitHub auth", detail: "signed in on the selected server", done: (s) => s.authSignedIn, cta: "Connect GitHub", item: STEP_AUTH },
|
|
19880
20631
|
{ id: "tasks", label: "Task source", detail: "where work comes from", done: (s) => s.taskSourceReady, cta: "Pick a task source", item: STEP_TASKS }
|
|
19881
20632
|
];
|
|
19882
20633
|
var SECONDARY_ACTIONS = [
|
|
19883
|
-
{ label: "repair", detail: "reconfigure generated config and private state", item: { id: "repair", label: "repair", intent: { scene: "
|
|
19884
|
-
{ label: "demo", detail: "seed an offline demo task source to explore", item: { id: "demo", label: "demo", intent: { scene: "
|
|
20634
|
+
{ label: "repair", detail: "reconfigure generated config and private state", item: { id: "repair", label: "repair", intent: { scene: "init", argv: ["init", "--repair", "--yes"], action: { kind: "init-start", label: "Reconfigure project" } }, message: "verify or rewrite generated config natively" } },
|
|
20635
|
+
{ label: "demo", detail: "seed an offline demo task source to explore", item: { id: "demo", label: "demo", intent: { scene: "init", argv: ["init", "--demo", "--repair", "--yes"], action: { kind: "init-start", label: "Seed demo project" } }, message: "offline demo project without embedded CLI prompts" } },
|
|
19885
20636
|
{ label: "doctor", detail: "diagnose what is still missing", item: { id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "verify setup" } }
|
|
19886
20637
|
];
|
|
19887
20638
|
function record2(value) {
|
|
@@ -19925,11 +20676,11 @@ function renderInitScene(state, layout) {
|
|
|
19925
20676
|
const allDone = completed === SETUP_STEPS.length;
|
|
19926
20677
|
const nextStep = SETUP_STEPS.find((step) => !step.done(signals));
|
|
19927
20678
|
const selected = Math.max(0, state.selection.index);
|
|
19928
|
-
const primary = nextStep ? selectableDeckRow({ label: "next", detail: `${nextStep.cta} \u2014 recommended`, active: selected === 0 }, { ...nextStep.item, id: "init-primary" }) : selectableDeckRow({ label: "verify", detail: "
|
|
20679
|
+
const primary = nextStep ? selectableDeckRow({ label: "next", detail: `${nextStep.cta} \u2014 recommended`, active: selected === 0 }, { ...nextStep.item, id: "init-primary" }) : selectableDeckRow({ label: "verify", detail: "Init complete \u2014 run doctor to confirm", active: selected === 0 }, { id: "init-primary", label: "verify", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "verify setup end-to-end" });
|
|
19929
20680
|
const secondaryRows = SECONDARY_ACTIONS.map(({ label, detail, item }, index) => selectableDeckRow({ label, detail, active: selected === index + 1 }, item));
|
|
19930
20681
|
const progress = allDone ? "all set" : `${completed} of ${SETUP_STEPS.length} complete`;
|
|
19931
20682
|
const panelLines = [
|
|
19932
|
-
line(allDone ? "
|
|
20683
|
+
line(allDone ? "INIT \xB7 ready to go" : "INIT \xB7 let's get you running", { fg: allDone ? RIG_UI.limeDim : RIG_UI.ink, bold: true }),
|
|
19933
20684
|
line(`progress ${progress}`, { fg: allDone ? RIG_UI.limeDim : RIG_UI.ink2 }),
|
|
19934
20685
|
blank(),
|
|
19935
20686
|
line("CHECKLIST", { fg: RIG_UI.ink3, bold: true }),
|
|
@@ -19941,11 +20692,11 @@ function renderInitScene(state, layout) {
|
|
|
19941
20692
|
line("OTHER PATHS", { fg: RIG_UI.ink3, bold: true }),
|
|
19942
20693
|
...secondaryRows,
|
|
19943
20694
|
blank(),
|
|
19944
|
-
line("enter/click runs the highlighted action \xB7 esc goes back \xB7 tab switches sections", { fg: RIG_UI.ink4 })
|
|
20695
|
+
line("enter/click runs the highlighted native action \xB7 esc goes back \xB7 tab switches sections", { fg: RIG_UI.ink4 })
|
|
19945
20696
|
];
|
|
19946
20697
|
return makeSceneFrame({
|
|
19947
20698
|
scene: "init",
|
|
19948
|
-
title: "
|
|
20699
|
+
title: "Init",
|
|
19949
20700
|
lines: [],
|
|
19950
20701
|
panels: [{
|
|
19951
20702
|
id: "init-setup",
|
|
@@ -19958,11 +20709,11 @@ function renderInitScene(state, layout) {
|
|
|
19958
20709
|
opacity: 0.98,
|
|
19959
20710
|
border: false,
|
|
19960
20711
|
chrome: "ad-terminal",
|
|
19961
|
-
headerText: "rig
|
|
20712
|
+
headerText: "rig init \xB7 guided onboarding",
|
|
19962
20713
|
paddingX: 5,
|
|
19963
20714
|
paddingY: 2
|
|
19964
20715
|
}],
|
|
19965
|
-
footer: { message: allDone ? "
|
|
20716
|
+
footer: { message: allDone ? "init complete" : "init in progress" },
|
|
19966
20717
|
live: !allDone || state.status === "action"
|
|
19967
20718
|
});
|
|
19968
20719
|
}
|
|
@@ -21235,16 +21986,40 @@ function renderRunDetailScene(state, layout) {
|
|
|
21235
21986
|
// packages/cli/src/app-opentui/scenes/server.ts
|
|
21236
21987
|
var SERVER_ACTIONS = [
|
|
21237
21988
|
{ detail: "probe selected server, project root, and GitHub auth", item: { id: "refresh", label: "refresh", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Refresh server" } }, message: "refresh selected server" } },
|
|
21238
|
-
{ detail: "select local server for this repo", item: { id: "local", label: "use local", intent: { scene: "
|
|
21239
|
-
{ detail: "
|
|
21240
|
-
{ detail: "show saved local/remote aliases", item: { id: "list", label: "list servers", intent: { scene: "
|
|
21241
|
-
{ detail: "
|
|
21989
|
+
{ detail: "select local server for this repo", item: { id: "local", label: "use local", intent: { scene: "server", argv: ["server", "use", "local"], action: { kind: "server-use-local", label: "Use local server" } }, message: "switch this repo to local" } },
|
|
21990
|
+
{ detail: "type a saved remote alias to select", item: { id: "remote", label: "use remote", prompt: { label: "Use remote alias", scene: "server", argv: ["server", "use"], intentKind: "server-use-remote", payloadBase: {}, payloadKey: "alias" }, message: "choose a saved remote alias" } },
|
|
21991
|
+
{ detail: "show saved local/remote aliases in the status panel", item: { id: "list", label: "list servers", intent: { scene: "server", argv: ["server", "list"], action: { kind: "refresh", label: "List servers" } }, message: "list saved server aliases" } },
|
|
21992
|
+
{ detail: "add and select a remote: enter <alias> <https-url>", item: { id: "add", label: "add remote", prompt: { label: "Add remote", scene: "server", argv: ["server", "add"], intentKind: "server-add-remote", payloadBase: {}, payloadKey: "remote", appendValueToArgv: true }, message: "add a remote server alias" } },
|
|
21242
21993
|
{ detail: "spawn the local rig-server detached and return here", item: { id: "start", label: "start local", intent: { scene: "server", argv: ["server", "start"], action: { kind: "refresh", payload: { startLocal: true }, label: "Start local server" } }, message: "start local server detached" } },
|
|
21243
|
-
{ detail: "import gh token into the selected server namespace", item: { id: "auth", label: "import auth", intent: { scene: "
|
|
21994
|
+
{ detail: "import gh token into the selected server namespace", item: { id: "auth", label: "import auth", intent: { scene: "server", argv: ["github", "auth", "import-gh"], action: { kind: "github-auth-import", label: "Import GitHub auth" } }, message: "import gh auth to selected server" } },
|
|
21244
21995
|
{ detail: "diagnose server/auth/project linkage", item: { id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "verify server/auth" } },
|
|
21245
21996
|
{ detail: "verify selected server can list task source", item: { id: "tasks", label: "tasks", intent: { scene: "tasks", argv: ["task", "list"], action: { kind: "refresh", label: "Open tasks" } }, message: "verify task source" } },
|
|
21246
21997
|
{ detail: "verify selected server can list recent runs", item: { id: "runs", label: "runs", intent: { scene: "fleet", argv: ["run", "status"], action: { kind: "refresh", label: "Open runs" } }, message: "open recent runs" } }
|
|
21247
21998
|
];
|
|
21999
|
+
function remoteAliasActions(server) {
|
|
22000
|
+
const aliases = (server?.aliases ?? []).filter((alias) => alias.kind === "remote");
|
|
22001
|
+
return aliases.map((alias) => ({
|
|
22002
|
+
detail: `${alias.selected ? "selected" : "select"} ${alias.baseUrl ?? "remote endpoint"}`,
|
|
22003
|
+
item: {
|
|
22004
|
+
id: `remote-alias:${alias.alias}`,
|
|
22005
|
+
label: alias.selected ? `\u2713 ${alias.alias}` : `use ${alias.alias}`,
|
|
22006
|
+
intent: { scene: "server", argv: ["server", "use", alias.alias], action: { kind: "server-use-remote", label: `Use ${alias.alias}`, payload: { alias: alias.alias } } },
|
|
22007
|
+
message: `select ${alias.alias}`
|
|
22008
|
+
}
|
|
22009
|
+
}));
|
|
22010
|
+
}
|
|
22011
|
+
function serverActions(state) {
|
|
22012
|
+
const server = serverState(state);
|
|
22013
|
+
const remoteRows = remoteAliasActions(server);
|
|
22014
|
+
let actions = remoteRows.length > 0 ? [...SERVER_ACTIONS.slice(0, 3), ...remoteRows, ...SERVER_ACTIONS.slice(3)] : [...SERVER_ACTIONS];
|
|
22015
|
+
if (!shouldOfferRemoteLinkRepair(state))
|
|
22016
|
+
return actions;
|
|
22017
|
+
const repair = { detail: "backfill or prepare the selected remote checkout/root link", item: { id: "repair-link", label: "repair link", intent: { scene: "server", argv: ["server", "repair-link"], action: { kind: "remote-link-repair", label: "Repair remote link" } }, message: "prepare remote checkout link" } };
|
|
22018
|
+
const doctorIndex = actions.findIndex((entry) => entry.item.id === "doctor");
|
|
22019
|
+
if (doctorIndex < 0)
|
|
22020
|
+
return [...actions, repair];
|
|
22021
|
+
return [...actions.slice(0, doctorIndex), repair, ...actions.slice(doctorIndex)];
|
|
22022
|
+
}
|
|
21248
22023
|
function cleanVisible(value, fallback = "unknown") {
|
|
21249
22024
|
return value?.trim() || fallback;
|
|
21250
22025
|
}
|
|
@@ -21269,31 +22044,37 @@ function selectedIndex(state, count) {
|
|
|
21269
22044
|
function statusRows2(server) {
|
|
21270
22045
|
const auth = server?.auth;
|
|
21271
22046
|
const signedIn = auth && (auth.signedIn === true || auth.authenticated === true || auth.status === "authenticated") ? "authenticated" : "auth unknown";
|
|
22047
|
+
const link = server?.remoteProjectLink;
|
|
22048
|
+
const linkText = link ? link.ok ? `ready \xB7 ${link.serverProjectRoot ?? "linked"}` : `${link.status ?? "needs repair"} \xB7 ${link.hint ?? link.message ?? "run repair link"}` : server?.kind === "remote" ? "not checked" : "not required";
|
|
22049
|
+
const selectedLinkSummary = link?.ok ? " \xB7 root link ready" : server?.kind === "remote" && link ? ` \xB7 root link ${link.status ?? "needs repair"}` : "";
|
|
21272
22050
|
return [
|
|
21273
|
-
line(`selected ${cleanVisible(server?.label, "not checked")}`, { fg: RIG_UI.ink2 }),
|
|
22051
|
+
line(`selected ${cleanVisible(server?.label, "not checked")}${selectedLinkSummary}`, { fg: RIG_UI.ink2 }),
|
|
21274
22052
|
line(`target ${targetLabel(server)}`, { fg: RIG_UI.ink3 }),
|
|
21275
22053
|
line(`mode ${server?.kind ?? "local or remote"}`, { fg: RIG_UI.ink3 }),
|
|
21276
22054
|
line(`health ${server ? server.reachable ? "reachable" : "unreachable" : "check pending"}`, { fg: server?.reachable ? RIG_UI.limeDim : server ? RIG_UI.red : RIG_UI.yellow }),
|
|
21277
22055
|
line(`github ${signedIn}`, { fg: signedIn === "authenticated" ? RIG_UI.limeDim : RIG_UI.ink4 }),
|
|
22056
|
+
line(`root link ${linkText}`, { fg: link?.ok ? RIG_UI.limeDim : server?.kind === "remote" ? RIG_UI.yellow : RIG_UI.ink4 }),
|
|
22057
|
+
...server?.aliases && server.aliases.length > 0 ? [line(`aliases ${server.aliases.map((alias) => `${alias.selected ? "*" : ""}${alias.alias}${alias.kind === "remote" && alias.baseUrl ? `=${alias.baseUrl}` : ""}`).join(", ")}`, { fg: RIG_UI.ink4 })] : [],
|
|
21278
22058
|
...server?.error ? [line(`attention ${server.error}`, { fg: RIG_UI.yellow })] : []
|
|
21279
22059
|
];
|
|
21280
22060
|
}
|
|
21281
22061
|
function renderServerScene(state, layout) {
|
|
21282
22062
|
const server = serverState(state);
|
|
21283
|
-
const
|
|
22063
|
+
const actions = serverActions(state);
|
|
22064
|
+
const selected = selectedIndex(state, actions.length);
|
|
21284
22065
|
const loading = state.status === "loading" && !server;
|
|
21285
22066
|
const errorText = state.error?.message ?? lastRefreshError(state);
|
|
21286
22067
|
const panelLines = [
|
|
21287
22068
|
...errorText ? errorBanner(errorText, "select refresh or doctor below to retry") : [],
|
|
21288
22069
|
line("server controls", { fg: RIG_UI.ink3 }),
|
|
21289
22070
|
blank(),
|
|
21290
|
-
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
21291
|
-
...SERVER_ACTIONS.map(({ detail, item }, index) => selectableDeckRow({ label: item.label, detail, index, active: selected === index }, item)),
|
|
21292
|
-
blank(),
|
|
21293
22071
|
line("STATUS", { fg: RIG_UI.ink3, bold: true }),
|
|
21294
22072
|
...loading ? loadingRows("server status", state.tick) : statusRows2(server),
|
|
21295
22073
|
blank(),
|
|
21296
|
-
line("
|
|
22074
|
+
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
22075
|
+
...actions.map(({ detail, item }, index) => selectableDeckRow({ label: item.label, detail, index, active: selected === index }, item)),
|
|
22076
|
+
blank(),
|
|
22077
|
+
line("enter/click runs native actions \xB7 add/use remote prompts stay in OpenTUI", { fg: RIG_UI.ink4 })
|
|
21297
22078
|
];
|
|
21298
22079
|
return makeSceneFrame({
|
|
21299
22080
|
scene: "server",
|
|
@@ -21320,13 +22101,13 @@ function renderServerScene(state, layout) {
|
|
|
21320
22101
|
}
|
|
21321
22102
|
|
|
21322
22103
|
// packages/cli/src/app-opentui/scenes/tasks.ts
|
|
21323
|
-
var
|
|
22104
|
+
var BASE_TASK_RECOVERY_ITEMS = [
|
|
21324
22105
|
{ id: "refresh", label: "refresh", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Refresh tasks" } }, message: "refresh task source" },
|
|
21325
|
-
{ id: "next", label: "next", intent: { scene: "
|
|
21326
|
-
{ id: "repair", label: "repair", intent: { scene: "command", argv: ["init", "--repair"], action: { kind: "command-run", label: "Repair task source" } }, message: "repair project/task source" },
|
|
22106
|
+
{ id: "next", label: "next", intent: { scene: "tasks", argv: ["task", "run", "--next"], action: { kind: "task-run-next", label: "Dispatch next task" } }, message: "dispatch next runnable task" },
|
|
21327
22107
|
{ id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Open server controls" } }, message: "server controls" },
|
|
21328
22108
|
{ id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "diagnose task source" }
|
|
21329
22109
|
];
|
|
22110
|
+
var TASK_REPAIR_LINK_ITEM = { id: "repair-link", label: "repair link", intent: { scene: "server", argv: ["server", "repair-link"], action: { kind: "remote-link-repair", label: "Repair remote link", payload: { returnScene: "tasks" } } }, message: "backfill or prepare remote project link" };
|
|
21330
22111
|
var COL3 = {
|
|
21331
22112
|
glyph: 1,
|
|
21332
22113
|
id: 11,
|
|
@@ -21486,34 +22267,44 @@ function taskRow(width, task, active, optimistic) {
|
|
|
21486
22267
|
const item = taskSelectableItem(task);
|
|
21487
22268
|
return item ? withSelectable(row, item) : row;
|
|
21488
22269
|
}
|
|
21489
|
-
var
|
|
22270
|
+
var BASE_RECOVERY_DECKS2 = [
|
|
21490
22271
|
{ label: "refresh", detail: "reload task source" },
|
|
21491
22272
|
{ label: "next", detail: "dispatch next runnable task" },
|
|
21492
|
-
{ label: "repair", detail: "repair project/task source link" },
|
|
21493
22273
|
{ label: "server", detail: "open server controls" },
|
|
21494
22274
|
{ label: "doctor", detail: "diagnose task source" }
|
|
21495
22275
|
];
|
|
21496
|
-
function
|
|
22276
|
+
function taskRecoveryItems(state) {
|
|
22277
|
+
if (!shouldOfferRemoteLinkRepair(state))
|
|
22278
|
+
return BASE_TASK_RECOVERY_ITEMS;
|
|
22279
|
+
return [BASE_TASK_RECOVERY_ITEMS[0], BASE_TASK_RECOVERY_ITEMS[1], TASK_REPAIR_LINK_ITEM, ...BASE_TASK_RECOVERY_ITEMS.slice(2)];
|
|
22280
|
+
}
|
|
22281
|
+
function taskRecoveryDecks(state) {
|
|
22282
|
+
if (!shouldOfferRemoteLinkRepair(state))
|
|
22283
|
+
return BASE_RECOVERY_DECKS2;
|
|
22284
|
+
return [BASE_RECOVERY_DECKS2[0], BASE_RECOVERY_DECKS2[1], { label: "repair link", detail: "backfill/prepare remote project-root link" }, ...BASE_RECOVERY_DECKS2.slice(2)];
|
|
22285
|
+
}
|
|
22286
|
+
function recoveryRows2(state, selected, reason) {
|
|
22287
|
+
const items = taskRecoveryItems(state);
|
|
21497
22288
|
return [
|
|
21498
22289
|
...reason ? [line(reason, { fg: RIG_UI.yellow }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
21499
22290
|
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
21500
|
-
...
|
|
22291
|
+
...taskRecoveryDecks(state).map((deck, index) => selectableDeckRow({ ...deck, index, active: selected === index }, items[index]))
|
|
21501
22292
|
];
|
|
21502
22293
|
}
|
|
21503
|
-
function emptyRows2(query, total, selected) {
|
|
22294
|
+
function emptyRows2(state, query, total, selected) {
|
|
21504
22295
|
if (!query.trim() && total === 0)
|
|
21505
|
-
return recoveryRows2(selected, "No tasks loaded.");
|
|
22296
|
+
return recoveryRows2(state, selected, "No tasks loaded.");
|
|
21506
22297
|
if (query.trim() && total > 0) {
|
|
21507
22298
|
return [
|
|
21508
|
-
...recoveryRows2(selected, `No matching tasks for ${JSON.stringify(query)} (${total} total).`)
|
|
22299
|
+
...recoveryRows2(state, selected, `No matching tasks for ${JSON.stringify(query)} (${total} total).`)
|
|
21509
22300
|
];
|
|
21510
22301
|
}
|
|
21511
|
-
return recoveryRows2(selected, "No tasks are visible with this filter.");
|
|
22302
|
+
return recoveryRows2(state, selected, "No tasks are visible with this filter.");
|
|
21512
22303
|
}
|
|
21513
22304
|
function degradedRows2(state, selected) {
|
|
21514
22305
|
if (!state.error)
|
|
21515
22306
|
return [];
|
|
21516
|
-
return recoveryRows2(selected, state.error.message);
|
|
22307
|
+
return recoveryRows2(state, selected, state.error.message);
|
|
21517
22308
|
}
|
|
21518
22309
|
function rawString(raw, key) {
|
|
21519
22310
|
const value = raw?.[key];
|
|
@@ -21537,7 +22328,10 @@ function renderTaskDetail(state, taskId3, layout) {
|
|
|
21537
22328
|
const activeRunId = task?.activeRun?.runId?.trim();
|
|
21538
22329
|
const width = panelWidth13(layout);
|
|
21539
22330
|
const selected = Math.max(0, state.selection.index);
|
|
22331
|
+
const errorText = state.error?.message ?? lastRefreshError(state);
|
|
22332
|
+
const offerRepairLink = shouldOfferRemoteLinkRepair(state, errorText);
|
|
21540
22333
|
const headerLines = [
|
|
22334
|
+
...errorText ? errorBanner(errorText, offerRepairLink ? "select repair link below to prepare the remote checkout" : "retry dispatch after resolving the issue") : [],
|
|
21541
22335
|
line(`${glyph2} ${title}`, { fg: color, bold: true }),
|
|
21542
22336
|
line(`task ${taskId3} \xB7 ${status}`, { fg: RIG_UI.ink3 }),
|
|
21543
22337
|
...task && task.labels.length > 0 ? [line(`labels: ${task.labels.join(", ")}`, { fg: RIG_UI.ink4 })] : [],
|
|
@@ -21549,8 +22343,16 @@ function renderTaskDetail(state, taskId3, layout) {
|
|
|
21549
22343
|
const actionRows2 = [];
|
|
21550
22344
|
actionRows2.push(selectableDeckRow({ label: "back", detail: "return to the task list", index, active: selected === index }, { id: "task-detail-back", label: "back", data: { taskDetailId: undefined }, message: "back to task list" }));
|
|
21551
22345
|
index += 1;
|
|
21552
|
-
|
|
21553
|
-
|
|
22346
|
+
if (offerRepairLink) {
|
|
22347
|
+
actionRows2.push(selectableDeckRow({ label: "repair link", detail: "prepare/backfill the selected remote project-root link", index, active: selected === index }, { id: `task-detail-repair-link:${taskId3}`, label: "repair link", intent: { scene: "server", argv: ["server", "repair-link"], action: { kind: "remote-link-repair", label: "Repair remote link", payload: { returnScene: "tasks", taskDetailId: taskId3 } } }, message: "prepare remote checkout link" }));
|
|
22348
|
+
index += 1;
|
|
22349
|
+
}
|
|
22350
|
+
if (offerRepairLink) {
|
|
22351
|
+
actionRows2.push(line(" dispatch blocked until the remote project link is repaired", { fg: RIG_UI.ink4 }));
|
|
22352
|
+
} else {
|
|
22353
|
+
actionRows2.push(selectableDeckRow({ label: "dispatch", detail: "submit a Pi run for this task", index, active: selected === index }, { id: `task-detail-run:${taskId3}`, label: `dispatch ${taskId3}`, intent: { scene: "tasks", argv: ["run", taskId3], action: { kind: "task-run-id", payload: { task: taskId3 }, label: `Dispatching ${taskId3}` } }, message: `dispatch task ${taskId3}` }));
|
|
22354
|
+
index += 1;
|
|
22355
|
+
}
|
|
21554
22356
|
if (activeRunId) {
|
|
21555
22357
|
actionRows2.push(selectableDeckRow({ label: "attach", detail: `attach the Pi console to run ${activeRunId.slice(0, 8)}`, index, active: selected === index }, { id: `task-detail-attach:${taskId3}`, label: `attach ${activeRunId.slice(0, 8)}`, intent: { scene: "handoff", argv: ["attach", activeRunId], action: { kind: "run-attach", payload: { runId: activeRunId }, label: `Attach Pi ${activeRunId.slice(0, 8)}` } }, message: `attach Pi to ${activeRunId.slice(0, 8)}` }));
|
|
21556
22358
|
index += 1;
|
|
@@ -21609,7 +22411,7 @@ function renderTasksScene(state, layout) {
|
|
|
21609
22411
|
const tasks = sortTasks2(filterTasksForSearch(allTasks, query), spec);
|
|
21610
22412
|
const selected = typeof state.data.selectedTaskId === "string" && tasks.some((task) => task.id === state.data.selectedTaskId) ? state.data.selectedTaskId : tasks[0]?.id;
|
|
21611
22413
|
const selectedIndex2 = Math.max(0, tasks.findIndex((task) => task.id === selected));
|
|
21612
|
-
const recoveryIndex = Math.max(0, Math.min(
|
|
22414
|
+
const recoveryIndex = Math.max(0, Math.min(taskRecoveryItems(state).length - 1, state.selection.index));
|
|
21613
22415
|
const dispatching = dispatchingFor(state);
|
|
21614
22416
|
const dispatchLine = dispatching ? ` \xB7 ${state.data.dispatchingRun?.runId ?? "new"} ${dispatching.status}` : "";
|
|
21615
22417
|
const updatedAgo = updatedAgoLabel2(state);
|
|
@@ -21629,7 +22431,7 @@ function renderTasksScene(state, layout) {
|
|
|
21629
22431
|
...tasks.map((task, index) => taskRow(contentWidth, task, index === selectedIndex2, dispatching && dispatching.taskId === task.id ? dispatching.status : undefined))
|
|
21630
22432
|
] : state.error ? degradedRows2(state, recoveryIndex) : loading ? loadingRows("tasks", state.tick) : [
|
|
21631
22433
|
...query.trim() ? [line(searchSummary("tasks", query, tasks.length, allTasks.length), { fg: RIG_UI.ink4 }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
21632
|
-
...emptyRows2(query, allTasks.length, recoveryIndex)
|
|
22434
|
+
...emptyRows2(state, query, allTasks.length, recoveryIndex)
|
|
21633
22435
|
]
|
|
21634
22436
|
];
|
|
21635
22437
|
return makeSceneFrame({
|
|
@@ -21986,6 +22788,29 @@ function createDomainAdapter() {
|
|
|
21986
22788
|
else
|
|
21987
22789
|
await loadInitFacts(ctx);
|
|
21988
22790
|
return true;
|
|
22791
|
+
case "server-use-local":
|
|
22792
|
+
await useLocalServerFromApp(ctx);
|
|
22793
|
+
return true;
|
|
22794
|
+
case "server-use-remote":
|
|
22795
|
+
await useRemoteServerFromApp(ctx, payloadString8(intent, "alias") ?? intent.argv[2]);
|
|
22796
|
+
return true;
|
|
22797
|
+
case "server-add-remote":
|
|
22798
|
+
await addRemoteServerFromApp(ctx, intent.argv);
|
|
22799
|
+
return true;
|
|
22800
|
+
case "github-auth-import":
|
|
22801
|
+
await importGitHubAuthFromGhApp(ctx);
|
|
22802
|
+
return true;
|
|
22803
|
+
case "remote-link-repair": {
|
|
22804
|
+
await repairRemoteProjectRootLinkFromApp(ctx);
|
|
22805
|
+
const returnScene = payloadString8(intent, "returnScene");
|
|
22806
|
+
if (returnScene && returnScene !== intent.scene) {
|
|
22807
|
+
ctx.emit({ type: "scene.change", scene: returnScene, intent: { scene: returnScene, argv: intent.argv, action: { kind: "refresh", label: `Refresh ${returnScene}`, payload: intent.action.payload } } });
|
|
22808
|
+
await refreshScene(ctx, returnScene, { scene: returnScene, argv: intent.argv, action: { kind: "refresh", label: `Refresh ${returnScene}`, payload: intent.action.payload } });
|
|
22809
|
+
} else {
|
|
22810
|
+
await refreshServerStatus(ctx);
|
|
22811
|
+
}
|
|
22812
|
+
return true;
|
|
22813
|
+
}
|
|
21989
22814
|
case "doctor-run":
|
|
21990
22815
|
await runDoctorChecksForApp(ctx);
|
|
21991
22816
|
return true;
|