@h-rig/cli 0.0.6-alpha.5 → 0.0.6-alpha.50

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.
Files changed (49) hide show
  1. package/dist/bin/rig.js +4072 -1204
  2. package/dist/src/commands/_cli-format.js +369 -0
  3. package/dist/src/commands/_connection-state.js +12 -6
  4. package/dist/src/commands/_doctor-checks.js +65 -34
  5. package/dist/src/commands/_help-catalog.js +445 -0
  6. package/dist/src/commands/_operator-surface.js +220 -0
  7. package/dist/src/commands/_operator-view.js +1109 -63
  8. package/dist/src/commands/_parsers.js +0 -2
  9. package/dist/src/commands/_pi-frontend.js +1066 -0
  10. package/dist/src/commands/_pi-install.js +4 -3
  11. package/dist/src/commands/_pi-remote-session.js +757 -0
  12. package/dist/src/commands/_pi-worker-bridge-extension.js +820 -0
  13. package/dist/src/commands/_policy.js +0 -2
  14. package/dist/src/commands/_preflight.js +84 -116
  15. package/dist/src/commands/_run-driver-helpers.js +2 -2
  16. package/dist/src/commands/_server-client.js +211 -48
  17. package/dist/src/commands/_snapshot-upload.js +60 -30
  18. package/dist/src/commands/_spinner.js +63 -0
  19. package/dist/src/commands/_task-picker.js +44 -16
  20. package/dist/src/commands/agent.js +8 -9
  21. package/dist/src/commands/browser.js +4 -6
  22. package/dist/src/commands/connect.js +134 -26
  23. package/dist/src/commands/dist.js +4 -6
  24. package/dist/src/commands/doctor.js +65 -34
  25. package/dist/src/commands/github.js +62 -32
  26. package/dist/src/commands/inbox.js +396 -31
  27. package/dist/src/commands/init.js +342 -88
  28. package/dist/src/commands/inspect.js +282 -23
  29. package/dist/src/commands/inspector.js +2 -4
  30. package/dist/src/commands/pi.js +168 -0
  31. package/dist/src/commands/plugin.js +81 -22
  32. package/dist/src/commands/profile-and-review.js +8 -10
  33. package/dist/src/commands/queue.js +2 -3
  34. package/dist/src/commands/remote.js +18 -20
  35. package/dist/src/commands/repo-git-harness.js +6 -8
  36. package/dist/src/commands/run.js +1407 -130
  37. package/dist/src/commands/server.js +266 -40
  38. package/dist/src/commands/setup.js +69 -44
  39. package/dist/src/commands/task-report-bug.js +5 -7
  40. package/dist/src/commands/task-run-driver.js +662 -70
  41. package/dist/src/commands/task.js +1846 -259
  42. package/dist/src/commands/test.js +3 -5
  43. package/dist/src/commands/workspace.js +4 -6
  44. package/dist/src/commands.js +4054 -1180
  45. package/dist/src/index.js +4065 -1200
  46. package/dist/src/launcher.js +5 -3
  47. package/dist/src/report-bug.js +3 -3
  48. package/dist/src/runner.js +5 -19
  49. package/package.json +7 -4
@@ -5,8 +5,6 @@ var __require = import.meta.require;
5
5
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
6
6
  import { CliError } from "@rig/runtime/control-plane/errors";
7
7
  import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
8
- import { PluginManager } from "@rig/runtime/control-plane/runtime/plugins";
9
- import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/context";
10
8
  import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
11
9
  import { CliError as CliError2 } from "@rig/runtime/control-plane/errors";
12
10
  function requireNoExtraArgs(args, usage) {
@@ -46,6 +44,11 @@ function readJsonFile(path) {
46
44
  throw new CliError2(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1);
47
45
  }
48
46
  }
47
+ function writeJsonFile(path, value) {
48
+ mkdirSync(dirname(path), { recursive: true });
49
+ writeFileSync(path, `${JSON.stringify(value, null, 2)}
50
+ `, "utf8");
51
+ }
49
52
  function normalizeConnection(value) {
50
53
  if (!value || typeof value !== "object" || Array.isArray(value))
51
54
  return null;
@@ -86,29 +89,38 @@ function readRepoConnection(projectRoot) {
86
89
  return {
87
90
  selected,
88
91
  project: typeof record.project === "string" ? record.project : undefined,
89
- linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
92
+ linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
93
+ serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
90
94
  };
91
95
  }
96
+ function writeRepoConnection(projectRoot, state) {
97
+ writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
98
+ }
92
99
  function resolveSelectedConnection(projectRoot, options = {}) {
93
100
  const repo = readRepoConnection(projectRoot);
94
101
  if (!repo)
95
102
  return null;
96
103
  if (repo.selected === "local")
97
- return { alias: "local", connection: { kind: "local", mode: "auto" } };
104
+ return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
98
105
  const global = readGlobalConnections(options);
99
106
  const connection = global.connections[repo.selected];
100
107
  if (!connection) {
101
- throw new CliError2(`Selected Rig connection "${repo.selected}" was not found. Run \`rig connect list\` or \`rig connect use local\`.`, 1);
108
+ throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
102
109
  }
103
- return { alias: repo.selected, connection };
110
+ return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
111
+ }
112
+ function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
113
+ const repo = readRepoConnection(projectRoot);
114
+ if (!repo)
115
+ return;
116
+ writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
104
117
  }
105
118
 
106
119
  // packages/cli/src/commands/_server-client.ts
107
- import { spawnSync } from "child_process";
108
120
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
109
121
  import { resolve as resolve2 } from "path";
110
122
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
111
- var cachedGitHubBearerToken;
123
+ var scopedGitHubBearerTokens = new Map;
112
124
  function cleanToken(value) {
113
125
  const trimmed = value?.trim();
114
126
  return trimmed ? trimmed : null;
@@ -125,41 +137,33 @@ function readPrivateRemoteSessionToken(projectRoot) {
125
137
  }
126
138
  }
127
139
  function readGitHubBearerTokenForRemote(projectRoot) {
128
- if (cachedGitHubBearerToken !== undefined)
129
- return cachedGitHubBearerToken;
140
+ const scopedKey = resolve2(projectRoot);
141
+ if (scopedGitHubBearerTokens.has(scopedKey))
142
+ return scopedGitHubBearerTokens.get(scopedKey) ?? null;
130
143
  const privateSession = readPrivateRemoteSessionToken(projectRoot);
131
- if (privateSession) {
132
- cachedGitHubBearerToken = privateSession;
133
- return cachedGitHubBearerToken;
134
- }
135
- const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
136
- if (envToken) {
137
- cachedGitHubBearerToken = envToken;
138
- return cachedGitHubBearerToken;
139
- }
140
- const result = spawnSync("gh", ["auth", "token"], {
141
- encoding: "utf8",
142
- timeout: 5000,
143
- stdio: ["ignore", "pipe", "ignore"]
144
- });
145
- cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
146
- return cachedGitHubBearerToken;
144
+ if (privateSession)
145
+ return privateSession;
146
+ return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
147
147
  }
148
148
  async function ensureServerForCli(projectRoot) {
149
149
  try {
150
150
  const selected = resolveSelectedConnection(projectRoot);
151
151
  if (selected?.connection.kind === "remote") {
152
+ const authToken = readGitHubBearerTokenForRemote(projectRoot);
153
+ const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
152
154
  return {
153
155
  baseUrl: selected.connection.baseUrl,
154
- authToken: readGitHubBearerTokenForRemote(projectRoot),
155
- connectionKind: "remote"
156
+ authToken,
157
+ connectionKind: "remote",
158
+ serverProjectRoot
156
159
  };
157
160
  }
158
161
  const connection = await ensureLocalRigServerConnection(projectRoot);
159
162
  return {
160
163
  baseUrl: connection.baseUrl,
161
164
  authToken: connection.authToken,
162
- connectionKind: "local"
165
+ connectionKind: "local",
166
+ serverProjectRoot: resolve2(projectRoot)
163
167
  };
164
168
  } catch (error) {
165
169
  if (error instanceof Error) {
@@ -168,6 +172,29 @@ async function ensureServerForCli(projectRoot) {
168
172
  throw error;
169
173
  }
170
174
  }
175
+ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
176
+ const repo = readRepoConnection(projectRoot);
177
+ const slug = repo?.project?.trim();
178
+ if (!slug)
179
+ return null;
180
+ try {
181
+ const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
182
+ headers: mergeHeaders(undefined, authToken)
183
+ });
184
+ if (!response.ok)
185
+ return null;
186
+ const payload = await response.json();
187
+ const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
188
+ const checkouts = Array.isArray(project?.checkouts) ? project.checkouts : [];
189
+ const latestCheckout = [...checkouts].reverse().find((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.path === "string"));
190
+ const path = typeof latestCheckout?.path === "string" && latestCheckout.path.trim() ? latestCheckout.path.trim() : null;
191
+ if (path)
192
+ writeRepoServerProjectRoot(projectRoot, path);
193
+ return path;
194
+ } catch {
195
+ return null;
196
+ }
197
+ }
171
198
  function mergeHeaders(headers, authToken) {
172
199
  const merged = new Headers(headers);
173
200
  if (authToken) {
@@ -192,9 +219,12 @@ function diagnosticMessage(payload) {
192
219
  }
193
220
  async function requestServerJson(context, pathname, init = {}) {
194
221
  const server = await ensureServerForCli(context.projectRoot);
222
+ const headers = mergeHeaders(init.headers, server.authToken);
223
+ if (server.serverProjectRoot)
224
+ headers.set("x-rig-project-root", server.serverProjectRoot);
195
225
  const response = await fetch(`${server.baseUrl}${pathname}`, {
196
226
  ...init,
197
- headers: mergeHeaders(init.headers, server.authToken)
227
+ headers
198
228
  });
199
229
  const text = await response.text();
200
230
  const payload = text.trim().length > 0 ? (() => {
@@ -226,7 +256,8 @@ async function loadRigConfigOrNull(projectRoot) {
226
256
  import { existsSync as existsSync3, readFileSync as readFileSync3, rmSync } from "fs";
227
257
  import { homedir as homedir2 } from "os";
228
258
  import { resolve as resolve3 } from "path";
229
- var PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
259
+ var PI_RIG_PACKAGE_NAME = "@h-rig/pi-rig";
260
+ var LEGACY_PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
230
261
  async function defaultCommandRunner(command, options = {}) {
231
262
  const proc = Bun.spawn(command, { cwd: options.cwd, stdout: "pipe", stderr: "pipe" });
232
263
  const [stdout, stderr, exitCode] = await Promise.all([
@@ -245,7 +276,7 @@ function resolvePiHomeDir(inputHomeDir) {
245
276
  function piListContainsPiRig(output) {
246
277
  return output.split(/\r?\n/).some((line) => {
247
278
  const normalized = line.trim();
248
- return normalized.includes(PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
279
+ return normalized.includes(PI_RIG_PACKAGE_NAME) || normalized.includes(LEGACY_PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
249
280
  });
250
281
  }
251
282
  async function safeRun(runner, command, options) {
@@ -421,7 +452,7 @@ async function runRigDoctorChecks(options) {
421
452
  const taskSourceKind = config?.taskSource?.kind;
422
453
  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."));
423
454
  const repo = readRepoConnection(projectRoot);
424
- checks.push(repo ? check("project-link", "repo selected Rig connection", repo.project ? "pass" : "warn", `${repo.selected}${repo.project ? ` -> ${repo.project}` : ""}`, "Run `rig init --yes --repo owner/repo` to link this checkout to a GitHub repo slug.") : check("project-link", "repo selected Rig connection", "fail", "missing .rig/state/connection.json", "Run `rig init` or `rig connect use <alias|local>`."));
455
+ checks.push(repo ? check("project-link", "repo selected Rig server", repo.project ? "pass" : "warn", `${repo.selected}${repo.project ? ` -> ${repo.project}` : ""}`, "Run `rig init --yes --repo owner/repo` to link this checkout to a GitHub repo slug.") : check("project-link", "repo selected Rig server", "fail", "missing .rig/state/connection.json", "Run `rig init` or `rig server use <alias|local>`."));
425
456
  const selected = (() => {
426
457
  try {
427
458
  return resolveSelectedConnection(projectRoot);
@@ -429,7 +460,7 @@ async function runRigDoctorChecks(options) {
429
460
  return null;
430
461
  }
431
462
  })();
432
- checks.push(selected ? check("connection", "selected server connection", "pass", selected.connection.kind === "remote" ? selected.connection.baseUrl : "local auto") : check("connection", "selected server connection", repo ? "fail" : "warn", repo ? "selected alias is missing" : "will auto-start local server", repo ? "Run `rig connect list` and `rig connect use <alias|local>`." : undefined));
463
+ checks.push(selected ? check("connection", "selected server connection", "pass", selected.connection.kind === "remote" ? selected.connection.baseUrl : "local auto") : check("connection", "selected server", repo ? "fail" : "warn", repo ? "selected alias is missing" : "will auto-start local server", repo ? "Run `rig server list` and `rig server use <alias|local>`." : undefined));
433
464
  let server = null;
434
465
  try {
435
466
  server = await (options.resolveServer ?? ensureServerForCli)(projectRoot);
@@ -1,13 +1,11 @@
1
1
  // @bun
2
2
  // packages/cli/src/commands/github.ts
3
- import { spawnSync as spawnSync2 } from "child_process";
3
+ import { spawnSync } from "child_process";
4
4
 
5
5
  // packages/cli/src/runner.ts
6
6
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
7
7
  import { CliError } from "@rig/runtime/control-plane/errors";
8
8
  import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
9
- import { PluginManager } from "@rig/runtime/control-plane/runtime/plugins";
10
- import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/context";
11
9
  import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
12
10
  import { CliError as CliError2 } from "@rig/runtime/control-plane/errors";
13
11
  function takeOption(args, option) {
@@ -32,7 +30,6 @@ function takeOption(args, option) {
32
30
  }
33
31
 
34
32
  // packages/cli/src/commands/_server-client.ts
35
- import { spawnSync } from "child_process";
36
33
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
37
34
  import { resolve as resolve2 } from "path";
38
35
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
@@ -62,6 +59,11 @@ function readJsonFile(path) {
62
59
  throw new CliError2(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1);
63
60
  }
64
61
  }
62
+ function writeJsonFile(path, value) {
63
+ mkdirSync(dirname(path), { recursive: true });
64
+ writeFileSync(path, `${JSON.stringify(value, null, 2)}
65
+ `, "utf8");
66
+ }
65
67
  function normalizeConnection(value) {
66
68
  if (!value || typeof value !== "object" || Array.isArray(value))
67
69
  return null;
@@ -102,25 +104,35 @@ function readRepoConnection(projectRoot) {
102
104
  return {
103
105
  selected,
104
106
  project: typeof record.project === "string" ? record.project : undefined,
105
- linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
107
+ linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
108
+ serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
106
109
  };
107
110
  }
111
+ function writeRepoConnection(projectRoot, state) {
112
+ writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
113
+ }
108
114
  function resolveSelectedConnection(projectRoot, options = {}) {
109
115
  const repo = readRepoConnection(projectRoot);
110
116
  if (!repo)
111
117
  return null;
112
118
  if (repo.selected === "local")
113
- return { alias: "local", connection: { kind: "local", mode: "auto" } };
119
+ return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
114
120
  const global = readGlobalConnections(options);
115
121
  const connection = global.connections[repo.selected];
116
122
  if (!connection) {
117
- throw new CliError2(`Selected Rig connection "${repo.selected}" was not found. Run \`rig connect list\` or \`rig connect use local\`.`, 1);
123
+ throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
118
124
  }
119
- return { alias: repo.selected, connection };
125
+ return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
126
+ }
127
+ function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
128
+ const repo = readRepoConnection(projectRoot);
129
+ if (!repo)
130
+ return;
131
+ writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
120
132
  }
121
133
 
122
134
  // packages/cli/src/commands/_server-client.ts
123
- var cachedGitHubBearerToken;
135
+ var scopedGitHubBearerTokens = new Map;
124
136
  function cleanToken(value) {
125
137
  const trimmed = value?.trim();
126
138
  return trimmed ? trimmed : null;
@@ -137,41 +149,33 @@ function readPrivateRemoteSessionToken(projectRoot) {
137
149
  }
138
150
  }
139
151
  function readGitHubBearerTokenForRemote(projectRoot) {
140
- if (cachedGitHubBearerToken !== undefined)
141
- return cachedGitHubBearerToken;
152
+ const scopedKey = resolve2(projectRoot);
153
+ if (scopedGitHubBearerTokens.has(scopedKey))
154
+ return scopedGitHubBearerTokens.get(scopedKey) ?? null;
142
155
  const privateSession = readPrivateRemoteSessionToken(projectRoot);
143
- if (privateSession) {
144
- cachedGitHubBearerToken = privateSession;
145
- return cachedGitHubBearerToken;
146
- }
147
- const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
148
- if (envToken) {
149
- cachedGitHubBearerToken = envToken;
150
- return cachedGitHubBearerToken;
151
- }
152
- const result = spawnSync("gh", ["auth", "token"], {
153
- encoding: "utf8",
154
- timeout: 5000,
155
- stdio: ["ignore", "pipe", "ignore"]
156
- });
157
- cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
158
- return cachedGitHubBearerToken;
156
+ if (privateSession)
157
+ return privateSession;
158
+ return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
159
159
  }
160
160
  async function ensureServerForCli(projectRoot) {
161
161
  try {
162
162
  const selected = resolveSelectedConnection(projectRoot);
163
163
  if (selected?.connection.kind === "remote") {
164
+ const authToken = readGitHubBearerTokenForRemote(projectRoot);
165
+ const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
164
166
  return {
165
167
  baseUrl: selected.connection.baseUrl,
166
- authToken: readGitHubBearerTokenForRemote(projectRoot),
167
- connectionKind: "remote"
168
+ authToken,
169
+ connectionKind: "remote",
170
+ serverProjectRoot
168
171
  };
169
172
  }
170
173
  const connection = await ensureLocalRigServerConnection(projectRoot);
171
174
  return {
172
175
  baseUrl: connection.baseUrl,
173
176
  authToken: connection.authToken,
174
- connectionKind: "local"
177
+ connectionKind: "local",
178
+ serverProjectRoot: resolve2(projectRoot)
175
179
  };
176
180
  } catch (error) {
177
181
  if (error instanceof Error) {
@@ -180,6 +184,29 @@ async function ensureServerForCli(projectRoot) {
180
184
  throw error;
181
185
  }
182
186
  }
187
+ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
188
+ const repo = readRepoConnection(projectRoot);
189
+ const slug = repo?.project?.trim();
190
+ if (!slug)
191
+ return null;
192
+ try {
193
+ const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
194
+ headers: mergeHeaders(undefined, authToken)
195
+ });
196
+ if (!response.ok)
197
+ return null;
198
+ const payload = await response.json();
199
+ const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
200
+ const checkouts = Array.isArray(project?.checkouts) ? project.checkouts : [];
201
+ const latestCheckout = [...checkouts].reverse().find((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.path === "string"));
202
+ const path = typeof latestCheckout?.path === "string" && latestCheckout.path.trim() ? latestCheckout.path.trim() : null;
203
+ if (path)
204
+ writeRepoServerProjectRoot(projectRoot, path);
205
+ return path;
206
+ } catch {
207
+ return null;
208
+ }
209
+ }
183
210
  function mergeHeaders(headers, authToken) {
184
211
  const merged = new Headers(headers);
185
212
  if (authToken) {
@@ -204,9 +231,12 @@ function diagnosticMessage(payload) {
204
231
  }
205
232
  async function requestServerJson(context, pathname, init = {}) {
206
233
  const server = await ensureServerForCli(context.projectRoot);
234
+ const headers = mergeHeaders(init.headers, server.authToken);
235
+ if (server.serverProjectRoot)
236
+ headers.set("x-rig-project-root", server.serverProjectRoot);
207
237
  const response = await fetch(`${server.baseUrl}${pathname}`, {
208
238
  ...init,
209
- headers: mergeHeaders(init.headers, server.authToken)
239
+ headers
210
240
  });
211
241
  const text = await response.text();
212
242
  const payload = text.trim().length > 0 ? (() => {
@@ -244,7 +274,7 @@ function printPayload(context, payload, fallback) {
244
274
  console.log(fallback);
245
275
  }
246
276
  function readGhToken() {
247
- const result = spawnSync2("gh", ["auth", "token"], { encoding: "utf8" });
277
+ const result = spawnSync("gh", ["auth", "token"], { encoding: "utf8" });
248
278
  if (result.status !== 0) {
249
279
  const detail = result.stderr?.trim() || result.stdout?.trim() || "gh auth token failed";
250
280
  throw new CliError2(`Could not import GitHub token from gh: ${detail}`, 1);