@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
|
@@ -643,7 +643,8 @@ __export(exports__connection_state, {
|
|
|
643
643
|
resolveGlobalConnectionsPath: () => resolveGlobalConnectionsPath,
|
|
644
644
|
readRepoConnection: () => readRepoConnection,
|
|
645
645
|
readGlobalConnections: () => readGlobalConnections,
|
|
646
|
-
isRemoteConnectionSelected: () => isRemoteConnectionSelected
|
|
646
|
+
isRemoteConnectionSelected: () => isRemoteConnectionSelected,
|
|
647
|
+
clearRepoServerProjectRoot: () => clearRepoServerProjectRoot
|
|
647
648
|
});
|
|
648
649
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "fs";
|
|
649
650
|
import { homedir } from "os";
|
|
@@ -727,12 +728,28 @@ function readRepoConnection(projectRoot) {
|
|
|
727
728
|
selected,
|
|
728
729
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
729
730
|
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
730
|
-
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
731
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined,
|
|
732
|
+
serverProjectRootAlias: typeof record.serverProjectRootAlias === "string" && record.serverProjectRootAlias.trim() ? record.serverProjectRootAlias.trim() : undefined,
|
|
733
|
+
serverProjectRootBaseUrl: typeof record.serverProjectRootBaseUrl === "string" && record.serverProjectRootBaseUrl.trim() ? record.serverProjectRootBaseUrl.trim().replace(/\/+$/, "") : undefined
|
|
731
734
|
};
|
|
732
735
|
}
|
|
733
736
|
function writeRepoConnection(projectRoot, state) {
|
|
734
737
|
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
735
738
|
}
|
|
739
|
+
function rootAllowedForSelection(repo, connection) {
|
|
740
|
+
const root = repo.serverProjectRoot?.trim();
|
|
741
|
+
if (!root)
|
|
742
|
+
return;
|
|
743
|
+
if (connection.kind === "remote") {
|
|
744
|
+
if (repo.serverProjectRootAlias !== repo.selected)
|
|
745
|
+
return;
|
|
746
|
+
if (repo.serverProjectRootBaseUrl !== connection.baseUrl)
|
|
747
|
+
return;
|
|
748
|
+
} else if (repo.serverProjectRootAlias && repo.serverProjectRootAlias !== repo.selected) {
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
return root;
|
|
752
|
+
}
|
|
736
753
|
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
737
754
|
const repo = readRepoConnection(projectRoot);
|
|
738
755
|
if (!repo)
|
|
@@ -744,13 +761,41 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
744
761
|
if (!connection) {
|
|
745
762
|
throw new CliError(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
746
763
|
}
|
|
747
|
-
return { alias: repo.selected, connection, serverProjectRoot: repo
|
|
764
|
+
return { alias: repo.selected, connection, serverProjectRoot: rootAllowedForSelection(repo, connection) };
|
|
748
765
|
}
|
|
749
|
-
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
766
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot, metadata = {}) {
|
|
750
767
|
const repo = readRepoConnection(projectRoot);
|
|
751
768
|
if (!repo)
|
|
752
769
|
return;
|
|
753
|
-
|
|
770
|
+
let inferred = metadata;
|
|
771
|
+
if (!inferred.alias || !inferred.baseUrl) {
|
|
772
|
+
try {
|
|
773
|
+
const selected = resolveSelectedConnection(projectRoot);
|
|
774
|
+
if (selected?.connection.kind === "remote") {
|
|
775
|
+
inferred = {
|
|
776
|
+
alias: inferred.alias ?? selected.alias,
|
|
777
|
+
baseUrl: inferred.baseUrl ?? selected.connection.baseUrl
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
} catch {}
|
|
781
|
+
}
|
|
782
|
+
writeRepoConnection(projectRoot, {
|
|
783
|
+
...repo,
|
|
784
|
+
...metadata.project ? { project: metadata.project } : {},
|
|
785
|
+
serverProjectRoot,
|
|
786
|
+
...inferred.alias ? { serverProjectRootAlias: inferred.alias } : {},
|
|
787
|
+
...inferred.baseUrl ? { serverProjectRootBaseUrl: inferred.baseUrl.replace(/\/+$/, "") } : {}
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
function clearRepoServerProjectRoot(projectRoot) {
|
|
791
|
+
const repo = readRepoConnection(projectRoot);
|
|
792
|
+
if (!repo)
|
|
793
|
+
return;
|
|
794
|
+
writeRepoConnection(projectRoot, {
|
|
795
|
+
selected: repo.selected,
|
|
796
|
+
...repo.project ? { project: repo.project } : {},
|
|
797
|
+
...repo.linkedAt ? { linkedAt: repo.linkedAt } : {}
|
|
798
|
+
});
|
|
754
799
|
}
|
|
755
800
|
function isRemoteConnectionSelected(projectRoot) {
|
|
756
801
|
return resolveSelectedConnection(projectRoot)?.connection.kind === "remote";
|
|
@@ -777,12 +822,16 @@ __export(exports__server_client, {
|
|
|
777
822
|
respondRunPiExtensionUiViaServer: () => respondRunPiExtensionUiViaServer,
|
|
778
823
|
resolveServerConnectionLabel: () => resolveServerConnectionLabel,
|
|
779
824
|
requestServerJson: () => requestServerJson,
|
|
825
|
+
repairRemoteProjectRootLink: () => repairRemoteProjectRootLink,
|
|
780
826
|
registerProjectViaServer: () => registerProjectViaServer,
|
|
781
827
|
prepareRemoteCheckoutViaServer: () => prepareRemoteCheckoutViaServer,
|
|
782
828
|
postGitHubTokenViaServer: () => postGitHubTokenViaServer,
|
|
829
|
+
normalizeRepoSlug: () => normalizeRepoSlug,
|
|
783
830
|
listWorkspaceTasksViaServer: () => listWorkspaceTasksViaServer,
|
|
784
831
|
listRunsViaServer: () => listRunsViaServer,
|
|
785
832
|
listGitHubProjectsViaServer: () => listGitHubProjectsViaServer,
|
|
833
|
+
isRemoteProjectRootLinkError: () => isRemoteProjectRootLinkError,
|
|
834
|
+
inspectRemoteProjectLink: () => inspectRemoteProjectLink,
|
|
786
835
|
getWorkspaceTaskViaServer: () => getWorkspaceTaskViaServer,
|
|
787
836
|
getRunTimelineViaServer: () => getRunTimelineViaServer,
|
|
788
837
|
getRunPiStatusViaServer: () => getRunPiStatusViaServer,
|
|
@@ -794,13 +843,15 @@ __export(exports__server_client, {
|
|
|
794
843
|
getRunDetailsViaServer: () => getRunDetailsViaServer,
|
|
795
844
|
getGitHubProjectStatusFieldViaServer: () => getGitHubProjectStatusFieldViaServer,
|
|
796
845
|
getGitHubAuthStatusViaServer: () => getGitHubAuthStatusViaServer,
|
|
846
|
+
formatRemoteProjectLinkHint: () => formatRemoteProjectLinkHint,
|
|
797
847
|
ensureTaskLabelsViaServer: () => ensureTaskLabelsViaServer,
|
|
798
848
|
ensureServerForCli: () => ensureServerForCli,
|
|
849
|
+
ensureRemoteProjectRootLink: () => ensureRemoteProjectRootLink,
|
|
799
850
|
buildRunPiEventsWebSocketUrl: () => buildRunPiEventsWebSocketUrl,
|
|
800
851
|
abortRunPiViaServer: () => abortRunPiViaServer
|
|
801
852
|
});
|
|
802
|
-
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
803
|
-
import { resolve as resolve3 } from "path";
|
|
853
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
854
|
+
import { dirname as dirname2, isAbsolute, resolve as resolve3 } from "path";
|
|
804
855
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
805
856
|
function setServerPhaseListener(listener) {
|
|
806
857
|
const previous = serverPhaseListener;
|
|
@@ -846,11 +897,10 @@ function readStoredGitHubAuthToken(projectRoot) {
|
|
|
846
897
|
const parsed = readRemoteAuthState(projectRoot);
|
|
847
898
|
return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
|
|
848
899
|
}
|
|
849
|
-
function
|
|
850
|
-
|
|
851
|
-
const slug = repo?.project?.trim();
|
|
852
|
-
if (!slug || !/^[^/]+\/[^/]+$/.test(slug))
|
|
900
|
+
function inferRemoteServerProjectRootCandidateFromAuthState(projectRoot, repoSlug) {
|
|
901
|
+
if (!/^[^/]+\/[^/]+$/.test(repoSlug))
|
|
853
902
|
return null;
|
|
903
|
+
const repo = readRepoConnection(projectRoot);
|
|
854
904
|
const auth = readRemoteAuthState(projectRoot);
|
|
855
905
|
const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
|
|
856
906
|
const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
|
|
@@ -859,25 +909,426 @@ function inferRemoteServerProjectRootFromAuthState(projectRoot) {
|
|
|
859
909
|
const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
|
|
860
910
|
if (!checkoutBaseDir)
|
|
861
911
|
return null;
|
|
862
|
-
|
|
863
|
-
writeRepoServerProjectRoot(projectRoot, inferred);
|
|
864
|
-
return inferred;
|
|
912
|
+
return `${checkoutBaseDir.replace(/\/+$/, "")}/${repoSlug}`;
|
|
865
913
|
}
|
|
866
914
|
function readLocalConnectionFallbackToken(projectRoot) {
|
|
867
915
|
return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
|
|
868
916
|
}
|
|
917
|
+
function normalizeRepoSlug(value) {
|
|
918
|
+
const slug = value?.trim();
|
|
919
|
+
return slug && /^[^/\s]+\/[^/\s]+$/.test(slug) ? slug : null;
|
|
920
|
+
}
|
|
921
|
+
function readProjectLinkSlug(projectRoot) {
|
|
922
|
+
const path = resolve3(projectRoot, ".rig", "state", "project-link.json");
|
|
923
|
+
if (!existsSync3(path))
|
|
924
|
+
return null;
|
|
925
|
+
try {
|
|
926
|
+
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
927
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
928
|
+
return null;
|
|
929
|
+
return normalizeRepoSlug(typeof parsed.repoSlug === "string" ? String(parsed.repoSlug) : null);
|
|
930
|
+
} catch {
|
|
931
|
+
return null;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
function writeProjectLinkConnection(projectRoot, repoSlug, alias) {
|
|
935
|
+
const path = resolve3(projectRoot, ".rig", "state", "project-link.json");
|
|
936
|
+
mkdirSync3(dirname2(path), { recursive: true });
|
|
937
|
+
writeFileSync2(path, `${JSON.stringify({ repoSlug, connection: alias, linkedAt: new Date().toISOString() }, null, 2)}
|
|
938
|
+
`, "utf8");
|
|
939
|
+
}
|
|
940
|
+
function remoteLinkRepairCommand(repoSlug) {
|
|
941
|
+
return repoSlug ? `rig server repair-link --repo ${repoSlug}` : "rig server repair-link --repo owner/repo";
|
|
942
|
+
}
|
|
943
|
+
function isRemoteProjectRootLinkError(error) {
|
|
944
|
+
const text = error instanceof Error ? error.message : String(error ?? "");
|
|
945
|
+
return /no server-host project root link|remote project(?:-root)? link|x-rig-project-root|serverProjectRoot/i.test(text);
|
|
946
|
+
}
|
|
947
|
+
function formatRemoteProjectLinkHint(resolution) {
|
|
948
|
+
const repair = remoteLinkRepairCommand(resolution.repoSlug);
|
|
949
|
+
if (resolution.status === "auth_required") {
|
|
950
|
+
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}` : ""}\`.`;
|
|
951
|
+
}
|
|
952
|
+
if (resolution.status === "missing_project") {
|
|
953
|
+
return `Record the repo slug, then run \`${repair}\` (or \`rig init --repo owner/repo --server remote --github-auth device\`).`;
|
|
954
|
+
}
|
|
955
|
+
if (resolution.status === "not_remote")
|
|
956
|
+
return "Select a remote server with `rig server use <alias>` before repairing a remote project link.";
|
|
957
|
+
return `Run \`${repair}\` to backfill or prepare a server-host checkout for the selected remote${resolution.alias ? ` (${resolution.alias})` : ""}.`;
|
|
958
|
+
}
|
|
959
|
+
function remoteProjectLinkFailure(input) {
|
|
960
|
+
const partial = {
|
|
961
|
+
status: input.status,
|
|
962
|
+
alias: input.alias,
|
|
963
|
+
baseUrl: input.baseUrl,
|
|
964
|
+
repoSlug: input.repoSlug
|
|
965
|
+
};
|
|
966
|
+
return {
|
|
967
|
+
ok: false,
|
|
968
|
+
...input,
|
|
969
|
+
hint: formatRemoteProjectLinkHint(partial),
|
|
970
|
+
next: remoteLinkRepairCommand(input.repoSlug)
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
function remoteProjectLinkSuccess(input) {
|
|
974
|
+
return {
|
|
975
|
+
ok: true,
|
|
976
|
+
status: input.status,
|
|
977
|
+
alias: input.alias,
|
|
978
|
+
baseUrl: input.baseUrl,
|
|
979
|
+
repoSlug: input.repoSlug,
|
|
980
|
+
serverProjectRoot: input.serverProjectRoot,
|
|
981
|
+
source: input.source,
|
|
982
|
+
prepared: input.prepared ?? input.status === "prepared",
|
|
983
|
+
validated: input.validated ?? false,
|
|
984
|
+
message: input.message ?? `Remote project link ready for ${input.repoSlug}.`,
|
|
985
|
+
hint: "Remote-scoped task/run/status requests will send x-rig-project-root for this server-host checkout.",
|
|
986
|
+
next: "rig task list"
|
|
987
|
+
};
|
|
988
|
+
}
|
|
989
|
+
function localCheckoutPathCandidate(projectRoot, candidate) {
|
|
990
|
+
try {
|
|
991
|
+
const local = resolve3(projectRoot);
|
|
992
|
+
const resolved = resolve3(candidate);
|
|
993
|
+
return resolved === local || resolved.startsWith(`${local}/`);
|
|
994
|
+
} catch {
|
|
995
|
+
return false;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
async function requestRemoteProjectLinkJson(baseUrl, pathname, authToken, init = {}) {
|
|
999
|
+
const requestUrl = new URL(`${baseUrl}${pathname}`);
|
|
1000
|
+
if (authToken && queryAuthFallbackEnabled())
|
|
1001
|
+
requestUrl.searchParams.set("rt", authToken);
|
|
1002
|
+
const response = await fetch(requestUrl, {
|
|
1003
|
+
...init,
|
|
1004
|
+
headers: mergeHeaders(init.headers, authToken)
|
|
1005
|
+
});
|
|
1006
|
+
const text = await response.text();
|
|
1007
|
+
const payload = text.trim().length > 0 ? (() => {
|
|
1008
|
+
try {
|
|
1009
|
+
return JSON.parse(text);
|
|
1010
|
+
} catch {
|
|
1011
|
+
return null;
|
|
1012
|
+
}
|
|
1013
|
+
})() : null;
|
|
1014
|
+
return { ok: response.ok, status: response.status, payload, text };
|
|
1015
|
+
}
|
|
1016
|
+
function payloadError(payload, fallback) {
|
|
1017
|
+
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
1018
|
+
const record = payload;
|
|
1019
|
+
const value = record.error ?? record.message ?? record.reason;
|
|
1020
|
+
if (typeof value === "string" && value.trim())
|
|
1021
|
+
return value.trim();
|
|
1022
|
+
}
|
|
1023
|
+
return fallback;
|
|
1024
|
+
}
|
|
1025
|
+
function checkoutPathsFromProjectPayload(payload) {
|
|
1026
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
1027
|
+
return [];
|
|
1028
|
+
const project = payload.project;
|
|
1029
|
+
if (!project || typeof project !== "object" || Array.isArray(project))
|
|
1030
|
+
return [];
|
|
1031
|
+
const checkouts = project.checkouts;
|
|
1032
|
+
if (!Array.isArray(checkouts))
|
|
1033
|
+
return [];
|
|
1034
|
+
return [...checkouts].reverse().flatMap((entry) => {
|
|
1035
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
1036
|
+
return [];
|
|
1037
|
+
const path = entry.path;
|
|
1038
|
+
return typeof path === "string" && path.trim() ? [path.trim()] : [];
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
function checkoutPathFromPreparePayload(payload) {
|
|
1042
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
1043
|
+
return null;
|
|
1044
|
+
const checkout = payload.checkout;
|
|
1045
|
+
if (!checkout || typeof checkout !== "object" || Array.isArray(checkout))
|
|
1046
|
+
return null;
|
|
1047
|
+
const path = checkout.path;
|
|
1048
|
+
return typeof path === "string" && path.trim() ? path.trim() : null;
|
|
1049
|
+
}
|
|
1050
|
+
async function validateAndPersistRemoteRoot(input) {
|
|
1051
|
+
const candidate = input.candidate.trim();
|
|
1052
|
+
if (!candidate || !isAbsolute(candidate)) {
|
|
1053
|
+
return remoteProjectLinkFailure({
|
|
1054
|
+
status: "invalid_root",
|
|
1055
|
+
alias: input.alias,
|
|
1056
|
+
baseUrl: input.baseUrl,
|
|
1057
|
+
repoSlug: input.repoSlug,
|
|
1058
|
+
message: `Remote project root candidate is not an absolute server-host path: ${candidate || "(empty)"}.`
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
if (localCheckoutPathCandidate(input.projectRoot, candidate)) {
|
|
1062
|
+
return remoteProjectLinkFailure({
|
|
1063
|
+
status: "invalid_root",
|
|
1064
|
+
alias: input.alias,
|
|
1065
|
+
baseUrl: input.baseUrl,
|
|
1066
|
+
repoSlug: input.repoSlug,
|
|
1067
|
+
message: `Refusing to use local checkout path ${candidate} as a remote server project root.`
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
let response;
|
|
1071
|
+
try {
|
|
1072
|
+
response = await requestRemoteProjectLinkJson(input.baseUrl, "/api/server/project-root", input.authToken, {
|
|
1073
|
+
method: "POST",
|
|
1074
|
+
headers: { "content-type": "application/json" },
|
|
1075
|
+
body: JSON.stringify({ projectRoot: candidate })
|
|
1076
|
+
});
|
|
1077
|
+
} catch (error) {
|
|
1078
|
+
return remoteProjectLinkFailure({
|
|
1079
|
+
status: "error",
|
|
1080
|
+
alias: input.alias,
|
|
1081
|
+
baseUrl: input.baseUrl,
|
|
1082
|
+
repoSlug: input.repoSlug,
|
|
1083
|
+
message: `Could not validate remote project root ${candidate}: ${error instanceof Error ? error.message : String(error)}`
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
1086
|
+
if (response.status === 401 || response.status === 403) {
|
|
1087
|
+
return remoteProjectLinkFailure({
|
|
1088
|
+
status: "auth_required",
|
|
1089
|
+
alias: input.alias,
|
|
1090
|
+
baseUrl: input.baseUrl,
|
|
1091
|
+
repoSlug: input.repoSlug,
|
|
1092
|
+
statusCode: response.status,
|
|
1093
|
+
message: `Remote server ${input.alias} requires authentication before validating project root ${candidate}.`
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
if (!response.ok) {
|
|
1097
|
+
return remoteProjectLinkFailure({
|
|
1098
|
+
status: "invalid_root",
|
|
1099
|
+
alias: input.alias,
|
|
1100
|
+
baseUrl: input.baseUrl,
|
|
1101
|
+
repoSlug: input.repoSlug,
|
|
1102
|
+
statusCode: response.status,
|
|
1103
|
+
message: `Remote server rejected project root ${candidate} (${response.status}): ${payloadError(response.payload, response.text || "project-root validation failed")}`
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
const record = response.payload && typeof response.payload === "object" && !Array.isArray(response.payload) ? response.payload : {};
|
|
1107
|
+
if (record.ok !== true) {
|
|
1108
|
+
return remoteProjectLinkFailure({
|
|
1109
|
+
status: "invalid_root",
|
|
1110
|
+
alias: input.alias,
|
|
1111
|
+
baseUrl: input.baseUrl,
|
|
1112
|
+
repoSlug: input.repoSlug,
|
|
1113
|
+
message: `Remote server did not accept project root ${candidate}: ${payloadError(response.payload, "project-root validation failed")}`
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
const accepted = typeof record.projectRoot === "string" && record.projectRoot.trim() ? record.projectRoot.trim() : typeof record.requestedProjectRoot === "string" && record.requestedProjectRoot.trim() ? record.requestedProjectRoot.trim() : candidate;
|
|
1117
|
+
writeRepoServerProjectRoot(input.projectRoot, accepted, { alias: input.alias, baseUrl: input.baseUrl, project: input.repoSlug });
|
|
1118
|
+
writeProjectLinkConnection(input.projectRoot, input.repoSlug, input.alias);
|
|
1119
|
+
const status = input.status ?? (input.prepared ? "prepared" : "backfilled");
|
|
1120
|
+
return remoteProjectLinkSuccess({
|
|
1121
|
+
status,
|
|
1122
|
+
alias: input.alias,
|
|
1123
|
+
baseUrl: input.baseUrl,
|
|
1124
|
+
repoSlug: input.repoSlug,
|
|
1125
|
+
serverProjectRoot: accepted,
|
|
1126
|
+
source: input.source,
|
|
1127
|
+
prepared: input.prepared,
|
|
1128
|
+
validated: true,
|
|
1129
|
+
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}.`
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
async function ensureRemoteProjectRootLink(projectRoot, options = {}) {
|
|
1133
|
+
let selected;
|
|
1134
|
+
try {
|
|
1135
|
+
selected = resolveSelectedConnection(projectRoot);
|
|
1136
|
+
} catch (error) {
|
|
1137
|
+
return remoteProjectLinkFailure({ status: "error", message: error instanceof Error ? error.message : String(error) });
|
|
1138
|
+
}
|
|
1139
|
+
if (!selected || selected.connection.kind !== "remote") {
|
|
1140
|
+
return remoteProjectLinkFailure({ status: "not_remote", message: "No remote Rig server is selected for this repo." });
|
|
1141
|
+
}
|
|
1142
|
+
const repo = readRepoConnection(projectRoot);
|
|
1143
|
+
const explicitRepoRequested = options.repoSlug !== undefined;
|
|
1144
|
+
const explicitRepoSlug = explicitRepoRequested ? normalizeRepoSlug(options.repoSlug) : null;
|
|
1145
|
+
const repoProjectSlug = normalizeRepoSlug(repo?.project);
|
|
1146
|
+
const repoSlug = explicitRepoSlug ?? repoProjectSlug ?? readProjectLinkSlug(projectRoot);
|
|
1147
|
+
const alias = selected.alias;
|
|
1148
|
+
const baseUrl = selected.connection.baseUrl;
|
|
1149
|
+
const authToken = options.authToken === undefined ? readGitHubBearerTokenForRemote(projectRoot) : options.authToken;
|
|
1150
|
+
const mode = options.mode ?? "backfill-only";
|
|
1151
|
+
if (explicitRepoRequested && !explicitRepoSlug) {
|
|
1152
|
+
return remoteProjectLinkFailure({
|
|
1153
|
+
status: "missing_project",
|
|
1154
|
+
alias,
|
|
1155
|
+
baseUrl,
|
|
1156
|
+
message: `Invalid --repo value ${JSON.stringify(options.repoSlug)}. Expected owner/repo.`
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1159
|
+
if (!repoSlug) {
|
|
1160
|
+
return remoteProjectLinkFailure({
|
|
1161
|
+
status: "missing_project",
|
|
1162
|
+
alias,
|
|
1163
|
+
baseUrl,
|
|
1164
|
+
message: `Remote server ${alias} is selected, but this checkout has no GitHub repo slug recorded.`
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
const skippedCandidates = [];
|
|
1168
|
+
const storedRoot = selected.serverProjectRoot?.trim() || null;
|
|
1169
|
+
const storedRootMatchesResolvedRepo = repoProjectSlug === repoSlug;
|
|
1170
|
+
if (storedRoot && storedRootMatchesResolvedRepo) {
|
|
1171
|
+
if (localCheckoutPathCandidate(projectRoot, storedRoot)) {
|
|
1172
|
+
clearRepoServerProjectRoot(projectRoot);
|
|
1173
|
+
skippedCandidates.push(storedRoot);
|
|
1174
|
+
} else {
|
|
1175
|
+
const storedResult = await validateAndPersistRemoteRoot({
|
|
1176
|
+
projectRoot,
|
|
1177
|
+
alias,
|
|
1178
|
+
baseUrl,
|
|
1179
|
+
authToken,
|
|
1180
|
+
repoSlug,
|
|
1181
|
+
candidate: storedRoot,
|
|
1182
|
+
source: "stored",
|
|
1183
|
+
status: "ready"
|
|
1184
|
+
});
|
|
1185
|
+
if (storedResult.ok || storedResult.status === "auth_required" || storedResult.status === "error")
|
|
1186
|
+
return storedResult;
|
|
1187
|
+
clearRepoServerProjectRoot(projectRoot);
|
|
1188
|
+
skippedCandidates.push(storedRoot);
|
|
1189
|
+
}
|
|
1190
|
+
} else if (storedRoot) {
|
|
1191
|
+
skippedCandidates.push(storedRoot);
|
|
1192
|
+
}
|
|
1193
|
+
const authCandidate = inferRemoteServerProjectRootCandidateFromAuthState(projectRoot, repoSlug);
|
|
1194
|
+
if (authCandidate) {
|
|
1195
|
+
const authResult = await validateAndPersistRemoteRoot({ projectRoot, alias, baseUrl, authToken, repoSlug, candidate: authCandidate, source: "auth-state" });
|
|
1196
|
+
if (authResult.ok || authResult.status === "auth_required")
|
|
1197
|
+
return authResult;
|
|
1198
|
+
}
|
|
1199
|
+
let registryResponse;
|
|
1200
|
+
try {
|
|
1201
|
+
registryResponse = await requestRemoteProjectLinkJson(baseUrl, `/api/projects/${encodeURIComponent(repoSlug)}`, authToken);
|
|
1202
|
+
} catch (error) {
|
|
1203
|
+
return remoteProjectLinkFailure({
|
|
1204
|
+
status: "error",
|
|
1205
|
+
alias,
|
|
1206
|
+
baseUrl,
|
|
1207
|
+
repoSlug,
|
|
1208
|
+
message: `Could not read remote project registry for ${repoSlug} on ${alias}: ${error instanceof Error ? error.message : String(error)}`
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
if (registryResponse.status === 401 || registryResponse.status === 403) {
|
|
1212
|
+
return remoteProjectLinkFailure({
|
|
1213
|
+
status: "auth_required",
|
|
1214
|
+
alias,
|
|
1215
|
+
baseUrl,
|
|
1216
|
+
repoSlug,
|
|
1217
|
+
statusCode: registryResponse.status,
|
|
1218
|
+
message: `Remote server ${alias} requires authentication before reading the ${repoSlug} project registry.`
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
if (registryResponse.ok) {
|
|
1222
|
+
const candidates = checkoutPathsFromProjectPayload(registryResponse.payload);
|
|
1223
|
+
for (const candidate of candidates) {
|
|
1224
|
+
const result = await validateAndPersistRemoteRoot({ projectRoot, alias, baseUrl, authToken, repoSlug, candidate, source: "registry" });
|
|
1225
|
+
if (result.ok || result.status === "auth_required")
|
|
1226
|
+
return result;
|
|
1227
|
+
skippedCandidates.push(candidate);
|
|
1228
|
+
}
|
|
1229
|
+
if (mode === "backfill-only") {
|
|
1230
|
+
return remoteProjectLinkFailure({
|
|
1231
|
+
status: candidates.length > 0 ? "invalid_root" : "no_server_checkout",
|
|
1232
|
+
alias,
|
|
1233
|
+
baseUrl,
|
|
1234
|
+
repoSlug,
|
|
1235
|
+
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.`,
|
|
1236
|
+
skippedCandidates
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
} else if (registryResponse.status === 404) {
|
|
1240
|
+
if (mode === "backfill-only") {
|
|
1241
|
+
return remoteProjectLinkFailure({
|
|
1242
|
+
status: "project_not_registered",
|
|
1243
|
+
alias,
|
|
1244
|
+
baseUrl,
|
|
1245
|
+
repoSlug,
|
|
1246
|
+
statusCode: registryResponse.status,
|
|
1247
|
+
message: `Remote server ${alias} has no registered project record for ${repoSlug}.`
|
|
1248
|
+
});
|
|
1249
|
+
}
|
|
1250
|
+
} else {
|
|
1251
|
+
return remoteProjectLinkFailure({
|
|
1252
|
+
status: "error",
|
|
1253
|
+
alias,
|
|
1254
|
+
baseUrl,
|
|
1255
|
+
repoSlug,
|
|
1256
|
+
statusCode: registryResponse.status,
|
|
1257
|
+
message: `Could not backfill ${repoSlug} from remote registry (${registryResponse.status}): ${payloadError(registryResponse.payload, registryResponse.text || "registry lookup failed")}`,
|
|
1258
|
+
skippedCandidates
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
1261
|
+
let prepareResponse;
|
|
1262
|
+
try {
|
|
1263
|
+
prepareResponse = await requestRemoteProjectLinkJson(baseUrl, `/api/projects/${encodeURIComponent(repoSlug)}/prepare-checkout`, authToken, {
|
|
1264
|
+
method: "POST",
|
|
1265
|
+
headers: { "content-type": "application/json" },
|
|
1266
|
+
body: JSON.stringify({ checkout: { kind: "managed-clone" }, repoUrl: `https://github.com/${repoSlug}.git` })
|
|
1267
|
+
});
|
|
1268
|
+
} catch (error) {
|
|
1269
|
+
return remoteProjectLinkFailure({
|
|
1270
|
+
status: "error",
|
|
1271
|
+
alias,
|
|
1272
|
+
baseUrl,
|
|
1273
|
+
repoSlug,
|
|
1274
|
+
message: `Could not prepare remote checkout for ${repoSlug} on ${alias}: ${error instanceof Error ? error.message : String(error)}`
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
if (prepareResponse.status === 401 || prepareResponse.status === 403) {
|
|
1278
|
+
return remoteProjectLinkFailure({
|
|
1279
|
+
status: "auth_required",
|
|
1280
|
+
alias,
|
|
1281
|
+
baseUrl,
|
|
1282
|
+
repoSlug,
|
|
1283
|
+
statusCode: prepareResponse.status,
|
|
1284
|
+
message: `Remote server ${alias} requires authentication before preparing ${repoSlug}.`
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
if (!prepareResponse.ok) {
|
|
1288
|
+
return remoteProjectLinkFailure({
|
|
1289
|
+
status: "error",
|
|
1290
|
+
alias,
|
|
1291
|
+
baseUrl,
|
|
1292
|
+
repoSlug,
|
|
1293
|
+
statusCode: prepareResponse.status,
|
|
1294
|
+
message: `Remote checkout prepare failed for ${repoSlug} (${prepareResponse.status}): ${payloadError(prepareResponse.payload, prepareResponse.text || "prepare-checkout failed")}`,
|
|
1295
|
+
skippedCandidates
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
const preparedPath = checkoutPathFromPreparePayload(prepareResponse.payload);
|
|
1299
|
+
if (!preparedPath) {
|
|
1300
|
+
return remoteProjectLinkFailure({
|
|
1301
|
+
status: "invalid_root",
|
|
1302
|
+
alias,
|
|
1303
|
+
baseUrl,
|
|
1304
|
+
repoSlug,
|
|
1305
|
+
message: `Remote checkout prepare for ${repoSlug} did not return a checkout.path.`,
|
|
1306
|
+
skippedCandidates
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
return validateAndPersistRemoteRoot({ projectRoot, alias, baseUrl, authToken, repoSlug, candidate: preparedPath, source: "prepare", prepared: true });
|
|
1310
|
+
}
|
|
1311
|
+
async function inspectRemoteProjectLink(projectRoot) {
|
|
1312
|
+
return ensureRemoteProjectRootLink(projectRoot, { mode: "backfill-only" });
|
|
1313
|
+
}
|
|
1314
|
+
async function repairRemoteProjectRootLink(context, options = {}) {
|
|
1315
|
+
const resolution = await ensureRemoteProjectRootLink(context.projectRoot, { mode: options.mode ?? "prepare-if-missing", repoSlug: options.repoSlug });
|
|
1316
|
+
if (!resolution.ok)
|
|
1317
|
+
throw new CliError(resolution.message, 1, { hint: resolution.hint });
|
|
1318
|
+
return resolution;
|
|
1319
|
+
}
|
|
869
1320
|
async function ensureServerForCli(projectRoot) {
|
|
870
1321
|
try {
|
|
871
1322
|
const selected = resolveSelectedConnection(projectRoot);
|
|
872
1323
|
if (selected?.connection.kind === "remote") {
|
|
873
1324
|
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
874
1325
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
875
|
-
const
|
|
1326
|
+
const link = await ensureRemoteProjectRootLink(projectRoot, { mode: "backfill-only", authToken });
|
|
876
1327
|
return {
|
|
877
1328
|
baseUrl: selected.connection.baseUrl,
|
|
878
1329
|
authToken,
|
|
879
1330
|
connectionKind: "remote",
|
|
880
|
-
serverProjectRoot
|
|
1331
|
+
serverProjectRoot: link.ok ? link.serverProjectRoot ?? null : null
|
|
881
1332
|
};
|
|
882
1333
|
}
|
|
883
1334
|
reportServerPhase("Starting local Rig server\u2026");
|
|
@@ -895,32 +1346,6 @@ async function ensureServerForCli(projectRoot) {
|
|
|
895
1346
|
throw error;
|
|
896
1347
|
}
|
|
897
1348
|
}
|
|
898
|
-
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
899
|
-
const repo = readRepoConnection(projectRoot);
|
|
900
|
-
const slug = repo?.project?.trim();
|
|
901
|
-
if (!slug)
|
|
902
|
-
return null;
|
|
903
|
-
try {
|
|
904
|
-
const url = new URL(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`);
|
|
905
|
-
if (authToken && queryAuthFallbackEnabled())
|
|
906
|
-
url.searchParams.set("rt", authToken);
|
|
907
|
-
const response = await fetch(url, {
|
|
908
|
-
headers: mergeHeaders(undefined, authToken)
|
|
909
|
-
});
|
|
910
|
-
if (!response.ok)
|
|
911
|
-
return null;
|
|
912
|
-
const payload = await response.json();
|
|
913
|
-
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
914
|
-
const checkouts = Array.isArray(project?.checkouts) ? project.checkouts : [];
|
|
915
|
-
const latestCheckout = [...checkouts].reverse().find((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.path === "string"));
|
|
916
|
-
const path = typeof latestCheckout?.path === "string" && latestCheckout.path.trim() ? latestCheckout.path.trim() : null;
|
|
917
|
-
if (path)
|
|
918
|
-
writeRepoServerProjectRoot(projectRoot, path);
|
|
919
|
-
return path;
|
|
920
|
-
} catch {
|
|
921
|
-
return null;
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
1349
|
function appendTaskFilterParams(url, filters) {
|
|
925
1350
|
if (filters.assignee)
|
|
926
1351
|
url.searchParams.set("assignee", filters.assignee);
|
|
@@ -1021,13 +1446,20 @@ function canUseRemoteWithoutProjectRoot(pathname) {
|
|
|
1021
1446
|
async function requestServerJson(context, pathname, init = {}) {
|
|
1022
1447
|
const server = await ensureServerForCli(context.projectRoot);
|
|
1023
1448
|
const requestUrl = new URL(`${server.baseUrl}${pathname}`);
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1449
|
+
let scopedServerProjectRoot = server.serverProjectRoot;
|
|
1450
|
+
if (server.connectionKind === "remote" && !scopedServerProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
|
|
1451
|
+
const link = await ensureRemoteProjectRootLink(context.projectRoot, { mode: "backfill-only", authToken: server.authToken });
|
|
1452
|
+
if (link.ok && link.serverProjectRoot) {
|
|
1453
|
+
scopedServerProjectRoot = link.serverProjectRoot;
|
|
1454
|
+
} else {
|
|
1455
|
+
const repo = readRepoConnection(context.projectRoot);
|
|
1456
|
+
const target = link.alias && link.baseUrl ? `${link.alias} (${link.baseUrl})` : server.baseUrl;
|
|
1457
|
+
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 });
|
|
1458
|
+
}
|
|
1027
1459
|
}
|
|
1028
1460
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
1029
|
-
if (
|
|
1030
|
-
headers.set("x-rig-project-root",
|
|
1461
|
+
if (scopedServerProjectRoot)
|
|
1462
|
+
headers.set("x-rig-project-root", scopedServerProjectRoot);
|
|
1031
1463
|
if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
|
|
1032
1464
|
requestUrl.searchParams.set("rt", server.authToken);
|
|
1033
1465
|
}
|
|
@@ -2072,12 +2504,13 @@ var init__help_catalog = __esm(() => {
|
|
|
2072
2504
|
{
|
|
2073
2505
|
name: "server",
|
|
2074
2506
|
summary: "Choose, inspect, and start the Rig server that owns tasks and runs.",
|
|
2075
|
-
usage: ["rig server <status|list|add|use|start> [options]"],
|
|
2507
|
+
usage: ["rig server <status|list|add|use|repair-link|start> [options]"],
|
|
2076
2508
|
commands: [
|
|
2077
|
-
{ command: "status", description: "Show the selected server for this repo.", primary: true },
|
|
2509
|
+
{ command: "status", description: "Show the selected server and remote project-root link for this repo.", primary: true },
|
|
2078
2510
|
{ command: "use local", description: "Switch this repo to the local Rig server.", primary: true },
|
|
2079
2511
|
{ command: "add <alias> <url>", description: "Save a remote Rig server URL.", primary: true },
|
|
2080
2512
|
{ command: "use <alias>", description: "Select a saved remote server alias.", primary: true },
|
|
2513
|
+
{ command: "repair-link [--prepare|--backfill-only] [--repo owner/repo]", description: "Backfill or prepare the selected remote's server-host checkout link.", primary: true },
|
|
2081
2514
|
{ command: "list", description: "List saved local/remote server aliases.", primary: true },
|
|
2082
2515
|
{ command: "start [--host <host>] [--port <n>]", description: "Start a local rig-server process." }
|
|
2083
2516
|
],
|
|
@@ -2085,6 +2518,7 @@ var init__help_catalog = __esm(() => {
|
|
|
2085
2518
|
"rig server status",
|
|
2086
2519
|
"rig server add prod https://where.rig-does.work",
|
|
2087
2520
|
"rig server use prod",
|
|
2521
|
+
"rig server repair-link --repo owner/repo",
|
|
2088
2522
|
"rig server use local",
|
|
2089
2523
|
"rig server start --port 3773"
|
|
2090
2524
|
],
|
|
@@ -2795,7 +3229,7 @@ function resolveControlPlaneDefinitionRoot(projectRoot) {
|
|
|
2795
3229
|
var init__paths = () => {};
|
|
2796
3230
|
|
|
2797
3231
|
// packages/cli/src/report-bug.ts
|
|
2798
|
-
import { copyFileSync, existsSync as existsSync6, mkdirSync as
|
|
3232
|
+
import { copyFileSync, existsSync as existsSync6, mkdirSync as mkdirSync4, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
2799
3233
|
import { basename as basename2, extname, join, resolve as resolve8 } from "path";
|
|
2800
3234
|
function slugifyBugTitle(value) {
|
|
2801
3235
|
const slug = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80).replace(/-+$/g, "");
|
|
@@ -2834,8 +3268,8 @@ function createBugReportFiles(input) {
|
|
|
2834
3268
|
}
|
|
2835
3269
|
rmSync2(reportDir, { recursive: true, force: true });
|
|
2836
3270
|
}
|
|
2837
|
-
|
|
2838
|
-
|
|
3271
|
+
mkdirSync4(assetDir, { recursive: true });
|
|
3272
|
+
mkdirSync4(screenshotDir, { recursive: true });
|
|
2839
3273
|
const copiedScreenshots = copyEvidenceFiles(input.projectRoot, screenshotDir, input.screenshots ?? [], "screenshot");
|
|
2840
3274
|
const copiedAssets = copyEvidenceFiles(input.projectRoot, assetDir, input.assets ?? [], "asset");
|
|
2841
3275
|
const manifestAssets = [
|
|
@@ -2865,15 +3299,15 @@ function createBugReportFiles(input) {
|
|
|
2865
3299
|
platform: process.platform,
|
|
2866
3300
|
arch: process.arch
|
|
2867
3301
|
};
|
|
2868
|
-
|
|
2869
|
-
|
|
3302
|
+
writeFileSync3(join(assetDir, "README.md"), buildAssetReadme(input.title), "utf8");
|
|
3303
|
+
writeFileSync3(join(screenshotDir, "README.md"), buildScreenshotReadme(input.title), "utf8");
|
|
2870
3304
|
if (browserPath && browser) {
|
|
2871
|
-
|
|
3305
|
+
writeFileSync3(browserPath, `${JSON.stringify(browser, null, 2)}
|
|
2872
3306
|
`, "utf8");
|
|
2873
3307
|
}
|
|
2874
|
-
|
|
3308
|
+
writeFileSync3(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
2875
3309
|
`, "utf8");
|
|
2876
|
-
|
|
3310
|
+
writeFileSync3(taskPath, buildBugReportMarkdown(input, browser, copiedScreenshots, copiedAssets), "utf8");
|
|
2877
3311
|
return {
|
|
2878
3312
|
slug,
|
|
2879
3313
|
reportDir,
|
|
@@ -3050,7 +3484,7 @@ function formatAssetMarkdown(name, path) {
|
|
|
3050
3484
|
var init_report_bug = () => {};
|
|
3051
3485
|
|
|
3052
3486
|
// packages/cli/src/commands/task-report-bug.ts
|
|
3053
|
-
import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as
|
|
3487
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
3054
3488
|
import { resolve as resolve9 } from "path";
|
|
3055
3489
|
import pc2 from "picocolors";
|
|
3056
3490
|
import {
|
|
@@ -3412,7 +3846,7 @@ function appendTaskConfigEntryPreservingText(taskConfigPath, issueId, entry) {
|
|
|
3412
3846
|
`).map((line) => ` ${line}`).join(`
|
|
3413
3847
|
`);
|
|
3414
3848
|
if (!trimmed || trimmed === "{}") {
|
|
3415
|
-
|
|
3849
|
+
writeFileSync4(taskConfigPath, `{
|
|
3416
3850
|
${serializedEntry}
|
|
3417
3851
|
}
|
|
3418
3852
|
`, "utf8");
|
|
@@ -3428,7 +3862,7 @@ ${serializedEntry}
|
|
|
3428
3862
|
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." });
|
|
3429
3863
|
}
|
|
3430
3864
|
const comma = before.trim() === "{" ? "" : ",";
|
|
3431
|
-
|
|
3865
|
+
writeFileSync4(taskConfigPath, `${before}${comma}
|
|
3432
3866
|
${serializedEntry}
|
|
3433
3867
|
}
|
|
3434
3868
|
`, "utf8");
|
|
@@ -3813,7 +4247,7 @@ var init_task_report_bug = __esm(() => {
|
|
|
3813
4247
|
});
|
|
3814
4248
|
|
|
3815
4249
|
// packages/cli/src/commands/browser.ts
|
|
3816
|
-
import { mkdirSync as
|
|
4250
|
+
import { mkdirSync as mkdirSync5, rmSync as rmSync3 } from "fs";
|
|
3817
4251
|
import { resolve as resolve10 } from "path";
|
|
3818
4252
|
import { spawn } from "child_process";
|
|
3819
4253
|
import { emitKeypressEvents } from "readline";
|
|
@@ -4391,7 +4825,7 @@ function readBrowserDemoCommandLine(command) {
|
|
|
4391
4825
|
}
|
|
4392
4826
|
async function launchBrowserDemo(runtime) {
|
|
4393
4827
|
rmSync3(resolve10(runtime.browserDir, runtime.stateDir), { recursive: true, force: true });
|
|
4394
|
-
|
|
4828
|
+
mkdirSync5(resolve10(runtime.browserDir, runtime.stateDir), { recursive: true });
|
|
4395
4829
|
const launcherPath = resolve10(runtime.browserDir, "scripts/electron-launcher.mjs");
|
|
4396
4830
|
const launcher = await import(pathToFileURL(launcherPath).href);
|
|
4397
4831
|
const electronPath = await launcher.resolveElectronPath();
|
|
@@ -4740,7 +5174,7 @@ var init_profile_and_review = __esm(() => {
|
|
|
4740
5174
|
});
|
|
4741
5175
|
|
|
4742
5176
|
// packages/cli/src/commands/_policy.ts
|
|
4743
|
-
import { appendFileSync, mkdirSync as
|
|
5177
|
+
import { appendFileSync, mkdirSync as mkdirSync6 } from "fs";
|
|
4744
5178
|
import { resolve as resolve11 } from "path";
|
|
4745
5179
|
import { evaluate as evaluate2, loadPolicy as loadPolicy2, resolveAction as resolveAction2 } from "@rig/runtime/control-plane/runtime/guard";
|
|
4746
5180
|
import { resolveHarnessPaths } from "@rig/runtime/control-plane/native/utils";
|
|
@@ -4757,7 +5191,7 @@ function appendControlledBashAudit(context, mode, command, args, matchedRuleIds,
|
|
|
4757
5191
|
}
|
|
4758
5192
|
const logsDir = resolveHarnessPaths(context.projectRoot).logsDir;
|
|
4759
5193
|
const logFile = resolve11(logsDir, "controlled-bash.jsonl");
|
|
4760
|
-
|
|
5194
|
+
mkdirSync6(logsDir, { recursive: true });
|
|
4761
5195
|
const payload = {
|
|
4762
5196
|
timestamp: new Date().toISOString(),
|
|
4763
5197
|
mode,
|
|
@@ -5051,9 +5485,9 @@ var exports_pi = {};
|
|
|
5051
5485
|
__export(exports_pi, {
|
|
5052
5486
|
executePi: () => executePi
|
|
5053
5487
|
});
|
|
5054
|
-
import { existsSync as existsSync9, mkdirSync as
|
|
5488
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
5055
5489
|
import { homedir as homedir4 } from "os";
|
|
5056
|
-
import { dirname as
|
|
5490
|
+
import { dirname as dirname3, resolve as resolve13 } from "path";
|
|
5057
5491
|
function settingsPath(root) {
|
|
5058
5492
|
return resolve13(root, ".pi", "settings.json");
|
|
5059
5493
|
}
|
|
@@ -5078,8 +5512,8 @@ function packageKey(entry) {
|
|
|
5078
5512
|
return JSON.stringify(entry);
|
|
5079
5513
|
}
|
|
5080
5514
|
function writeSettings(path, settings) {
|
|
5081
|
-
|
|
5082
|
-
|
|
5515
|
+
mkdirSync7(dirname3(path), { recursive: true });
|
|
5516
|
+
writeFileSync5(path, `${JSON.stringify(settings, null, 2)}
|
|
5083
5517
|
`, "utf-8");
|
|
5084
5518
|
}
|
|
5085
5519
|
async function searchNpmForPiExtensions(term) {
|
|
@@ -5262,6 +5696,14 @@ function permissionAllowsPr2(payload) {
|
|
|
5262
5696
|
function isNotFoundError(error) {
|
|
5263
5697
|
return /\b(404|not found)\b/i.test(message(error));
|
|
5264
5698
|
}
|
|
5699
|
+
function isLoopbackBaseUrl(baseUrl) {
|
|
5700
|
+
try {
|
|
5701
|
+
const host = new URL(baseUrl).hostname.toLowerCase();
|
|
5702
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
|
|
5703
|
+
} catch {
|
|
5704
|
+
return false;
|
|
5705
|
+
}
|
|
5706
|
+
}
|
|
5265
5707
|
function projectCheckoutReady(payload) {
|
|
5266
5708
|
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
5267
5709
|
return null;
|
|
@@ -5316,25 +5758,37 @@ async function runFastTaskRunPreflight(context, options = {}) {
|
|
|
5316
5758
|
}
|
|
5317
5759
|
const repo = readRepoConnection(context.projectRoot);
|
|
5318
5760
|
const remoteWithoutProjectLink = selectedServer?.connectionKind === "remote" && !repo?.project;
|
|
5319
|
-
|
|
5761
|
+
let remoteRootBlocked = false;
|
|
5762
|
+
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>`."));
|
|
5763
|
+
if (selectedServer?.connectionKind === "remote" && repo?.project && !selectedServer.serverProjectRoot) {
|
|
5764
|
+
const link = await ensureRemoteProjectRootLink(context.projectRoot, { mode: "backfill-only", authToken: selectedServer.authToken });
|
|
5765
|
+
const loopbackDevRemote = !selectedServer.authToken && isLoopbackBaseUrl(selectedServer.baseUrl);
|
|
5766
|
+
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));
|
|
5767
|
+
remoteRootBlocked = !link.ok && !loopbackDevRemote;
|
|
5768
|
+
}
|
|
5320
5769
|
try {
|
|
5321
5770
|
const auth = await request("/api/github/auth/status");
|
|
5322
5771
|
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>`."));
|
|
5323
5772
|
} catch (error) {
|
|
5324
5773
|
checks.push(preflightCheck("github-auth", "GitHub auth valid", legacyServerCompatibility ? "warn" : "fail", message(error), "Fix GitHub auth on the selected Rig server."));
|
|
5325
5774
|
}
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5775
|
+
if (!remoteRootBlocked) {
|
|
5776
|
+
try {
|
|
5777
|
+
const projection = await request("/api/workspace/task-projection");
|
|
5778
|
+
checks.push(preflightCheck("task-projection", "task projection ready", "pass", JSON.stringify(projection).slice(0, 120)));
|
|
5779
|
+
} catch (error) {
|
|
5780
|
+
checks.push(preflightCheck("task-projection", "task projection ready", "warn", message(error), "Refresh task projection with `rig task list` before launching."));
|
|
5781
|
+
}
|
|
5782
|
+
try {
|
|
5783
|
+
const permissions = await request("/api/github/repo/permissions");
|
|
5784
|
+
const allowed = permissionAllowsPr2(permissions);
|
|
5785
|
+
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."));
|
|
5786
|
+
} catch (error) {
|
|
5787
|
+
checks.push(preflightCheck("github-repo-permissions", "GitHub PR permissions", "warn", message(error), "Ensure the selected token can push branches and open PRs."));
|
|
5788
|
+
}
|
|
5789
|
+
} else {
|
|
5790
|
+
checks.push(preflightCheck("task-projection", "task projection ready", "warn", "skipped until remote project-root link is repaired", "Run `rig server repair-link`, then retry."));
|
|
5791
|
+
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."));
|
|
5338
5792
|
}
|
|
5339
5793
|
if (repo?.project) {
|
|
5340
5794
|
try {
|
|
@@ -5346,19 +5800,24 @@ async function runFastTaskRunPreflight(context, options = {}) {
|
|
|
5346
5800
|
}
|
|
5347
5801
|
}
|
|
5348
5802
|
if (taskId) {
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5803
|
+
if (!remoteRootBlocked) {
|
|
5804
|
+
try {
|
|
5805
|
+
const tasks = await request(`/api/workspace/tasks?limit=200&refresh=1`);
|
|
5806
|
+
const found = Array.isArray(tasks) && tasks.some((task) => taskMatchesId(task, taskId));
|
|
5807
|
+
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."));
|
|
5808
|
+
} catch (error) {
|
|
5809
|
+
checks.push(preflightCheck("issue", "task/issue accessible", legacyServerCompatibility ? "warn" : "fail", message(error), "Fix the task source before launching a run."));
|
|
5810
|
+
}
|
|
5811
|
+
try {
|
|
5812
|
+
const runs = await request("/api/runs?limit=200");
|
|
5813
|
+
const duplicate = activeDuplicateRun(runs, taskId);
|
|
5814
|
+
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));
|
|
5815
|
+
} catch (error) {
|
|
5816
|
+
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."));
|
|
5817
|
+
}
|
|
5818
|
+
} else {
|
|
5819
|
+
checks.push(preflightCheck("issue", "task/issue accessible", "fail", "skipped until remote project-root link is repaired", "Run `rig server repair-link`, then retry."));
|
|
5820
|
+
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."));
|
|
5362
5821
|
}
|
|
5363
5822
|
}
|
|
5364
5823
|
if ((options.runtimeAdapter ?? "pi") === "pi") {
|
|
@@ -5839,7 +6298,7 @@ import {
|
|
|
5839
6298
|
chmodSync,
|
|
5840
6299
|
copyFileSync as copyFileSync2,
|
|
5841
6300
|
existsSync as existsSync11,
|
|
5842
|
-
mkdirSync as
|
|
6301
|
+
mkdirSync as mkdirSync8,
|
|
5843
6302
|
readdirSync,
|
|
5844
6303
|
readlinkSync,
|
|
5845
6304
|
rmSync as rmSync4,
|
|
@@ -5944,7 +6403,7 @@ async function executeDist(context, args) {
|
|
|
5944
6403
|
requireNoExtraArgs(pending, "rig dist install [--scope user|system] [--path <dir>]");
|
|
5945
6404
|
const scope = parseInstallScope(scopeResult.value);
|
|
5946
6405
|
const installDir = resolveInstallDir(scope, pathResult.value);
|
|
5947
|
-
|
|
6406
|
+
mkdirSync8(installDir, { recursive: true });
|
|
5948
6407
|
let source = await findLatestDistBinary(context.projectRoot);
|
|
5949
6408
|
let buildDir = null;
|
|
5950
6409
|
if (!source) {
|
|
@@ -5999,7 +6458,7 @@ async function executeDist(context, args) {
|
|
|
5999
6458
|
const fp = await computeRuntimeImageFingerprint(context.projectRoot);
|
|
6000
6459
|
const currentId = computeRuntimeImageId(fp);
|
|
6001
6460
|
const imagesDir = resolve16(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "images");
|
|
6002
|
-
|
|
6461
|
+
mkdirSync8(imagesDir, { recursive: true });
|
|
6003
6462
|
let pruned = 0;
|
|
6004
6463
|
for (const entry of readdirSync(imagesDir, { withFileTypes: true })) {
|
|
6005
6464
|
if (entry.isDirectory() && entry.name !== currentId) {
|
|
@@ -6011,9 +6470,9 @@ async function executeDist(context, args) {
|
|
|
6011
6470
|
console.log(`Pruned ${pruned} stale image(s).`);
|
|
6012
6471
|
}
|
|
6013
6472
|
const imageDir = resolve16(imagesDir, currentId);
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6473
|
+
mkdirSync8(resolve16(imageDir, "bin/hooks"), { recursive: true });
|
|
6474
|
+
mkdirSync8(resolve16(imageDir, "bin/plugins"), { recursive: true });
|
|
6475
|
+
mkdirSync8(resolve16(imageDir, "bin/validators"), { recursive: true });
|
|
6017
6476
|
const hookNames = [
|
|
6018
6477
|
"scope-guard",
|
|
6019
6478
|
"import-guard",
|
|
@@ -6038,8 +6497,8 @@ async function executeDist(context, args) {
|
|
|
6038
6497
|
const binPluginsDir = resolve16(resolveControlPlaneHostBinDir(context.projectRoot), "plugins");
|
|
6039
6498
|
const validatorsRoot = resolve16(hostProjectRoot, "packages/runtime/src/control-plane/validators");
|
|
6040
6499
|
const binValidatorsDir = resolve16(resolveControlPlaneHostBinDir(context.projectRoot), "validators");
|
|
6041
|
-
|
|
6042
|
-
|
|
6500
|
+
mkdirSync8(binPluginsDir, { recursive: true });
|
|
6501
|
+
mkdirSync8(binValidatorsDir, { recursive: true });
|
|
6043
6502
|
if (existsSync11(pluginsDir)) {
|
|
6044
6503
|
for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
|
|
6045
6504
|
const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
@@ -6478,16 +6937,19 @@ function formatConnectionList(connections) {
|
|
|
6478
6937
|
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(`
|
|
6479
6938
|
`);
|
|
6480
6939
|
}
|
|
6481
|
-
function formatConnectionStatus(selected, connections) {
|
|
6940
|
+
function formatConnectionStatus(selected, connections, repo, remoteProjectLink) {
|
|
6482
6941
|
const connection = selected === "local" ? { kind: "local", mode: "auto" } : connections[selected];
|
|
6483
6942
|
const target = !connection ? "not configured" : connection.kind === "remote" ? connection.baseUrl : "local";
|
|
6943
|
+
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";
|
|
6484
6944
|
return [
|
|
6485
6945
|
formatSection("Rig server", "selected for this repo"),
|
|
6486
6946
|
`${themeFaint("\u2502")} ${themeDim("selected ")} ${pc4.bold(selected)}`,
|
|
6487
6947
|
`${themeFaint("\u2502")} ${themeDim("kind ")} ${formatStatusPill(connection?.kind ?? "unknown")}`,
|
|
6488
6948
|
`${themeFaint("\u2502")} ${themeDim("target ")} ${target ?? "not configured"}`,
|
|
6949
|
+
...repo?.project ? [`${themeFaint("\u2502")} ${themeDim("project ")} ${repo.project}`] : [],
|
|
6950
|
+
...connection?.kind === "remote" ? [`${themeFaint("\u2502")} ${themeDim("root ")} ${rootLabel}`] : [],
|
|
6489
6951
|
"",
|
|
6490
|
-
...formatNextSteps(["Change: `rig server use <alias|local>`", "List saved servers: `rig server list`"])
|
|
6952
|
+
...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`"])
|
|
6491
6953
|
].join(`
|
|
6492
6954
|
`);
|
|
6493
6955
|
}
|
|
@@ -6778,7 +7240,7 @@ var init_inbox = __esm(() => {
|
|
|
6778
7240
|
|
|
6779
7241
|
// packages/cli/src/commands/_snapshot-upload.ts
|
|
6780
7242
|
import { mkdir, readdir, readFile, writeFile } from "fs/promises";
|
|
6781
|
-
import { dirname as
|
|
7243
|
+
import { dirname as dirname4, resolve as resolve17, relative, sep } from "path";
|
|
6782
7244
|
function toPosixPath(path) {
|
|
6783
7245
|
return path.split(sep).join("/");
|
|
6784
7246
|
}
|
|
@@ -6879,7 +7341,7 @@ __export(exports_init, {
|
|
|
6879
7341
|
DEMO_TASKS_RELATIVE_DIR: () => DEMO_TASKS_RELATIVE_DIR,
|
|
6880
7342
|
DEMO_TASKS: () => DEMO_TASKS
|
|
6881
7343
|
});
|
|
6882
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync12, mkdirSync as
|
|
7344
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
|
|
6883
7345
|
import { spawnSync } from "child_process";
|
|
6884
7346
|
import { basename as basename3, resolve as resolve18 } from "path";
|
|
6885
7347
|
import { buildRigInitConfigSource } from "@rig/core";
|
|
@@ -6903,14 +7365,14 @@ function parseRepoSlug(value) {
|
|
|
6903
7365
|
}
|
|
6904
7366
|
function ensureRigPrivateDirs(projectRoot) {
|
|
6905
7367
|
const rigDir = resolve18(projectRoot, ".rig");
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
7368
|
+
mkdirSync9(resolve18(rigDir, "state"), { recursive: true });
|
|
7369
|
+
mkdirSync9(resolve18(rigDir, "logs"), { recursive: true });
|
|
7370
|
+
mkdirSync9(resolve18(rigDir, "runs"), { recursive: true });
|
|
7371
|
+
mkdirSync9(resolve18(rigDir, "tmp"), { recursive: true });
|
|
7372
|
+
mkdirSync9(resolve18(projectRoot, "artifacts"), { recursive: true });
|
|
6911
7373
|
const taskConfigPath = resolve18(rigDir, "task-config.json");
|
|
6912
7374
|
if (!existsSync12(taskConfigPath))
|
|
6913
|
-
|
|
7375
|
+
writeFileSync6(taskConfigPath, `{}
|
|
6914
7376
|
`, "utf-8");
|
|
6915
7377
|
}
|
|
6916
7378
|
function ensureGitignoreEntries(projectRoot) {
|
|
@@ -6938,7 +7400,7 @@ function ensureRigConfigPackageDependencies(projectRoot) {
|
|
|
6938
7400
|
...existsSync12(path) ? existing : { name: "rig-project", private: true },
|
|
6939
7401
|
devDependencies
|
|
6940
7402
|
};
|
|
6941
|
-
|
|
7403
|
+
writeFileSync6(path, `${JSON.stringify(next, null, 2)}
|
|
6942
7404
|
`, "utf8");
|
|
6943
7405
|
}
|
|
6944
7406
|
function applyGitHubProjectConfig(source, options) {
|
|
@@ -6964,9 +7426,9 @@ function checkoutForInit(projectRoot, serverKind, strategy) {
|
|
|
6964
7426
|
const selected = strategy ?? { kind: "managed-clone" };
|
|
6965
7427
|
switch (selected.kind) {
|
|
6966
7428
|
case "managed-clone":
|
|
6967
|
-
return { kind: "managed-clone"
|
|
7429
|
+
return { kind: "managed-clone" };
|
|
6968
7430
|
case "current-ref":
|
|
6969
|
-
return { kind: "current-ref",
|
|
7431
|
+
return { kind: "current-ref", ...selected.ref ? { ref: selected.ref } : {} };
|
|
6970
7432
|
case "uploaded-snapshot":
|
|
6971
7433
|
return { kind: "uploaded-snapshot", path: projectRoot, source: "local-working-tree" };
|
|
6972
7434
|
case "existing-path":
|
|
@@ -7219,7 +7681,7 @@ function remoteGitHubAuthMetadata(payload) {
|
|
|
7219
7681
|
};
|
|
7220
7682
|
}
|
|
7221
7683
|
function writeRemoteGitHubAuthState(projectRoot, input) {
|
|
7222
|
-
|
|
7684
|
+
writeFileSync6(resolve18(projectRoot, ".rig", "state", "github-auth.json"), `${JSON.stringify({
|
|
7223
7685
|
authenticated: true,
|
|
7224
7686
|
source: input.source,
|
|
7225
7687
|
storedOnServer: true,
|
|
@@ -7267,7 +7729,7 @@ function runLocalFilesInit(context, options) {
|
|
|
7267
7729
|
console.log("rig.config already exists; leaving it unchanged. Pass --repair to rewrite it.");
|
|
7268
7730
|
} else {
|
|
7269
7731
|
const projectName = basename3(projectRoot) || "rig-project";
|
|
7270
|
-
|
|
7732
|
+
writeFileSync6(configTsPath, buildRigInitConfigSource({
|
|
7271
7733
|
projectName,
|
|
7272
7734
|
taskSource: { kind: "files", path: "tasks" },
|
|
7273
7735
|
useStandardPlugin: true
|
|
@@ -7276,8 +7738,8 @@ function runLocalFilesInit(context, options) {
|
|
|
7276
7738
|
ensureRigConfigPackageDependencies(projectRoot);
|
|
7277
7739
|
const tasksDir = resolve18(projectRoot, "tasks");
|
|
7278
7740
|
if (!existsSync12(tasksDir)) {
|
|
7279
|
-
|
|
7280
|
-
|
|
7741
|
+
mkdirSync9(tasksDir, { recursive: true });
|
|
7742
|
+
writeFileSync6(resolve18(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)}
|
|
7281
7743
|
`, "utf-8");
|
|
7282
7744
|
}
|
|
7283
7745
|
if (context.outputMode !== "json") {
|
|
@@ -7301,7 +7763,7 @@ function runDemoInit(context, options) {
|
|
|
7301
7763
|
console.log("rig.config already exists; leaving it unchanged. Pass --repair to rewrite it for the demo.");
|
|
7302
7764
|
}
|
|
7303
7765
|
} else {
|
|
7304
|
-
|
|
7766
|
+
writeFileSync6(configTsPath, buildRigInitConfigSource({
|
|
7305
7767
|
projectName: basename3(projectRoot) || "rig-demo",
|
|
7306
7768
|
taskSource: { kind: "files", path: DEMO_TASKS_RELATIVE_DIR },
|
|
7307
7769
|
useStandardPlugin: true
|
|
@@ -7310,14 +7772,14 @@ function runDemoInit(context, options) {
|
|
|
7310
7772
|
}
|
|
7311
7773
|
ensureRigConfigPackageDependencies(projectRoot);
|
|
7312
7774
|
const demoTasksDir = resolve18(projectRoot, DEMO_TASKS_RELATIVE_DIR);
|
|
7313
|
-
|
|
7775
|
+
mkdirSync9(demoTasksDir, { recursive: true });
|
|
7314
7776
|
const taskIds = [];
|
|
7315
7777
|
for (const task of DEMO_TASKS) {
|
|
7316
7778
|
const id = String(task.id);
|
|
7317
7779
|
taskIds.push(id);
|
|
7318
7780
|
const taskPath = resolve18(demoTasksDir, `${id}.json`);
|
|
7319
7781
|
if (!existsSync12(taskPath)) {
|
|
7320
|
-
|
|
7782
|
+
writeFileSync6(taskPath, `${JSON.stringify(task, null, 2)}
|
|
7321
7783
|
`, "utf-8");
|
|
7322
7784
|
}
|
|
7323
7785
|
}
|
|
@@ -7345,21 +7807,32 @@ function runDemoInit(context, options) {
|
|
|
7345
7807
|
}
|
|
7346
7808
|
async function runControlPlaneInit(context, options) {
|
|
7347
7809
|
const projectRoot = context.projectRoot;
|
|
7348
|
-
const
|
|
7810
|
+
const existingRepoConnection = readRepoConnection(projectRoot);
|
|
7811
|
+
const selectedConnection = (() => {
|
|
7812
|
+
try {
|
|
7813
|
+
return resolveSelectedConnection(projectRoot);
|
|
7814
|
+
} catch {
|
|
7815
|
+
return null;
|
|
7816
|
+
}
|
|
7817
|
+
})();
|
|
7818
|
+
const selectedRemote = selectedConnection?.connection.kind === "remote" ? { alias: selectedConnection.alias, connection: selectedConnection.connection } : null;
|
|
7819
|
+
const detectedSlug = options.repoSlug ?? existingRepoConnection?.project ?? detectOriginRepoSlug(projectRoot);
|
|
7820
|
+
const serverKind = options.server ?? (selectedRemote ? "remote" : "local");
|
|
7349
7821
|
if (!detectedSlug) {
|
|
7350
7822
|
const authMethod2 = options.githubAuthMethod ?? (options.githubToken ? "token" : "skip");
|
|
7351
|
-
if (
|
|
7823
|
+
if (serverKind === "local" && authMethod2 === "skip") {
|
|
7352
7824
|
return runLocalFilesInit(context, options);
|
|
7353
7825
|
}
|
|
7354
7826
|
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);
|
|
7355
7827
|
}
|
|
7356
7828
|
const repo = parseRepoSlug(detectedSlug);
|
|
7357
|
-
const
|
|
7358
|
-
const
|
|
7829
|
+
const connectionAlias = options.connectionAlias ?? (serverKind === "local" ? "local" : selectedRemote?.alias ?? "remote");
|
|
7830
|
+
const selectedRemoteUrl = selectedRemote && (!options.connectionAlias || options.connectionAlias === selectedRemote.alias) ? selectedRemote.connection.baseUrl : undefined;
|
|
7831
|
+
const remoteUrl = serverKind === "remote" ? (options.remoteUrl ?? selectedRemoteUrl)?.replace(/\/+$/, "") : undefined;
|
|
7359
7832
|
if (serverKind === "remote") {
|
|
7360
|
-
if (!
|
|
7361
|
-
throw new CliError("Missing --remote-url for --server remote.", 1, { hint: "Re-run as `rig init --server remote --remote-url https://your-rig-server
|
|
7362
|
-
upsertGlobalConnection(connectionAlias, { kind: "remote", baseUrl:
|
|
7833
|
+
if (!remoteUrl)
|
|
7834
|
+
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>`." });
|
|
7835
|
+
upsertGlobalConnection(connectionAlias, { kind: "remote", baseUrl: remoteUrl });
|
|
7363
7836
|
}
|
|
7364
7837
|
writeRepoConnection(projectRoot, {
|
|
7365
7838
|
selected: connectionAlias,
|
|
@@ -7382,11 +7855,11 @@ async function runControlPlaneInit(context, options) {
|
|
|
7382
7855
|
taskSource: { kind: "github-issues", owner: repo.owner, repo: repo.repo },
|
|
7383
7856
|
useStandardPlugin: true
|
|
7384
7857
|
}), options);
|
|
7385
|
-
|
|
7858
|
+
writeFileSync6(configTsPath, source, "utf-8");
|
|
7386
7859
|
}
|
|
7387
7860
|
ensureRigConfigPackageDependencies(projectRoot);
|
|
7388
7861
|
}
|
|
7389
|
-
|
|
7862
|
+
writeFileSync6(resolve18(projectRoot, ".rig", "state", "project-link.json"), `${JSON.stringify({ repoSlug: repo.slug, connection: connectionAlias, linkedAt: new Date().toISOString() }, null, 2)}
|
|
7390
7863
|
`, "utf8");
|
|
7391
7864
|
const checkout = checkoutForInit(projectRoot, serverKind, options.remoteCheckout);
|
|
7392
7865
|
let uploadedSnapshot = null;
|
|
@@ -7401,7 +7874,7 @@ async function runControlPlaneInit(context, options) {
|
|
|
7401
7874
|
let githubAuth = null;
|
|
7402
7875
|
let deviceAuth = null;
|
|
7403
7876
|
const authMethod = options.githubAuthMethod ?? (options.githubToken ? "token" : "skip");
|
|
7404
|
-
const remoteGhTokenWarning = serverKind === "remote" && authMethod === "gh" ? `This sends a GitHub token from this machine to ${
|
|
7877
|
+
const remoteGhTokenWarning = serverKind === "remote" && authMethod === "gh" ? `This sends a GitHub token from this machine to ${remoteUrl ?? "the remote Rig server"}.` : null;
|
|
7405
7878
|
if (remoteGhTokenWarning && !options.yes) {
|
|
7406
7879
|
throw new CliError(`${remoteGhTokenWarning} Re-run with --yes to confirm this explicit token transfer.`, 1);
|
|
7407
7880
|
}
|
|
@@ -7781,8 +8254,8 @@ var init_init = __esm(() => {
|
|
|
7781
8254
|
|
|
7782
8255
|
// packages/cli/src/commands/github.ts
|
|
7783
8256
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
7784
|
-
import { mkdirSync as
|
|
7785
|
-
import { dirname as
|
|
8257
|
+
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync7 } from "fs";
|
|
8258
|
+
import { dirname as dirname5, resolve as resolve19 } from "path";
|
|
7786
8259
|
function printPayload(context, payload, fallback) {
|
|
7787
8260
|
if (context.outputMode === "json")
|
|
7788
8261
|
console.log(JSON.stringify(payload, null, 2));
|
|
@@ -7821,8 +8294,8 @@ function persistRemoteAuthSession(context, source, result, fallbackToken) {
|
|
|
7821
8294
|
return;
|
|
7822
8295
|
const repo = readRepoConnection(context.projectRoot);
|
|
7823
8296
|
const path = resolve19(context.projectRoot, ".rig", "state", "github-auth.json");
|
|
7824
|
-
|
|
7825
|
-
|
|
8297
|
+
mkdirSync10(dirname5(path), { recursive: true });
|
|
8298
|
+
writeFileSync7(path, `${JSON.stringify({
|
|
7826
8299
|
authenticated: true,
|
|
7827
8300
|
source,
|
|
7828
8301
|
storedOnServer: true,
|
|
@@ -9333,7 +9806,7 @@ __export(exports__pi_frontend, {
|
|
|
9333
9806
|
buildOperatorPiEnv: () => buildOperatorPiEnv,
|
|
9334
9807
|
attachRunBundledPiFrontend: () => attachRunBundledPiFrontend
|
|
9335
9808
|
});
|
|
9336
|
-
import { existsSync as existsSync15, mkdirSync as
|
|
9809
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync11, mkdtempSync, readFileSync as readFileSync10, rmSync as rmSync5, writeFileSync as writeFileSync8 } from "fs";
|
|
9337
9810
|
import { homedir as homedir6, tmpdir } from "os";
|
|
9338
9811
|
import { join as join3 } from "path";
|
|
9339
9812
|
import { main as runPiMain } from "@earendil-works/pi-coding-agent";
|
|
@@ -9385,7 +9858,7 @@ function statusFromRunDetails(run) {
|
|
|
9385
9858
|
async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
9386
9859
|
const server = await ensureServerForCli(context.projectRoot);
|
|
9387
9860
|
const localCwd = join3(homedir6(), ".rig", "drones", runId.slice(0, 8));
|
|
9388
|
-
|
|
9861
|
+
mkdirSync11(localCwd, { recursive: true });
|
|
9389
9862
|
trustDroneCwd(localCwd);
|
|
9390
9863
|
installRigPiTheme();
|
|
9391
9864
|
let sessionFileArg = [];
|
|
@@ -9407,7 +9880,7 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
9407
9880
|
return line;
|
|
9408
9881
|
}).join(`
|
|
9409
9882
|
`);
|
|
9410
|
-
|
|
9883
|
+
writeFileSync8(localSessionPath, content);
|
|
9411
9884
|
sessionFileArg = ["--session", localSessionPath];
|
|
9412
9885
|
}
|
|
9413
9886
|
} catch {}
|
|
@@ -9423,12 +9896,12 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
9423
9896
|
function trustDroneCwd(localCwd) {
|
|
9424
9897
|
try {
|
|
9425
9898
|
const agentDir = join3(homedir6(), ".pi", "agent");
|
|
9426
|
-
|
|
9899
|
+
mkdirSync11(agentDir, { recursive: true });
|
|
9427
9900
|
const trustPath = join3(agentDir, "trust.json");
|
|
9428
9901
|
const store = existsSync15(trustPath) ? JSON.parse(readFileSync10(trustPath, "utf8")) : {};
|
|
9429
9902
|
if (store[localCwd] !== true) {
|
|
9430
9903
|
store[localCwd] = true;
|
|
9431
|
-
|
|
9904
|
+
writeFileSync8(trustPath, `${JSON.stringify(store, null, "\t")}
|
|
9432
9905
|
`);
|
|
9433
9906
|
}
|
|
9434
9907
|
} catch {}
|
|
@@ -9436,12 +9909,12 @@ function trustDroneCwd(localCwd) {
|
|
|
9436
9909
|
function installRigPiTheme() {
|
|
9437
9910
|
try {
|
|
9438
9911
|
const themesDir = join3(homedir6(), ".pi", "agent", "themes");
|
|
9439
|
-
|
|
9912
|
+
mkdirSync11(themesDir, { recursive: true });
|
|
9440
9913
|
const themePath = join3(themesDir, "rig.json");
|
|
9441
9914
|
const next = `${JSON.stringify(RIG_PI_THEME, null, "\t")}
|
|
9442
9915
|
`;
|
|
9443
9916
|
if (!existsSync15(themePath) || readFileSync10(themePath, "utf8") !== next) {
|
|
9444
|
-
|
|
9917
|
+
writeFileSync8(themePath, next);
|
|
9445
9918
|
}
|
|
9446
9919
|
} catch {}
|
|
9447
9920
|
}
|
|
@@ -10225,13 +10698,46 @@ function parseConnection(alias, value, options) {
|
|
|
10225
10698
|
}
|
|
10226
10699
|
return { kind: "remote", baseUrl: parsed.toString().replace(/\/+$/, "") };
|
|
10227
10700
|
}
|
|
10228
|
-
function printJsonOrText(context,
|
|
10229
|
-
if (context.outputMode
|
|
10230
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
10231
|
-
} else {
|
|
10701
|
+
function printJsonOrText(context, _payload, text2) {
|
|
10702
|
+
if (context.outputMode !== "json") {
|
|
10232
10703
|
console.log(text2);
|
|
10233
10704
|
}
|
|
10234
10705
|
}
|
|
10706
|
+
function formatRemoteProjectLinkText(result) {
|
|
10707
|
+
return formatSuccessCard(result.ok ? "Remote project link ready" : "Remote project link needs repair", [
|
|
10708
|
+
["selected", result.alias ?? "remote"],
|
|
10709
|
+
["target", result.baseUrl ?? "unknown"],
|
|
10710
|
+
["repo", result.repoSlug ?? "owner/repo"],
|
|
10711
|
+
["status", result.status],
|
|
10712
|
+
...result.serverProjectRoot ? [["server root", result.serverProjectRoot]] : [],
|
|
10713
|
+
["next", result.ok ? result.next ?? "rig task list" : result.hint]
|
|
10714
|
+
]);
|
|
10715
|
+
}
|
|
10716
|
+
function parseRepairLinkArgs(rest, usage) {
|
|
10717
|
+
let repoSlug;
|
|
10718
|
+
let mode = "prepare-if-missing";
|
|
10719
|
+
const pending = [...rest];
|
|
10720
|
+
while (pending.length > 0) {
|
|
10721
|
+
const token = pending.shift();
|
|
10722
|
+
if (token === "--repo") {
|
|
10723
|
+
const value = pending.shift()?.trim();
|
|
10724
|
+
if (!value)
|
|
10725
|
+
throw new CliError(`Missing --repo value. Usage: ${usage}`, 1);
|
|
10726
|
+
const normalized = normalizeRepoSlug(value);
|
|
10727
|
+
if (!normalized)
|
|
10728
|
+
throw new CliError(`Invalid --repo value: ${value}`, 1, { hint: "Use the canonical owner/repo slug, e.g. `--repo humanity-org/humanwork`." });
|
|
10729
|
+
repoSlug = normalized;
|
|
10730
|
+
} else if (token === "--backfill-only") {
|
|
10731
|
+
mode = "backfill-only";
|
|
10732
|
+
} else if (token === "--prepare") {
|
|
10733
|
+
mode = "prepare-if-missing";
|
|
10734
|
+
} else {
|
|
10735
|
+
throw new CliError(`Unexpected argument: ${String(token)}
|
|
10736
|
+
Usage: ${usage}`, 1);
|
|
10737
|
+
}
|
|
10738
|
+
}
|
|
10739
|
+
return { repoSlug, mode };
|
|
10740
|
+
}
|
|
10235
10741
|
async function promptForConnectionAlias(context) {
|
|
10236
10742
|
const state = readGlobalConnections();
|
|
10237
10743
|
const repo = readRepoConnection(context.projectRoot);
|
|
@@ -10285,37 +10791,67 @@ async function executeConnectionCommand(context, args, options) {
|
|
|
10285
10791
|
}
|
|
10286
10792
|
if (!alias)
|
|
10287
10793
|
throw new CliError(`Missing alias. Usage: ${usageName(options)} use <alias|local>`, 1);
|
|
10794
|
+
let selectedConnection = { kind: "local", mode: "auto" };
|
|
10288
10795
|
if (alias !== "local") {
|
|
10289
10796
|
const state = readGlobalConnections();
|
|
10290
|
-
|
|
10797
|
+
const connection = state.connections[alias];
|
|
10798
|
+
if (!connection)
|
|
10291
10799
|
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>`." });
|
|
10800
|
+
selectedConnection = connection;
|
|
10292
10801
|
}
|
|
10293
10802
|
const previousRepo = readRepoConnection(context.projectRoot);
|
|
10803
|
+
const preserveRemoteRoot = Boolean(previousRepo?.serverProjectRoot && previousRepo.selected === alias && selectedConnection.kind === "remote" && previousRepo.serverProjectRootAlias === alias && previousRepo.serverProjectRootBaseUrl === selectedConnection.baseUrl);
|
|
10294
10804
|
const repoState = {
|
|
10295
10805
|
selected: alias,
|
|
10296
10806
|
...previousRepo?.project ? { project: previousRepo.project } : {},
|
|
10297
10807
|
linkedAt: new Date().toISOString(),
|
|
10298
|
-
...
|
|
10808
|
+
...preserveRemoteRoot ? {
|
|
10809
|
+
serverProjectRoot: previousRepo.serverProjectRoot,
|
|
10810
|
+
serverProjectRootAlias: previousRepo.serverProjectRootAlias,
|
|
10811
|
+
serverProjectRootBaseUrl: previousRepo.serverProjectRootBaseUrl
|
|
10812
|
+
} : {}
|
|
10299
10813
|
};
|
|
10300
10814
|
writeRepoConnection(context.projectRoot, repoState);
|
|
10301
|
-
|
|
10815
|
+
const remoteProjectLink = alias !== "local" ? await ensureRemoteProjectRootLink(context.projectRoot, { mode: "backfill-only" }).catch((error) => ({
|
|
10816
|
+
ok: false,
|
|
10817
|
+
status: "error",
|
|
10818
|
+
message: error instanceof Error ? error.message : String(error),
|
|
10819
|
+
hint: "Run `rig server repair-link` after authenticating the selected remote."
|
|
10820
|
+
})) : null;
|
|
10821
|
+
const latestRepo = readRepoConnection(context.projectRoot);
|
|
10822
|
+
const details = { selected: latestRepo?.selected ?? alias, repo: latestRepo, remoteProjectLink };
|
|
10823
|
+
printJsonOrText(context, details, formatSuccessCard("Rig server selected", [
|
|
10302
10824
|
["selected", alias],
|
|
10303
10825
|
["scope", "this repo"],
|
|
10304
|
-
["
|
|
10826
|
+
...remoteProjectLink ? [["remote link", remoteProjectLink.ok ? `ready (${remoteProjectLink.serverProjectRoot ?? "linked"})` : `${remoteProjectLink.status}: ${remoteProjectLink.hint}`]] : [],
|
|
10827
|
+
["next", remoteProjectLink && !remoteProjectLink.ok ? "rig server repair-link" : "rig task list"]
|
|
10305
10828
|
]));
|
|
10306
|
-
return { ok: true, group: options.group, command: "use", details
|
|
10829
|
+
return { ok: true, group: options.group, command: "use", details };
|
|
10830
|
+
}
|
|
10831
|
+
case "repair-link": {
|
|
10832
|
+
const parsed = parseRepairLinkArgs(rest, `${usageName(options)} repair-link [--prepare|--backfill-only] [--repo owner/repo]`);
|
|
10833
|
+
const result = await repairRemoteProjectRootLink(context, parsed);
|
|
10834
|
+
printJsonOrText(context, result, formatRemoteProjectLinkText(result));
|
|
10835
|
+
return { ok: true, group: options.group, command: "repair-link", details: result };
|
|
10307
10836
|
}
|
|
10308
10837
|
case "status": {
|
|
10309
10838
|
requireNoExtraArgs(rest, `${usageName(options)} status`);
|
|
10310
10839
|
const repo = readRepoConnection(context.projectRoot);
|
|
10311
10840
|
const global = readGlobalConnections();
|
|
10312
|
-
const
|
|
10313
|
-
|
|
10841
|
+
const remoteProjectLink = repo?.selected && repo.selected !== "local" ? await ensureRemoteProjectRootLink(context.projectRoot, { mode: "backfill-only" }).catch((error) => ({
|
|
10842
|
+
ok: false,
|
|
10843
|
+
status: "error",
|
|
10844
|
+
message: error instanceof Error ? error.message : String(error),
|
|
10845
|
+
hint: "Run `rig server repair-link` after authenticating the selected remote."
|
|
10846
|
+
})) : null;
|
|
10847
|
+
const latestRepo = readRepoConnection(context.projectRoot) ?? repo;
|
|
10848
|
+
const details = { selected: latestRepo?.selected ?? "local", repo: latestRepo, connections: global.connections, remoteProjectLink };
|
|
10849
|
+
printJsonOrText(context, details, formatConnectionStatus(details.selected, global.connections, latestRepo ?? null, remoteProjectLink));
|
|
10314
10850
|
return { ok: true, group: options.group, command: "status", details };
|
|
10315
10851
|
}
|
|
10316
10852
|
default:
|
|
10317
10853
|
throw new CliError(`Unknown ${options.group} command: ${String(command)}
|
|
10318
|
-
Usage: ${usageName(options)} <list|add|use|status>`, 1);
|
|
10854
|
+
Usage: ${usageName(options)} <list|add|use|status|repair-link>`, 1);
|
|
10319
10855
|
}
|
|
10320
10856
|
}
|
|
10321
10857
|
var init_connect = __esm(() => {
|
|
@@ -10323,13 +10859,14 @@ var init_connect = __esm(() => {
|
|
|
10323
10859
|
init_runner();
|
|
10324
10860
|
init__connection_state();
|
|
10325
10861
|
init__cli_format();
|
|
10862
|
+
init__server_client();
|
|
10326
10863
|
});
|
|
10327
10864
|
|
|
10328
10865
|
// packages/cli/src/commands/server.ts
|
|
10329
10866
|
import { resolveRigServerCommand } from "@rig/runtime/local-server";
|
|
10330
10867
|
async function executeServer(context, args, options) {
|
|
10331
10868
|
const [command = "status", ...rest] = args;
|
|
10332
|
-
if (["status", "list", "add", "use"].includes(command)) {
|
|
10869
|
+
if (["status", "list", "add", "use", "repair-link"].includes(command)) {
|
|
10333
10870
|
return executeConnectionCommand(context, [command, ...rest], { group: "server", interactiveUse: true });
|
|
10334
10871
|
}
|
|
10335
10872
|
switch (command) {
|
|
@@ -11116,7 +11653,7 @@ var init_task = __esm(() => {
|
|
|
11116
11653
|
});
|
|
11117
11654
|
|
|
11118
11655
|
// packages/cli/src/commands/task-run-driver.ts
|
|
11119
|
-
import { copyFileSync as copyFileSync3, existsSync as existsSync16, mkdirSync as
|
|
11656
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync16, mkdirSync as mkdirSync12, readFileSync as readFileSync12, statSync as statSync2, writeFileSync as writeFileSync9 } from "fs";
|
|
11120
11657
|
import { resolve as resolve24 } from "path";
|
|
11121
11658
|
import { spawn as spawn2, spawnSync as spawnSync4 } from "child_process";
|
|
11122
11659
|
import { createInterface as createLineInterface } from "readline";
|
|
@@ -11219,7 +11756,7 @@ function copyUntrackedDirtyFiles(sourceRoot, targetRoot) {
|
|
|
11219
11756
|
try {
|
|
11220
11757
|
if (!statSync2(sourcePath).isFile())
|
|
11221
11758
|
continue;
|
|
11222
|
-
|
|
11759
|
+
mkdirSync12(resolve24(targetPath, ".."), { recursive: true });
|
|
11223
11760
|
copyFileSync3(sourcePath, targetPath);
|
|
11224
11761
|
copied += 1;
|
|
11225
11762
|
} catch {}
|
|
@@ -12090,8 +12627,8 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
12090
12627
|
artifactPath: planningClassification.planningRequired ? planningArtifactPath : null,
|
|
12091
12628
|
classifiedAt: new Date().toISOString()
|
|
12092
12629
|
};
|
|
12093
|
-
|
|
12094
|
-
|
|
12630
|
+
mkdirSync12(resolve24(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
|
|
12631
|
+
writeFileSync9(resolve24(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
|
|
12095
12632
|
`, "utf8");
|
|
12096
12633
|
patchAuthorityRun(context.projectRoot, input.runId, { planning: persistedPlanning });
|
|
12097
12634
|
prompt = `${prompt}
|
|
@@ -12238,8 +12775,8 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
12238
12775
|
const dirty = applyDirtyBaselineSnapshot({ sourceRoot: context.projectRoot, targetRoot: latestRuntimeWorkspace });
|
|
12239
12776
|
const readyFile = childEnv.RIG_DIRTY_BASELINE_READY_FILE;
|
|
12240
12777
|
if (readyFile) {
|
|
12241
|
-
|
|
12242
|
-
|
|
12778
|
+
mkdirSync12(resolve24(readyFile, ".."), { recursive: true });
|
|
12779
|
+
writeFileSync9(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
|
|
12243
12780
|
`, "utf8");
|
|
12244
12781
|
}
|
|
12245
12782
|
appendRunLog(context.projectRoot, input.runId, {
|
|
@@ -13185,7 +13722,7 @@ var init_test = __esm(() => {
|
|
|
13185
13722
|
});
|
|
13186
13723
|
|
|
13187
13724
|
// packages/cli/src/commands/setup.ts
|
|
13188
|
-
import { existsSync as existsSync17, mkdirSync as
|
|
13725
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync13, readdirSync as readdirSync3, writeFileSync as writeFileSync10 } from "fs";
|
|
13189
13726
|
import { resolve as resolve25 } from "path";
|
|
13190
13727
|
import { createPluginHost } from "@rig/core";
|
|
13191
13728
|
import {
|
|
@@ -13240,12 +13777,12 @@ function runSetupInit(projectRoot) {
|
|
|
13240
13777
|
const stateDir = resolveControlPlaneHostStateDir(projectRoot);
|
|
13241
13778
|
const logsDir = resolveControlPlaneHostLogsDir(projectRoot);
|
|
13242
13779
|
const artifactsDir = resolveControlPlaneArtifactsDir(projectRoot);
|
|
13243
|
-
|
|
13244
|
-
|
|
13245
|
-
|
|
13780
|
+
mkdirSync13(stateDir, { recursive: true });
|
|
13781
|
+
mkdirSync13(logsDir, { recursive: true });
|
|
13782
|
+
mkdirSync13(artifactsDir, { recursive: true });
|
|
13246
13783
|
const failuresPath = resolve25(stateDir, "failed_approaches.md");
|
|
13247
13784
|
if (!existsSync17(failuresPath)) {
|
|
13248
|
-
|
|
13785
|
+
writeFileSync10(failuresPath, `# Failed Approaches
|
|
13249
13786
|
|
|
13250
13787
|
`, "utf-8");
|
|
13251
13788
|
}
|
|
@@ -15429,6 +15966,51 @@ var init_selectable = __esm(() => {
|
|
|
15429
15966
|
init_scene();
|
|
15430
15967
|
});
|
|
15431
15968
|
|
|
15969
|
+
// packages/cli/src/app-opentui/remote-link.ts
|
|
15970
|
+
function remoteProjectLinkError(message2) {
|
|
15971
|
+
return /no server-host project root link|remote project(?:-root)? link|x-rig-project-root|serverProjectRoot/i.test(message2 ?? "");
|
|
15972
|
+
}
|
|
15973
|
+
function serverRecordForRemoteLink(state) {
|
|
15974
|
+
const server = state.data.server;
|
|
15975
|
+
return server && typeof server === "object" && !Array.isArray(server) ? server : null;
|
|
15976
|
+
}
|
|
15977
|
+
function remoteProjectLinkState(state) {
|
|
15978
|
+
const serverRecord = serverRecordForRemoteLink(state);
|
|
15979
|
+
if (!serverRecord || serverRecord.kind !== "remote")
|
|
15980
|
+
return null;
|
|
15981
|
+
const link = serverRecord.remoteProjectLink;
|
|
15982
|
+
if (link && typeof link === "object" && !Array.isArray(link))
|
|
15983
|
+
return link;
|
|
15984
|
+
const direct = state.data.remoteProjectLink;
|
|
15985
|
+
if (direct && typeof direct === "object" && !Array.isArray(direct))
|
|
15986
|
+
return direct;
|
|
15987
|
+
return null;
|
|
15988
|
+
}
|
|
15989
|
+
function shouldOfferRemoteLinkRepair(state, message2) {
|
|
15990
|
+
const link = remoteProjectLinkState(state);
|
|
15991
|
+
if (link) {
|
|
15992
|
+
if (link.ok === true)
|
|
15993
|
+
return false;
|
|
15994
|
+
const status = link.status ?? "";
|
|
15995
|
+
return REPAIRABLE_REMOTE_LINK_STATUSES.has(status);
|
|
15996
|
+
}
|
|
15997
|
+
const serverRecord = serverRecordForRemoteLink(state);
|
|
15998
|
+
if (serverRecord && serverRecord.kind !== "remote")
|
|
15999
|
+
return false;
|
|
16000
|
+
return remoteProjectLinkError(message2 ?? state.error?.message);
|
|
16001
|
+
}
|
|
16002
|
+
var REPAIRABLE_REMOTE_LINK_STATUSES;
|
|
16003
|
+
var init_remote_link = __esm(() => {
|
|
16004
|
+
REPAIRABLE_REMOTE_LINK_STATUSES = new Set([
|
|
16005
|
+
"auth_required",
|
|
16006
|
+
"project_not_registered",
|
|
16007
|
+
"no_server_checkout",
|
|
16008
|
+
"invalid_root",
|
|
16009
|
+
"needs_prepare",
|
|
16010
|
+
"error"
|
|
16011
|
+
]);
|
|
16012
|
+
});
|
|
16013
|
+
|
|
15432
16014
|
// packages/cli/src/app-opentui/fleet-stats.ts
|
|
15433
16015
|
function normalizeStatus(status) {
|
|
15434
16016
|
return status.replace(/_/g, "-").toLowerCase();
|
|
@@ -15619,7 +16201,9 @@ import {
|
|
|
15619
16201
|
RigInboxInputsOutput,
|
|
15620
16202
|
RigRunListOutput,
|
|
15621
16203
|
RigRunShowOutput,
|
|
16204
|
+
RigServerRepairLinkOutput,
|
|
15622
16205
|
RigServerStatusOutput,
|
|
16206
|
+
RigServerUseOutput,
|
|
15623
16207
|
RigStatsOutput,
|
|
15624
16208
|
RigTaskListOutput,
|
|
15625
16209
|
RigTaskShowOutput
|
|
@@ -15655,7 +16239,9 @@ var init__json_output = __esm(() => {
|
|
|
15655
16239
|
"task show": RigTaskShowOutput,
|
|
15656
16240
|
"run list": RigRunListOutput,
|
|
15657
16241
|
"run show": RigRunShowOutput,
|
|
16242
|
+
"server use": RigServerUseOutput,
|
|
15658
16243
|
"server status": RigServerStatusOutput,
|
|
16244
|
+
"server repair-link": RigServerRepairLinkOutput,
|
|
15659
16245
|
"inbox approvals": RigInboxApprovalsOutput,
|
|
15660
16246
|
"inbox inputs": RigInboxInputsOutput,
|
|
15661
16247
|
"doctor check": RigDoctorCheckOutput,
|
|
@@ -15986,16 +16572,31 @@ function taskViewIntent(argv, command = "", rest = [], raw) {
|
|
|
15986
16572
|
const { payload, label } = taskViewPayload(command, rest);
|
|
15987
16573
|
return intent("tasks", argv, "refresh", payload, label, raw);
|
|
15988
16574
|
}
|
|
15989
|
-
function routeServer(argv, command, raw, checkingLabel) {
|
|
15990
|
-
if (!command || command === "status") {
|
|
16575
|
+
function routeServer(argv, command, rest, raw, checkingLabel) {
|
|
16576
|
+
if (!command || command === "status" || command === "list") {
|
|
15991
16577
|
return intent("server", argv, "refresh", undefined, command ? checkingLabel : "Loading server", raw);
|
|
15992
16578
|
}
|
|
16579
|
+
if (command === "use") {
|
|
16580
|
+
const alias = firstNonOption(rest);
|
|
16581
|
+
if (alias === "local")
|
|
16582
|
+
return intent("server", argv, "server-use-local", undefined, "Use local server", raw);
|
|
16583
|
+
if (alias)
|
|
16584
|
+
return intent("server", argv, "server-use-remote", { alias }, `Use ${alias}`, raw);
|
|
16585
|
+
return intent("server", argv, "refresh", undefined, "Select a remote alias in Server", raw);
|
|
16586
|
+
}
|
|
16587
|
+
if (command === "add")
|
|
16588
|
+
return intent("server", argv, "server-add-remote", { argv: [...argv] }, "Add remote server", raw);
|
|
16589
|
+
if (command === "repair-link")
|
|
16590
|
+
return intent("server", argv, "remote-link-repair", undefined, "Repair remote link", raw);
|
|
15993
16591
|
return commandRunIntent(argv, raw);
|
|
15994
16592
|
}
|
|
15995
16593
|
function routeGithub(argv, command, rest, raw) {
|
|
15996
16594
|
if (command === "auth" && (rest[0]?.toLowerCase() ?? "status") === "status" && rest.length <= 1) {
|
|
15997
16595
|
return intent("server", argv, "refresh", undefined, "Checking GitHub auth", raw);
|
|
15998
16596
|
}
|
|
16597
|
+
if (command === "auth" && rest[0]?.toLowerCase() === "import-gh" && rest.length <= 1) {
|
|
16598
|
+
return intent("server", argv, "github-auth-import", undefined, "Import GitHub auth", raw);
|
|
16599
|
+
}
|
|
15999
16600
|
return commandRunIntent(argv, raw);
|
|
16000
16601
|
}
|
|
16001
16602
|
function routeDoctor(argv, command, raw) {
|
|
@@ -16044,11 +16645,16 @@ function intentFromArgv(argv) {
|
|
|
16044
16645
|
return commandRunIntent(argv);
|
|
16045
16646
|
}
|
|
16046
16647
|
if (normalizedGroup === "server")
|
|
16047
|
-
return routeServer(argv, normalizedCommand, undefined, "Checking server");
|
|
16648
|
+
return routeServer(argv, normalizedCommand, rest, undefined, "Checking server");
|
|
16048
16649
|
if (normalizedGroup === "github")
|
|
16049
16650
|
return routeGithub(argv, normalizedCommand, rest);
|
|
16050
|
-
if (normalizedGroup === "init")
|
|
16051
|
-
|
|
16651
|
+
if (normalizedGroup === "init") {
|
|
16652
|
+
if (!normalizedCommand)
|
|
16653
|
+
return intent("init", argv, "refresh", undefined, "Open init");
|
|
16654
|
+
if (rest.includes("--yes") || normalizedCommand === "--yes")
|
|
16655
|
+
return intent("init", argv, "init-start", undefined, "Run init");
|
|
16656
|
+
return intent("init", argv, "refresh", undefined, "Open init");
|
|
16657
|
+
}
|
|
16052
16658
|
if (normalizedGroup === "doctor")
|
|
16053
16659
|
return routeDoctor(argv, normalizedCommand);
|
|
16054
16660
|
if (normalizedGroup === "inbox")
|
|
@@ -16111,12 +16717,17 @@ function intentFromTypeBar(value) {
|
|
|
16111
16717
|
return commandRunIntent(parts, value);
|
|
16112
16718
|
return intent("tasks", parts, "refresh", undefined, "Select a task, then press Enter; or use run next", value);
|
|
16113
16719
|
}
|
|
16114
|
-
if (first === "init")
|
|
16115
|
-
|
|
16720
|
+
if (first === "init") {
|
|
16721
|
+
if (!second)
|
|
16722
|
+
return intent("init", parts, "refresh", undefined, "Open init", value);
|
|
16723
|
+
if (parts.includes("--yes"))
|
|
16724
|
+
return intent("init", parts, "init-start", undefined, "Run init", value);
|
|
16725
|
+
return intent("init", parts, "refresh", undefined, "Open init", value);
|
|
16726
|
+
}
|
|
16116
16727
|
if (first === "doctor")
|
|
16117
16728
|
return routeDoctor(parts, second, value);
|
|
16118
16729
|
if (first === "server")
|
|
16119
|
-
return routeServer(parts, second, value, "Loading server");
|
|
16730
|
+
return routeServer(parts, second, rest, value, "Loading server");
|
|
16120
16731
|
if (first === "github")
|
|
16121
16732
|
return routeGithub(parts, second, rest, value);
|
|
16122
16733
|
if (first === "inbox")
|
|
@@ -16559,12 +17170,6 @@ var init_autocomplete = __esm(() => {
|
|
|
16559
17170
|
NAV_VERBS = ["runs", "tasks", "inbox", "server", "doctor", "help", "init", "main"];
|
|
16560
17171
|
});
|
|
16561
17172
|
|
|
16562
|
-
// packages/cli/src/app-opentui/pi-pty-host.ts
|
|
16563
|
-
function getActivePiHost() {
|
|
16564
|
-
return null;
|
|
16565
|
-
}
|
|
16566
|
-
function stopActivePiHost(_reason) {}
|
|
16567
|
-
|
|
16568
17173
|
// packages/cli/src/app-opentui/keymap.ts
|
|
16569
17174
|
function clearTypeBar(context, message2) {
|
|
16570
17175
|
const typeBar = context.getTypeBar();
|
|
@@ -16573,22 +17178,15 @@ function clearTypeBar(context, message2) {
|
|
|
16573
17178
|
context.emitTypeBarPatch({ value: "", mode: "nav", prompt: undefined, message: message2 });
|
|
16574
17179
|
}
|
|
16575
17180
|
function handleEmbeddedTerminalKey(context, key) {
|
|
16576
|
-
|
|
16577
|
-
|
|
16578
|
-
const
|
|
16579
|
-
const host = state.scene === "handoff" ? piHost : state.scene === "command" ? commandHost : null;
|
|
17181
|
+
if (context.getState().scene !== "command")
|
|
17182
|
+
return false;
|
|
17183
|
+
const host = getActiveCommandHost();
|
|
16580
17184
|
if (!host)
|
|
16581
17185
|
return false;
|
|
16582
17186
|
if (key.ctrl && key.name === "]") {
|
|
16583
|
-
|
|
16584
|
-
|
|
16585
|
-
|
|
16586
|
-
context.runAppAction("Opening runs", () => context.runtime.runIntent({ scene: "fleet", argv: ["runs"], action: { kind: "refresh", label: "Opening runs" } }));
|
|
16587
|
-
} else {
|
|
16588
|
-
stopActiveCommandHost("operator detach");
|
|
16589
|
-
clearTypeBar(context, "closed command");
|
|
16590
|
-
context.runAppAction("Project menu", () => context.runtime.runIntent({ scene: "main", argv: ["main"], action: { kind: "none", label: "Project menu" } }));
|
|
16591
|
-
}
|
|
17187
|
+
stopActiveCommandHost("operator detach");
|
|
17188
|
+
clearTypeBar(context, "closed command");
|
|
17189
|
+
context.runAppAction("Project menu", () => context.runtime.runIntent({ scene: "main", argv: ["main"], action: { kind: "none", label: "Project menu" } }));
|
|
16592
17190
|
return true;
|
|
16593
17191
|
}
|
|
16594
17192
|
const sequence = key.raw || key.sequence;
|
|
@@ -18097,10 +18695,14 @@ var init_preloader = __esm(() => {
|
|
|
18097
18695
|
});
|
|
18098
18696
|
|
|
18099
18697
|
// packages/cli/src/app-opentui/scenes/error.ts
|
|
18698
|
+
function errorActions(state) {
|
|
18699
|
+
return shouldOfferRemoteLinkRepair(state, state.error?.message) ? [...ERROR_ACTIONS, ERROR_REPAIR_LINK_ACTION] : ERROR_ACTIONS;
|
|
18700
|
+
}
|
|
18100
18701
|
function renderErrorScene(state) {
|
|
18101
18702
|
const message2 = state.error?.message ?? "Unknown app error";
|
|
18102
18703
|
const hint = state.error?.hint ?? "Use the actions below to recover.";
|
|
18103
|
-
const
|
|
18704
|
+
const actions = errorActions(state);
|
|
18705
|
+
const selected = Math.max(0, Math.min(actions.length - 1, state.selection.index));
|
|
18104
18706
|
return makeSceneFrame({
|
|
18105
18707
|
scene: "error",
|
|
18106
18708
|
title: "Error",
|
|
@@ -18118,7 +18720,7 @@ function renderErrorScene(state) {
|
|
|
18118
18720
|
...hint ? [line(hint, { fg: RIG_UI.yellow })] : [],
|
|
18119
18721
|
line("", { fg: RIG_UI.ink3 }),
|
|
18120
18722
|
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
18121
|
-
...
|
|
18723
|
+
...actions.map(({ detail, item }, index) => selectableDeckRow({ label: item.label, detail, index, active: selected === index }, item))
|
|
18122
18724
|
],
|
|
18123
18725
|
backgroundColor: RIG_UI.panel,
|
|
18124
18726
|
backgroundAlpha: 184,
|
|
@@ -18135,18 +18737,19 @@ function renderErrorScene(state) {
|
|
|
18135
18737
|
live: true
|
|
18136
18738
|
});
|
|
18137
18739
|
}
|
|
18138
|
-
var ERROR_ACTIONS;
|
|
18740
|
+
var ERROR_ACTIONS, ERROR_REPAIR_LINK_ACTION;
|
|
18139
18741
|
var init_error = __esm(() => {
|
|
18140
18742
|
init_drone();
|
|
18141
18743
|
init_theme2();
|
|
18744
|
+
init_remote_link();
|
|
18142
18745
|
init_scene();
|
|
18143
18746
|
init_selectable();
|
|
18144
18747
|
ERROR_ACTIONS = [
|
|
18145
18748
|
{ detail: "return to dashboard", item: { id: "main", label: "main", intent: { scene: "main", argv: [], action: { kind: "refresh", label: "Back to dashboard" } }, message: "back to dashboard" } },
|
|
18146
18749
|
{ detail: "run diagnostics", item: { id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "run diagnostics" } },
|
|
18147
|
-
{ 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" } }
|
|
18148
|
-
{ detail: "repair project/server/auth link", item: { id: "repair", label: "repair", intent: { scene: "command", argv: ["init", "--repair"], action: { kind: "command-run", label: "Repair project link" } }, message: "repair project link" } }
|
|
18750
|
+
{ 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" } }
|
|
18149
18751
|
];
|
|
18752
|
+
ERROR_REPAIR_LINK_ACTION = { detail: "backfill or prepare selected remote project-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", payload: { returnScene: "server" } } }, message: "repair remote project link" } };
|
|
18150
18753
|
});
|
|
18151
18754
|
|
|
18152
18755
|
// packages/cli/src/app-opentui/scenes/help.ts
|
|
@@ -18321,7 +18924,7 @@ function configuredMenuRows(selectedIndex2) {
|
|
|
18321
18924
|
}));
|
|
18322
18925
|
}
|
|
18323
18926
|
function onboardingRows(selectedIndex2) {
|
|
18324
|
-
const primary = selectableDeckRow({ label: "
|
|
18927
|
+
const primary = selectableDeckRow({ label: "init", detail: "Start guided init \u2014 recommended", active: selectedIndex2 === 0 }, ONBOARD_PRIMARY);
|
|
18325
18928
|
const secondary = ONBOARD_SECONDARY.map(([label, detail, item], index) => ({
|
|
18326
18929
|
...deckRow({ label, detail, index: index + 1, active: selectedIndex2 === index + 1, activateOnClick: true }),
|
|
18327
18930
|
selectable: item
|
|
@@ -18381,7 +18984,7 @@ function renderMainScene(state, layout) {
|
|
|
18381
18984
|
statusLine(state)
|
|
18382
18985
|
] : [
|
|
18383
18986
|
line("WELCOME", { fg: RIG_UI.ink, bold: true }),
|
|
18384
|
-
line("This project isn't
|
|
18987
|
+
line("This project isn't initialized yet. One native init flow gets you running.", { fg: RIG_UI.ink2 }),
|
|
18385
18988
|
blank(),
|
|
18386
18989
|
line("GET STARTED", { fg: RIG_UI.ink, bold: true }),
|
|
18387
18990
|
...onboardingRows(actionSelected),
|
|
@@ -18422,7 +19025,7 @@ var init_main = __esm(() => {
|
|
|
18422
19025
|
init_theme2();
|
|
18423
19026
|
init_fleet_stats();
|
|
18424
19027
|
CONFIGURED_MENU = [
|
|
18425
|
-
["init", "setup, reconfigure, repair project state", { id: "init", label: "init", intent: { scene: "
|
|
19028
|
+
["init", "guided setup, reconfigure, repair project state", { id: "init", label: "init", intent: { scene: "init", argv: ["init"], action: { kind: "refresh", label: "Open init" } }, message: "open native init flow" }],
|
|
18426
19029
|
["server", "local/remote target, auth, linkage", { id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Checking server" } }, message: "check selected server" }],
|
|
18427
19030
|
["github", "auth, selected repo, stored token", { id: "github", label: "github", intent: { scene: "server", argv: ["github", "auth", "status"], action: { kind: "refresh", label: "Checking GitHub auth" } }, message: "check GitHub auth" }],
|
|
18428
19031
|
["tasks", "browse, filter, dispatch, attach active work", { id: "tasks", label: "tasks", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Opening tasks" } }, message: "selected tasks" }],
|
|
@@ -18441,10 +19044,10 @@ var init_main = __esm(() => {
|
|
|
18441
19044
|
["help", "all actions, shortcuts, mouse controls", { id: "help", label: "help", intent: { scene: "help", argv: ["help"], action: { kind: "none", label: "Opening help" } }, message: "selected help" }]
|
|
18442
19045
|
];
|
|
18443
19046
|
ONBOARD_PRIMARY = {
|
|
18444
|
-
id: "onboard-
|
|
18445
|
-
label: "Start guided
|
|
18446
|
-
intent: { scene: "init", argv: ["init"], action: { kind: "refresh", label: "
|
|
18447
|
-
message: "open the
|
|
19047
|
+
id: "onboard-init",
|
|
19048
|
+
label: "Start guided init",
|
|
19049
|
+
intent: { scene: "init", argv: ["init"], action: { kind: "refresh", label: "Init" } },
|
|
19050
|
+
message: "open the native init checklist"
|
|
18448
19051
|
};
|
|
18449
19052
|
ONBOARD_SECONDARY = [
|
|
18450
19053
|
["server", "select a local or remote target", { id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Checking server" } }, message: "check selected server" }],
|
|
@@ -18457,6 +19060,12 @@ var init_main = __esm(() => {
|
|
|
18457
19060
|
TILE_TASKS = { id: "tile-tasks", label: "tasks", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Opening tasks" } }, message: "ready tasks \u2014 dispatch work" };
|
|
18458
19061
|
});
|
|
18459
19062
|
|
|
19063
|
+
// packages/cli/src/app-opentui/pi-pty-host.ts
|
|
19064
|
+
function getActivePiHost() {
|
|
19065
|
+
return null;
|
|
19066
|
+
}
|
|
19067
|
+
function stopActivePiHost(_reason) {}
|
|
19068
|
+
|
|
18460
19069
|
// packages/cli/src/app-opentui/runtime.ts
|
|
18461
19070
|
var exports_runtime = {};
|
|
18462
19071
|
__export(exports_runtime, {
|
|
@@ -18523,7 +19132,7 @@ function entryIntentForScene(scene) {
|
|
|
18523
19132
|
case "doctor":
|
|
18524
19133
|
return { scene, argv: ["doctor"], action: { kind: "doctor-run", label: "Doctor" } };
|
|
18525
19134
|
case "init":
|
|
18526
|
-
return { scene, argv: ["init"], action: { kind: "refresh", label: "
|
|
19135
|
+
return { scene, argv: ["init"], action: { kind: "refresh", label: "Init" } };
|
|
18527
19136
|
case "run-detail":
|
|
18528
19137
|
return { scene, argv: ["run", "status"], action: { kind: "refresh", label: "Run" } };
|
|
18529
19138
|
case "pi":
|
|
@@ -18612,7 +19221,7 @@ function sceneSectionLabel(scene) {
|
|
|
18612
19221
|
handoff: "pi console",
|
|
18613
19222
|
server: "server",
|
|
18614
19223
|
doctor: "doctor",
|
|
18615
|
-
init: "
|
|
19224
|
+
init: "init",
|
|
18616
19225
|
pi: "pi",
|
|
18617
19226
|
plugin: "plugins",
|
|
18618
19227
|
repo: "repo",
|
|
@@ -19102,7 +19711,7 @@ async function launchRigOpenTuiApp(options) {
|
|
|
19102
19711
|
}
|
|
19103
19712
|
for (const adapter of options.adapters ?? [])
|
|
19104
19713
|
await adapter.start?.(runtime);
|
|
19105
|
-
|
|
19714
|
+
connectRigServerEvents(options.projectRoot, {
|
|
19106
19715
|
onSnapshotInvalidated: () => refreshCurrentDataScene(),
|
|
19107
19716
|
onRunLogAppended: () => {
|
|
19108
19717
|
const scene = store.getState().scene;
|
|
@@ -19110,11 +19719,17 @@ async function launchRigOpenTuiApp(options) {
|
|
|
19110
19719
|
refreshCurrentDataScene();
|
|
19111
19720
|
},
|
|
19112
19721
|
onStatus: (status) => store.patch({ footer: { live: liveLinkLabel(status) } })
|
|
19113
|
-
}).
|
|
19114
|
-
|
|
19115
|
-
|
|
19116
|
-
|
|
19722
|
+
}).then((subscription) => {
|
|
19723
|
+
if (destroyed) {
|
|
19724
|
+
subscription.close();
|
|
19725
|
+
return;
|
|
19726
|
+
}
|
|
19727
|
+
liveEvents = subscription;
|
|
19117
19728
|
resources.add(() => liveEvents?.close());
|
|
19729
|
+
}).catch(() => {
|
|
19730
|
+
if (!destroyed)
|
|
19731
|
+
store.patch({ footer: { live: liveLinkLabel("disconnected") } });
|
|
19732
|
+
});
|
|
19118
19733
|
await runtime.runIntent(store.getState().intent);
|
|
19119
19734
|
} catch (error) {
|
|
19120
19735
|
const normalized = normalizeError(error);
|
|
@@ -19307,7 +19922,7 @@ var init_runtime = __esm(() => {
|
|
|
19307
19922
|
{ id: "tasks", label: "Tasks", scene: "tasks", argv: ["tasks"], enterLabel: "Tasks", member: ["tasks"] },
|
|
19308
19923
|
{ id: "inbox", label: "Inbox", scene: "inbox", argv: ["inbox"], enterLabel: "Inbox", member: ["inbox"], badge: inboxPendingCount },
|
|
19309
19924
|
{ id: "stats", label: "Stats", scene: "family", argv: ["stats"], enterLabel: "Stats", member: ["family"] },
|
|
19310
|
-
{ id: "
|
|
19925
|
+
{ id: "init", label: "Init", scene: "init", argv: ["init"], enterLabel: "Init", member: ["init", "doctor", "server", "pi", "plugin", "repo", "workspace"] },
|
|
19311
19926
|
{ id: "help", label: "Help", scene: "help", argv: ["help"], enterLabel: "Help", member: ["help"] }
|
|
19312
19927
|
];
|
|
19313
19928
|
SCENE_DATA_KEY = {
|
|
@@ -19671,7 +20286,7 @@ var init_nav = __esm(() => {
|
|
|
19671
20286
|
{ id: "tasks", label: "Tasks", scene: "tasks", argv: ["tasks"], enterLabel: "Tasks", member: ["tasks"] },
|
|
19672
20287
|
{ id: "inbox", label: "Inbox", scene: "inbox", argv: ["inbox"], enterLabel: "Inbox", member: ["inbox"], badge: inboxPendingCount2 },
|
|
19673
20288
|
{ id: "stats", label: "Stats", scene: "family", argv: ["stats"], enterLabel: "Stats", member: ["family"] },
|
|
19674
|
-
{ id: "
|
|
20289
|
+
{ id: "init", label: "Init", scene: "init", argv: ["init"], enterLabel: "Init", member: ["init", "doctor", "server", "pi", "plugin", "repo", "workspace"] },
|
|
19675
20290
|
{ id: "help", label: "Help", scene: "help", argv: ["help"], enterLabel: "Help", member: ["help"] }
|
|
19676
20291
|
];
|
|
19677
20292
|
});
|
|
@@ -19937,7 +20552,7 @@ async function launchRigReactApp(options) {
|
|
|
19937
20552
|
}
|
|
19938
20553
|
for (const adapter of options.adapters ?? [])
|
|
19939
20554
|
await adapter.start?.(runtime);
|
|
19940
|
-
|
|
20555
|
+
connectRigServerEvents(options.projectRoot, {
|
|
19941
20556
|
onSnapshotInvalidated: () => refreshCurrentDataScene(),
|
|
19942
20557
|
onRunLogAppended: () => {
|
|
19943
20558
|
const scene = store.getState().scene;
|
|
@@ -19945,9 +20560,11 @@ async function launchRigReactApp(options) {
|
|
|
19945
20560
|
refreshCurrentDataScene();
|
|
19946
20561
|
},
|
|
19947
20562
|
onStatus: (status) => store.patch({ footer: { live: liveLinkLabel(status) } })
|
|
19948
|
-
}).
|
|
19949
|
-
|
|
20563
|
+
}).then((subscription) => {
|
|
20564
|
+
liveEvents = subscription;
|
|
20565
|
+
}).catch(() => {
|
|
19950
20566
|
store.patch({ footer: { live: liveLinkLabel("disconnected") } });
|
|
20567
|
+
});
|
|
19951
20568
|
await runtime.runIntent(store.getState().intent);
|
|
19952
20569
|
} catch (error) {
|
|
19953
20570
|
const n = normalizeError(error);
|
|
@@ -21108,6 +21725,7 @@ async function stopRunFromDetail(ctx, runId) {
|
|
|
21108
21725
|
}
|
|
21109
21726
|
|
|
21110
21727
|
// packages/cli/src/app-opentui/adapters/server.ts
|
|
21728
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
21111
21729
|
var SERVER_PROBE_TIMEOUT_MS = Number(process.env.RIG_SERVER_PROBE_TIMEOUT_MS) || 5000;
|
|
21112
21730
|
function withTimeout(promise, ms, label) {
|
|
21113
21731
|
return new Promise((resolve29, reject) => {
|
|
@@ -21145,11 +21763,128 @@ function startLocalRequested(ctx) {
|
|
|
21145
21763
|
const action = intent.action;
|
|
21146
21764
|
return action?.payload?.startLocal === true;
|
|
21147
21765
|
}
|
|
21766
|
+
async function serverAliases(projectRoot) {
|
|
21767
|
+
const { readGlobalConnections: readGlobalConnections2, readRepoConnection: readRepoConnection2 } = await Promise.resolve().then(() => (init__connection_state(), exports__connection_state));
|
|
21768
|
+
const selected = readRepoConnection2(projectRoot)?.selected ?? "local";
|
|
21769
|
+
const global = readGlobalConnections2();
|
|
21770
|
+
const aliases = [{ alias: "local", kind: "local", selected: selected === "local" }];
|
|
21771
|
+
for (const [alias, connection] of Object.entries(global.connections)) {
|
|
21772
|
+
aliases.push({
|
|
21773
|
+
alias,
|
|
21774
|
+
kind: connection.kind,
|
|
21775
|
+
...connection.kind === "remote" ? { baseUrl: connection.baseUrl } : {},
|
|
21776
|
+
selected: alias === selected
|
|
21777
|
+
});
|
|
21778
|
+
}
|
|
21779
|
+
return aliases;
|
|
21780
|
+
}
|
|
21781
|
+
function firstString2(parts, offset = 0) {
|
|
21782
|
+
return parts.slice(offset).find((part) => part.trim() && !part.startsWith("-"))?.trim();
|
|
21783
|
+
}
|
|
21784
|
+
function normalizeUrl(value) {
|
|
21785
|
+
const trimmed = value?.trim().replace(/\/+$/, "");
|
|
21786
|
+
if (!trimmed)
|
|
21787
|
+
return;
|
|
21788
|
+
return /^https?:\/\//i.test(trimmed) ? trimmed : undefined;
|
|
21789
|
+
}
|
|
21790
|
+
async function useLocalServerFromApp(ctx) {
|
|
21791
|
+
const label = "Selecting local server";
|
|
21792
|
+
emitStarted(ctx, label);
|
|
21793
|
+
try {
|
|
21794
|
+
const projectRoot = projectRootOf(ctx);
|
|
21795
|
+
const { readRepoConnection: readRepoConnection2, writeRepoConnection: writeRepoConnection2 } = await Promise.resolve().then(() => (init__connection_state(), exports__connection_state));
|
|
21796
|
+
const previous = readRepoConnection2(projectRoot);
|
|
21797
|
+
writeRepoConnection2(projectRoot, {
|
|
21798
|
+
selected: "local",
|
|
21799
|
+
...previous?.project ? { project: previous.project } : {},
|
|
21800
|
+
linkedAt: new Date().toISOString()
|
|
21801
|
+
});
|
|
21802
|
+
emitCompleted(ctx, label, { selected: "local" });
|
|
21803
|
+
return refreshServerStatus(ctx);
|
|
21804
|
+
} catch (error) {
|
|
21805
|
+
emitFailed(ctx, label, error);
|
|
21806
|
+
throw error;
|
|
21807
|
+
}
|
|
21808
|
+
}
|
|
21809
|
+
async function useRemoteServerFromApp(ctx, alias) {
|
|
21810
|
+
const label = alias ? `Selecting remote ${alias}` : "Selecting remote server";
|
|
21811
|
+
emitStarted(ctx, label);
|
|
21812
|
+
try {
|
|
21813
|
+
const cleanAlias = alias?.trim();
|
|
21814
|
+
if (!cleanAlias)
|
|
21815
|
+
throw new Error("Enter a saved remote alias, or add one with: add remote \u2192 <alias> <https-url>.");
|
|
21816
|
+
const projectRoot = projectRootOf(ctx);
|
|
21817
|
+
const { readGlobalConnections: readGlobalConnections2, readRepoConnection: readRepoConnection2, writeRepoConnection: writeRepoConnection2 } = await Promise.resolve().then(() => (init__connection_state(), exports__connection_state));
|
|
21818
|
+
const connection = readGlobalConnections2().connections[cleanAlias];
|
|
21819
|
+
if (!connection)
|
|
21820
|
+
throw new Error(`Remote alias ${cleanAlias} is not saved yet. Use add remote first.`);
|
|
21821
|
+
if (connection.kind !== "remote")
|
|
21822
|
+
throw new Error(`${cleanAlias} is not a remote server alias.`);
|
|
21823
|
+
const previous = readRepoConnection2(projectRoot);
|
|
21824
|
+
writeRepoConnection2(projectRoot, {
|
|
21825
|
+
selected: cleanAlias,
|
|
21826
|
+
...previous?.project ? { project: previous.project } : {},
|
|
21827
|
+
linkedAt: new Date().toISOString()
|
|
21828
|
+
});
|
|
21829
|
+
emitCompleted(ctx, label, { selected: cleanAlias, baseUrl: connection.baseUrl });
|
|
21830
|
+
return refreshServerStatus(ctx);
|
|
21831
|
+
} catch (error) {
|
|
21832
|
+
emitFailed(ctx, label, error);
|
|
21833
|
+
throw error;
|
|
21834
|
+
}
|
|
21835
|
+
}
|
|
21836
|
+
async function addRemoteServerFromApp(ctx, args) {
|
|
21837
|
+
const label = "Adding remote server";
|
|
21838
|
+
emitStarted(ctx, label);
|
|
21839
|
+
try {
|
|
21840
|
+
const alias = firstString2(args, 2);
|
|
21841
|
+
const url = normalizeUrl(firstString2(args, alias ? args.indexOf(alias) + 1 : 3));
|
|
21842
|
+
if (!alias || !url)
|
|
21843
|
+
throw new Error("Add remote expects: <alias> <https-url>. Example: prod https://rig.example.com");
|
|
21844
|
+
const projectRoot = projectRootOf(ctx);
|
|
21845
|
+
const { readRepoConnection: readRepoConnection2, upsertGlobalConnection: upsertGlobalConnection2, writeRepoConnection: writeRepoConnection2 } = await Promise.resolve().then(() => (init__connection_state(), exports__connection_state));
|
|
21846
|
+
upsertGlobalConnection2(alias, { kind: "remote", baseUrl: url });
|
|
21847
|
+
const previous = readRepoConnection2(projectRoot);
|
|
21848
|
+
writeRepoConnection2(projectRoot, {
|
|
21849
|
+
selected: alias,
|
|
21850
|
+
...previous?.project ? { project: previous.project } : {},
|
|
21851
|
+
linkedAt: new Date().toISOString()
|
|
21852
|
+
});
|
|
21853
|
+
emitCompleted(ctx, label, { alias, baseUrl: url });
|
|
21854
|
+
return refreshServerStatus(ctx);
|
|
21855
|
+
} catch (error) {
|
|
21856
|
+
emitFailed(ctx, label, error);
|
|
21857
|
+
throw error;
|
|
21858
|
+
}
|
|
21859
|
+
}
|
|
21860
|
+
async function importGitHubAuthFromGhApp(ctx) {
|
|
21861
|
+
const label = "Importing GitHub auth";
|
|
21862
|
+
emitStarted(ctx, label);
|
|
21863
|
+
try {
|
|
21864
|
+
const projectRoot = projectRootOf(ctx);
|
|
21865
|
+
const token = spawnSync5("gh", ["auth", "token"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 1e4 }).stdout.trim();
|
|
21866
|
+
if (!token)
|
|
21867
|
+
throw new Error("Could not read GitHub token from gh. Sign in with gh auth login, then retry import auth.");
|
|
21868
|
+
const runtime = await runtimeOf(ctx);
|
|
21869
|
+
const { postGitHubTokenViaServer: postGitHubTokenViaServer2, setGitHubBearerTokenForCurrentProcess: setGitHubBearerTokenForCurrentProcess2 } = await Promise.resolve().then(() => (init__server_client(), exports__server_client));
|
|
21870
|
+
const { readRepoConnection: readRepoConnection2 } = await Promise.resolve().then(() => (init__connection_state(), exports__connection_state));
|
|
21871
|
+
const selectedRepo = readRepoConnection2(projectRoot)?.project;
|
|
21872
|
+
const payload = await postGitHubTokenViaServer2(runtime, token, selectedRepo ? { selectedRepo } : {});
|
|
21873
|
+
const apiSessionToken = payload && typeof payload === "object" && !Array.isArray(payload) ? payload.apiSessionToken : undefined;
|
|
21874
|
+
setGitHubBearerTokenForCurrentProcess2(typeof apiSessionToken === "string" ? apiSessionToken : token, projectRoot);
|
|
21875
|
+
emitCompleted(ctx, label, { selectedRepo: selectedRepo ?? null });
|
|
21876
|
+
return refreshServerStatus(ctx);
|
|
21877
|
+
} catch (error) {
|
|
21878
|
+
emitFailed(ctx, label, error);
|
|
21879
|
+
throw error;
|
|
21880
|
+
}
|
|
21881
|
+
}
|
|
21148
21882
|
async function startLocalServerFromApp(ctx) {
|
|
21149
21883
|
const label = "Starting local server";
|
|
21150
21884
|
emitStarted(ctx, label);
|
|
21151
21885
|
patchData(ctx, {
|
|
21152
21886
|
lastIntent: undefined,
|
|
21887
|
+
remoteProjectLink: undefined,
|
|
21153
21888
|
server: { label: "starting local server", reachable: false, error: "spawning local rig-server (detached)\u2026" }
|
|
21154
21889
|
});
|
|
21155
21890
|
try {
|
|
@@ -21174,32 +21909,61 @@ async function startLocalServerFromApp(ctx) {
|
|
|
21174
21909
|
reachable: false,
|
|
21175
21910
|
error: error instanceof Error ? error.message : String(error)
|
|
21176
21911
|
};
|
|
21177
|
-
patchData(ctx, { server: state, lastRefreshError: state.error });
|
|
21912
|
+
patchData(ctx, { server: state, remoteProjectLink: undefined, lastRefreshError: state.error });
|
|
21178
21913
|
patchFooter(ctx, { server: "unavailable" });
|
|
21179
|
-
emitCompleted(ctx, label, {
|
|
21914
|
+
emitCompleted(ctx, label, { serverLabel: state.label, reachable: false, error: state.error });
|
|
21180
21915
|
return state;
|
|
21181
21916
|
}
|
|
21182
21917
|
}
|
|
21918
|
+
async function repairRemoteProjectRootLinkFromApp(ctx) {
|
|
21919
|
+
const label = "Repairing remote project link";
|
|
21920
|
+
emitStarted(ctx, label);
|
|
21921
|
+
try {
|
|
21922
|
+
const projectRoot = projectRootOf(ctx);
|
|
21923
|
+
const { ensureRemoteProjectRootLink: ensureRemoteProjectRootLink2 } = await Promise.resolve().then(() => (init__server_client(), exports__server_client));
|
|
21924
|
+
emitProgress(ctx, label, "backfilling or preparing server-host checkout");
|
|
21925
|
+
const result = await ensureRemoteProjectRootLink2(projectRoot, { mode: "prepare-if-missing" });
|
|
21926
|
+
patchData(ctx, { remoteProjectLink: result, server: { label: result.alias ?? "remote", baseUrl: result.baseUrl, kind: "remote", reachable: result.status !== "not_remote", remoteProjectLink: result } });
|
|
21927
|
+
patchFooter(ctx, { server: result.alias ?? "remote", message: `remote link ${result.status}` });
|
|
21928
|
+
if (!result.ok) {
|
|
21929
|
+
const error = new Error(result.message);
|
|
21930
|
+
error.hint = result.hint;
|
|
21931
|
+
patchData(ctx, { lastRefreshError: result.message });
|
|
21932
|
+
throw error;
|
|
21933
|
+
}
|
|
21934
|
+
emitCompleted(ctx, label, { repoSlug: result.repoSlug, serverProjectRoot: result.serverProjectRoot, status: result.status });
|
|
21935
|
+
return result;
|
|
21936
|
+
} catch (error) {
|
|
21937
|
+
const message2 = error instanceof Error ? error.message : String(error);
|
|
21938
|
+
const existing = ctx.getState().data?.remoteProjectLink;
|
|
21939
|
+
const remoteProjectLink = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : { ok: false, status: "error", message: message2 };
|
|
21940
|
+
patchData(ctx, { lastRefreshError: message2, remoteProjectLink });
|
|
21941
|
+
emitCompleted(ctx, label, { ok: false, error: message2, remoteProjectLink });
|
|
21942
|
+
throw error;
|
|
21943
|
+
}
|
|
21944
|
+
}
|
|
21183
21945
|
async function refreshServerStatus(ctx) {
|
|
21184
21946
|
if (startLocalRequested(ctx)) {
|
|
21185
21947
|
return startLocalServerFromApp(ctx);
|
|
21186
21948
|
}
|
|
21187
21949
|
const label = "Checking server";
|
|
21188
21950
|
emitStarted(ctx, label);
|
|
21189
|
-
patchData(ctx, { server: { label: "checking selected server", reachable: false, error: "checking selected server\u2026" } });
|
|
21951
|
+
patchData(ctx, { server: { label: "checking selected server", reachable: false, error: "checking selected server\u2026" }, remoteProjectLink: undefined });
|
|
21190
21952
|
const started = Date.now();
|
|
21191
21953
|
try {
|
|
21192
|
-
const { ensureServerForCli: ensureServerForCli2, requestServerJson: requestServerJson2, resolveServerConnectionLabel: resolveServerConnectionLabel2 } = await Promise.resolve().then(() => (init__server_client(), exports__server_client));
|
|
21954
|
+
const { ensureRemoteProjectRootLink: ensureRemoteProjectRootLink2, ensureServerForCli: ensureServerForCli2, requestServerJson: requestServerJson2, resolveServerConnectionLabel: resolveServerConnectionLabel2 } = await Promise.resolve().then(() => (init__server_client(), exports__server_client));
|
|
21193
21955
|
const projectRoot = projectRootOf(ctx);
|
|
21956
|
+
const aliases = await serverAliases(projectRoot);
|
|
21194
21957
|
emitProgress(ctx, label, "resolving selected server");
|
|
21195
21958
|
const [connectionLabel, server] = await Promise.all([
|
|
21196
21959
|
resolveServerConnectionLabel2(projectRoot),
|
|
21197
21960
|
withTimeout(ensureServerForCli2(projectRoot), 5000, "server connection")
|
|
21198
21961
|
]);
|
|
21199
21962
|
emitProgress(ctx, label, "requesting server status", { baseUrl: server.baseUrl, kind: server.connectionKind });
|
|
21200
|
-
const [status, auth] = await Promise.all([
|
|
21963
|
+
const [status, auth, remoteProjectLink] = await Promise.all([
|
|
21201
21964
|
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) })),
|
|
21202
|
-
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) }))
|
|
21965
|
+
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) })),
|
|
21966
|
+
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)
|
|
21203
21967
|
]);
|
|
21204
21968
|
const state = {
|
|
21205
21969
|
label: connectionLabel,
|
|
@@ -21208,22 +21972,25 @@ async function refreshServerStatus(ctx) {
|
|
|
21208
21972
|
reachable: true,
|
|
21209
21973
|
latencyMs: Date.now() - started,
|
|
21210
21974
|
status: status && typeof status === "object" && !Array.isArray(status) ? status : {},
|
|
21211
|
-
auth: auth && typeof auth === "object" && !Array.isArray(auth) ? auth : {}
|
|
21975
|
+
auth: auth && typeof auth === "object" && !Array.isArray(auth) ? auth : {},
|
|
21976
|
+
aliases,
|
|
21977
|
+
...remoteProjectLink && typeof remoteProjectLink === "object" && !Array.isArray(remoteProjectLink) ? { remoteProjectLink } : {}
|
|
21212
21978
|
};
|
|
21213
|
-
patchData(ctx, { server: state });
|
|
21979
|
+
patchData(ctx, { server: state, remoteProjectLink: state.remoteProjectLink });
|
|
21214
21980
|
patchFooter(ctx, { server: connectionLabel, latency: `${state.latencyMs}ms` });
|
|
21215
|
-
emitCompleted(ctx, label, {
|
|
21981
|
+
emitCompleted(ctx, label, { serverLabel: connectionLabel, latencyMs: state.latencyMs });
|
|
21216
21982
|
return state;
|
|
21217
21983
|
} catch (error) {
|
|
21218
21984
|
const state = {
|
|
21219
21985
|
label: "server unavailable",
|
|
21220
21986
|
reachable: false,
|
|
21221
21987
|
latencyMs: Date.now() - started,
|
|
21988
|
+
aliases: await serverAliases(projectRootOf(ctx)).catch(() => []),
|
|
21222
21989
|
error: error instanceof Error ? error.message : String(error)
|
|
21223
21990
|
};
|
|
21224
|
-
patchData(ctx, { server: state });
|
|
21991
|
+
patchData(ctx, { server: state, remoteProjectLink: undefined });
|
|
21225
21992
|
patchFooter(ctx, { server: "unavailable" });
|
|
21226
|
-
emitCompleted(ctx, label, {
|
|
21993
|
+
emitCompleted(ctx, label, { serverLabel: state.label, reachable: false, error: state.error });
|
|
21227
21994
|
return state;
|
|
21228
21995
|
}
|
|
21229
21996
|
}
|
|
@@ -21810,7 +22577,7 @@ init_theme2();
|
|
|
21810
22577
|
var DOCTOR_ACTIONS = [
|
|
21811
22578
|
{ detail: "run diagnostics now", item: { id: "run", label: "run", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "run diagnostics" } },
|
|
21812
22579
|
{ 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" } },
|
|
21813
|
-
{ detail: "repair project/server/auth link", item: { id: "repair", label: "repair", intent: { scene: "
|
|
22580
|
+
{ 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" } },
|
|
21814
22581
|
{ detail: "open tasks", item: { id: "tasks", label: "tasks", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Open tasks" } }, message: "open tasks" } }
|
|
21815
22582
|
];
|
|
21816
22583
|
function checks(state) {
|
|
@@ -21886,6 +22653,7 @@ function renderDoctorScene(state, layout) {
|
|
|
21886
22653
|
// packages/cli/src/app-opentui/scenes/family.ts
|
|
21887
22654
|
init_scene();
|
|
21888
22655
|
init_selectable();
|
|
22656
|
+
init_remote_link();
|
|
21889
22657
|
init_theme2();
|
|
21890
22658
|
|
|
21891
22659
|
// packages/cli/src/app-opentui/scenes/family-domains/kit.ts
|
|
@@ -23648,13 +24416,18 @@ function overviewBody(state, family, snap, layout) {
|
|
|
23648
24416
|
function familyRecoveryRows(state, family, errorMessage2) {
|
|
23649
24417
|
const selected = Math.max(0, state.selection.index);
|
|
23650
24418
|
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 });
|
|
23651
|
-
|
|
24419
|
+
const repairRemote = shouldOfferRemoteLinkRepair(state, errorMessage2);
|
|
24420
|
+
const rows = [
|
|
23652
24421
|
intro,
|
|
23653
|
-
blank()
|
|
23654
|
-
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" }),
|
|
23655
|
-
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" }),
|
|
23656
|
-
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" })
|
|
24422
|
+
blank()
|
|
23657
24423
|
];
|
|
24424
|
+
let index = 0;
|
|
24425
|
+
if (repairRemote) {
|
|
24426
|
+
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" }));
|
|
24427
|
+
index += 1;
|
|
24428
|
+
}
|
|
24429
|
+
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" }));
|
|
24430
|
+
return rows;
|
|
23658
24431
|
}
|
|
23659
24432
|
function renderFamilyScene(state, layout) {
|
|
23660
24433
|
const family = typeof state.data.familyName === "string" ? state.data.familyName : "";
|
|
@@ -23663,9 +24436,16 @@ function renderFamilyScene(state, layout) {
|
|
|
23663
24436
|
const loading = state.status === "loading" && !snap;
|
|
23664
24437
|
const errorMessage2 = state.error?.message ?? lastRefreshError(state) ?? undefined;
|
|
23665
24438
|
const probeFailed = snap ? snap.state.ran === false && Boolean(state.error) : Boolean(state.error);
|
|
24439
|
+
const selected = Math.max(0, state.selection.index);
|
|
23666
24440
|
const body = [
|
|
23667
24441
|
...loading ? loadingRows(family || "family", state.tick) : snap ? [
|
|
23668
|
-
...probeFailed && errorMessage2 ? [
|
|
24442
|
+
...probeFailed && errorMessage2 ? [
|
|
24443
|
+
...errorBanner(errorMessage2),
|
|
24444
|
+
...shouldOfferRemoteLinkRepair(state, errorMessage2) ? [
|
|
24445
|
+
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" })
|
|
24446
|
+
] : [],
|
|
24447
|
+
blank()
|
|
24448
|
+
] : [],
|
|
23669
24449
|
...current.subId ? formView(state, family, snap, current).lines : overviewBody(state, family, snap, layout)
|
|
23670
24450
|
] : familyRecoveryRows(state, family, errorMessage2)
|
|
23671
24451
|
];
|
|
@@ -23817,13 +24597,14 @@ function sortTasks2(tasks, spec) {
|
|
|
23817
24597
|
|
|
23818
24598
|
// packages/cli/src/app-opentui/scenes/fleet.ts
|
|
23819
24599
|
init_fleet_stats();
|
|
24600
|
+
init_remote_link();
|
|
23820
24601
|
init_theme2();
|
|
23821
|
-
var
|
|
24602
|
+
var BASE_FLEET_RECOVERY_ITEMS = [
|
|
23822
24603
|
{ id: "tasks", label: "tasks", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Open tasks" } }, message: "open tasks and dispatch work" },
|
|
23823
|
-
{ id: "repair", label: "repair", intent: { scene: "command", argv: ["init", "--repair"], action: { kind: "command-run", label: "Repair project link" } }, message: "repair project/server/auth link" },
|
|
23824
24604
|
{ id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Open server controls" } }, message: "server controls" },
|
|
23825
24605
|
{ id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "diagnose project" }
|
|
23826
24606
|
];
|
|
24607
|
+
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" };
|
|
23827
24608
|
var COL2 = {
|
|
23828
24609
|
glyph: 1,
|
|
23829
24610
|
runId: 8,
|
|
@@ -23988,33 +24769,43 @@ function runRow(width, run, active, optimistic) {
|
|
|
23988
24769
|
const item = runSelectableItem(run);
|
|
23989
24770
|
return item ? withSelectable(row, item) : row;
|
|
23990
24771
|
}
|
|
23991
|
-
var
|
|
24772
|
+
var BASE_RECOVERY_DECKS = [
|
|
23992
24773
|
{ label: "tasks", detail: "open tasks and dispatch work" },
|
|
23993
|
-
{ label: "repair", detail: "repair project/server/auth link" },
|
|
23994
24774
|
{ label: "server", detail: "open server controls" },
|
|
23995
24775
|
{ label: "doctor", detail: "diagnose project" }
|
|
23996
24776
|
];
|
|
23997
|
-
function
|
|
24777
|
+
function fleetRecoveryItems(state) {
|
|
24778
|
+
if (!shouldOfferRemoteLinkRepair(state))
|
|
24779
|
+
return BASE_FLEET_RECOVERY_ITEMS;
|
|
24780
|
+
return [BASE_FLEET_RECOVERY_ITEMS[0], FLEET_REPAIR_LINK_ITEM, ...BASE_FLEET_RECOVERY_ITEMS.slice(1)];
|
|
24781
|
+
}
|
|
24782
|
+
function fleetRecoveryDecks(state) {
|
|
24783
|
+
if (!shouldOfferRemoteLinkRepair(state))
|
|
24784
|
+
return BASE_RECOVERY_DECKS;
|
|
24785
|
+
return [BASE_RECOVERY_DECKS[0], { label: "repair link", detail: "backfill/prepare remote project-root link" }, ...BASE_RECOVERY_DECKS.slice(1)];
|
|
24786
|
+
}
|
|
24787
|
+
function recoveryRows(state, selected, reason) {
|
|
24788
|
+
const items = fleetRecoveryItems(state);
|
|
23998
24789
|
return [
|
|
23999
24790
|
...reason ? [line(reason, { fg: RIG_UI.yellow }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
24000
24791
|
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
24001
|
-
...
|
|
24792
|
+
...fleetRecoveryDecks(state).map((deck, index) => selectableDeckRow({ ...deck, index, active: selected === index }, items[index]))
|
|
24002
24793
|
];
|
|
24003
24794
|
}
|
|
24004
|
-
function emptyRows(query, total, selected) {
|
|
24795
|
+
function emptyRows(state, query, total, selected) {
|
|
24005
24796
|
if (!query.trim() && total === 0)
|
|
24006
|
-
return recoveryRows(selected, "No runs yet.");
|
|
24797
|
+
return recoveryRows(state, selected, "No runs yet.");
|
|
24007
24798
|
if (query.trim() && total > 0) {
|
|
24008
24799
|
return [
|
|
24009
|
-
...recoveryRows(selected, `No matching runs for ${JSON.stringify(query)} (${total} total).`)
|
|
24800
|
+
...recoveryRows(state, selected, `No matching runs for ${JSON.stringify(query)} (${total} total).`)
|
|
24010
24801
|
];
|
|
24011
24802
|
}
|
|
24012
|
-
return recoveryRows(selected, "No runs are visible with this filter.");
|
|
24803
|
+
return recoveryRows(state, selected, "No runs are visible with this filter.");
|
|
24013
24804
|
}
|
|
24014
24805
|
function degradedRows(state, selected) {
|
|
24015
24806
|
if (!state.error)
|
|
24016
24807
|
return [];
|
|
24017
|
-
return recoveryRows(selected, state.error.message);
|
|
24808
|
+
return recoveryRows(state, selected, state.error.message);
|
|
24018
24809
|
}
|
|
24019
24810
|
function renderFleetScene(state, layout) {
|
|
24020
24811
|
const width = panelWidth4(layout);
|
|
@@ -24024,7 +24815,7 @@ function renderFleetScene(state, layout) {
|
|
|
24024
24815
|
const runs = sortRuns(filterRunsForSearch(allRuns, query), spec);
|
|
24025
24816
|
const selectedRun = typeof state.data.selectedRunId === "string" && runs.some((run) => run.runId === state.data.selectedRunId) ? state.data.selectedRunId : runs[0]?.runId;
|
|
24026
24817
|
const selectedIndex = Math.max(0, runs.findIndex((run) => run.runId === selectedRun));
|
|
24027
|
-
const recoveryIndex = Math.max(0, Math.min(
|
|
24818
|
+
const recoveryIndex = Math.max(0, Math.min(fleetRecoveryItems(state).length - 1, state.selection.index));
|
|
24028
24819
|
const optimistic = optimisticStatuses(state);
|
|
24029
24820
|
const updatedAgo = updatedAgoLabel(state);
|
|
24030
24821
|
const panelTop = 0;
|
|
@@ -24056,7 +24847,7 @@ function renderFleetScene(state, layout) {
|
|
|
24056
24847
|
...runs.map((run, index) => runRow(contentWidth, run, index === selectedIndex, optimistic.get(run.runId)))
|
|
24057
24848
|
] : state.error ? degradedRows(state, recoveryIndex) : loading ? loadingRows("runs", state.tick) : [
|
|
24058
24849
|
...query.trim() ? [line(searchSummary("runs", query, runs.length, allRuns.length), { fg: RIG_UI.ink4 }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
24059
|
-
...emptyRows(query, allRuns.length, recoveryIndex)
|
|
24850
|
+
...emptyRows(state, query, allRuns.length, recoveryIndex)
|
|
24060
24851
|
]
|
|
24061
24852
|
];
|
|
24062
24853
|
return makeSceneFrame({
|
|
@@ -24544,19 +25335,19 @@ function renderInboxScene(state, layout) {
|
|
|
24544
25335
|
init_scene();
|
|
24545
25336
|
init_selectable();
|
|
24546
25337
|
init_theme2();
|
|
24547
|
-
var STEP_CONFIG_RUN = { id: "step-config", label: "run
|
|
25338
|
+
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" };
|
|
24548
25339
|
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" };
|
|
24549
|
-
var STEP_AUTH = { id: "step-auth", label: "connect GitHub", intent: { scene: "
|
|
24550
|
-
var STEP_TASKS = { id: "step-tasks", label: "
|
|
25340
|
+
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" };
|
|
25341
|
+
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" };
|
|
24551
25342
|
var SETUP_STEPS = [
|
|
24552
|
-
{ id: "config", label: "Project config", detail: "rig.config + private state", done: (s) => s.configured, cta: "Run
|
|
25343
|
+
{ id: "config", label: "Project config", detail: "rig.config + private state", done: (s) => s.configured, cta: "Run init", item: STEP_CONFIG_RUN },
|
|
24553
25344
|
{ id: "server", label: "Server target", detail: "local or remote, reachable", done: (s) => s.serverReachable, cta: "Choose a server", item: STEP_SERVER },
|
|
24554
25345
|
{ id: "auth", label: "GitHub auth", detail: "signed in on the selected server", done: (s) => s.authSignedIn, cta: "Connect GitHub", item: STEP_AUTH },
|
|
24555
25346
|
{ id: "tasks", label: "Task source", detail: "where work comes from", done: (s) => s.taskSourceReady, cta: "Pick a task source", item: STEP_TASKS }
|
|
24556
25347
|
];
|
|
24557
25348
|
var SECONDARY_ACTIONS = [
|
|
24558
|
-
{ label: "repair", detail: "reconfigure generated config and private state", item: { id: "repair", label: "repair", intent: { scene: "
|
|
24559
|
-
{ label: "demo", detail: "seed an offline demo task source to explore", item: { id: "demo", label: "demo", intent: { scene: "
|
|
25349
|
+
{ 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" } },
|
|
25350
|
+
{ 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" } },
|
|
24560
25351
|
{ 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" } }
|
|
24561
25352
|
];
|
|
24562
25353
|
function record2(value) {
|
|
@@ -24600,11 +25391,11 @@ function renderInitScene(state, layout) {
|
|
|
24600
25391
|
const allDone = completed === SETUP_STEPS.length;
|
|
24601
25392
|
const nextStep = SETUP_STEPS.find((step) => !step.done(signals));
|
|
24602
25393
|
const selected = Math.max(0, state.selection.index);
|
|
24603
|
-
const primary = nextStep ? selectableDeckRow({ label: "next", detail: `${nextStep.cta} \u2014 recommended`, active: selected === 0 }, { ...nextStep.item, id: "init-primary" }) : selectableDeckRow({ label: "verify", detail: "
|
|
25394
|
+
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" });
|
|
24604
25395
|
const secondaryRows = SECONDARY_ACTIONS.map(({ label, detail, item }, index) => selectableDeckRow({ label, detail, active: selected === index + 1 }, item));
|
|
24605
25396
|
const progress = allDone ? "all set" : `${completed} of ${SETUP_STEPS.length} complete`;
|
|
24606
25397
|
const panelLines = [
|
|
24607
|
-
line(allDone ? "
|
|
25398
|
+
line(allDone ? "INIT \xB7 ready to go" : "INIT \xB7 let's get you running", { fg: allDone ? RIG_UI.limeDim : RIG_UI.ink, bold: true }),
|
|
24608
25399
|
line(`progress ${progress}`, { fg: allDone ? RIG_UI.limeDim : RIG_UI.ink2 }),
|
|
24609
25400
|
blank(),
|
|
24610
25401
|
line("CHECKLIST", { fg: RIG_UI.ink3, bold: true }),
|
|
@@ -24616,11 +25407,11 @@ function renderInitScene(state, layout) {
|
|
|
24616
25407
|
line("OTHER PATHS", { fg: RIG_UI.ink3, bold: true }),
|
|
24617
25408
|
...secondaryRows,
|
|
24618
25409
|
blank(),
|
|
24619
|
-
line("enter/click runs the highlighted action \xB7 esc goes back \xB7 tab switches sections", { fg: RIG_UI.ink4 })
|
|
25410
|
+
line("enter/click runs the highlighted native action \xB7 esc goes back \xB7 tab switches sections", { fg: RIG_UI.ink4 })
|
|
24620
25411
|
];
|
|
24621
25412
|
return makeSceneFrame({
|
|
24622
25413
|
scene: "init",
|
|
24623
|
-
title: "
|
|
25414
|
+
title: "Init",
|
|
24624
25415
|
lines: [],
|
|
24625
25416
|
panels: [{
|
|
24626
25417
|
id: "init-setup",
|
|
@@ -24633,11 +25424,11 @@ function renderInitScene(state, layout) {
|
|
|
24633
25424
|
opacity: 0.98,
|
|
24634
25425
|
border: false,
|
|
24635
25426
|
chrome: "ad-terminal",
|
|
24636
|
-
headerText: "rig
|
|
25427
|
+
headerText: "rig init \xB7 guided onboarding",
|
|
24637
25428
|
paddingX: 5,
|
|
24638
25429
|
paddingY: 2
|
|
24639
25430
|
}],
|
|
24640
|
-
footer: { message: allDone ? "
|
|
25431
|
+
footer: { message: allDone ? "init complete" : "init in progress" },
|
|
24641
25432
|
live: !allDone || state.status === "action"
|
|
24642
25433
|
});
|
|
24643
25434
|
}
|
|
@@ -25926,18 +26717,43 @@ function renderRunDetailScene(state, layout) {
|
|
|
25926
26717
|
init_scene();
|
|
25927
26718
|
init_selectable();
|
|
25928
26719
|
init_theme2();
|
|
26720
|
+
init_remote_link();
|
|
25929
26721
|
var SERVER_ACTIONS = [
|
|
25930
26722
|
{ 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" } },
|
|
25931
|
-
{ detail: "select local server for this repo", item: { id: "local", label: "use local", intent: { scene: "
|
|
25932
|
-
{ detail: "
|
|
25933
|
-
{ detail: "show saved local/remote aliases", item: { id: "list", label: "list servers", intent: { scene: "
|
|
25934
|
-
{ detail: "
|
|
26723
|
+
{ 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" } },
|
|
26724
|
+
{ 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" } },
|
|
26725
|
+
{ 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" } },
|
|
26726
|
+
{ 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" } },
|
|
25935
26727
|
{ 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" } },
|
|
25936
|
-
{ detail: "import gh token into the selected server namespace", item: { id: "auth", label: "import auth", intent: { scene: "
|
|
26728
|
+
{ 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" } },
|
|
25937
26729
|
{ 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" } },
|
|
25938
26730
|
{ 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" } },
|
|
25939
26731
|
{ 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" } }
|
|
25940
26732
|
];
|
|
26733
|
+
function remoteAliasActions(server) {
|
|
26734
|
+
const aliases = (server?.aliases ?? []).filter((alias) => alias.kind === "remote");
|
|
26735
|
+
return aliases.map((alias) => ({
|
|
26736
|
+
detail: `${alias.selected ? "selected" : "select"} ${alias.baseUrl ?? "remote endpoint"}`,
|
|
26737
|
+
item: {
|
|
26738
|
+
id: `remote-alias:${alias.alias}`,
|
|
26739
|
+
label: alias.selected ? `\u2713 ${alias.alias}` : `use ${alias.alias}`,
|
|
26740
|
+
intent: { scene: "server", argv: ["server", "use", alias.alias], action: { kind: "server-use-remote", label: `Use ${alias.alias}`, payload: { alias: alias.alias } } },
|
|
26741
|
+
message: `select ${alias.alias}`
|
|
26742
|
+
}
|
|
26743
|
+
}));
|
|
26744
|
+
}
|
|
26745
|
+
function serverActions(state) {
|
|
26746
|
+
const server = serverState(state);
|
|
26747
|
+
const remoteRows = remoteAliasActions(server);
|
|
26748
|
+
let actions = remoteRows.length > 0 ? [...SERVER_ACTIONS.slice(0, 3), ...remoteRows, ...SERVER_ACTIONS.slice(3)] : [...SERVER_ACTIONS];
|
|
26749
|
+
if (!shouldOfferRemoteLinkRepair(state))
|
|
26750
|
+
return actions;
|
|
26751
|
+
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" } };
|
|
26752
|
+
const doctorIndex = actions.findIndex((entry) => entry.item.id === "doctor");
|
|
26753
|
+
if (doctorIndex < 0)
|
|
26754
|
+
return [...actions, repair];
|
|
26755
|
+
return [...actions.slice(0, doctorIndex), repair, ...actions.slice(doctorIndex)];
|
|
26756
|
+
}
|
|
25941
26757
|
function cleanVisible(value, fallback = "unknown") {
|
|
25942
26758
|
return value?.trim() || fallback;
|
|
25943
26759
|
}
|
|
@@ -25962,31 +26778,37 @@ function selectedIndex(state, count) {
|
|
|
25962
26778
|
function statusRows2(server) {
|
|
25963
26779
|
const auth = server?.auth;
|
|
25964
26780
|
const signedIn = auth && (auth.signedIn === true || auth.authenticated === true || auth.status === "authenticated") ? "authenticated" : "auth unknown";
|
|
26781
|
+
const link = server?.remoteProjectLink;
|
|
26782
|
+
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";
|
|
26783
|
+
const selectedLinkSummary = link?.ok ? " \xB7 root link ready" : server?.kind === "remote" && link ? ` \xB7 root link ${link.status ?? "needs repair"}` : "";
|
|
25965
26784
|
return [
|
|
25966
|
-
line(`selected ${cleanVisible(server?.label, "not checked")}`, { fg: RIG_UI.ink2 }),
|
|
26785
|
+
line(`selected ${cleanVisible(server?.label, "not checked")}${selectedLinkSummary}`, { fg: RIG_UI.ink2 }),
|
|
25967
26786
|
line(`target ${targetLabel(server)}`, { fg: RIG_UI.ink3 }),
|
|
25968
26787
|
line(`mode ${server?.kind ?? "local or remote"}`, { fg: RIG_UI.ink3 }),
|
|
25969
26788
|
line(`health ${server ? server.reachable ? "reachable" : "unreachable" : "check pending"}`, { fg: server?.reachable ? RIG_UI.limeDim : server ? RIG_UI.red : RIG_UI.yellow }),
|
|
25970
26789
|
line(`github ${signedIn}`, { fg: signedIn === "authenticated" ? RIG_UI.limeDim : RIG_UI.ink4 }),
|
|
26790
|
+
line(`root link ${linkText}`, { fg: link?.ok ? RIG_UI.limeDim : server?.kind === "remote" ? RIG_UI.yellow : RIG_UI.ink4 }),
|
|
26791
|
+
...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 })] : [],
|
|
25971
26792
|
...server?.error ? [line(`attention ${server.error}`, { fg: RIG_UI.yellow })] : []
|
|
25972
26793
|
];
|
|
25973
26794
|
}
|
|
25974
26795
|
function renderServerScene(state, layout) {
|
|
25975
26796
|
const server = serverState(state);
|
|
25976
|
-
const
|
|
26797
|
+
const actions = serverActions(state);
|
|
26798
|
+
const selected = selectedIndex(state, actions.length);
|
|
25977
26799
|
const loading = state.status === "loading" && !server;
|
|
25978
26800
|
const errorText = state.error?.message ?? lastRefreshError(state);
|
|
25979
26801
|
const panelLines = [
|
|
25980
26802
|
...errorText ? errorBanner(errorText, "select refresh or doctor below to retry") : [],
|
|
25981
26803
|
line("server controls", { fg: RIG_UI.ink3 }),
|
|
25982
26804
|
blank(),
|
|
25983
|
-
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
25984
|
-
...SERVER_ACTIONS.map(({ detail, item }, index) => selectableDeckRow({ label: item.label, detail, index, active: selected === index }, item)),
|
|
25985
|
-
blank(),
|
|
25986
26805
|
line("STATUS", { fg: RIG_UI.ink3, bold: true }),
|
|
25987
26806
|
...loading ? loadingRows("server status", state.tick) : statusRows2(server),
|
|
25988
26807
|
blank(),
|
|
25989
|
-
line("
|
|
26808
|
+
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
26809
|
+
...actions.map(({ detail, item }, index) => selectableDeckRow({ label: item.label, detail, index, active: selected === index }, item)),
|
|
26810
|
+
blank(),
|
|
26811
|
+
line("enter/click runs native actions \xB7 add/use remote prompts stay in OpenTUI", { fg: RIG_UI.ink4 })
|
|
25990
26812
|
];
|
|
25991
26813
|
return makeSceneFrame({
|
|
25992
26814
|
scene: "server",
|
|
@@ -26015,14 +26837,15 @@ function renderServerScene(state, layout) {
|
|
|
26015
26837
|
// packages/cli/src/app-opentui/scenes/tasks.ts
|
|
26016
26838
|
init_scene();
|
|
26017
26839
|
init_selectable();
|
|
26840
|
+
init_remote_link();
|
|
26018
26841
|
init_theme2();
|
|
26019
|
-
var
|
|
26842
|
+
var BASE_TASK_RECOVERY_ITEMS = [
|
|
26020
26843
|
{ id: "refresh", label: "refresh", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Refresh tasks" } }, message: "refresh task source" },
|
|
26021
|
-
{ id: "next", label: "next", intent: { scene: "
|
|
26022
|
-
{ id: "repair", label: "repair", intent: { scene: "command", argv: ["init", "--repair"], action: { kind: "command-run", label: "Repair task source" } }, message: "repair project/task source" },
|
|
26844
|
+
{ 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" },
|
|
26023
26845
|
{ id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Open server controls" } }, message: "server controls" },
|
|
26024
26846
|
{ id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "diagnose task source" }
|
|
26025
26847
|
];
|
|
26848
|
+
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" };
|
|
26026
26849
|
var COL3 = {
|
|
26027
26850
|
glyph: 1,
|
|
26028
26851
|
id: 11,
|
|
@@ -26182,34 +27005,44 @@ function taskRow(width, task, active, optimistic) {
|
|
|
26182
27005
|
const item = taskSelectableItem(task);
|
|
26183
27006
|
return item ? withSelectable(row, item) : row;
|
|
26184
27007
|
}
|
|
26185
|
-
var
|
|
27008
|
+
var BASE_RECOVERY_DECKS2 = [
|
|
26186
27009
|
{ label: "refresh", detail: "reload task source" },
|
|
26187
27010
|
{ label: "next", detail: "dispatch next runnable task" },
|
|
26188
|
-
{ label: "repair", detail: "repair project/task source link" },
|
|
26189
27011
|
{ label: "server", detail: "open server controls" },
|
|
26190
27012
|
{ label: "doctor", detail: "diagnose task source" }
|
|
26191
27013
|
];
|
|
26192
|
-
function
|
|
27014
|
+
function taskRecoveryItems(state) {
|
|
27015
|
+
if (!shouldOfferRemoteLinkRepair(state))
|
|
27016
|
+
return BASE_TASK_RECOVERY_ITEMS;
|
|
27017
|
+
return [BASE_TASK_RECOVERY_ITEMS[0], BASE_TASK_RECOVERY_ITEMS[1], TASK_REPAIR_LINK_ITEM, ...BASE_TASK_RECOVERY_ITEMS.slice(2)];
|
|
27018
|
+
}
|
|
27019
|
+
function taskRecoveryDecks(state) {
|
|
27020
|
+
if (!shouldOfferRemoteLinkRepair(state))
|
|
27021
|
+
return BASE_RECOVERY_DECKS2;
|
|
27022
|
+
return [BASE_RECOVERY_DECKS2[0], BASE_RECOVERY_DECKS2[1], { label: "repair link", detail: "backfill/prepare remote project-root link" }, ...BASE_RECOVERY_DECKS2.slice(2)];
|
|
27023
|
+
}
|
|
27024
|
+
function recoveryRows2(state, selected, reason) {
|
|
27025
|
+
const items = taskRecoveryItems(state);
|
|
26193
27026
|
return [
|
|
26194
27027
|
...reason ? [line(reason, { fg: RIG_UI.yellow }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
26195
27028
|
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
26196
|
-
...
|
|
27029
|
+
...taskRecoveryDecks(state).map((deck, index) => selectableDeckRow({ ...deck, index, active: selected === index }, items[index]))
|
|
26197
27030
|
];
|
|
26198
27031
|
}
|
|
26199
|
-
function emptyRows2(query, total, selected) {
|
|
27032
|
+
function emptyRows2(state, query, total, selected) {
|
|
26200
27033
|
if (!query.trim() && total === 0)
|
|
26201
|
-
return recoveryRows2(selected, "No tasks loaded.");
|
|
27034
|
+
return recoveryRows2(state, selected, "No tasks loaded.");
|
|
26202
27035
|
if (query.trim() && total > 0) {
|
|
26203
27036
|
return [
|
|
26204
|
-
...recoveryRows2(selected, `No matching tasks for ${JSON.stringify(query)} (${total} total).`)
|
|
27037
|
+
...recoveryRows2(state, selected, `No matching tasks for ${JSON.stringify(query)} (${total} total).`)
|
|
26205
27038
|
];
|
|
26206
27039
|
}
|
|
26207
|
-
return recoveryRows2(selected, "No tasks are visible with this filter.");
|
|
27040
|
+
return recoveryRows2(state, selected, "No tasks are visible with this filter.");
|
|
26208
27041
|
}
|
|
26209
27042
|
function degradedRows2(state, selected) {
|
|
26210
27043
|
if (!state.error)
|
|
26211
27044
|
return [];
|
|
26212
|
-
return recoveryRows2(selected, state.error.message);
|
|
27045
|
+
return recoveryRows2(state, selected, state.error.message);
|
|
26213
27046
|
}
|
|
26214
27047
|
function rawString(raw, key) {
|
|
26215
27048
|
const value = raw?.[key];
|
|
@@ -26233,7 +27066,10 @@ function renderTaskDetail(state, taskId3, layout) {
|
|
|
26233
27066
|
const activeRunId = task?.activeRun?.runId?.trim();
|
|
26234
27067
|
const width = panelWidth13(layout);
|
|
26235
27068
|
const selected = Math.max(0, state.selection.index);
|
|
27069
|
+
const errorText = state.error?.message ?? lastRefreshError(state);
|
|
27070
|
+
const offerRepairLink = shouldOfferRemoteLinkRepair(state, errorText);
|
|
26236
27071
|
const headerLines = [
|
|
27072
|
+
...errorText ? errorBanner(errorText, offerRepairLink ? "select repair link below to prepare the remote checkout" : "retry dispatch after resolving the issue") : [],
|
|
26237
27073
|
line(`${glyph2} ${title}`, { fg: color, bold: true }),
|
|
26238
27074
|
line(`task ${taskId3} \xB7 ${status}`, { fg: RIG_UI.ink3 }),
|
|
26239
27075
|
...task && task.labels.length > 0 ? [line(`labels: ${task.labels.join(", ")}`, { fg: RIG_UI.ink4 })] : [],
|
|
@@ -26245,8 +27081,16 @@ function renderTaskDetail(state, taskId3, layout) {
|
|
|
26245
27081
|
const actionRows2 = [];
|
|
26246
27082
|
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" }));
|
|
26247
27083
|
index += 1;
|
|
26248
|
-
|
|
26249
|
-
|
|
27084
|
+
if (offerRepairLink) {
|
|
27085
|
+
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" }));
|
|
27086
|
+
index += 1;
|
|
27087
|
+
}
|
|
27088
|
+
if (offerRepairLink) {
|
|
27089
|
+
actionRows2.push(line(" dispatch blocked until the remote project link is repaired", { fg: RIG_UI.ink4 }));
|
|
27090
|
+
} else {
|
|
27091
|
+
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}` }));
|
|
27092
|
+
index += 1;
|
|
27093
|
+
}
|
|
26250
27094
|
if (activeRunId) {
|
|
26251
27095
|
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)}` }));
|
|
26252
27096
|
index += 1;
|
|
@@ -26305,7 +27149,7 @@ function renderTasksScene(state, layout) {
|
|
|
26305
27149
|
const tasks = sortTasks2(filterTasksForSearch(allTasks, query), spec);
|
|
26306
27150
|
const selected = typeof state.data.selectedTaskId === "string" && tasks.some((task) => task.id === state.data.selectedTaskId) ? state.data.selectedTaskId : tasks[0]?.id;
|
|
26307
27151
|
const selectedIndex2 = Math.max(0, tasks.findIndex((task) => task.id === selected));
|
|
26308
|
-
const recoveryIndex = Math.max(0, Math.min(
|
|
27152
|
+
const recoveryIndex = Math.max(0, Math.min(taskRecoveryItems(state).length - 1, state.selection.index));
|
|
26309
27153
|
const dispatching = dispatchingFor(state);
|
|
26310
27154
|
const dispatchLine = dispatching ? ` \xB7 ${state.data.dispatchingRun?.runId ?? "new"} ${dispatching.status}` : "";
|
|
26311
27155
|
const updatedAgo = updatedAgoLabel2(state);
|
|
@@ -26325,7 +27169,7 @@ function renderTasksScene(state, layout) {
|
|
|
26325
27169
|
...tasks.map((task, index) => taskRow(contentWidth, task, index === selectedIndex2, dispatching && dispatching.taskId === task.id ? dispatching.status : undefined))
|
|
26326
27170
|
] : state.error ? degradedRows2(state, recoveryIndex) : loading ? loadingRows("tasks", state.tick) : [
|
|
26327
27171
|
...query.trim() ? [line(searchSummary("tasks", query, tasks.length, allTasks.length), { fg: RIG_UI.ink4 }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
26328
|
-
...emptyRows2(query, allTasks.length, recoveryIndex)
|
|
27172
|
+
...emptyRows2(state, query, allTasks.length, recoveryIndex)
|
|
26329
27173
|
]
|
|
26330
27174
|
];
|
|
26331
27175
|
return makeSceneFrame({
|
|
@@ -26686,6 +27530,29 @@ function createDomainAdapter() {
|
|
|
26686
27530
|
else
|
|
26687
27531
|
await loadInitFacts(ctx);
|
|
26688
27532
|
return true;
|
|
27533
|
+
case "server-use-local":
|
|
27534
|
+
await useLocalServerFromApp(ctx);
|
|
27535
|
+
return true;
|
|
27536
|
+
case "server-use-remote":
|
|
27537
|
+
await useRemoteServerFromApp(ctx, payloadString8(intent, "alias") ?? intent.argv[2]);
|
|
27538
|
+
return true;
|
|
27539
|
+
case "server-add-remote":
|
|
27540
|
+
await addRemoteServerFromApp(ctx, intent.argv);
|
|
27541
|
+
return true;
|
|
27542
|
+
case "github-auth-import":
|
|
27543
|
+
await importGitHubAuthFromGhApp(ctx);
|
|
27544
|
+
return true;
|
|
27545
|
+
case "remote-link-repair": {
|
|
27546
|
+
await repairRemoteProjectRootLinkFromApp(ctx);
|
|
27547
|
+
const returnScene = payloadString8(intent, "returnScene");
|
|
27548
|
+
if (returnScene && returnScene !== intent.scene) {
|
|
27549
|
+
ctx.emit({ type: "scene.change", scene: returnScene, intent: { scene: returnScene, argv: intent.argv, action: { kind: "refresh", label: `Refresh ${returnScene}`, payload: intent.action.payload } } });
|
|
27550
|
+
await refreshScene(ctx, returnScene, { scene: returnScene, argv: intent.argv, action: { kind: "refresh", label: `Refresh ${returnScene}`, payload: intent.action.payload } });
|
|
27551
|
+
} else {
|
|
27552
|
+
await refreshServerStatus(ctx);
|
|
27553
|
+
}
|
|
27554
|
+
return true;
|
|
27555
|
+
}
|
|
26689
27556
|
case "doctor-run":
|
|
26690
27557
|
await runDoctorChecksForApp(ctx);
|
|
26691
27558
|
return true;
|