@h-rig/cli 0.0.6-alpha.1 → 0.0.6-alpha.11

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.
@@ -67,6 +67,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
67
67
  const runtimeAdapter = normalizeRuntimeAdapter(input.runtimeAdapter ?? existing?.runtimeAdapter ?? "claude-code");
68
68
  const title = resolveTaskTitleForAuthorityRun(projectRoot, input.taskId) ?? input.taskId;
69
69
  const next = {
70
+ ...existing ?? {},
70
71
  runId: input.runId,
71
72
  projectRoot,
72
73
  workspaceId: existing?.workspaceId ?? RIG_WORKSPACE_ID,
@@ -2,8 +2,8 @@
2
2
  var __require = import.meta.require;
3
3
 
4
4
  // packages/cli/src/commands/_doctor-checks.ts
5
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
6
- import { resolve as resolve3 } from "path";
5
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
6
+ import { resolve as resolve4 } from "path";
7
7
 
8
8
  // packages/cli/src/runner.ts
9
9
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
@@ -101,15 +101,33 @@ function resolveSelectedConnection(projectRoot, options = {}) {
101
101
 
102
102
  // packages/cli/src/commands/_server-client.ts
103
103
  import { spawnSync } from "child_process";
104
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
105
+ import { resolve as resolve2 } from "path";
104
106
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
105
107
  var cachedGitHubBearerToken;
106
108
  function cleanToken(value) {
107
109
  const trimmed = value?.trim();
108
110
  return trimmed ? trimmed : null;
109
111
  }
110
- function readGitHubBearerTokenForRemote() {
112
+ function readPrivateRemoteSessionToken(projectRoot) {
113
+ const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
114
+ if (!existsSync2(path))
115
+ return null;
116
+ try {
117
+ const parsed = JSON.parse(readFileSync2(path, "utf8"));
118
+ return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
119
+ } catch {
120
+ return null;
121
+ }
122
+ }
123
+ function readGitHubBearerTokenForRemote(projectRoot) {
111
124
  if (cachedGitHubBearerToken !== undefined)
112
125
  return cachedGitHubBearerToken;
126
+ const privateSession = readPrivateRemoteSessionToken(projectRoot);
127
+ if (privateSession) {
128
+ cachedGitHubBearerToken = privateSession;
129
+ return cachedGitHubBearerToken;
130
+ }
113
131
  const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
114
132
  if (envToken) {
115
133
  cachedGitHubBearerToken = envToken;
@@ -129,7 +147,7 @@ async function ensureServerForCli(projectRoot) {
129
147
  if (selected?.connection.kind === "remote") {
130
148
  return {
131
149
  baseUrl: selected.connection.baseUrl,
132
- authToken: readGitHubBearerTokenForRemote(),
150
+ authToken: readGitHubBearerTokenForRemote(projectRoot),
133
151
  connectionKind: "remote"
134
152
  };
135
153
  }
@@ -201,9 +219,9 @@ async function loadRigConfigOrNull(projectRoot) {
201
219
  }
202
220
 
203
221
  // packages/cli/src/commands/_pi-install.ts
204
- import { existsSync as existsSync2, readFileSync as readFileSync2, rmSync } from "fs";
222
+ import { existsSync as existsSync3, readFileSync as readFileSync3, rmSync } from "fs";
205
223
  import { homedir as homedir2 } from "os";
206
- import { resolve as resolve2 } from "path";
224
+ import { resolve as resolve3 } from "path";
207
225
  var PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
208
226
  async function defaultCommandRunner(command, options = {}) {
209
227
  const proc = Bun.spawn(command, { cwd: options.cwd, stdout: "pipe", stderr: "pipe" });
@@ -215,7 +233,7 @@ async function defaultCommandRunner(command, options = {}) {
215
233
  return { exitCode, stdout, stderr };
216
234
  }
217
235
  function resolvePiRigExtensionPath(homeDir) {
218
- return resolve2(homeDir, ".pi", "agent", "extensions", "pi-rig");
236
+ return resolve3(homeDir, ".pi", "agent", "extensions", "pi-rig");
219
237
  }
220
238
  function resolvePiHomeDir(inputHomeDir) {
221
239
  return inputHomeDir ?? process.env.RIG_PI_HOME_DIR?.trim() ?? homedir2();
@@ -243,13 +261,13 @@ async function checkPiRigInstall(input = {}) {
243
261
  piRig: { ok: true, label: "pi-rig global extension", detail: extensionPath }
244
262
  };
245
263
  }
246
- const exists = input.exists ?? existsSync2;
264
+ const exists = input.exists ?? existsSync3;
247
265
  const runner = input.commandRunner ?? defaultCommandRunner;
248
266
  const piResult = await safeRun(runner, ["pi", "--version"]);
249
267
  const piListResult = piResult.exitCode === 0 ? await safeRun(runner, ["pi", "list"]) : { exitCode: 1, stdout: "", stderr: "" };
250
268
  const listedPiRig = piListResult.exitCode === 0 && piListContainsPiRig(`${piListResult.stdout}
251
269
  ${piListResult.stderr}`);
252
- const legacyBridge = exists(resolve2(extensionPath, "index.ts"));
270
+ const legacyBridge = exists(resolve3(extensionPath, "index.ts"));
253
271
  const hasPiRig = listedPiRig;
254
272
  return {
255
273
  extensionPath,
@@ -311,11 +329,11 @@ function repoSlugFromConfig(config) {
311
329
  function loadFallbackConfig(projectRoot) {
312
330
  const candidates = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
313
331
  for (const name of candidates) {
314
- const path = resolve3(projectRoot, name);
315
- if (!existsSync3(path))
332
+ const path = resolve4(projectRoot, name);
333
+ if (!existsSync4(path))
316
334
  continue;
317
335
  try {
318
- const source = readFileSync3(path, "utf8");
336
+ const source = readFileSync4(path, "utf8");
319
337
  if (name.endsWith(".json"))
320
338
  return JSON.parse(source);
321
339
  const owner = source.match(/owner\s*:\s*["']([^"']+)["']/)?.[1];
@@ -394,7 +412,7 @@ async function runRigDoctorChecks(options) {
394
412
  checks.push(check("bun", `bun >= ${MIN_SUPPORTED_BUN_VERSION}`, isSupportedBunVersion(bunVersion) ? "pass" : "fail", `found ${bunVersion}`, `Install Bun ${MIN_SUPPORTED_BUN_VERSION} or newer.`), check("git", "git", which("git") ? "pass" : "fail", which("git") ?? undefined, "Install git and ensure it is on PATH."), check("jq", "jq", which("jq") ? "pass" : "warn", which("jq") ?? undefined, "Install jq (for example `brew install jq`)."));
395
413
  const loadedConfig = await loadConfig(projectRoot).catch(() => null);
396
414
  const config = loadedConfig ?? loadFallbackConfig(projectRoot);
397
- const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync3(resolve3(projectRoot, name)));
415
+ const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync4(resolve4(projectRoot, name)));
398
416
  checks.push(config ? check("config", "rig.config loadable", "pass") : check("config", "rig.config loadable", hasConfigFile ? "fail" : "fail", hasConfigFile ? "config file exists but failed to load" : "missing rig.config.ts/json", "Run `rig init` or fix the config error."));
399
417
  const taskSourceKind = config?.taskSource?.kind;
400
418
  checks.push(taskSourceKind ? check("task-source", "task source configured", "pass", taskSourceKind) : check("task-source", "task source configured", "fail", "missing taskSource", "Configure taskSource in rig.config.ts."));
@@ -4,6 +4,8 @@ import { createInterface } from "readline";
4
4
 
5
5
  // packages/cli/src/commands/_server-client.ts
6
6
  import { spawnSync } from "child_process";
7
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
8
+ import { resolve as resolve2 } from "path";
7
9
 
8
10
  // packages/cli/src/runner.ts
9
11
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
@@ -105,9 +107,25 @@ function cleanToken(value) {
105
107
  const trimmed = value?.trim();
106
108
  return trimmed ? trimmed : null;
107
109
  }
108
- function readGitHubBearerTokenForRemote() {
110
+ function readPrivateRemoteSessionToken(projectRoot) {
111
+ const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
112
+ if (!existsSync2(path))
113
+ return null;
114
+ try {
115
+ const parsed = JSON.parse(readFileSync2(path, "utf8"));
116
+ return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
117
+ } catch {
118
+ return null;
119
+ }
120
+ }
121
+ function readGitHubBearerTokenForRemote(projectRoot) {
109
122
  if (cachedGitHubBearerToken !== undefined)
110
123
  return cachedGitHubBearerToken;
124
+ const privateSession = readPrivateRemoteSessionToken(projectRoot);
125
+ if (privateSession) {
126
+ cachedGitHubBearerToken = privateSession;
127
+ return cachedGitHubBearerToken;
128
+ }
111
129
  const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
112
130
  if (envToken) {
113
131
  cachedGitHubBearerToken = envToken;
@@ -127,7 +145,7 @@ async function ensureServerForCli(projectRoot) {
127
145
  if (selected?.connection.kind === "remote") {
128
146
  return {
129
147
  baseUrl: selected.connection.baseUrl,
130
- authToken: readGitHubBearerTokenForRemote(),
148
+ authToken: readGitHubBearerTokenForRemote(projectRoot),
131
149
  connectionKind: "remote"
132
150
  };
133
151
  }
@@ -95,15 +95,33 @@ function resolveSelectedConnection(projectRoot, options = {}) {
95
95
 
96
96
  // packages/cli/src/commands/_server-client.ts
97
97
  import { spawnSync } from "child_process";
98
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
99
+ import { resolve as resolve2 } from "path";
98
100
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
99
101
  var cachedGitHubBearerToken;
100
102
  function cleanToken(value) {
101
103
  const trimmed = value?.trim();
102
104
  return trimmed ? trimmed : null;
103
105
  }
104
- function readGitHubBearerTokenForRemote() {
106
+ function readPrivateRemoteSessionToken(projectRoot) {
107
+ const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
108
+ if (!existsSync2(path))
109
+ return null;
110
+ try {
111
+ const parsed = JSON.parse(readFileSync2(path, "utf8"));
112
+ return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
113
+ } catch {
114
+ return null;
115
+ }
116
+ }
117
+ function readGitHubBearerTokenForRemote(projectRoot) {
105
118
  if (cachedGitHubBearerToken !== undefined)
106
119
  return cachedGitHubBearerToken;
120
+ const privateSession = readPrivateRemoteSessionToken(projectRoot);
121
+ if (privateSession) {
122
+ cachedGitHubBearerToken = privateSession;
123
+ return cachedGitHubBearerToken;
124
+ }
107
125
  const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
108
126
  if (envToken) {
109
127
  cachedGitHubBearerToken = envToken;
@@ -123,7 +141,7 @@ async function ensureServerForCli(projectRoot) {
123
141
  if (selected?.connection.kind === "remote") {
124
142
  return {
125
143
  baseUrl: selected.connection.baseUrl,
126
- authToken: readGitHubBearerTokenForRemote(),
144
+ authToken: readGitHubBearerTokenForRemote(projectRoot),
127
145
  connectionKind: "remote"
128
146
  };
129
147
  }
@@ -185,9 +203,9 @@ async function requestServerJson(context, pathname, init = {}) {
185
203
  }
186
204
 
187
205
  // packages/cli/src/commands/_pi-install.ts
188
- import { existsSync as existsSync2, readFileSync as readFileSync2, rmSync } from "fs";
206
+ import { existsSync as existsSync3, readFileSync as readFileSync3, rmSync } from "fs";
189
207
  import { homedir as homedir2 } from "os";
190
- import { resolve as resolve2 } from "path";
208
+ import { resolve as resolve3 } from "path";
191
209
  var PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
192
210
  async function defaultCommandRunner(command, options = {}) {
193
211
  const proc = Bun.spawn(command, { cwd: options.cwd, stdout: "pipe", stderr: "pipe" });
@@ -199,7 +217,7 @@ async function defaultCommandRunner(command, options = {}) {
199
217
  return { exitCode, stdout, stderr };
200
218
  }
201
219
  function resolvePiRigExtensionPath(homeDir) {
202
- return resolve2(homeDir, ".pi", "agent", "extensions", "pi-rig");
220
+ return resolve3(homeDir, ".pi", "agent", "extensions", "pi-rig");
203
221
  }
204
222
  function resolvePiHomeDir(inputHomeDir) {
205
223
  return inputHomeDir ?? process.env.RIG_PI_HOME_DIR?.trim() ?? homedir2();
@@ -227,13 +245,13 @@ async function checkPiRigInstall(input = {}) {
227
245
  piRig: { ok: true, label: "pi-rig global extension", detail: extensionPath }
228
246
  };
229
247
  }
230
- const exists = input.exists ?? existsSync2;
248
+ const exists = input.exists ?? existsSync3;
231
249
  const runner = input.commandRunner ?? defaultCommandRunner;
232
250
  const piResult = await safeRun(runner, ["pi", "--version"]);
233
251
  const piListResult = piResult.exitCode === 0 ? await safeRun(runner, ["pi", "list"]) : { exitCode: 1, stdout: "", stderr: "" };
234
252
  const listedPiRig = piListResult.exitCode === 0 && piListContainsPiRig(`${piListResult.stdout}
235
253
  ${piListResult.stderr}`);
236
- const legacyBridge = exists(resolve2(extensionPath, "index.ts"));
254
+ const legacyBridge = exists(resolve3(extensionPath, "index.ts"));
237
255
  const hasPiRig = listedPiRig;
238
256
  return {
239
257
  extensionPath,
@@ -1,6 +1,8 @@
1
1
  // @bun
2
2
  // packages/cli/src/commands/_server-client.ts
3
3
  import { spawnSync } from "child_process";
4
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
5
+ import { resolve as resolve2 } from "path";
4
6
 
5
7
  // packages/cli/src/runner.ts
6
8
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
@@ -105,9 +107,25 @@ function cleanToken(value) {
105
107
  function setGitHubBearerTokenForCurrentProcess(token) {
106
108
  cachedGitHubBearerToken = cleanToken(token ?? undefined);
107
109
  }
108
- function readGitHubBearerTokenForRemote() {
110
+ function readPrivateRemoteSessionToken(projectRoot) {
111
+ const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
112
+ if (!existsSync2(path))
113
+ return null;
114
+ try {
115
+ const parsed = JSON.parse(readFileSync2(path, "utf8"));
116
+ return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
117
+ } catch {
118
+ return null;
119
+ }
120
+ }
121
+ function readGitHubBearerTokenForRemote(projectRoot) {
109
122
  if (cachedGitHubBearerToken !== undefined)
110
123
  return cachedGitHubBearerToken;
124
+ const privateSession = readPrivateRemoteSessionToken(projectRoot);
125
+ if (privateSession) {
126
+ cachedGitHubBearerToken = privateSession;
127
+ return cachedGitHubBearerToken;
128
+ }
111
129
  const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
112
130
  if (envToken) {
113
131
  cachedGitHubBearerToken = envToken;
@@ -127,7 +145,7 @@ async function ensureServerForCli(projectRoot) {
127
145
  if (selected?.connection.kind === "remote") {
128
146
  return {
129
147
  baseUrl: selected.connection.baseUrl,
130
- authToken: readGitHubBearerTokenForRemote(),
148
+ authToken: readGitHubBearerTokenForRemote(projectRoot),
131
149
  connectionKind: "remote"
132
150
  };
133
151
  }
@@ -234,7 +252,7 @@ async function postGitHubTokenViaServer(context, token, options = {}) {
234
252
  const payload = await requestServerJson(context, "/api/github/auth/token", {
235
253
  method: "POST",
236
254
  headers: { "content-type": "application/json" },
237
- body: JSON.stringify({ token, selectedRepo: options.selectedRepo })
255
+ body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot })
238
256
  });
239
257
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
240
258
  }
@@ -255,18 +273,38 @@ async function registerProjectViaServer(context, input) {
255
273
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
256
274
  }
257
275
  function sleep(ms) {
258
- return new Promise((resolve2) => setTimeout(resolve2, ms));
276
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
277
+ }
278
+ function isRetryableProjectRootSwitchError(error) {
279
+ if (!(error instanceof Error))
280
+ return false;
281
+ const message = error.message.toLowerCase();
282
+ return message.includes("rig server request failed (401): auth-required") || message.includes("rig server request failed (401): github-token-required") || message.includes("rig server request failed (502)") || message.includes("rig server request failed (503)") || message.includes("bad gateway") || message.includes("fetch failed") || message.includes("econnrefused") || message.includes("connection refused");
259
283
  }
260
284
  async function switchServerProjectRootViaServer(context, projectRoot, options = {}) {
261
- const switched = await requestServerJson(context, "/api/server/project-root", {
262
- method: "POST",
263
- headers: { "content-type": "application/json" },
264
- body: JSON.stringify({ projectRoot })
265
- });
266
285
  const timeoutMs = options.timeoutMs ?? 30000;
267
286
  const pollMs = options.pollMs ?? 1000;
268
287
  const deadline = Date.now() + timeoutMs;
269
288
  let lastError;
289
+ let switched = null;
290
+ while (Date.now() < deadline) {
291
+ try {
292
+ switched = await requestServerJson(context, "/api/server/project-root", {
293
+ method: "POST",
294
+ headers: { "content-type": "application/json" },
295
+ body: JSON.stringify({ projectRoot })
296
+ });
297
+ break;
298
+ } catch (error) {
299
+ lastError = error;
300
+ if (!isRetryableProjectRootSwitchError(error))
301
+ throw error;
302
+ await sleep(pollMs);
303
+ }
304
+ }
305
+ if (!switched) {
306
+ throw new CliError2(`Rig server did not accept project-root switch to ${projectRoot} before timeout (${lastError instanceof Error ? lastError.message : String(lastError ?? "no response")}).`, 1);
307
+ }
270
308
  while (Date.now() < deadline) {
271
309
  try {
272
310
  const status = await requestServerJson(context, "/api/server/status");
@@ -1,10 +1,12 @@
1
1
  // @bun
2
2
  // packages/cli/src/commands/_snapshot-upload.ts
3
3
  import { mkdir, readdir, readFile, writeFile } from "fs/promises";
4
- import { dirname as dirname2, resolve as resolve2, relative, sep } from "path";
4
+ import { dirname as dirname2, resolve as resolve3, relative, sep } from "path";
5
5
 
6
6
  // packages/cli/src/commands/_server-client.ts
7
7
  import { spawnSync } from "child_process";
8
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
9
+ import { resolve as resolve2 } from "path";
8
10
 
9
11
  // packages/cli/src/runner.ts
10
12
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
@@ -106,9 +108,25 @@ function cleanToken(value) {
106
108
  const trimmed = value?.trim();
107
109
  return trimmed ? trimmed : null;
108
110
  }
109
- function readGitHubBearerTokenForRemote() {
111
+ function readPrivateRemoteSessionToken(projectRoot) {
112
+ const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
113
+ if (!existsSync2(path))
114
+ return null;
115
+ try {
116
+ const parsed = JSON.parse(readFileSync2(path, "utf8"));
117
+ return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
118
+ } catch {
119
+ return null;
120
+ }
121
+ }
122
+ function readGitHubBearerTokenForRemote(projectRoot) {
110
123
  if (cachedGitHubBearerToken !== undefined)
111
124
  return cachedGitHubBearerToken;
125
+ const privateSession = readPrivateRemoteSessionToken(projectRoot);
126
+ if (privateSession) {
127
+ cachedGitHubBearerToken = privateSession;
128
+ return cachedGitHubBearerToken;
129
+ }
112
130
  const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
113
131
  if (envToken) {
114
132
  cachedGitHubBearerToken = envToken;
@@ -128,7 +146,7 @@ async function ensureServerForCli(projectRoot) {
128
146
  if (selected?.connection.kind === "remote") {
129
147
  return {
130
148
  baseUrl: selected.connection.baseUrl,
131
- authToken: readGitHubBearerTokenForRemote(),
149
+ authToken: readGitHubBearerTokenForRemote(projectRoot),
132
150
  connectionKind: "remote"
133
151
  };
134
152
  }
@@ -212,15 +230,15 @@ function assertManifestPath(root, relativePath) {
212
230
  if (!relativePath || relativePath.startsWith("/") || relativePath.includes("\x00")) {
213
231
  throw new Error(`Invalid snapshot path: ${relativePath}`);
214
232
  }
215
- const resolved = resolve2(root, relativePath);
233
+ const resolved = resolve3(root, relativePath);
216
234
  const relativeToRoot = relative(root, resolved);
217
- if (relativeToRoot.startsWith("..") || relativeToRoot === ".." || resolve2(relativeToRoot) === resolved) {
235
+ if (relativeToRoot.startsWith("..") || relativeToRoot === ".." || resolve3(relativeToRoot) === resolved) {
218
236
  throw new Error(`Snapshot path escapes project root: ${relativePath}`);
219
237
  }
220
238
  return resolved;
221
239
  }
222
240
  async function buildSnapshotUploadManifest(projectRoot, options = {}) {
223
- const root = resolve2(projectRoot);
241
+ const root = resolve3(projectRoot);
224
242
  const excludedDirectories = [...new Set([
225
243
  ...DEFAULT_EXCLUDED_DIRECTORIES,
226
244
  ...options.excludedDirectories ?? []
@@ -232,7 +250,7 @@ async function buildSnapshotUploadManifest(projectRoot, options = {}) {
232
250
  for (const entry of entries) {
233
251
  if (entry.isDirectory() && excludedSet.has(entry.name))
234
252
  continue;
235
- const fullPath = resolve2(dir, entry.name);
253
+ const fullPath = resolve3(dir, entry.name);
236
254
  if (entry.isDirectory()) {
237
255
  await visit(fullPath);
238
256
  continue;
@@ -268,7 +286,7 @@ function encodeSnapshotUploadArchive(archive) {
268
286
  }
269
287
  async function writeSnapshotUploadArchive(projectRoot, outputPath, options = {}) {
270
288
  const archive = await createSnapshotUploadArchive(projectRoot, options);
271
- const target = resolve2(outputPath);
289
+ const target = resolve3(outputPath);
272
290
  await mkdir(dirname2(target), { recursive: true });
273
291
  await writeFile(target, JSON.stringify(archive, null, 2), "utf8");
274
292
  return archive;
@@ -126,6 +126,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
126
126
  const runtimeAdapter = normalizeRuntimeAdapter(input.runtimeAdapter ?? existing?.runtimeAdapter ?? "claude-code");
127
127
  const title = resolveTaskTitleForAuthorityRun(projectRoot, input.taskId) ?? input.taskId;
128
128
  const next = {
129
+ ...existing ?? {},
129
130
  runId: input.runId,
130
131
  projectRoot,
131
132
  workspaceId: existing?.workspaceId ?? RIG_WORKSPACE_ID,
@@ -17,8 +17,8 @@ Usage: ${usage}`);
17
17
  }
18
18
 
19
19
  // packages/cli/src/commands/_doctor-checks.ts
20
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
21
- import { resolve as resolve3 } from "path";
20
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
21
+ import { resolve as resolve4 } from "path";
22
22
  import { isSupportedBunVersion, MIN_SUPPORTED_BUN_VERSION } from "@rig/runtime/control-plane/setup-version";
23
23
 
24
24
  // packages/cli/src/commands/_connection-state.ts
@@ -105,15 +105,33 @@ function resolveSelectedConnection(projectRoot, options = {}) {
105
105
 
106
106
  // packages/cli/src/commands/_server-client.ts
107
107
  import { spawnSync } from "child_process";
108
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
109
+ import { resolve as resolve2 } from "path";
108
110
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
109
111
  var cachedGitHubBearerToken;
110
112
  function cleanToken(value) {
111
113
  const trimmed = value?.trim();
112
114
  return trimmed ? trimmed : null;
113
115
  }
114
- function readGitHubBearerTokenForRemote() {
116
+ function readPrivateRemoteSessionToken(projectRoot) {
117
+ const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
118
+ if (!existsSync2(path))
119
+ return null;
120
+ try {
121
+ const parsed = JSON.parse(readFileSync2(path, "utf8"));
122
+ return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
123
+ } catch {
124
+ return null;
125
+ }
126
+ }
127
+ function readGitHubBearerTokenForRemote(projectRoot) {
115
128
  if (cachedGitHubBearerToken !== undefined)
116
129
  return cachedGitHubBearerToken;
130
+ const privateSession = readPrivateRemoteSessionToken(projectRoot);
131
+ if (privateSession) {
132
+ cachedGitHubBearerToken = privateSession;
133
+ return cachedGitHubBearerToken;
134
+ }
117
135
  const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
118
136
  if (envToken) {
119
137
  cachedGitHubBearerToken = envToken;
@@ -133,7 +151,7 @@ async function ensureServerForCli(projectRoot) {
133
151
  if (selected?.connection.kind === "remote") {
134
152
  return {
135
153
  baseUrl: selected.connection.baseUrl,
136
- authToken: readGitHubBearerTokenForRemote(),
154
+ authToken: readGitHubBearerTokenForRemote(projectRoot),
137
155
  connectionKind: "remote"
138
156
  };
139
157
  }
@@ -205,9 +223,9 @@ async function loadRigConfigOrNull(projectRoot) {
205
223
  }
206
224
 
207
225
  // packages/cli/src/commands/_pi-install.ts
208
- import { existsSync as existsSync2, readFileSync as readFileSync2, rmSync } from "fs";
226
+ import { existsSync as existsSync3, readFileSync as readFileSync3, rmSync } from "fs";
209
227
  import { homedir as homedir2 } from "os";
210
- import { resolve as resolve2 } from "path";
228
+ import { resolve as resolve3 } from "path";
211
229
  var PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
212
230
  async function defaultCommandRunner(command, options = {}) {
213
231
  const proc = Bun.spawn(command, { cwd: options.cwd, stdout: "pipe", stderr: "pipe" });
@@ -219,7 +237,7 @@ async function defaultCommandRunner(command, options = {}) {
219
237
  return { exitCode, stdout, stderr };
220
238
  }
221
239
  function resolvePiRigExtensionPath(homeDir) {
222
- return resolve2(homeDir, ".pi", "agent", "extensions", "pi-rig");
240
+ return resolve3(homeDir, ".pi", "agent", "extensions", "pi-rig");
223
241
  }
224
242
  function resolvePiHomeDir(inputHomeDir) {
225
243
  return inputHomeDir ?? process.env.RIG_PI_HOME_DIR?.trim() ?? homedir2();
@@ -247,13 +265,13 @@ async function checkPiRigInstall(input = {}) {
247
265
  piRig: { ok: true, label: "pi-rig global extension", detail: extensionPath }
248
266
  };
249
267
  }
250
- const exists = input.exists ?? existsSync2;
268
+ const exists = input.exists ?? existsSync3;
251
269
  const runner = input.commandRunner ?? defaultCommandRunner;
252
270
  const piResult = await safeRun(runner, ["pi", "--version"]);
253
271
  const piListResult = piResult.exitCode === 0 ? await safeRun(runner, ["pi", "list"]) : { exitCode: 1, stdout: "", stderr: "" };
254
272
  const listedPiRig = piListResult.exitCode === 0 && piListContainsPiRig(`${piListResult.stdout}
255
273
  ${piListResult.stderr}`);
256
- const legacyBridge = exists(resolve2(extensionPath, "index.ts"));
274
+ const legacyBridge = exists(resolve3(extensionPath, "index.ts"));
257
275
  const hasPiRig = listedPiRig;
258
276
  return {
259
277
  extensionPath,
@@ -315,11 +333,11 @@ function repoSlugFromConfig(config) {
315
333
  function loadFallbackConfig(projectRoot) {
316
334
  const candidates = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
317
335
  for (const name of candidates) {
318
- const path = resolve3(projectRoot, name);
319
- if (!existsSync3(path))
336
+ const path = resolve4(projectRoot, name);
337
+ if (!existsSync4(path))
320
338
  continue;
321
339
  try {
322
- const source = readFileSync3(path, "utf8");
340
+ const source = readFileSync4(path, "utf8");
323
341
  if (name.endsWith(".json"))
324
342
  return JSON.parse(source);
325
343
  const owner = source.match(/owner\s*:\s*["']([^"']+)["']/)?.[1];
@@ -398,7 +416,7 @@ async function runRigDoctorChecks(options) {
398
416
  checks.push(check("bun", `bun >= ${MIN_SUPPORTED_BUN_VERSION}`, isSupportedBunVersion(bunVersion) ? "pass" : "fail", `found ${bunVersion}`, `Install Bun ${MIN_SUPPORTED_BUN_VERSION} or newer.`), check("git", "git", which("git") ? "pass" : "fail", which("git") ?? undefined, "Install git and ensure it is on PATH."), check("jq", "jq", which("jq") ? "pass" : "warn", which("jq") ?? undefined, "Install jq (for example `brew install jq`)."));
399
417
  const loadedConfig = await loadConfig(projectRoot).catch(() => null);
400
418
  const config = loadedConfig ?? loadFallbackConfig(projectRoot);
401
- const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync3(resolve3(projectRoot, name)));
419
+ const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync4(resolve4(projectRoot, name)));
402
420
  checks.push(config ? check("config", "rig.config loadable", "pass") : check("config", "rig.config loadable", hasConfigFile ? "fail" : "fail", hasConfigFile ? "config file exists but failed to load" : "missing rig.config.ts/json", "Run `rig init` or fix the config error."));
403
421
  const taskSourceKind = config?.taskSource?.kind;
404
422
  checks.push(taskSourceKind ? check("task-source", "task source configured", "pass", taskSourceKind) : check("task-source", "task source configured", "fail", "missing taskSource", "Configure taskSource in rig.config.ts."));
@@ -33,6 +33,8 @@ function takeOption(args, option) {
33
33
 
34
34
  // packages/cli/src/commands/_server-client.ts
35
35
  import { spawnSync } from "child_process";
36
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
37
+ import { resolve as resolve2 } from "path";
36
38
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
37
39
 
38
40
  // packages/cli/src/commands/_connection-state.ts
@@ -123,9 +125,25 @@ function cleanToken(value) {
123
125
  const trimmed = value?.trim();
124
126
  return trimmed ? trimmed : null;
125
127
  }
126
- function readGitHubBearerTokenForRemote() {
128
+ function readPrivateRemoteSessionToken(projectRoot) {
129
+ const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
130
+ if (!existsSync2(path))
131
+ return null;
132
+ try {
133
+ const parsed = JSON.parse(readFileSync2(path, "utf8"));
134
+ return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
135
+ } catch {
136
+ return null;
137
+ }
138
+ }
139
+ function readGitHubBearerTokenForRemote(projectRoot) {
127
140
  if (cachedGitHubBearerToken !== undefined)
128
141
  return cachedGitHubBearerToken;
142
+ const privateSession = readPrivateRemoteSessionToken(projectRoot);
143
+ if (privateSession) {
144
+ cachedGitHubBearerToken = privateSession;
145
+ return cachedGitHubBearerToken;
146
+ }
129
147
  const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
130
148
  if (envToken) {
131
149
  cachedGitHubBearerToken = envToken;
@@ -145,7 +163,7 @@ async function ensureServerForCli(projectRoot) {
145
163
  if (selected?.connection.kind === "remote") {
146
164
  return {
147
165
  baseUrl: selected.connection.baseUrl,
148
- authToken: readGitHubBearerTokenForRemote(),
166
+ authToken: readGitHubBearerTokenForRemote(projectRoot),
149
167
  connectionKind: "remote"
150
168
  };
151
169
  }
@@ -213,7 +231,7 @@ async function postGitHubTokenViaServer(context, token, options = {}) {
213
231
  const payload = await requestServerJson(context, "/api/github/auth/token", {
214
232
  method: "POST",
215
233
  headers: { "content-type": "application/json" },
216
- body: JSON.stringify({ token, selectedRepo: options.selectedRepo })
234
+ body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot })
217
235
  });
218
236
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
219
237
  }