@h-rig/cli 0.0.6-alpha.82 → 0.0.6-alpha.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/build-rig-binaries.js +40 -8
- package/dist/bin/rig.js +2798 -1440
- package/dist/src/app/board.js +62 -13
- package/dist/src/app-opentui/adapters/command.d.ts +2 -0
- package/dist/src/app-opentui/adapters/command.js +329 -0
- package/dist/src/app-opentui/adapters/common.js +2 -2
- package/dist/src/app-opentui/adapters/doctor.js +63 -14
- package/dist/src/app-opentui/adapters/fleet.js +84 -20
- package/dist/src/app-opentui/adapters/inbox.js +83 -19
- package/dist/src/app-opentui/adapters/init.js +87 -23
- package/dist/src/app-opentui/adapters/pi-attach.js +96 -34
- package/dist/src/app-opentui/adapters/run-detail.js +83 -19
- package/dist/src/app-opentui/adapters/server.js +100 -23
- package/dist/src/app-opentui/adapters/tasks.d.ts +11 -0
- package/dist/src/app-opentui/adapters/tasks.js +742 -94
- package/dist/src/app-opentui/bootstrap.d.ts +1 -6
- package/dist/src/app-opentui/bootstrap.js +13769 -12368
- package/dist/src/app-opentui/command-pty-host.d.ts +62 -0
- package/dist/src/app-opentui/command-pty-host.js +248 -0
- package/dist/src/app-opentui/events.js +1 -1
- package/dist/src/app-opentui/focus-manager.d.ts +14 -0
- package/dist/src/app-opentui/focus-manager.js +24 -0
- package/dist/src/app-opentui/index.js +3802 -2882
- package/dist/src/app-opentui/intent.js +154 -48
- package/dist/src/app-opentui/keymap.d.ts +20 -0
- package/dist/src/app-opentui/keymap.js +707 -0
- package/dist/src/app-opentui/launch-routing.d.ts +16 -0
- package/dist/src/app-opentui/launch-routing.js +55 -0
- package/dist/src/app-opentui/layout.js +2 -2
- package/dist/src/app-opentui/pi-host-child.js +66 -16
- package/dist/src/app-opentui/pi-pty-host.d.ts +9 -0
- package/dist/src/app-opentui/pi-pty-host.js +9 -11
- package/dist/src/app-opentui/registry.js +3231 -2403
- package/dist/src/app-opentui/render/ascii-fleet.d.ts +15 -0
- package/dist/src/app-opentui/render/ascii-fleet.js +82 -0
- package/dist/src/app-opentui/render/graphics.d.ts +1 -1
- package/dist/src/app-opentui/render/graphics.js +131 -16
- package/dist/src/app-opentui/render/image-visual-layer-worker.js +408 -957
- package/dist/src/app-opentui/render/image-visual-layer.d.ts +18 -10
- package/dist/src/app-opentui/render/image-visual-layer.js +386 -356
- package/dist/src/app-opentui/render/panel-layout.d.ts +38 -0
- package/dist/src/app-opentui/render/panel-layout.js +48 -0
- package/dist/src/app-opentui/render/panels.d.ts +2 -0
- package/dist/src/app-opentui/render/panels.js +62 -29
- package/dist/src/app-opentui/render/preloader.d.ts +10 -0
- package/dist/src/app-opentui/render/preloader.js +163 -0
- package/dist/src/app-opentui/render/scene.d.ts +3 -0
- package/dist/src/app-opentui/render/scene.js +12 -0
- package/dist/src/app-opentui/render/text.js +5 -1
- package/dist/src/app-opentui/render/type-bar.d.ts +2 -1
- package/dist/src/app-opentui/render/type-bar.js +51 -16
- package/dist/src/app-opentui/runtime-resources.d.ts +16 -0
- package/dist/src/app-opentui/runtime-resources.js +62 -0
- package/dist/src/app-opentui/runtime.js +2322 -1513
- package/dist/src/app-opentui/scenes/command.d.ts +3 -0
- package/dist/src/app-opentui/scenes/command.js +103 -0
- package/dist/src/app-opentui/scenes/doctor.d.ts +2 -1
- package/dist/src/app-opentui/scenes/doctor.js +53 -14
- package/dist/src/app-opentui/scenes/error.js +44 -14
- package/dist/src/app-opentui/scenes/fleet.js +40 -21
- package/dist/src/app-opentui/scenes/handoff.js +142 -27
- package/dist/src/app-opentui/scenes/help.js +63 -48
- package/dist/src/app-opentui/scenes/inbox.d.ts +2 -1
- package/dist/src/app-opentui/scenes/inbox.js +64 -17
- package/dist/src/app-opentui/scenes/init.d.ts +2 -1
- package/dist/src/app-opentui/scenes/init.js +62 -21
- package/dist/src/app-opentui/scenes/main.d.ts +2 -1
- package/dist/src/app-opentui/scenes/main.js +80 -24
- package/dist/src/app-opentui/scenes/run-detail.d.ts +2 -1
- package/dist/src/app-opentui/scenes/run-detail.js +39 -25
- package/dist/src/app-opentui/scenes/server.d.ts +2 -1
- package/dist/src/app-opentui/scenes/server.js +71 -20
- package/dist/src/app-opentui/scenes/tasks.js +44 -22
- package/dist/src/app-opentui/state.js +70 -30
- package/dist/src/app-opentui/terminal-capabilities.d.ts +7 -0
- package/dist/src/app-opentui/terminal-capabilities.js +15 -0
- package/dist/src/app-opentui/types.d.ts +10 -2
- package/dist/src/commands/_doctor-checks.js +62 -13
- package/dist/src/commands/_operator-view.js +63 -13
- package/dist/src/commands/_pi-frontend.js +63 -13
- package/dist/src/commands/_preflight.js +64 -14
- package/dist/src/commands/_server-client.js +82 -18
- package/dist/src/commands/_snapshot-upload.js +62 -13
- package/dist/src/commands/connect.js +7 -1
- package/dist/src/commands/doctor.js +62 -13
- package/dist/src/commands/github.js +144 -23
- package/dist/src/commands/inbox.js +62 -13
- package/dist/src/commands/init.js +82 -18
- package/dist/src/commands/inspect.js +62 -13
- package/dist/src/commands/run.js +66 -13
- package/dist/src/commands/server.js +69 -14
- package/dist/src/commands/setup.js +62 -13
- package/dist/src/commands/stats.js +62 -13
- package/dist/src/commands/task-run-driver.js +62 -13
- package/dist/src/commands/task.js +65 -14
- package/dist/src/commands.js +227 -92
- package/dist/src/index.js +234 -99
- package/package.json +8 -9
- package/dist/src/app-opentui/render/image-visual-layer-native-canvas.d.ts +0 -2
- package/dist/src/app-opentui/render/image-visual-layer-native-canvas.js +0 -1484
|
@@ -134,17 +134,21 @@ function cleanToken(value) {
|
|
|
134
134
|
const trimmed = value?.trim();
|
|
135
135
|
return trimmed ? trimmed : null;
|
|
136
136
|
}
|
|
137
|
-
function
|
|
137
|
+
function readRemoteAuthState(projectRoot) {
|
|
138
138
|
const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
|
|
139
139
|
if (!existsSync2(path))
|
|
140
140
|
return null;
|
|
141
141
|
try {
|
|
142
142
|
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
143
|
-
return
|
|
143
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
144
144
|
} catch {
|
|
145
145
|
return null;
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
+
function readPrivateRemoteSessionToken(projectRoot) {
|
|
149
|
+
const parsed = readRemoteAuthState(projectRoot);
|
|
150
|
+
return parsed ? cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined) : null;
|
|
151
|
+
}
|
|
148
152
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
149
153
|
const scopedKey = resolve2(projectRoot);
|
|
150
154
|
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
@@ -155,15 +159,25 @@ function readGitHubBearerTokenForRemote(projectRoot) {
|
|
|
155
159
|
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
156
160
|
}
|
|
157
161
|
function readStoredGitHubAuthToken(projectRoot) {
|
|
158
|
-
const
|
|
159
|
-
|
|
162
|
+
const parsed = readRemoteAuthState(projectRoot);
|
|
163
|
+
return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
|
|
164
|
+
}
|
|
165
|
+
function inferRemoteServerProjectRootFromAuthState(projectRoot) {
|
|
166
|
+
const repo = readRepoConnection(projectRoot);
|
|
167
|
+
const slug = repo?.project?.trim();
|
|
168
|
+
if (!slug || !/^[^/]+\/[^/]+$/.test(slug))
|
|
160
169
|
return null;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
170
|
+
const auth = readRemoteAuthState(projectRoot);
|
|
171
|
+
const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
|
|
172
|
+
const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
|
|
173
|
+
if (Number.isFinite(authUpdatedAt) && Number.isFinite(repoLinkedAt) && authUpdatedAt + 1000 < repoLinkedAt)
|
|
165
174
|
return null;
|
|
166
|
-
|
|
175
|
+
const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
|
|
176
|
+
if (!checkoutBaseDir)
|
|
177
|
+
return null;
|
|
178
|
+
const inferred = `${checkoutBaseDir.replace(/\/+$/, "")}/${slug}`;
|
|
179
|
+
writeRepoServerProjectRoot(projectRoot, inferred);
|
|
180
|
+
return inferred;
|
|
167
181
|
}
|
|
168
182
|
function readLocalConnectionFallbackToken(projectRoot) {
|
|
169
183
|
return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
|
|
@@ -174,7 +188,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
174
188
|
if (selected?.connection.kind === "remote") {
|
|
175
189
|
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
176
190
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
177
|
-
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
191
|
+
const serverProjectRoot = selected.serverProjectRoot ?? inferRemoteServerProjectRootFromAuthState(projectRoot) ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
178
192
|
return {
|
|
179
193
|
baseUrl: selected.connection.baseUrl,
|
|
180
194
|
authToken,
|
|
@@ -203,7 +217,10 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
|
|
|
203
217
|
if (!slug)
|
|
204
218
|
return null;
|
|
205
219
|
try {
|
|
206
|
-
const
|
|
220
|
+
const url = new URL(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`);
|
|
221
|
+
if (authToken && queryAuthFallbackEnabled())
|
|
222
|
+
url.searchParams.set("rt", authToken);
|
|
223
|
+
const response = await fetch(url, {
|
|
207
224
|
headers: mergeHeaders(undefined, authToken)
|
|
208
225
|
});
|
|
209
226
|
if (!response.ok)
|
|
@@ -220,10 +237,23 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
|
|
|
220
237
|
return null;
|
|
221
238
|
}
|
|
222
239
|
}
|
|
240
|
+
function mergeCookie(existing, name, value) {
|
|
241
|
+
const encoded = `${name}=${encodeURIComponent(value)}`;
|
|
242
|
+
if (!existing?.trim())
|
|
243
|
+
return encoded;
|
|
244
|
+
const parts = existing.split(";").map((part) => part.trim()).filter((part) => part && !part.startsWith(`${name}=`));
|
|
245
|
+
return [...parts, encoded].join("; ");
|
|
246
|
+
}
|
|
247
|
+
function queryAuthFallbackEnabled(env = process.env) {
|
|
248
|
+
return env.RIG_ENABLE_QUERY_AUTH_FALLBACK === "1" || env.RIG_QUERY_AUTH_FALLBACK === "1";
|
|
249
|
+
}
|
|
223
250
|
function mergeHeaders(headers, authToken) {
|
|
224
251
|
const merged = new Headers(headers);
|
|
225
252
|
if (authToken) {
|
|
226
|
-
|
|
253
|
+
const bearer = `Bearer ${authToken}`;
|
|
254
|
+
merged.set("authorization", bearer);
|
|
255
|
+
merged.set("x-auth", bearer);
|
|
256
|
+
merged.set("cookie", mergeCookie(merged.get("cookie"), "rig_auth", authToken));
|
|
227
257
|
}
|
|
228
258
|
return merged;
|
|
229
259
|
}
|
|
@@ -284,15 +314,34 @@ async function buildServerFailureContext(projectRoot, server) {
|
|
|
284
314
|
hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
|
|
285
315
|
};
|
|
286
316
|
}
|
|
317
|
+
function isLoopbackRemoteBaseUrl(baseUrl) {
|
|
318
|
+
try {
|
|
319
|
+
const host = new URL(baseUrl).hostname.toLowerCase();
|
|
320
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
|
|
321
|
+
} catch {
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function canUseRemoteWithoutProjectRoot(pathname) {
|
|
326
|
+
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/");
|
|
327
|
+
}
|
|
287
328
|
async function requestServerJson(context, pathname, init = {}) {
|
|
288
329
|
const server = await ensureServerForCli(context.projectRoot);
|
|
330
|
+
const requestUrl = new URL(`${server.baseUrl}${pathname}`);
|
|
331
|
+
if (server.connectionKind === "remote" && !server.serverProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
|
|
332
|
+
const repo = readRepoConnection(context.projectRoot);
|
|
333
|
+
throw new CliError(`Remote server is selected for ${repo?.project ?? "this repo"}, but this checkout has no server-host project root link.`, 1, { hint: "Run `rig init --repair` or `rig init --yes --repo owner/repo --server remote` to repair the remote project link before task/run commands." });
|
|
334
|
+
}
|
|
289
335
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
290
336
|
if (server.serverProjectRoot)
|
|
291
337
|
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
338
|
+
if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
|
|
339
|
+
requestUrl.searchParams.set("rt", server.authToken);
|
|
340
|
+
}
|
|
292
341
|
reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
|
|
293
342
|
let response;
|
|
294
343
|
try {
|
|
295
|
-
response = await fetch(
|
|
344
|
+
response = await fetch(requestUrl, {
|
|
296
345
|
...init,
|
|
297
346
|
headers
|
|
298
347
|
});
|
|
@@ -943,6 +992,7 @@ async function attachRunBundledPiFrontend(context, input) {
|
|
|
943
992
|
let detached = false;
|
|
944
993
|
try {
|
|
945
994
|
await runPiMain([
|
|
995
|
+
"--offline",
|
|
946
996
|
"--no-extensions",
|
|
947
997
|
"--no-skills",
|
|
948
998
|
"--no-prompt-templates",
|
|
@@ -141,17 +141,21 @@ function cleanToken(value) {
|
|
|
141
141
|
const trimmed = value?.trim();
|
|
142
142
|
return trimmed ? trimmed : null;
|
|
143
143
|
}
|
|
144
|
-
function
|
|
144
|
+
function readRemoteAuthState(projectRoot) {
|
|
145
145
|
const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
|
|
146
146
|
if (!existsSync2(path))
|
|
147
147
|
return null;
|
|
148
148
|
try {
|
|
149
149
|
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
150
|
-
return
|
|
150
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
151
151
|
} catch {
|
|
152
152
|
return null;
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
+
function readPrivateRemoteSessionToken(projectRoot) {
|
|
156
|
+
const parsed = readRemoteAuthState(projectRoot);
|
|
157
|
+
return parsed ? cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined) : null;
|
|
158
|
+
}
|
|
155
159
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
156
160
|
const scopedKey = resolve2(projectRoot);
|
|
157
161
|
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
@@ -162,15 +166,25 @@ function readGitHubBearerTokenForRemote(projectRoot) {
|
|
|
162
166
|
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
163
167
|
}
|
|
164
168
|
function readStoredGitHubAuthToken(projectRoot) {
|
|
165
|
-
const
|
|
166
|
-
|
|
169
|
+
const parsed = readRemoteAuthState(projectRoot);
|
|
170
|
+
return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
|
|
171
|
+
}
|
|
172
|
+
function inferRemoteServerProjectRootFromAuthState(projectRoot) {
|
|
173
|
+
const repo = readRepoConnection(projectRoot);
|
|
174
|
+
const slug = repo?.project?.trim();
|
|
175
|
+
if (!slug || !/^[^/]+\/[^/]+$/.test(slug))
|
|
167
176
|
return null;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
177
|
+
const auth = readRemoteAuthState(projectRoot);
|
|
178
|
+
const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
|
|
179
|
+
const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
|
|
180
|
+
if (Number.isFinite(authUpdatedAt) && Number.isFinite(repoLinkedAt) && authUpdatedAt + 1000 < repoLinkedAt)
|
|
172
181
|
return null;
|
|
173
|
-
|
|
182
|
+
const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
|
|
183
|
+
if (!checkoutBaseDir)
|
|
184
|
+
return null;
|
|
185
|
+
const inferred = `${checkoutBaseDir.replace(/\/+$/, "")}/${slug}`;
|
|
186
|
+
writeRepoServerProjectRoot(projectRoot, inferred);
|
|
187
|
+
return inferred;
|
|
174
188
|
}
|
|
175
189
|
function readLocalConnectionFallbackToken(projectRoot) {
|
|
176
190
|
return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
|
|
@@ -181,7 +195,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
181
195
|
if (selected?.connection.kind === "remote") {
|
|
182
196
|
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
183
197
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
184
|
-
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
198
|
+
const serverProjectRoot = selected.serverProjectRoot ?? inferRemoteServerProjectRootFromAuthState(projectRoot) ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
185
199
|
return {
|
|
186
200
|
baseUrl: selected.connection.baseUrl,
|
|
187
201
|
authToken,
|
|
@@ -210,7 +224,10 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
|
|
|
210
224
|
if (!slug)
|
|
211
225
|
return null;
|
|
212
226
|
try {
|
|
213
|
-
const
|
|
227
|
+
const url = new URL(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`);
|
|
228
|
+
if (authToken && queryAuthFallbackEnabled())
|
|
229
|
+
url.searchParams.set("rt", authToken);
|
|
230
|
+
const response = await fetch(url, {
|
|
214
231
|
headers: mergeHeaders(undefined, authToken)
|
|
215
232
|
});
|
|
216
233
|
if (!response.ok)
|
|
@@ -227,10 +244,23 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
|
|
|
227
244
|
return null;
|
|
228
245
|
}
|
|
229
246
|
}
|
|
247
|
+
function mergeCookie(existing, name, value) {
|
|
248
|
+
const encoded = `${name}=${encodeURIComponent(value)}`;
|
|
249
|
+
if (!existing?.trim())
|
|
250
|
+
return encoded;
|
|
251
|
+
const parts = existing.split(";").map((part) => part.trim()).filter((part) => part && !part.startsWith(`${name}=`));
|
|
252
|
+
return [...parts, encoded].join("; ");
|
|
253
|
+
}
|
|
254
|
+
function queryAuthFallbackEnabled(env = process.env) {
|
|
255
|
+
return env.RIG_ENABLE_QUERY_AUTH_FALLBACK === "1" || env.RIG_QUERY_AUTH_FALLBACK === "1";
|
|
256
|
+
}
|
|
230
257
|
function mergeHeaders(headers, authToken) {
|
|
231
258
|
const merged = new Headers(headers);
|
|
232
259
|
if (authToken) {
|
|
233
|
-
|
|
260
|
+
const bearer = `Bearer ${authToken}`;
|
|
261
|
+
merged.set("authorization", bearer);
|
|
262
|
+
merged.set("x-auth", bearer);
|
|
263
|
+
merged.set("cookie", mergeCookie(merged.get("cookie"), "rig_auth", authToken));
|
|
234
264
|
}
|
|
235
265
|
return merged;
|
|
236
266
|
}
|
|
@@ -291,15 +321,34 @@ async function buildServerFailureContext(projectRoot, server) {
|
|
|
291
321
|
hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
|
|
292
322
|
};
|
|
293
323
|
}
|
|
324
|
+
function isLoopbackRemoteBaseUrl(baseUrl) {
|
|
325
|
+
try {
|
|
326
|
+
const host = new URL(baseUrl).hostname.toLowerCase();
|
|
327
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
|
|
328
|
+
} catch {
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
function canUseRemoteWithoutProjectRoot(pathname) {
|
|
333
|
+
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/");
|
|
334
|
+
}
|
|
294
335
|
async function requestServerJson(context, pathname, init = {}) {
|
|
295
336
|
const server = await ensureServerForCli(context.projectRoot);
|
|
337
|
+
const requestUrl = new URL(`${server.baseUrl}${pathname}`);
|
|
338
|
+
if (server.connectionKind === "remote" && !server.serverProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
|
|
339
|
+
const repo = readRepoConnection(context.projectRoot);
|
|
340
|
+
throw new CliError(`Remote server is selected for ${repo?.project ?? "this repo"}, but this checkout has no server-host project root link.`, 1, { hint: "Run `rig init --repair` or `rig init --yes --repo owner/repo --server remote` to repair the remote project link before task/run commands." });
|
|
341
|
+
}
|
|
296
342
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
297
343
|
if (server.serverProjectRoot)
|
|
298
344
|
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
345
|
+
if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
|
|
346
|
+
requestUrl.searchParams.set("rt", server.authToken);
|
|
347
|
+
}
|
|
299
348
|
reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
|
|
300
349
|
let response;
|
|
301
350
|
try {
|
|
302
|
-
response = await fetch(
|
|
351
|
+
response = await fetch(requestUrl, {
|
|
303
352
|
...init,
|
|
304
353
|
headers
|
|
305
354
|
});
|
|
@@ -709,6 +758,7 @@ async function attachRunBundledPiFrontend(context, input) {
|
|
|
709
758
|
let detached = false;
|
|
710
759
|
try {
|
|
711
760
|
await runPiMain([
|
|
761
|
+
"--offline",
|
|
712
762
|
"--no-extensions",
|
|
713
763
|
"--no-skills",
|
|
714
764
|
"--no-prompt-templates",
|
|
@@ -128,17 +128,21 @@ function cleanToken(value) {
|
|
|
128
128
|
const trimmed = value?.trim();
|
|
129
129
|
return trimmed ? trimmed : null;
|
|
130
130
|
}
|
|
131
|
-
function
|
|
131
|
+
function readRemoteAuthState(projectRoot) {
|
|
132
132
|
const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
|
|
133
133
|
if (!existsSync2(path))
|
|
134
134
|
return null;
|
|
135
135
|
try {
|
|
136
136
|
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
137
|
-
return
|
|
137
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
138
138
|
} catch {
|
|
139
139
|
return null;
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
+
function readPrivateRemoteSessionToken(projectRoot) {
|
|
143
|
+
const parsed = readRemoteAuthState(projectRoot);
|
|
144
|
+
return parsed ? cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined) : null;
|
|
145
|
+
}
|
|
142
146
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
143
147
|
const scopedKey = resolve2(projectRoot);
|
|
144
148
|
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
@@ -149,15 +153,25 @@ function readGitHubBearerTokenForRemote(projectRoot) {
|
|
|
149
153
|
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
150
154
|
}
|
|
151
155
|
function readStoredGitHubAuthToken(projectRoot) {
|
|
152
|
-
const
|
|
153
|
-
|
|
156
|
+
const parsed = readRemoteAuthState(projectRoot);
|
|
157
|
+
return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
|
|
158
|
+
}
|
|
159
|
+
function inferRemoteServerProjectRootFromAuthState(projectRoot) {
|
|
160
|
+
const repo = readRepoConnection(projectRoot);
|
|
161
|
+
const slug = repo?.project?.trim();
|
|
162
|
+
if (!slug || !/^[^/]+\/[^/]+$/.test(slug))
|
|
154
163
|
return null;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
164
|
+
const auth = readRemoteAuthState(projectRoot);
|
|
165
|
+
const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
|
|
166
|
+
const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
|
|
167
|
+
if (Number.isFinite(authUpdatedAt) && Number.isFinite(repoLinkedAt) && authUpdatedAt + 1000 < repoLinkedAt)
|
|
159
168
|
return null;
|
|
160
|
-
|
|
169
|
+
const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
|
|
170
|
+
if (!checkoutBaseDir)
|
|
171
|
+
return null;
|
|
172
|
+
const inferred = `${checkoutBaseDir.replace(/\/+$/, "")}/${slug}`;
|
|
173
|
+
writeRepoServerProjectRoot(projectRoot, inferred);
|
|
174
|
+
return inferred;
|
|
161
175
|
}
|
|
162
176
|
function readLocalConnectionFallbackToken(projectRoot) {
|
|
163
177
|
return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
|
|
@@ -168,7 +182,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
168
182
|
if (selected?.connection.kind === "remote") {
|
|
169
183
|
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
170
184
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
171
|
-
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
185
|
+
const serverProjectRoot = selected.serverProjectRoot ?? inferRemoteServerProjectRootFromAuthState(projectRoot) ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
172
186
|
return {
|
|
173
187
|
baseUrl: selected.connection.baseUrl,
|
|
174
188
|
authToken,
|
|
@@ -197,7 +211,10 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
|
|
|
197
211
|
if (!slug)
|
|
198
212
|
return null;
|
|
199
213
|
try {
|
|
200
|
-
const
|
|
214
|
+
const url = new URL(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`);
|
|
215
|
+
if (authToken && queryAuthFallbackEnabled())
|
|
216
|
+
url.searchParams.set("rt", authToken);
|
|
217
|
+
const response = await fetch(url, {
|
|
201
218
|
headers: mergeHeaders(undefined, authToken)
|
|
202
219
|
});
|
|
203
220
|
if (!response.ok)
|
|
@@ -214,10 +231,23 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
|
|
|
214
231
|
return null;
|
|
215
232
|
}
|
|
216
233
|
}
|
|
234
|
+
function mergeCookie(existing, name, value) {
|
|
235
|
+
const encoded = `${name}=${encodeURIComponent(value)}`;
|
|
236
|
+
if (!existing?.trim())
|
|
237
|
+
return encoded;
|
|
238
|
+
const parts = existing.split(";").map((part) => part.trim()).filter((part) => part && !part.startsWith(`${name}=`));
|
|
239
|
+
return [...parts, encoded].join("; ");
|
|
240
|
+
}
|
|
241
|
+
function queryAuthFallbackEnabled(env = process.env) {
|
|
242
|
+
return env.RIG_ENABLE_QUERY_AUTH_FALLBACK === "1" || env.RIG_QUERY_AUTH_FALLBACK === "1";
|
|
243
|
+
}
|
|
217
244
|
function mergeHeaders(headers, authToken) {
|
|
218
245
|
const merged = new Headers(headers);
|
|
219
246
|
if (authToken) {
|
|
220
|
-
|
|
247
|
+
const bearer = `Bearer ${authToken}`;
|
|
248
|
+
merged.set("authorization", bearer);
|
|
249
|
+
merged.set("x-auth", bearer);
|
|
250
|
+
merged.set("cookie", mergeCookie(merged.get("cookie"), "rig_auth", authToken));
|
|
221
251
|
}
|
|
222
252
|
return merged;
|
|
223
253
|
}
|
|
@@ -278,15 +308,34 @@ async function buildServerFailureContext(projectRoot, server) {
|
|
|
278
308
|
hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
|
|
279
309
|
};
|
|
280
310
|
}
|
|
311
|
+
function isLoopbackRemoteBaseUrl(baseUrl) {
|
|
312
|
+
try {
|
|
313
|
+
const host = new URL(baseUrl).hostname.toLowerCase();
|
|
314
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
|
|
315
|
+
} catch {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
function canUseRemoteWithoutProjectRoot(pathname) {
|
|
320
|
+
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/");
|
|
321
|
+
}
|
|
281
322
|
async function requestServerJson(context, pathname, init = {}) {
|
|
282
323
|
const server = await ensureServerForCli(context.projectRoot);
|
|
324
|
+
const requestUrl = new URL(`${server.baseUrl}${pathname}`);
|
|
325
|
+
if (server.connectionKind === "remote" && !server.serverProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
|
|
326
|
+
const repo = readRepoConnection(context.projectRoot);
|
|
327
|
+
throw new CliError(`Remote server is selected for ${repo?.project ?? "this repo"}, but this checkout has no server-host project root link.`, 1, { hint: "Run `rig init --repair` or `rig init --yes --repo owner/repo --server remote` to repair the remote project link before task/run commands." });
|
|
328
|
+
}
|
|
283
329
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
284
330
|
if (server.serverProjectRoot)
|
|
285
331
|
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
332
|
+
if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
|
|
333
|
+
requestUrl.searchParams.set("rt", server.authToken);
|
|
334
|
+
}
|
|
286
335
|
reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
|
|
287
336
|
let response;
|
|
288
337
|
try {
|
|
289
|
-
response = await fetch(
|
|
338
|
+
response = await fetch(requestUrl, {
|
|
290
339
|
...init,
|
|
291
340
|
headers
|
|
292
341
|
});
|
|
@@ -437,7 +486,8 @@ async function runFastTaskRunPreflight(context, options = {}) {
|
|
|
437
486
|
}
|
|
438
487
|
}
|
|
439
488
|
const repo = readRepoConnection(context.projectRoot);
|
|
440
|
-
|
|
489
|
+
const remoteWithoutProjectLink = selectedServer?.connectionKind === "remote" && !repo?.project;
|
|
490
|
+
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 init --repair` or `rig init --yes --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>`."));
|
|
441
491
|
try {
|
|
442
492
|
const auth = await request("/api/github/auth/status");
|
|
443
493
|
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>`."));
|
|
@@ -138,17 +138,21 @@ function setGitHubBearerTokenForCurrentProcess(token, projectRoot) {
|
|
|
138
138
|
const scopedKey = resolve2(projectRoot ?? process.cwd());
|
|
139
139
|
scopedGitHubBearerTokens.set(scopedKey, cleanToken(token ?? undefined));
|
|
140
140
|
}
|
|
141
|
-
function
|
|
141
|
+
function readRemoteAuthState(projectRoot) {
|
|
142
142
|
const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
|
|
143
143
|
if (!existsSync2(path))
|
|
144
144
|
return null;
|
|
145
145
|
try {
|
|
146
146
|
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
147
|
-
return
|
|
147
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
148
148
|
} catch {
|
|
149
149
|
return null;
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
|
+
function readPrivateRemoteSessionToken(projectRoot) {
|
|
153
|
+
const parsed = readRemoteAuthState(projectRoot);
|
|
154
|
+
return parsed ? cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined) : null;
|
|
155
|
+
}
|
|
152
156
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
153
157
|
const scopedKey = resolve2(projectRoot);
|
|
154
158
|
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
@@ -159,15 +163,25 @@ function readGitHubBearerTokenForRemote(projectRoot) {
|
|
|
159
163
|
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
160
164
|
}
|
|
161
165
|
function readStoredGitHubAuthToken(projectRoot) {
|
|
162
|
-
const
|
|
163
|
-
|
|
166
|
+
const parsed = readRemoteAuthState(projectRoot);
|
|
167
|
+
return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
|
|
168
|
+
}
|
|
169
|
+
function inferRemoteServerProjectRootFromAuthState(projectRoot) {
|
|
170
|
+
const repo = readRepoConnection(projectRoot);
|
|
171
|
+
const slug = repo?.project?.trim();
|
|
172
|
+
if (!slug || !/^[^/]+\/[^/]+$/.test(slug))
|
|
164
173
|
return null;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
174
|
+
const auth = readRemoteAuthState(projectRoot);
|
|
175
|
+
const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
|
|
176
|
+
const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
|
|
177
|
+
if (Number.isFinite(authUpdatedAt) && Number.isFinite(repoLinkedAt) && authUpdatedAt + 1000 < repoLinkedAt)
|
|
169
178
|
return null;
|
|
170
|
-
|
|
179
|
+
const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
|
|
180
|
+
if (!checkoutBaseDir)
|
|
181
|
+
return null;
|
|
182
|
+
const inferred = `${checkoutBaseDir.replace(/\/+$/, "")}/${slug}`;
|
|
183
|
+
writeRepoServerProjectRoot(projectRoot, inferred);
|
|
184
|
+
return inferred;
|
|
171
185
|
}
|
|
172
186
|
function readLocalConnectionFallbackToken(projectRoot) {
|
|
173
187
|
return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
|
|
@@ -178,7 +192,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
178
192
|
if (selected?.connection.kind === "remote") {
|
|
179
193
|
reportServerPhase(`Connecting to ${selected.alias}\u2026`);
|
|
180
194
|
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
181
|
-
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
195
|
+
const serverProjectRoot = selected.serverProjectRoot ?? inferRemoteServerProjectRootFromAuthState(projectRoot) ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
182
196
|
return {
|
|
183
197
|
baseUrl: selected.connection.baseUrl,
|
|
184
198
|
authToken,
|
|
@@ -207,7 +221,10 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
|
|
|
207
221
|
if (!slug)
|
|
208
222
|
return null;
|
|
209
223
|
try {
|
|
210
|
-
const
|
|
224
|
+
const url = new URL(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`);
|
|
225
|
+
if (authToken && queryAuthFallbackEnabled())
|
|
226
|
+
url.searchParams.set("rt", authToken);
|
|
227
|
+
const response = await fetch(url, {
|
|
211
228
|
headers: mergeHeaders(undefined, authToken)
|
|
212
229
|
});
|
|
213
230
|
if (!response.ok)
|
|
@@ -234,10 +251,23 @@ function appendTaskFilterParams(url, filters) {
|
|
|
234
251
|
if (filters.limit !== undefined)
|
|
235
252
|
url.searchParams.set("limit", String(filters.limit));
|
|
236
253
|
}
|
|
254
|
+
function mergeCookie(existing, name, value) {
|
|
255
|
+
const encoded = `${name}=${encodeURIComponent(value)}`;
|
|
256
|
+
if (!existing?.trim())
|
|
257
|
+
return encoded;
|
|
258
|
+
const parts = existing.split(";").map((part) => part.trim()).filter((part) => part && !part.startsWith(`${name}=`));
|
|
259
|
+
return [...parts, encoded].join("; ");
|
|
260
|
+
}
|
|
261
|
+
function queryAuthFallbackEnabled(env = process.env) {
|
|
262
|
+
return env.RIG_ENABLE_QUERY_AUTH_FALLBACK === "1" || env.RIG_QUERY_AUTH_FALLBACK === "1";
|
|
263
|
+
}
|
|
237
264
|
function mergeHeaders(headers, authToken) {
|
|
238
265
|
const merged = new Headers(headers);
|
|
239
266
|
if (authToken) {
|
|
240
|
-
|
|
267
|
+
const bearer = `Bearer ${authToken}`;
|
|
268
|
+
merged.set("authorization", bearer);
|
|
269
|
+
merged.set("x-auth", bearer);
|
|
270
|
+
merged.set("cookie", mergeCookie(merged.get("cookie"), "rig_auth", authToken));
|
|
241
271
|
}
|
|
242
272
|
return merged;
|
|
243
273
|
}
|
|
@@ -298,15 +328,34 @@ async function buildServerFailureContext(projectRoot, server) {
|
|
|
298
328
|
hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
|
|
299
329
|
};
|
|
300
330
|
}
|
|
331
|
+
function isLoopbackRemoteBaseUrl(baseUrl) {
|
|
332
|
+
try {
|
|
333
|
+
const host = new URL(baseUrl).hostname.toLowerCase();
|
|
334
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
|
|
335
|
+
} catch {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function canUseRemoteWithoutProjectRoot(pathname) {
|
|
340
|
+
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/");
|
|
341
|
+
}
|
|
301
342
|
async function requestServerJson(context, pathname, init = {}) {
|
|
302
343
|
const server = await ensureServerForCli(context.projectRoot);
|
|
344
|
+
const requestUrl = new URL(`${server.baseUrl}${pathname}`);
|
|
345
|
+
if (server.connectionKind === "remote" && !server.serverProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
|
|
346
|
+
const repo = readRepoConnection(context.projectRoot);
|
|
347
|
+
throw new CliError(`Remote server is selected for ${repo?.project ?? "this repo"}, but this checkout has no server-host project root link.`, 1, { hint: "Run `rig init --repair` or `rig init --yes --repo owner/repo --server remote` to repair the remote project link before task/run commands." });
|
|
348
|
+
}
|
|
303
349
|
const headers = mergeHeaders(init.headers, server.authToken);
|
|
304
350
|
if (server.serverProjectRoot)
|
|
305
351
|
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
352
|
+
if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
|
|
353
|
+
requestUrl.searchParams.set("rt", server.authToken);
|
|
354
|
+
}
|
|
306
355
|
reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
|
|
307
356
|
let response;
|
|
308
357
|
try {
|
|
309
|
-
response = await fetch(
|
|
358
|
+
response = await fetch(requestUrl, {
|
|
310
359
|
...init,
|
|
311
360
|
headers
|
|
312
361
|
});
|
|
@@ -368,11 +417,26 @@ async function getGitHubAuthStatusViaServer(context) {
|
|
|
368
417
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
369
418
|
}
|
|
370
419
|
async function postGitHubTokenViaServer(context, token, options = {}) {
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
420
|
+
const server = await ensureServerForCli(context.projectRoot);
|
|
421
|
+
const requestUrl = new URL(`${server.baseUrl}/api/github/auth/token`);
|
|
422
|
+
reportServerPhase("POST /api/github/auth/token\u2026");
|
|
423
|
+
let response;
|
|
424
|
+
try {
|
|
425
|
+
response = await fetch(requestUrl, {
|
|
426
|
+
method: "POST",
|
|
427
|
+
headers: { "content-type": "application/json" },
|
|
428
|
+
body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot ?? server.serverProjectRoot ?? undefined })
|
|
429
|
+
});
|
|
430
|
+
} catch (error) {
|
|
431
|
+
const failure = await buildServerFailureContext(context.projectRoot, server);
|
|
432
|
+
throw new CliError(`Rig server auth bootstrap failed: ${error instanceof Error ? error.message : String(error)}
|
|
433
|
+
${failure.contextLine}`, 1, { hint: failure.hint });
|
|
434
|
+
}
|
|
435
|
+
const payload = await response.json().catch(() => null);
|
|
436
|
+
if (!response.ok) {
|
|
437
|
+
const detail = payload && typeof payload === "object" && !Array.isArray(payload) ? String(payload.error ?? JSON.stringify(payload)) : `HTTP ${response.status}`;
|
|
438
|
+
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`." });
|
|
439
|
+
}
|
|
376
440
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
377
441
|
}
|
|
378
442
|
async function prepareRemoteCheckoutViaServer(context, input) {
|