@h-rig/cli 0.0.6-alpha.82 → 0.0.6-alpha.84
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/build-rig-binaries.js +40 -8
- package/dist/bin/rig.js +23402 -14577
- package/dist/src/app/board.js +217 -41
- package/dist/src/app-opentui/adapters/command.d.ts +2 -0
- package/dist/src/app-opentui/adapters/command.js +329 -0
- package/dist/src/app-opentui/adapters/common.js +2 -2
- package/dist/src/app-opentui/adapters/doctor.d.ts +0 -2
- package/dist/src/app-opentui/adapters/doctor.js +64 -39
- package/dist/src/app-opentui/adapters/family.d.ts +62 -0
- package/dist/src/app-opentui/adapters/family.js +14305 -0
- package/dist/src/app-opentui/adapters/fleet.d.ts +0 -2
- package/dist/src/app-opentui/adapters/fleet.js +90 -60
- package/dist/src/app-opentui/adapters/inbox.d.ts +12 -2
- package/dist/src/app-opentui/adapters/inbox.js +137 -78
- package/dist/src/app-opentui/adapters/init.d.ts +0 -2
- package/dist/src/app-opentui/adapters/init.js +85 -47
- package/dist/src/app-opentui/adapters/inspect.d.ts +52 -0
- package/dist/src/app-opentui/adapters/inspect.js +1024 -0
- package/dist/src/app-opentui/adapters/pi-attach.d.ts +15 -6
- package/dist/src/app-opentui/adapters/pi-attach.js +442 -125
- package/dist/src/app-opentui/adapters/pi.d.ts +23 -0
- package/dist/src/app-opentui/adapters/pi.js +363 -0
- package/dist/src/app-opentui/adapters/plugin.d.ts +84 -0
- package/dist/src/app-opentui/adapters/plugin.js +544 -0
- package/dist/src/app-opentui/adapters/repo.d.ts +37 -0
- package/dist/src/app-opentui/adapters/repo.js +186 -0
- package/dist/src/app-opentui/adapters/run-detail.d.ts +9 -2
- package/dist/src/app-opentui/adapters/run-detail.js +180 -63
- package/dist/src/app-opentui/adapters/server.d.ts +10 -2
- package/dist/src/app-opentui/adapters/server.js +191 -45
- package/dist/src/app-opentui/adapters/tasks.d.ts +11 -2
- package/dist/src/app-opentui/adapters/tasks.js +1123 -143
- package/dist/src/app-opentui/adapters/workspace.d.ts +49 -0
- package/dist/src/app-opentui/adapters/workspace.js +333 -0
- package/dist/src/app-opentui/autocomplete.d.ts +20 -0
- package/dist/src/app-opentui/autocomplete.js +576 -0
- package/dist/src/app-opentui/bootstrap.d.ts +1 -6
- package/dist/src/app-opentui/bootstrap.js +25252 -16474
- package/dist/src/app-opentui/command-palette.d.ts +3 -0
- package/dist/src/app-opentui/command-palette.js +1010 -0
- package/dist/src/app-opentui/command-pty-host.d.ts +62 -0
- package/dist/src/app-opentui/command-pty-host.js +248 -0
- package/dist/src/app-opentui/drone.js +8 -6
- package/dist/src/app-opentui/events.js +1 -1
- package/dist/src/app-opentui/fleet-stats.d.ts +32 -0
- package/dist/src/app-opentui/fleet-stats.js +114 -0
- package/dist/src/app-opentui/focus-manager.d.ts +14 -0
- package/dist/src/app-opentui/focus-manager.js +24 -0
- package/dist/src/app-opentui/index.js +5431 -2797
- package/dist/src/app-opentui/intent.js +179 -50
- package/dist/src/app-opentui/keymap.d.ts +21 -0
- package/dist/src/app-opentui/keymap.js +1748 -0
- package/dist/src/app-opentui/launch-routing.d.ts +16 -0
- package/dist/src/app-opentui/launch-routing.js +55 -0
- package/dist/src/app-opentui/layout.d.ts +7 -0
- package/dist/src/app-opentui/layout.js +13 -6
- package/dist/src/app-opentui/list-search.d.ts +24 -0
- package/dist/src/app-opentui/list-search.js +88 -1
- package/dist/src/app-opentui/pi-host-child.js +99 -17
- package/dist/src/app-opentui/pi-pty-host.d.ts +14 -0
- package/dist/src/app-opentui/pi-pty-host.js +30 -14
- package/dist/src/app-opentui/react/App.d.ts +9 -0
- package/dist/src/app-opentui/react/App.js +5144 -0
- package/dist/src/app-opentui/react/Backdrop.d.ts +5 -0
- package/dist/src/app-opentui/react/Backdrop.js +1834 -0
- package/dist/src/app-opentui/react/ChromeHost.d.ts +5 -0
- package/dist/src/app-opentui/react/ChromeHost.js +2942 -0
- package/dist/src/app-opentui/react/SceneFrameView.d.ts +7 -0
- package/dist/src/app-opentui/react/SceneFrameView.js +529 -0
- package/dist/src/app-opentui/react/context.d.ts +17 -0
- package/dist/src/app-opentui/react/context.js +37 -0
- package/dist/src/app-opentui/react/launch.d.ts +2 -0
- package/dist/src/app-opentui/react/launch.js +5743 -0
- package/dist/src/app-opentui/react/nav.d.ts +18 -0
- package/dist/src/app-opentui/react/nav.js +54 -0
- package/dist/src/app-opentui/react/scroll.d.ts +12 -0
- package/dist/src/app-opentui/react/scroll.js +21 -0
- package/dist/src/app-opentui/react/syntax.d.ts +2 -0
- package/dist/src/app-opentui/react/syntax.js +64 -0
- package/dist/src/app-opentui/registry.js +20428 -4828
- package/dist/src/app-opentui/render/ascii-fleet.d.ts +15 -0
- package/dist/src/app-opentui/render/ascii-fleet.js +82 -0
- package/dist/src/app-opentui/render/constants.d.ts +31 -0
- package/dist/src/app-opentui/render/constants.js +66 -0
- package/dist/src/app-opentui/render/graphics.d.ts +2 -1
- package/dist/src/app-opentui/render/graphics.js +228 -46
- package/dist/src/app-opentui/render/image-visual-layer-worker.js +469 -930
- package/dist/src/app-opentui/render/image-visual-layer.d.ts +25 -10
- package/dist/src/app-opentui/render/image-visual-layer.js +448 -329
- package/dist/src/app-opentui/render/native-host.d.ts +37 -0
- package/dist/src/app-opentui/render/native-host.js +179 -0
- package/dist/src/app-opentui/render/panel-layout.d.ts +38 -0
- package/dist/src/app-opentui/render/panel-layout.js +48 -0
- package/dist/src/app-opentui/render/panels.d.ts +2 -0
- package/dist/src/app-opentui/render/panels.js +78 -38
- package/dist/src/app-opentui/render/preloader.d.ts +10 -0
- package/dist/src/app-opentui/render/preloader.js +165 -0
- package/dist/src/app-opentui/render/scene.d.ts +53 -1
- package/dist/src/app-opentui/render/scene.js +195 -6
- package/dist/src/app-opentui/render/text.d.ts +7 -1
- package/dist/src/app-opentui/render/text.js +15 -8
- package/dist/src/app-opentui/render/type-bar.d.ts +2 -1
- package/dist/src/app-opentui/render/type-bar.js +113 -39
- package/dist/src/app-opentui/runtime-resources.d.ts +16 -0
- package/dist/src/app-opentui/runtime-resources.js +62 -0
- package/dist/src/app-opentui/runtime.d.ts +44 -1
- package/dist/src/app-opentui/runtime.js +5415 -2738
- package/dist/src/app-opentui/scenes/command.d.ts +3 -0
- package/dist/src/app-opentui/scenes/command.js +117 -0
- package/dist/src/app-opentui/scenes/doctor.d.ts +2 -1
- package/dist/src/app-opentui/scenes/doctor.js +221 -17
- package/dist/src/app-opentui/scenes/error.js +60 -20
- package/dist/src/app-opentui/scenes/family-domains/agent.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/agent.js +348 -0
- package/dist/src/app-opentui/scenes/family-domains/browser.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/browser.js +195 -0
- package/dist/src/app-opentui/scenes/family-domains/dist.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/dist.js +243 -0
- package/dist/src/app-opentui/scenes/family-domains/git.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/git.js +195 -0
- package/dist/src/app-opentui/scenes/family-domains/github.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/github.js +274 -0
- package/dist/src/app-opentui/scenes/family-domains/harness.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/harness.js +152 -0
- package/dist/src/app-opentui/scenes/family-domains/index.d.ts +4 -0
- package/dist/src/app-opentui/scenes/family-domains/index.js +1679 -0
- package/dist/src/app-opentui/scenes/family-domains/kit.d.ts +76 -0
- package/dist/src/app-opentui/scenes/family-domains/kit.js +305 -0
- package/dist/src/app-opentui/scenes/family-domains/profile.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/profile.js +212 -0
- package/dist/src/app-opentui/scenes/family-domains/queue.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/queue.js +146 -0
- package/dist/src/app-opentui/scenes/family-domains/remote.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/remote.js +518 -0
- package/dist/src/app-opentui/scenes/family-domains/review.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/review.js +280 -0
- package/dist/src/app-opentui/scenes/family-domains/setup.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/setup.js +267 -0
- package/dist/src/app-opentui/scenes/family-domains/stats.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/stats.js +370 -0
- package/dist/src/app-opentui/scenes/family.d.ts +3 -0
- package/dist/src/app-opentui/scenes/family.js +2144 -0
- package/dist/src/app-opentui/scenes/fleet.js +552 -43
- package/dist/src/app-opentui/scenes/handoff.js +342 -35
- package/dist/src/app-opentui/scenes/help.js +640 -56
- package/dist/src/app-opentui/scenes/inbox.d.ts +2 -1
- package/dist/src/app-opentui/scenes/inbox.js +329 -21
- package/dist/src/app-opentui/scenes/init.d.ts +2 -1
- package/dist/src/app-opentui/scenes/init.js +120 -34
- package/dist/src/app-opentui/scenes/inspect.d.ts +3 -0
- package/dist/src/app-opentui/scenes/inspect.js +793 -0
- package/dist/src/app-opentui/scenes/main.d.ts +2 -1
- package/dist/src/app-opentui/scenes/main.js +264 -29
- package/dist/src/app-opentui/scenes/pi.d.ts +3 -0
- package/dist/src/app-opentui/scenes/pi.js +508 -0
- package/dist/src/app-opentui/scenes/plugin.d.ts +3 -0
- package/dist/src/app-opentui/scenes/plugin.js +486 -0
- package/dist/src/app-opentui/scenes/repo.d.ts +3 -0
- package/dist/src/app-opentui/scenes/repo.js +424 -0
- package/dist/src/app-opentui/scenes/run-detail.d.ts +2 -1
- package/dist/src/app-opentui/scenes/run-detail.js +362 -35
- package/dist/src/app-opentui/scenes/server.d.ts +2 -1
- package/dist/src/app-opentui/scenes/server.js +243 -26
- package/dist/src/app-opentui/scenes/tasks.js +518 -41
- package/dist/src/app-opentui/scenes/workspace.d.ts +3 -0
- package/dist/src/app-opentui/scenes/workspace.js +426 -0
- package/dist/src/app-opentui/selectable.d.ts +19 -0
- package/dist/src/app-opentui/selectable.js +79 -0
- package/dist/src/app-opentui/state.js +129 -36
- package/dist/src/app-opentui/surface-catalog.d.ts +20 -0
- package/dist/src/app-opentui/surface-catalog.js +540 -0
- package/dist/src/app-opentui/terminal-capabilities.d.ts +7 -0
- package/dist/src/app-opentui/terminal-capabilities.js +15 -0
- package/dist/src/app-opentui/theme.d.ts +28 -6
- package/dist/src/app-opentui/theme.js +61 -8
- package/dist/src/app-opentui/types.d.ts +130 -5
- package/dist/src/commands/_authority-runs.d.ts +1 -1
- package/dist/src/commands/_authority-runs.js +2 -12
- package/dist/src/commands/_doctor-checks.js +62 -13
- package/dist/src/commands/_help-catalog.js +95 -15
- package/dist/src/commands/_operator-view.js +97 -15
- package/dist/src/commands/_pi-frontend.d.ts +2 -0
- package/dist/src/commands/_pi-frontend.js +97 -13
- package/dist/src/commands/_preflight.js +64 -14
- package/dist/src/commands/_server-client.js +82 -18
- package/dist/src/commands/_server-events.d.ts +26 -0
- package/dist/src/commands/_server-events.js +310 -0
- package/dist/src/commands/_snapshot-upload.js +62 -13
- package/dist/src/commands/agent.js +2 -12
- package/dist/src/commands/connect.js +7 -1
- package/dist/src/commands/doctor.js +62 -13
- package/dist/src/commands/github.js +144 -23
- package/dist/src/commands/inbox.js +62 -13
- package/dist/src/commands/init.js +82 -18
- package/dist/src/commands/inspect.js +62 -13
- package/dist/src/commands/run.js +100 -15
- package/dist/src/commands/server.js +71 -26
- package/dist/src/commands/setup.js +62 -13
- package/dist/src/commands/stats.js +157 -28
- package/dist/src/commands/task-run-driver.js +64 -25
- package/dist/src/commands/task.js +196 -43
- package/dist/src/commands.js +419 -123
- package/dist/src/index.js +426 -130
- package/package.json +11 -10
- package/dist/src/app-opentui/render/image-visual-layer-native-canvas.d.ts +0 -2
- package/dist/src/app-opentui/render/image-visual-layer-native-canvas.js +0 -1484
|
@@ -502,17 +502,21 @@ function setGitHubBearerTokenForCurrentProcess(token, projectRoot) {
|
|
|
502
502
|
const scopedKey = resolve2(projectRoot ?? process.cwd());
|
|
503
503
|
scopedGitHubBearerTokens.set(scopedKey, cleanToken(token ?? undefined));
|
|
504
504
|
}
|
|
505
|
-
function
|
|
505
|
+
function readRemoteAuthState(projectRoot) {
|
|
506
506
|
const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
|
|
507
507
|
if (!existsSync2(path))
|
|
508
508
|
return null;
|
|
509
509
|
try {
|
|
510
510
|
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
511
|
-
return
|
|
511
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
512
512
|
} catch {
|
|
513
513
|
return null;
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
|
+
function readPrivateRemoteSessionToken(projectRoot) {
|
|
517
|
+
const parsed = readRemoteAuthState(projectRoot);
|
|
518
|
+
return parsed ? cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined) : null;
|
|
519
|
+
}
|
|
516
520
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
517
521
|
const scopedKey = resolve2(projectRoot);
|
|
518
522
|
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
@@ -523,15 +527,25 @@ function readGitHubBearerTokenForRemote(projectRoot) {
|
|
|
523
527
|
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
524
528
|
}
|
|
525
529
|
function readStoredGitHubAuthToken(projectRoot) {
|
|
526
|
-
const
|
|
527
|
-
|
|
530
|
+
const parsed = readRemoteAuthState(projectRoot);
|
|
531
|
+
return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
|
|
532
|
+
}
|
|
533
|
+
function inferRemoteServerProjectRootFromAuthState(projectRoot) {
|
|
534
|
+
const repo = readRepoConnection(projectRoot);
|
|
535
|
+
const slug = repo?.project?.trim();
|
|
536
|
+
if (!slug || !/^[^/]+\/[^/]+$/.test(slug))
|
|
528
537
|
return null;
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
538
|
+
const auth = readRemoteAuthState(projectRoot);
|
|
539
|
+
const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
|
|
540
|
+
const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
|
|
541
|
+
if (Number.isFinite(authUpdatedAt) && Number.isFinite(repoLinkedAt) && authUpdatedAt + 1000 < repoLinkedAt)
|
|
533
542
|
return null;
|
|
534
|
-
|
|
543
|
+
const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
|
|
544
|
+
if (!checkoutBaseDir)
|
|
545
|
+
return null;
|
|
546
|
+
const inferred = `${checkoutBaseDir.replace(/\/+$/, "")}/${slug}`;
|
|
547
|
+
writeRepoServerProjectRoot(projectRoot, inferred);
|
|
548
|
+
return inferred;
|
|
535
549
|
}
|
|
536
550
|
function readLocalConnectionFallbackToken(projectRoot) {
|
|
537
551
|
return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
|
|
@@ -542,7 +556,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
542
556
|
if (selected?.connection.kind === "remote") {
|
|
543
557
|
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
544
558
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
545
|
-
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
559
|
+
const serverProjectRoot = selected.serverProjectRoot ?? inferRemoteServerProjectRootFromAuthState(projectRoot) ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
546
560
|
return {
|
|
547
561
|
baseUrl: selected.connection.baseUrl,
|
|
548
562
|
authToken,
|
|
@@ -571,7 +585,10 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
|
|
|
571
585
|
if (!slug)
|
|
572
586
|
return null;
|
|
573
587
|
try {
|
|
574
|
-
const
|
|
588
|
+
const url = new URL(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`);
|
|
589
|
+
if (authToken && queryAuthFallbackEnabled())
|
|
590
|
+
url.searchParams.set("rt", authToken);
|
|
591
|
+
const response = await fetch(url, {
|
|
575
592
|
headers: mergeHeaders(undefined, authToken)
|
|
576
593
|
});
|
|
577
594
|
if (!response.ok)
|
|
@@ -588,10 +605,23 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
|
|
|
588
605
|
return null;
|
|
589
606
|
}
|
|
590
607
|
}
|
|
608
|
+
function mergeCookie(existing, name, value) {
|
|
609
|
+
const encoded = `${name}=${encodeURIComponent(value)}`;
|
|
610
|
+
if (!existing?.trim())
|
|
611
|
+
return encoded;
|
|
612
|
+
const parts = existing.split(";").map((part) => part.trim()).filter((part) => part && !part.startsWith(`${name}=`));
|
|
613
|
+
return [...parts, encoded].join("; ");
|
|
614
|
+
}
|
|
615
|
+
function queryAuthFallbackEnabled(env = process.env) {
|
|
616
|
+
return env.RIG_ENABLE_QUERY_AUTH_FALLBACK === "1" || env.RIG_QUERY_AUTH_FALLBACK === "1";
|
|
617
|
+
}
|
|
591
618
|
function mergeHeaders(headers, authToken) {
|
|
592
619
|
const merged = new Headers(headers);
|
|
593
620
|
if (authToken) {
|
|
594
|
-
|
|
621
|
+
const bearer = `Bearer ${authToken}`;
|
|
622
|
+
merged.set("authorization", bearer);
|
|
623
|
+
merged.set("x-auth", bearer);
|
|
624
|
+
merged.set("cookie", mergeCookie(merged.get("cookie"), "rig_auth", authToken));
|
|
595
625
|
}
|
|
596
626
|
return merged;
|
|
597
627
|
}
|
|
@@ -652,15 +682,34 @@ async function buildServerFailureContext(projectRoot, server) {
|
|
|
652
682
|
hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
|
|
653
683
|
};
|
|
654
684
|
}
|
|
685
|
+
function isLoopbackRemoteBaseUrl(baseUrl) {
|
|
686
|
+
try {
|
|
687
|
+
const host = new URL(baseUrl).hostname.toLowerCase();
|
|
688
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
|
|
689
|
+
} catch {
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
function canUseRemoteWithoutProjectRoot(pathname) {
|
|
694
|
+
return pathname === "/health" || pathname === "/api/health" || pathname === "/api/server/status" || pathname === "/api/server/project-root" || pathname.startsWith("/api/github/auth/") || pathname === "/api/projects" || pathname.startsWith("/api/projects/");
|
|
695
|
+
}
|
|
655
696
|
async function requestServerJson(context, pathname, init = {}) {
|
|
656
697
|
const server = await ensureServerForCli(context.projectRoot);
|
|
698
|
+
const requestUrl = new URL(`${server.baseUrl}${pathname}`);
|
|
699
|
+
if (server.connectionKind === "remote" && !server.serverProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
|
|
700
|
+
const repo = readRepoConnection(context.projectRoot);
|
|
701
|
+
throw new CliError(`Remote server is selected for ${repo?.project ?? "this repo"}, but this checkout has no server-host project root link.`, 1, { hint: "Run `rig init --repair` or `rig init --yes --repo owner/repo --server remote` to repair the remote project link before task/run commands." });
|
|
702
|
+
}
|
|
657
703
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
658
704
|
if (server.serverProjectRoot)
|
|
659
705
|
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
706
|
+
if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
|
|
707
|
+
requestUrl.searchParams.set("rt", server.authToken);
|
|
708
|
+
}
|
|
660
709
|
reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
|
|
661
710
|
let response;
|
|
662
711
|
try {
|
|
663
|
-
response = await fetch(
|
|
712
|
+
response = await fetch(requestUrl, {
|
|
664
713
|
...init,
|
|
665
714
|
headers
|
|
666
715
|
});
|
|
@@ -689,11 +738,26 @@ ${failure.contextLine}`, 1, { hint: failure.hint });
|
|
|
689
738
|
return payload;
|
|
690
739
|
}
|
|
691
740
|
async function postGitHubTokenViaServer(context, token, options = {}) {
|
|
692
|
-
const
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
741
|
+
const server = await ensureServerForCli(context.projectRoot);
|
|
742
|
+
const requestUrl = new URL(`${server.baseUrl}/api/github/auth/token`);
|
|
743
|
+
reportServerPhase("POST /api/github/auth/token\u2026");
|
|
744
|
+
let response;
|
|
745
|
+
try {
|
|
746
|
+
response = await fetch(requestUrl, {
|
|
747
|
+
method: "POST",
|
|
748
|
+
headers: { "content-type": "application/json" },
|
|
749
|
+
body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot ?? server.serverProjectRoot ?? undefined })
|
|
750
|
+
});
|
|
751
|
+
} catch (error) {
|
|
752
|
+
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
753
|
+
throw new CliError(`Rig server auth bootstrap failed: ${error instanceof Error ? error.message : String(error)}
|
|
754
|
+
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
755
|
+
}
|
|
756
|
+
const payload = await response.json().catch(() => null);
|
|
757
|
+
if (!response.ok) {
|
|
758
|
+
const detail = payload && typeof payload === "object" && !Array.isArray(payload) ? String(payload.error ?? JSON.stringify(payload)) : `HTTP ${response.status}`;
|
|
759
|
+
throw new CliError(`Rig server auth bootstrap failed (${response.status}): ${detail}`, 1, { hint: "Re-run `rig github auth import-gh`, or check the selected server with `rig server status`." });
|
|
760
|
+
}
|
|
697
761
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
698
762
|
}
|
|
699
763
|
async function prepareRemoteCheckoutViaServer(context, input) {
|
|
@@ -180,17 +180,21 @@ function cleanToken(value) {
|
|
|
180
180
|
const trimmed = value?.trim();
|
|
181
181
|
return trimmed ? trimmed : null;
|
|
182
182
|
}
|
|
183
|
-
function
|
|
183
|
+
function readRemoteAuthState(projectRoot) {
|
|
184
184
|
const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
|
|
185
185
|
if (!existsSync2(path))
|
|
186
186
|
return null;
|
|
187
187
|
try {
|
|
188
188
|
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
189
|
-
return
|
|
189
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
190
190
|
} catch {
|
|
191
191
|
return null;
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
|
+
function readPrivateRemoteSessionToken(projectRoot) {
|
|
195
|
+
const parsed = readRemoteAuthState(projectRoot);
|
|
196
|
+
return parsed ? cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined) : null;
|
|
197
|
+
}
|
|
194
198
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
195
199
|
const scopedKey = resolve2(projectRoot);
|
|
196
200
|
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
@@ -201,15 +205,25 @@ function readGitHubBearerTokenForRemote(projectRoot) {
|
|
|
201
205
|
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
202
206
|
}
|
|
203
207
|
function readStoredGitHubAuthToken(projectRoot) {
|
|
204
|
-
const
|
|
205
|
-
|
|
208
|
+
const parsed = readRemoteAuthState(projectRoot);
|
|
209
|
+
return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
|
|
210
|
+
}
|
|
211
|
+
function inferRemoteServerProjectRootFromAuthState(projectRoot) {
|
|
212
|
+
const repo = readRepoConnection(projectRoot);
|
|
213
|
+
const slug = repo?.project?.trim();
|
|
214
|
+
if (!slug || !/^[^/]+\/[^/]+$/.test(slug))
|
|
206
215
|
return null;
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
216
|
+
const auth = readRemoteAuthState(projectRoot);
|
|
217
|
+
const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
|
|
218
|
+
const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
|
|
219
|
+
if (Number.isFinite(authUpdatedAt) && Number.isFinite(repoLinkedAt) && authUpdatedAt + 1000 < repoLinkedAt)
|
|
211
220
|
return null;
|
|
212
|
-
|
|
221
|
+
const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
|
|
222
|
+
if (!checkoutBaseDir)
|
|
223
|
+
return null;
|
|
224
|
+
const inferred = `${checkoutBaseDir.replace(/\/+$/, "")}/${slug}`;
|
|
225
|
+
writeRepoServerProjectRoot(projectRoot, inferred);
|
|
226
|
+
return inferred;
|
|
213
227
|
}
|
|
214
228
|
function readLocalConnectionFallbackToken(projectRoot) {
|
|
215
229
|
return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
|
|
@@ -220,7 +234,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
220
234
|
if (selected?.connection.kind === "remote") {
|
|
221
235
|
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
222
236
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
223
|
-
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
237
|
+
const serverProjectRoot = selected.serverProjectRoot ?? inferRemoteServerProjectRootFromAuthState(projectRoot) ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
224
238
|
return {
|
|
225
239
|
baseUrl: selected.connection.baseUrl,
|
|
226
240
|
authToken,
|
|
@@ -249,7 +263,10 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
|
|
|
249
263
|
if (!slug)
|
|
250
264
|
return null;
|
|
251
265
|
try {
|
|
252
|
-
const
|
|
266
|
+
const url = new URL(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`);
|
|
267
|
+
if (authToken && queryAuthFallbackEnabled())
|
|
268
|
+
url.searchParams.set("rt", authToken);
|
|
269
|
+
const response = await fetch(url, {
|
|
253
270
|
headers: mergeHeaders(undefined, authToken)
|
|
254
271
|
});
|
|
255
272
|
if (!response.ok)
|
|
@@ -266,10 +283,23 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
|
|
|
266
283
|
return null;
|
|
267
284
|
}
|
|
268
285
|
}
|
|
286
|
+
function mergeCookie(existing, name, value) {
|
|
287
|
+
const encoded = `${name}=${encodeURIComponent(value)}`;
|
|
288
|
+
if (!existing?.trim())
|
|
289
|
+
return encoded;
|
|
290
|
+
const parts = existing.split(";").map((part) => part.trim()).filter((part) => part && !part.startsWith(`${name}=`));
|
|
291
|
+
return [...parts, encoded].join("; ");
|
|
292
|
+
}
|
|
293
|
+
function queryAuthFallbackEnabled(env = process.env) {
|
|
294
|
+
return env.RIG_ENABLE_QUERY_AUTH_FALLBACK === "1" || env.RIG_QUERY_AUTH_FALLBACK === "1";
|
|
295
|
+
}
|
|
269
296
|
function mergeHeaders(headers, authToken) {
|
|
270
297
|
const merged = new Headers(headers);
|
|
271
298
|
if (authToken) {
|
|
272
|
-
|
|
299
|
+
const bearer = `Bearer ${authToken}`;
|
|
300
|
+
merged.set("authorization", bearer);
|
|
301
|
+
merged.set("x-auth", bearer);
|
|
302
|
+
merged.set("cookie", mergeCookie(merged.get("cookie"), "rig_auth", authToken));
|
|
273
303
|
}
|
|
274
304
|
return merged;
|
|
275
305
|
}
|
|
@@ -330,15 +360,34 @@ async function buildServerFailureContext(projectRoot, server) {
|
|
|
330
360
|
hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
|
|
331
361
|
};
|
|
332
362
|
}
|
|
363
|
+
function isLoopbackRemoteBaseUrl(baseUrl) {
|
|
364
|
+
try {
|
|
365
|
+
const host = new URL(baseUrl).hostname.toLowerCase();
|
|
366
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
|
|
367
|
+
} catch {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function canUseRemoteWithoutProjectRoot(pathname) {
|
|
372
|
+
return pathname === "/health" || pathname === "/api/health" || pathname === "/api/server/status" || pathname === "/api/server/project-root" || pathname.startsWith("/api/github/auth/") || pathname === "/api/projects" || pathname.startsWith("/api/projects/");
|
|
373
|
+
}
|
|
333
374
|
async function requestServerJson(context, pathname, init = {}) {
|
|
334
375
|
const server = await ensureServerForCli(context.projectRoot);
|
|
376
|
+
const requestUrl = new URL(`${server.baseUrl}${pathname}`);
|
|
377
|
+
if (server.connectionKind === "remote" && !server.serverProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
|
|
378
|
+
const repo = readRepoConnection(context.projectRoot);
|
|
379
|
+
throw new CliError(`Remote server is selected for ${repo?.project ?? "this repo"}, but this checkout has no server-host project root link.`, 1, { hint: "Run `rig init --repair` or `rig init --yes --repo owner/repo --server remote` to repair the remote project link before task/run commands." });
|
|
380
|
+
}
|
|
335
381
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
336
382
|
if (server.serverProjectRoot)
|
|
337
383
|
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
384
|
+
if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
|
|
385
|
+
requestUrl.searchParams.set("rt", server.authToken);
|
|
386
|
+
}
|
|
338
387
|
reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
|
|
339
388
|
let response;
|
|
340
389
|
try {
|
|
341
|
-
response = await fetch(
|
|
390
|
+
response = await fetch(requestUrl, {
|
|
342
391
|
...init,
|
|
343
392
|
headers
|
|
344
393
|
});
|
package/dist/src/commands/run.js
CHANGED
|
@@ -205,17 +205,21 @@ function cleanToken(value) {
|
|
|
205
205
|
const trimmed = value?.trim();
|
|
206
206
|
return trimmed ? trimmed : null;
|
|
207
207
|
}
|
|
208
|
-
function
|
|
208
|
+
function readRemoteAuthState(projectRoot) {
|
|
209
209
|
const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
|
|
210
210
|
if (!existsSync2(path))
|
|
211
211
|
return null;
|
|
212
212
|
try {
|
|
213
213
|
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
214
|
-
return
|
|
214
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
215
215
|
} catch {
|
|
216
216
|
return null;
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
|
+
function readPrivateRemoteSessionToken(projectRoot) {
|
|
220
|
+
const parsed = readRemoteAuthState(projectRoot);
|
|
221
|
+
return parsed ? cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined) : null;
|
|
222
|
+
}
|
|
219
223
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
220
224
|
const scopedKey = resolve2(projectRoot);
|
|
221
225
|
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
@@ -226,15 +230,25 @@ function readGitHubBearerTokenForRemote(projectRoot) {
|
|
|
226
230
|
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
227
231
|
}
|
|
228
232
|
function readStoredGitHubAuthToken(projectRoot) {
|
|
229
|
-
const
|
|
230
|
-
|
|
233
|
+
const parsed = readRemoteAuthState(projectRoot);
|
|
234
|
+
return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
|
|
235
|
+
}
|
|
236
|
+
function inferRemoteServerProjectRootFromAuthState(projectRoot) {
|
|
237
|
+
const repo = readRepoConnection(projectRoot);
|
|
238
|
+
const slug = repo?.project?.trim();
|
|
239
|
+
if (!slug || !/^[^/]+\/[^/]+$/.test(slug))
|
|
231
240
|
return null;
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
241
|
+
const auth = readRemoteAuthState(projectRoot);
|
|
242
|
+
const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
|
|
243
|
+
const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
|
|
244
|
+
if (Number.isFinite(authUpdatedAt) && Number.isFinite(repoLinkedAt) && authUpdatedAt + 1000 < repoLinkedAt)
|
|
236
245
|
return null;
|
|
237
|
-
|
|
246
|
+
const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
|
|
247
|
+
if (!checkoutBaseDir)
|
|
248
|
+
return null;
|
|
249
|
+
const inferred = `${checkoutBaseDir.replace(/\/+$/, "")}/${slug}`;
|
|
250
|
+
writeRepoServerProjectRoot(projectRoot, inferred);
|
|
251
|
+
return inferred;
|
|
238
252
|
}
|
|
239
253
|
function readLocalConnectionFallbackToken(projectRoot) {
|
|
240
254
|
return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
|
|
@@ -245,7 +259,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
245
259
|
if (selected?.connection.kind === "remote") {
|
|
246
260
|
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
247
261
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
248
|
-
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
262
|
+
const serverProjectRoot = selected.serverProjectRoot ?? inferRemoteServerProjectRootFromAuthState(projectRoot) ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
249
263
|
return {
|
|
250
264
|
baseUrl: selected.connection.baseUrl,
|
|
251
265
|
authToken,
|
|
@@ -274,7 +288,10 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
|
|
|
274
288
|
if (!slug)
|
|
275
289
|
return null;
|
|
276
290
|
try {
|
|
277
|
-
const
|
|
291
|
+
const url = new URL(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`);
|
|
292
|
+
if (authToken && queryAuthFallbackEnabled())
|
|
293
|
+
url.searchParams.set("rt", authToken);
|
|
294
|
+
const response = await fetch(url, {
|
|
278
295
|
headers: mergeHeaders(undefined, authToken)
|
|
279
296
|
});
|
|
280
297
|
if (!response.ok)
|
|
@@ -291,10 +308,23 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
|
|
|
291
308
|
return null;
|
|
292
309
|
}
|
|
293
310
|
}
|
|
311
|
+
function mergeCookie(existing, name, value) {
|
|
312
|
+
const encoded = `${name}=${encodeURIComponent(value)}`;
|
|
313
|
+
if (!existing?.trim())
|
|
314
|
+
return encoded;
|
|
315
|
+
const parts = existing.split(";").map((part) => part.trim()).filter((part) => part && !part.startsWith(`${name}=`));
|
|
316
|
+
return [...parts, encoded].join("; ");
|
|
317
|
+
}
|
|
318
|
+
function queryAuthFallbackEnabled(env = process.env) {
|
|
319
|
+
return env.RIG_ENABLE_QUERY_AUTH_FALLBACK === "1" || env.RIG_QUERY_AUTH_FALLBACK === "1";
|
|
320
|
+
}
|
|
294
321
|
function mergeHeaders(headers, authToken) {
|
|
295
322
|
const merged = new Headers(headers);
|
|
296
323
|
if (authToken) {
|
|
297
|
-
|
|
324
|
+
const bearer = `Bearer ${authToken}`;
|
|
325
|
+
merged.set("authorization", bearer);
|
|
326
|
+
merged.set("x-auth", bearer);
|
|
327
|
+
merged.set("cookie", mergeCookie(merged.get("cookie"), "rig_auth", authToken));
|
|
298
328
|
}
|
|
299
329
|
return merged;
|
|
300
330
|
}
|
|
@@ -355,15 +385,34 @@ async function buildServerFailureContext(projectRoot, server) {
|
|
|
355
385
|
hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
|
|
356
386
|
};
|
|
357
387
|
}
|
|
388
|
+
function isLoopbackRemoteBaseUrl(baseUrl) {
|
|
389
|
+
try {
|
|
390
|
+
const host = new URL(baseUrl).hostname.toLowerCase();
|
|
391
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
|
|
392
|
+
} catch {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
function canUseRemoteWithoutProjectRoot(pathname) {
|
|
397
|
+
return pathname === "/health" || pathname === "/api/health" || pathname === "/api/server/status" || pathname === "/api/server/project-root" || pathname.startsWith("/api/github/auth/") || pathname === "/api/projects" || pathname.startsWith("/api/projects/");
|
|
398
|
+
}
|
|
358
399
|
async function requestServerJson(context, pathname, init = {}) {
|
|
359
400
|
const server = await ensureServerForCli(context.projectRoot);
|
|
401
|
+
const requestUrl = new URL(`${server.baseUrl}${pathname}`);
|
|
402
|
+
if (server.connectionKind === "remote" && !server.serverProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
|
|
403
|
+
const repo = readRepoConnection(context.projectRoot);
|
|
404
|
+
throw new CliError(`Remote server is selected for ${repo?.project ?? "this repo"}, but this checkout has no server-host project root link.`, 1, { hint: "Run `rig init --repair` or `rig init --yes --repo owner/repo --server remote` to repair the remote project link before task/run commands." });
|
|
405
|
+
}
|
|
360
406
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
361
407
|
if (server.serverProjectRoot)
|
|
362
408
|
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
409
|
+
if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
|
|
410
|
+
requestUrl.searchParams.set("rt", server.authToken);
|
|
411
|
+
}
|
|
363
412
|
reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
|
|
364
413
|
let response;
|
|
365
414
|
try {
|
|
366
|
-
response = await fetch(
|
|
415
|
+
response = await fetch(requestUrl, {
|
|
367
416
|
...init,
|
|
368
417
|
headers
|
|
369
418
|
});
|
|
@@ -1008,6 +1057,14 @@ async function withSpinner(label, work, options = {}) {
|
|
|
1008
1057
|
}
|
|
1009
1058
|
|
|
1010
1059
|
// packages/cli/src/commands/_pi-frontend.ts
|
|
1060
|
+
var TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
|
|
1061
|
+
|
|
1062
|
+
class OperatorTranscriptUnavailableError extends Error {
|
|
1063
|
+
constructor(message) {
|
|
1064
|
+
super(message);
|
|
1065
|
+
this.name = "OperatorTranscriptUnavailableError";
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1011
1068
|
function setTemporaryEnv(updates) {
|
|
1012
1069
|
const previous = new Map;
|
|
1013
1070
|
for (const [key, value] of Object.entries(updates)) {
|
|
@@ -1035,6 +1092,23 @@ function buildOperatorPiEnv(input) {
|
|
|
1035
1092
|
...input.serverProjectRoot ? { RIG_PROJECT_ROOT: input.serverProjectRoot } : {}
|
|
1036
1093
|
};
|
|
1037
1094
|
}
|
|
1095
|
+
function shouldRequireOperatorTranscript(status) {
|
|
1096
|
+
return typeof status === "string" && TERMINAL_RUN_STATUSES.has(status.trim().toLowerCase());
|
|
1097
|
+
}
|
|
1098
|
+
function missingOperatorTranscriptMessage(runId, status) {
|
|
1099
|
+
const shortRun = runId.trim().slice(0, 8) || "unknown";
|
|
1100
|
+
const statusText = typeof status === "string" && status.trim() ? status.trim() : "terminal";
|
|
1101
|
+
return `Run ${shortRun} is ${statusText}, but no worker Pi session transcript is recorded for this run. It likely failed before Pi started or predates full-session capture. Use \`rig run show ${runId}\` and \`rig run logs ${runId}\` for the lifecycle details.`;
|
|
1102
|
+
}
|
|
1103
|
+
function statusFromRunDetails(run) {
|
|
1104
|
+
if (!run || typeof run !== "object" || Array.isArray(run))
|
|
1105
|
+
return;
|
|
1106
|
+
const record = run;
|
|
1107
|
+
if (typeof record.status === "string")
|
|
1108
|
+
return record.status;
|
|
1109
|
+
const nested = record.run;
|
|
1110
|
+
return nested && typeof nested === "object" && !Array.isArray(nested) ? nested.status : undefined;
|
|
1111
|
+
}
|
|
1038
1112
|
async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
1039
1113
|
const server = await ensureServerForCli(context.projectRoot);
|
|
1040
1114
|
const localCwd = join2(homedir2(), ".rig", "drones", runId.slice(0, 8));
|
|
@@ -1064,6 +1138,13 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
1064
1138
|
sessionFileArg = ["--session", localSessionPath];
|
|
1065
1139
|
}
|
|
1066
1140
|
} catch {}
|
|
1141
|
+
if (sessionFileArg.length === 0) {
|
|
1142
|
+
const run = await getRunDetailsViaServer(context, runId).catch(() => null);
|
|
1143
|
+
const status = statusFromRunDetails(run);
|
|
1144
|
+
if (shouldRequireOperatorTranscript(status)) {
|
|
1145
|
+
throw new OperatorTranscriptUnavailableError(missingOperatorTranscriptMessage(runId, status));
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1067
1148
|
return { server, sessionFileArg };
|
|
1068
1149
|
}
|
|
1069
1150
|
var RIG_PI_THEME = {
|
|
@@ -1181,6 +1262,7 @@ async function attachRunBundledPiFrontend(context, input) {
|
|
|
1181
1262
|
let detached = false;
|
|
1182
1263
|
try {
|
|
1183
1264
|
await runPiMain([
|
|
1265
|
+
"--offline",
|
|
1184
1266
|
"--no-extensions",
|
|
1185
1267
|
"--no-skills",
|
|
1186
1268
|
"--no-prompt-templates",
|
|
@@ -1210,7 +1292,7 @@ async function attachRunBundledPiFrontend(context, input) {
|
|
|
1210
1292
|
}
|
|
1211
1293
|
|
|
1212
1294
|
// packages/cli/src/commands/_operator-view.ts
|
|
1213
|
-
var
|
|
1295
|
+
var TERMINAL_RUN_STATUSES2 = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
|
|
1214
1296
|
function runStatusFromPayload(payload) {
|
|
1215
1297
|
const run = payload.run && typeof payload.run === "object" && !Array.isArray(payload.run) ? payload.run : payload;
|
|
1216
1298
|
return String(run.status ?? "unknown").toLowerCase();
|
|
@@ -1288,7 +1370,7 @@ async function attachRunOperatorView(context, input) {
|
|
|
1288
1370
|
}
|
|
1289
1371
|
const pollMs = Math.max(250, Math.trunc(input.pollMs ?? 2000));
|
|
1290
1372
|
let timelineCursor = snapshot.timelineCursor;
|
|
1291
|
-
while (!detached && !
|
|
1373
|
+
while (!detached && !TERMINAL_RUN_STATUSES2.has(runStatusFromPayload(snapshot.run))) {
|
|
1292
1374
|
await Bun.sleep(pollMs);
|
|
1293
1375
|
snapshot = await readOperatorSnapshot(context, input.runId, { timelineCursor });
|
|
1294
1376
|
timelineCursor = snapshot.timelineCursor;
|
|
@@ -1991,6 +2073,9 @@ async function executeRun(context, args) {
|
|
|
1991
2073
|
console.log(`Stop requested: ${runId}`);
|
|
1992
2074
|
return { ok: true, group: "run", command, details: stopped };
|
|
1993
2075
|
}
|
|
2076
|
+
if (isRemoteConnectionSelected(context.projectRoot)) {
|
|
2077
|
+
throw new CliError("Remote run stop requires an explicit run id.", 2, { hint: "Run `rig run list`, then `rig run stop <run-id>`." });
|
|
2078
|
+
}
|
|
1994
2079
|
const result = await runStop(context.projectRoot);
|
|
1995
2080
|
if (result.remaining.length > 0) {
|
|
1996
2081
|
throw new CliError(`Failed to stop run(s): ${result.remaining.join(", ")}`, 1, { hint: "Check `rig run status`, then retry `rig run stop <run-id>` for the remaining runs." });
|