@h-rig/cli 0.0.6-alpha.87 → 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 +1380 -865
- package/dist/src/app/board.js +462 -48
- package/dist/src/app-opentui/adapters/common.d.ts +3 -0
- package/dist/src/app-opentui/adapters/common.js +4 -0
- package/dist/src/app-opentui/adapters/doctor.js +458 -46
- package/dist/src/app-opentui/adapters/family.js +701 -151
- 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.d.ts +7 -0
- package/dist/src/app-opentui/adapters/pi-attach.js +1004 -519
- 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 +621 -549
- package/dist/src/app-opentui/autocomplete.js +4 -2
- package/dist/src/app-opentui/bootstrap.js +1376 -861
- package/dist/src/app-opentui/command-palette.js +37 -10
- package/dist/src/app-opentui/index.js +632 -528
- package/dist/src/app-opentui/intent.js +33 -8
- package/dist/src/app-opentui/keymap.js +43 -414
- package/dist/src/app-opentui/pi-host-child.js +496 -57
- package/dist/src/app-opentui/pi-pty-host.d.ts +14 -64
- package/dist/src/app-opentui/pi-pty-host.js +3 -397
- package/dist/src/app-opentui/react/App.js +144 -469
- package/dist/src/app-opentui/react/ChromeHost.js +44 -415
- package/dist/src/app-opentui/react/launch.js +659 -552
- package/dist/src/app-opentui/react/nav.js +1 -1
- package/dist/src/app-opentui/registry.js +1181 -742
- 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/render/terminal-handoff.d.ts +16 -0
- package/dist/src/app-opentui/render/terminal-handoff.js +14 -0
- package/dist/src/app-opentui/runtime.js +632 -528
- 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 +496 -57
- package/dist/src/commands/_pi-frontend.d.ts +25 -0
- package/dist/src/commands/_pi-frontend.js +497 -57
- 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 +496 -57
- 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 +551 -85
- package/dist/src/commands.js +701 -151
- package/dist/src/index.js +705 -151
- package/dist/src/launcher.js +4 -0
- package/package.json +8 -8
|
@@ -91,6 +91,21 @@ async function captureConsole(fn) {
|
|
|
91
91
|
console.error = original.error;
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
+
async function releaseRendererForExternalTui(ctx) {
|
|
95
|
+
const renderer = ctx.renderer;
|
|
96
|
+
if (!renderer)
|
|
97
|
+
return;
|
|
98
|
+
if (renderer.suspend) {
|
|
99
|
+
await renderer.suspend();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (renderer.destroy) {
|
|
103
|
+
await renderer.destroy();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async function resumeRendererAfterExternalTui(ctx) {
|
|
107
|
+
await ctx.renderer?.resume?.();
|
|
108
|
+
}
|
|
94
109
|
function arrayFromPayload(value) {
|
|
95
110
|
if (Array.isArray(value)) {
|
|
96
111
|
return value.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry)));
|
|
@@ -628,7 +643,8 @@ __export(exports__connection_state, {
|
|
|
628
643
|
resolveGlobalConnectionsPath: () => resolveGlobalConnectionsPath,
|
|
629
644
|
readRepoConnection: () => readRepoConnection,
|
|
630
645
|
readGlobalConnections: () => readGlobalConnections,
|
|
631
|
-
isRemoteConnectionSelected: () => isRemoteConnectionSelected
|
|
646
|
+
isRemoteConnectionSelected: () => isRemoteConnectionSelected,
|
|
647
|
+
clearRepoServerProjectRoot: () => clearRepoServerProjectRoot
|
|
632
648
|
});
|
|
633
649
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "fs";
|
|
634
650
|
import { homedir } from "os";
|
|
@@ -712,12 +728,28 @@ function readRepoConnection(projectRoot) {
|
|
|
712
728
|
selected,
|
|
713
729
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
714
730
|
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
715
|
-
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
|
|
716
734
|
};
|
|
717
735
|
}
|
|
718
736
|
function writeRepoConnection(projectRoot, state) {
|
|
719
737
|
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
720
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
|
+
}
|
|
721
753
|
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
722
754
|
const repo = readRepoConnection(projectRoot);
|
|
723
755
|
if (!repo)
|
|
@@ -729,13 +761,41 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
729
761
|
if (!connection) {
|
|
730
762
|
throw new CliError(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
731
763
|
}
|
|
732
|
-
return { alias: repo.selected, connection, serverProjectRoot: repo
|
|
764
|
+
return { alias: repo.selected, connection, serverProjectRoot: rootAllowedForSelection(repo, connection) };
|
|
765
|
+
}
|
|
766
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot, metadata = {}) {
|
|
767
|
+
const repo = readRepoConnection(projectRoot);
|
|
768
|
+
if (!repo)
|
|
769
|
+
return;
|
|
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
|
+
});
|
|
733
789
|
}
|
|
734
|
-
function
|
|
790
|
+
function clearRepoServerProjectRoot(projectRoot) {
|
|
735
791
|
const repo = readRepoConnection(projectRoot);
|
|
736
792
|
if (!repo)
|
|
737
793
|
return;
|
|
738
|
-
writeRepoConnection(projectRoot, {
|
|
794
|
+
writeRepoConnection(projectRoot, {
|
|
795
|
+
selected: repo.selected,
|
|
796
|
+
...repo.project ? { project: repo.project } : {},
|
|
797
|
+
...repo.linkedAt ? { linkedAt: repo.linkedAt } : {}
|
|
798
|
+
});
|
|
739
799
|
}
|
|
740
800
|
function isRemoteConnectionSelected(projectRoot) {
|
|
741
801
|
return resolveSelectedConnection(projectRoot)?.connection.kind === "remote";
|
|
@@ -762,12 +822,16 @@ __export(exports__server_client, {
|
|
|
762
822
|
respondRunPiExtensionUiViaServer: () => respondRunPiExtensionUiViaServer,
|
|
763
823
|
resolveServerConnectionLabel: () => resolveServerConnectionLabel,
|
|
764
824
|
requestServerJson: () => requestServerJson,
|
|
825
|
+
repairRemoteProjectRootLink: () => repairRemoteProjectRootLink,
|
|
765
826
|
registerProjectViaServer: () => registerProjectViaServer,
|
|
766
827
|
prepareRemoteCheckoutViaServer: () => prepareRemoteCheckoutViaServer,
|
|
767
828
|
postGitHubTokenViaServer: () => postGitHubTokenViaServer,
|
|
829
|
+
normalizeRepoSlug: () => normalizeRepoSlug,
|
|
768
830
|
listWorkspaceTasksViaServer: () => listWorkspaceTasksViaServer,
|
|
769
831
|
listRunsViaServer: () => listRunsViaServer,
|
|
770
832
|
listGitHubProjectsViaServer: () => listGitHubProjectsViaServer,
|
|
833
|
+
isRemoteProjectRootLinkError: () => isRemoteProjectRootLinkError,
|
|
834
|
+
inspectRemoteProjectLink: () => inspectRemoteProjectLink,
|
|
771
835
|
getWorkspaceTaskViaServer: () => getWorkspaceTaskViaServer,
|
|
772
836
|
getRunTimelineViaServer: () => getRunTimelineViaServer,
|
|
773
837
|
getRunPiStatusViaServer: () => getRunPiStatusViaServer,
|
|
@@ -779,13 +843,15 @@ __export(exports__server_client, {
|
|
|
779
843
|
getRunDetailsViaServer: () => getRunDetailsViaServer,
|
|
780
844
|
getGitHubProjectStatusFieldViaServer: () => getGitHubProjectStatusFieldViaServer,
|
|
781
845
|
getGitHubAuthStatusViaServer: () => getGitHubAuthStatusViaServer,
|
|
846
|
+
formatRemoteProjectLinkHint: () => formatRemoteProjectLinkHint,
|
|
782
847
|
ensureTaskLabelsViaServer: () => ensureTaskLabelsViaServer,
|
|
783
848
|
ensureServerForCli: () => ensureServerForCli,
|
|
849
|
+
ensureRemoteProjectRootLink: () => ensureRemoteProjectRootLink,
|
|
784
850
|
buildRunPiEventsWebSocketUrl: () => buildRunPiEventsWebSocketUrl,
|
|
785
851
|
abortRunPiViaServer: () => abortRunPiViaServer
|
|
786
852
|
});
|
|
787
|
-
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
788
|
-
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";
|
|
789
855
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
790
856
|
function setServerPhaseListener(listener) {
|
|
791
857
|
const previous = serverPhaseListener;
|
|
@@ -831,11 +897,10 @@ function readStoredGitHubAuthToken(projectRoot) {
|
|
|
831
897
|
const parsed = readRemoteAuthState(projectRoot);
|
|
832
898
|
return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
|
|
833
899
|
}
|
|
834
|
-
function
|
|
835
|
-
|
|
836
|
-
const slug = repo?.project?.trim();
|
|
837
|
-
if (!slug || !/^[^/]+\/[^/]+$/.test(slug))
|
|
900
|
+
function inferRemoteServerProjectRootCandidateFromAuthState(projectRoot, repoSlug) {
|
|
901
|
+
if (!/^[^/]+\/[^/]+$/.test(repoSlug))
|
|
838
902
|
return null;
|
|
903
|
+
const repo = readRepoConnection(projectRoot);
|
|
839
904
|
const auth = readRemoteAuthState(projectRoot);
|
|
840
905
|
const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
|
|
841
906
|
const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
|
|
@@ -844,25 +909,426 @@ function inferRemoteServerProjectRootFromAuthState(projectRoot) {
|
|
|
844
909
|
const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
|
|
845
910
|
if (!checkoutBaseDir)
|
|
846
911
|
return null;
|
|
847
|
-
|
|
848
|
-
writeRepoServerProjectRoot(projectRoot, inferred);
|
|
849
|
-
return inferred;
|
|
912
|
+
return `${checkoutBaseDir.replace(/\/+$/, "")}/${repoSlug}`;
|
|
850
913
|
}
|
|
851
914
|
function readLocalConnectionFallbackToken(projectRoot) {
|
|
852
915
|
return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
|
|
853
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
|
+
}
|
|
854
1320
|
async function ensureServerForCli(projectRoot) {
|
|
855
1321
|
try {
|
|
856
1322
|
const selected = resolveSelectedConnection(projectRoot);
|
|
857
1323
|
if (selected?.connection.kind === "remote") {
|
|
858
1324
|
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
859
1325
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
860
|
-
const
|
|
1326
|
+
const link = await ensureRemoteProjectRootLink(projectRoot, { mode: "backfill-only", authToken });
|
|
861
1327
|
return {
|
|
862
1328
|
baseUrl: selected.connection.baseUrl,
|
|
863
1329
|
authToken,
|
|
864
1330
|
connectionKind: "remote",
|
|
865
|
-
serverProjectRoot
|
|
1331
|
+
serverProjectRoot: link.ok ? link.serverProjectRoot ?? null : null
|
|
866
1332
|
};
|
|
867
1333
|
}
|
|
868
1334
|
reportServerPhase("Starting local Rig server\u2026");
|
|
@@ -880,32 +1346,6 @@ async function ensureServerForCli(projectRoot) {
|
|
|
880
1346
|
throw error;
|
|
881
1347
|
}
|
|
882
1348
|
}
|
|
883
|
-
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
884
|
-
const repo = readRepoConnection(projectRoot);
|
|
885
|
-
const slug = repo?.project?.trim();
|
|
886
|
-
if (!slug)
|
|
887
|
-
return null;
|
|
888
|
-
try {
|
|
889
|
-
const url = new URL(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`);
|
|
890
|
-
if (authToken && queryAuthFallbackEnabled())
|
|
891
|
-
url.searchParams.set("rt", authToken);
|
|
892
|
-
const response = await fetch(url, {
|
|
893
|
-
headers: mergeHeaders(undefined, authToken)
|
|
894
|
-
});
|
|
895
|
-
if (!response.ok)
|
|
896
|
-
return null;
|
|
897
|
-
const payload = await response.json();
|
|
898
|
-
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
899
|
-
const checkouts = Array.isArray(project?.checkouts) ? project.checkouts : [];
|
|
900
|
-
const latestCheckout = [...checkouts].reverse().find((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.path === "string"));
|
|
901
|
-
const path = typeof latestCheckout?.path === "string" && latestCheckout.path.trim() ? latestCheckout.path.trim() : null;
|
|
902
|
-
if (path)
|
|
903
|
-
writeRepoServerProjectRoot(projectRoot, path);
|
|
904
|
-
return path;
|
|
905
|
-
} catch {
|
|
906
|
-
return null;
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
1349
|
function appendTaskFilterParams(url, filters) {
|
|
910
1350
|
if (filters.assignee)
|
|
911
1351
|
url.searchParams.set("assignee", filters.assignee);
|
|
@@ -1006,13 +1446,20 @@ function canUseRemoteWithoutProjectRoot(pathname) {
|
|
|
1006
1446
|
async function requestServerJson(context, pathname, init = {}) {
|
|
1007
1447
|
const server = await ensureServerForCli(context.projectRoot);
|
|
1008
1448
|
const requestUrl = new URL(`${server.baseUrl}${pathname}`);
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
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
|
+
}
|
|
1012
1459
|
}
|
|
1013
1460
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
1014
|
-
if (
|
|
1015
|
-
headers.set("x-rig-project-root",
|
|
1461
|
+
if (scopedServerProjectRoot)
|
|
1462
|
+
headers.set("x-rig-project-root", scopedServerProjectRoot);
|
|
1016
1463
|
if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
|
|
1017
1464
|
requestUrl.searchParams.set("rt", server.authToken);
|
|
1018
1465
|
}
|
|
@@ -2057,12 +2504,13 @@ var init__help_catalog = __esm(() => {
|
|
|
2057
2504
|
{
|
|
2058
2505
|
name: "server",
|
|
2059
2506
|
summary: "Choose, inspect, and start the Rig server that owns tasks and runs.",
|
|
2060
|
-
usage: ["rig server <status|list|add|use|start> [options]"],
|
|
2507
|
+
usage: ["rig server <status|list|add|use|repair-link|start> [options]"],
|
|
2061
2508
|
commands: [
|
|
2062
|
-
{ 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 },
|
|
2063
2510
|
{ command: "use local", description: "Switch this repo to the local Rig server.", primary: true },
|
|
2064
2511
|
{ command: "add <alias> <url>", description: "Save a remote Rig server URL.", primary: true },
|
|
2065
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 },
|
|
2066
2514
|
{ command: "list", description: "List saved local/remote server aliases.", primary: true },
|
|
2067
2515
|
{ command: "start [--host <host>] [--port <n>]", description: "Start a local rig-server process." }
|
|
2068
2516
|
],
|
|
@@ -2070,6 +2518,7 @@ var init__help_catalog = __esm(() => {
|
|
|
2070
2518
|
"rig server status",
|
|
2071
2519
|
"rig server add prod https://where.rig-does.work",
|
|
2072
2520
|
"rig server use prod",
|
|
2521
|
+
"rig server repair-link --repo owner/repo",
|
|
2073
2522
|
"rig server use local",
|
|
2074
2523
|
"rig server start --port 3773"
|
|
2075
2524
|
],
|
|
@@ -2780,7 +3229,7 @@ function resolveControlPlaneDefinitionRoot(projectRoot) {
|
|
|
2780
3229
|
var init__paths = () => {};
|
|
2781
3230
|
|
|
2782
3231
|
// packages/cli/src/report-bug.ts
|
|
2783
|
-
import { copyFileSync, existsSync as existsSync6, mkdirSync as
|
|
3232
|
+
import { copyFileSync, existsSync as existsSync6, mkdirSync as mkdirSync4, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
2784
3233
|
import { basename as basename2, extname, join, resolve as resolve8 } from "path";
|
|
2785
3234
|
function slugifyBugTitle(value) {
|
|
2786
3235
|
const slug = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80).replace(/-+$/g, "");
|
|
@@ -2819,8 +3268,8 @@ function createBugReportFiles(input) {
|
|
|
2819
3268
|
}
|
|
2820
3269
|
rmSync2(reportDir, { recursive: true, force: true });
|
|
2821
3270
|
}
|
|
2822
|
-
|
|
2823
|
-
|
|
3271
|
+
mkdirSync4(assetDir, { recursive: true });
|
|
3272
|
+
mkdirSync4(screenshotDir, { recursive: true });
|
|
2824
3273
|
const copiedScreenshots = copyEvidenceFiles(input.projectRoot, screenshotDir, input.screenshots ?? [], "screenshot");
|
|
2825
3274
|
const copiedAssets = copyEvidenceFiles(input.projectRoot, assetDir, input.assets ?? [], "asset");
|
|
2826
3275
|
const manifestAssets = [
|
|
@@ -2850,15 +3299,15 @@ function createBugReportFiles(input) {
|
|
|
2850
3299
|
platform: process.platform,
|
|
2851
3300
|
arch: process.arch
|
|
2852
3301
|
};
|
|
2853
|
-
|
|
2854
|
-
|
|
3302
|
+
writeFileSync3(join(assetDir, "README.md"), buildAssetReadme(input.title), "utf8");
|
|
3303
|
+
writeFileSync3(join(screenshotDir, "README.md"), buildScreenshotReadme(input.title), "utf8");
|
|
2855
3304
|
if (browserPath && browser) {
|
|
2856
|
-
|
|
3305
|
+
writeFileSync3(browserPath, `${JSON.stringify(browser, null, 2)}
|
|
2857
3306
|
`, "utf8");
|
|
2858
3307
|
}
|
|
2859
|
-
|
|
3308
|
+
writeFileSync3(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
2860
3309
|
`, "utf8");
|
|
2861
|
-
|
|
3310
|
+
writeFileSync3(taskPath, buildBugReportMarkdown(input, browser, copiedScreenshots, copiedAssets), "utf8");
|
|
2862
3311
|
return {
|
|
2863
3312
|
slug,
|
|
2864
3313
|
reportDir,
|
|
@@ -3035,7 +3484,7 @@ function formatAssetMarkdown(name, path) {
|
|
|
3035
3484
|
var init_report_bug = () => {};
|
|
3036
3485
|
|
|
3037
3486
|
// packages/cli/src/commands/task-report-bug.ts
|
|
3038
|
-
import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as
|
|
3487
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
3039
3488
|
import { resolve as resolve9 } from "path";
|
|
3040
3489
|
import pc2 from "picocolors";
|
|
3041
3490
|
import {
|
|
@@ -3397,7 +3846,7 @@ function appendTaskConfigEntryPreservingText(taskConfigPath, issueId, entry) {
|
|
|
3397
3846
|
`).map((line) => ` ${line}`).join(`
|
|
3398
3847
|
`);
|
|
3399
3848
|
if (!trimmed || trimmed === "{}") {
|
|
3400
|
-
|
|
3849
|
+
writeFileSync4(taskConfigPath, `{
|
|
3401
3850
|
${serializedEntry}
|
|
3402
3851
|
}
|
|
3403
3852
|
`, "utf8");
|
|
@@ -3413,7 +3862,7 @@ ${serializedEntry}
|
|
|
3413
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." });
|
|
3414
3863
|
}
|
|
3415
3864
|
const comma = before.trim() === "{" ? "" : ",";
|
|
3416
|
-
|
|
3865
|
+
writeFileSync4(taskConfigPath, `${before}${comma}
|
|
3417
3866
|
${serializedEntry}
|
|
3418
3867
|
}
|
|
3419
3868
|
`, "utf8");
|
|
@@ -3798,7 +4247,7 @@ var init_task_report_bug = __esm(() => {
|
|
|
3798
4247
|
});
|
|
3799
4248
|
|
|
3800
4249
|
// packages/cli/src/commands/browser.ts
|
|
3801
|
-
import { mkdirSync as
|
|
4250
|
+
import { mkdirSync as mkdirSync5, rmSync as rmSync3 } from "fs";
|
|
3802
4251
|
import { resolve as resolve10 } from "path";
|
|
3803
4252
|
import { spawn } from "child_process";
|
|
3804
4253
|
import { emitKeypressEvents } from "readline";
|
|
@@ -4376,7 +4825,7 @@ function readBrowserDemoCommandLine(command) {
|
|
|
4376
4825
|
}
|
|
4377
4826
|
async function launchBrowserDemo(runtime) {
|
|
4378
4827
|
rmSync3(resolve10(runtime.browserDir, runtime.stateDir), { recursive: true, force: true });
|
|
4379
|
-
|
|
4828
|
+
mkdirSync5(resolve10(runtime.browserDir, runtime.stateDir), { recursive: true });
|
|
4380
4829
|
const launcherPath = resolve10(runtime.browserDir, "scripts/electron-launcher.mjs");
|
|
4381
4830
|
const launcher = await import(pathToFileURL(launcherPath).href);
|
|
4382
4831
|
const electronPath = await launcher.resolveElectronPath();
|
|
@@ -4725,7 +5174,7 @@ var init_profile_and_review = __esm(() => {
|
|
|
4725
5174
|
});
|
|
4726
5175
|
|
|
4727
5176
|
// packages/cli/src/commands/_policy.ts
|
|
4728
|
-
import { appendFileSync, mkdirSync as
|
|
5177
|
+
import { appendFileSync, mkdirSync as mkdirSync6 } from "fs";
|
|
4729
5178
|
import { resolve as resolve11 } from "path";
|
|
4730
5179
|
import { evaluate as evaluate2, loadPolicy as loadPolicy2, resolveAction as resolveAction2 } from "@rig/runtime/control-plane/runtime/guard";
|
|
4731
5180
|
import { resolveHarnessPaths } from "@rig/runtime/control-plane/native/utils";
|
|
@@ -4742,7 +5191,7 @@ function appendControlledBashAudit(context, mode, command, args, matchedRuleIds,
|
|
|
4742
5191
|
}
|
|
4743
5192
|
const logsDir = resolveHarnessPaths(context.projectRoot).logsDir;
|
|
4744
5193
|
const logFile = resolve11(logsDir, "controlled-bash.jsonl");
|
|
4745
|
-
|
|
5194
|
+
mkdirSync6(logsDir, { recursive: true });
|
|
4746
5195
|
const payload = {
|
|
4747
5196
|
timestamp: new Date().toISOString(),
|
|
4748
5197
|
mode,
|
|
@@ -5036,9 +5485,9 @@ var exports_pi = {};
|
|
|
5036
5485
|
__export(exports_pi, {
|
|
5037
5486
|
executePi: () => executePi
|
|
5038
5487
|
});
|
|
5039
|
-
import { existsSync as existsSync9, mkdirSync as
|
|
5488
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
5040
5489
|
import { homedir as homedir4 } from "os";
|
|
5041
|
-
import { dirname as
|
|
5490
|
+
import { dirname as dirname3, resolve as resolve13 } from "path";
|
|
5042
5491
|
function settingsPath(root) {
|
|
5043
5492
|
return resolve13(root, ".pi", "settings.json");
|
|
5044
5493
|
}
|
|
@@ -5063,8 +5512,8 @@ function packageKey(entry) {
|
|
|
5063
5512
|
return JSON.stringify(entry);
|
|
5064
5513
|
}
|
|
5065
5514
|
function writeSettings(path, settings) {
|
|
5066
|
-
|
|
5067
|
-
|
|
5515
|
+
mkdirSync7(dirname3(path), { recursive: true });
|
|
5516
|
+
writeFileSync5(path, `${JSON.stringify(settings, null, 2)}
|
|
5068
5517
|
`, "utf-8");
|
|
5069
5518
|
}
|
|
5070
5519
|
async function searchNpmForPiExtensions(term) {
|
|
@@ -5247,6 +5696,14 @@ function permissionAllowsPr2(payload) {
|
|
|
5247
5696
|
function isNotFoundError(error) {
|
|
5248
5697
|
return /\b(404|not found)\b/i.test(message(error));
|
|
5249
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
|
+
}
|
|
5250
5707
|
function projectCheckoutReady(payload) {
|
|
5251
5708
|
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
5252
5709
|
return null;
|
|
@@ -5301,25 +5758,37 @@ async function runFastTaskRunPreflight(context, options = {}) {
|
|
|
5301
5758
|
}
|
|
5302
5759
|
const repo = readRepoConnection(context.projectRoot);
|
|
5303
5760
|
const remoteWithoutProjectLink = selectedServer?.connectionKind === "remote" && !repo?.project;
|
|
5304
|
-
|
|
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
|
+
}
|
|
5305
5769
|
try {
|
|
5306
5770
|
const auth = await request("/api/github/auth/status");
|
|
5307
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>`."));
|
|
5308
5772
|
} catch (error) {
|
|
5309
5773
|
checks.push(preflightCheck("github-auth", "GitHub auth valid", legacyServerCompatibility ? "warn" : "fail", message(error), "Fix GitHub auth on the selected Rig server."));
|
|
5310
5774
|
}
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
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."));
|
|
5323
5792
|
}
|
|
5324
5793
|
if (repo?.project) {
|
|
5325
5794
|
try {
|
|
@@ -5331,19 +5800,24 @@ async function runFastTaskRunPreflight(context, options = {}) {
|
|
|
5331
5800
|
}
|
|
5332
5801
|
}
|
|
5333
5802
|
if (taskId) {
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
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."));
|
|
5347
5821
|
}
|
|
5348
5822
|
}
|
|
5349
5823
|
if ((options.runtimeAdapter ?? "pi") === "pi") {
|
|
@@ -5824,7 +6298,7 @@ import {
|
|
|
5824
6298
|
chmodSync,
|
|
5825
6299
|
copyFileSync as copyFileSync2,
|
|
5826
6300
|
existsSync as existsSync11,
|
|
5827
|
-
mkdirSync as
|
|
6301
|
+
mkdirSync as mkdirSync8,
|
|
5828
6302
|
readdirSync,
|
|
5829
6303
|
readlinkSync,
|
|
5830
6304
|
rmSync as rmSync4,
|
|
@@ -5929,7 +6403,7 @@ async function executeDist(context, args) {
|
|
|
5929
6403
|
requireNoExtraArgs(pending, "rig dist install [--scope user|system] [--path <dir>]");
|
|
5930
6404
|
const scope = parseInstallScope(scopeResult.value);
|
|
5931
6405
|
const installDir = resolveInstallDir(scope, pathResult.value);
|
|
5932
|
-
|
|
6406
|
+
mkdirSync8(installDir, { recursive: true });
|
|
5933
6407
|
let source = await findLatestDistBinary(context.projectRoot);
|
|
5934
6408
|
let buildDir = null;
|
|
5935
6409
|
if (!source) {
|
|
@@ -5984,7 +6458,7 @@ async function executeDist(context, args) {
|
|
|
5984
6458
|
const fp = await computeRuntimeImageFingerprint(context.projectRoot);
|
|
5985
6459
|
const currentId = computeRuntimeImageId(fp);
|
|
5986
6460
|
const imagesDir = resolve16(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "images");
|
|
5987
|
-
|
|
6461
|
+
mkdirSync8(imagesDir, { recursive: true });
|
|
5988
6462
|
let pruned = 0;
|
|
5989
6463
|
for (const entry of readdirSync(imagesDir, { withFileTypes: true })) {
|
|
5990
6464
|
if (entry.isDirectory() && entry.name !== currentId) {
|
|
@@ -5996,9 +6470,9 @@ async function executeDist(context, args) {
|
|
|
5996
6470
|
console.log(`Pruned ${pruned} stale image(s).`);
|
|
5997
6471
|
}
|
|
5998
6472
|
const imageDir = resolve16(imagesDir, currentId);
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6473
|
+
mkdirSync8(resolve16(imageDir, "bin/hooks"), { recursive: true });
|
|
6474
|
+
mkdirSync8(resolve16(imageDir, "bin/plugins"), { recursive: true });
|
|
6475
|
+
mkdirSync8(resolve16(imageDir, "bin/validators"), { recursive: true });
|
|
6002
6476
|
const hookNames = [
|
|
6003
6477
|
"scope-guard",
|
|
6004
6478
|
"import-guard",
|
|
@@ -6023,8 +6497,8 @@ async function executeDist(context, args) {
|
|
|
6023
6497
|
const binPluginsDir = resolve16(resolveControlPlaneHostBinDir(context.projectRoot), "plugins");
|
|
6024
6498
|
const validatorsRoot = resolve16(hostProjectRoot, "packages/runtime/src/control-plane/validators");
|
|
6025
6499
|
const binValidatorsDir = resolve16(resolveControlPlaneHostBinDir(context.projectRoot), "validators");
|
|
6026
|
-
|
|
6027
|
-
|
|
6500
|
+
mkdirSync8(binPluginsDir, { recursive: true });
|
|
6501
|
+
mkdirSync8(binValidatorsDir, { recursive: true });
|
|
6028
6502
|
if (existsSync11(pluginsDir)) {
|
|
6029
6503
|
for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
|
|
6030
6504
|
const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
@@ -6463,16 +6937,19 @@ function formatConnectionList(connections) {
|
|
|
6463
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(`
|
|
6464
6938
|
`);
|
|
6465
6939
|
}
|
|
6466
|
-
function formatConnectionStatus(selected, connections) {
|
|
6940
|
+
function formatConnectionStatus(selected, connections, repo, remoteProjectLink) {
|
|
6467
6941
|
const connection = selected === "local" ? { kind: "local", mode: "auto" } : connections[selected];
|
|
6468
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";
|
|
6469
6944
|
return [
|
|
6470
6945
|
formatSection("Rig server", "selected for this repo"),
|
|
6471
6946
|
`${themeFaint("\u2502")} ${themeDim("selected ")} ${pc4.bold(selected)}`,
|
|
6472
6947
|
`${themeFaint("\u2502")} ${themeDim("kind ")} ${formatStatusPill(connection?.kind ?? "unknown")}`,
|
|
6473
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}`] : [],
|
|
6474
6951
|
"",
|
|
6475
|
-
...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`"])
|
|
6476
6953
|
].join(`
|
|
6477
6954
|
`);
|
|
6478
6955
|
}
|
|
@@ -6763,7 +7240,7 @@ var init_inbox = __esm(() => {
|
|
|
6763
7240
|
|
|
6764
7241
|
// packages/cli/src/commands/_snapshot-upload.ts
|
|
6765
7242
|
import { mkdir, readdir, readFile, writeFile } from "fs/promises";
|
|
6766
|
-
import { dirname as
|
|
7243
|
+
import { dirname as dirname4, resolve as resolve17, relative, sep } from "path";
|
|
6767
7244
|
function toPosixPath(path) {
|
|
6768
7245
|
return path.split(sep).join("/");
|
|
6769
7246
|
}
|
|
@@ -6864,7 +7341,7 @@ __export(exports_init, {
|
|
|
6864
7341
|
DEMO_TASKS_RELATIVE_DIR: () => DEMO_TASKS_RELATIVE_DIR,
|
|
6865
7342
|
DEMO_TASKS: () => DEMO_TASKS
|
|
6866
7343
|
});
|
|
6867
|
-
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";
|
|
6868
7345
|
import { spawnSync } from "child_process";
|
|
6869
7346
|
import { basename as basename3, resolve as resolve18 } from "path";
|
|
6870
7347
|
import { buildRigInitConfigSource } from "@rig/core";
|
|
@@ -6888,14 +7365,14 @@ function parseRepoSlug(value) {
|
|
|
6888
7365
|
}
|
|
6889
7366
|
function ensureRigPrivateDirs(projectRoot) {
|
|
6890
7367
|
const rigDir = resolve18(projectRoot, ".rig");
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
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 });
|
|
6896
7373
|
const taskConfigPath = resolve18(rigDir, "task-config.json");
|
|
6897
7374
|
if (!existsSync12(taskConfigPath))
|
|
6898
|
-
|
|
7375
|
+
writeFileSync6(taskConfigPath, `{}
|
|
6899
7376
|
`, "utf-8");
|
|
6900
7377
|
}
|
|
6901
7378
|
function ensureGitignoreEntries(projectRoot) {
|
|
@@ -6923,7 +7400,7 @@ function ensureRigConfigPackageDependencies(projectRoot) {
|
|
|
6923
7400
|
...existsSync12(path) ? existing : { name: "rig-project", private: true },
|
|
6924
7401
|
devDependencies
|
|
6925
7402
|
};
|
|
6926
|
-
|
|
7403
|
+
writeFileSync6(path, `${JSON.stringify(next, null, 2)}
|
|
6927
7404
|
`, "utf8");
|
|
6928
7405
|
}
|
|
6929
7406
|
function applyGitHubProjectConfig(source, options) {
|
|
@@ -6949,9 +7426,9 @@ function checkoutForInit(projectRoot, serverKind, strategy) {
|
|
|
6949
7426
|
const selected = strategy ?? { kind: "managed-clone" };
|
|
6950
7427
|
switch (selected.kind) {
|
|
6951
7428
|
case "managed-clone":
|
|
6952
|
-
return { kind: "managed-clone"
|
|
7429
|
+
return { kind: "managed-clone" };
|
|
6953
7430
|
case "current-ref":
|
|
6954
|
-
return { kind: "current-ref",
|
|
7431
|
+
return { kind: "current-ref", ...selected.ref ? { ref: selected.ref } : {} };
|
|
6955
7432
|
case "uploaded-snapshot":
|
|
6956
7433
|
return { kind: "uploaded-snapshot", path: projectRoot, source: "local-working-tree" };
|
|
6957
7434
|
case "existing-path":
|
|
@@ -7204,7 +7681,7 @@ function remoteGitHubAuthMetadata(payload) {
|
|
|
7204
7681
|
};
|
|
7205
7682
|
}
|
|
7206
7683
|
function writeRemoteGitHubAuthState(projectRoot, input) {
|
|
7207
|
-
|
|
7684
|
+
writeFileSync6(resolve18(projectRoot, ".rig", "state", "github-auth.json"), `${JSON.stringify({
|
|
7208
7685
|
authenticated: true,
|
|
7209
7686
|
source: input.source,
|
|
7210
7687
|
storedOnServer: true,
|
|
@@ -7252,7 +7729,7 @@ function runLocalFilesInit(context, options) {
|
|
|
7252
7729
|
console.log("rig.config already exists; leaving it unchanged. Pass --repair to rewrite it.");
|
|
7253
7730
|
} else {
|
|
7254
7731
|
const projectName = basename3(projectRoot) || "rig-project";
|
|
7255
|
-
|
|
7732
|
+
writeFileSync6(configTsPath, buildRigInitConfigSource({
|
|
7256
7733
|
projectName,
|
|
7257
7734
|
taskSource: { kind: "files", path: "tasks" },
|
|
7258
7735
|
useStandardPlugin: true
|
|
@@ -7261,8 +7738,8 @@ function runLocalFilesInit(context, options) {
|
|
|
7261
7738
|
ensureRigConfigPackageDependencies(projectRoot);
|
|
7262
7739
|
const tasksDir = resolve18(projectRoot, "tasks");
|
|
7263
7740
|
if (!existsSync12(tasksDir)) {
|
|
7264
|
-
|
|
7265
|
-
|
|
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)}
|
|
7266
7743
|
`, "utf-8");
|
|
7267
7744
|
}
|
|
7268
7745
|
if (context.outputMode !== "json") {
|
|
@@ -7286,7 +7763,7 @@ function runDemoInit(context, options) {
|
|
|
7286
7763
|
console.log("rig.config already exists; leaving it unchanged. Pass --repair to rewrite it for the demo.");
|
|
7287
7764
|
}
|
|
7288
7765
|
} else {
|
|
7289
|
-
|
|
7766
|
+
writeFileSync6(configTsPath, buildRigInitConfigSource({
|
|
7290
7767
|
projectName: basename3(projectRoot) || "rig-demo",
|
|
7291
7768
|
taskSource: { kind: "files", path: DEMO_TASKS_RELATIVE_DIR },
|
|
7292
7769
|
useStandardPlugin: true
|
|
@@ -7295,14 +7772,14 @@ function runDemoInit(context, options) {
|
|
|
7295
7772
|
}
|
|
7296
7773
|
ensureRigConfigPackageDependencies(projectRoot);
|
|
7297
7774
|
const demoTasksDir = resolve18(projectRoot, DEMO_TASKS_RELATIVE_DIR);
|
|
7298
|
-
|
|
7775
|
+
mkdirSync9(demoTasksDir, { recursive: true });
|
|
7299
7776
|
const taskIds = [];
|
|
7300
7777
|
for (const task of DEMO_TASKS) {
|
|
7301
7778
|
const id = String(task.id);
|
|
7302
7779
|
taskIds.push(id);
|
|
7303
7780
|
const taskPath = resolve18(demoTasksDir, `${id}.json`);
|
|
7304
7781
|
if (!existsSync12(taskPath)) {
|
|
7305
|
-
|
|
7782
|
+
writeFileSync6(taskPath, `${JSON.stringify(task, null, 2)}
|
|
7306
7783
|
`, "utf-8");
|
|
7307
7784
|
}
|
|
7308
7785
|
}
|
|
@@ -7330,21 +7807,32 @@ function runDemoInit(context, options) {
|
|
|
7330
7807
|
}
|
|
7331
7808
|
async function runControlPlaneInit(context, options) {
|
|
7332
7809
|
const projectRoot = context.projectRoot;
|
|
7333
|
-
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");
|
|
7334
7821
|
if (!detectedSlug) {
|
|
7335
7822
|
const authMethod2 = options.githubAuthMethod ?? (options.githubToken ? "token" : "skip");
|
|
7336
|
-
if (
|
|
7823
|
+
if (serverKind === "local" && authMethod2 === "skip") {
|
|
7337
7824
|
return runLocalFilesInit(context, options);
|
|
7338
7825
|
}
|
|
7339
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);
|
|
7340
7827
|
}
|
|
7341
7828
|
const repo = parseRepoSlug(detectedSlug);
|
|
7342
|
-
const
|
|
7343
|
-
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;
|
|
7344
7832
|
if (serverKind === "remote") {
|
|
7345
|
-
if (!
|
|
7346
|
-
throw new CliError("Missing --remote-url for --server remote.", 1, { hint: "Re-run as `rig init --server remote --remote-url https://your-rig-server
|
|
7347
|
-
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 });
|
|
7348
7836
|
}
|
|
7349
7837
|
writeRepoConnection(projectRoot, {
|
|
7350
7838
|
selected: connectionAlias,
|
|
@@ -7367,11 +7855,11 @@ async function runControlPlaneInit(context, options) {
|
|
|
7367
7855
|
taskSource: { kind: "github-issues", owner: repo.owner, repo: repo.repo },
|
|
7368
7856
|
useStandardPlugin: true
|
|
7369
7857
|
}), options);
|
|
7370
|
-
|
|
7858
|
+
writeFileSync6(configTsPath, source, "utf-8");
|
|
7371
7859
|
}
|
|
7372
7860
|
ensureRigConfigPackageDependencies(projectRoot);
|
|
7373
7861
|
}
|
|
7374
|
-
|
|
7862
|
+
writeFileSync6(resolve18(projectRoot, ".rig", "state", "project-link.json"), `${JSON.stringify({ repoSlug: repo.slug, connection: connectionAlias, linkedAt: new Date().toISOString() }, null, 2)}
|
|
7375
7863
|
`, "utf8");
|
|
7376
7864
|
const checkout = checkoutForInit(projectRoot, serverKind, options.remoteCheckout);
|
|
7377
7865
|
let uploadedSnapshot = null;
|
|
@@ -7386,7 +7874,7 @@ async function runControlPlaneInit(context, options) {
|
|
|
7386
7874
|
let githubAuth = null;
|
|
7387
7875
|
let deviceAuth = null;
|
|
7388
7876
|
const authMethod = options.githubAuthMethod ?? (options.githubToken ? "token" : "skip");
|
|
7389
|
-
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;
|
|
7390
7878
|
if (remoteGhTokenWarning && !options.yes) {
|
|
7391
7879
|
throw new CliError(`${remoteGhTokenWarning} Re-run with --yes to confirm this explicit token transfer.`, 1);
|
|
7392
7880
|
}
|
|
@@ -7766,8 +8254,8 @@ var init_init = __esm(() => {
|
|
|
7766
8254
|
|
|
7767
8255
|
// packages/cli/src/commands/github.ts
|
|
7768
8256
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
7769
|
-
import { mkdirSync as
|
|
7770
|
-
import { dirname as
|
|
8257
|
+
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync7 } from "fs";
|
|
8258
|
+
import { dirname as dirname5, resolve as resolve19 } from "path";
|
|
7771
8259
|
function printPayload(context, payload, fallback) {
|
|
7772
8260
|
if (context.outputMode === "json")
|
|
7773
8261
|
console.log(JSON.stringify(payload, null, 2));
|
|
@@ -7806,8 +8294,8 @@ function persistRemoteAuthSession(context, source, result, fallbackToken) {
|
|
|
7806
8294
|
return;
|
|
7807
8295
|
const repo = readRepoConnection(context.projectRoot);
|
|
7808
8296
|
const path = resolve19(context.projectRoot, ".rig", "state", "github-auth.json");
|
|
7809
|
-
|
|
7810
|
-
|
|
8297
|
+
mkdirSync10(dirname5(path), { recursive: true });
|
|
8298
|
+
writeFileSync7(path, `${JSON.stringify({
|
|
7811
8299
|
authenticated: true,
|
|
7812
8300
|
source,
|
|
7813
8301
|
storedOnServer: true,
|
|
@@ -9310,7 +9798,15 @@ var init__operator_surface = __esm(() => {
|
|
|
9310
9798
|
});
|
|
9311
9799
|
|
|
9312
9800
|
// packages/cli/src/commands/_pi-frontend.ts
|
|
9313
|
-
|
|
9801
|
+
var exports__pi_frontend = {};
|
|
9802
|
+
__export(exports__pi_frontend, {
|
|
9803
|
+
shouldRequireOperatorTranscript: () => shouldRequireOperatorTranscript,
|
|
9804
|
+
runWithProcessExitGuard: () => runWithProcessExitGuard,
|
|
9805
|
+
missingOperatorTranscriptMessage: () => missingOperatorTranscriptMessage,
|
|
9806
|
+
buildOperatorPiEnv: () => buildOperatorPiEnv,
|
|
9807
|
+
attachRunBundledPiFrontend: () => attachRunBundledPiFrontend
|
|
9808
|
+
});
|
|
9809
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync11, mkdtempSync, readFileSync as readFileSync10, rmSync as rmSync5, writeFileSync as writeFileSync8 } from "fs";
|
|
9314
9810
|
import { homedir as homedir6, tmpdir } from "os";
|
|
9315
9811
|
import { join as join3 } from "path";
|
|
9316
9812
|
import { main as runPiMain } from "@earendil-works/pi-coding-agent";
|
|
@@ -9362,7 +9858,7 @@ function statusFromRunDetails(run) {
|
|
|
9362
9858
|
async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
9363
9859
|
const server = await ensureServerForCli(context.projectRoot);
|
|
9364
9860
|
const localCwd = join3(homedir6(), ".rig", "drones", runId.slice(0, 8));
|
|
9365
|
-
|
|
9861
|
+
mkdirSync11(localCwd, { recursive: true });
|
|
9366
9862
|
trustDroneCwd(localCwd);
|
|
9367
9863
|
installRigPiTheme();
|
|
9368
9864
|
let sessionFileArg = [];
|
|
@@ -9384,7 +9880,7 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
9384
9880
|
return line;
|
|
9385
9881
|
}).join(`
|
|
9386
9882
|
`);
|
|
9387
|
-
|
|
9883
|
+
writeFileSync8(localSessionPath, content);
|
|
9388
9884
|
sessionFileArg = ["--session", localSessionPath];
|
|
9389
9885
|
}
|
|
9390
9886
|
} catch {}
|
|
@@ -9400,12 +9896,12 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
9400
9896
|
function trustDroneCwd(localCwd) {
|
|
9401
9897
|
try {
|
|
9402
9898
|
const agentDir = join3(homedir6(), ".pi", "agent");
|
|
9403
|
-
|
|
9899
|
+
mkdirSync11(agentDir, { recursive: true });
|
|
9404
9900
|
const trustPath = join3(agentDir, "trust.json");
|
|
9405
9901
|
const store = existsSync15(trustPath) ? JSON.parse(readFileSync10(trustPath, "utf8")) : {};
|
|
9406
9902
|
if (store[localCwd] !== true) {
|
|
9407
9903
|
store[localCwd] = true;
|
|
9408
|
-
|
|
9904
|
+
writeFileSync8(trustPath, `${JSON.stringify(store, null, "\t")}
|
|
9409
9905
|
`);
|
|
9410
9906
|
}
|
|
9411
9907
|
} catch {}
|
|
@@ -9413,15 +9909,38 @@ function trustDroneCwd(localCwd) {
|
|
|
9413
9909
|
function installRigPiTheme() {
|
|
9414
9910
|
try {
|
|
9415
9911
|
const themesDir = join3(homedir6(), ".pi", "agent", "themes");
|
|
9416
|
-
|
|
9912
|
+
mkdirSync11(themesDir, { recursive: true });
|
|
9417
9913
|
const themePath = join3(themesDir, "rig.json");
|
|
9418
9914
|
const next = `${JSON.stringify(RIG_PI_THEME, null, "\t")}
|
|
9419
9915
|
`;
|
|
9420
9916
|
if (!existsSync15(themePath) || readFileSync10(themePath, "utf8") !== next) {
|
|
9421
|
-
|
|
9917
|
+
writeFileSync8(themePath, next);
|
|
9422
9918
|
}
|
|
9423
9919
|
} catch {}
|
|
9424
9920
|
}
|
|
9921
|
+
async function runWithProcessExitGuard(body) {
|
|
9922
|
+
const realExit = process.exit;
|
|
9923
|
+
let exitCode = 0;
|
|
9924
|
+
let signalQuit = () => {};
|
|
9925
|
+
const quit = new Promise((resolve23) => {
|
|
9926
|
+
signalQuit = resolve23;
|
|
9927
|
+
});
|
|
9928
|
+
const guardedExit = (code) => {
|
|
9929
|
+
exitCode = typeof code === "number" ? code : 0;
|
|
9930
|
+
signalQuit();
|
|
9931
|
+
return;
|
|
9932
|
+
};
|
|
9933
|
+
process.exit = guardedExit;
|
|
9934
|
+
try {
|
|
9935
|
+
await Promise.race([Promise.resolve().then(body), quit]);
|
|
9936
|
+
} finally {
|
|
9937
|
+
process.exit = realExit;
|
|
9938
|
+
}
|
|
9939
|
+
return exitCode;
|
|
9940
|
+
}
|
|
9941
|
+
function runPiMainReturningOnQuit(args, options) {
|
|
9942
|
+
return runWithProcessExitGuard(() => runPiMain(args, options));
|
|
9943
|
+
}
|
|
9425
9944
|
async function attachRunBundledPiFrontend(context, input) {
|
|
9426
9945
|
const tempSessionDir = mkdtempSync(join3(tmpdir(), "rig-pi-frontend-sessions-"));
|
|
9427
9946
|
const { server, sessionFileArg } = await withSpinner(`Opening Pi console for run ${input.runId}\u2026`, () => prepareOperatorConsole(context, input.runId, tempSessionDir), { outputMode: context.outputMode });
|
|
@@ -9437,16 +9956,20 @@ async function attachRunBundledPiFrontend(context, input) {
|
|
|
9437
9956
|
};
|
|
9438
9957
|
let detached = false;
|
|
9439
9958
|
try {
|
|
9440
|
-
|
|
9959
|
+
const piArgs = [
|
|
9441
9960
|
"--offline",
|
|
9442
9961
|
"--no-extensions",
|
|
9443
9962
|
"--no-skills",
|
|
9444
9963
|
"--no-prompt-templates",
|
|
9445
9964
|
"--no-context-files",
|
|
9446
9965
|
...sessionFileArg
|
|
9447
|
-
]
|
|
9448
|
-
|
|
9449
|
-
|
|
9966
|
+
];
|
|
9967
|
+
const piOptions = { extensionFactories: [piRigExtensionFactory] };
|
|
9968
|
+
if (input.returnOnQuit) {
|
|
9969
|
+
await runPiMainReturningOnQuit(piArgs, piOptions);
|
|
9970
|
+
} else {
|
|
9971
|
+
await runPiMain(piArgs, piOptions);
|
|
9972
|
+
}
|
|
9450
9973
|
detached = true;
|
|
9451
9974
|
} finally {
|
|
9452
9975
|
restoreEnv();
|
|
@@ -10175,13 +10698,46 @@ function parseConnection(alias, value, options) {
|
|
|
10175
10698
|
}
|
|
10176
10699
|
return { kind: "remote", baseUrl: parsed.toString().replace(/\/+$/, "") };
|
|
10177
10700
|
}
|
|
10178
|
-
function printJsonOrText(context,
|
|
10179
|
-
if (context.outputMode
|
|
10180
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
10181
|
-
} else {
|
|
10701
|
+
function printJsonOrText(context, _payload, text2) {
|
|
10702
|
+
if (context.outputMode !== "json") {
|
|
10182
10703
|
console.log(text2);
|
|
10183
10704
|
}
|
|
10184
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
|
+
}
|
|
10185
10741
|
async function promptForConnectionAlias(context) {
|
|
10186
10742
|
const state = readGlobalConnections();
|
|
10187
10743
|
const repo = readRepoConnection(context.projectRoot);
|
|
@@ -10235,37 +10791,67 @@ async function executeConnectionCommand(context, args, options) {
|
|
|
10235
10791
|
}
|
|
10236
10792
|
if (!alias)
|
|
10237
10793
|
throw new CliError(`Missing alias. Usage: ${usageName(options)} use <alias|local>`, 1);
|
|
10794
|
+
let selectedConnection = { kind: "local", mode: "auto" };
|
|
10238
10795
|
if (alias !== "local") {
|
|
10239
10796
|
const state = readGlobalConnections();
|
|
10240
|
-
|
|
10797
|
+
const connection = state.connections[alias];
|
|
10798
|
+
if (!connection)
|
|
10241
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;
|
|
10242
10801
|
}
|
|
10243
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);
|
|
10244
10804
|
const repoState = {
|
|
10245
10805
|
selected: alias,
|
|
10246
10806
|
...previousRepo?.project ? { project: previousRepo.project } : {},
|
|
10247
10807
|
linkedAt: new Date().toISOString(),
|
|
10248
|
-
...
|
|
10808
|
+
...preserveRemoteRoot ? {
|
|
10809
|
+
serverProjectRoot: previousRepo.serverProjectRoot,
|
|
10810
|
+
serverProjectRootAlias: previousRepo.serverProjectRootAlias,
|
|
10811
|
+
serverProjectRootBaseUrl: previousRepo.serverProjectRootBaseUrl
|
|
10812
|
+
} : {}
|
|
10249
10813
|
};
|
|
10250
10814
|
writeRepoConnection(context.projectRoot, repoState);
|
|
10251
|
-
|
|
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", [
|
|
10252
10824
|
["selected", alias],
|
|
10253
10825
|
["scope", "this repo"],
|
|
10254
|
-
["
|
|
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"]
|
|
10255
10828
|
]));
|
|
10256
|
-
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 };
|
|
10257
10836
|
}
|
|
10258
10837
|
case "status": {
|
|
10259
10838
|
requireNoExtraArgs(rest, `${usageName(options)} status`);
|
|
10260
10839
|
const repo = readRepoConnection(context.projectRoot);
|
|
10261
10840
|
const global = readGlobalConnections();
|
|
10262
|
-
const
|
|
10263
|
-
|
|
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));
|
|
10264
10850
|
return { ok: true, group: options.group, command: "status", details };
|
|
10265
10851
|
}
|
|
10266
10852
|
default:
|
|
10267
10853
|
throw new CliError(`Unknown ${options.group} command: ${String(command)}
|
|
10268
|
-
Usage: ${usageName(options)} <list|add|use|status>`, 1);
|
|
10854
|
+
Usage: ${usageName(options)} <list|add|use|status|repair-link>`, 1);
|
|
10269
10855
|
}
|
|
10270
10856
|
}
|
|
10271
10857
|
var init_connect = __esm(() => {
|
|
@@ -10273,13 +10859,14 @@ var init_connect = __esm(() => {
|
|
|
10273
10859
|
init_runner();
|
|
10274
10860
|
init__connection_state();
|
|
10275
10861
|
init__cli_format();
|
|
10862
|
+
init__server_client();
|
|
10276
10863
|
});
|
|
10277
10864
|
|
|
10278
10865
|
// packages/cli/src/commands/server.ts
|
|
10279
10866
|
import { resolveRigServerCommand } from "@rig/runtime/local-server";
|
|
10280
10867
|
async function executeServer(context, args, options) {
|
|
10281
10868
|
const [command = "status", ...rest] = args;
|
|
10282
|
-
if (["status", "list", "add", "use"].includes(command)) {
|
|
10869
|
+
if (["status", "list", "add", "use", "repair-link"].includes(command)) {
|
|
10283
10870
|
return executeConnectionCommand(context, [command, ...rest], { group: "server", interactiveUse: true });
|
|
10284
10871
|
}
|
|
10285
10872
|
switch (command) {
|
|
@@ -11066,7 +11653,7 @@ var init_task = __esm(() => {
|
|
|
11066
11653
|
});
|
|
11067
11654
|
|
|
11068
11655
|
// packages/cli/src/commands/task-run-driver.ts
|
|
11069
|
-
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";
|
|
11070
11657
|
import { resolve as resolve24 } from "path";
|
|
11071
11658
|
import { spawn as spawn2, spawnSync as spawnSync4 } from "child_process";
|
|
11072
11659
|
import { createInterface as createLineInterface } from "readline";
|
|
@@ -11169,7 +11756,7 @@ function copyUntrackedDirtyFiles(sourceRoot, targetRoot) {
|
|
|
11169
11756
|
try {
|
|
11170
11757
|
if (!statSync2(sourcePath).isFile())
|
|
11171
11758
|
continue;
|
|
11172
|
-
|
|
11759
|
+
mkdirSync12(resolve24(targetPath, ".."), { recursive: true });
|
|
11173
11760
|
copyFileSync3(sourcePath, targetPath);
|
|
11174
11761
|
copied += 1;
|
|
11175
11762
|
} catch {}
|
|
@@ -12040,8 +12627,8 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
12040
12627
|
artifactPath: planningClassification.planningRequired ? planningArtifactPath : null,
|
|
12041
12628
|
classifiedAt: new Date().toISOString()
|
|
12042
12629
|
};
|
|
12043
|
-
|
|
12044
|
-
|
|
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)}
|
|
12045
12632
|
`, "utf8");
|
|
12046
12633
|
patchAuthorityRun(context.projectRoot, input.runId, { planning: persistedPlanning });
|
|
12047
12634
|
prompt = `${prompt}
|
|
@@ -12188,8 +12775,8 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
12188
12775
|
const dirty = applyDirtyBaselineSnapshot({ sourceRoot: context.projectRoot, targetRoot: latestRuntimeWorkspace });
|
|
12189
12776
|
const readyFile = childEnv.RIG_DIRTY_BASELINE_READY_FILE;
|
|
12190
12777
|
if (readyFile) {
|
|
12191
|
-
|
|
12192
|
-
|
|
12778
|
+
mkdirSync12(resolve24(readyFile, ".."), { recursive: true });
|
|
12779
|
+
writeFileSync9(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
|
|
12193
12780
|
`, "utf8");
|
|
12194
12781
|
}
|
|
12195
12782
|
appendRunLog(context.projectRoot, input.runId, {
|
|
@@ -13135,7 +13722,7 @@ var init_test = __esm(() => {
|
|
|
13135
13722
|
});
|
|
13136
13723
|
|
|
13137
13724
|
// packages/cli/src/commands/setup.ts
|
|
13138
|
-
import { existsSync as existsSync17, mkdirSync as
|
|
13725
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync13, readdirSync as readdirSync3, writeFileSync as writeFileSync10 } from "fs";
|
|
13139
13726
|
import { resolve as resolve25 } from "path";
|
|
13140
13727
|
import { createPluginHost } from "@rig/core";
|
|
13141
13728
|
import {
|
|
@@ -13190,12 +13777,12 @@ function runSetupInit(projectRoot) {
|
|
|
13190
13777
|
const stateDir = resolveControlPlaneHostStateDir(projectRoot);
|
|
13191
13778
|
const logsDir = resolveControlPlaneHostLogsDir(projectRoot);
|
|
13192
13779
|
const artifactsDir = resolveControlPlaneArtifactsDir(projectRoot);
|
|
13193
|
-
|
|
13194
|
-
|
|
13195
|
-
|
|
13780
|
+
mkdirSync13(stateDir, { recursive: true });
|
|
13781
|
+
mkdirSync13(logsDir, { recursive: true });
|
|
13782
|
+
mkdirSync13(artifactsDir, { recursive: true });
|
|
13196
13783
|
const failuresPath = resolve25(stateDir, "failed_approaches.md");
|
|
13197
13784
|
if (!existsSync17(failuresPath)) {
|
|
13198
|
-
|
|
13785
|
+
writeFileSync10(failuresPath, `# Failed Approaches
|
|
13199
13786
|
|
|
13200
13787
|
`, "utf-8");
|
|
13201
13788
|
}
|
|
@@ -14712,414 +15299,23 @@ async function stopFleetRun(ctx, runId) {
|
|
|
14712
15299
|
}
|
|
14713
15300
|
var init_fleet = () => {};
|
|
14714
15301
|
|
|
14715
|
-
// packages/cli/src/app-opentui/
|
|
14716
|
-
|
|
14717
|
-
|
|
14718
|
-
|
|
14719
|
-
|
|
14720
|
-
|
|
14721
|
-
|
|
14722
|
-
}
|
|
14723
|
-
|
|
14724
|
-
|
|
14725
|
-
}
|
|
14726
|
-
|
|
14727
|
-
|
|
14728
|
-
|
|
14729
|
-
|
|
14730
|
-
|
|
14731
|
-
|
|
14732
|
-
}
|
|
14733
|
-
return;
|
|
14734
|
-
}
|
|
14735
|
-
function textAttributesFromCell(cell) {
|
|
14736
|
-
let attributes = TextAttributes.NONE;
|
|
14737
|
-
if (cell.isBold())
|
|
14738
|
-
attributes |= TextAttributes.BOLD;
|
|
14739
|
-
if (cell.isDim())
|
|
14740
|
-
attributes |= TextAttributes.DIM;
|
|
14741
|
-
if (cell.isItalic())
|
|
14742
|
-
attributes |= TextAttributes.ITALIC;
|
|
14743
|
-
if (cell.isUnderline())
|
|
14744
|
-
attributes |= TextAttributes.UNDERLINE;
|
|
14745
|
-
if (cell.isBlink())
|
|
14746
|
-
attributes |= TextAttributes.BLINK;
|
|
14747
|
-
if (cell.isInverse())
|
|
14748
|
-
attributes |= TextAttributes.INVERSE;
|
|
14749
|
-
if (cell.isInvisible())
|
|
14750
|
-
attributes |= TextAttributes.HIDDEN;
|
|
14751
|
-
if (cell.isStrikethrough())
|
|
14752
|
-
attributes |= TextAttributes.STRIKETHROUGH;
|
|
14753
|
-
return attributes;
|
|
14754
|
-
}
|
|
14755
|
-
function sameRgba(a, b) {
|
|
14756
|
-
if (!a && !b)
|
|
14757
|
-
return true;
|
|
14758
|
-
return Boolean(a && b && a.equals(b));
|
|
14759
|
-
}
|
|
14760
|
-
function sameStyle(a, b) {
|
|
14761
|
-
return sameRgba(a.fg, b.fg) && sameRgba(a.bg, b.bg) && (a.attributes ?? 0) === (b.attributes ?? 0);
|
|
14762
|
-
}
|
|
14763
|
-
function styleFromCell(cell) {
|
|
14764
|
-
return {
|
|
14765
|
-
fg: rgbaFromXtermColor(cell.getFgColorMode(), cell.getFgColor()),
|
|
14766
|
-
bg: rgbaFromXtermColor(cell.getBgColorMode(), cell.getBgColor()),
|
|
14767
|
-
attributes: textAttributesFromCell(cell)
|
|
14768
|
-
};
|
|
14769
|
-
}
|
|
14770
|
-
function lineToStyledText(line, cols) {
|
|
14771
|
-
if (!line)
|
|
14772
|
-
return new StyledText([{ __isChunk: true, text: "" }]);
|
|
14773
|
-
const chunks = [];
|
|
14774
|
-
let run = "";
|
|
14775
|
-
let runStyle = null;
|
|
14776
|
-
const flush = () => {
|
|
14777
|
-
if (!run)
|
|
14778
|
-
return;
|
|
14779
|
-
chunks.push({
|
|
14780
|
-
__isChunk: true,
|
|
14781
|
-
text: run,
|
|
14782
|
-
...runStyle?.fg ? { fg: runStyle.fg } : {},
|
|
14783
|
-
...runStyle?.bg ? { bg: runStyle.bg } : {},
|
|
14784
|
-
...(runStyle?.attributes ?? 0) !== 0 ? { attributes: runStyle.attributes } : {}
|
|
14785
|
-
});
|
|
14786
|
-
run = "";
|
|
14787
|
-
};
|
|
14788
|
-
for (let index = 0;index < cols; index += 1) {
|
|
14789
|
-
const cell = line.getCell(index);
|
|
14790
|
-
if (!cell) {
|
|
14791
|
-
if (runStyle !== null)
|
|
14792
|
-
flush();
|
|
14793
|
-
runStyle = null;
|
|
14794
|
-
run += " ";
|
|
14795
|
-
continue;
|
|
14796
|
-
}
|
|
14797
|
-
if (cell.getWidth() === 0)
|
|
14798
|
-
continue;
|
|
14799
|
-
const style = styleFromCell(cell);
|
|
14800
|
-
if (!runStyle || !sameStyle(runStyle, style)) {
|
|
14801
|
-
flush();
|
|
14802
|
-
runStyle = style;
|
|
14803
|
-
}
|
|
14804
|
-
run += cell.getChars() || " ";
|
|
14805
|
-
}
|
|
14806
|
-
flush();
|
|
14807
|
-
return new StyledText(chunks.length > 0 ? chunks : [{ __isChunk: true, text: "" }]);
|
|
14808
|
-
}
|
|
14809
|
-
function childCommandPrefix2() {
|
|
14810
|
-
const execName = basename4(process.execPath).toLowerCase();
|
|
14811
|
-
const currentEntry = process.argv[1];
|
|
14812
|
-
if (execName === "bun" || execName === "bun.exe") {
|
|
14813
|
-
return currentEntry ? [process.execPath, currentEntry, "__opentui-pi-host"] : [process.execPath, fallbackChildScriptPath];
|
|
14814
|
-
}
|
|
14815
|
-
return [process.execPath, "__opentui-pi-host"];
|
|
14816
|
-
}
|
|
14817
|
-
function withEnv2(base) {
|
|
14818
|
-
const env = {};
|
|
14819
|
-
for (const [key, value] of Object.entries(base ?? process.env)) {
|
|
14820
|
-
if (key === "RIG_PLAIN" || key === "RIG_CLI_PLAIN_HELP" || key === "NO_COLOR")
|
|
14821
|
-
continue;
|
|
14822
|
-
if (typeof value === "string")
|
|
14823
|
-
env[key] = value;
|
|
14824
|
-
}
|
|
14825
|
-
return {
|
|
14826
|
-
...env,
|
|
14827
|
-
TERM: "xterm-256color",
|
|
14828
|
-
COLORTERM: "truecolor",
|
|
14829
|
-
FORCE_COLOR: env.FORCE_COLOR ?? "1",
|
|
14830
|
-
RIG_OPENTUI_PI_HOST: "1"
|
|
14831
|
-
};
|
|
14832
|
-
}
|
|
14833
|
-
function getActivePiHost() {
|
|
14834
|
-
return activeHost2 && !activeHost2.disposed ? activeHost2 : null;
|
|
14835
|
-
}
|
|
14836
|
-
async function startPiPtyHost(options) {
|
|
14837
|
-
activeHost2?.dispose("replace");
|
|
14838
|
-
const host = new PiPtyHost(options);
|
|
14839
|
-
activeHost2 = host;
|
|
14840
|
-
await host.start();
|
|
14841
|
-
return host;
|
|
14842
|
-
}
|
|
14843
|
-
function stopActivePiHost(reason = "detach") {
|
|
14844
|
-
activeHost2?.dispose(reason);
|
|
14845
|
-
activeHost2 = null;
|
|
14846
|
-
}
|
|
14847
|
-
|
|
14848
|
-
class PiPtyHost {
|
|
14849
|
-
runId;
|
|
14850
|
-
projectRoot;
|
|
14851
|
-
onSnapshot;
|
|
14852
|
-
onExit;
|
|
14853
|
-
onError;
|
|
14854
|
-
terminal;
|
|
14855
|
-
disposables = [];
|
|
14856
|
-
decoder = new TextDecoder("utf-8");
|
|
14857
|
-
proc = null;
|
|
14858
|
-
pty = null;
|
|
14859
|
-
status = "starting";
|
|
14860
|
-
cols;
|
|
14861
|
-
rows;
|
|
14862
|
-
message = "starting bundled Pi";
|
|
14863
|
-
lastResizeError = null;
|
|
14864
|
-
exitCode;
|
|
14865
|
-
signal;
|
|
14866
|
-
notifyTimer = null;
|
|
14867
|
-
lastStreamKey = "";
|
|
14868
|
-
_disposed = false;
|
|
14869
|
-
constructor(options) {
|
|
14870
|
-
this.runId = options.runId;
|
|
14871
|
-
this.projectRoot = options.projectRoot;
|
|
14872
|
-
this.cols = clampCols2(options.cols);
|
|
14873
|
-
this.rows = clampRows2(options.rows);
|
|
14874
|
-
this.onSnapshot = options.onSnapshot;
|
|
14875
|
-
this.onExit = options.onExit;
|
|
14876
|
-
this.onError = options.onError;
|
|
14877
|
-
this.terminal = new XtermTerminal2({
|
|
14878
|
-
allowProposedApi: true,
|
|
14879
|
-
cols: this.cols,
|
|
14880
|
-
rows: this.rows,
|
|
14881
|
-
scrollback: 1000
|
|
14882
|
-
});
|
|
14883
|
-
this.registerTerminalResponders();
|
|
14884
|
-
this.disposables.push(this.terminal.onWriteParsed(() => {
|
|
14885
|
-
if (this._disposed)
|
|
14886
|
-
return;
|
|
14887
|
-
const snapshot = this.createSnapshot();
|
|
14888
|
-
const key = snapshot.lines.join(`
|
|
14889
|
-
`);
|
|
14890
|
-
if (key === this.lastStreamKey)
|
|
14891
|
-
return;
|
|
14892
|
-
this.lastStreamKey = key;
|
|
14893
|
-
this.onSnapshot?.(snapshot);
|
|
14894
|
-
}));
|
|
14895
|
-
}
|
|
14896
|
-
get disposed() {
|
|
14897
|
-
return this._disposed;
|
|
14898
|
-
}
|
|
14899
|
-
get snapshot() {
|
|
14900
|
-
return this.createSnapshot();
|
|
14901
|
-
}
|
|
14902
|
-
async start() {
|
|
14903
|
-
if (this._disposed)
|
|
14904
|
-
throw new Error("Pi PTY host is disposed.");
|
|
14905
|
-
if (typeof Bun.Terminal !== "function") {
|
|
14906
|
-
throw new Error("Bun native PTY is unavailable in this runtime. Pi host requires Bun.Terminal.");
|
|
14907
|
-
}
|
|
14908
|
-
const spawnOptions = {
|
|
14909
|
-
cwd: this.projectRoot,
|
|
14910
|
-
env: withEnv2(process.env),
|
|
14911
|
-
terminal: {
|
|
14912
|
-
cols: this.cols,
|
|
14913
|
-
rows: this.rows,
|
|
14914
|
-
name: "xterm-256color",
|
|
14915
|
-
data: (_terminal, data) => this.handlePtyData(data)
|
|
14916
|
-
}
|
|
14917
|
-
};
|
|
14918
|
-
const proc = Bun.spawn([
|
|
14919
|
-
...childCommandPrefix2(),
|
|
14920
|
-
"--run-id",
|
|
14921
|
-
this.runId,
|
|
14922
|
-
"--project-root",
|
|
14923
|
-
this.projectRoot
|
|
14924
|
-
], spawnOptions);
|
|
14925
|
-
if (!proc.terminal)
|
|
14926
|
-
throw new Error("Bun did not attach a terminal to the bundled Pi child process.");
|
|
14927
|
-
this.proc = proc;
|
|
14928
|
-
this.pty = proc.terminal;
|
|
14929
|
-
this.status = "running";
|
|
14930
|
-
this.message = "bundled Pi running inside this app";
|
|
14931
|
-
this.emitSnapshotSoon(0);
|
|
14932
|
-
proc.exited.then((exitCode) => {
|
|
14933
|
-
if (this._disposed)
|
|
14934
|
-
return;
|
|
14935
|
-
this.status = exitCode === 0 ? "exited" : "failed";
|
|
14936
|
-
this.exitCode = exitCode;
|
|
14937
|
-
this.signal = null;
|
|
14938
|
-
this.message = exitCode === 0 ? "bundled Pi exited" : `bundled Pi exited with code ${exitCode}`;
|
|
14939
|
-
const snapshot = this.createSnapshot();
|
|
14940
|
-
this.onSnapshot?.(snapshot);
|
|
14941
|
-
this.onExit?.(snapshot);
|
|
14942
|
-
if (activeHost2 === this)
|
|
14943
|
-
activeHost2 = null;
|
|
14944
|
-
this.dispose("exit", { kill: false, notify: false });
|
|
14945
|
-
}).catch((error) => {
|
|
14946
|
-
if (this._disposed)
|
|
14947
|
-
return;
|
|
14948
|
-
this.status = "failed";
|
|
14949
|
-
this.message = error instanceof Error ? error.message : String(error);
|
|
14950
|
-
const snapshot = this.createSnapshot();
|
|
14951
|
-
this.onSnapshot?.(snapshot);
|
|
14952
|
-
this.onError?.(error, snapshot);
|
|
14953
|
-
if (activeHost2 === this)
|
|
14954
|
-
activeHost2 = null;
|
|
14955
|
-
this.dispose("error", { kill: false, notify: false });
|
|
14956
|
-
});
|
|
14957
|
-
}
|
|
14958
|
-
write(data) {
|
|
14959
|
-
if (this._disposed || !this.pty)
|
|
14960
|
-
return;
|
|
14961
|
-
try {
|
|
14962
|
-
this.pty.write(data);
|
|
14963
|
-
} catch (error) {
|
|
14964
|
-
this.status = "failed";
|
|
14965
|
-
this.message = error instanceof Error ? error.message : String(error);
|
|
14966
|
-
const snapshot = this.createSnapshot();
|
|
14967
|
-
this.onSnapshot?.(snapshot);
|
|
14968
|
-
this.onError?.(error, snapshot);
|
|
14969
|
-
}
|
|
14970
|
-
}
|
|
14971
|
-
resize(cols, rows) {
|
|
14972
|
-
const nextCols = clampCols2(cols);
|
|
14973
|
-
const nextRows = clampRows2(rows);
|
|
14974
|
-
if (nextCols === this.cols && nextRows === this.rows)
|
|
14975
|
-
return;
|
|
14976
|
-
this.cols = nextCols;
|
|
14977
|
-
this.rows = nextRows;
|
|
14978
|
-
this.terminal.resize(nextCols, nextRows);
|
|
14979
|
-
try {
|
|
14980
|
-
this.pty?.resize(nextCols, nextRows);
|
|
14981
|
-
this.lastResizeError = null;
|
|
14982
|
-
} catch (error) {
|
|
14983
|
-
this.lastResizeError = error instanceof Error ? error.message : String(error);
|
|
14984
|
-
}
|
|
14985
|
-
this.emitSnapshotSoon(0);
|
|
14986
|
-
}
|
|
14987
|
-
detach() {
|
|
14988
|
-
this.dispose("detach");
|
|
14989
|
-
return this.createSnapshot("detached from bundled Pi");
|
|
14990
|
-
}
|
|
14991
|
-
dispose(reason = "dispose", options = {}) {
|
|
14992
|
-
if (this._disposed)
|
|
14993
|
-
return;
|
|
14994
|
-
this._disposed = true;
|
|
14995
|
-
if (this.notifyTimer)
|
|
14996
|
-
clearTimeout(this.notifyTimer);
|
|
14997
|
-
this.notifyTimer = null;
|
|
14998
|
-
for (const disposable of this.disposables.splice(0)) {
|
|
14999
|
-
try {
|
|
15000
|
-
disposable.dispose();
|
|
15001
|
-
} catch {}
|
|
15002
|
-
}
|
|
15003
|
-
if (options.kill !== false) {
|
|
15004
|
-
try {
|
|
15005
|
-
this.proc?.kill("SIGTERM");
|
|
15006
|
-
} catch {}
|
|
15007
|
-
}
|
|
15008
|
-
try {
|
|
15009
|
-
this.pty?.close();
|
|
15010
|
-
} catch {}
|
|
15011
|
-
try {
|
|
15012
|
-
this.terminal.dispose();
|
|
15013
|
-
} catch {}
|
|
15014
|
-
if (activeHost2 === this)
|
|
15015
|
-
activeHost2 = null;
|
|
15016
|
-
if (options.notify) {
|
|
15017
|
-
this.message = reason;
|
|
15018
|
-
this.onSnapshot?.(this.createSnapshot(reason));
|
|
15019
|
-
}
|
|
15020
|
-
}
|
|
15021
|
-
handlePtyData(data) {
|
|
15022
|
-
if (this._disposed)
|
|
15023
|
-
return;
|
|
15024
|
-
const text2 = this.decoder.decode(data, { stream: true });
|
|
15025
|
-
this.respondToRawTerminalQueries(text2);
|
|
15026
|
-
this.terminal.write(data);
|
|
15027
|
-
}
|
|
15028
|
-
emitSnapshotSoon(delayMs = SNAPSHOT_DELAY_MS2) {
|
|
15029
|
-
if (this._disposed || this.notifyTimer)
|
|
15030
|
-
return;
|
|
15031
|
-
this.notifyTimer = setTimeout(() => {
|
|
15032
|
-
this.notifyTimer = null;
|
|
15033
|
-
if (this._disposed)
|
|
15034
|
-
return;
|
|
15035
|
-
this.onSnapshot?.(this.createSnapshot());
|
|
15036
|
-
}, delayMs);
|
|
15037
|
-
}
|
|
15038
|
-
createSnapshot(message2 = this.message) {
|
|
15039
|
-
const buffer = this.terminal.buffer.active;
|
|
15040
|
-
const end = buffer.length;
|
|
15041
|
-
const start = Math.max(0, end - MAX_SNAPSHOT_LINES2);
|
|
15042
|
-
const styledStart = Math.max(start, end - this.rows - STYLED_SNAPSHOT_MARGIN);
|
|
15043
|
-
const lines = [];
|
|
15044
|
-
const styledLines = [];
|
|
15045
|
-
for (let row = start;row < end; row += 1) {
|
|
15046
|
-
const line = buffer.getLine(row);
|
|
15047
|
-
lines.push((line?.translateToString(false) ?? "").slice(0, this.cols));
|
|
15048
|
-
if (row >= styledStart)
|
|
15049
|
-
styledLines[lines.length - 1] = lineToStyledText(line, this.cols);
|
|
15050
|
-
}
|
|
15051
|
-
while (lines.length < this.rows) {
|
|
15052
|
-
lines.push("");
|
|
15053
|
-
styledLines[lines.length - 1] = new StyledText([{ __isChunk: true, text: "" }]);
|
|
15054
|
-
}
|
|
15055
|
-
const resolvedMessage = this.lastResizeError ? `resize degraded: ${this.lastResizeError}` : message2;
|
|
15056
|
-
return {
|
|
15057
|
-
runId: this.runId,
|
|
15058
|
-
status: this.status,
|
|
15059
|
-
cols: this.cols,
|
|
15060
|
-
rows: this.rows,
|
|
15061
|
-
lines,
|
|
15062
|
-
styledLines,
|
|
15063
|
-
message: resolvedMessage,
|
|
15064
|
-
...this.lastResizeError ? { resizeError: this.lastResizeError } : {},
|
|
15065
|
-
...this.exitCode !== undefined ? { exitCode: this.exitCode } : {},
|
|
15066
|
-
...this.signal !== undefined ? { signal: this.signal } : {}
|
|
15067
|
-
};
|
|
15068
|
-
}
|
|
15069
|
-
registerTerminalResponders() {
|
|
15070
|
-
this.disposables.push(this.terminal.parser.registerCsiHandler({ final: "c" }, (params) => {
|
|
15071
|
-
if (params.length === 0 || params[0] === 0)
|
|
15072
|
-
this.write("\x1B[?62;22c");
|
|
15073
|
-
return false;
|
|
15074
|
-
}));
|
|
15075
|
-
this.disposables.push(this.terminal.parser.registerCsiHandler({ prefix: ">", final: "c" }, (params) => {
|
|
15076
|
-
if (params.length === 0 || params[0] === 0)
|
|
15077
|
-
this.write("\x1B[>0;0;0c");
|
|
15078
|
-
return false;
|
|
15079
|
-
}));
|
|
15080
|
-
this.disposables.push(this.terminal.parser.registerCsiHandler({ final: "n" }, (params) => {
|
|
15081
|
-
if (params[0] === 5) {
|
|
15082
|
-
this.write("\x1B[0n");
|
|
15083
|
-
} else if (params[0] === 6) {
|
|
15084
|
-
const row = this.terminal.buffer.active.cursorY + 1;
|
|
15085
|
-
const col = this.terminal.buffer.active.cursorX + 1;
|
|
15086
|
-
this.write(`\x1B[${row};${col}R`);
|
|
15087
|
-
}
|
|
15088
|
-
return false;
|
|
15089
|
-
}));
|
|
15090
|
-
}
|
|
15091
|
-
respondToRawTerminalQueries(text2) {
|
|
15092
|
-
if (!text2)
|
|
15093
|
-
return;
|
|
15094
|
-
const decrqm = /\x1b\[\?(\d+)\$p/g;
|
|
15095
|
-
let match;
|
|
15096
|
-
while ((match = decrqm.exec(text2)) !== null) {
|
|
15097
|
-
this.write(`\x1B[?${match[1]};2$y`);
|
|
15098
|
-
}
|
|
15099
|
-
}
|
|
15100
|
-
}
|
|
15101
|
-
var MIN_COLS2 = 40, MIN_ROWS2 = 12, MAX_ROWS2 = 300, MAX_SNAPSHOT_LINES2 = 360, STYLED_SNAPSHOT_MARGIN = 6, SNAPSHOT_DELAY_MS2 = 120, fallbackChildScriptPath, activeHost2 = null, XTERM_COLOR_MODE_INDEXED_16 = 16777216, XTERM_COLOR_MODE_INDEXED_256 = 33554432, XTERM_COLOR_MODE_RGB = 50331648;
|
|
15102
|
-
var init_pi_pty_host = __esm(() => {
|
|
15103
|
-
fallbackChildScriptPath = fileURLToPath2(new URL("./pi-host-child.ts", import.meta.url));
|
|
15104
|
-
});
|
|
15105
|
-
|
|
15106
|
-
// packages/cli/src/app-opentui/adapters/inspect.ts
|
|
15107
|
-
var exports_inspect = {};
|
|
15108
|
-
__export(exports_inspect, {
|
|
15109
|
-
loadInspectRuns: () => loadInspectRuns,
|
|
15110
|
-
loadInspect: () => loadInspect,
|
|
15111
|
-
INSPECT_VIEWS: () => INSPECT_VIEWS
|
|
15112
|
-
});
|
|
15113
|
-
import { execFile } from "child_process";
|
|
15114
|
-
import { existsSync as existsSync21, readFileSync as readFileSync14, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
|
|
15115
|
-
import { resolve as resolve28 } from "path";
|
|
15116
|
-
import { promisify } from "util";
|
|
15117
|
-
import { resolveTaskArtifactDirs as resolveTaskArtifactDirs3 } from "@rig/runtime/control-plane/authority-files";
|
|
15118
|
-
import { readTaskArtifactPreview as readTaskArtifactPreview2 } from "@rig/runtime/control-plane/native/workspace-ops";
|
|
15119
|
-
import { resolveHarnessPaths as resolveHarnessPaths3, resolveMonorepoRoot as resolveMonorepoRoot3, runCapture as runCapture4 } from "@rig/runtime/control-plane/native/utils";
|
|
15120
|
-
function isFailureEntry(entry) {
|
|
15121
|
-
const status = `${entry.status ?? entry.level ?? entry.type ?? ""}`.toLowerCase();
|
|
15122
|
-
return status.includes("fail") || status.includes("error");
|
|
15302
|
+
// packages/cli/src/app-opentui/adapters/inspect.ts
|
|
15303
|
+
var exports_inspect = {};
|
|
15304
|
+
__export(exports_inspect, {
|
|
15305
|
+
loadInspectRuns: () => loadInspectRuns,
|
|
15306
|
+
loadInspect: () => loadInspect,
|
|
15307
|
+
INSPECT_VIEWS: () => INSPECT_VIEWS
|
|
15308
|
+
});
|
|
15309
|
+
import { execFile } from "child_process";
|
|
15310
|
+
import { existsSync as existsSync21, readFileSync as readFileSync14, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
|
|
15311
|
+
import { resolve as resolve28 } from "path";
|
|
15312
|
+
import { promisify } from "util";
|
|
15313
|
+
import { resolveTaskArtifactDirs as resolveTaskArtifactDirs3 } from "@rig/runtime/control-plane/authority-files";
|
|
15314
|
+
import { readTaskArtifactPreview as readTaskArtifactPreview2 } from "@rig/runtime/control-plane/native/workspace-ops";
|
|
15315
|
+
import { resolveHarnessPaths as resolveHarnessPaths3, resolveMonorepoRoot as resolveMonorepoRoot3, runCapture as runCapture4 } from "@rig/runtime/control-plane/native/utils";
|
|
15316
|
+
function isFailureEntry(entry) {
|
|
15317
|
+
const status = `${entry.status ?? entry.level ?? entry.type ?? ""}`.toLowerCase();
|
|
15318
|
+
return status.includes("fail") || status.includes("error");
|
|
15123
15319
|
}
|
|
15124
15320
|
async function gitDiff(projectRoot) {
|
|
15125
15321
|
try {
|
|
@@ -15325,14 +15521,6 @@ function recordStep(ctx, runId, label, emitLabel) {
|
|
|
15325
15521
|
});
|
|
15326
15522
|
emitProgress(ctx, emitLabel, label);
|
|
15327
15523
|
}
|
|
15328
|
-
function settleSteps(ctx, runId) {
|
|
15329
|
-
const now = Date.now();
|
|
15330
|
-
const previous = currentAttachState(ctx, runId);
|
|
15331
|
-
if (!previous?.steps)
|
|
15332
|
-
return;
|
|
15333
|
-
const steps = previous.steps.map((step) => step.status === "running" ? { ...step, status: "done", endedAtMs: step.endedAtMs ?? now } : step);
|
|
15334
|
-
patchData(ctx, { piAttach: { ...previous, steps } });
|
|
15335
|
-
}
|
|
15336
15524
|
async function preparePiAttachHandoff(ctx, runId) {
|
|
15337
15525
|
const cleanRunId = runId.trim();
|
|
15338
15526
|
const label = `Preparing Pi ${cleanRunId.slice(0, 8)}`;
|
|
@@ -15380,85 +15568,41 @@ async function attachRunWithBundledPi(ctx, runId) {
|
|
|
15380
15568
|
throw error;
|
|
15381
15569
|
}
|
|
15382
15570
|
emitStarted(ctx, label, { piAttach: { runId: cleanRunId, status: "entering-pi" } });
|
|
15383
|
-
patchData(ctx, { piAttach: { runId: cleanRunId, status: "entering-pi", message: "
|
|
15571
|
+
patchData(ctx, { piAttach: { runId: cleanRunId, status: "entering-pi", message: "handing the terminal to worker Pi\u2026" } });
|
|
15572
|
+
const projectRoot = projectRootOf(ctx);
|
|
15573
|
+
const outputMode = ctx.rig?.outputMode ?? "text";
|
|
15574
|
+
await releaseRendererForExternalTui(ctx);
|
|
15575
|
+
let outcome = null;
|
|
15576
|
+
let attachError = null;
|
|
15384
15577
|
try {
|
|
15385
|
-
|
|
15386
|
-
await
|
|
15387
|
-
patchData(ctx, { lastRefreshError: normalizeAppError(error).message });
|
|
15388
|
-
return null;
|
|
15389
|
-
});
|
|
15390
|
-
recordStep(ctx, cleanRunId, "spawning Bun PTY host for bundled Pi", label);
|
|
15391
|
-
const projectRoot = projectRootOf(ctx);
|
|
15392
|
-
const cols = typeof process.stdout.columns === "number" ? process.stdout.columns : 100;
|
|
15393
|
-
const rows = Math.max(1, (typeof process.stdout.rows === "number" ? process.stdout.rows : 35) - 1);
|
|
15394
|
-
const patchTerminal = (snapshot) => {
|
|
15395
|
-
const previousSteps = currentAttachState(ctx, cleanRunId)?.steps;
|
|
15396
|
-
const failed = snapshot.status === "failed";
|
|
15397
|
-
const reason = failed ? snapshot.message ?? `bundled Pi exited with code ${snapshot.exitCode ?? "unknown"}` : undefined;
|
|
15398
|
-
patchData(ctx, {
|
|
15399
|
-
piTerminal: snapshot,
|
|
15400
|
-
piAttach: {
|
|
15401
|
-
runId: cleanRunId,
|
|
15402
|
-
status: failed ? "failed" : snapshot.status === "exited" ? "returned" : "entering-pi",
|
|
15403
|
-
message: snapshot.message ?? "bundled Pi running",
|
|
15404
|
-
result: { runId: cleanRunId, status: snapshot.status, exitCode: snapshot.exitCode },
|
|
15405
|
-
...previousSteps ? { steps: previousSteps } : {},
|
|
15406
|
-
...reason ? { failureReason: reason } : {}
|
|
15407
|
-
}
|
|
15408
|
-
});
|
|
15409
|
-
};
|
|
15410
|
-
recordStep(ctx, cleanRunId, "starting bundled Pi", label);
|
|
15411
|
-
await startPiPtyHost({
|
|
15412
|
-
runId: cleanRunId,
|
|
15413
|
-
projectRoot,
|
|
15414
|
-
cols,
|
|
15415
|
-
rows,
|
|
15416
|
-
onSnapshot: (snapshot) => {
|
|
15417
|
-
if (snapshot.status === "running" && snapshot.lines.some((entry) => entry.trim().length > 0)) {
|
|
15418
|
-
settleSteps(ctx, cleanRunId);
|
|
15419
|
-
}
|
|
15420
|
-
patchTerminal(snapshot);
|
|
15421
|
-
},
|
|
15422
|
-
onExit: (snapshot) => {
|
|
15423
|
-
patchTerminal(snapshot);
|
|
15424
|
-
if (snapshot.status === "failed") {
|
|
15425
|
-
Promise.resolve().then(() => (init_inspect2(), exports_inspect)).then(({ loadInspect: loadInspect2 }) => loadInspect2(ctx, cleanRunId)).catch(() => null);
|
|
15426
|
-
emitFailed(ctx, label, new Error(snapshot.message ?? `bundled Pi exited with code ${snapshot.exitCode ?? "unknown"}`), { runId: cleanRunId, result: { status: snapshot.status, exitCode: snapshot.exitCode } });
|
|
15427
|
-
return;
|
|
15428
|
-
}
|
|
15429
|
-
emitCompleted(ctx, label, { runId: cleanRunId, result: { status: snapshot.status, exitCode: snapshot.exitCode } });
|
|
15430
|
-
ctx.emit({ type: "scene.change", scene: "fleet", intent: { scene: "fleet", argv: ["runs"], action: { kind: "refresh", label: "Opening runs" } } });
|
|
15431
|
-
refreshFleet(ctx).catch((error) => emitFailed(ctx, "Refresh runs", error));
|
|
15432
|
-
},
|
|
15433
|
-
onError: (error, snapshot) => {
|
|
15434
|
-
patchTerminal(snapshot);
|
|
15435
|
-
emitFailed(ctx, label, error, { runId: cleanRunId });
|
|
15436
|
-
}
|
|
15437
|
-
});
|
|
15438
|
-
const record = {
|
|
15439
|
-
runId: cleanRunId,
|
|
15440
|
-
status: "running",
|
|
15441
|
-
rendered: "bundled Pi embedded via Bun.Terminal + @xterm/headless"
|
|
15442
|
-
};
|
|
15443
|
-
emitProgress(ctx, label, "bundled Pi is running", { piAttach: { runId: cleanRunId, status: "entering-pi", message: "bundled Pi running", result: record } });
|
|
15444
|
-
return record;
|
|
15578
|
+
const { attachRunBundledPiFrontend: attachRunBundledPiFrontend2 } = await Promise.resolve().then(() => (init__pi_frontend(), exports__pi_frontend));
|
|
15579
|
+
outcome = await attachRunBundledPiFrontend2({ projectRoot, outputMode }, { runId: cleanRunId, returnOnQuit: true });
|
|
15445
15580
|
} catch (error) {
|
|
15446
|
-
|
|
15581
|
+
attachError = error;
|
|
15582
|
+
} finally {
|
|
15583
|
+
await resumeRendererAfterExternalTui(ctx);
|
|
15584
|
+
}
|
|
15585
|
+
if (attachError) {
|
|
15586
|
+
const reason = normalizeAppError(attachError).message;
|
|
15447
15587
|
patchData(ctx, {
|
|
15448
|
-
|
|
15449
|
-
|
|
15450
|
-
status: "failed",
|
|
15451
|
-
message: reason,
|
|
15452
|
-
failureReason: reason,
|
|
15453
|
-
...currentAttachState(ctx, cleanRunId)?.steps ? { steps: currentAttachState(ctx, cleanRunId).steps } : {}
|
|
15454
|
-
}
|
|
15588
|
+
piTerminal: undefined,
|
|
15589
|
+
piAttach: { runId: cleanRunId, status: "failed", message: reason, failureReason: reason }
|
|
15455
15590
|
});
|
|
15456
|
-
|
|
15457
|
-
|
|
15591
|
+
Promise.resolve().then(() => (init_inspect2(), exports_inspect)).then(({ loadInspect: loadInspect2 }) => loadInspect2(ctx, cleanRunId)).catch(() => null);
|
|
15592
|
+
emitFailed(ctx, label, attachError, { runId: cleanRunId });
|
|
15593
|
+
throw attachError;
|
|
15458
15594
|
}
|
|
15595
|
+
const detached = outcome?.detached === true;
|
|
15596
|
+
patchData(ctx, {
|
|
15597
|
+
piTerminal: undefined,
|
|
15598
|
+
piAttach: { runId: cleanRunId, status: "returned", message: detached ? "detached from worker Pi" : "returned from worker Pi" }
|
|
15599
|
+
});
|
|
15600
|
+
emitCompleted(ctx, label, { runId: cleanRunId, result: { runId: cleanRunId, detached } });
|
|
15601
|
+
ctx.emit({ type: "scene.change", scene: "fleet", intent: { scene: "fleet", argv: ["runs"], action: { kind: "refresh", label: "Opening runs" } } });
|
|
15602
|
+
refreshFleet(ctx).catch((error) => emitFailed(ctx, "Refresh runs", error));
|
|
15603
|
+
return { runId: cleanRunId, status: "returned", detached };
|
|
15459
15604
|
}
|
|
15460
15605
|
var init_pi_attach = __esm(() => {
|
|
15461
|
-
init_pi_pty_host();
|
|
15462
15606
|
init_fleet();
|
|
15463
15607
|
});
|
|
15464
15608
|
|
|
@@ -15510,7 +15654,7 @@ import {
|
|
|
15510
15654
|
dim as otuiDim,
|
|
15511
15655
|
fg as otuiFg,
|
|
15512
15656
|
t,
|
|
15513
|
-
TextAttributes
|
|
15657
|
+
TextAttributes
|
|
15514
15658
|
} from "@opentui/core";
|
|
15515
15659
|
function statusColor3(status) {
|
|
15516
15660
|
switch (status) {
|
|
@@ -15615,7 +15759,7 @@ var init_theme2 = __esm(() => {
|
|
|
15615
15759
|
});
|
|
15616
15760
|
|
|
15617
15761
|
// packages/cli/src/app-opentui/drone.ts
|
|
15618
|
-
import { RGBA
|
|
15762
|
+
import { RGBA, StyledText, TextAttributes as TextAttributes2 } from "@opentui/core";
|
|
15619
15763
|
function bladeForTick(tick, phase = 0) {
|
|
15620
15764
|
return BLADE_FRAMES2[(Math.floor(tick / 3) + phase) % BLADE_FRAMES2.length];
|
|
15621
15765
|
}
|
|
@@ -15624,12 +15768,12 @@ function eyeForTick(tick, phase = 0) {
|
|
|
15624
15768
|
return pulse > 0.55 ? EYE_FRAMES2[1] : pulse > 0.1 ? EYE_FRAMES2[0] : pulse > -0.45 ? EYE_FRAMES2[2] : EYE_FRAMES2[3];
|
|
15625
15769
|
}
|
|
15626
15770
|
function chunk(text2, fg2, bold2 = false, dim = false) {
|
|
15627
|
-
let attributes =
|
|
15771
|
+
let attributes = TextAttributes2.NONE;
|
|
15628
15772
|
if (bold2)
|
|
15629
|
-
attributes |=
|
|
15773
|
+
attributes |= TextAttributes2.BOLD;
|
|
15630
15774
|
if (dim)
|
|
15631
|
-
attributes |=
|
|
15632
|
-
return { __isChunk: true, text: text2, fg: fg2, ...attributes !==
|
|
15775
|
+
attributes |= TextAttributes2.DIM;
|
|
15776
|
+
return { __isChunk: true, text: text2, fg: fg2, ...attributes !== TextAttributes2.NONE ? { attributes } : {} };
|
|
15633
15777
|
}
|
|
15634
15778
|
function styledLine(text2, colorFor) {
|
|
15635
15779
|
const chunks = [];
|
|
@@ -15650,7 +15794,7 @@ function styledLine(text2, colorFor) {
|
|
|
15650
15794
|
run += char;
|
|
15651
15795
|
}
|
|
15652
15796
|
flush();
|
|
15653
|
-
return new
|
|
15797
|
+
return new StyledText(chunks.length > 0 ? chunks : [chunk("", COLOR.ink)]);
|
|
15654
15798
|
}
|
|
15655
15799
|
function droneColor(char) {
|
|
15656
15800
|
if (char === "?" || char === "o" || char === "@" || char === "\u2022")
|
|
@@ -15742,13 +15886,13 @@ var init_drone = __esm(() => {
|
|
|
15742
15886
|
BLADE_FRAMES2 = ["---", "\\\\\\", "|||", "///"];
|
|
15743
15887
|
EYE_FRAMES2 = ["o", "@", "\u2022", "."];
|
|
15744
15888
|
COLOR = {
|
|
15745
|
-
body:
|
|
15746
|
-
mini:
|
|
15747
|
-
rotor:
|
|
15748
|
-
path:
|
|
15749
|
-
eye:
|
|
15750
|
-
dim:
|
|
15751
|
-
ink:
|
|
15889
|
+
body: RGBA.fromHex(RIG_UI.lime),
|
|
15890
|
+
mini: RGBA.fromHex(RIG_UI.limeDim),
|
|
15891
|
+
rotor: RGBA.fromHex(RIG_UI.cyan),
|
|
15892
|
+
path: RGBA.fromHex(RIG_UI.cyan),
|
|
15893
|
+
eye: RGBA.fromHex(RIG_UI.ink),
|
|
15894
|
+
dim: RGBA.fromHex(RIG_UI.ink4),
|
|
15895
|
+
ink: RGBA.fromHex(RIG_UI.ink2)
|
|
15752
15896
|
};
|
|
15753
15897
|
});
|
|
15754
15898
|
|
|
@@ -15822,6 +15966,51 @@ var init_selectable = __esm(() => {
|
|
|
15822
15966
|
init_scene();
|
|
15823
15967
|
});
|
|
15824
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
|
+
|
|
15825
16014
|
// packages/cli/src/app-opentui/fleet-stats.ts
|
|
15826
16015
|
function normalizeStatus(status) {
|
|
15827
16016
|
return status.replace(/_/g, "-").toLowerCase();
|
|
@@ -16012,7 +16201,9 @@ import {
|
|
|
16012
16201
|
RigInboxInputsOutput,
|
|
16013
16202
|
RigRunListOutput,
|
|
16014
16203
|
RigRunShowOutput,
|
|
16204
|
+
RigServerRepairLinkOutput,
|
|
16015
16205
|
RigServerStatusOutput,
|
|
16206
|
+
RigServerUseOutput,
|
|
16016
16207
|
RigStatsOutput,
|
|
16017
16208
|
RigTaskListOutput,
|
|
16018
16209
|
RigTaskShowOutput
|
|
@@ -16048,7 +16239,9 @@ var init__json_output = __esm(() => {
|
|
|
16048
16239
|
"task show": RigTaskShowOutput,
|
|
16049
16240
|
"run list": RigRunListOutput,
|
|
16050
16241
|
"run show": RigRunShowOutput,
|
|
16242
|
+
"server use": RigServerUseOutput,
|
|
16051
16243
|
"server status": RigServerStatusOutput,
|
|
16244
|
+
"server repair-link": RigServerRepairLinkOutput,
|
|
16052
16245
|
"inbox approvals": RigInboxApprovalsOutput,
|
|
16053
16246
|
"inbox inputs": RigInboxInputsOutput,
|
|
16054
16247
|
"doctor check": RigDoctorCheckOutput,
|
|
@@ -16058,7 +16251,7 @@ var init__json_output = __esm(() => {
|
|
|
16058
16251
|
|
|
16059
16252
|
// packages/cli/src/launcher.ts
|
|
16060
16253
|
import { existsSync as existsSync22 } from "fs";
|
|
16061
|
-
import { basename as
|
|
16254
|
+
import { basename as basename4, resolve as resolve29 } from "path";
|
|
16062
16255
|
import { loadDotEnvSecrets } from "@rig/runtime/baked-secrets";
|
|
16063
16256
|
import { RIG_DEFINITION_DIRNAME, RIG_STATE_DIRNAME, resolveNearestRigProjectRoot } from "@rig/runtime/layout";
|
|
16064
16257
|
function parsePolicyMode(value) {
|
|
@@ -16083,7 +16276,7 @@ function resolveProjectRoot({
|
|
|
16083
16276
|
return resolve29(cwd, envProjectRoot);
|
|
16084
16277
|
}
|
|
16085
16278
|
const fallbackImportDir = importDir ?? cwd;
|
|
16086
|
-
const execName =
|
|
16279
|
+
const execName = basename4(execPath).toLowerCase();
|
|
16087
16280
|
const execCandidates = execName === "rig" || execName === "rig.exe" ? [resolve29(execPath, "..", "..")] : [];
|
|
16088
16281
|
const candidates = [cwd, ...execCandidates, resolve29(fallbackImportDir, "..")];
|
|
16089
16282
|
for (const candidate of candidates) {
|
|
@@ -16379,16 +16572,31 @@ function taskViewIntent(argv, command = "", rest = [], raw) {
|
|
|
16379
16572
|
const { payload, label } = taskViewPayload(command, rest);
|
|
16380
16573
|
return intent("tasks", argv, "refresh", payload, label, raw);
|
|
16381
16574
|
}
|
|
16382
|
-
function routeServer(argv, command, raw, checkingLabel) {
|
|
16383
|
-
if (!command || command === "status") {
|
|
16575
|
+
function routeServer(argv, command, rest, raw, checkingLabel) {
|
|
16576
|
+
if (!command || command === "status" || command === "list") {
|
|
16384
16577
|
return intent("server", argv, "refresh", undefined, command ? checkingLabel : "Loading server", raw);
|
|
16385
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);
|
|
16386
16591
|
return commandRunIntent(argv, raw);
|
|
16387
16592
|
}
|
|
16388
16593
|
function routeGithub(argv, command, rest, raw) {
|
|
16389
16594
|
if (command === "auth" && (rest[0]?.toLowerCase() ?? "status") === "status" && rest.length <= 1) {
|
|
16390
16595
|
return intent("server", argv, "refresh", undefined, "Checking GitHub auth", raw);
|
|
16391
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
|
+
}
|
|
16392
16600
|
return commandRunIntent(argv, raw);
|
|
16393
16601
|
}
|
|
16394
16602
|
function routeDoctor(argv, command, raw) {
|
|
@@ -16437,11 +16645,16 @@ function intentFromArgv(argv) {
|
|
|
16437
16645
|
return commandRunIntent(argv);
|
|
16438
16646
|
}
|
|
16439
16647
|
if (normalizedGroup === "server")
|
|
16440
|
-
return routeServer(argv, normalizedCommand, undefined, "Checking server");
|
|
16648
|
+
return routeServer(argv, normalizedCommand, rest, undefined, "Checking server");
|
|
16441
16649
|
if (normalizedGroup === "github")
|
|
16442
16650
|
return routeGithub(argv, normalizedCommand, rest);
|
|
16443
|
-
if (normalizedGroup === "init")
|
|
16444
|
-
|
|
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
|
+
}
|
|
16445
16658
|
if (normalizedGroup === "doctor")
|
|
16446
16659
|
return routeDoctor(argv, normalizedCommand);
|
|
16447
16660
|
if (normalizedGroup === "inbox")
|
|
@@ -16504,12 +16717,17 @@ function intentFromTypeBar(value) {
|
|
|
16504
16717
|
return commandRunIntent(parts, value);
|
|
16505
16718
|
return intent("tasks", parts, "refresh", undefined, "Select a task, then press Enter; or use run next", value);
|
|
16506
16719
|
}
|
|
16507
|
-
if (first === "init")
|
|
16508
|
-
|
|
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
|
+
}
|
|
16509
16727
|
if (first === "doctor")
|
|
16510
16728
|
return routeDoctor(parts, second, value);
|
|
16511
16729
|
if (first === "server")
|
|
16512
|
-
return routeServer(parts, second, value, "Loading server");
|
|
16730
|
+
return routeServer(parts, second, rest, value, "Loading server");
|
|
16513
16731
|
if (first === "github")
|
|
16514
16732
|
return routeGithub(parts, second, rest, value);
|
|
16515
16733
|
if (first === "inbox")
|
|
@@ -16960,22 +17178,15 @@ function clearTypeBar(context, message2) {
|
|
|
16960
17178
|
context.emitTypeBarPatch({ value: "", mode: "nav", prompt: undefined, message: message2 });
|
|
16961
17179
|
}
|
|
16962
17180
|
function handleEmbeddedTerminalKey(context, key) {
|
|
16963
|
-
|
|
16964
|
-
|
|
16965
|
-
const
|
|
16966
|
-
const host = state.scene === "handoff" ? piHost : state.scene === "command" ? commandHost : null;
|
|
17181
|
+
if (context.getState().scene !== "command")
|
|
17182
|
+
return false;
|
|
17183
|
+
const host = getActiveCommandHost();
|
|
16967
17184
|
if (!host)
|
|
16968
17185
|
return false;
|
|
16969
17186
|
if (key.ctrl && key.name === "]") {
|
|
16970
|
-
|
|
16971
|
-
|
|
16972
|
-
|
|
16973
|
-
context.runAppAction("Opening runs", () => context.runtime.runIntent({ scene: "fleet", argv: ["runs"], action: { kind: "refresh", label: "Opening runs" } }));
|
|
16974
|
-
} else {
|
|
16975
|
-
stopActiveCommandHost("operator detach");
|
|
16976
|
-
clearTypeBar(context, "closed command");
|
|
16977
|
-
context.runAppAction("Project menu", () => context.runtime.runIntent({ scene: "main", argv: ["main"], action: { kind: "none", label: "Project menu" } }));
|
|
16978
|
-
}
|
|
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" } }));
|
|
16979
17190
|
return true;
|
|
16980
17191
|
}
|
|
16981
17192
|
const sequence = key.raw || key.sequence;
|
|
@@ -17184,7 +17395,6 @@ var init_keymap = __esm(() => {
|
|
|
17184
17395
|
init_autocomplete();
|
|
17185
17396
|
init_command_pty_host();
|
|
17186
17397
|
init_intent();
|
|
17187
|
-
init_pi_pty_host();
|
|
17188
17398
|
});
|
|
17189
17399
|
|
|
17190
17400
|
// packages/cli/src/app-opentui/runtime-resources.ts
|
|
@@ -17341,7 +17551,7 @@ var init_constants = __esm(() => {
|
|
|
17341
17551
|
});
|
|
17342
17552
|
|
|
17343
17553
|
// packages/cli/src/app-opentui/render/graphics.ts
|
|
17344
|
-
import { FrameBufferRenderable, RGBA as
|
|
17554
|
+
import { FrameBufferRenderable, RGBA as RGBA2 } from "@opentui/core";
|
|
17345
17555
|
function sceneKind(scene) {
|
|
17346
17556
|
if (scene === "tasks")
|
|
17347
17557
|
return "loop";
|
|
@@ -17436,7 +17646,7 @@ function paletteColor(ac, c2, mg, ink5) {
|
|
|
17436
17646
|
const b = (AC_RGB[2] * ac + C2_RGB[2] * c2 + MG_RGB[2] * mg + INK_RGB[2] * ink5) / total;
|
|
17437
17647
|
const intensity = Math.min(1, total / 4);
|
|
17438
17648
|
const lift = 0.34 + intensity * 0.66;
|
|
17439
|
-
return
|
|
17649
|
+
return RGBA2.fromInts(Math.round(r * lift), Math.round(g * lift), Math.round(b * lift), 255);
|
|
17440
17650
|
}
|
|
17441
17651
|
function clearCanvas(canvas) {
|
|
17442
17652
|
canvas.ac.fill(0);
|
|
@@ -17791,8 +18001,8 @@ function staticFleetTick(scene) {
|
|
|
17791
18001
|
}
|
|
17792
18002
|
function withAlpha(hex, alpha) {
|
|
17793
18003
|
const a = Math.max(0, Math.min(255, Math.round(alpha * 255)));
|
|
17794
|
-
const [r, g, b] =
|
|
17795
|
-
return
|
|
18004
|
+
const [r, g, b] = RGBA2.fromHex(hex).toInts();
|
|
18005
|
+
return RGBA2.fromInts(r, g, b, a);
|
|
17796
18006
|
}
|
|
17797
18007
|
function asciiFleetColor(char, row, alpha) {
|
|
17798
18008
|
if (char === "@" || char === "$" || char === "o")
|
|
@@ -17800,7 +18010,7 @@ function asciiFleetColor(char, row, alpha) {
|
|
|
17800
18010
|
if (char === "%" || char === "!" || char === "/" || char === "\\" || char === "|")
|
|
17801
18011
|
return withAlpha(RIG_UI.cyan, alpha);
|
|
17802
18012
|
if (char === "." || char === "'" || char === "_" || row < 3 || row > FLEET_GRID_HEIGHT - 4) {
|
|
17803
|
-
return
|
|
18013
|
+
return RGBA2.fromInts(108, 110, 121, Math.min(170, Math.max(0, Math.min(255, Math.round(alpha * 255)))));
|
|
17804
18014
|
}
|
|
17805
18015
|
return withAlpha(RIG_UI.limeDim, alpha);
|
|
17806
18016
|
}
|
|
@@ -17854,13 +18064,13 @@ var init_graphics = __esm(() => {
|
|
|
17854
18064
|
init_theme2();
|
|
17855
18065
|
init_ascii_fleet();
|
|
17856
18066
|
init_constants();
|
|
17857
|
-
TRANSPARENT =
|
|
17858
|
-
BACKDROP =
|
|
17859
|
-
PANEL_BG =
|
|
17860
|
-
PANEL_HEADER_BG =
|
|
17861
|
-
PANEL_LINE =
|
|
17862
|
-
PANEL_LINE_DIM =
|
|
17863
|
-
PANEL_TEXT_DIM =
|
|
18067
|
+
TRANSPARENT = RGBA2.fromValues(0, 0, 0, 0);
|
|
18068
|
+
BACKDROP = RGBA2.fromHex(RIG_UI.bg);
|
|
18069
|
+
PANEL_BG = RGBA2.fromInts(16, 17, 21, 184);
|
|
18070
|
+
PANEL_HEADER_BG = RGBA2.fromInts(16, 17, 21, 188);
|
|
18071
|
+
PANEL_LINE = RGBA2.fromInts(255, 255, 255, 20);
|
|
18072
|
+
PANEL_LINE_DIM = RGBA2.fromInts(255, 255, 255, 8);
|
|
18073
|
+
PANEL_TEXT_DIM = RGBA2.fromInts(108, 110, 121, 255);
|
|
17864
18074
|
AC_RGB = [204, 255, 77];
|
|
17865
18075
|
C2_RGB = [86, 216, 255];
|
|
17866
18076
|
MG_RGB = [255, 121, 176];
|
|
@@ -17903,7 +18113,7 @@ var init_hover = __esm(() => {
|
|
|
17903
18113
|
});
|
|
17904
18114
|
|
|
17905
18115
|
// packages/cli/src/app-opentui/render/text.ts
|
|
17906
|
-
import { RGBA as
|
|
18116
|
+
import { RGBA as RGBA3, TextAttributes as TextAttributes3, TextRenderable } from "@opentui/core";
|
|
17907
18117
|
function lineIsClickable(line2) {
|
|
17908
18118
|
return line2?.selectable !== undefined || line2?.selectableIndex !== undefined;
|
|
17909
18119
|
}
|
|
@@ -17912,7 +18122,7 @@ function lineSelectableId(line2) {
|
|
|
17912
18122
|
}
|
|
17913
18123
|
function lineBackground(line2) {
|
|
17914
18124
|
if (line2?.bg)
|
|
17915
|
-
return
|
|
18125
|
+
return RGBA3.fromHex(line2.bg);
|
|
17916
18126
|
const id = lineSelectableId(line2);
|
|
17917
18127
|
if (id !== undefined && isHovered(id))
|
|
17918
18128
|
return HOVER_BG;
|
|
@@ -17981,7 +18191,7 @@ function applyTextLine(renderable, line2, top, left, width) {
|
|
|
17981
18191
|
renderable.content = line2?.styledText ?? line2?.text ?? "";
|
|
17982
18192
|
renderable.fg = line2?.fg ?? RIG_UI.ink2;
|
|
17983
18193
|
renderable.bg = lineBackground(line2);
|
|
17984
|
-
renderable.attributes = line2?.bold ?
|
|
18194
|
+
renderable.attributes = line2?.bold ? TextAttributes3.BOLD : line2?.dim ? TextAttributes3.DIM : 0;
|
|
17985
18195
|
}
|
|
17986
18196
|
function applyFlowTextLine(renderable, line2, width) {
|
|
17987
18197
|
renderable.setRigSceneLine?.(line2);
|
|
@@ -17991,7 +18201,7 @@ function applyFlowTextLine(renderable, line2, width) {
|
|
|
17991
18201
|
renderable.content = line2?.styledText ?? line2?.text ?? "";
|
|
17992
18202
|
renderable.fg = line2?.fg ?? RIG_UI.ink2;
|
|
17993
18203
|
renderable.bg = lineBackground(line2);
|
|
17994
|
-
renderable.attributes = line2?.bold ?
|
|
18204
|
+
renderable.attributes = line2?.bold ? TextAttributes3.BOLD : line2?.dim ? TextAttributes3.DIM : 0;
|
|
17995
18205
|
}
|
|
17996
18206
|
function clearTextLines(renderables, from = 0) {
|
|
17997
18207
|
for (let index = from;index < renderables.length; index += 1) {
|
|
@@ -18008,19 +18218,30 @@ var TRANSPARENT2, HOVER_BG;
|
|
|
18008
18218
|
var init_text = __esm(() => {
|
|
18009
18219
|
init_theme2();
|
|
18010
18220
|
init_hover();
|
|
18011
|
-
TRANSPARENT2 =
|
|
18012
|
-
HOVER_BG =
|
|
18221
|
+
TRANSPARENT2 = RGBA3.fromInts(0, 0, 0, 0);
|
|
18222
|
+
HOVER_BG = RGBA3.fromHex(RIG_UI.hover);
|
|
18013
18223
|
});
|
|
18014
18224
|
|
|
18225
|
+
// packages/cli/src/app-opentui/render/terminal-handoff.ts
|
|
18226
|
+
function resumeRendererClean(renderer) {
|
|
18227
|
+
try {
|
|
18228
|
+
renderer.pendingSuspendedTerminalSetup = true;
|
|
18229
|
+
} catch {}
|
|
18230
|
+
renderer.resume();
|
|
18231
|
+
try {
|
|
18232
|
+
renderer.requestRender?.();
|
|
18233
|
+
} catch {}
|
|
18234
|
+
}
|
|
18235
|
+
|
|
18015
18236
|
// packages/cli/src/app-opentui/render/panels.ts
|
|
18016
|
-
import { RGBA as
|
|
18237
|
+
import { RGBA as RGBA4, ScrollBoxRenderable } from "@opentui/core";
|
|
18017
18238
|
function hexToRgba(hex, alpha) {
|
|
18018
18239
|
const clean = hex.replace(/^#/, "");
|
|
18019
18240
|
const full = clean.length === 3 ? clean.split("").map((part) => `${part}${part}`).join("") : clean;
|
|
18020
18241
|
const value = Number.parseInt(full, 16);
|
|
18021
18242
|
if (!Number.isFinite(value))
|
|
18022
|
-
return
|
|
18023
|
-
return
|
|
18243
|
+
return RGBA4.fromInts(14, 15, 17, alpha);
|
|
18244
|
+
return RGBA4.fromInts(value >> 16 & 255, value >> 8 & 255, value & 255, alpha);
|
|
18024
18245
|
}
|
|
18025
18246
|
function panelBackground(panel) {
|
|
18026
18247
|
return hexToRgba(panel.backgroundColor ?? RIG_UI.panel, PANEL_OPAQUE_ALPHA);
|
|
@@ -18137,12 +18358,12 @@ var TRANSPARENT3, MAX_PANEL_LINES = 420, PANEL_OPAQUE_ALPHA = 255, PANEL_BORDER;
|
|
|
18137
18358
|
var init_panels = __esm(() => {
|
|
18138
18359
|
init_theme2();
|
|
18139
18360
|
init_text();
|
|
18140
|
-
TRANSPARENT3 =
|
|
18361
|
+
TRANSPARENT3 = RGBA4.fromInts(0, 0, 0, 0);
|
|
18141
18362
|
PANEL_BORDER = hexToRgba(RIG_UI.border, 255);
|
|
18142
18363
|
});
|
|
18143
18364
|
|
|
18144
18365
|
// packages/cli/src/app-opentui/render/type-bar.ts
|
|
18145
|
-
import { BoxRenderable, InputRenderable, InputRenderableEvents, RGBA as
|
|
18366
|
+
import { BoxRenderable, InputRenderable, InputRenderableEvents, RGBA as RGBA5, StyledText as StyledText2, TextRenderable as TextRenderable2 } from "@opentui/core";
|
|
18146
18367
|
function createTypeBar(renderer) {
|
|
18147
18368
|
const background = new BoxRenderable(renderer, {
|
|
18148
18369
|
id: "typebar-card",
|
|
@@ -18289,13 +18510,13 @@ function formatFooter(footer, width) {
|
|
|
18289
18510
|
chunks.push(cell4.style(text2));
|
|
18290
18511
|
used += visibleWidth(text2);
|
|
18291
18512
|
});
|
|
18292
|
-
return new
|
|
18513
|
+
return new StyledText2(chunks);
|
|
18293
18514
|
}
|
|
18294
18515
|
var TYPEBAR_BG, TYPEBAR_BORDER, FOOTER_SEPARATOR = " \xB7 ";
|
|
18295
18516
|
var init_type_bar = __esm(() => {
|
|
18296
18517
|
init_theme2();
|
|
18297
|
-
TYPEBAR_BG =
|
|
18298
|
-
TYPEBAR_BORDER =
|
|
18518
|
+
TYPEBAR_BG = RGBA5.fromInts(20, 25, 14, 224);
|
|
18519
|
+
TYPEBAR_BORDER = RGBA5.fromInts(204, 255, 77, 92);
|
|
18299
18520
|
});
|
|
18300
18521
|
|
|
18301
18522
|
// packages/cli/src/app-opentui/render/native-host.ts
|
|
@@ -18303,7 +18524,7 @@ import {
|
|
|
18303
18524
|
BoxRenderable as BoxRenderable2,
|
|
18304
18525
|
CodeRenderable,
|
|
18305
18526
|
DiffRenderable,
|
|
18306
|
-
RGBA as
|
|
18527
|
+
RGBA as RGBA6,
|
|
18307
18528
|
ScrollBoxRenderable as ScrollBoxRenderable2,
|
|
18308
18529
|
SyntaxStyle,
|
|
18309
18530
|
TextRenderable as TextRenderable3,
|
|
@@ -18313,19 +18534,19 @@ function rigSyntaxStyle() {
|
|
|
18313
18534
|
if (syntaxStyle)
|
|
18314
18535
|
return syntaxStyle;
|
|
18315
18536
|
syntaxStyle = SyntaxStyle.fromStyles({
|
|
18316
|
-
keyword: { fg:
|
|
18317
|
-
string: { fg:
|
|
18318
|
-
number: { fg:
|
|
18319
|
-
comment: { fg:
|
|
18320
|
-
function: { fg:
|
|
18321
|
-
type: { fg:
|
|
18322
|
-
constant: { fg:
|
|
18323
|
-
default: { fg:
|
|
18537
|
+
keyword: { fg: RGBA6.fromHex(RIG_UI.magenta), bold: true },
|
|
18538
|
+
string: { fg: RGBA6.fromHex(RIG_UI.lime) },
|
|
18539
|
+
number: { fg: RGBA6.fromHex(RIG_UI.cyan) },
|
|
18540
|
+
comment: { fg: RGBA6.fromHex(RIG_UI.ink4), italic: true },
|
|
18541
|
+
function: { fg: RGBA6.fromHex(RIG_UI.cyan) },
|
|
18542
|
+
type: { fg: RGBA6.fromHex(RIG_UI.limeDim) },
|
|
18543
|
+
constant: { fg: RGBA6.fromHex(RIG_UI.yellow) },
|
|
18544
|
+
default: { fg: RGBA6.fromHex(RIG_UI.ink2) }
|
|
18324
18545
|
});
|
|
18325
18546
|
return syntaxStyle;
|
|
18326
18547
|
}
|
|
18327
18548
|
function tableContent(rows) {
|
|
18328
|
-
return rows.map((row, rowIndex) => row.map((cell4) => [{ __isChunk: true, text: cell4, fg:
|
|
18549
|
+
return rows.map((row, rowIndex) => row.map((cell4) => [{ __isChunk: true, text: cell4, fg: RGBA6.fromHex(rowIndex === 0 ? RIG_UI.ink3 : RIG_UI.ink2) }]));
|
|
18329
18550
|
}
|
|
18330
18551
|
function createNativeHost(renderer) {
|
|
18331
18552
|
try {
|
|
@@ -18474,10 +18695,14 @@ var init_preloader = __esm(() => {
|
|
|
18474
18695
|
});
|
|
18475
18696
|
|
|
18476
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
|
+
}
|
|
18477
18701
|
function renderErrorScene(state) {
|
|
18478
18702
|
const message2 = state.error?.message ?? "Unknown app error";
|
|
18479
18703
|
const hint = state.error?.hint ?? "Use the actions below to recover.";
|
|
18480
|
-
const
|
|
18704
|
+
const actions = errorActions(state);
|
|
18705
|
+
const selected = Math.max(0, Math.min(actions.length - 1, state.selection.index));
|
|
18481
18706
|
return makeSceneFrame({
|
|
18482
18707
|
scene: "error",
|
|
18483
18708
|
title: "Error",
|
|
@@ -18495,7 +18720,7 @@ function renderErrorScene(state) {
|
|
|
18495
18720
|
...hint ? [line(hint, { fg: RIG_UI.yellow })] : [],
|
|
18496
18721
|
line("", { fg: RIG_UI.ink3 }),
|
|
18497
18722
|
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
18498
|
-
...
|
|
18723
|
+
...actions.map(({ detail, item }, index) => selectableDeckRow({ label: item.label, detail, index, active: selected === index }, item))
|
|
18499
18724
|
],
|
|
18500
18725
|
backgroundColor: RIG_UI.panel,
|
|
18501
18726
|
backgroundAlpha: 184,
|
|
@@ -18512,18 +18737,19 @@ function renderErrorScene(state) {
|
|
|
18512
18737
|
live: true
|
|
18513
18738
|
});
|
|
18514
18739
|
}
|
|
18515
|
-
var ERROR_ACTIONS;
|
|
18740
|
+
var ERROR_ACTIONS, ERROR_REPAIR_LINK_ACTION;
|
|
18516
18741
|
var init_error = __esm(() => {
|
|
18517
18742
|
init_drone();
|
|
18518
18743
|
init_theme2();
|
|
18744
|
+
init_remote_link();
|
|
18519
18745
|
init_scene();
|
|
18520
18746
|
init_selectable();
|
|
18521
18747
|
ERROR_ACTIONS = [
|
|
18522
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" } },
|
|
18523
18749
|
{ detail: "run diagnostics", item: { id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "run diagnostics" } },
|
|
18524
|
-
{ 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" } }
|
|
18525
|
-
{ 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" } }
|
|
18526
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" } };
|
|
18527
18753
|
});
|
|
18528
18754
|
|
|
18529
18755
|
// packages/cli/src/app-opentui/scenes/help.ts
|
|
@@ -18698,7 +18924,7 @@ function configuredMenuRows(selectedIndex2) {
|
|
|
18698
18924
|
}));
|
|
18699
18925
|
}
|
|
18700
18926
|
function onboardingRows(selectedIndex2) {
|
|
18701
|
-
const primary = selectableDeckRow({ label: "
|
|
18927
|
+
const primary = selectableDeckRow({ label: "init", detail: "Start guided init \u2014 recommended", active: selectedIndex2 === 0 }, ONBOARD_PRIMARY);
|
|
18702
18928
|
const secondary = ONBOARD_SECONDARY.map(([label, detail, item], index) => ({
|
|
18703
18929
|
...deckRow({ label, detail, index: index + 1, active: selectedIndex2 === index + 1, activateOnClick: true }),
|
|
18704
18930
|
selectable: item
|
|
@@ -18758,7 +18984,7 @@ function renderMainScene(state, layout) {
|
|
|
18758
18984
|
statusLine(state)
|
|
18759
18985
|
] : [
|
|
18760
18986
|
line("WELCOME", { fg: RIG_UI.ink, bold: true }),
|
|
18761
|
-
line("This project isn't
|
|
18987
|
+
line("This project isn't initialized yet. One native init flow gets you running.", { fg: RIG_UI.ink2 }),
|
|
18762
18988
|
blank(),
|
|
18763
18989
|
line("GET STARTED", { fg: RIG_UI.ink, bold: true }),
|
|
18764
18990
|
...onboardingRows(actionSelected),
|
|
@@ -18799,7 +19025,7 @@ var init_main = __esm(() => {
|
|
|
18799
19025
|
init_theme2();
|
|
18800
19026
|
init_fleet_stats();
|
|
18801
19027
|
CONFIGURED_MENU = [
|
|
18802
|
-
["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" }],
|
|
18803
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" }],
|
|
18804
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" }],
|
|
18805
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" }],
|
|
@@ -18818,10 +19044,10 @@ var init_main = __esm(() => {
|
|
|
18818
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" }]
|
|
18819
19045
|
];
|
|
18820
19046
|
ONBOARD_PRIMARY = {
|
|
18821
|
-
id: "onboard-
|
|
18822
|
-
label: "Start guided
|
|
18823
|
-
intent: { scene: "init", argv: ["init"], action: { kind: "refresh", label: "
|
|
18824
|
-
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"
|
|
18825
19051
|
};
|
|
18826
19052
|
ONBOARD_SECONDARY = [
|
|
18827
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" }],
|
|
@@ -18834,6 +19060,12 @@ var init_main = __esm(() => {
|
|
|
18834
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" };
|
|
18835
19061
|
});
|
|
18836
19062
|
|
|
19063
|
+
// packages/cli/src/app-opentui/pi-pty-host.ts
|
|
19064
|
+
function getActivePiHost() {
|
|
19065
|
+
return null;
|
|
19066
|
+
}
|
|
19067
|
+
function stopActivePiHost(_reason) {}
|
|
19068
|
+
|
|
18837
19069
|
// packages/cli/src/app-opentui/runtime.ts
|
|
18838
19070
|
var exports_runtime = {};
|
|
18839
19071
|
__export(exports_runtime, {
|
|
@@ -18853,7 +19085,7 @@ __export(exports_runtime, {
|
|
|
18853
19085
|
});
|
|
18854
19086
|
import { existsSync as existsSync23 } from "fs";
|
|
18855
19087
|
import { resolve as resolve30 } from "path";
|
|
18856
|
-
import { BoxRenderable as BoxRenderable3, RGBA as
|
|
19088
|
+
import { BoxRenderable as BoxRenderable3, RGBA as RGBA7, StyledText as StyledText3, TextRenderable as TextRenderable4, createCliRenderer } from "@opentui/core";
|
|
18857
19089
|
function inboxPendingCount(state) {
|
|
18858
19090
|
const inbox = state.data.inbox;
|
|
18859
19091
|
if (!inbox || typeof inbox !== "object" || Array.isArray(inbox))
|
|
@@ -18900,7 +19132,7 @@ function entryIntentForScene(scene) {
|
|
|
18900
19132
|
case "doctor":
|
|
18901
19133
|
return { scene, argv: ["doctor"], action: { kind: "doctor-run", label: "Doctor" } };
|
|
18902
19134
|
case "init":
|
|
18903
|
-
return { scene, argv: ["init"], action: { kind: "refresh", label: "
|
|
19135
|
+
return { scene, argv: ["init"], action: { kind: "refresh", label: "Init" } };
|
|
18904
19136
|
case "run-detail":
|
|
18905
19137
|
return { scene, argv: ["run", "status"], action: { kind: "refresh", label: "Run" } };
|
|
18906
19138
|
case "pi":
|
|
@@ -18989,7 +19221,7 @@ function sceneSectionLabel(scene) {
|
|
|
18989
19221
|
handoff: "pi console",
|
|
18990
19222
|
server: "server",
|
|
18991
19223
|
doctor: "doctor",
|
|
18992
|
-
init: "
|
|
19224
|
+
init: "init",
|
|
18993
19225
|
pi: "pi",
|
|
18994
19226
|
plugin: "plugins",
|
|
18995
19227
|
repo: "repo",
|
|
@@ -19022,7 +19254,7 @@ function buildNavStrip(state) {
|
|
|
19022
19254
|
chunks.push(otuiBold(styles.yellow(String(badgeCount))));
|
|
19023
19255
|
}
|
|
19024
19256
|
});
|
|
19025
|
-
return new
|
|
19257
|
+
return new StyledText3(chunks);
|
|
19026
19258
|
}
|
|
19027
19259
|
function requestRender(renderer) {
|
|
19028
19260
|
renderer.requestRender?.();
|
|
@@ -19250,7 +19482,8 @@ async function launchRigOpenTuiApp(options) {
|
|
|
19250
19482
|
},
|
|
19251
19483
|
suspend: () => renderer?.suspend(),
|
|
19252
19484
|
resume: () => {
|
|
19253
|
-
renderer
|
|
19485
|
+
if (renderer)
|
|
19486
|
+
resumeRendererClean(renderer);
|
|
19254
19487
|
renderApp();
|
|
19255
19488
|
},
|
|
19256
19489
|
destroy: () => renderer?.destroy()
|
|
@@ -19478,7 +19711,7 @@ async function launchRigOpenTuiApp(options) {
|
|
|
19478
19711
|
}
|
|
19479
19712
|
for (const adapter of options.adapters ?? [])
|
|
19480
19713
|
await adapter.start?.(runtime);
|
|
19481
|
-
|
|
19714
|
+
connectRigServerEvents(options.projectRoot, {
|
|
19482
19715
|
onSnapshotInvalidated: () => refreshCurrentDataScene(),
|
|
19483
19716
|
onRunLogAppended: () => {
|
|
19484
19717
|
const scene = store.getState().scene;
|
|
@@ -19486,11 +19719,17 @@ async function launchRigOpenTuiApp(options) {
|
|
|
19486
19719
|
refreshCurrentDataScene();
|
|
19487
19720
|
},
|
|
19488
19721
|
onStatus: (status) => store.patch({ footer: { live: liveLinkLabel(status) } })
|
|
19489
|
-
}).
|
|
19490
|
-
|
|
19491
|
-
|
|
19492
|
-
|
|
19722
|
+
}).then((subscription) => {
|
|
19723
|
+
if (destroyed) {
|
|
19724
|
+
subscription.close();
|
|
19725
|
+
return;
|
|
19726
|
+
}
|
|
19727
|
+
liveEvents = subscription;
|
|
19493
19728
|
resources.add(() => liveEvents?.close());
|
|
19729
|
+
}).catch(() => {
|
|
19730
|
+
if (!destroyed)
|
|
19731
|
+
store.patch({ footer: { live: liveLinkLabel("disconnected") } });
|
|
19732
|
+
});
|
|
19494
19733
|
await runtime.runIntent(store.getState().intent);
|
|
19495
19734
|
} catch (error) {
|
|
19496
19735
|
const normalized = normalizeError(error);
|
|
@@ -19676,15 +19915,14 @@ var init_runtime = __esm(() => {
|
|
|
19676
19915
|
init_help();
|
|
19677
19916
|
init_main();
|
|
19678
19917
|
init_selectable();
|
|
19679
|
-
|
|
19680
|
-
PRELOADER_BACKDROP = RGBA8.fromHex(RIG_UI.bg);
|
|
19918
|
+
PRELOADER_BACKDROP = RGBA7.fromHex(RIG_UI.bg);
|
|
19681
19919
|
PRIMARY_NAV = [
|
|
19682
19920
|
{ id: "cockpit", label: "Cockpit", scene: "main", argv: ["main"], enterLabel: "Cockpit", member: ["main"] },
|
|
19683
19921
|
{ id: "runs", label: "Runs", scene: "fleet", argv: ["runs"], enterLabel: "Runs", member: ["fleet", "run-detail", "inspect", "handoff"] },
|
|
19684
19922
|
{ id: "tasks", label: "Tasks", scene: "tasks", argv: ["tasks"], enterLabel: "Tasks", member: ["tasks"] },
|
|
19685
19923
|
{ id: "inbox", label: "Inbox", scene: "inbox", argv: ["inbox"], enterLabel: "Inbox", member: ["inbox"], badge: inboxPendingCount },
|
|
19686
19924
|
{ id: "stats", label: "Stats", scene: "family", argv: ["stats"], enterLabel: "Stats", member: ["family"] },
|
|
19687
|
-
{ id: "
|
|
19925
|
+
{ id: "init", label: "Init", scene: "init", argv: ["init"], enterLabel: "Init", member: ["init", "doctor", "server", "pi", "plugin", "repo", "workspace"] },
|
|
19688
19926
|
{ id: "help", label: "Help", scene: "help", argv: ["help"], enterLabel: "Help", member: ["help"] }
|
|
19689
19927
|
];
|
|
19690
19928
|
SCENE_DATA_KEY = {
|
|
@@ -19794,10 +20032,10 @@ var init_scroll = __esm(() => {
|
|
|
19794
20032
|
// packages/cli/src/app-opentui/react/SceneFrameView.tsx
|
|
19795
20033
|
import { useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
19796
20034
|
import { useRenderer as useRenderer2 } from "@opentui/react";
|
|
19797
|
-
import { TextAttributes as
|
|
20035
|
+
import { TextAttributes as TextAttributes4 } from "@opentui/core";
|
|
19798
20036
|
import { jsxDEV, Fragment } from "@opentui/react/jsx-dev-runtime";
|
|
19799
20037
|
function lineAttributes(line2) {
|
|
19800
|
-
return line2?.bold ?
|
|
20038
|
+
return line2?.bold ? TextAttributes4.BOLD : line2?.dim ? TextAttributes4.DIM : 0;
|
|
19801
20039
|
}
|
|
19802
20040
|
function lineContent(line2) {
|
|
19803
20041
|
return line2.styledText ?? line2.text ?? "";
|
|
@@ -20048,7 +20286,7 @@ var init_nav = __esm(() => {
|
|
|
20048
20286
|
{ id: "tasks", label: "Tasks", scene: "tasks", argv: ["tasks"], enterLabel: "Tasks", member: ["tasks"] },
|
|
20049
20287
|
{ id: "inbox", label: "Inbox", scene: "inbox", argv: ["inbox"], enterLabel: "Inbox", member: ["inbox"], badge: inboxPendingCount2 },
|
|
20050
20288
|
{ id: "stats", label: "Stats", scene: "family", argv: ["stats"], enterLabel: "Stats", member: ["family"] },
|
|
20051
|
-
{ id: "
|
|
20289
|
+
{ id: "init", label: "Init", scene: "init", argv: ["init"], enterLabel: "Init", member: ["init", "doctor", "server", "pi", "plugin", "repo", "workspace"] },
|
|
20052
20290
|
{ id: "help", label: "Help", scene: "help", argv: ["help"], enterLabel: "Help", member: ["help"] }
|
|
20053
20291
|
];
|
|
20054
20292
|
});
|
|
@@ -20180,8 +20418,48 @@ async function launchRigReactApp(options) {
|
|
|
20180
20418
|
const store = createAppStore(initialState);
|
|
20181
20419
|
const events = createAppEventBus();
|
|
20182
20420
|
let renderer = null;
|
|
20421
|
+
let root = null;
|
|
20183
20422
|
let runnerPromise = null;
|
|
20184
20423
|
let suppressHistoryPush = false;
|
|
20424
|
+
let resolveExit = () => {};
|
|
20425
|
+
const appExit = new Promise((resolve31) => {
|
|
20426
|
+
resolveExit = resolve31;
|
|
20427
|
+
});
|
|
20428
|
+
let relaunching = false;
|
|
20429
|
+
const mountRenderer = async () => {
|
|
20430
|
+
renderer = await createCliRenderer2({
|
|
20431
|
+
screenMode: "alternate-screen",
|
|
20432
|
+
exitOnCtrlC: false,
|
|
20433
|
+
targetFps: 30,
|
|
20434
|
+
maxFps: 30,
|
|
20435
|
+
useMouse: true,
|
|
20436
|
+
autoFocus: false,
|
|
20437
|
+
useKittyKeyboard: { disambiguate: true }
|
|
20438
|
+
});
|
|
20439
|
+
renderer.on("destroy", () => {
|
|
20440
|
+
if (!relaunching)
|
|
20441
|
+
resolveExit();
|
|
20442
|
+
});
|
|
20443
|
+
root = createRoot(renderer);
|
|
20444
|
+
root.render(/* @__PURE__ */ jsxDEV4(RigAppProvider, {
|
|
20445
|
+
value: { store, runtime, runAppAction },
|
|
20446
|
+
children: /* @__PURE__ */ jsxDEV4(App, {
|
|
20447
|
+
sceneRenderers: options.sceneRenderers
|
|
20448
|
+
}, undefined, false, undefined, this)
|
|
20449
|
+
}, undefined, false, undefined, this));
|
|
20450
|
+
relaunching = false;
|
|
20451
|
+
};
|
|
20452
|
+
const teardownRenderer = () => {
|
|
20453
|
+
relaunching = true;
|
|
20454
|
+
try {
|
|
20455
|
+
root?.unmount();
|
|
20456
|
+
} catch {}
|
|
20457
|
+
root = null;
|
|
20458
|
+
try {
|
|
20459
|
+
renderer?.destroy();
|
|
20460
|
+
} catch {}
|
|
20461
|
+
renderer = null;
|
|
20462
|
+
};
|
|
20185
20463
|
const runAppAction = (label, action) => {
|
|
20186
20464
|
action().catch((error) => {
|
|
20187
20465
|
const n = normalizeError(error);
|
|
@@ -20223,8 +20501,10 @@ async function launchRigReactApp(options) {
|
|
|
20223
20501
|
runnerPromise ??= options.initializeRuntime();
|
|
20224
20502
|
return runnerPromise;
|
|
20225
20503
|
},
|
|
20226
|
-
suspend: () =>
|
|
20227
|
-
resume: () =>
|
|
20504
|
+
suspend: () => teardownRenderer(),
|
|
20505
|
+
resume: async () => {
|
|
20506
|
+
await mountRenderer();
|
|
20507
|
+
},
|
|
20228
20508
|
destroy: () => renderer?.destroy()
|
|
20229
20509
|
};
|
|
20230
20510
|
events.subscribe((event) => store.patch(reduceAppEvent(store.getState(), event)));
|
|
@@ -20232,15 +20512,7 @@ async function launchRigReactApp(options) {
|
|
|
20232
20512
|
if (typeof tick.unref === "function") {
|
|
20233
20513
|
tick.unref();
|
|
20234
20514
|
}
|
|
20235
|
-
|
|
20236
|
-
screenMode: "alternate-screen",
|
|
20237
|
-
exitOnCtrlC: false,
|
|
20238
|
-
targetFps: 30,
|
|
20239
|
-
maxFps: 30,
|
|
20240
|
-
useMouse: true,
|
|
20241
|
-
autoFocus: false,
|
|
20242
|
-
useKittyKeyboard: { disambiguate: true }
|
|
20243
|
-
});
|
|
20515
|
+
await mountRenderer();
|
|
20244
20516
|
let liveEvents = null;
|
|
20245
20517
|
const canAutoRefresh = (state) => {
|
|
20246
20518
|
if (state.status === "action" || state.status === "loading")
|
|
@@ -20271,12 +20543,6 @@ async function launchRigReactApp(options) {
|
|
|
20271
20543
|
}, FALLBACK_REFRESH_MS);
|
|
20272
20544
|
if (typeof poll.unref === "function")
|
|
20273
20545
|
poll.unref();
|
|
20274
|
-
createRoot(renderer).render(/* @__PURE__ */ jsxDEV4(RigAppProvider, {
|
|
20275
|
-
value: { store, runtime, runAppAction },
|
|
20276
|
-
children: /* @__PURE__ */ jsxDEV4(App, {
|
|
20277
|
-
sceneRenderers: options.sceneRenderers
|
|
20278
|
-
}, undefined, false, undefined, this)
|
|
20279
|
-
}, undefined, false, undefined, this));
|
|
20280
20546
|
queueMicrotask(() => {
|
|
20281
20547
|
(async () => {
|
|
20282
20548
|
try {
|
|
@@ -20286,7 +20552,7 @@ async function launchRigReactApp(options) {
|
|
|
20286
20552
|
}
|
|
20287
20553
|
for (const adapter of options.adapters ?? [])
|
|
20288
20554
|
await adapter.start?.(runtime);
|
|
20289
|
-
|
|
20555
|
+
connectRigServerEvents(options.projectRoot, {
|
|
20290
20556
|
onSnapshotInvalidated: () => refreshCurrentDataScene(),
|
|
20291
20557
|
onRunLogAppended: () => {
|
|
20292
20558
|
const scene = store.getState().scene;
|
|
@@ -20294,9 +20560,11 @@ async function launchRigReactApp(options) {
|
|
|
20294
20560
|
refreshCurrentDataScene();
|
|
20295
20561
|
},
|
|
20296
20562
|
onStatus: (status) => store.patch({ footer: { live: liveLinkLabel(status) } })
|
|
20297
|
-
}).
|
|
20298
|
-
|
|
20563
|
+
}).then((subscription) => {
|
|
20564
|
+
liveEvents = subscription;
|
|
20565
|
+
}).catch(() => {
|
|
20299
20566
|
store.patch({ footer: { live: liveLinkLabel("disconnected") } });
|
|
20567
|
+
});
|
|
20300
20568
|
await runtime.runIntent(store.getState().intent);
|
|
20301
20569
|
} catch (error) {
|
|
20302
20570
|
const n = normalizeError(error);
|
|
@@ -20304,14 +20572,11 @@ async function launchRigReactApp(options) {
|
|
|
20304
20572
|
}
|
|
20305
20573
|
})();
|
|
20306
20574
|
});
|
|
20307
|
-
await
|
|
20308
|
-
|
|
20309
|
-
|
|
20310
|
-
|
|
20311
|
-
|
|
20312
|
-
resolve31();
|
|
20313
|
-
});
|
|
20314
|
-
});
|
|
20575
|
+
await appExit;
|
|
20576
|
+
clearInterval(tick);
|
|
20577
|
+
clearInterval(poll);
|
|
20578
|
+
liveEvents?.close();
|
|
20579
|
+
teardownRenderer();
|
|
20315
20580
|
}
|
|
20316
20581
|
var POLLABLE_SCENES;
|
|
20317
20582
|
var init_launch = __esm(() => {
|
|
@@ -20325,7 +20590,7 @@ var init_launch = __esm(() => {
|
|
|
20325
20590
|
|
|
20326
20591
|
// packages/cli/src/app-opentui/bootstrap.ts
|
|
20327
20592
|
import { existsSync as existsSync24, readFileSync as readFileSync15 } from "fs";
|
|
20328
|
-
import { basename as
|
|
20593
|
+
import { basename as basename5, resolve as resolve31 } from "path";
|
|
20329
20594
|
|
|
20330
20595
|
// packages/cli/src/app-opentui/adapters/command.ts
|
|
20331
20596
|
init_command_pty_host();
|
|
@@ -21460,6 +21725,7 @@ async function stopRunFromDetail(ctx, runId) {
|
|
|
21460
21725
|
}
|
|
21461
21726
|
|
|
21462
21727
|
// packages/cli/src/app-opentui/adapters/server.ts
|
|
21728
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
21463
21729
|
var SERVER_PROBE_TIMEOUT_MS = Number(process.env.RIG_SERVER_PROBE_TIMEOUT_MS) || 5000;
|
|
21464
21730
|
function withTimeout(promise, ms, label) {
|
|
21465
21731
|
return new Promise((resolve29, reject) => {
|
|
@@ -21497,11 +21763,128 @@ function startLocalRequested(ctx) {
|
|
|
21497
21763
|
const action = intent.action;
|
|
21498
21764
|
return action?.payload?.startLocal === true;
|
|
21499
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
|
+
}
|
|
21500
21882
|
async function startLocalServerFromApp(ctx) {
|
|
21501
21883
|
const label = "Starting local server";
|
|
21502
21884
|
emitStarted(ctx, label);
|
|
21503
21885
|
patchData(ctx, {
|
|
21504
21886
|
lastIntent: undefined,
|
|
21887
|
+
remoteProjectLink: undefined,
|
|
21505
21888
|
server: { label: "starting local server", reachable: false, error: "spawning local rig-server (detached)\u2026" }
|
|
21506
21889
|
});
|
|
21507
21890
|
try {
|
|
@@ -21526,32 +21909,61 @@ async function startLocalServerFromApp(ctx) {
|
|
|
21526
21909
|
reachable: false,
|
|
21527
21910
|
error: error instanceof Error ? error.message : String(error)
|
|
21528
21911
|
};
|
|
21529
|
-
patchData(ctx, { server: state, lastRefreshError: state.error });
|
|
21912
|
+
patchData(ctx, { server: state, remoteProjectLink: undefined, lastRefreshError: state.error });
|
|
21530
21913
|
patchFooter(ctx, { server: "unavailable" });
|
|
21531
|
-
emitCompleted(ctx, label, {
|
|
21914
|
+
emitCompleted(ctx, label, { serverLabel: state.label, reachable: false, error: state.error });
|
|
21532
21915
|
return state;
|
|
21533
21916
|
}
|
|
21534
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
|
+
}
|
|
21535
21945
|
async function refreshServerStatus(ctx) {
|
|
21536
21946
|
if (startLocalRequested(ctx)) {
|
|
21537
21947
|
return startLocalServerFromApp(ctx);
|
|
21538
21948
|
}
|
|
21539
21949
|
const label = "Checking server";
|
|
21540
21950
|
emitStarted(ctx, label);
|
|
21541
|
-
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 });
|
|
21542
21952
|
const started = Date.now();
|
|
21543
21953
|
try {
|
|
21544
|
-
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));
|
|
21545
21955
|
const projectRoot = projectRootOf(ctx);
|
|
21956
|
+
const aliases = await serverAliases(projectRoot);
|
|
21546
21957
|
emitProgress(ctx, label, "resolving selected server");
|
|
21547
21958
|
const [connectionLabel, server] = await Promise.all([
|
|
21548
21959
|
resolveServerConnectionLabel2(projectRoot),
|
|
21549
21960
|
withTimeout(ensureServerForCli2(projectRoot), 5000, "server connection")
|
|
21550
21961
|
]);
|
|
21551
21962
|
emitProgress(ctx, label, "requesting server status", { baseUrl: server.baseUrl, kind: server.connectionKind });
|
|
21552
|
-
const [status, auth] = await Promise.all([
|
|
21963
|
+
const [status, auth, remoteProjectLink] = await Promise.all([
|
|
21553
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) })),
|
|
21554
|
-
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)
|
|
21555
21967
|
]);
|
|
21556
21968
|
const state = {
|
|
21557
21969
|
label: connectionLabel,
|
|
@@ -21560,22 +21972,25 @@ async function refreshServerStatus(ctx) {
|
|
|
21560
21972
|
reachable: true,
|
|
21561
21973
|
latencyMs: Date.now() - started,
|
|
21562
21974
|
status: status && typeof status === "object" && !Array.isArray(status) ? status : {},
|
|
21563
|
-
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 } : {}
|
|
21564
21978
|
};
|
|
21565
|
-
patchData(ctx, { server: state });
|
|
21979
|
+
patchData(ctx, { server: state, remoteProjectLink: state.remoteProjectLink });
|
|
21566
21980
|
patchFooter(ctx, { server: connectionLabel, latency: `${state.latencyMs}ms` });
|
|
21567
|
-
emitCompleted(ctx, label, {
|
|
21981
|
+
emitCompleted(ctx, label, { serverLabel: connectionLabel, latencyMs: state.latencyMs });
|
|
21568
21982
|
return state;
|
|
21569
21983
|
} catch (error) {
|
|
21570
21984
|
const state = {
|
|
21571
21985
|
label: "server unavailable",
|
|
21572
21986
|
reachable: false,
|
|
21573
21987
|
latencyMs: Date.now() - started,
|
|
21988
|
+
aliases: await serverAliases(projectRootOf(ctx)).catch(() => []),
|
|
21574
21989
|
error: error instanceof Error ? error.message : String(error)
|
|
21575
21990
|
};
|
|
21576
|
-
patchData(ctx, { server: state });
|
|
21991
|
+
patchData(ctx, { server: state, remoteProjectLink: undefined });
|
|
21577
21992
|
patchFooter(ctx, { server: "unavailable" });
|
|
21578
|
-
emitCompleted(ctx, label, {
|
|
21993
|
+
emitCompleted(ctx, label, { serverLabel: state.label, reachable: false, error: state.error });
|
|
21579
21994
|
return state;
|
|
21580
21995
|
}
|
|
21581
21996
|
}
|
|
@@ -22162,7 +22577,7 @@ init_theme2();
|
|
|
22162
22577
|
var DOCTOR_ACTIONS = [
|
|
22163
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" } },
|
|
22164
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" } },
|
|
22165
|
-
{ 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" } },
|
|
22166
22581
|
{ detail: "open tasks", item: { id: "tasks", label: "tasks", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Open tasks" } }, message: "open tasks" } }
|
|
22167
22582
|
];
|
|
22168
22583
|
function checks(state) {
|
|
@@ -22238,6 +22653,7 @@ function renderDoctorScene(state, layout) {
|
|
|
22238
22653
|
// packages/cli/src/app-opentui/scenes/family.ts
|
|
22239
22654
|
init_scene();
|
|
22240
22655
|
init_selectable();
|
|
22656
|
+
init_remote_link();
|
|
22241
22657
|
init_theme2();
|
|
22242
22658
|
|
|
22243
22659
|
// packages/cli/src/app-opentui/scenes/family-domains/kit.ts
|
|
@@ -24000,13 +24416,18 @@ function overviewBody(state, family, snap, layout) {
|
|
|
24000
24416
|
function familyRecoveryRows(state, family, errorMessage2) {
|
|
24001
24417
|
const selected = Math.max(0, state.selection.index);
|
|
24002
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 });
|
|
24003
|
-
|
|
24419
|
+
const repairRemote = shouldOfferRemoteLinkRepair(state, errorMessage2);
|
|
24420
|
+
const rows = [
|
|
24004
24421
|
intro,
|
|
24005
|
-
blank()
|
|
24006
|
-
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" }),
|
|
24007
|
-
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" }),
|
|
24008
|
-
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()
|
|
24009
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;
|
|
24010
24431
|
}
|
|
24011
24432
|
function renderFamilyScene(state, layout) {
|
|
24012
24433
|
const family = typeof state.data.familyName === "string" ? state.data.familyName : "";
|
|
@@ -24015,9 +24436,16 @@ function renderFamilyScene(state, layout) {
|
|
|
24015
24436
|
const loading = state.status === "loading" && !snap;
|
|
24016
24437
|
const errorMessage2 = state.error?.message ?? lastRefreshError(state) ?? undefined;
|
|
24017
24438
|
const probeFailed = snap ? snap.state.ran === false && Boolean(state.error) : Boolean(state.error);
|
|
24439
|
+
const selected = Math.max(0, state.selection.index);
|
|
24018
24440
|
const body = [
|
|
24019
24441
|
...loading ? loadingRows(family || "family", state.tick) : snap ? [
|
|
24020
|
-
...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
|
+
] : [],
|
|
24021
24449
|
...current.subId ? formView(state, family, snap, current).lines : overviewBody(state, family, snap, layout)
|
|
24022
24450
|
] : familyRecoveryRows(state, family, errorMessage2)
|
|
24023
24451
|
];
|
|
@@ -24169,13 +24597,14 @@ function sortTasks2(tasks, spec) {
|
|
|
24169
24597
|
|
|
24170
24598
|
// packages/cli/src/app-opentui/scenes/fleet.ts
|
|
24171
24599
|
init_fleet_stats();
|
|
24600
|
+
init_remote_link();
|
|
24172
24601
|
init_theme2();
|
|
24173
|
-
var
|
|
24602
|
+
var BASE_FLEET_RECOVERY_ITEMS = [
|
|
24174
24603
|
{ id: "tasks", label: "tasks", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Open tasks" } }, message: "open tasks and dispatch work" },
|
|
24175
|
-
{ id: "repair", label: "repair", intent: { scene: "command", argv: ["init", "--repair"], action: { kind: "command-run", label: "Repair project link" } }, message: "repair project/server/auth link" },
|
|
24176
24604
|
{ id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Open server controls" } }, message: "server controls" },
|
|
24177
24605
|
{ id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "diagnose project" }
|
|
24178
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" };
|
|
24179
24608
|
var COL2 = {
|
|
24180
24609
|
glyph: 1,
|
|
24181
24610
|
runId: 8,
|
|
@@ -24340,33 +24769,43 @@ function runRow(width, run, active, optimistic) {
|
|
|
24340
24769
|
const item = runSelectableItem(run);
|
|
24341
24770
|
return item ? withSelectable(row, item) : row;
|
|
24342
24771
|
}
|
|
24343
|
-
var
|
|
24772
|
+
var BASE_RECOVERY_DECKS = [
|
|
24344
24773
|
{ label: "tasks", detail: "open tasks and dispatch work" },
|
|
24345
|
-
{ label: "repair", detail: "repair project/server/auth link" },
|
|
24346
24774
|
{ label: "server", detail: "open server controls" },
|
|
24347
24775
|
{ label: "doctor", detail: "diagnose project" }
|
|
24348
24776
|
];
|
|
24349
|
-
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);
|
|
24350
24789
|
return [
|
|
24351
24790
|
...reason ? [line(reason, { fg: RIG_UI.yellow }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
24352
24791
|
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
24353
|
-
...
|
|
24792
|
+
...fleetRecoveryDecks(state).map((deck, index) => selectableDeckRow({ ...deck, index, active: selected === index }, items[index]))
|
|
24354
24793
|
];
|
|
24355
24794
|
}
|
|
24356
|
-
function emptyRows(query, total, selected) {
|
|
24795
|
+
function emptyRows(state, query, total, selected) {
|
|
24357
24796
|
if (!query.trim() && total === 0)
|
|
24358
|
-
return recoveryRows(selected, "No runs yet.");
|
|
24797
|
+
return recoveryRows(state, selected, "No runs yet.");
|
|
24359
24798
|
if (query.trim() && total > 0) {
|
|
24360
24799
|
return [
|
|
24361
|
-
...recoveryRows(selected, `No matching runs for ${JSON.stringify(query)} (${total} total).`)
|
|
24800
|
+
...recoveryRows(state, selected, `No matching runs for ${JSON.stringify(query)} (${total} total).`)
|
|
24362
24801
|
];
|
|
24363
24802
|
}
|
|
24364
|
-
return recoveryRows(selected, "No runs are visible with this filter.");
|
|
24803
|
+
return recoveryRows(state, selected, "No runs are visible with this filter.");
|
|
24365
24804
|
}
|
|
24366
24805
|
function degradedRows(state, selected) {
|
|
24367
24806
|
if (!state.error)
|
|
24368
24807
|
return [];
|
|
24369
|
-
return recoveryRows(selected, state.error.message);
|
|
24808
|
+
return recoveryRows(state, selected, state.error.message);
|
|
24370
24809
|
}
|
|
24371
24810
|
function renderFleetScene(state, layout) {
|
|
24372
24811
|
const width = panelWidth4(layout);
|
|
@@ -24376,7 +24815,7 @@ function renderFleetScene(state, layout) {
|
|
|
24376
24815
|
const runs = sortRuns(filterRunsForSearch(allRuns, query), spec);
|
|
24377
24816
|
const selectedRun = typeof state.data.selectedRunId === "string" && runs.some((run) => run.runId === state.data.selectedRunId) ? state.data.selectedRunId : runs[0]?.runId;
|
|
24378
24817
|
const selectedIndex = Math.max(0, runs.findIndex((run) => run.runId === selectedRun));
|
|
24379
|
-
const recoveryIndex = Math.max(0, Math.min(
|
|
24818
|
+
const recoveryIndex = Math.max(0, Math.min(fleetRecoveryItems(state).length - 1, state.selection.index));
|
|
24380
24819
|
const optimistic = optimisticStatuses(state);
|
|
24381
24820
|
const updatedAgo = updatedAgoLabel(state);
|
|
24382
24821
|
const panelTop = 0;
|
|
@@ -24408,7 +24847,7 @@ function renderFleetScene(state, layout) {
|
|
|
24408
24847
|
...runs.map((run, index) => runRow(contentWidth, run, index === selectedIndex, optimistic.get(run.runId)))
|
|
24409
24848
|
] : state.error ? degradedRows(state, recoveryIndex) : loading ? loadingRows("runs", state.tick) : [
|
|
24410
24849
|
...query.trim() ? [line(searchSummary("runs", query, runs.length, allRuns.length), { fg: RIG_UI.ink4 }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
24411
|
-
...emptyRows(query, allRuns.length, recoveryIndex)
|
|
24850
|
+
...emptyRows(state, query, allRuns.length, recoveryIndex)
|
|
24412
24851
|
]
|
|
24413
24852
|
];
|
|
24414
24853
|
return makeSceneFrame({
|
|
@@ -24896,19 +25335,19 @@ function renderInboxScene(state, layout) {
|
|
|
24896
25335
|
init_scene();
|
|
24897
25336
|
init_selectable();
|
|
24898
25337
|
init_theme2();
|
|
24899
|
-
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" };
|
|
24900
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" };
|
|
24901
|
-
var STEP_AUTH = { id: "step-auth", label: "connect GitHub", intent: { scene: "
|
|
24902
|
-
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" };
|
|
24903
25342
|
var SETUP_STEPS = [
|
|
24904
|
-
{ 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 },
|
|
24905
25344
|
{ id: "server", label: "Server target", detail: "local or remote, reachable", done: (s) => s.serverReachable, cta: "Choose a server", item: STEP_SERVER },
|
|
24906
25345
|
{ id: "auth", label: "GitHub auth", detail: "signed in on the selected server", done: (s) => s.authSignedIn, cta: "Connect GitHub", item: STEP_AUTH },
|
|
24907
25346
|
{ id: "tasks", label: "Task source", detail: "where work comes from", done: (s) => s.taskSourceReady, cta: "Pick a task source", item: STEP_TASKS }
|
|
24908
25347
|
];
|
|
24909
25348
|
var SECONDARY_ACTIONS = [
|
|
24910
|
-
{ label: "repair", detail: "reconfigure generated config and private state", item: { id: "repair", label: "repair", intent: { scene: "
|
|
24911
|
-
{ 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" } },
|
|
24912
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" } }
|
|
24913
25352
|
];
|
|
24914
25353
|
function record2(value) {
|
|
@@ -24952,11 +25391,11 @@ function renderInitScene(state, layout) {
|
|
|
24952
25391
|
const allDone = completed === SETUP_STEPS.length;
|
|
24953
25392
|
const nextStep = SETUP_STEPS.find((step) => !step.done(signals));
|
|
24954
25393
|
const selected = Math.max(0, state.selection.index);
|
|
24955
|
-
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" });
|
|
24956
25395
|
const secondaryRows = SECONDARY_ACTIONS.map(({ label, detail, item }, index) => selectableDeckRow({ label, detail, active: selected === index + 1 }, item));
|
|
24957
25396
|
const progress = allDone ? "all set" : `${completed} of ${SETUP_STEPS.length} complete`;
|
|
24958
25397
|
const panelLines = [
|
|
24959
|
-
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 }),
|
|
24960
25399
|
line(`progress ${progress}`, { fg: allDone ? RIG_UI.limeDim : RIG_UI.ink2 }),
|
|
24961
25400
|
blank(),
|
|
24962
25401
|
line("CHECKLIST", { fg: RIG_UI.ink3, bold: true }),
|
|
@@ -24968,11 +25407,11 @@ function renderInitScene(state, layout) {
|
|
|
24968
25407
|
line("OTHER PATHS", { fg: RIG_UI.ink3, bold: true }),
|
|
24969
25408
|
...secondaryRows,
|
|
24970
25409
|
blank(),
|
|
24971
|
-
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 })
|
|
24972
25411
|
];
|
|
24973
25412
|
return makeSceneFrame({
|
|
24974
25413
|
scene: "init",
|
|
24975
|
-
title: "
|
|
25414
|
+
title: "Init",
|
|
24976
25415
|
lines: [],
|
|
24977
25416
|
panels: [{
|
|
24978
25417
|
id: "init-setup",
|
|
@@ -24985,11 +25424,11 @@ function renderInitScene(state, layout) {
|
|
|
24985
25424
|
opacity: 0.98,
|
|
24986
25425
|
border: false,
|
|
24987
25426
|
chrome: "ad-terminal",
|
|
24988
|
-
headerText: "rig
|
|
25427
|
+
headerText: "rig init \xB7 guided onboarding",
|
|
24989
25428
|
paddingX: 5,
|
|
24990
25429
|
paddingY: 2
|
|
24991
25430
|
}],
|
|
24992
|
-
footer: { message: allDone ? "
|
|
25431
|
+
footer: { message: allDone ? "init complete" : "init in progress" },
|
|
24993
25432
|
live: !allDone || state.status === "action"
|
|
24994
25433
|
});
|
|
24995
25434
|
}
|
|
@@ -26278,18 +26717,43 @@ function renderRunDetailScene(state, layout) {
|
|
|
26278
26717
|
init_scene();
|
|
26279
26718
|
init_selectable();
|
|
26280
26719
|
init_theme2();
|
|
26720
|
+
init_remote_link();
|
|
26281
26721
|
var SERVER_ACTIONS = [
|
|
26282
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" } },
|
|
26283
|
-
{ detail: "select local server for this repo", item: { id: "local", label: "use local", intent: { scene: "
|
|
26284
|
-
{ detail: "
|
|
26285
|
-
{ detail: "show saved local/remote aliases", item: { id: "list", label: "list servers", intent: { scene: "
|
|
26286
|
-
{ 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" } },
|
|
26287
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" } },
|
|
26288
|
-
{ 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" } },
|
|
26289
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" } },
|
|
26290
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" } },
|
|
26291
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" } }
|
|
26292
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
|
+
}
|
|
26293
26757
|
function cleanVisible(value, fallback = "unknown") {
|
|
26294
26758
|
return value?.trim() || fallback;
|
|
26295
26759
|
}
|
|
@@ -26314,31 +26778,37 @@ function selectedIndex(state, count) {
|
|
|
26314
26778
|
function statusRows2(server) {
|
|
26315
26779
|
const auth = server?.auth;
|
|
26316
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"}` : "";
|
|
26317
26784
|
return [
|
|
26318
|
-
line(`selected ${cleanVisible(server?.label, "not checked")}`, { fg: RIG_UI.ink2 }),
|
|
26785
|
+
line(`selected ${cleanVisible(server?.label, "not checked")}${selectedLinkSummary}`, { fg: RIG_UI.ink2 }),
|
|
26319
26786
|
line(`target ${targetLabel(server)}`, { fg: RIG_UI.ink3 }),
|
|
26320
26787
|
line(`mode ${server?.kind ?? "local or remote"}`, { fg: RIG_UI.ink3 }),
|
|
26321
26788
|
line(`health ${server ? server.reachable ? "reachable" : "unreachable" : "check pending"}`, { fg: server?.reachable ? RIG_UI.limeDim : server ? RIG_UI.red : RIG_UI.yellow }),
|
|
26322
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 })] : [],
|
|
26323
26792
|
...server?.error ? [line(`attention ${server.error}`, { fg: RIG_UI.yellow })] : []
|
|
26324
26793
|
];
|
|
26325
26794
|
}
|
|
26326
26795
|
function renderServerScene(state, layout) {
|
|
26327
26796
|
const server = serverState(state);
|
|
26328
|
-
const
|
|
26797
|
+
const actions = serverActions(state);
|
|
26798
|
+
const selected = selectedIndex(state, actions.length);
|
|
26329
26799
|
const loading = state.status === "loading" && !server;
|
|
26330
26800
|
const errorText = state.error?.message ?? lastRefreshError(state);
|
|
26331
26801
|
const panelLines = [
|
|
26332
26802
|
...errorText ? errorBanner(errorText, "select refresh or doctor below to retry") : [],
|
|
26333
26803
|
line("server controls", { fg: RIG_UI.ink3 }),
|
|
26334
26804
|
blank(),
|
|
26335
|
-
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
26336
|
-
...SERVER_ACTIONS.map(({ detail, item }, index) => selectableDeckRow({ label: item.label, detail, index, active: selected === index }, item)),
|
|
26337
|
-
blank(),
|
|
26338
26805
|
line("STATUS", { fg: RIG_UI.ink3, bold: true }),
|
|
26339
26806
|
...loading ? loadingRows("server status", state.tick) : statusRows2(server),
|
|
26340
26807
|
blank(),
|
|
26341
|
-
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 })
|
|
26342
26812
|
];
|
|
26343
26813
|
return makeSceneFrame({
|
|
26344
26814
|
scene: "server",
|
|
@@ -26367,14 +26837,15 @@ function renderServerScene(state, layout) {
|
|
|
26367
26837
|
// packages/cli/src/app-opentui/scenes/tasks.ts
|
|
26368
26838
|
init_scene();
|
|
26369
26839
|
init_selectable();
|
|
26840
|
+
init_remote_link();
|
|
26370
26841
|
init_theme2();
|
|
26371
|
-
var
|
|
26842
|
+
var BASE_TASK_RECOVERY_ITEMS = [
|
|
26372
26843
|
{ id: "refresh", label: "refresh", intent: { scene: "tasks", argv: ["tasks"], action: { kind: "refresh", label: "Refresh tasks" } }, message: "refresh task source" },
|
|
26373
|
-
{ id: "next", label: "next", intent: { scene: "
|
|
26374
|
-
{ 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" },
|
|
26375
26845
|
{ id: "server", label: "server", intent: { scene: "server", argv: ["server", "status"], action: { kind: "refresh", label: "Open server controls" } }, message: "server controls" },
|
|
26376
26846
|
{ id: "doctor", label: "doctor", intent: { scene: "doctor", argv: ["doctor"], action: { kind: "doctor-run", label: "Run doctor" } }, message: "diagnose task source" }
|
|
26377
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" };
|
|
26378
26849
|
var COL3 = {
|
|
26379
26850
|
glyph: 1,
|
|
26380
26851
|
id: 11,
|
|
@@ -26534,34 +27005,44 @@ function taskRow(width, task, active, optimistic) {
|
|
|
26534
27005
|
const item = taskSelectableItem(task);
|
|
26535
27006
|
return item ? withSelectable(row, item) : row;
|
|
26536
27007
|
}
|
|
26537
|
-
var
|
|
27008
|
+
var BASE_RECOVERY_DECKS2 = [
|
|
26538
27009
|
{ label: "refresh", detail: "reload task source" },
|
|
26539
27010
|
{ label: "next", detail: "dispatch next runnable task" },
|
|
26540
|
-
{ label: "repair", detail: "repair project/task source link" },
|
|
26541
27011
|
{ label: "server", detail: "open server controls" },
|
|
26542
27012
|
{ label: "doctor", detail: "diagnose task source" }
|
|
26543
27013
|
];
|
|
26544
|
-
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);
|
|
26545
27026
|
return [
|
|
26546
27027
|
...reason ? [line(reason, { fg: RIG_UI.yellow }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
26547
27028
|
line("ACTIONS", { fg: RIG_UI.ink3, bold: true }),
|
|
26548
|
-
...
|
|
27029
|
+
...taskRecoveryDecks(state).map((deck, index) => selectableDeckRow({ ...deck, index, active: selected === index }, items[index]))
|
|
26549
27030
|
];
|
|
26550
27031
|
}
|
|
26551
|
-
function emptyRows2(query, total, selected) {
|
|
27032
|
+
function emptyRows2(state, query, total, selected) {
|
|
26552
27033
|
if (!query.trim() && total === 0)
|
|
26553
|
-
return recoveryRows2(selected, "No tasks loaded.");
|
|
27034
|
+
return recoveryRows2(state, selected, "No tasks loaded.");
|
|
26554
27035
|
if (query.trim() && total > 0) {
|
|
26555
27036
|
return [
|
|
26556
|
-
...recoveryRows2(selected, `No matching tasks for ${JSON.stringify(query)} (${total} total).`)
|
|
27037
|
+
...recoveryRows2(state, selected, `No matching tasks for ${JSON.stringify(query)} (${total} total).`)
|
|
26557
27038
|
];
|
|
26558
27039
|
}
|
|
26559
|
-
return recoveryRows2(selected, "No tasks are visible with this filter.");
|
|
27040
|
+
return recoveryRows2(state, selected, "No tasks are visible with this filter.");
|
|
26560
27041
|
}
|
|
26561
27042
|
function degradedRows2(state, selected) {
|
|
26562
27043
|
if (!state.error)
|
|
26563
27044
|
return [];
|
|
26564
|
-
return recoveryRows2(selected, state.error.message);
|
|
27045
|
+
return recoveryRows2(state, selected, state.error.message);
|
|
26565
27046
|
}
|
|
26566
27047
|
function rawString(raw, key) {
|
|
26567
27048
|
const value = raw?.[key];
|
|
@@ -26585,7 +27066,10 @@ function renderTaskDetail(state, taskId3, layout) {
|
|
|
26585
27066
|
const activeRunId = task?.activeRun?.runId?.trim();
|
|
26586
27067
|
const width = panelWidth13(layout);
|
|
26587
27068
|
const selected = Math.max(0, state.selection.index);
|
|
27069
|
+
const errorText = state.error?.message ?? lastRefreshError(state);
|
|
27070
|
+
const offerRepairLink = shouldOfferRemoteLinkRepair(state, errorText);
|
|
26588
27071
|
const headerLines = [
|
|
27072
|
+
...errorText ? errorBanner(errorText, offerRepairLink ? "select repair link below to prepare the remote checkout" : "retry dispatch after resolving the issue") : [],
|
|
26589
27073
|
line(`${glyph2} ${title}`, { fg: color, bold: true }),
|
|
26590
27074
|
line(`task ${taskId3} \xB7 ${status}`, { fg: RIG_UI.ink3 }),
|
|
26591
27075
|
...task && task.labels.length > 0 ? [line(`labels: ${task.labels.join(", ")}`, { fg: RIG_UI.ink4 })] : [],
|
|
@@ -26597,8 +27081,16 @@ function renderTaskDetail(state, taskId3, layout) {
|
|
|
26597
27081
|
const actionRows2 = [];
|
|
26598
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" }));
|
|
26599
27083
|
index += 1;
|
|
26600
|
-
|
|
26601
|
-
|
|
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
|
+
}
|
|
26602
27094
|
if (activeRunId) {
|
|
26603
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)}` }));
|
|
26604
27096
|
index += 1;
|
|
@@ -26657,7 +27149,7 @@ function renderTasksScene(state, layout) {
|
|
|
26657
27149
|
const tasks = sortTasks2(filterTasksForSearch(allTasks, query), spec);
|
|
26658
27150
|
const selected = typeof state.data.selectedTaskId === "string" && tasks.some((task) => task.id === state.data.selectedTaskId) ? state.data.selectedTaskId : tasks[0]?.id;
|
|
26659
27151
|
const selectedIndex2 = Math.max(0, tasks.findIndex((task) => task.id === selected));
|
|
26660
|
-
const recoveryIndex = Math.max(0, Math.min(
|
|
27152
|
+
const recoveryIndex = Math.max(0, Math.min(taskRecoveryItems(state).length - 1, state.selection.index));
|
|
26661
27153
|
const dispatching = dispatchingFor(state);
|
|
26662
27154
|
const dispatchLine = dispatching ? ` \xB7 ${state.data.dispatchingRun?.runId ?? "new"} ${dispatching.status}` : "";
|
|
26663
27155
|
const updatedAgo = updatedAgoLabel2(state);
|
|
@@ -26677,7 +27169,7 @@ function renderTasksScene(state, layout) {
|
|
|
26677
27169
|
...tasks.map((task, index) => taskRow(contentWidth, task, index === selectedIndex2, dispatching && dispatching.taskId === task.id ? dispatching.status : undefined))
|
|
26678
27170
|
] : state.error ? degradedRows2(state, recoveryIndex) : loading ? loadingRows("tasks", state.tick) : [
|
|
26679
27171
|
...query.trim() ? [line(searchSummary("tasks", query, tasks.length, allTasks.length), { fg: RIG_UI.ink4 }), line("", { fg: RIG_UI.ink3 })] : [],
|
|
26680
|
-
...emptyRows2(query, allTasks.length, recoveryIndex)
|
|
27172
|
+
...emptyRows2(state, query, allTasks.length, recoveryIndex)
|
|
26681
27173
|
]
|
|
26682
27174
|
];
|
|
26683
27175
|
return makeSceneFrame({
|
|
@@ -27038,6 +27530,29 @@ function createDomainAdapter() {
|
|
|
27038
27530
|
else
|
|
27039
27531
|
await loadInitFacts(ctx);
|
|
27040
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
|
+
}
|
|
27041
27556
|
case "doctor-run":
|
|
27042
27557
|
await runDoctorChecksForApp(ctx);
|
|
27043
27558
|
return true;
|
|
@@ -27256,7 +27771,7 @@ function parsePolicyMode2(value) {
|
|
|
27256
27771
|
function resolveProjectRoot2(input) {
|
|
27257
27772
|
if (input.envProjectRoot)
|
|
27258
27773
|
return resolve31(input.cwd, input.envProjectRoot);
|
|
27259
|
-
const execName =
|
|
27774
|
+
const execName = basename5(input.execPath).toLowerCase();
|
|
27260
27775
|
const execCandidates = execName === "rig" || execName === "rig.exe" ? [resolve31(input.execPath, "..", "..")] : [];
|
|
27261
27776
|
const candidates = [input.cwd, ...execCandidates, resolve31(input.importDir, "..")];
|
|
27262
27777
|
for (const candidate of candidates) {
|