@h-rig/cli 0.0.6-alpha.89 → 0.0.6-alpha.90
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 +8 -40
- package/dist/bin/rig.js +12519 -26675
- package/dist/src/app/board.js +74 -693
- package/dist/src/app/drone-ui.js +1 -1
- package/dist/src/app/theme.js +0 -1
- package/dist/src/commands/_async-ui.js +1 -1
- package/dist/src/commands/_authority-runs.d.ts +1 -1
- package/dist/src/commands/_authority-runs.js +12 -2
- package/dist/src/commands/_cli-format.d.ts +1 -10
- package/dist/src/commands/_cli-format.js +2 -5
- package/dist/src/commands/_connection-state.d.ts +1 -11
- package/dist/src/commands/_connection-state.js +5 -50
- package/dist/src/commands/_doctor-checks.js +40 -501
- package/dist/src/commands/_help-catalog.js +17 -99
- package/dist/src/commands/_json-output.js +0 -4
- package/dist/src/commands/_operator-view.js +54 -575
- package/dist/src/commands/_pi-frontend.d.ts +0 -27
- package/dist/src/commands/_pi-frontend.js +52 -576
- package/dist/src/commands/_preflight.js +66 -553
- package/dist/src/commands/_server-client.d.ts +0 -33
- package/dist/src/commands/_server-client.js +46 -541
- package/dist/src/commands/_snapshot-upload.js +42 -503
- package/dist/src/commands/_spinner.js +1 -1
- package/dist/src/commands/agent.js +12 -2
- package/dist/src/commands/browser.js +1 -1
- package/dist/src/commands/connect.js +15 -626
- package/dist/src/commands/doctor.js +41 -502
- package/dist/src/commands/github.js +51 -584
- package/dist/src/commands/inbox.js +41 -502
- package/dist/src/commands/init.js +74 -561
- package/dist/src/commands/inspect.js +41 -502
- package/dist/src/commands/run.js +54 -578
- package/dist/src/commands/server.js +163 -692
- package/dist/src/commands/setup.js +46 -507
- package/dist/src/commands/stats.js +58 -601
- package/dist/src/commands/task-run-driver.js +58 -509
- package/dist/src/commands/task.js +110 -729
- package/dist/src/commands.js +237 -1112
- package/dist/src/index.js +244 -1123
- package/dist/src/launcher.js +0 -4
- package/package.json +9 -13
- package/dist/src/app-opentui/adapters/command.d.ts +0 -2
- package/dist/src/app-opentui/adapters/command.js +0 -329
- package/dist/src/app-opentui/adapters/common.d.ts +0 -56
- package/dist/src/app-opentui/adapters/common.js +0 -153
- package/dist/src/app-opentui/adapters/doctor.d.ts +0 -9
- package/dist/src/app-opentui/adapters/doctor.js +0 -1217
- package/dist/src/app-opentui/adapters/family.d.ts +0 -62
- package/dist/src/app-opentui/adapters/family.js +0 -14855
- package/dist/src/app-opentui/adapters/fleet.d.ts +0 -14
- package/dist/src/app-opentui/adapters/fleet.js +0 -1335
- package/dist/src/app-opentui/adapters/inbox.d.ts +0 -43
- package/dist/src/app-opentui/adapters/inbox.js +0 -1944
- package/dist/src/app-opentui/adapters/init.d.ts +0 -11
- package/dist/src/app-opentui/adapters/init.js +0 -2818
- package/dist/src/app-opentui/adapters/inspect.d.ts +0 -52
- package/dist/src/app-opentui/adapters/inspect.js +0 -1455
- package/dist/src/app-opentui/adapters/pi-attach.d.ts +0 -32
- package/dist/src/app-opentui/adapters/pi-attach.js +0 -2101
- package/dist/src/app-opentui/adapters/pi.d.ts +0 -23
- package/dist/src/app-opentui/adapters/pi.js +0 -363
- package/dist/src/app-opentui/adapters/plugin.d.ts +0 -84
- package/dist/src/app-opentui/adapters/plugin.js +0 -544
- package/dist/src/app-opentui/adapters/repo.d.ts +0 -37
- package/dist/src/app-opentui/adapters/repo.js +0 -186
- package/dist/src/app-opentui/adapters/run-detail.d.ts +0 -27
- package/dist/src/app-opentui/adapters/run-detail.js +0 -1441
- package/dist/src/app-opentui/adapters/server.d.ts +0 -48
- package/dist/src/app-opentui/adapters/server.js +0 -1561
- package/dist/src/app-opentui/adapters/tasks.d.ts +0 -64
- package/dist/src/app-opentui/adapters/tasks.js +0 -4524
- package/dist/src/app-opentui/adapters/workspace.d.ts +0 -49
- package/dist/src/app-opentui/adapters/workspace.js +0 -333
- package/dist/src/app-opentui/autocomplete.d.ts +0 -20
- package/dist/src/app-opentui/autocomplete.js +0 -578
- package/dist/src/app-opentui/bootstrap.d.ts +0 -11
- package/dist/src/app-opentui/bootstrap.js +0 -27833
- package/dist/src/app-opentui/command-palette.d.ts +0 -3
- package/dist/src/app-opentui/command-palette.js +0 -1038
- package/dist/src/app-opentui/command-pty-host.d.ts +0 -62
- package/dist/src/app-opentui/command-pty-host.js +0 -248
- package/dist/src/app-opentui/drone.d.ts +0 -12
- package/dist/src/app-opentui/drone.js +0 -230
- package/dist/src/app-opentui/events.d.ts +0 -7
- package/dist/src/app-opentui/events.js +0 -28
- package/dist/src/app-opentui/fleet-stats.d.ts +0 -32
- package/dist/src/app-opentui/fleet-stats.js +0 -114
- package/dist/src/app-opentui/focus-manager.d.ts +0 -14
- package/dist/src/app-opentui/focus-manager.js +0 -24
- package/dist/src/app-opentui/index.d.ts +0 -8
- package/dist/src/app-opentui/index.js +0 -5260
- package/dist/src/app-opentui/intent.d.ts +0 -3
- package/dist/src/app-opentui/intent.js +0 -365
- package/dist/src/app-opentui/keymap.d.ts +0 -21
- package/dist/src/app-opentui/keymap.js +0 -1377
- package/dist/src/app-opentui/launch-routing.d.ts +0 -16
- package/dist/src/app-opentui/launch-routing.js +0 -55
- package/dist/src/app-opentui/layout.d.ts +0 -22
- package/dist/src/app-opentui/layout.js +0 -51
- package/dist/src/app-opentui/list-search.d.ts +0 -36
- package/dist/src/app-opentui/list-search.js +0 -130
- package/dist/src/app-opentui/pi-host-child.d.ts +0 -2
- package/dist/src/app-opentui/pi-host-child.js +0 -1299
- package/dist/src/app-opentui/pi-pty-host.d.ts +0 -28
- package/dist/src/app-opentui/pi-pty-host.js +0 -10
- package/dist/src/app-opentui/react/App.d.ts +0 -9
- package/dist/src/app-opentui/react/App.js +0 -3866
- package/dist/src/app-opentui/react/Backdrop.d.ts +0 -5
- package/dist/src/app-opentui/react/Backdrop.js +0 -823
- package/dist/src/app-opentui/react/ChromeHost.d.ts +0 -5
- package/dist/src/app-opentui/react/ChromeHost.js +0 -1539
- package/dist/src/app-opentui/react/SceneFrameView.d.ts +0 -7
- package/dist/src/app-opentui/react/SceneFrameView.js +0 -579
- package/dist/src/app-opentui/react/context.d.ts +0 -17
- package/dist/src/app-opentui/react/context.js +0 -37
- package/dist/src/app-opentui/react/launch.d.ts +0 -2
- package/dist/src/app-opentui/react/launch.js +0 -4897
- package/dist/src/app-opentui/react/nav.d.ts +0 -18
- package/dist/src/app-opentui/react/nav.js +0 -54
- package/dist/src/app-opentui/react/scroll.d.ts +0 -12
- package/dist/src/app-opentui/react/scroll.js +0 -21
- package/dist/src/app-opentui/react/syntax.d.ts +0 -2
- package/dist/src/app-opentui/react/syntax.js +0 -65
- package/dist/src/app-opentui/registry.d.ts +0 -4
- package/dist/src/app-opentui/registry.js +0 -22876
- package/dist/src/app-opentui/remote-link.d.ts +0 -10
- package/dist/src/app-opentui/remote-link.js +0 -47
- package/dist/src/app-opentui/render/ascii-fleet.d.ts +0 -15
- package/dist/src/app-opentui/render/ascii-fleet.js +0 -82
- package/dist/src/app-opentui/render/constants.d.ts +0 -30
- package/dist/src/app-opentui/render/constants.js +0 -64
- package/dist/src/app-opentui/render/graphics.d.ts +0 -40
- package/dist/src/app-opentui/render/graphics.js +0 -713
- package/dist/src/app-opentui/render/hover.d.ts +0 -11
- package/dist/src/app-opentui/render/hover.js +0 -34
- package/dist/src/app-opentui/render/native-host.d.ts +0 -37
- package/dist/src/app-opentui/render/native-host.js +0 -180
- package/dist/src/app-opentui/render/panel-layout.d.ts +0 -38
- package/dist/src/app-opentui/render/panel-layout.js +0 -48
- package/dist/src/app-opentui/render/panels.d.ts +0 -12
- package/dist/src/app-opentui/render/panels.js +0 -288
- package/dist/src/app-opentui/render/preloader.d.ts +0 -10
- package/dist/src/app-opentui/render/preloader.js +0 -166
- package/dist/src/app-opentui/render/scene.d.ts +0 -68
- package/dist/src/app-opentui/render/scene.js +0 -300
- package/dist/src/app-opentui/render/terminal-handoff.d.ts +0 -16
- package/dist/src/app-opentui/render/terminal-handoff.js +0 -14
- package/dist/src/app-opentui/render/text.d.ts +0 -29
- package/dist/src/app-opentui/render/text.js +0 -177
- package/dist/src/app-opentui/render/type-bar.d.ts +0 -15
- package/dist/src/app-opentui/render/type-bar.js +0 -212
- package/dist/src/app-opentui/runtime-resources.d.ts +0 -16
- package/dist/src/app-opentui/runtime-resources.js +0 -62
- package/dist/src/app-opentui/runtime.d.ts +0 -45
- package/dist/src/app-opentui/runtime.js +0 -5232
- package/dist/src/app-opentui/scenes/command.d.ts +0 -3
- package/dist/src/app-opentui/scenes/command.js +0 -118
- package/dist/src/app-opentui/scenes/doctor.d.ts +0 -3
- package/dist/src/app-opentui/scenes/doctor.js +0 -296
- package/dist/src/app-opentui/scenes/error.d.ts +0 -2
- package/dist/src/app-opentui/scenes/error.js +0 -277
- package/dist/src/app-opentui/scenes/family-domains/agent.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/agent.js +0 -349
- package/dist/src/app-opentui/scenes/family-domains/browser.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/browser.js +0 -196
- package/dist/src/app-opentui/scenes/family-domains/dist.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/dist.js +0 -244
- package/dist/src/app-opentui/scenes/family-domains/git.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/git.js +0 -196
- package/dist/src/app-opentui/scenes/family-domains/github.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/github.js +0 -275
- package/dist/src/app-opentui/scenes/family-domains/harness.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/harness.js +0 -153
- package/dist/src/app-opentui/scenes/family-domains/index.d.ts +0 -4
- package/dist/src/app-opentui/scenes/family-domains/index.js +0 -1680
- package/dist/src/app-opentui/scenes/family-domains/kit.d.ts +0 -76
- package/dist/src/app-opentui/scenes/family-domains/kit.js +0 -306
- package/dist/src/app-opentui/scenes/family-domains/profile.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/profile.js +0 -213
- package/dist/src/app-opentui/scenes/family-domains/queue.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/queue.js +0 -147
- package/dist/src/app-opentui/scenes/family-domains/remote.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/remote.js +0 -519
- package/dist/src/app-opentui/scenes/family-domains/review.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/review.js +0 -281
- package/dist/src/app-opentui/scenes/family-domains/setup.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/setup.js +0 -268
- package/dist/src/app-opentui/scenes/family-domains/stats.d.ts +0 -2
- package/dist/src/app-opentui/scenes/family-domains/stats.js +0 -371
- package/dist/src/app-opentui/scenes/family.d.ts +0 -3
- package/dist/src/app-opentui/scenes/family.js +0 -2199
- package/dist/src/app-opentui/scenes/fleet.d.ts +0 -3
- package/dist/src/app-opentui/scenes/fleet.js +0 -766
- package/dist/src/app-opentui/scenes/handoff.d.ts +0 -2
- package/dist/src/app-opentui/scenes/handoff.js +0 -455
- package/dist/src/app-opentui/scenes/help.d.ts +0 -3
- package/dist/src/app-opentui/scenes/help.js +0 -725
- package/dist/src/app-opentui/scenes/inbox.d.ts +0 -3
- package/dist/src/app-opentui/scenes/inbox.js +0 -427
- package/dist/src/app-opentui/scenes/init.d.ts +0 -3
- package/dist/src/app-opentui/scenes/init.js +0 -181
- package/dist/src/app-opentui/scenes/inspect.d.ts +0 -3
- package/dist/src/app-opentui/scenes/inspect.js +0 -794
- package/dist/src/app-opentui/scenes/main.d.ts +0 -3
- package/dist/src/app-opentui/scenes/main.js +0 -332
- package/dist/src/app-opentui/scenes/pi.d.ts +0 -3
- package/dist/src/app-opentui/scenes/pi.js +0 -509
- package/dist/src/app-opentui/scenes/plugin.d.ts +0 -3
- package/dist/src/app-opentui/scenes/plugin.js +0 -487
- package/dist/src/app-opentui/scenes/repo.d.ts +0 -3
- package/dist/src/app-opentui/scenes/repo.js +0 -425
- package/dist/src/app-opentui/scenes/run-detail.d.ts +0 -3
- package/dist/src/app-opentui/scenes/run-detail.js +0 -467
- package/dist/src/app-opentui/scenes/server.d.ts +0 -3
- package/dist/src/app-opentui/scenes/server.js +0 -378
- package/dist/src/app-opentui/scenes/tasks.d.ts +0 -3
- package/dist/src/app-opentui/scenes/tasks.js +0 -768
- package/dist/src/app-opentui/scenes/workspace.d.ts +0 -3
- package/dist/src/app-opentui/scenes/workspace.js +0 -427
- package/dist/src/app-opentui/selectable.d.ts +0 -19
- package/dist/src/app-opentui/selectable.js +0 -80
- package/dist/src/app-opentui/state.d.ts +0 -4
- package/dist/src/app-opentui/state.js +0 -399
- package/dist/src/app-opentui/surface-catalog.d.ts +0 -20
- package/dist/src/app-opentui/surface-catalog.js +0 -542
- package/dist/src/app-opentui/theme.d.ts +0 -59
- package/dist/src/app-opentui/theme.js +0 -142
- package/dist/src/app-opentui/types.d.ts +0 -313
- package/dist/src/app-opentui/types.js +0 -1
- package/dist/src/commands/_server-events.d.ts +0 -26
- package/dist/src/commands/_server-events.js +0 -715
package/dist/src/index.js
CHANGED
|
@@ -296,7 +296,6 @@ function statusColor(status) {
|
|
|
296
296
|
case "validating":
|
|
297
297
|
case "reviewing":
|
|
298
298
|
case "closing-out":
|
|
299
|
-
case "stopping":
|
|
300
299
|
return cyan;
|
|
301
300
|
case "needs-attention":
|
|
302
301
|
case "needs_attention":
|
|
@@ -433,7 +432,7 @@ function createTtySpinner(input) {
|
|
|
433
432
|
output.write("\r\x1B[2K");
|
|
434
433
|
};
|
|
435
434
|
render();
|
|
436
|
-
const timer = isTty ? setInterval(render, input.intervalMs ??
|
|
435
|
+
const timer = isTty ? setInterval(render, input.intervalMs ?? 120) : null;
|
|
437
436
|
return {
|
|
438
437
|
setLabel(next) {
|
|
439
438
|
label = next;
|
|
@@ -1053,28 +1052,12 @@ function readRepoConnection(projectRoot) {
|
|
|
1053
1052
|
selected,
|
|
1054
1053
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
1055
1054
|
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
1056
|
-
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
1057
|
-
serverProjectRootAlias: typeof record.serverProjectRootAlias === "string" && record.serverProjectRootAlias.trim() ? record.serverProjectRootAlias.trim() : undefined,
|
|
1058
|
-
serverProjectRootBaseUrl: typeof record.serverProjectRootBaseUrl === "string" && record.serverProjectRootBaseUrl.trim() ? record.serverProjectRootBaseUrl.trim().replace(/\/+$/, "") : undefined
|
|
1055
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
1059
1056
|
};
|
|
1060
1057
|
}
|
|
1061
1058
|
function writeRepoConnection(projectRoot, state) {
|
|
1062
1059
|
writeJsonFile2(resolveRepoConnectionPath(projectRoot), state);
|
|
1063
1060
|
}
|
|
1064
|
-
function rootAllowedForSelection(repo, connection) {
|
|
1065
|
-
const root = repo.serverProjectRoot?.trim();
|
|
1066
|
-
if (!root)
|
|
1067
|
-
return;
|
|
1068
|
-
if (connection.kind === "remote") {
|
|
1069
|
-
if (repo.serverProjectRootAlias !== repo.selected)
|
|
1070
|
-
return;
|
|
1071
|
-
if (repo.serverProjectRootBaseUrl !== connection.baseUrl)
|
|
1072
|
-
return;
|
|
1073
|
-
} else if (repo.serverProjectRootAlias && repo.serverProjectRootAlias !== repo.selected) {
|
|
1074
|
-
return;
|
|
1075
|
-
}
|
|
1076
|
-
return root;
|
|
1077
|
-
}
|
|
1078
1061
|
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
1079
1062
|
const repo = readRepoConnection(projectRoot);
|
|
1080
1063
|
if (!repo)
|
|
@@ -1086,41 +1069,13 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
1086
1069
|
if (!connection) {
|
|
1087
1070
|
throw new CliError(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
1088
1071
|
}
|
|
1089
|
-
return { alias: repo.selected, connection, serverProjectRoot:
|
|
1072
|
+
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
1090
1073
|
}
|
|
1091
|
-
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot
|
|
1074
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
1092
1075
|
const repo = readRepoConnection(projectRoot);
|
|
1093
1076
|
if (!repo)
|
|
1094
1077
|
return;
|
|
1095
|
-
|
|
1096
|
-
if (!inferred.alias || !inferred.baseUrl) {
|
|
1097
|
-
try {
|
|
1098
|
-
const selected = resolveSelectedConnection(projectRoot);
|
|
1099
|
-
if (selected?.connection.kind === "remote") {
|
|
1100
|
-
inferred = {
|
|
1101
|
-
alias: inferred.alias ?? selected.alias,
|
|
1102
|
-
baseUrl: inferred.baseUrl ?? selected.connection.baseUrl
|
|
1103
|
-
};
|
|
1104
|
-
}
|
|
1105
|
-
} catch {}
|
|
1106
|
-
}
|
|
1107
|
-
writeRepoConnection(projectRoot, {
|
|
1108
|
-
...repo,
|
|
1109
|
-
...metadata.project ? { project: metadata.project } : {},
|
|
1110
|
-
serverProjectRoot,
|
|
1111
|
-
...inferred.alias ? { serverProjectRootAlias: inferred.alias } : {},
|
|
1112
|
-
...inferred.baseUrl ? { serverProjectRootBaseUrl: inferred.baseUrl.replace(/\/+$/, "") } : {}
|
|
1113
|
-
});
|
|
1114
|
-
}
|
|
1115
|
-
function clearRepoServerProjectRoot(projectRoot) {
|
|
1116
|
-
const repo = readRepoConnection(projectRoot);
|
|
1117
|
-
if (!repo)
|
|
1118
|
-
return;
|
|
1119
|
-
writeRepoConnection(projectRoot, {
|
|
1120
|
-
selected: repo.selected,
|
|
1121
|
-
...repo.project ? { project: repo.project } : {},
|
|
1122
|
-
...repo.linkedAt ? { linkedAt: repo.linkedAt } : {}
|
|
1123
|
-
});
|
|
1078
|
+
writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
|
|
1124
1079
|
}
|
|
1125
1080
|
function isRemoteConnectionSelected(projectRoot) {
|
|
1126
1081
|
return resolveSelectedConnection(projectRoot)?.connection.kind === "remote";
|
|
@@ -1130,8 +1085,8 @@ var init__connection_state = __esm(() => {
|
|
|
1130
1085
|
});
|
|
1131
1086
|
|
|
1132
1087
|
// packages/cli/src/commands/_server-client.ts
|
|
1133
|
-
import { existsSync as existsSync7,
|
|
1134
|
-
import {
|
|
1088
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
|
|
1089
|
+
import { resolve as resolve11 } from "path";
|
|
1135
1090
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
1136
1091
|
function setServerPhaseListener(listener) {
|
|
1137
1092
|
const previous = serverPhaseListener;
|
|
@@ -1149,21 +1104,17 @@ function setGitHubBearerTokenForCurrentProcess(token, projectRoot) {
|
|
|
1149
1104
|
const scopedKey = resolve11(projectRoot ?? process.cwd());
|
|
1150
1105
|
scopedGitHubBearerTokens.set(scopedKey, cleanToken(token ?? undefined));
|
|
1151
1106
|
}
|
|
1152
|
-
function
|
|
1107
|
+
function readPrivateRemoteSessionToken(projectRoot) {
|
|
1153
1108
|
const path = resolve11(projectRoot, ".rig", "state", "github-auth.json");
|
|
1154
1109
|
if (!existsSync7(path))
|
|
1155
1110
|
return null;
|
|
1156
1111
|
try {
|
|
1157
1112
|
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
1158
|
-
return
|
|
1113
|
+
return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
|
|
1159
1114
|
} catch {
|
|
1160
1115
|
return null;
|
|
1161
1116
|
}
|
|
1162
1117
|
}
|
|
1163
|
-
function readPrivateRemoteSessionToken(projectRoot) {
|
|
1164
|
-
const parsed = readRemoteAuthState(projectRoot);
|
|
1165
|
-
return parsed ? cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined) : null;
|
|
1166
|
-
}
|
|
1167
1118
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
1168
1119
|
const scopedKey = resolve11(projectRoot);
|
|
1169
1120
|
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
@@ -1174,421 +1125,18 @@ function readGitHubBearerTokenForRemote(projectRoot) {
|
|
|
1174
1125
|
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
1175
1126
|
}
|
|
1176
1127
|
function readStoredGitHubAuthToken(projectRoot) {
|
|
1177
|
-
const
|
|
1178
|
-
return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
|
|
1179
|
-
}
|
|
1180
|
-
function inferRemoteServerProjectRootCandidateFromAuthState(projectRoot, repoSlug) {
|
|
1181
|
-
if (!/^[^/]+\/[^/]+$/.test(repoSlug))
|
|
1182
|
-
return null;
|
|
1183
|
-
const repo = readRepoConnection(projectRoot);
|
|
1184
|
-
const auth = readRemoteAuthState(projectRoot);
|
|
1185
|
-
const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
|
|
1186
|
-
const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
|
|
1187
|
-
if (Number.isFinite(authUpdatedAt) && Number.isFinite(repoLinkedAt) && authUpdatedAt + 1000 < repoLinkedAt)
|
|
1188
|
-
return null;
|
|
1189
|
-
const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
|
|
1190
|
-
if (!checkoutBaseDir)
|
|
1191
|
-
return null;
|
|
1192
|
-
return `${checkoutBaseDir.replace(/\/+$/, "")}/${repoSlug}`;
|
|
1193
|
-
}
|
|
1194
|
-
function readLocalConnectionFallbackToken(projectRoot) {
|
|
1195
|
-
return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
|
|
1196
|
-
}
|
|
1197
|
-
function normalizeRepoSlug(value) {
|
|
1198
|
-
const slug = value?.trim();
|
|
1199
|
-
return slug && /^[^/\s]+\/[^/\s]+$/.test(slug) ? slug : null;
|
|
1200
|
-
}
|
|
1201
|
-
function readProjectLinkSlug(projectRoot) {
|
|
1202
|
-
const path = resolve11(projectRoot, ".rig", "state", "project-link.json");
|
|
1128
|
+
const path = resolve11(projectRoot, ".rig", "state", "github-auth.json");
|
|
1203
1129
|
if (!existsSync7(path))
|
|
1204
1130
|
return null;
|
|
1205
1131
|
try {
|
|
1206
1132
|
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
1207
|
-
|
|
1208
|
-
return null;
|
|
1209
|
-
return normalizeRepoSlug(typeof parsed.repoSlug === "string" ? String(parsed.repoSlug) : null);
|
|
1133
|
+
return cleanToken(typeof parsed.token === "string" ? parsed.token : undefined);
|
|
1210
1134
|
} catch {
|
|
1211
1135
|
return null;
|
|
1212
1136
|
}
|
|
1213
1137
|
}
|
|
1214
|
-
function
|
|
1215
|
-
|
|
1216
|
-
mkdirSync7(dirname3(path), { recursive: true });
|
|
1217
|
-
writeFileSync5(path, `${JSON.stringify({ repoSlug, connection: alias, linkedAt: new Date().toISOString() }, null, 2)}
|
|
1218
|
-
`, "utf8");
|
|
1219
|
-
}
|
|
1220
|
-
function remoteLinkRepairCommand(repoSlug) {
|
|
1221
|
-
return repoSlug ? `rig server repair-link --repo ${repoSlug}` : "rig server repair-link --repo owner/repo";
|
|
1222
|
-
}
|
|
1223
|
-
function formatRemoteProjectLinkHint(resolution) {
|
|
1224
|
-
const repair = remoteLinkRepairCommand(resolution.repoSlug);
|
|
1225
|
-
if (resolution.status === "auth_required") {
|
|
1226
|
-
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}` : ""}\`.`;
|
|
1227
|
-
}
|
|
1228
|
-
if (resolution.status === "missing_project") {
|
|
1229
|
-
return `Record the repo slug, then run \`${repair}\` (or \`rig init --repo owner/repo --server remote --github-auth device\`).`;
|
|
1230
|
-
}
|
|
1231
|
-
if (resolution.status === "not_remote")
|
|
1232
|
-
return "Select a remote server with `rig server use <alias>` before repairing a remote project link.";
|
|
1233
|
-
return `Run \`${repair}\` to backfill or prepare a server-host checkout for the selected remote${resolution.alias ? ` (${resolution.alias})` : ""}.`;
|
|
1234
|
-
}
|
|
1235
|
-
function remoteProjectLinkFailure(input) {
|
|
1236
|
-
const partial = {
|
|
1237
|
-
status: input.status,
|
|
1238
|
-
alias: input.alias,
|
|
1239
|
-
baseUrl: input.baseUrl,
|
|
1240
|
-
repoSlug: input.repoSlug
|
|
1241
|
-
};
|
|
1242
|
-
return {
|
|
1243
|
-
ok: false,
|
|
1244
|
-
...input,
|
|
1245
|
-
hint: formatRemoteProjectLinkHint(partial),
|
|
1246
|
-
next: remoteLinkRepairCommand(input.repoSlug)
|
|
1247
|
-
};
|
|
1248
|
-
}
|
|
1249
|
-
function remoteProjectLinkSuccess(input) {
|
|
1250
|
-
return {
|
|
1251
|
-
ok: true,
|
|
1252
|
-
status: input.status,
|
|
1253
|
-
alias: input.alias,
|
|
1254
|
-
baseUrl: input.baseUrl,
|
|
1255
|
-
repoSlug: input.repoSlug,
|
|
1256
|
-
serverProjectRoot: input.serverProjectRoot,
|
|
1257
|
-
source: input.source,
|
|
1258
|
-
prepared: input.prepared ?? input.status === "prepared",
|
|
1259
|
-
validated: input.validated ?? false,
|
|
1260
|
-
message: input.message ?? `Remote project link ready for ${input.repoSlug}.`,
|
|
1261
|
-
hint: "Remote-scoped task/run/status requests will send x-rig-project-root for this server-host checkout.",
|
|
1262
|
-
next: "rig task list"
|
|
1263
|
-
};
|
|
1264
|
-
}
|
|
1265
|
-
function localCheckoutPathCandidate(projectRoot, candidate) {
|
|
1266
|
-
try {
|
|
1267
|
-
const local = resolve11(projectRoot);
|
|
1268
|
-
const resolved = resolve11(candidate);
|
|
1269
|
-
return resolved === local || resolved.startsWith(`${local}/`);
|
|
1270
|
-
} catch {
|
|
1271
|
-
return false;
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
|
-
async function requestRemoteProjectLinkJson(baseUrl, pathname, authToken, init = {}) {
|
|
1275
|
-
const requestUrl = new URL(`${baseUrl}${pathname}`);
|
|
1276
|
-
if (authToken && queryAuthFallbackEnabled())
|
|
1277
|
-
requestUrl.searchParams.set("rt", authToken);
|
|
1278
|
-
const response = await fetch(requestUrl, {
|
|
1279
|
-
...init,
|
|
1280
|
-
headers: mergeHeaders(init.headers, authToken)
|
|
1281
|
-
});
|
|
1282
|
-
const text = await response.text();
|
|
1283
|
-
const payload = text.trim().length > 0 ? (() => {
|
|
1284
|
-
try {
|
|
1285
|
-
return JSON.parse(text);
|
|
1286
|
-
} catch {
|
|
1287
|
-
return null;
|
|
1288
|
-
}
|
|
1289
|
-
})() : null;
|
|
1290
|
-
return { ok: response.ok, status: response.status, payload, text };
|
|
1291
|
-
}
|
|
1292
|
-
function payloadError(payload, fallback) {
|
|
1293
|
-
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
1294
|
-
const record = payload;
|
|
1295
|
-
const value = record.error ?? record.message ?? record.reason;
|
|
1296
|
-
if (typeof value === "string" && value.trim())
|
|
1297
|
-
return value.trim();
|
|
1298
|
-
}
|
|
1299
|
-
return fallback;
|
|
1300
|
-
}
|
|
1301
|
-
function checkoutPathsFromProjectPayload(payload) {
|
|
1302
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
1303
|
-
return [];
|
|
1304
|
-
const project = payload.project;
|
|
1305
|
-
if (!project || typeof project !== "object" || Array.isArray(project))
|
|
1306
|
-
return [];
|
|
1307
|
-
const checkouts = project.checkouts;
|
|
1308
|
-
if (!Array.isArray(checkouts))
|
|
1309
|
-
return [];
|
|
1310
|
-
return [...checkouts].reverse().flatMap((entry) => {
|
|
1311
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
1312
|
-
return [];
|
|
1313
|
-
const path = entry.path;
|
|
1314
|
-
return typeof path === "string" && path.trim() ? [path.trim()] : [];
|
|
1315
|
-
});
|
|
1316
|
-
}
|
|
1317
|
-
function checkoutPathFromPreparePayload(payload) {
|
|
1318
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
1319
|
-
return null;
|
|
1320
|
-
const checkout = payload.checkout;
|
|
1321
|
-
if (!checkout || typeof checkout !== "object" || Array.isArray(checkout))
|
|
1322
|
-
return null;
|
|
1323
|
-
const path = checkout.path;
|
|
1324
|
-
return typeof path === "string" && path.trim() ? path.trim() : null;
|
|
1325
|
-
}
|
|
1326
|
-
async function validateAndPersistRemoteRoot(input) {
|
|
1327
|
-
const candidate = input.candidate.trim();
|
|
1328
|
-
if (!candidate || !isAbsolute(candidate)) {
|
|
1329
|
-
return remoteProjectLinkFailure({
|
|
1330
|
-
status: "invalid_root",
|
|
1331
|
-
alias: input.alias,
|
|
1332
|
-
baseUrl: input.baseUrl,
|
|
1333
|
-
repoSlug: input.repoSlug,
|
|
1334
|
-
message: `Remote project root candidate is not an absolute server-host path: ${candidate || "(empty)"}.`
|
|
1335
|
-
});
|
|
1336
|
-
}
|
|
1337
|
-
if (localCheckoutPathCandidate(input.projectRoot, candidate)) {
|
|
1338
|
-
return remoteProjectLinkFailure({
|
|
1339
|
-
status: "invalid_root",
|
|
1340
|
-
alias: input.alias,
|
|
1341
|
-
baseUrl: input.baseUrl,
|
|
1342
|
-
repoSlug: input.repoSlug,
|
|
1343
|
-
message: `Refusing to use local checkout path ${candidate} as a remote server project root.`
|
|
1344
|
-
});
|
|
1345
|
-
}
|
|
1346
|
-
let response;
|
|
1347
|
-
try {
|
|
1348
|
-
response = await requestRemoteProjectLinkJson(input.baseUrl, "/api/server/project-root", input.authToken, {
|
|
1349
|
-
method: "POST",
|
|
1350
|
-
headers: { "content-type": "application/json" },
|
|
1351
|
-
body: JSON.stringify({ projectRoot: candidate })
|
|
1352
|
-
});
|
|
1353
|
-
} catch (error) {
|
|
1354
|
-
return remoteProjectLinkFailure({
|
|
1355
|
-
status: "error",
|
|
1356
|
-
alias: input.alias,
|
|
1357
|
-
baseUrl: input.baseUrl,
|
|
1358
|
-
repoSlug: input.repoSlug,
|
|
1359
|
-
message: `Could not validate remote project root ${candidate}: ${error instanceof Error ? error.message : String(error)}`
|
|
1360
|
-
});
|
|
1361
|
-
}
|
|
1362
|
-
if (response.status === 401 || response.status === 403) {
|
|
1363
|
-
return remoteProjectLinkFailure({
|
|
1364
|
-
status: "auth_required",
|
|
1365
|
-
alias: input.alias,
|
|
1366
|
-
baseUrl: input.baseUrl,
|
|
1367
|
-
repoSlug: input.repoSlug,
|
|
1368
|
-
statusCode: response.status,
|
|
1369
|
-
message: `Remote server ${input.alias} requires authentication before validating project root ${candidate}.`
|
|
1370
|
-
});
|
|
1371
|
-
}
|
|
1372
|
-
if (!response.ok) {
|
|
1373
|
-
return remoteProjectLinkFailure({
|
|
1374
|
-
status: "invalid_root",
|
|
1375
|
-
alias: input.alias,
|
|
1376
|
-
baseUrl: input.baseUrl,
|
|
1377
|
-
repoSlug: input.repoSlug,
|
|
1378
|
-
statusCode: response.status,
|
|
1379
|
-
message: `Remote server rejected project root ${candidate} (${response.status}): ${payloadError(response.payload, response.text || "project-root validation failed")}`
|
|
1380
|
-
});
|
|
1381
|
-
}
|
|
1382
|
-
const record = response.payload && typeof response.payload === "object" && !Array.isArray(response.payload) ? response.payload : {};
|
|
1383
|
-
if (record.ok !== true) {
|
|
1384
|
-
return remoteProjectLinkFailure({
|
|
1385
|
-
status: "invalid_root",
|
|
1386
|
-
alias: input.alias,
|
|
1387
|
-
baseUrl: input.baseUrl,
|
|
1388
|
-
repoSlug: input.repoSlug,
|
|
1389
|
-
message: `Remote server did not accept project root ${candidate}: ${payloadError(response.payload, "project-root validation failed")}`
|
|
1390
|
-
});
|
|
1391
|
-
}
|
|
1392
|
-
const accepted = typeof record.projectRoot === "string" && record.projectRoot.trim() ? record.projectRoot.trim() : typeof record.requestedProjectRoot === "string" && record.requestedProjectRoot.trim() ? record.requestedProjectRoot.trim() : candidate;
|
|
1393
|
-
writeRepoServerProjectRoot(input.projectRoot, accepted, { alias: input.alias, baseUrl: input.baseUrl, project: input.repoSlug });
|
|
1394
|
-
writeProjectLinkConnection(input.projectRoot, input.repoSlug, input.alias);
|
|
1395
|
-
const status = input.status ?? (input.prepared ? "prepared" : "backfilled");
|
|
1396
|
-
return remoteProjectLinkSuccess({
|
|
1397
|
-
status,
|
|
1398
|
-
alias: input.alias,
|
|
1399
|
-
baseUrl: input.baseUrl,
|
|
1400
|
-
repoSlug: input.repoSlug,
|
|
1401
|
-
serverProjectRoot: accepted,
|
|
1402
|
-
source: input.source,
|
|
1403
|
-
prepared: input.prepared,
|
|
1404
|
-
validated: true,
|
|
1405
|
-
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}.`
|
|
1406
|
-
});
|
|
1407
|
-
}
|
|
1408
|
-
async function ensureRemoteProjectRootLink(projectRoot, options = {}) {
|
|
1409
|
-
let selected;
|
|
1410
|
-
try {
|
|
1411
|
-
selected = resolveSelectedConnection(projectRoot);
|
|
1412
|
-
} catch (error) {
|
|
1413
|
-
return remoteProjectLinkFailure({ status: "error", message: error instanceof Error ? error.message : String(error) });
|
|
1414
|
-
}
|
|
1415
|
-
if (!selected || selected.connection.kind !== "remote") {
|
|
1416
|
-
return remoteProjectLinkFailure({ status: "not_remote", message: "No remote Rig server is selected for this repo." });
|
|
1417
|
-
}
|
|
1418
|
-
const repo = readRepoConnection(projectRoot);
|
|
1419
|
-
const explicitRepoRequested = options.repoSlug !== undefined;
|
|
1420
|
-
const explicitRepoSlug = explicitRepoRequested ? normalizeRepoSlug(options.repoSlug) : null;
|
|
1421
|
-
const repoProjectSlug = normalizeRepoSlug(repo?.project);
|
|
1422
|
-
const repoSlug = explicitRepoSlug ?? repoProjectSlug ?? readProjectLinkSlug(projectRoot);
|
|
1423
|
-
const alias = selected.alias;
|
|
1424
|
-
const baseUrl = selected.connection.baseUrl;
|
|
1425
|
-
const authToken = options.authToken === undefined ? readGitHubBearerTokenForRemote(projectRoot) : options.authToken;
|
|
1426
|
-
const mode = options.mode ?? "backfill-only";
|
|
1427
|
-
if (explicitRepoRequested && !explicitRepoSlug) {
|
|
1428
|
-
return remoteProjectLinkFailure({
|
|
1429
|
-
status: "missing_project",
|
|
1430
|
-
alias,
|
|
1431
|
-
baseUrl,
|
|
1432
|
-
message: `Invalid --repo value ${JSON.stringify(options.repoSlug)}. Expected owner/repo.`
|
|
1433
|
-
});
|
|
1434
|
-
}
|
|
1435
|
-
if (!repoSlug) {
|
|
1436
|
-
return remoteProjectLinkFailure({
|
|
1437
|
-
status: "missing_project",
|
|
1438
|
-
alias,
|
|
1439
|
-
baseUrl,
|
|
1440
|
-
message: `Remote server ${alias} is selected, but this checkout has no GitHub repo slug recorded.`
|
|
1441
|
-
});
|
|
1442
|
-
}
|
|
1443
|
-
const skippedCandidates = [];
|
|
1444
|
-
const storedRoot = selected.serverProjectRoot?.trim() || null;
|
|
1445
|
-
const storedRootMatchesResolvedRepo = repoProjectSlug === repoSlug;
|
|
1446
|
-
if (storedRoot && storedRootMatchesResolvedRepo) {
|
|
1447
|
-
if (localCheckoutPathCandidate(projectRoot, storedRoot)) {
|
|
1448
|
-
clearRepoServerProjectRoot(projectRoot);
|
|
1449
|
-
skippedCandidates.push(storedRoot);
|
|
1450
|
-
} else {
|
|
1451
|
-
const storedResult = await validateAndPersistRemoteRoot({
|
|
1452
|
-
projectRoot,
|
|
1453
|
-
alias,
|
|
1454
|
-
baseUrl,
|
|
1455
|
-
authToken,
|
|
1456
|
-
repoSlug,
|
|
1457
|
-
candidate: storedRoot,
|
|
1458
|
-
source: "stored",
|
|
1459
|
-
status: "ready"
|
|
1460
|
-
});
|
|
1461
|
-
if (storedResult.ok || storedResult.status === "auth_required" || storedResult.status === "error")
|
|
1462
|
-
return storedResult;
|
|
1463
|
-
clearRepoServerProjectRoot(projectRoot);
|
|
1464
|
-
skippedCandidates.push(storedRoot);
|
|
1465
|
-
}
|
|
1466
|
-
} else if (storedRoot) {
|
|
1467
|
-
skippedCandidates.push(storedRoot);
|
|
1468
|
-
}
|
|
1469
|
-
const authCandidate = inferRemoteServerProjectRootCandidateFromAuthState(projectRoot, repoSlug);
|
|
1470
|
-
if (authCandidate) {
|
|
1471
|
-
const authResult = await validateAndPersistRemoteRoot({ projectRoot, alias, baseUrl, authToken, repoSlug, candidate: authCandidate, source: "auth-state" });
|
|
1472
|
-
if (authResult.ok || authResult.status === "auth_required")
|
|
1473
|
-
return authResult;
|
|
1474
|
-
}
|
|
1475
|
-
let registryResponse;
|
|
1476
|
-
try {
|
|
1477
|
-
registryResponse = await requestRemoteProjectLinkJson(baseUrl, `/api/projects/${encodeURIComponent(repoSlug)}`, authToken);
|
|
1478
|
-
} catch (error) {
|
|
1479
|
-
return remoteProjectLinkFailure({
|
|
1480
|
-
status: "error",
|
|
1481
|
-
alias,
|
|
1482
|
-
baseUrl,
|
|
1483
|
-
repoSlug,
|
|
1484
|
-
message: `Could not read remote project registry for ${repoSlug} on ${alias}: ${error instanceof Error ? error.message : String(error)}`
|
|
1485
|
-
});
|
|
1486
|
-
}
|
|
1487
|
-
if (registryResponse.status === 401 || registryResponse.status === 403) {
|
|
1488
|
-
return remoteProjectLinkFailure({
|
|
1489
|
-
status: "auth_required",
|
|
1490
|
-
alias,
|
|
1491
|
-
baseUrl,
|
|
1492
|
-
repoSlug,
|
|
1493
|
-
statusCode: registryResponse.status,
|
|
1494
|
-
message: `Remote server ${alias} requires authentication before reading the ${repoSlug} project registry.`
|
|
1495
|
-
});
|
|
1496
|
-
}
|
|
1497
|
-
if (registryResponse.ok) {
|
|
1498
|
-
const candidates = checkoutPathsFromProjectPayload(registryResponse.payload);
|
|
1499
|
-
for (const candidate of candidates) {
|
|
1500
|
-
const result = await validateAndPersistRemoteRoot({ projectRoot, alias, baseUrl, authToken, repoSlug, candidate, source: "registry" });
|
|
1501
|
-
if (result.ok || result.status === "auth_required")
|
|
1502
|
-
return result;
|
|
1503
|
-
skippedCandidates.push(candidate);
|
|
1504
|
-
}
|
|
1505
|
-
if (mode === "backfill-only") {
|
|
1506
|
-
return remoteProjectLinkFailure({
|
|
1507
|
-
status: candidates.length > 0 ? "invalid_root" : "no_server_checkout",
|
|
1508
|
-
alias,
|
|
1509
|
-
baseUrl,
|
|
1510
|
-
repoSlug,
|
|
1511
|
-
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.`,
|
|
1512
|
-
skippedCandidates
|
|
1513
|
-
});
|
|
1514
|
-
}
|
|
1515
|
-
} else if (registryResponse.status === 404) {
|
|
1516
|
-
if (mode === "backfill-only") {
|
|
1517
|
-
return remoteProjectLinkFailure({
|
|
1518
|
-
status: "project_not_registered",
|
|
1519
|
-
alias,
|
|
1520
|
-
baseUrl,
|
|
1521
|
-
repoSlug,
|
|
1522
|
-
statusCode: registryResponse.status,
|
|
1523
|
-
message: `Remote server ${alias} has no registered project record for ${repoSlug}.`
|
|
1524
|
-
});
|
|
1525
|
-
}
|
|
1526
|
-
} else {
|
|
1527
|
-
return remoteProjectLinkFailure({
|
|
1528
|
-
status: "error",
|
|
1529
|
-
alias,
|
|
1530
|
-
baseUrl,
|
|
1531
|
-
repoSlug,
|
|
1532
|
-
statusCode: registryResponse.status,
|
|
1533
|
-
message: `Could not backfill ${repoSlug} from remote registry (${registryResponse.status}): ${payloadError(registryResponse.payload, registryResponse.text || "registry lookup failed")}`,
|
|
1534
|
-
skippedCandidates
|
|
1535
|
-
});
|
|
1536
|
-
}
|
|
1537
|
-
let prepareResponse;
|
|
1538
|
-
try {
|
|
1539
|
-
prepareResponse = await requestRemoteProjectLinkJson(baseUrl, `/api/projects/${encodeURIComponent(repoSlug)}/prepare-checkout`, authToken, {
|
|
1540
|
-
method: "POST",
|
|
1541
|
-
headers: { "content-type": "application/json" },
|
|
1542
|
-
body: JSON.stringify({ checkout: { kind: "managed-clone" }, repoUrl: `https://github.com/${repoSlug}.git` })
|
|
1543
|
-
});
|
|
1544
|
-
} catch (error) {
|
|
1545
|
-
return remoteProjectLinkFailure({
|
|
1546
|
-
status: "error",
|
|
1547
|
-
alias,
|
|
1548
|
-
baseUrl,
|
|
1549
|
-
repoSlug,
|
|
1550
|
-
message: `Could not prepare remote checkout for ${repoSlug} on ${alias}: ${error instanceof Error ? error.message : String(error)}`
|
|
1551
|
-
});
|
|
1552
|
-
}
|
|
1553
|
-
if (prepareResponse.status === 401 || prepareResponse.status === 403) {
|
|
1554
|
-
return remoteProjectLinkFailure({
|
|
1555
|
-
status: "auth_required",
|
|
1556
|
-
alias,
|
|
1557
|
-
baseUrl,
|
|
1558
|
-
repoSlug,
|
|
1559
|
-
statusCode: prepareResponse.status,
|
|
1560
|
-
message: `Remote server ${alias} requires authentication before preparing ${repoSlug}.`
|
|
1561
|
-
});
|
|
1562
|
-
}
|
|
1563
|
-
if (!prepareResponse.ok) {
|
|
1564
|
-
return remoteProjectLinkFailure({
|
|
1565
|
-
status: "error",
|
|
1566
|
-
alias,
|
|
1567
|
-
baseUrl,
|
|
1568
|
-
repoSlug,
|
|
1569
|
-
statusCode: prepareResponse.status,
|
|
1570
|
-
message: `Remote checkout prepare failed for ${repoSlug} (${prepareResponse.status}): ${payloadError(prepareResponse.payload, prepareResponse.text || "prepare-checkout failed")}`,
|
|
1571
|
-
skippedCandidates
|
|
1572
|
-
});
|
|
1573
|
-
}
|
|
1574
|
-
const preparedPath = checkoutPathFromPreparePayload(prepareResponse.payload);
|
|
1575
|
-
if (!preparedPath) {
|
|
1576
|
-
return remoteProjectLinkFailure({
|
|
1577
|
-
status: "invalid_root",
|
|
1578
|
-
alias,
|
|
1579
|
-
baseUrl,
|
|
1580
|
-
repoSlug,
|
|
1581
|
-
message: `Remote checkout prepare for ${repoSlug} did not return a checkout.path.`,
|
|
1582
|
-
skippedCandidates
|
|
1583
|
-
});
|
|
1584
|
-
}
|
|
1585
|
-
return validateAndPersistRemoteRoot({ projectRoot, alias, baseUrl, authToken, repoSlug, candidate: preparedPath, source: "prepare", prepared: true });
|
|
1586
|
-
}
|
|
1587
|
-
async function repairRemoteProjectRootLink(context, options = {}) {
|
|
1588
|
-
const resolution = await ensureRemoteProjectRootLink(context.projectRoot, { mode: options.mode ?? "prepare-if-missing", repoSlug: options.repoSlug });
|
|
1589
|
-
if (!resolution.ok)
|
|
1590
|
-
throw new CliError(resolution.message, 1, { hint: resolution.hint });
|
|
1591
|
-
return resolution;
|
|
1138
|
+
function readLocalConnectionFallbackToken(projectRoot) {
|
|
1139
|
+
return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
|
|
1592
1140
|
}
|
|
1593
1141
|
async function ensureServerForCli(projectRoot) {
|
|
1594
1142
|
try {
|
|
@@ -1596,12 +1144,12 @@ async function ensureServerForCli(projectRoot) {
|
|
|
1596
1144
|
if (selected?.connection.kind === "remote") {
|
|
1597
1145
|
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
1598
1146
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
1599
|
-
const
|
|
1147
|
+
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
1600
1148
|
return {
|
|
1601
1149
|
baseUrl: selected.connection.baseUrl,
|
|
1602
1150
|
authToken,
|
|
1603
1151
|
connectionKind: "remote",
|
|
1604
|
-
serverProjectRoot
|
|
1152
|
+
serverProjectRoot
|
|
1605
1153
|
};
|
|
1606
1154
|
}
|
|
1607
1155
|
reportServerPhase("Starting local Rig server\u2026");
|
|
@@ -1619,6 +1167,29 @@ async function ensureServerForCli(projectRoot) {
|
|
|
1619
1167
|
throw error;
|
|
1620
1168
|
}
|
|
1621
1169
|
}
|
|
1170
|
+
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
1171
|
+
const repo = readRepoConnection(projectRoot);
|
|
1172
|
+
const slug = repo?.project?.trim();
|
|
1173
|
+
if (!slug)
|
|
1174
|
+
return null;
|
|
1175
|
+
try {
|
|
1176
|
+
const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
|
|
1177
|
+
headers: mergeHeaders(undefined, authToken)
|
|
1178
|
+
});
|
|
1179
|
+
if (!response.ok)
|
|
1180
|
+
return null;
|
|
1181
|
+
const payload = await response.json();
|
|
1182
|
+
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
1183
|
+
const checkouts = Array.isArray(project?.checkouts) ? project.checkouts : [];
|
|
1184
|
+
const latestCheckout = [...checkouts].reverse().find((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.path === "string"));
|
|
1185
|
+
const path = typeof latestCheckout?.path === "string" && latestCheckout.path.trim() ? latestCheckout.path.trim() : null;
|
|
1186
|
+
if (path)
|
|
1187
|
+
writeRepoServerProjectRoot(projectRoot, path);
|
|
1188
|
+
return path;
|
|
1189
|
+
} catch {
|
|
1190
|
+
return null;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1622
1193
|
function appendTaskFilterParams(url, filters) {
|
|
1623
1194
|
if (filters.assignee)
|
|
1624
1195
|
url.searchParams.set("assignee", filters.assignee);
|
|
@@ -1629,23 +1200,10 @@ function appendTaskFilterParams(url, filters) {
|
|
|
1629
1200
|
if (filters.limit !== undefined)
|
|
1630
1201
|
url.searchParams.set("limit", String(filters.limit));
|
|
1631
1202
|
}
|
|
1632
|
-
function mergeCookie(existing, name, value) {
|
|
1633
|
-
const encoded = `${name}=${encodeURIComponent(value)}`;
|
|
1634
|
-
if (!existing?.trim())
|
|
1635
|
-
return encoded;
|
|
1636
|
-
const parts = existing.split(";").map((part) => part.trim()).filter((part) => part && !part.startsWith(`${name}=`));
|
|
1637
|
-
return [...parts, encoded].join("; ");
|
|
1638
|
-
}
|
|
1639
|
-
function queryAuthFallbackEnabled(env = process.env) {
|
|
1640
|
-
return env.RIG_ENABLE_QUERY_AUTH_FALLBACK === "1" || env.RIG_QUERY_AUTH_FALLBACK === "1";
|
|
1641
|
-
}
|
|
1642
1203
|
function mergeHeaders(headers, authToken) {
|
|
1643
1204
|
const merged = new Headers(headers);
|
|
1644
1205
|
if (authToken) {
|
|
1645
|
-
|
|
1646
|
-
merged.set("authorization", bearer);
|
|
1647
|
-
merged.set("x-auth", bearer);
|
|
1648
|
-
merged.set("cookie", mergeCookie(merged.get("cookie"), "rig_auth", authToken));
|
|
1206
|
+
merged.set("authorization", `Bearer ${authToken}`);
|
|
1649
1207
|
}
|
|
1650
1208
|
return merged;
|
|
1651
1209
|
}
|
|
@@ -1705,41 +1263,15 @@ async function buildServerFailureContext(projectRoot, server) {
|
|
|
1705
1263
|
hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
|
|
1706
1264
|
};
|
|
1707
1265
|
}
|
|
1708
|
-
function isLoopbackRemoteBaseUrl(baseUrl) {
|
|
1709
|
-
try {
|
|
1710
|
-
const host = new URL(baseUrl).hostname.toLowerCase();
|
|
1711
|
-
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
|
|
1712
|
-
} catch {
|
|
1713
|
-
return false;
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
1716
|
-
function canUseRemoteWithoutProjectRoot(pathname) {
|
|
1717
|
-
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/");
|
|
1718
|
-
}
|
|
1719
1266
|
async function requestServerJson(context, pathname, init = {}) {
|
|
1720
1267
|
const server = await ensureServerForCli(context.projectRoot);
|
|
1721
|
-
const requestUrl = new URL(`${server.baseUrl}${pathname}`);
|
|
1722
|
-
let scopedServerProjectRoot = server.serverProjectRoot;
|
|
1723
|
-
if (server.connectionKind === "remote" && !scopedServerProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
|
|
1724
|
-
const link = await ensureRemoteProjectRootLink(context.projectRoot, { mode: "backfill-only", authToken: server.authToken });
|
|
1725
|
-
if (link.ok && link.serverProjectRoot) {
|
|
1726
|
-
scopedServerProjectRoot = link.serverProjectRoot;
|
|
1727
|
-
} else {
|
|
1728
|
-
const repo = readRepoConnection(context.projectRoot);
|
|
1729
|
-
const target = link.alias && link.baseUrl ? `${link.alias} (${link.baseUrl})` : server.baseUrl;
|
|
1730
|
-
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 });
|
|
1731
|
-
}
|
|
1732
|
-
}
|
|
1733
1268
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
1734
|
-
if (
|
|
1735
|
-
headers.set("x-rig-project-root",
|
|
1736
|
-
if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
|
|
1737
|
-
requestUrl.searchParams.set("rt", server.authToken);
|
|
1738
|
-
}
|
|
1269
|
+
if (server.serverProjectRoot)
|
|
1270
|
+
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
1739
1271
|
reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
|
|
1740
1272
|
let response;
|
|
1741
1273
|
try {
|
|
1742
|
-
response = await fetch(
|
|
1274
|
+
response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
1743
1275
|
...init,
|
|
1744
1276
|
headers
|
|
1745
1277
|
});
|
|
@@ -1801,26 +1333,11 @@ async function getGitHubAuthStatusViaServer(context) {
|
|
|
1801
1333
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
1802
1334
|
}
|
|
1803
1335
|
async function postGitHubTokenViaServer(context, token, options = {}) {
|
|
1804
|
-
const
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
response = await fetch(requestUrl, {
|
|
1810
|
-
method: "POST",
|
|
1811
|
-
headers: { "content-type": "application/json" },
|
|
1812
|
-
body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot ?? server.serverProjectRoot ?? undefined })
|
|
1813
|
-
});
|
|
1814
|
-
} catch (error) {
|
|
1815
|
-
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
1816
|
-
throw new CliError(`Rig server auth bootstrap failed: ${error instanceof Error ? error.message : String(error)}
|
|
1817
|
-
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
1818
|
-
}
|
|
1819
|
-
const payload = await response.json().catch(() => null);
|
|
1820
|
-
if (!response.ok) {
|
|
1821
|
-
const detail = payload && typeof payload === "object" && !Array.isArray(payload) ? String(payload.error ?? JSON.stringify(payload)) : `HTTP ${response.status}`;
|
|
1822
|
-
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`." });
|
|
1823
|
-
}
|
|
1336
|
+
const payload = await requestServerJson(context, "/api/github/auth/token", {
|
|
1337
|
+
method: "POST",
|
|
1338
|
+
headers: { "content-type": "application/json" },
|
|
1339
|
+
body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot })
|
|
1340
|
+
});
|
|
1824
1341
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
1825
1342
|
}
|
|
1826
1343
|
async function prepareRemoteCheckoutViaServer(context, input) {
|
|
@@ -2098,14 +1615,6 @@ function permissionAllowsPr(payload) {
|
|
|
2098
1615
|
function isNotFoundError(error) {
|
|
2099
1616
|
return /\b(404|not found)\b/i.test(message(error));
|
|
2100
1617
|
}
|
|
2101
|
-
function isLoopbackBaseUrl(baseUrl) {
|
|
2102
|
-
try {
|
|
2103
|
-
const host = new URL(baseUrl).hostname.toLowerCase();
|
|
2104
|
-
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
|
|
2105
|
-
} catch {
|
|
2106
|
-
return false;
|
|
2107
|
-
}
|
|
2108
|
-
}
|
|
2109
1618
|
function projectCheckoutReady(payload) {
|
|
2110
1619
|
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
2111
1620
|
return null;
|
|
@@ -2159,38 +1668,25 @@ async function runFastTaskRunPreflight(context, options = {}) {
|
|
|
2159
1668
|
}
|
|
2160
1669
|
}
|
|
2161
1670
|
const repo = readRepoConnection(context.projectRoot);
|
|
2162
|
-
|
|
2163
|
-
let remoteRootBlocked = false;
|
|
2164
|
-
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>`."));
|
|
2165
|
-
if (selectedServer?.connectionKind === "remote" && repo?.project && !selectedServer.serverProjectRoot) {
|
|
2166
|
-
const link = await ensureRemoteProjectRootLink(context.projectRoot, { mode: "backfill-only", authToken: selectedServer.authToken });
|
|
2167
|
-
const loopbackDevRemote = !selectedServer.authToken && isLoopbackBaseUrl(selectedServer.baseUrl);
|
|
2168
|
-
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));
|
|
2169
|
-
remoteRootBlocked = !link.ok && !loopbackDevRemote;
|
|
2170
|
-
}
|
|
1671
|
+
checks.push(repo ? preflightCheck("project-link", "project linked to Rig server", repo.project ? "pass" : "warn", `${repo.selected}${repo.project ? ` -> ${repo.project}` : ""}`, "Run `rig init --yes --repo owner/repo` to record the GitHub repo slug.") : preflightCheck("project-link", "project linked to Rig server", legacyServerCompatibility ? "warn" : "fail", "missing .rig/state/connection.json", "Run `rig init` or `rig server use <alias|local>`."));
|
|
2171
1672
|
try {
|
|
2172
1673
|
const auth = await request("/api/github/auth/status");
|
|
2173
1674
|
checks.push(isAuthenticated(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>`."));
|
|
2174
1675
|
} catch (error) {
|
|
2175
1676
|
checks.push(preflightCheck("github-auth", "GitHub auth valid", legacyServerCompatibility ? "warn" : "fail", message(error), "Fix GitHub auth on the selected Rig server."));
|
|
2176
1677
|
}
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
checks.push(preflightCheck("github-repo-permissions", "GitHub PR permissions", "warn", message(error), "Ensure the selected token can push branches and open PRs."));
|
|
2190
|
-
}
|
|
2191
|
-
} else {
|
|
2192
|
-
checks.push(preflightCheck("task-projection", "task projection ready", "warn", "skipped until remote project-root link is repaired", "Run `rig server repair-link`, then retry."));
|
|
2193
|
-
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."));
|
|
1678
|
+
try {
|
|
1679
|
+
const projection = await request("/api/workspace/task-projection");
|
|
1680
|
+
checks.push(preflightCheck("task-projection", "task projection ready", "pass", JSON.stringify(projection).slice(0, 120)));
|
|
1681
|
+
} catch (error) {
|
|
1682
|
+
checks.push(preflightCheck("task-projection", "task projection ready", "warn", message(error), "Refresh task projection with `rig task list` before launching."));
|
|
1683
|
+
}
|
|
1684
|
+
try {
|
|
1685
|
+
const permissions = await request("/api/github/repo/permissions");
|
|
1686
|
+
const allowed = permissionAllowsPr(permissions);
|
|
1687
|
+
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."));
|
|
1688
|
+
} catch (error) {
|
|
1689
|
+
checks.push(preflightCheck("github-repo-permissions", "GitHub PR permissions", "warn", message(error), "Ensure the selected token can push branches and open PRs."));
|
|
2194
1690
|
}
|
|
2195
1691
|
if (repo?.project) {
|
|
2196
1692
|
try {
|
|
@@ -2202,24 +1698,19 @@ async function runFastTaskRunPreflight(context, options = {}) {
|
|
|
2202
1698
|
}
|
|
2203
1699
|
}
|
|
2204
1700
|
if (taskId) {
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
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."));
|
|
2219
|
-
}
|
|
2220
|
-
} else {
|
|
2221
|
-
checks.push(preflightCheck("issue", "task/issue accessible", "fail", "skipped until remote project-root link is repaired", "Run `rig server repair-link`, then retry."));
|
|
2222
|
-
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."));
|
|
1701
|
+
try {
|
|
1702
|
+
const tasks = await request(`/api/workspace/tasks?limit=200&refresh=1`);
|
|
1703
|
+
const found = Array.isArray(tasks) && tasks.some((task) => taskMatchesId(task, taskId));
|
|
1704
|
+
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."));
|
|
1705
|
+
} catch (error) {
|
|
1706
|
+
checks.push(preflightCheck("issue", "task/issue accessible", legacyServerCompatibility ? "warn" : "fail", message(error), "Fix the task source before launching a run."));
|
|
1707
|
+
}
|
|
1708
|
+
try {
|
|
1709
|
+
const runs = await request("/api/runs?limit=200");
|
|
1710
|
+
const duplicate = activeDuplicateRun(runs, taskId);
|
|
1711
|
+
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));
|
|
1712
|
+
} catch (error) {
|
|
1713
|
+
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."));
|
|
2223
1714
|
}
|
|
2224
1715
|
}
|
|
2225
1716
|
if ((options.runtimeAdapter ?? "pi") === "pi") {
|
|
@@ -2288,8 +1779,18 @@ import {
|
|
|
2288
1779
|
readJsonlFile as readJsonlFile2,
|
|
2289
1780
|
writeAuthorityRunRecord
|
|
2290
1781
|
} from "@rig/runtime/control-plane/authority-files";
|
|
2291
|
-
function normalizeRuntimeAdapter(
|
|
2292
|
-
|
|
1782
|
+
function normalizeRuntimeAdapter(value) {
|
|
1783
|
+
const normalized = value?.trim().toLowerCase();
|
|
1784
|
+
if (!normalized) {
|
|
1785
|
+
return "pi";
|
|
1786
|
+
}
|
|
1787
|
+
if (normalized === "codex" || normalized === "codex-cli" || normalized === "codex-app-server" || normalized === "gpt-codex") {
|
|
1788
|
+
return "codex";
|
|
1789
|
+
}
|
|
1790
|
+
if (normalized === "pi" || normalized === "rig-pi" || normalized === "@rig/pi") {
|
|
1791
|
+
return "pi";
|
|
1792
|
+
}
|
|
1793
|
+
return "claude-code";
|
|
2293
1794
|
}
|
|
2294
1795
|
function readLatestBeadRecord(projectRoot, taskId) {
|
|
2295
1796
|
const issuesPath = resolve12(resolveControlPlaneMonorepoRoot(projectRoot), ".beads", "issues.jsonl");
|
|
@@ -2703,19 +2204,16 @@ function formatConnectionList(connections) {
|
|
|
2703
2204
|
return [formatSection("Rig servers", `${rows.length} available`), `${pc3.bold(pad("ALIAS", aliasWidth))} ${pc3.bold("KIND")} ${pc3.bold("TARGET")}`, ...lines, "", ...formatNextSteps(["Select one: `rig server use <alias|local>`"])].join(`
|
|
2704
2205
|
`);
|
|
2705
2206
|
}
|
|
2706
|
-
function formatConnectionStatus(selected, connections
|
|
2207
|
+
function formatConnectionStatus(selected, connections) {
|
|
2707
2208
|
const connection = selected === "local" ? { kind: "local", mode: "auto" } : connections[selected];
|
|
2708
2209
|
const target = !connection ? "not configured" : connection.kind === "remote" ? connection.baseUrl : "local";
|
|
2709
|
-
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";
|
|
2710
2210
|
return [
|
|
2711
2211
|
formatSection("Rig server", "selected for this repo"),
|
|
2712
2212
|
`${themeFaint("\u2502")} ${themeDim("selected ")} ${pc3.bold(selected)}`,
|
|
2713
2213
|
`${themeFaint("\u2502")} ${themeDim("kind ")} ${formatStatusPill(connection?.kind ?? "unknown")}`,
|
|
2714
2214
|
`${themeFaint("\u2502")} ${themeDim("target ")} ${target ?? "not configured"}`,
|
|
2715
|
-
...repo?.project ? [`${themeFaint("\u2502")} ${themeDim("project ")} ${repo.project}`] : [],
|
|
2716
|
-
...connection?.kind === "remote" ? [`${themeFaint("\u2502")} ${themeDim("root ")} ${rootLabel}`] : [],
|
|
2717
2215
|
"",
|
|
2718
|
-
...formatNextSteps(
|
|
2216
|
+
...formatNextSteps(["Change: `rig server use <alias|local>`", "List saved servers: `rig server list`"])
|
|
2719
2217
|
].join(`
|
|
2720
2218
|
`);
|
|
2721
2219
|
}
|
|
@@ -3214,7 +2712,7 @@ var init__operator_surface = __esm(() => {
|
|
|
3214
2712
|
});
|
|
3215
2713
|
|
|
3216
2714
|
// packages/cli/src/commands/_pi-frontend.ts
|
|
3217
|
-
import { existsSync as existsSync15, mkdirSync as
|
|
2715
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync9, mkdtempSync, readFileSync as readFileSync10, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
3218
2716
|
import { homedir as homedir6, tmpdir } from "os";
|
|
3219
2717
|
import { join as join3 } from "path";
|
|
3220
2718
|
import { main as runPiMain } from "@earendil-works/pi-coding-agent";
|
|
@@ -3246,27 +2744,10 @@ function buildOperatorPiEnv(input) {
|
|
|
3246
2744
|
...input.serverProjectRoot ? { RIG_PROJECT_ROOT: input.serverProjectRoot } : {}
|
|
3247
2745
|
};
|
|
3248
2746
|
}
|
|
3249
|
-
function shouldRequireOperatorTranscript(status) {
|
|
3250
|
-
return typeof status === "string" && TERMINAL_RUN_STATUSES.has(status.trim().toLowerCase());
|
|
3251
|
-
}
|
|
3252
|
-
function missingOperatorTranscriptMessage(runId, status) {
|
|
3253
|
-
const shortRun = runId.trim().slice(0, 8) || "unknown";
|
|
3254
|
-
const statusText = typeof status === "string" && status.trim() ? status.trim() : "terminal";
|
|
3255
|
-
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.`;
|
|
3256
|
-
}
|
|
3257
|
-
function statusFromRunDetails(run) {
|
|
3258
|
-
if (!run || typeof run !== "object" || Array.isArray(run))
|
|
3259
|
-
return;
|
|
3260
|
-
const record = run;
|
|
3261
|
-
if (typeof record.status === "string")
|
|
3262
|
-
return record.status;
|
|
3263
|
-
const nested = record.run;
|
|
3264
|
-
return nested && typeof nested === "object" && !Array.isArray(nested) ? nested.status : undefined;
|
|
3265
|
-
}
|
|
3266
2747
|
async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
3267
2748
|
const server = await ensureServerForCli(context.projectRoot);
|
|
3268
2749
|
const localCwd = join3(homedir6(), ".rig", "drones", runId.slice(0, 8));
|
|
3269
|
-
|
|
2750
|
+
mkdirSync9(localCwd, { recursive: true });
|
|
3270
2751
|
trustDroneCwd(localCwd);
|
|
3271
2752
|
installRigPiTheme();
|
|
3272
2753
|
let sessionFileArg = [];
|
|
@@ -3288,28 +2769,21 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
3288
2769
|
return line;
|
|
3289
2770
|
}).join(`
|
|
3290
2771
|
`);
|
|
3291
|
-
|
|
2772
|
+
writeFileSync6(localSessionPath, content);
|
|
3292
2773
|
sessionFileArg = ["--session", localSessionPath];
|
|
3293
2774
|
}
|
|
3294
2775
|
} catch {}
|
|
3295
|
-
if (sessionFileArg.length === 0) {
|
|
3296
|
-
const run = await getRunDetailsViaServer(context, runId).catch(() => null);
|
|
3297
|
-
const status = statusFromRunDetails(run);
|
|
3298
|
-
if (shouldRequireOperatorTranscript(status)) {
|
|
3299
|
-
throw new OperatorTranscriptUnavailableError(missingOperatorTranscriptMessage(runId, status));
|
|
3300
|
-
}
|
|
3301
|
-
}
|
|
3302
2776
|
return { server, sessionFileArg };
|
|
3303
2777
|
}
|
|
3304
2778
|
function trustDroneCwd(localCwd) {
|
|
3305
2779
|
try {
|
|
3306
2780
|
const agentDir = join3(homedir6(), ".pi", "agent");
|
|
3307
|
-
|
|
2781
|
+
mkdirSync9(agentDir, { recursive: true });
|
|
3308
2782
|
const trustPath = join3(agentDir, "trust.json");
|
|
3309
2783
|
const store = existsSync15(trustPath) ? JSON.parse(readFileSync10(trustPath, "utf8")) : {};
|
|
3310
2784
|
if (store[localCwd] !== true) {
|
|
3311
2785
|
store[localCwd] = true;
|
|
3312
|
-
|
|
2786
|
+
writeFileSync6(trustPath, `${JSON.stringify(store, null, "\t")}
|
|
3313
2787
|
`);
|
|
3314
2788
|
}
|
|
3315
2789
|
} catch {}
|
|
@@ -3317,38 +2791,15 @@ function trustDroneCwd(localCwd) {
|
|
|
3317
2791
|
function installRigPiTheme() {
|
|
3318
2792
|
try {
|
|
3319
2793
|
const themesDir = join3(homedir6(), ".pi", "agent", "themes");
|
|
3320
|
-
|
|
2794
|
+
mkdirSync9(themesDir, { recursive: true });
|
|
3321
2795
|
const themePath = join3(themesDir, "rig.json");
|
|
3322
2796
|
const next = `${JSON.stringify(RIG_PI_THEME, null, "\t")}
|
|
3323
2797
|
`;
|
|
3324
2798
|
if (!existsSync15(themePath) || readFileSync10(themePath, "utf8") !== next) {
|
|
3325
|
-
|
|
2799
|
+
writeFileSync6(themePath, next);
|
|
3326
2800
|
}
|
|
3327
2801
|
} catch {}
|
|
3328
2802
|
}
|
|
3329
|
-
async function runWithProcessExitGuard(body) {
|
|
3330
|
-
const realExit = process.exit;
|
|
3331
|
-
let exitCode = 0;
|
|
3332
|
-
let signalQuit = () => {};
|
|
3333
|
-
const quit = new Promise((resolve23) => {
|
|
3334
|
-
signalQuit = resolve23;
|
|
3335
|
-
});
|
|
3336
|
-
const guardedExit = (code) => {
|
|
3337
|
-
exitCode = typeof code === "number" ? code : 0;
|
|
3338
|
-
signalQuit();
|
|
3339
|
-
return;
|
|
3340
|
-
};
|
|
3341
|
-
process.exit = guardedExit;
|
|
3342
|
-
try {
|
|
3343
|
-
await Promise.race([Promise.resolve().then(body), quit]);
|
|
3344
|
-
} finally {
|
|
3345
|
-
process.exit = realExit;
|
|
3346
|
-
}
|
|
3347
|
-
return exitCode;
|
|
3348
|
-
}
|
|
3349
|
-
function runPiMainReturningOnQuit(args, options) {
|
|
3350
|
-
return runWithProcessExitGuard(() => runPiMain(args, options));
|
|
3351
|
-
}
|
|
3352
2803
|
async function attachRunBundledPiFrontend(context, input) {
|
|
3353
2804
|
const tempSessionDir = mkdtempSync(join3(tmpdir(), "rig-pi-frontend-sessions-"));
|
|
3354
2805
|
const { server, sessionFileArg } = await withSpinner(`Opening Pi console for run ${input.runId}\u2026`, () => prepareOperatorConsole(context, input.runId, tempSessionDir), { outputMode: context.outputMode });
|
|
@@ -3364,20 +2815,15 @@ async function attachRunBundledPiFrontend(context, input) {
|
|
|
3364
2815
|
};
|
|
3365
2816
|
let detached = false;
|
|
3366
2817
|
try {
|
|
3367
|
-
|
|
3368
|
-
"--offline",
|
|
2818
|
+
await runPiMain([
|
|
3369
2819
|
"--no-extensions",
|
|
3370
2820
|
"--no-skills",
|
|
3371
2821
|
"--no-prompt-templates",
|
|
3372
2822
|
"--no-context-files",
|
|
3373
2823
|
...sessionFileArg
|
|
3374
|
-
]
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
await runPiMainReturningOnQuit(piArgs, piOptions);
|
|
3378
|
-
} else {
|
|
3379
|
-
await runPiMain(piArgs, piOptions);
|
|
3380
|
-
}
|
|
2824
|
+
], {
|
|
2825
|
+
extensionFactories: [piRigExtensionFactory]
|
|
2826
|
+
});
|
|
3381
2827
|
detached = true;
|
|
3382
2828
|
} finally {
|
|
3383
2829
|
restoreEnv();
|
|
@@ -3397,17 +2843,10 @@ async function attachRunBundledPiFrontend(context, input) {
|
|
|
3397
2843
|
rendered: "stock Pi operator console with the pi-rig extension"
|
|
3398
2844
|
};
|
|
3399
2845
|
}
|
|
3400
|
-
var
|
|
2846
|
+
var RIG_PI_THEME;
|
|
3401
2847
|
var init__pi_frontend = __esm(() => {
|
|
3402
2848
|
init__server_client();
|
|
3403
2849
|
init__async_ui();
|
|
3404
|
-
TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
|
|
3405
|
-
OperatorTranscriptUnavailableError = class OperatorTranscriptUnavailableError extends Error {
|
|
3406
|
-
constructor(message2) {
|
|
3407
|
-
super(message2);
|
|
3408
|
-
this.name = "OperatorTranscriptUnavailableError";
|
|
3409
|
-
}
|
|
3410
|
-
};
|
|
3411
2850
|
RIG_PI_THEME = {
|
|
3412
2851
|
$schema: "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
|
|
3413
2852
|
name: "rig",
|
|
@@ -3562,7 +3001,7 @@ async function attachRunOperatorView(context, input) {
|
|
|
3562
3001
|
}
|
|
3563
3002
|
const pollMs = Math.max(250, Math.trunc(input.pollMs ?? 2000));
|
|
3564
3003
|
let timelineCursor = snapshot.timelineCursor;
|
|
3565
|
-
while (!detached && !
|
|
3004
|
+
while (!detached && !TERMINAL_RUN_STATUSES.has(runStatusFromPayload(snapshot.run))) {
|
|
3566
3005
|
await Bun.sleep(pollMs);
|
|
3567
3006
|
snapshot = await readOperatorSnapshot(context, input.runId, { timelineCursor });
|
|
3568
3007
|
timelineCursor = snapshot.timelineCursor;
|
|
@@ -3574,13 +3013,13 @@ async function attachRunOperatorView(context, input) {
|
|
|
3574
3013
|
}
|
|
3575
3014
|
return { ...snapshot, steered, detached };
|
|
3576
3015
|
}
|
|
3577
|
-
var
|
|
3016
|
+
var TERMINAL_RUN_STATUSES;
|
|
3578
3017
|
var init__operator_view = __esm(() => {
|
|
3579
3018
|
init__server_client();
|
|
3580
3019
|
init__operator_surface();
|
|
3581
3020
|
init__pi_frontend();
|
|
3582
3021
|
init__async_ui();
|
|
3583
|
-
|
|
3022
|
+
TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
|
|
3584
3023
|
});
|
|
3585
3024
|
|
|
3586
3025
|
// packages/cli/src/commands/_help-catalog.ts
|
|
@@ -3750,13 +3189,12 @@ var init__help_catalog = __esm(() => {
|
|
|
3750
3189
|
{
|
|
3751
3190
|
name: "server",
|
|
3752
3191
|
summary: "Choose, inspect, and start the Rig server that owns tasks and runs.",
|
|
3753
|
-
usage: ["rig server <status|list|add|use|
|
|
3192
|
+
usage: ["rig server <status|list|add|use|start> [options]"],
|
|
3754
3193
|
commands: [
|
|
3755
|
-
{ command: "status", description: "Show the selected server
|
|
3194
|
+
{ command: "status", description: "Show the selected server for this repo.", primary: true },
|
|
3756
3195
|
{ command: "use local", description: "Switch this repo to the local Rig server.", primary: true },
|
|
3757
3196
|
{ command: "add <alias> <url>", description: "Save a remote Rig server URL.", primary: true },
|
|
3758
3197
|
{ command: "use <alias>", description: "Select a saved remote server alias.", primary: true },
|
|
3759
|
-
{ command: "repair-link [--prepare|--backfill-only] [--repo owner/repo]", description: "Backfill or prepare the selected remote's server-host checkout link.", primary: true },
|
|
3760
3198
|
{ command: "list", description: "List saved local/remote server aliases.", primary: true },
|
|
3761
3199
|
{ command: "start [--host <host>] [--port <n>]", description: "Start a local rig-server process." }
|
|
3762
3200
|
],
|
|
@@ -3764,7 +3202,6 @@ var init__help_catalog = __esm(() => {
|
|
|
3764
3202
|
"rig server status",
|
|
3765
3203
|
"rig server add prod https://where.rig-does.work",
|
|
3766
3204
|
"rig server use prod",
|
|
3767
|
-
"rig server repair-link --repo owner/repo",
|
|
3768
3205
|
"rig server use local",
|
|
3769
3206
|
"rig server start --port 3773"
|
|
3770
3207
|
],
|
|
@@ -3939,62 +3376,30 @@ var init__help_catalog = __esm(() => {
|
|
|
3939
3376
|
}
|
|
3940
3377
|
];
|
|
3941
3378
|
ADVANCED_GROUPS = [
|
|
3942
|
-
{
|
|
3943
|
-
|
|
3944
|
-
summary: "Bootstrap/check local setup.",
|
|
3945
|
-
usage: ["rig setup <bootstrap|check|preflight>"],
|
|
3946
|
-
commands: [
|
|
3947
|
-
{ command: "bootstrap", description: "Bootstrap local setup dependencies.", primary: true },
|
|
3948
|
-
{ command: "check", description: "Check local setup state (toolchain, deps, config).", primary: true },
|
|
3949
|
-
{ command: "preflight", description: "Run preflight checks before a run.", primary: true }
|
|
3950
|
-
]
|
|
3951
|
-
},
|
|
3952
|
-
{
|
|
3953
|
-
name: "profile",
|
|
3954
|
-
summary: "Runtime profile/model defaults.",
|
|
3955
|
-
usage: ["rig profile <show|set>"],
|
|
3956
|
-
commands: [
|
|
3957
|
-
{ command: "show", description: "Show the active execution profile.", primary: true },
|
|
3958
|
-
{ command: "set [--model <model>] [--runtime <runtime>] [--plugin <plugin>]", description: "Set model/runtime/plugin profile defaults.", primary: true }
|
|
3959
|
-
]
|
|
3960
|
-
},
|
|
3379
|
+
{ name: "setup", summary: "Bootstrap/check local setup.", usage: ["rig setup <bootstrap|check|preflight>"], commands: [{ command: "bootstrap|check|preflight", description: "Setup helpers." }] },
|
|
3380
|
+
{ name: "profile", summary: "Runtime profile/model defaults.", usage: ["rig profile <show|set>"], commands: [{ command: "show", description: "Show active profile." }] },
|
|
3961
3381
|
{
|
|
3962
3382
|
name: "review",
|
|
3963
3383
|
summary: "Inspect or change completion review gate policy.",
|
|
3964
3384
|
usage: ["rig review <show|set>"],
|
|
3965
3385
|
commands: [
|
|
3966
3386
|
{ command: "show", description: "Show current review gate settings." },
|
|
3967
|
-
{ command: "set <off|advisory|required> [--provider
|
|
3387
|
+
{ command: "set <off|advisory|required> [--provider greptile]", description: "Change review strictness/provider." }
|
|
3968
3388
|
],
|
|
3969
3389
|
examples: ["rig review show", "rig review set required --provider greptile"],
|
|
3970
3390
|
next: ["Use `rig inbox approvals` for blocked run handoffs."]
|
|
3971
3391
|
},
|
|
3972
3392
|
{
|
|
3973
3393
|
name: "browser",
|
|
3974
|
-
summary: "Browser
|
|
3975
|
-
usage: ["rig browser <help|explain|demo|hp-next
|
|
3394
|
+
summary: "Browser/app diagnostics for browser-required tasks.",
|
|
3395
|
+
usage: ["rig browser <help|explain|demo|app|hp-next> [options]"],
|
|
3976
3396
|
commands: [
|
|
3977
|
-
{ command: "help", description: "Rich browser command help (canonical: `rig browser help`)."
|
|
3978
|
-
{ command: "explain", description: "Explain the browser-required task contract
|
|
3979
|
-
{ command: "demo
|
|
3980
|
-
{ command: "
|
|
3981
|
-
{ command: "hp-next
|
|
3982
|
-
|
|
3983
|
-
{ command: "hp-next e2e", description: "Run hp-next browser e2e smoke checks through Rig Browser.", primary: true },
|
|
3984
|
-
{ command: "hp-next reset", description: "Reset the hp-next browser profile when stale browser state is suspected.", primary: true },
|
|
3985
|
-
{ command: "cdp-probe", description: "Run an isolated CDP attach/evaluate/layout probe." },
|
|
3986
|
-
{ command: "profile-persistence", description: "Verify a named browser profile persists browser state." },
|
|
3987
|
-
{ command: "profile-lock-check", description: "Verify concurrent launches reject the same profile." },
|
|
3988
|
-
{ command: "smoke-test", description: "Run the browser package smoke test." }
|
|
3989
|
-
],
|
|
3990
|
-
examples: [
|
|
3991
|
-
"rig browser help",
|
|
3992
|
-
"rig browser hp-next check",
|
|
3993
|
-
"rig browser hp-next e2e",
|
|
3994
|
-
"rig browser cdp-probe",
|
|
3995
|
-
"rig browser profile-lock-check"
|
|
3996
|
-
],
|
|
3997
|
-
next: ["Inside a task run, use rig-browser-launch, rig-browser-check, and rig-browser-attach-info from the worker PATH."]
|
|
3397
|
+
{ command: "help", description: "Rich browser command help (canonical: `rig browser help`)." },
|
|
3398
|
+
{ command: "explain", description: "Explain the browser-required task contract." },
|
|
3399
|
+
{ command: "demo", description: "Run browser demo flows against a local page." },
|
|
3400
|
+
{ command: "app", description: "Launch the Rig Browser workstation app." },
|
|
3401
|
+
{ command: "hp-next <dev|check|e2e|reset>", description: "Drive the hp-next browser test harness." }
|
|
3402
|
+
]
|
|
3998
3403
|
},
|
|
3999
3404
|
{
|
|
4000
3405
|
name: "pi",
|
|
@@ -4009,60 +3414,12 @@ var init__help_catalog = __esm(() => {
|
|
|
4009
3414
|
examples: ["rig pi search subagents", "rig pi add pi-subagents", "rig pi list"],
|
|
4010
3415
|
next: ["Config-managed extensions: declare `runtime: { pi: { packages: [...] } }` in rig.config.ts \u2014 workers pick them up automatically."]
|
|
4011
3416
|
},
|
|
4012
|
-
{
|
|
4013
|
-
|
|
4014
|
-
summary: "Run task queues locally.",
|
|
4015
|
-
usage: ["rig queue run [--workers <n>] [--max-tasks <n>] [--action validate|verify|pipeline] [--isolation off|worktree] [--no-runtime-reuse] [--fail-fast] [--skip-project-sync]"],
|
|
4016
|
-
commands: [
|
|
4017
|
-
{ command: "run [--workers <n>] [--max-tasks <n>] [--action validate|verify|pipeline] [--isolation off|worktree] [--no-runtime-reuse] [--fail-fast] [--skip-project-sync]", description: "Process queue work: drain matching tasks with N workers, optional per-task action and isolation.", primary: true }
|
|
4018
|
-
]
|
|
4019
|
-
},
|
|
4020
|
-
{
|
|
4021
|
-
name: "agent",
|
|
4022
|
-
summary: "Runtime agent workspace helpers.",
|
|
4023
|
-
usage: ["rig agent <list|prepare|run|cleanup>"],
|
|
4024
|
-
commands: [
|
|
4025
|
-
{ command: "list", description: "List prepared agent runtimes.", primary: true },
|
|
4026
|
-
{ command: "prepare [--id <id>] [--mode <mode>] [--task <task>]", description: "Prepare an isolated agent runtime workspace.", primary: true },
|
|
4027
|
-
{ command: "run [--id <id>] [--mode <mode>] [--task <task>] [--skip-project-sync]", description: "Prepare (if needed) and run an agent in its workspace.", primary: true },
|
|
4028
|
-
{ command: "cleanup [--all] [--id <id>]", description: "Remove prepared agent workspaces.", primary: true }
|
|
4029
|
-
]
|
|
4030
|
-
},
|
|
3417
|
+
{ name: "queue", summary: "Run task queues locally.", usage: ["rig queue run [options]"], commands: [{ command: "run", description: "Process queue work." }] },
|
|
3418
|
+
{ name: "agent", summary: "Runtime agent workspace helpers.", usage: ["rig agent <list|prepare|run|cleanup>"], commands: [{ command: "list", description: "List prepared agents." }] },
|
|
4031
3419
|
{ name: "inspector", summary: "Event stream and drift scanners.", usage: ["rig inspector <stream|scan-upstream-drift>"], commands: [{ command: "stream", description: "Stream events." }] },
|
|
4032
|
-
{
|
|
4033
|
-
name: "dist",
|
|
4034
|
-
summary: "Build/install packaged Rig CLI.",
|
|
4035
|
-
usage: ["rig dist <build|install|doctor|rebuild-agent>"],
|
|
4036
|
-
commands: [
|
|
4037
|
-
{ command: "build [--output-dir <dir>]", description: "Build the distributable Rig CLI.", primary: true },
|
|
4038
|
-
{ command: "install [--scope <scope>] [--path <path>]", description: "Install the built CLI to a scope/path.", primary: true },
|
|
4039
|
-
{ command: "doctor", description: "Diagnose the dist toolchain and install state.", primary: true },
|
|
4040
|
-
{ command: "rebuild-agent", description: "Rebuild the agent runtime image, pruning stale images.", primary: true }
|
|
4041
|
-
]
|
|
4042
|
-
},
|
|
3420
|
+
{ name: "dist", summary: "Build/install packaged Rig CLI.", usage: ["rig dist <build|install|doctor>"], commands: [{ command: "build", description: "Build distribution." }] },
|
|
4043
3421
|
{ name: "workspace", summary: "Workspace topology/service helpers.", usage: ["rig workspace <summary|topology|remote-hosts>"], commands: [{ command: "summary", description: "Show workspace summary." }] },
|
|
4044
|
-
{
|
|
4045
|
-
name: "remote",
|
|
4046
|
-
summary: "Compatibility remote orchestration controls.",
|
|
4047
|
-
usage: ["rig remote <status|tasks|watch|pause|resume|continue|stop|refresh|add-iterations|remove-iterations|endpoint ...>"],
|
|
4048
|
-
commands: [
|
|
4049
|
-
{ command: "status [--remote <alias>]", description: "Show the remote orchestration state.", primary: true },
|
|
4050
|
-
{ command: "tasks [--remote <alias>]", description: "List the remote's tracked tasks.", primary: true },
|
|
4051
|
-
{ command: "watch [--remote <alias>] [--seconds <n>] [--event <type>]", description: "Stream remote orchestration events.", primary: true },
|
|
4052
|
-
{ command: "pause [--remote <alias>]", description: "Pause the running remote orchestration.", primary: true },
|
|
4053
|
-
{ command: "resume [--remote <alias>] [--max-workers <n>] [--max-iterations <n>] [--direct-merge]", description: "Resume the remote with optional tuning.", primary: true },
|
|
4054
|
-
{ command: "continue [--remote <alias>]", description: "Continue a paused remote orchestration.", primary: true },
|
|
4055
|
-
{ command: "stop [--remote <alias>]", description: "Stop the remote orchestration.", primary: true },
|
|
4056
|
-
{ command: "refresh [--remote <alias>]", description: "Refresh remote state.", primary: true },
|
|
4057
|
-
{ command: "add-iterations [--count <n>] [--remote <alias>]", description: "Grant the remote more iterations.", primary: true },
|
|
4058
|
-
{ command: "remove-iterations [--count <n>] [--remote <alias>]", description: "Reduce the remote's iteration budget.", primary: true },
|
|
4059
|
-
{ command: "endpoint list", description: "List configured remote endpoints.", primary: true },
|
|
4060
|
-
{ command: "endpoint add --alias <alias> --host <host> --port <n> [--token <token>]", description: "Register a remote endpoint.", primary: true },
|
|
4061
|
-
{ command: "endpoint remove --alias <alias>", description: "Remove a remote endpoint.", primary: true },
|
|
4062
|
-
{ command: "endpoint test [--alias <alias>]", description: "Test connectivity to a remote endpoint.", primary: true },
|
|
4063
|
-
{ command: "endpoint doctor", description: "Diagnose remote endpoint configuration.", primary: true }
|
|
4064
|
-
]
|
|
4065
|
-
},
|
|
3422
|
+
{ name: "remote", summary: "Compatibility remote orchestration controls.", usage: ["rig remote <status|watch|pause|resume|...>"], commands: [{ command: "status", description: "Show remote state." }] },
|
|
4066
3423
|
{ name: "git", summary: "Pass through to Rig git-flow helper.", usage: ["rig git <args...>"], commands: [{ command: "<args...>", description: "Advanced git flow operations." }] },
|
|
4067
3424
|
{ name: "harness", summary: "Pass through to runtime harness CLI.", usage: ["rig harness <args...>"], commands: [{ command: "<args...>", description: "Advanced harness operations." }] },
|
|
4068
3425
|
{ name: "test", summary: "Project test wrappers.", usage: ["rig test <unit|e2e|all>"], commands: [{ command: "all", description: "Run configured project tests." }] }
|
|
@@ -4129,7 +3486,7 @@ var init__task_picker = __esm(() => {
|
|
|
4129
3486
|
// packages/cli/src/commands/task.ts
|
|
4130
3487
|
import { readFileSync as readFileSync11 } from "fs";
|
|
4131
3488
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
4132
|
-
import { resolve as
|
|
3489
|
+
import { resolve as resolve22 } from "path";
|
|
4133
3490
|
import {
|
|
4134
3491
|
taskArtifactDir,
|
|
4135
3492
|
taskArtifacts,
|
|
@@ -4407,7 +3764,7 @@ async function executeTask(context, args, options) {
|
|
|
4407
3764
|
const fileFlag = takeOption(rest.slice(1), "--file");
|
|
4408
3765
|
let content;
|
|
4409
3766
|
if (fileFlag.value) {
|
|
4410
|
-
content = readFileSync11(
|
|
3767
|
+
content = readFileSync11(resolve22(context.projectRoot, fileFlag.value), "utf-8");
|
|
4411
3768
|
} else {
|
|
4412
3769
|
content = await readStdin();
|
|
4413
3770
|
}
|
|
@@ -4645,47 +4002,6 @@ var init_task = __esm(() => {
|
|
|
4645
4002
|
init__connection_state();
|
|
4646
4003
|
});
|
|
4647
4004
|
|
|
4648
|
-
// packages/cli/src/commands/_server-events.ts
|
|
4649
|
-
import { WsTransport } from "@rig/client";
|
|
4650
|
-
import { RIG_WS_CHANNELS } from "@rig/contracts";
|
|
4651
|
-
function buildRigWebSocketUrl(baseUrl, authToken) {
|
|
4652
|
-
const url = new URL(baseUrl);
|
|
4653
|
-
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
4654
|
-
if (authToken)
|
|
4655
|
-
url.searchParams.set("token", authToken);
|
|
4656
|
-
return url.toString();
|
|
4657
|
-
}
|
|
4658
|
-
async function connectRigServerEvents(projectRoot, handlers) {
|
|
4659
|
-
const { baseUrl, authToken } = await ensureServerForCli(projectRoot);
|
|
4660
|
-
const transport = new WsTransport(buildRigWebSocketUrl(baseUrl, authToken));
|
|
4661
|
-
const unsubscribers = [];
|
|
4662
|
-
if (handlers.onSnapshotInvalidated)
|
|
4663
|
-
unsubscribers.push(transport.subscribe(RIG_WS_CHANNELS.snapshotInvalidated, handlers.onSnapshotInvalidated));
|
|
4664
|
-
if (handlers.onRunLogAppended)
|
|
4665
|
-
unsubscribers.push(transport.subscribe(RIG_WS_CHANNELS.runLogAppended, handlers.onRunLogAppended));
|
|
4666
|
-
if (handlers.onEngineEvent)
|
|
4667
|
-
unsubscribers.push(transport.subscribe(RIG_WS_CHANNELS.event, handlers.onEngineEvent));
|
|
4668
|
-
let status = "connecting";
|
|
4669
|
-
unsubscribers.push(transport.subscribeState((state) => {
|
|
4670
|
-
status = state.status;
|
|
4671
|
-
handlers.onStatus?.(state.status);
|
|
4672
|
-
}));
|
|
4673
|
-
return {
|
|
4674
|
-
connected: () => status === "connected",
|
|
4675
|
-
close: () => {
|
|
4676
|
-
for (const unsubscribe of unsubscribers) {
|
|
4677
|
-
try {
|
|
4678
|
-
unsubscribe();
|
|
4679
|
-
} catch {}
|
|
4680
|
-
}
|
|
4681
|
-
transport.dispose();
|
|
4682
|
-
}
|
|
4683
|
-
};
|
|
4684
|
-
}
|
|
4685
|
-
var init__server_events = __esm(() => {
|
|
4686
|
-
init__server_client();
|
|
4687
|
-
});
|
|
4688
|
-
|
|
4689
4005
|
// packages/cli/src/app/board.ts
|
|
4690
4006
|
var exports_board = {};
|
|
4691
4007
|
__export(exports_board, {
|
|
@@ -4717,7 +4033,6 @@ function statusRank(status) {
|
|
|
4717
4033
|
case "pending":
|
|
4718
4034
|
case "preparing":
|
|
4719
4035
|
case "adopted":
|
|
4720
|
-
case "stopping":
|
|
4721
4036
|
return 2;
|
|
4722
4037
|
case "completed":
|
|
4723
4038
|
case "merged":
|
|
@@ -4757,10 +4072,6 @@ class RunsList {
|
|
|
4757
4072
|
selectedRun() {
|
|
4758
4073
|
return this.visibleRuns()[this.selected] ?? null;
|
|
4759
4074
|
}
|
|
4760
|
-
patchRun(runId, patch) {
|
|
4761
|
-
this.runs = this.runs.map((run) => run.runId === runId ? { ...run, ...patch } : run);
|
|
4762
|
-
this.clampSelection();
|
|
4763
|
-
}
|
|
4764
4075
|
cycleSort() {
|
|
4765
4076
|
this.sortMode = this.sortMode === "active" ? "recent" : this.sortMode === "recent" ? "status" : "active";
|
|
4766
4077
|
this.clampSelection();
|
|
@@ -4983,14 +4294,6 @@ class InboxView {
|
|
|
4983
4294
|
selectedItem() {
|
|
4984
4295
|
return this.items[this.selected] ?? null;
|
|
4985
4296
|
}
|
|
4986
|
-
patchItem(requestId, summary) {
|
|
4987
|
-
this.items = this.items.map((item) => item.requestId === requestId ? { ...item, summary } : item);
|
|
4988
|
-
}
|
|
4989
|
-
removeItem(requestId) {
|
|
4990
|
-
const previousIndex = this.selected;
|
|
4991
|
-
this.items = this.items.filter((item) => item.requestId !== requestId);
|
|
4992
|
-
this.selected = Math.max(0, Math.min(previousIndex, Math.max(0, this.items.length - 1)));
|
|
4993
|
-
}
|
|
4994
4297
|
invalidate() {}
|
|
4995
4298
|
render(width) {
|
|
4996
4299
|
return this.renderLines(width).map((line) => truncateToWidth(line, Math.max(10, width - 1)));
|
|
@@ -5212,14 +4515,9 @@ async function runOperatorBoard(context, options = {}) {
|
|
|
5212
4515
|
tui.stop();
|
|
5213
4516
|
};
|
|
5214
4517
|
let refreshInFlight = false;
|
|
5215
|
-
const refresh = async (
|
|
4518
|
+
const refresh = async () => {
|
|
5216
4519
|
if (refreshInFlight)
|
|
5217
4520
|
return;
|
|
5218
|
-
if (!options2.quiet) {
|
|
5219
|
-
notice = "refreshing fleet\u2026";
|
|
5220
|
-
renderFooter();
|
|
5221
|
-
tui.requestRender();
|
|
5222
|
-
}
|
|
5223
4521
|
if (!hasRigProject(context.projectRoot)) {
|
|
5224
4522
|
list.loading = false;
|
|
5225
4523
|
list.noProject = true;
|
|
@@ -5302,7 +4600,6 @@ async function runOperatorBoard(context, options = {}) {
|
|
|
5302
4600
|
};
|
|
5303
4601
|
const resolveApproval = async (item, decision) => {
|
|
5304
4602
|
notice = `${decision === "approve" ? "approving" : "rejecting"} ${item.requestId.slice(0, 12)}\u2026`;
|
|
5305
|
-
inboxView.patchItem(item.requestId, `${decision === "approve" ? "approving" : "rejecting"}\u2026 ${item.summary}`);
|
|
5306
4603
|
renderFooter();
|
|
5307
4604
|
tui.requestRender();
|
|
5308
4605
|
try {
|
|
@@ -5311,10 +4608,8 @@ async function runOperatorBoard(context, options = {}) {
|
|
|
5311
4608
|
headers: { "content-type": "application/json" },
|
|
5312
4609
|
body: JSON.stringify({ runId: item.runId, requestId: item.requestId, decision, note: null })
|
|
5313
4610
|
});
|
|
5314
|
-
inboxView.removeItem(item.requestId);
|
|
5315
4611
|
notice = `${decision === "approve" ? "approved" : "rejected"} \u2014 drone resumes`;
|
|
5316
4612
|
} catch (error) {
|
|
5317
|
-
inboxView.patchItem(item.requestId, item.summary);
|
|
5318
4613
|
notice = `resolve failed: ${oneLine(error instanceof Error ? error.message : String(error))}`;
|
|
5319
4614
|
}
|
|
5320
4615
|
renderFooter();
|
|
@@ -5323,7 +4618,6 @@ async function runOperatorBoard(context, options = {}) {
|
|
|
5323
4618
|
};
|
|
5324
4619
|
const answerInput = async (item, text2) => {
|
|
5325
4620
|
notice = `answering ${item.requestId.slice(0, 12)}\u2026`;
|
|
5326
|
-
inboxView.patchItem(item.requestId, `answering\u2026 ${item.summary}`);
|
|
5327
4621
|
renderFooter();
|
|
5328
4622
|
tui.requestRender();
|
|
5329
4623
|
try {
|
|
@@ -5336,10 +4630,8 @@ async function runOperatorBoard(context, options = {}) {
|
|
|
5336
4630
|
answers: { [item.questionId ?? "response"]: text2 }
|
|
5337
4631
|
})
|
|
5338
4632
|
});
|
|
5339
|
-
inboxView.removeItem(item.requestId);
|
|
5340
4633
|
notice = "answer sent \u2014 drone resumes";
|
|
5341
4634
|
} catch (error) {
|
|
5342
|
-
inboxView.patchItem(item.requestId, item.summary);
|
|
5343
4635
|
notice = `answer failed: ${oneLine(error instanceof Error ? error.message : String(error))}`;
|
|
5344
4636
|
}
|
|
5345
4637
|
renderFooter();
|
|
@@ -5488,7 +4780,6 @@ async function runOperatorBoard(context, options = {}) {
|
|
|
5488
4780
|
const run = list.selectedRun();
|
|
5489
4781
|
if (run) {
|
|
5490
4782
|
notice = `stop requested for ${run.runId.slice(0, 8)}\u2026`;
|
|
5491
|
-
list.patchRun(run.runId, { status: "stopping" });
|
|
5492
4783
|
renderFooter();
|
|
5493
4784
|
tui.requestRender();
|
|
5494
4785
|
stopRunViaServer(context, run.runId).then(() => refresh()).catch(() => refresh());
|
|
@@ -5496,9 +4787,6 @@ async function runOperatorBoard(context, options = {}) {
|
|
|
5496
4787
|
return { consume: true };
|
|
5497
4788
|
}
|
|
5498
4789
|
if (data === "r") {
|
|
5499
|
-
notice = "refreshing fleet\u2026";
|
|
5500
|
-
renderFooter();
|
|
5501
|
-
tui.requestRender();
|
|
5502
4790
|
refresh();
|
|
5503
4791
|
return { consume: true };
|
|
5504
4792
|
}
|
|
@@ -5524,39 +4812,21 @@ async function runOperatorBoard(context, options = {}) {
|
|
|
5524
4812
|
tui.requestRender();
|
|
5525
4813
|
}
|
|
5526
4814
|
}, BOARD_TICK_MS);
|
|
5527
|
-
const live = { subscription: null };
|
|
5528
|
-
const refreshActiveView = () => {
|
|
5529
|
-
refresh({ quiet: true });
|
|
5530
|
-
if (view === "tasks")
|
|
5531
|
-
refreshTasks();
|
|
5532
|
-
if (view === "inbox")
|
|
5533
|
-
refreshInbox();
|
|
5534
|
-
};
|
|
5535
|
-
connectRigServerEvents(context.projectRoot, {
|
|
5536
|
-
onSnapshotInvalidated: () => refreshActiveView()
|
|
5537
|
-
}).then((subscription) => {
|
|
5538
|
-
live.subscription = subscription;
|
|
5539
|
-
}).catch(() => {
|
|
5540
|
-
live.subscription = null;
|
|
5541
|
-
});
|
|
5542
4815
|
const refreshTimer = setInterval(() => {
|
|
5543
|
-
if (live.subscription?.connected())
|
|
5544
|
-
return;
|
|
5545
4816
|
refresh();
|
|
5546
4817
|
}, BOARD_REFRESH_MS);
|
|
5547
4818
|
tui.start();
|
|
5548
|
-
refresh(
|
|
5549
|
-
await new Promise((
|
|
4819
|
+
refresh();
|
|
4820
|
+
await new Promise((resolve25) => {
|
|
5550
4821
|
const poll = setInterval(() => {
|
|
5551
4822
|
if (stopped) {
|
|
5552
4823
|
clearInterval(poll);
|
|
5553
|
-
|
|
4824
|
+
resolve25();
|
|
5554
4825
|
}
|
|
5555
4826
|
}, 50);
|
|
5556
4827
|
});
|
|
5557
4828
|
clearInterval(animation);
|
|
5558
4829
|
clearInterval(refreshTimer);
|
|
5559
|
-
live.subscription?.close();
|
|
5560
4830
|
return outcome;
|
|
5561
4831
|
}
|
|
5562
4832
|
async function runOperatorBoardLoop(context, attach, options = {}) {
|
|
@@ -5569,13 +4839,12 @@ async function runOperatorBoardLoop(context, attach, options = {}) {
|
|
|
5569
4839
|
await attach(outcome.runId);
|
|
5570
4840
|
}
|
|
5571
4841
|
}
|
|
5572
|
-
var BOARD_REFRESH_MS = 5000, BOARD_TICK_MS =
|
|
4842
|
+
var BOARD_REFRESH_MS = 5000, BOARD_TICK_MS = 250, BOARD_TASK_PAGE = 20;
|
|
5573
4843
|
var init_board = __esm(() => {
|
|
5574
4844
|
init_theme();
|
|
5575
4845
|
init__help_catalog();
|
|
5576
4846
|
init__server_client();
|
|
5577
4847
|
init__authority_runs();
|
|
5578
|
-
init__server_events();
|
|
5579
4848
|
init_inbox();
|
|
5580
4849
|
init_task();
|
|
5581
4850
|
});
|
|
@@ -5586,7 +4855,7 @@ import {
|
|
|
5586
4855
|
existsSync as existsSync19,
|
|
5587
4856
|
readFileSync as readFileSync13
|
|
5588
4857
|
} from "fs";
|
|
5589
|
-
import { resolve as
|
|
4858
|
+
import { resolve as resolve25 } from "path";
|
|
5590
4859
|
import { readBuildConfig } from "@rig/runtime/build-time-config";
|
|
5591
4860
|
|
|
5592
4861
|
// packages/cli/src/commands/browser.ts
|
|
@@ -8093,7 +7362,7 @@ import {
|
|
|
8093
7362
|
chmodSync,
|
|
8094
7363
|
copyFileSync as copyFileSync2,
|
|
8095
7364
|
existsSync as existsSync9,
|
|
8096
|
-
mkdirSync as
|
|
7365
|
+
mkdirSync as mkdirSync7,
|
|
8097
7366
|
readdirSync,
|
|
8098
7367
|
readlinkSync,
|
|
8099
7368
|
rmSync as rmSync3,
|
|
@@ -8210,7 +7479,7 @@ async function executeDist(context, args) {
|
|
|
8210
7479
|
requireNoExtraArgs(pending, "rig dist install [--scope user|system] [--path <dir>]");
|
|
8211
7480
|
const scope = parseInstallScope(scopeResult.value);
|
|
8212
7481
|
const installDir = resolveInstallDir(scope, pathResult.value);
|
|
8213
|
-
|
|
7482
|
+
mkdirSync7(installDir, { recursive: true });
|
|
8214
7483
|
let source = await findLatestDistBinary(context.projectRoot);
|
|
8215
7484
|
let buildDir = null;
|
|
8216
7485
|
if (!source) {
|
|
@@ -8265,7 +7534,7 @@ async function executeDist(context, args) {
|
|
|
8265
7534
|
const fp = await computeRuntimeImageFingerprint(context.projectRoot);
|
|
8266
7535
|
const currentId = computeRuntimeImageId(fp);
|
|
8267
7536
|
const imagesDir = resolve14(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "images");
|
|
8268
|
-
|
|
7537
|
+
mkdirSync7(imagesDir, { recursive: true });
|
|
8269
7538
|
let pruned = 0;
|
|
8270
7539
|
for (const entry of readdirSync(imagesDir, { withFileTypes: true })) {
|
|
8271
7540
|
if (entry.isDirectory() && entry.name !== currentId) {
|
|
@@ -8277,9 +7546,9 @@ async function executeDist(context, args) {
|
|
|
8277
7546
|
console.log(`Pruned ${pruned} stale image(s).`);
|
|
8278
7547
|
}
|
|
8279
7548
|
const imageDir = resolve14(imagesDir, currentId);
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
|
|
7549
|
+
mkdirSync7(resolve14(imageDir, "bin/hooks"), { recursive: true });
|
|
7550
|
+
mkdirSync7(resolve14(imageDir, "bin/plugins"), { recursive: true });
|
|
7551
|
+
mkdirSync7(resolve14(imageDir, "bin/validators"), { recursive: true });
|
|
8283
7552
|
const hookNames = [
|
|
8284
7553
|
"scope-guard",
|
|
8285
7554
|
"import-guard",
|
|
@@ -8304,8 +7573,8 @@ async function executeDist(context, args) {
|
|
|
8304
7573
|
const binPluginsDir = resolve14(resolveControlPlaneHostBinDir(context.projectRoot), "plugins");
|
|
8305
7574
|
const validatorsRoot = resolve14(hostProjectRoot, "packages/runtime/src/control-plane/validators");
|
|
8306
7575
|
const binValidatorsDir = resolve14(resolveControlPlaneHostBinDir(context.projectRoot), "validators");
|
|
8307
|
-
|
|
8308
|
-
|
|
7576
|
+
mkdirSync7(binPluginsDir, { recursive: true });
|
|
7577
|
+
mkdirSync7(binValidatorsDir, { recursive: true });
|
|
8309
7578
|
if (existsSync9(pluginsDir)) {
|
|
8310
7579
|
for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
|
|
8311
7580
|
const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
@@ -8412,7 +7681,7 @@ init_inbox();
|
|
|
8412
7681
|
init_runner();
|
|
8413
7682
|
init__connection_state();
|
|
8414
7683
|
init__server_client();
|
|
8415
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync12, mkdirSync as
|
|
7684
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
8416
7685
|
import { spawnSync } from "child_process";
|
|
8417
7686
|
import { basename as basename2, resolve as resolve18 } from "path";
|
|
8418
7687
|
import { buildRigInitConfigSource } from "@rig/core";
|
|
@@ -8598,7 +7867,7 @@ async function buildPiSetupChecks(input = {}) {
|
|
|
8598
7867
|
// packages/cli/src/commands/_snapshot-upload.ts
|
|
8599
7868
|
init__server_client();
|
|
8600
7869
|
import { mkdir, readdir, readFile, writeFile } from "fs/promises";
|
|
8601
|
-
import { dirname as
|
|
7870
|
+
import { dirname as dirname3, resolve as resolve16, relative, sep } from "path";
|
|
8602
7871
|
var SNAPSHOT_ARCHIVE_VERSION = 1;
|
|
8603
7872
|
var SNAPSHOT_ARCHIVE_CONTENT_TYPE = "application/vnd.rig.snapshot+json";
|
|
8604
7873
|
var DEFAULT_EXCLUDED_DIRECTORIES = new Set([
|
|
@@ -8947,14 +8216,14 @@ function parseRepoSlug(value) {
|
|
|
8947
8216
|
}
|
|
8948
8217
|
function ensureRigPrivateDirs(projectRoot) {
|
|
8949
8218
|
const rigDir = resolve18(projectRoot, ".rig");
|
|
8950
|
-
|
|
8951
|
-
|
|
8952
|
-
|
|
8953
|
-
|
|
8954
|
-
|
|
8219
|
+
mkdirSync8(resolve18(rigDir, "state"), { recursive: true });
|
|
8220
|
+
mkdirSync8(resolve18(rigDir, "logs"), { recursive: true });
|
|
8221
|
+
mkdirSync8(resolve18(rigDir, "runs"), { recursive: true });
|
|
8222
|
+
mkdirSync8(resolve18(rigDir, "tmp"), { recursive: true });
|
|
8223
|
+
mkdirSync8(resolve18(projectRoot, "artifacts"), { recursive: true });
|
|
8955
8224
|
const taskConfigPath = resolve18(rigDir, "task-config.json");
|
|
8956
8225
|
if (!existsSync12(taskConfigPath))
|
|
8957
|
-
|
|
8226
|
+
writeFileSync5(taskConfigPath, `{}
|
|
8958
8227
|
`, "utf-8");
|
|
8959
8228
|
}
|
|
8960
8229
|
function ensureGitignoreEntries(projectRoot) {
|
|
@@ -8982,7 +8251,7 @@ function ensureRigConfigPackageDependencies(projectRoot) {
|
|
|
8982
8251
|
...existsSync12(path) ? existing : { name: "rig-project", private: true },
|
|
8983
8252
|
devDependencies
|
|
8984
8253
|
};
|
|
8985
|
-
|
|
8254
|
+
writeFileSync5(path, `${JSON.stringify(next, null, 2)}
|
|
8986
8255
|
`, "utf8");
|
|
8987
8256
|
}
|
|
8988
8257
|
function applyGitHubProjectConfig(source, options) {
|
|
@@ -9008,9 +8277,9 @@ function checkoutForInit(projectRoot, serverKind, strategy) {
|
|
|
9008
8277
|
const selected = strategy ?? { kind: "managed-clone" };
|
|
9009
8278
|
switch (selected.kind) {
|
|
9010
8279
|
case "managed-clone":
|
|
9011
|
-
return { kind: "managed-clone" };
|
|
8280
|
+
return { kind: "managed-clone", path: projectRoot };
|
|
9012
8281
|
case "current-ref":
|
|
9013
|
-
return { kind: "current-ref", ...selected.ref ? { ref: selected.ref } : {} };
|
|
8282
|
+
return { kind: "current-ref", path: projectRoot, ...selected.ref ? { ref: selected.ref } : {} };
|
|
9014
8283
|
case "uploaded-snapshot":
|
|
9015
8284
|
return { kind: "uploaded-snapshot", path: projectRoot, source: "local-working-tree" };
|
|
9016
8285
|
case "existing-path":
|
|
@@ -9280,7 +8549,7 @@ function remoteGitHubAuthMetadata(payload) {
|
|
|
9280
8549
|
};
|
|
9281
8550
|
}
|
|
9282
8551
|
function writeRemoteGitHubAuthState(projectRoot, input) {
|
|
9283
|
-
|
|
8552
|
+
writeFileSync5(resolve18(projectRoot, ".rig", "state", "github-auth.json"), `${JSON.stringify({
|
|
9284
8553
|
authenticated: true,
|
|
9285
8554
|
source: input.source,
|
|
9286
8555
|
storedOnServer: true,
|
|
@@ -9328,7 +8597,7 @@ function runLocalFilesInit(context, options) {
|
|
|
9328
8597
|
console.log("rig.config already exists; leaving it unchanged. Pass --repair to rewrite it.");
|
|
9329
8598
|
} else {
|
|
9330
8599
|
const projectName = basename2(projectRoot) || "rig-project";
|
|
9331
|
-
|
|
8600
|
+
writeFileSync5(configTsPath, buildRigInitConfigSource({
|
|
9332
8601
|
projectName,
|
|
9333
8602
|
taskSource: { kind: "files", path: "tasks" },
|
|
9334
8603
|
useStandardPlugin: true
|
|
@@ -9337,8 +8606,8 @@ function runLocalFilesInit(context, options) {
|
|
|
9337
8606
|
ensureRigConfigPackageDependencies(projectRoot);
|
|
9338
8607
|
const tasksDir = resolve18(projectRoot, "tasks");
|
|
9339
8608
|
if (!existsSync12(tasksDir)) {
|
|
9340
|
-
|
|
9341
|
-
|
|
8609
|
+
mkdirSync8(tasksDir, { recursive: true });
|
|
8610
|
+
writeFileSync5(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)}
|
|
9342
8611
|
`, "utf-8");
|
|
9343
8612
|
}
|
|
9344
8613
|
if (context.outputMode !== "json") {
|
|
@@ -9401,7 +8670,7 @@ function runDemoInit(context, options) {
|
|
|
9401
8670
|
console.log("rig.config already exists; leaving it unchanged. Pass --repair to rewrite it for the demo.");
|
|
9402
8671
|
}
|
|
9403
8672
|
} else {
|
|
9404
|
-
|
|
8673
|
+
writeFileSync5(configTsPath, buildRigInitConfigSource({
|
|
9405
8674
|
projectName: basename2(projectRoot) || "rig-demo",
|
|
9406
8675
|
taskSource: { kind: "files", path: DEMO_TASKS_RELATIVE_DIR },
|
|
9407
8676
|
useStandardPlugin: true
|
|
@@ -9410,14 +8679,14 @@ function runDemoInit(context, options) {
|
|
|
9410
8679
|
}
|
|
9411
8680
|
ensureRigConfigPackageDependencies(projectRoot);
|
|
9412
8681
|
const demoTasksDir = resolve18(projectRoot, DEMO_TASKS_RELATIVE_DIR);
|
|
9413
|
-
|
|
8682
|
+
mkdirSync8(demoTasksDir, { recursive: true });
|
|
9414
8683
|
const taskIds = [];
|
|
9415
8684
|
for (const task of DEMO_TASKS) {
|
|
9416
8685
|
const id = String(task.id);
|
|
9417
8686
|
taskIds.push(id);
|
|
9418
8687
|
const taskPath = resolve18(demoTasksDir, `${id}.json`);
|
|
9419
8688
|
if (!existsSync12(taskPath)) {
|
|
9420
|
-
|
|
8689
|
+
writeFileSync5(taskPath, `${JSON.stringify(task, null, 2)}
|
|
9421
8690
|
`, "utf-8");
|
|
9422
8691
|
}
|
|
9423
8692
|
}
|
|
@@ -9445,32 +8714,21 @@ function runDemoInit(context, options) {
|
|
|
9445
8714
|
}
|
|
9446
8715
|
async function runControlPlaneInit(context, options) {
|
|
9447
8716
|
const projectRoot = context.projectRoot;
|
|
9448
|
-
const
|
|
9449
|
-
const selectedConnection = (() => {
|
|
9450
|
-
try {
|
|
9451
|
-
return resolveSelectedConnection(projectRoot);
|
|
9452
|
-
} catch {
|
|
9453
|
-
return null;
|
|
9454
|
-
}
|
|
9455
|
-
})();
|
|
9456
|
-
const selectedRemote = selectedConnection?.connection.kind === "remote" ? { alias: selectedConnection.alias, connection: selectedConnection.connection } : null;
|
|
9457
|
-
const detectedSlug = options.repoSlug ?? existingRepoConnection?.project ?? detectOriginRepoSlug(projectRoot);
|
|
9458
|
-
const serverKind = options.server ?? (selectedRemote ? "remote" : "local");
|
|
8717
|
+
const detectedSlug = options.repoSlug ?? detectOriginRepoSlug(projectRoot);
|
|
9459
8718
|
if (!detectedSlug) {
|
|
9460
8719
|
const authMethod2 = options.githubAuthMethod ?? (options.githubToken ? "token" : "skip");
|
|
9461
|
-
if (
|
|
8720
|
+
if ((options.server ?? "local") === "local" && authMethod2 === "skip") {
|
|
9462
8721
|
return runLocalFilesInit(context, options);
|
|
9463
8722
|
}
|
|
9464
8723
|
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);
|
|
9465
8724
|
}
|
|
9466
8725
|
const repo = parseRepoSlug(detectedSlug);
|
|
9467
|
-
const
|
|
9468
|
-
const
|
|
9469
|
-
const remoteUrl = serverKind === "remote" ? (options.remoteUrl ?? selectedRemoteUrl)?.replace(/\/+$/, "") : undefined;
|
|
8726
|
+
const serverKind = options.server ?? "local";
|
|
8727
|
+
const connectionAlias = options.connectionAlias ?? (serverKind === "local" ? "local" : "remote");
|
|
9470
8728
|
if (serverKind === "remote") {
|
|
9471
|
-
if (!remoteUrl)
|
|
9472
|
-
throw new CliError("Missing --remote-url for --server remote.", 1, { hint: "Re-run as `rig init --server remote --remote-url https://your-rig-server
|
|
9473
|
-
upsertGlobalConnection(connectionAlias, { kind: "remote", baseUrl: remoteUrl });
|
|
8729
|
+
if (!options.remoteUrl)
|
|
8730
|
+
throw new CliError("Missing --remote-url for --server remote.", 1, { hint: "Re-run as `rig init --server remote --remote-url https://your-rig-server`." });
|
|
8731
|
+
upsertGlobalConnection(connectionAlias, { kind: "remote", baseUrl: options.remoteUrl });
|
|
9474
8732
|
}
|
|
9475
8733
|
writeRepoConnection(projectRoot, {
|
|
9476
8734
|
selected: connectionAlias,
|
|
@@ -9493,11 +8751,11 @@ async function runControlPlaneInit(context, options) {
|
|
|
9493
8751
|
taskSource: { kind: "github-issues", owner: repo.owner, repo: repo.repo },
|
|
9494
8752
|
useStandardPlugin: true
|
|
9495
8753
|
}), options);
|
|
9496
|
-
|
|
8754
|
+
writeFileSync5(configTsPath, source, "utf-8");
|
|
9497
8755
|
}
|
|
9498
8756
|
ensureRigConfigPackageDependencies(projectRoot);
|
|
9499
8757
|
}
|
|
9500
|
-
|
|
8758
|
+
writeFileSync5(resolve18(projectRoot, ".rig", "state", "project-link.json"), `${JSON.stringify({ repoSlug: repo.slug, connection: connectionAlias, linkedAt: new Date().toISOString() }, null, 2)}
|
|
9501
8759
|
`, "utf8");
|
|
9502
8760
|
const checkout = checkoutForInit(projectRoot, serverKind, options.remoteCheckout);
|
|
9503
8761
|
let uploadedSnapshot = null;
|
|
@@ -9512,7 +8770,7 @@ async function runControlPlaneInit(context, options) {
|
|
|
9512
8770
|
let githubAuth = null;
|
|
9513
8771
|
let deviceAuth = null;
|
|
9514
8772
|
const authMethod = options.githubAuthMethod ?? (options.githubToken ? "token" : "skip");
|
|
9515
|
-
const remoteGhTokenWarning = serverKind === "remote" && authMethod === "gh" ? `This sends a GitHub token from this machine to ${remoteUrl ?? "the remote Rig server"}.` : null;
|
|
8773
|
+
const remoteGhTokenWarning = serverKind === "remote" && authMethod === "gh" ? `This sends a GitHub token from this machine to ${options.remoteUrl ?? "the remote Rig server"}.` : null;
|
|
9516
8774
|
if (remoteGhTokenWarning && !options.yes) {
|
|
9517
8775
|
throw new CliError(`${remoteGhTokenWarning} Re-run with --yes to confirm this explicit token transfer.`, 1);
|
|
9518
8776
|
}
|
|
@@ -9825,64 +9083,14 @@ Usage: rig init`, 1);
|
|
|
9825
9083
|
// packages/cli/src/commands/github.ts
|
|
9826
9084
|
init_runner();
|
|
9827
9085
|
init__server_client();
|
|
9828
|
-
init__connection_state();
|
|
9829
9086
|
init__async_ui();
|
|
9830
9087
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
9831
|
-
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync7 } from "fs";
|
|
9832
|
-
import { dirname as dirname5, resolve as resolve19 } from "path";
|
|
9833
9088
|
function printPayload(context, payload, fallback) {
|
|
9834
9089
|
if (context.outputMode === "json")
|
|
9835
9090
|
console.log(JSON.stringify(payload, null, 2));
|
|
9836
9091
|
else
|
|
9837
9092
|
console.log(fallback);
|
|
9838
9093
|
}
|
|
9839
|
-
function apiSessionTokenFrom2(payload) {
|
|
9840
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
9841
|
-
return null;
|
|
9842
|
-
const token = payload.apiSessionToken;
|
|
9843
|
-
return typeof token === "string" && token.trim() ? token.trim() : null;
|
|
9844
|
-
}
|
|
9845
|
-
function payloadString(payload, key) {
|
|
9846
|
-
const value = payload[key];
|
|
9847
|
-
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
9848
|
-
}
|
|
9849
|
-
function payloadRecord(payload, key) {
|
|
9850
|
-
const value = payload[key];
|
|
9851
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
9852
|
-
}
|
|
9853
|
-
function remoteNamespaceMetadata(result) {
|
|
9854
|
-
const namespace = payloadRecord(result, "userNamespace");
|
|
9855
|
-
return {
|
|
9856
|
-
...payloadString(result, "login") ? { login: payloadString(result, "login") } : {},
|
|
9857
|
-
...payloadString(result, "userId") ? { userId: payloadString(result, "userId") } : {},
|
|
9858
|
-
...namespace && payloadString(namespace, "key") ? { userNamespaceKey: payloadString(namespace, "key") } : {},
|
|
9859
|
-
...namespace && payloadString(namespace, "root") ? { userNamespaceRoot: payloadString(namespace, "root") } : {},
|
|
9860
|
-
...namespace && payloadString(namespace, "checkoutBaseDir") ? { checkoutBaseDir: payloadString(namespace, "checkoutBaseDir") } : {},
|
|
9861
|
-
...namespace && payloadString(namespace, "snapshotBaseDir") ? { snapshotBaseDir: payloadString(namespace, "snapshotBaseDir") } : {}
|
|
9862
|
-
};
|
|
9863
|
-
}
|
|
9864
|
-
function persistRemoteAuthSession(context, source, result, fallbackToken) {
|
|
9865
|
-
const apiSessionToken = apiSessionTokenFrom2(result);
|
|
9866
|
-
setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? fallbackToken, context.projectRoot);
|
|
9867
|
-
if (!apiSessionToken)
|
|
9868
|
-
return;
|
|
9869
|
-
const repo = readRepoConnection(context.projectRoot);
|
|
9870
|
-
const path = resolve19(context.projectRoot, ".rig", "state", "github-auth.json");
|
|
9871
|
-
mkdirSync10(dirname5(path), { recursive: true });
|
|
9872
|
-
writeFileSync7(path, `${JSON.stringify({
|
|
9873
|
-
authenticated: true,
|
|
9874
|
-
source,
|
|
9875
|
-
storedOnServer: true,
|
|
9876
|
-
...repo?.project ? { selectedRepo: repo.project } : {},
|
|
9877
|
-
...remoteNamespaceMetadata(result),
|
|
9878
|
-
apiSessionToken,
|
|
9879
|
-
updatedAt: new Date().toISOString()
|
|
9880
|
-
}, null, 2)}
|
|
9881
|
-
`, "utf8");
|
|
9882
|
-
}
|
|
9883
|
-
function isSignedIn(status) {
|
|
9884
|
-
return status.signedIn === true || status.authenticated === true;
|
|
9885
|
-
}
|
|
9886
9094
|
function readGhToken() {
|
|
9887
9095
|
const result = spawnSync2("gh", ["auth", "token"], { encoding: "utf8" });
|
|
9888
9096
|
if (result.status !== 0) {
|
|
@@ -9904,7 +9112,7 @@ async function executeGithub(context, args) {
|
|
|
9904
9112
|
if (rest.length > 0)
|
|
9905
9113
|
throw new CliError("Usage: rig github auth status", 1);
|
|
9906
9114
|
const status = await withSpinner("Checking GitHub auth on the server\u2026", () => getGitHubAuthStatusViaServer(context), { outputMode: context.outputMode });
|
|
9907
|
-
printPayload(context, status, `GitHub auth: ${
|
|
9115
|
+
printPayload(context, status, `GitHub auth: ${status.authenticated ? "authenticated" : "unauthenticated"}`);
|
|
9908
9116
|
return { ok: true, group: "github", command: "auth status", details: status };
|
|
9909
9117
|
}
|
|
9910
9118
|
case "token": {
|
|
@@ -9914,20 +9122,16 @@ async function executeGithub(context, args) {
|
|
|
9914
9122
|
const token = parsed.value?.trim();
|
|
9915
9123
|
if (!token)
|
|
9916
9124
|
throw new CliError("Missing --token value.", 1, { hint: "Re-run as `rig github auth token --token <token>`." });
|
|
9917
|
-
const
|
|
9918
|
-
|
|
9919
|
-
persistRemoteAuthSession(context, "token", result, token);
|
|
9920
|
-
printPayload(context, result, "GitHub token stored on the selected server.");
|
|
9125
|
+
const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, token), { outputMode: context.outputMode });
|
|
9126
|
+
printPayload(context, result, "GitHub token stored on the selected Rig server.");
|
|
9921
9127
|
return { ok: true, group: "github", command: "auth token", details: result };
|
|
9922
9128
|
}
|
|
9923
9129
|
case "import-gh": {
|
|
9924
9130
|
if (rest.length > 0)
|
|
9925
9131
|
throw new CliError("Usage: rig github auth import-gh", 1);
|
|
9926
9132
|
const importedToken = readGhToken();
|
|
9927
|
-
const
|
|
9928
|
-
|
|
9929
|
-
persistRemoteAuthSession(context, "gh", result, importedToken);
|
|
9930
|
-
printPayload(context, result, "GitHub token imported from gh and stored on the selected server.");
|
|
9133
|
+
const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, importedToken), { outputMode: context.outputMode });
|
|
9134
|
+
printPayload(context, result, "GitHub token imported from gh and stored on the selected Rig server.");
|
|
9931
9135
|
return { ok: true, group: "github", command: "auth import-gh", details: result };
|
|
9932
9136
|
}
|
|
9933
9137
|
default:
|
|
@@ -9957,7 +9161,7 @@ init_runner();
|
|
|
9957
9161
|
init__authority_runs();
|
|
9958
9162
|
init__paths();
|
|
9959
9163
|
import { readFileSync as readFileSync8 } from "fs";
|
|
9960
|
-
import { resolve as
|
|
9164
|
+
import { resolve as resolve19 } from "path";
|
|
9961
9165
|
import {
|
|
9962
9166
|
appendRunJournalEvent,
|
|
9963
9167
|
appendRunLogEntry,
|
|
@@ -9994,7 +9198,7 @@ function touchAuthorityRun(projectRoot, runId) {
|
|
|
9994
9198
|
if (!current) {
|
|
9995
9199
|
return;
|
|
9996
9200
|
}
|
|
9997
|
-
writeJsonFile3(
|
|
9201
|
+
writeJsonFile3(resolve19(resolveAuthorityRunDir(projectRoot, runId), "run.json"), {
|
|
9998
9202
|
...current,
|
|
9999
9203
|
updatedAt: new Date().toISOString()
|
|
10000
9204
|
});
|
|
@@ -10232,7 +9436,7 @@ init_runner();
|
|
|
10232
9436
|
init__server_client();
|
|
10233
9437
|
init__async_ui();
|
|
10234
9438
|
import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
|
|
10235
|
-
import { resolve as
|
|
9439
|
+
import { resolve as resolve20 } from "path";
|
|
10236
9440
|
import {
|
|
10237
9441
|
listAuthorityRuns,
|
|
10238
9442
|
readAuthorityRun as readAuthorityRun3,
|
|
@@ -10276,7 +9480,7 @@ async function executeInspect(context, args) {
|
|
|
10276
9480
|
}
|
|
10277
9481
|
return { ok: true, group: "inspect", command, details: { task: requiredTask, runId: fallback.runId, source: "server", entries } };
|
|
10278
9482
|
}
|
|
10279
|
-
const logsPath =
|
|
9483
|
+
const logsPath = resolve20(resolveAuthorityRunDir2(context.projectRoot, latestRun.runId), "logs.jsonl");
|
|
10280
9484
|
if (!existsSync13(logsPath)) {
|
|
10281
9485
|
throw new CliError(`No logs found for run ${latestRun.runId}.`, 1, { hint: `Try \`rig run show ${latestRun.runId}\` or \`rig run replay ${latestRun.runId}\`.` });
|
|
10282
9486
|
}
|
|
@@ -10364,7 +9568,7 @@ async function executeInspect(context, args) {
|
|
|
10364
9568
|
return { ok: true, group: "inspect", command };
|
|
10365
9569
|
case "audit": {
|
|
10366
9570
|
requireNoExtraArgs(rest, "rig inspect audit");
|
|
10367
|
-
const auditPath =
|
|
9571
|
+
const auditPath = resolve20(resolveHarnessPaths2(context.projectRoot).logsDir, "audit.jsonl");
|
|
10368
9572
|
if (!existsSync13(auditPath)) {
|
|
10369
9573
|
console.log("No audit log found.");
|
|
10370
9574
|
} else {
|
|
@@ -11023,7 +10227,7 @@ import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/co
|
|
|
11023
10227
|
|
|
11024
10228
|
// packages/cli/src/commands/_run-replay.ts
|
|
11025
10229
|
import { existsSync as existsSync14, readdirSync as readdirSync2 } from "fs";
|
|
11026
|
-
import { join as join2, resolve as
|
|
10230
|
+
import { join as join2, resolve as resolve21 } from "path";
|
|
11027
10231
|
import {
|
|
11028
10232
|
readAuthorityRun as readAuthorityRun4,
|
|
11029
10233
|
readJsonlFile as readJsonlFile3,
|
|
@@ -11116,7 +10320,7 @@ function resolveRunSessionFile(record) {
|
|
|
11116
10320
|
const sessionId = text(piSession.sessionId);
|
|
11117
10321
|
if (!cwd || !sessionId)
|
|
11118
10322
|
return null;
|
|
11119
|
-
const sessionDir =
|
|
10323
|
+
const sessionDir = resolve21(cwd, ".rig", "session");
|
|
11120
10324
|
try {
|
|
11121
10325
|
const match = readdirSync2(sessionDir).find((name) => name.endsWith(`_${sessionId}.jsonl`));
|
|
11122
10326
|
return match ? join2(sessionDir, match) : null;
|
|
@@ -11614,9 +10818,6 @@ async function executeRun(context, args) {
|
|
|
11614
10818
|
console.log(`Stop requested: ${runId}`);
|
|
11615
10819
|
return { ok: true, group: "run", command, details: stopped };
|
|
11616
10820
|
}
|
|
11617
|
-
if (isRemoteConnectionSelected(context.projectRoot)) {
|
|
11618
|
-
throw new CliError("Remote run stop requires an explicit run id.", 2, { hint: "Run `rig run list`, then `rig run stop <run-id>`." });
|
|
11619
|
-
}
|
|
11620
10821
|
const result = await runStop(context.projectRoot);
|
|
11621
10822
|
if (result.remaining.length > 0) {
|
|
11622
10823
|
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." });
|
|
@@ -11649,7 +10850,6 @@ init_drone_ui();
|
|
|
11649
10850
|
init_runner();
|
|
11650
10851
|
init__connection_state();
|
|
11651
10852
|
init__cli_format();
|
|
11652
|
-
init__server_client();
|
|
11653
10853
|
function usageName(options) {
|
|
11654
10854
|
return `rig ${options.group}`;
|
|
11655
10855
|
}
|
|
@@ -11669,46 +10869,13 @@ function parseConnection(alias, value, options) {
|
|
|
11669
10869
|
}
|
|
11670
10870
|
return { kind: "remote", baseUrl: parsed.toString().replace(/\/+$/, "") };
|
|
11671
10871
|
}
|
|
11672
|
-
function printJsonOrText(context,
|
|
11673
|
-
if (context.outputMode
|
|
10872
|
+
function printJsonOrText(context, payload, text2) {
|
|
10873
|
+
if (context.outputMode === "json") {
|
|
10874
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
10875
|
+
} else {
|
|
11674
10876
|
console.log(text2);
|
|
11675
10877
|
}
|
|
11676
10878
|
}
|
|
11677
|
-
function formatRemoteProjectLinkText(result) {
|
|
11678
|
-
return formatSuccessCard(result.ok ? "Remote project link ready" : "Remote project link needs repair", [
|
|
11679
|
-
["selected", result.alias ?? "remote"],
|
|
11680
|
-
["target", result.baseUrl ?? "unknown"],
|
|
11681
|
-
["repo", result.repoSlug ?? "owner/repo"],
|
|
11682
|
-
["status", result.status],
|
|
11683
|
-
...result.serverProjectRoot ? [["server root", result.serverProjectRoot]] : [],
|
|
11684
|
-
["next", result.ok ? result.next ?? "rig task list" : result.hint]
|
|
11685
|
-
]);
|
|
11686
|
-
}
|
|
11687
|
-
function parseRepairLinkArgs(rest, usage) {
|
|
11688
|
-
let repoSlug;
|
|
11689
|
-
let mode = "prepare-if-missing";
|
|
11690
|
-
const pending = [...rest];
|
|
11691
|
-
while (pending.length > 0) {
|
|
11692
|
-
const token = pending.shift();
|
|
11693
|
-
if (token === "--repo") {
|
|
11694
|
-
const value = pending.shift()?.trim();
|
|
11695
|
-
if (!value)
|
|
11696
|
-
throw new CliError(`Missing --repo value. Usage: ${usage}`, 1);
|
|
11697
|
-
const normalized = normalizeRepoSlug(value);
|
|
11698
|
-
if (!normalized)
|
|
11699
|
-
throw new CliError(`Invalid --repo value: ${value}`, 1, { hint: "Use the canonical owner/repo slug, e.g. `--repo humanity-org/humanwork`." });
|
|
11700
|
-
repoSlug = normalized;
|
|
11701
|
-
} else if (token === "--backfill-only") {
|
|
11702
|
-
mode = "backfill-only";
|
|
11703
|
-
} else if (token === "--prepare") {
|
|
11704
|
-
mode = "prepare-if-missing";
|
|
11705
|
-
} else {
|
|
11706
|
-
throw new CliError(`Unexpected argument: ${String(token)}
|
|
11707
|
-
Usage: ${usage}`, 1);
|
|
11708
|
-
}
|
|
11709
|
-
}
|
|
11710
|
-
return { repoSlug, mode };
|
|
11711
|
-
}
|
|
11712
10879
|
async function promptForConnectionAlias(context) {
|
|
11713
10880
|
const state = readGlobalConnections();
|
|
11714
10881
|
const repo = readRepoConnection(context.projectRoot);
|
|
@@ -11762,67 +10929,31 @@ async function executeConnectionCommand(context, args, options) {
|
|
|
11762
10929
|
}
|
|
11763
10930
|
if (!alias)
|
|
11764
10931
|
throw new CliError(`Missing alias. Usage: ${usageName(options)} use <alias|local>`, 1);
|
|
11765
|
-
let selectedConnection = { kind: "local", mode: "auto" };
|
|
11766
10932
|
if (alias !== "local") {
|
|
11767
10933
|
const state = readGlobalConnections();
|
|
11768
|
-
|
|
11769
|
-
if (!connection)
|
|
10934
|
+
if (!state.connections[alias])
|
|
11770
10935
|
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>`." });
|
|
11771
|
-
|
|
11772
|
-
}
|
|
11773
|
-
const previousRepo = readRepoConnection(context.projectRoot);
|
|
11774
|
-
const preserveRemoteRoot = Boolean(previousRepo?.serverProjectRoot && previousRepo.selected === alias && selectedConnection.kind === "remote" && previousRepo.serverProjectRootAlias === alias && previousRepo.serverProjectRootBaseUrl === selectedConnection.baseUrl);
|
|
11775
|
-
const repoState = {
|
|
11776
|
-
selected: alias,
|
|
11777
|
-
...previousRepo?.project ? { project: previousRepo.project } : {},
|
|
11778
|
-
linkedAt: new Date().toISOString(),
|
|
11779
|
-
...preserveRemoteRoot ? {
|
|
11780
|
-
serverProjectRoot: previousRepo.serverProjectRoot,
|
|
11781
|
-
serverProjectRootAlias: previousRepo.serverProjectRootAlias,
|
|
11782
|
-
serverProjectRootBaseUrl: previousRepo.serverProjectRootBaseUrl
|
|
11783
|
-
} : {}
|
|
11784
|
-
};
|
|
10936
|
+
}
|
|
10937
|
+
const repoState = { selected: alias, linkedAt: new Date().toISOString() };
|
|
11785
10938
|
writeRepoConnection(context.projectRoot, repoState);
|
|
11786
|
-
|
|
11787
|
-
ok: false,
|
|
11788
|
-
status: "error",
|
|
11789
|
-
message: error instanceof Error ? error.message : String(error),
|
|
11790
|
-
hint: "Run `rig server repair-link` after authenticating the selected remote."
|
|
11791
|
-
})) : null;
|
|
11792
|
-
const latestRepo = readRepoConnection(context.projectRoot);
|
|
11793
|
-
const details = { selected: latestRepo?.selected ?? alias, repo: latestRepo, remoteProjectLink };
|
|
11794
|
-
printJsonOrText(context, details, formatSuccessCard("Rig server selected", [
|
|
10939
|
+
printJsonOrText(context, repoState, formatSuccessCard("Rig server selected", [
|
|
11795
10940
|
["selected", alias],
|
|
11796
10941
|
["scope", "this repo"],
|
|
11797
|
-
|
|
11798
|
-
["next", remoteProjectLink && !remoteProjectLink.ok ? "rig server repair-link" : "rig task list"]
|
|
10942
|
+
["next", "rig task list"]
|
|
11799
10943
|
]));
|
|
11800
|
-
return { ok: true, group: options.group, command: "use", details };
|
|
11801
|
-
}
|
|
11802
|
-
case "repair-link": {
|
|
11803
|
-
const parsed = parseRepairLinkArgs(rest, `${usageName(options)} repair-link [--prepare|--backfill-only] [--repo owner/repo]`);
|
|
11804
|
-
const result = await repairRemoteProjectRootLink(context, parsed);
|
|
11805
|
-
printJsonOrText(context, result, formatRemoteProjectLinkText(result));
|
|
11806
|
-
return { ok: true, group: options.group, command: "repair-link", details: result };
|
|
10944
|
+
return { ok: true, group: options.group, command: "use", details: repoState };
|
|
11807
10945
|
}
|
|
11808
10946
|
case "status": {
|
|
11809
10947
|
requireNoExtraArgs(rest, `${usageName(options)} status`);
|
|
11810
10948
|
const repo = readRepoConnection(context.projectRoot);
|
|
11811
10949
|
const global = readGlobalConnections();
|
|
11812
|
-
const
|
|
11813
|
-
|
|
11814
|
-
status: "error",
|
|
11815
|
-
message: error instanceof Error ? error.message : String(error),
|
|
11816
|
-
hint: "Run `rig server repair-link` after authenticating the selected remote."
|
|
11817
|
-
})) : null;
|
|
11818
|
-
const latestRepo = readRepoConnection(context.projectRoot) ?? repo;
|
|
11819
|
-
const details = { selected: latestRepo?.selected ?? "local", repo: latestRepo, connections: global.connections, remoteProjectLink };
|
|
11820
|
-
printJsonOrText(context, details, formatConnectionStatus(details.selected, global.connections, latestRepo ?? null, remoteProjectLink));
|
|
10950
|
+
const details = { selected: repo?.selected ?? "local", repo, connections: global.connections };
|
|
10951
|
+
printJsonOrText(context, details, formatConnectionStatus(details.selected, global.connections));
|
|
11821
10952
|
return { ok: true, group: options.group, command: "status", details };
|
|
11822
10953
|
}
|
|
11823
10954
|
default:
|
|
11824
10955
|
throw new CliError(`Unknown ${options.group} command: ${String(command)}
|
|
11825
|
-
Usage: ${usageName(options)} <list|add|use|status
|
|
10956
|
+
Usage: ${usageName(options)} <list|add|use|status>`, 1);
|
|
11826
10957
|
}
|
|
11827
10958
|
}
|
|
11828
10959
|
|
|
@@ -11830,7 +10961,7 @@ Usage: ${usageName(options)} <list|add|use|status|repair-link>`, 1);
|
|
|
11830
10961
|
init__server_client();
|
|
11831
10962
|
async function executeServer(context, args, options) {
|
|
11832
10963
|
const [command = "status", ...rest] = args;
|
|
11833
|
-
if (["status", "list", "add", "use"
|
|
10964
|
+
if (["status", "list", "add", "use"].includes(command)) {
|
|
11834
10965
|
return executeConnectionCommand(context, [command, ...rest], { group: "server", interactiveUse: true });
|
|
11835
10966
|
}
|
|
11836
10967
|
switch (command) {
|
|
@@ -12038,8 +11169,8 @@ init_task();
|
|
|
12038
11169
|
|
|
12039
11170
|
// packages/cli/src/commands/task-run-driver.ts
|
|
12040
11171
|
init_runner();
|
|
12041
|
-
import { copyFileSync as copyFileSync3, existsSync as existsSync16, mkdirSync as
|
|
12042
|
-
import { resolve as
|
|
11172
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync16, mkdirSync as mkdirSync10, readFileSync as readFileSync12, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
|
|
11173
|
+
import { resolve as resolve23 } from "path";
|
|
12043
11174
|
import { spawn as spawn2, spawnSync as spawnSync4 } from "child_process";
|
|
12044
11175
|
import { createInterface as createLineInterface } from "readline";
|
|
12045
11176
|
import { loadConfig as loadConfig2 } from "@rig/core/load-config";
|
|
@@ -12138,12 +11269,12 @@ function copyUntrackedDirtyFiles(sourceRoot, targetRoot) {
|
|
|
12138
11269
|
return 0;
|
|
12139
11270
|
let copied = 0;
|
|
12140
11271
|
for (const relativePath of listed.stdout.split("\x00").filter(Boolean)) {
|
|
12141
|
-
const sourcePath =
|
|
12142
|
-
const targetPath =
|
|
11272
|
+
const sourcePath = resolve23(sourceRoot, relativePath);
|
|
11273
|
+
const targetPath = resolve23(targetRoot, relativePath);
|
|
12143
11274
|
try {
|
|
12144
11275
|
if (!statSync2(sourcePath).isFile())
|
|
12145
11276
|
continue;
|
|
12146
|
-
|
|
11277
|
+
mkdirSync10(resolve23(targetPath, ".."), { recursive: true });
|
|
12147
11278
|
copyFileSync3(sourcePath, targetPath);
|
|
12148
11279
|
copied += 1;
|
|
12149
11280
|
} catch {}
|
|
@@ -12182,7 +11313,7 @@ function buildDirtyBaselineHandshakeEnv(input) {
|
|
|
12182
11313
|
return { RIG_BASELINE_MODE: input.baselineMode ?? "head" };
|
|
12183
11314
|
return {
|
|
12184
11315
|
RIG_BASELINE_MODE: "dirty-snapshot",
|
|
12185
|
-
RIG_DIRTY_BASELINE_READY_FILE:
|
|
11316
|
+
RIG_DIRTY_BASELINE_READY_FILE: resolve23(input.projectRoot, ".rig", "runs", input.runId, "dirty-baseline.ready.json")
|
|
12186
11317
|
};
|
|
12187
11318
|
}
|
|
12188
11319
|
function positiveInt(value, fallback) {
|
|
@@ -12287,9 +11418,9 @@ function createCommandRunner(binary) {
|
|
|
12287
11418
|
const stderrChunks = [];
|
|
12288
11419
|
child.stdout.on("data", (chunk) => stdoutChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
|
|
12289
11420
|
child.stderr.on("data", (chunk) => stderrChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
|
|
12290
|
-
return await new Promise((
|
|
12291
|
-
child.once("error", (error) =>
|
|
12292
|
-
child.once("close", (code) =>
|
|
11421
|
+
return await new Promise((resolve24) => {
|
|
11422
|
+
child.once("error", (error) => resolve24({ exitCode: 1, stderr: error.message }));
|
|
11423
|
+
child.once("close", (code) => resolve24({
|
|
12293
11424
|
exitCode: code ?? 1,
|
|
12294
11425
|
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
12295
11426
|
stderr: Buffer.concat(stderrChunks).toString("utf8")
|
|
@@ -12363,7 +11494,7 @@ async function runTaskRunPostValidationLifecycle(input) {
|
|
|
12363
11494
|
config,
|
|
12364
11495
|
sourceTask: input.sourceTask,
|
|
12365
11496
|
uploadedSnapshot: input.uploadedSnapshot,
|
|
12366
|
-
artifactRoot:
|
|
11497
|
+
artifactRoot: resolve23(input.projectRoot, "artifacts", taskId3),
|
|
12367
11498
|
command: ghCommand,
|
|
12368
11499
|
gitCommand,
|
|
12369
11500
|
steerPi,
|
|
@@ -12493,7 +11624,7 @@ function summarizeValidationFailure(projectRoot, taskId3) {
|
|
|
12493
11624
|
return null;
|
|
12494
11625
|
}
|
|
12495
11626
|
for (const artifactDir of resolveTaskArtifactDirs2(projectRoot, taskId3)) {
|
|
12496
|
-
const summary = readJsonFile3(
|
|
11627
|
+
const summary = readJsonFile3(resolve23(artifactDir, "validation-summary.json"), null);
|
|
12497
11628
|
if (!summary || summary.status !== "fail") {
|
|
12498
11629
|
continue;
|
|
12499
11630
|
}
|
|
@@ -12574,9 +11705,9 @@ function readTaskRunAcceptedArtifactState(input) {
|
|
|
12574
11705
|
if (!input.taskId || !input.workspaceDir) {
|
|
12575
11706
|
return { accepted: false, reason: null };
|
|
12576
11707
|
}
|
|
12577
|
-
const artifactDir =
|
|
12578
|
-
const reviewStatusPath =
|
|
12579
|
-
const taskResultPath =
|
|
11708
|
+
const artifactDir = resolve23(input.workspaceDir, "artifacts", input.taskId);
|
|
11709
|
+
const reviewStatusPath = resolve23(artifactDir, "review-status.txt");
|
|
11710
|
+
const taskResultPath = resolve23(artifactDir, "task-result.json");
|
|
12580
11711
|
const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
|
|
12581
11712
|
if (reviewStatus !== "APPROVED") {
|
|
12582
11713
|
return { accepted: false, reason: null };
|
|
@@ -12613,12 +11744,12 @@ function resolveTaskRunRetryContext(input) {
|
|
|
12613
11744
|
if (!input.taskId || !input.workspaceDir) {
|
|
12614
11745
|
return { shouldRetry: false, failureDetail: null, nextPrompt: null };
|
|
12615
11746
|
}
|
|
12616
|
-
const artifactDir =
|
|
12617
|
-
const reviewStatePath =
|
|
12618
|
-
const reviewFeedbackPath =
|
|
12619
|
-
const reviewStatusPath =
|
|
12620
|
-
const failedApproachesPath =
|
|
12621
|
-
const validationSummaryPath =
|
|
11747
|
+
const artifactDir = resolve23(input.workspaceDir, "artifacts", input.taskId);
|
|
11748
|
+
const reviewStatePath = resolve23(artifactDir, "review-state.json");
|
|
11749
|
+
const reviewFeedbackPath = resolve23(artifactDir, "review-feedback.md");
|
|
11750
|
+
const reviewStatusPath = resolve23(artifactDir, "review-status.txt");
|
|
11751
|
+
const failedApproachesPath = resolve23(input.workspaceDir, ".rig", "state", "failed_approaches.md");
|
|
11752
|
+
const validationSummaryPath = resolve23(artifactDir, "validation-summary.json");
|
|
12622
11753
|
const reviewState = readJsonFile3(reviewStatePath, null);
|
|
12623
11754
|
const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
|
|
12624
11755
|
const reviewRejected = isTaskRunReviewRejected(reviewState);
|
|
@@ -13028,15 +12159,15 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
13028
12159
|
const loadedAutomationConfig = await loadTaskRunAutomationConfig(context.projectRoot);
|
|
13029
12160
|
const automationConfig = input.prMode ? { ...loadedAutomationConfig ?? {}, pr: { ...loadedAutomationConfig?.pr ?? {}, mode: input.prMode } } : loadedAutomationConfig;
|
|
13030
12161
|
const planningClassification = classifyPlanningNeed({ config: automationConfig, sourceTask });
|
|
13031
|
-
const planningArtifactPath =
|
|
12162
|
+
const planningArtifactPath = resolve23("artifacts", runtimeTaskId, "implementation-plan.md");
|
|
13032
12163
|
const persistedPlanning = {
|
|
13033
12164
|
...planningClassification,
|
|
13034
12165
|
classifier: input.runtimeAdapter === "pi" ? "pi-rig-structured-policy" : "rig-structured-policy",
|
|
13035
12166
|
artifactPath: planningClassification.planningRequired ? planningArtifactPath : null,
|
|
13036
12167
|
classifiedAt: new Date().toISOString()
|
|
13037
12168
|
};
|
|
13038
|
-
|
|
13039
|
-
|
|
12169
|
+
mkdirSync10(resolve23(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
|
|
12170
|
+
writeFileSync7(resolve23(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
|
|
13040
12171
|
`, "utf8");
|
|
13041
12172
|
patchAuthorityRun(context.projectRoot, input.runId, { planning: persistedPlanning });
|
|
13042
12173
|
prompt = `${prompt}
|
|
@@ -13086,7 +12217,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
13086
12217
|
let verificationStarted = false;
|
|
13087
12218
|
let reviewStarted = false;
|
|
13088
12219
|
let latestRuntimeWorkspace = resumeMode && typeof existingRunRecord?.worktreePath === "string" ? existingRunRecord.worktreePath : null;
|
|
13089
|
-
let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ?
|
|
12220
|
+
let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve23(existingRunRecord.sessionPath, "..") : null;
|
|
13090
12221
|
let latestLogsDir = resumeMode && typeof existingRunRecord?.logRoot === "string" ? existingRunRecord.logRoot : null;
|
|
13091
12222
|
let latestProviderCommand = null;
|
|
13092
12223
|
let latestRuntimeBranch = resumeMode && typeof existingRunRecord?.branch === "string" ? existingRunRecord.branch : null;
|
|
@@ -13172,10 +12303,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
13172
12303
|
setRunStatusOrFail(context.projectRoot, input.runId, "running");
|
|
13173
12304
|
patchAuthorityRun(context.projectRoot, input.runId, {
|
|
13174
12305
|
worktreePath: latestRuntimeWorkspace,
|
|
13175
|
-
artifactRoot: latestRuntimeWorkspace && input.taskId ?
|
|
12306
|
+
artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve23(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
|
|
13176
12307
|
logRoot: latestLogsDir,
|
|
13177
|
-
sessionPath: latestSessionDir ?
|
|
13178
|
-
sessionLogPath: latestLogsDir ?
|
|
12308
|
+
sessionPath: latestSessionDir ? resolve23(latestSessionDir, "session.json") : null,
|
|
12309
|
+
sessionLogPath: latestLogsDir ? resolve23(latestLogsDir, "agent-stdout.log") : null,
|
|
13179
12310
|
branch: runtimeId
|
|
13180
12311
|
});
|
|
13181
12312
|
if (!dirtyBaselineApplied && input.baselineMode === "dirty-snapshot" && latestRuntimeWorkspace) {
|
|
@@ -13183,8 +12314,8 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
13183
12314
|
const dirty = applyDirtyBaselineSnapshot({ sourceRoot: context.projectRoot, targetRoot: latestRuntimeWorkspace });
|
|
13184
12315
|
const readyFile = childEnv.RIG_DIRTY_BASELINE_READY_FILE;
|
|
13185
12316
|
if (readyFile) {
|
|
13186
|
-
|
|
13187
|
-
|
|
12317
|
+
mkdirSync10(resolve23(readyFile, ".."), { recursive: true });
|
|
12318
|
+
writeFileSync7(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
|
|
13188
12319
|
`, "utf8");
|
|
13189
12320
|
}
|
|
13190
12321
|
appendRunLog(context.projectRoot, input.runId, {
|
|
@@ -13580,7 +12711,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
13580
12711
|
let acceptedArtifactObservedAt = null;
|
|
13581
12712
|
let acceptedArtifactPollTimer = null;
|
|
13582
12713
|
let acceptedArtifactKillTimer = null;
|
|
13583
|
-
const attemptExit = await new Promise((
|
|
12714
|
+
const attemptExit = await new Promise((resolve24) => {
|
|
13584
12715
|
let settled = false;
|
|
13585
12716
|
const settle = (result) => {
|
|
13586
12717
|
if (settled)
|
|
@@ -13588,7 +12719,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
|
|
|
13588
12719
|
settled = true;
|
|
13589
12720
|
if (acceptedArtifactPollTimer)
|
|
13590
12721
|
clearInterval(acceptedArtifactPollTimer);
|
|
13591
|
-
|
|
12722
|
+
resolve24(result);
|
|
13592
12723
|
};
|
|
13593
12724
|
const pollAcceptedArtifacts = () => {
|
|
13594
12725
|
const artifactState = readTaskRunAcceptedArtifactState({
|
|
@@ -13791,7 +12922,7 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
13791
12922
|
}
|
|
13792
12923
|
if (planningClassification.planningRequired) {
|
|
13793
12924
|
const planWorkspace = latestRuntimeWorkspace ?? context.projectRoot;
|
|
13794
|
-
const expectedPlanPath =
|
|
12925
|
+
const expectedPlanPath = resolve23(planWorkspace, planningArtifactPath);
|
|
13795
12926
|
if (!existsSync16(expectedPlanPath)) {
|
|
13796
12927
|
const failedAt = new Date().toISOString();
|
|
13797
12928
|
const failureDetail = `Planning was required (${planningClassification.reason}) but ${planningArtifactPath} was not written before implementation completed.`;
|
|
@@ -13961,9 +13092,9 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
13961
13092
|
});
|
|
13962
13093
|
emitServerRunEvent({ type: "log", runId: input.runId, title: "Pi PR feedback fix stderr" });
|
|
13963
13094
|
});
|
|
13964
|
-
const exitCode = await new Promise((
|
|
13965
|
-
child.once("error", () =>
|
|
13966
|
-
child.once("close", (code) =>
|
|
13095
|
+
const exitCode = await new Promise((resolve24) => {
|
|
13096
|
+
child.once("error", () => resolve24(1));
|
|
13097
|
+
child.once("close", (code) => resolve24(code ?? 1));
|
|
13967
13098
|
});
|
|
13968
13099
|
for (const pendingLog of flushPendingClaudeToolUseLogs({
|
|
13969
13100
|
runId: input.runId,
|
|
@@ -14104,8 +13235,8 @@ async function executeTest(context, args) {
|
|
|
14104
13235
|
init_runner();
|
|
14105
13236
|
init__parsers();
|
|
14106
13237
|
init__paths();
|
|
14107
|
-
import { existsSync as existsSync17, mkdirSync as
|
|
14108
|
-
import { resolve as
|
|
13238
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync11, readdirSync as readdirSync3, writeFileSync as writeFileSync8 } from "fs";
|
|
13239
|
+
import { resolve as resolve24 } from "path";
|
|
14109
13240
|
import { createPluginHost } from "@rig/core";
|
|
14110
13241
|
import {
|
|
14111
13242
|
isSupportedBunVersion as isSupportedBunVersion2,
|
|
@@ -14160,12 +13291,12 @@ function runSetupInit(projectRoot) {
|
|
|
14160
13291
|
const stateDir = resolveControlPlaneHostStateDir(projectRoot);
|
|
14161
13292
|
const logsDir = resolveControlPlaneHostLogsDir(projectRoot);
|
|
14162
13293
|
const artifactsDir = resolveControlPlaneArtifactsDir(projectRoot);
|
|
14163
|
-
|
|
14164
|
-
|
|
14165
|
-
|
|
14166
|
-
const failuresPath =
|
|
13294
|
+
mkdirSync11(stateDir, { recursive: true });
|
|
13295
|
+
mkdirSync11(logsDir, { recursive: true });
|
|
13296
|
+
mkdirSync11(artifactsDir, { recursive: true });
|
|
13297
|
+
const failuresPath = resolve24(stateDir, "failed_approaches.md");
|
|
14167
13298
|
if (!existsSync17(failuresPath)) {
|
|
14168
|
-
|
|
13299
|
+
writeFileSync8(failuresPath, `# Failed Approaches
|
|
14169
13300
|
|
|
14170
13301
|
`, "utf-8");
|
|
14171
13302
|
}
|
|
@@ -14182,17 +13313,17 @@ async function runSetupCheck(projectRoot, outputMode = "text") {
|
|
|
14182
13313
|
}
|
|
14183
13314
|
async function runSetupPreflight(projectRoot, outputMode = "text") {
|
|
14184
13315
|
await runSetupCheck(projectRoot, outputMode);
|
|
14185
|
-
const validationRoot =
|
|
13316
|
+
const validationRoot = resolve24(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
|
|
14186
13317
|
if (existsSync17(validationRoot)) {
|
|
14187
13318
|
const validators = readdirSync3(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|
|
14188
13319
|
for (const validator of validators) {
|
|
14189
|
-
const script =
|
|
13320
|
+
const script = resolve24(validationRoot, validator.name, "validate.sh");
|
|
14190
13321
|
if (existsSync17(script)) {
|
|
14191
13322
|
console.log(`OK: validator script ${script}`);
|
|
14192
13323
|
}
|
|
14193
13324
|
}
|
|
14194
13325
|
}
|
|
14195
|
-
const hooksRoot =
|
|
13326
|
+
const hooksRoot = resolve24(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
|
|
14196
13327
|
if (existsSync17(hooksRoot)) {
|
|
14197
13328
|
const hooks = readdirSync3(hooksRoot).filter((name) => name.endsWith(".sh"));
|
|
14198
13329
|
for (const hook of hooks) {
|
|
@@ -14339,7 +13470,7 @@ var PROJECT_REQUIRED_GROUPS = new Set([
|
|
|
14339
13470
|
]);
|
|
14340
13471
|
var RIG_CONFIG_FILENAMES = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
|
|
14341
13472
|
function hasInitializedRigProject(projectRoot) {
|
|
14342
|
-
return RIG_CONFIG_FILENAMES.some((name) => existsSync19(
|
|
13473
|
+
return RIG_CONFIG_FILENAMES.some((name) => existsSync19(resolve25(projectRoot, name))) || existsSync19(resolve25(projectRoot, ".rig"));
|
|
14343
13474
|
}
|
|
14344
13475
|
function requireInitializedRigProject(context, group) {
|
|
14345
13476
|
if (hasInitializedRigProject(context.projectRoot)) {
|
|
@@ -14393,7 +13524,7 @@ function resolveTopLevelLaunchState(context) {
|
|
|
14393
13524
|
let selectedServer = null;
|
|
14394
13525
|
if (projectInitialized) {
|
|
14395
13526
|
try {
|
|
14396
|
-
const statePath =
|
|
13527
|
+
const statePath = resolve25(context.projectRoot, ".rig", "state", "connection.json");
|
|
14397
13528
|
if (existsSync19(statePath)) {
|
|
14398
13529
|
const parsed = JSON.parse(readFileSync13(statePath, "utf-8"));
|
|
14399
13530
|
selectedServer = parsed.remoteUrl || parsed.url || parsed.selected || null;
|
|
@@ -14402,14 +13533,8 @@ function resolveTopLevelLaunchState(context) {
|
|
|
14402
13533
|
}
|
|
14403
13534
|
return { projectInitialized, selectedServer, version: process.env.RIG_CLI_VERSION || readBuildConfig().RIG_CLI_VERSION || undefined };
|
|
14404
13535
|
}
|
|
14405
|
-
function envTruthy(value) {
|
|
14406
|
-
if (!value)
|
|
14407
|
-
return false;
|
|
14408
|
-
const normalized = value.trim().toLowerCase();
|
|
14409
|
-
return normalized !== "0" && normalized !== "false" && normalized !== "no";
|
|
14410
|
-
}
|
|
14411
13536
|
function shouldOpenApp(context) {
|
|
14412
|
-
return context.outputMode === "text" && Boolean(process.stdin.isTTY && process.stdout.isTTY) && process.env.RIG_CLI_PLAIN_HELP !== "1"
|
|
13537
|
+
return context.outputMode === "text" && Boolean(process.stdin.isTTY && process.stdout.isTTY) && process.env.RIG_CLI_PLAIN_HELP !== "1";
|
|
14413
13538
|
}
|
|
14414
13539
|
async function openApp(context, options = {}) {
|
|
14415
13540
|
const { runOperatorBoardLoop: runOperatorBoardLoop2 } = await Promise.resolve().then(() => (init_board(), exports_board));
|
|
@@ -14618,7 +13743,7 @@ var __testOnly = {
|
|
|
14618
13743
|
};
|
|
14619
13744
|
// packages/cli/src/launcher.ts
|
|
14620
13745
|
import { existsSync as existsSync20 } from "fs";
|
|
14621
|
-
import { basename as basename3, resolve as
|
|
13746
|
+
import { basename as basename3, resolve as resolve26 } from "path";
|
|
14622
13747
|
import { loadDotEnvSecrets } from "@rig/runtime/baked-secrets";
|
|
14623
13748
|
import { RIG_DEFINITION_DIRNAME, RIG_STATE_DIRNAME, resolveNearestRigProjectRoot } from "@rig/runtime/layout";
|
|
14624
13749
|
|
|
@@ -14630,9 +13755,7 @@ import {
|
|
|
14630
13755
|
RigInboxInputsOutput,
|
|
14631
13756
|
RigRunListOutput,
|
|
14632
13757
|
RigRunShowOutput,
|
|
14633
|
-
RigServerRepairLinkOutput,
|
|
14634
13758
|
RigServerStatusOutput,
|
|
14635
|
-
RigServerUseOutput,
|
|
14636
13759
|
RigStatsOutput,
|
|
14637
13760
|
RigTaskListOutput,
|
|
14638
13761
|
RigTaskShowOutput
|
|
@@ -14642,9 +13765,7 @@ var CLI_OUTPUT_SCHEMAS = {
|
|
|
14642
13765
|
"task show": RigTaskShowOutput,
|
|
14643
13766
|
"run list": RigRunListOutput,
|
|
14644
13767
|
"run show": RigRunShowOutput,
|
|
14645
|
-
"server use": RigServerUseOutput,
|
|
14646
13768
|
"server status": RigServerStatusOutput,
|
|
14647
|
-
"server repair-link": RigServerRepairLinkOutput,
|
|
14648
13769
|
"inbox approvals": RigInboxApprovalsOutput,
|
|
14649
13770
|
"inbox inputs": RigInboxInputsOutput,
|
|
14650
13771
|
"doctor check": RigDoctorCheckOutput,
|
|
@@ -14686,7 +13807,7 @@ function parsePolicyMode(value) {
|
|
|
14686
13807
|
throw new Error(`Invalid --policy-mode value: ${value}. Use off|observe|enforce.`);
|
|
14687
13808
|
}
|
|
14688
13809
|
function hasRigProjectMarker(candidate) {
|
|
14689
|
-
return existsSync20(
|
|
13810
|
+
return existsSync20(resolve26(candidate, RIG_DEFINITION_DIRNAME)) || existsSync20(resolve26(candidate, RIG_STATE_DIRNAME)) || existsSync20(resolve26(candidate, "rig.config.ts")) || existsSync20(resolve26(candidate, "rig.config.json")) || existsSync20(resolve26(candidate, ".git"));
|
|
14690
13811
|
}
|
|
14691
13812
|
function resolveProjectRoot({
|
|
14692
13813
|
envProjectRoot,
|
|
@@ -14695,19 +13816,19 @@ function resolveProjectRoot({
|
|
|
14695
13816
|
cwd = process.cwd()
|
|
14696
13817
|
}) {
|
|
14697
13818
|
if (envProjectRoot) {
|
|
14698
|
-
return
|
|
13819
|
+
return resolve26(cwd, envProjectRoot);
|
|
14699
13820
|
}
|
|
14700
13821
|
const fallbackImportDir = importDir ?? cwd;
|
|
14701
13822
|
const execName = basename3(execPath).toLowerCase();
|
|
14702
|
-
const execCandidates = execName === "rig" || execName === "rig.exe" ? [
|
|
14703
|
-
const candidates = [cwd, ...execCandidates,
|
|
13823
|
+
const execCandidates = execName === "rig" || execName === "rig.exe" ? [resolve26(execPath, "..", "..")] : [];
|
|
13824
|
+
const candidates = [cwd, ...execCandidates, resolve26(fallbackImportDir, "..")];
|
|
14704
13825
|
for (const candidate of candidates) {
|
|
14705
13826
|
const nearest = resolveNearestRigProjectRoot(candidate);
|
|
14706
13827
|
if (hasRigProjectMarker(nearest)) {
|
|
14707
13828
|
return nearest;
|
|
14708
13829
|
}
|
|
14709
13830
|
}
|
|
14710
|
-
return
|
|
13831
|
+
return resolve26(cwd);
|
|
14711
13832
|
}
|
|
14712
13833
|
function normalizeCliErrorCode(message2, isCliError) {
|
|
14713
13834
|
if (message2.startsWith("Invalid --policy-mode value:")) {
|
|
@@ -14781,7 +13902,7 @@ async function runRigCli(module, options = {}) {
|
|
|
14781
13902
|
runId: context.runId,
|
|
14782
13903
|
outcome,
|
|
14783
13904
|
eventsFile: context.eventBus.getEventsFile(),
|
|
14784
|
-
policyFile:
|
|
13905
|
+
policyFile: resolve26(projectRoot, "rig", "policy", "policy.json"),
|
|
14785
13906
|
policyMode: context.policyMode ?? policyMode ?? module.loadPolicy(projectRoot).mode
|
|
14786
13907
|
}, null, 2));
|
|
14787
13908
|
}
|