@h-rig/cli 0.0.6-alpha.45 → 0.0.6-alpha.46
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/rig.js +50 -22
- package/dist/src/commands/_connection-state.js +11 -3
- package/dist/src/commands/_doctor-checks.js +51 -7
- package/dist/src/commands/_operator-view.js +53 -7
- package/dist/src/commands/_pi-frontend.js +53 -7
- package/dist/src/commands/_pi-remote-session.js +53 -7
- package/dist/src/commands/_pi-worker-bridge-extension.js +53 -7
- package/dist/src/commands/_preflight.js +51 -7
- package/dist/src/commands/_server-client.js +58 -22
- package/dist/src/commands/_snapshot-upload.js +51 -7
- package/dist/src/commands/connect.js +2 -1
- package/dist/src/commands/doctor.js +51 -7
- package/dist/src/commands/github.js +51 -7
- package/dist/src/commands/inbox.js +51 -7
- package/dist/src/commands/init.js +48 -22
- package/dist/src/commands/inspect.js +51 -7
- package/dist/src/commands/run.js +53 -7
- package/dist/src/commands/server.js +43 -7
- package/dist/src/commands/setup.js +51 -7
- package/dist/src/commands/task-run-driver.js +51 -7
- package/dist/src/commands/task.js +53 -7
- package/dist/src/commands.js +50 -22
- package/dist/src/index.js +50 -22
- package/package.json +6 -6
|
@@ -59,6 +59,11 @@ function readJsonFile(path) {
|
|
|
59
59
|
throw new CliError2(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
+
function writeJsonFile(path, value) {
|
|
63
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
64
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
65
|
+
`, "utf8");
|
|
66
|
+
}
|
|
62
67
|
function normalizeConnection(value) {
|
|
63
68
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
64
69
|
return null;
|
|
@@ -99,21 +104,31 @@ function readRepoConnection(projectRoot) {
|
|
|
99
104
|
return {
|
|
100
105
|
selected,
|
|
101
106
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
102
|
-
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
|
|
103
109
|
};
|
|
104
110
|
}
|
|
111
|
+
function writeRepoConnection(projectRoot, state) {
|
|
112
|
+
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
113
|
+
}
|
|
105
114
|
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
106
115
|
const repo = readRepoConnection(projectRoot);
|
|
107
116
|
if (!repo)
|
|
108
117
|
return null;
|
|
109
118
|
if (repo.selected === "local")
|
|
110
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" } };
|
|
119
|
+
return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
|
|
111
120
|
const global = readGlobalConnections(options);
|
|
112
121
|
const connection = global.connections[repo.selected];
|
|
113
122
|
if (!connection) {
|
|
114
123
|
throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
115
124
|
}
|
|
116
|
-
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 });
|
|
117
132
|
}
|
|
118
133
|
|
|
119
134
|
// packages/cli/src/commands/_server-client.ts
|
|
@@ -146,17 +161,21 @@ async function ensureServerForCli(projectRoot) {
|
|
|
146
161
|
try {
|
|
147
162
|
const selected = resolveSelectedConnection(projectRoot);
|
|
148
163
|
if (selected?.connection.kind === "remote") {
|
|
164
|
+
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
165
|
+
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
149
166
|
return {
|
|
150
167
|
baseUrl: selected.connection.baseUrl,
|
|
151
|
-
authToken
|
|
152
|
-
connectionKind: "remote"
|
|
168
|
+
authToken,
|
|
169
|
+
connectionKind: "remote",
|
|
170
|
+
serverProjectRoot
|
|
153
171
|
};
|
|
154
172
|
}
|
|
155
173
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
156
174
|
return {
|
|
157
175
|
baseUrl: connection.baseUrl,
|
|
158
176
|
authToken: connection.authToken,
|
|
159
|
-
connectionKind: "local"
|
|
177
|
+
connectionKind: "local",
|
|
178
|
+
serverProjectRoot: resolve2(projectRoot)
|
|
160
179
|
};
|
|
161
180
|
} catch (error) {
|
|
162
181
|
if (error instanceof Error) {
|
|
@@ -165,6 +184,28 @@ async function ensureServerForCli(projectRoot) {
|
|
|
165
184
|
throw error;
|
|
166
185
|
}
|
|
167
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 checkout = project?.checkout && typeof project.checkout === "object" && !Array.isArray(project.checkout) ? project.checkout : null;
|
|
201
|
+
const path = typeof checkout?.path === "string" && checkout.path.trim() ? checkout.path.trim() : typeof project?.path === "string" && project.path.trim() ? project.path.trim() : null;
|
|
202
|
+
if (path)
|
|
203
|
+
writeRepoServerProjectRoot(projectRoot, path);
|
|
204
|
+
return path;
|
|
205
|
+
} catch {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
168
209
|
function mergeHeaders(headers, authToken) {
|
|
169
210
|
const merged = new Headers(headers);
|
|
170
211
|
if (authToken) {
|
|
@@ -189,9 +230,12 @@ function diagnosticMessage(payload) {
|
|
|
189
230
|
}
|
|
190
231
|
async function requestServerJson(context, pathname, init = {}) {
|
|
191
232
|
const server = await ensureServerForCli(context.projectRoot);
|
|
233
|
+
const headers = mergeHeaders(init.headers, server.authToken);
|
|
234
|
+
if (server.serverProjectRoot)
|
|
235
|
+
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
192
236
|
const response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
193
237
|
...init,
|
|
194
|
-
headers
|
|
238
|
+
headers
|
|
195
239
|
});
|
|
196
240
|
const text = await response.text();
|
|
197
241
|
const payload = text.trim().length > 0 ? (() => {
|
|
@@ -150,6 +150,11 @@ function readJsonFile(path) {
|
|
|
150
150
|
throw new CliError2(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1);
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
+
function writeJsonFile(path, value) {
|
|
154
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
155
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
156
|
+
`, "utf8");
|
|
157
|
+
}
|
|
153
158
|
function normalizeConnection(value) {
|
|
154
159
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
155
160
|
return null;
|
|
@@ -190,21 +195,31 @@ function readRepoConnection(projectRoot) {
|
|
|
190
195
|
return {
|
|
191
196
|
selected,
|
|
192
197
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
193
|
-
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
|
|
198
|
+
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
199
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
194
200
|
};
|
|
195
201
|
}
|
|
202
|
+
function writeRepoConnection(projectRoot, state) {
|
|
203
|
+
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
204
|
+
}
|
|
196
205
|
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
197
206
|
const repo = readRepoConnection(projectRoot);
|
|
198
207
|
if (!repo)
|
|
199
208
|
return null;
|
|
200
209
|
if (repo.selected === "local")
|
|
201
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" } };
|
|
210
|
+
return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
|
|
202
211
|
const global = readGlobalConnections(options);
|
|
203
212
|
const connection = global.connections[repo.selected];
|
|
204
213
|
if (!connection) {
|
|
205
214
|
throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
206
215
|
}
|
|
207
|
-
return { alias: repo.selected, connection };
|
|
216
|
+
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
217
|
+
}
|
|
218
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
219
|
+
const repo = readRepoConnection(projectRoot);
|
|
220
|
+
if (!repo)
|
|
221
|
+
return;
|
|
222
|
+
writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
|
|
208
223
|
}
|
|
209
224
|
|
|
210
225
|
// packages/cli/src/commands/_server-client.ts
|
|
@@ -240,17 +255,21 @@ async function ensureServerForCli(projectRoot) {
|
|
|
240
255
|
try {
|
|
241
256
|
const selected = resolveSelectedConnection(projectRoot);
|
|
242
257
|
if (selected?.connection.kind === "remote") {
|
|
258
|
+
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
259
|
+
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
243
260
|
return {
|
|
244
261
|
baseUrl: selected.connection.baseUrl,
|
|
245
|
-
authToken
|
|
246
|
-
connectionKind: "remote"
|
|
262
|
+
authToken,
|
|
263
|
+
connectionKind: "remote",
|
|
264
|
+
serverProjectRoot
|
|
247
265
|
};
|
|
248
266
|
}
|
|
249
267
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
250
268
|
return {
|
|
251
269
|
baseUrl: connection.baseUrl,
|
|
252
270
|
authToken: connection.authToken,
|
|
253
|
-
connectionKind: "local"
|
|
271
|
+
connectionKind: "local",
|
|
272
|
+
serverProjectRoot: resolve2(projectRoot)
|
|
254
273
|
};
|
|
255
274
|
} catch (error) {
|
|
256
275
|
if (error instanceof Error) {
|
|
@@ -259,6 +278,28 @@ async function ensureServerForCli(projectRoot) {
|
|
|
259
278
|
throw error;
|
|
260
279
|
}
|
|
261
280
|
}
|
|
281
|
+
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
282
|
+
const repo = readRepoConnection(projectRoot);
|
|
283
|
+
const slug = repo?.project?.trim();
|
|
284
|
+
if (!slug)
|
|
285
|
+
return null;
|
|
286
|
+
try {
|
|
287
|
+
const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
|
|
288
|
+
headers: mergeHeaders(undefined, authToken)
|
|
289
|
+
});
|
|
290
|
+
if (!response.ok)
|
|
291
|
+
return null;
|
|
292
|
+
const payload = await response.json();
|
|
293
|
+
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
294
|
+
const checkout = project?.checkout && typeof project.checkout === "object" && !Array.isArray(project.checkout) ? project.checkout : null;
|
|
295
|
+
const path = typeof checkout?.path === "string" && checkout.path.trim() ? checkout.path.trim() : typeof project?.path === "string" && project.path.trim() ? project.path.trim() : null;
|
|
296
|
+
if (path)
|
|
297
|
+
writeRepoServerProjectRoot(projectRoot, path);
|
|
298
|
+
return path;
|
|
299
|
+
} catch {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
262
303
|
function mergeHeaders(headers, authToken) {
|
|
263
304
|
const merged = new Headers(headers);
|
|
264
305
|
if (authToken) {
|
|
@@ -283,9 +324,12 @@ function diagnosticMessage(payload) {
|
|
|
283
324
|
}
|
|
284
325
|
async function requestServerJson(context, pathname, init = {}) {
|
|
285
326
|
const server = await ensureServerForCli(context.projectRoot);
|
|
327
|
+
const headers = mergeHeaders(init.headers, server.authToken);
|
|
328
|
+
if (server.serverProjectRoot)
|
|
329
|
+
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
286
330
|
const response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
287
331
|
...init,
|
|
288
|
-
headers
|
|
332
|
+
headers
|
|
289
333
|
});
|
|
290
334
|
const text = await response.text();
|
|
291
335
|
const payload = text.trim().length > 0 ? (() => {
|
|
@@ -131,7 +131,8 @@ function readRepoConnection(projectRoot) {
|
|
|
131
131
|
return {
|
|
132
132
|
selected,
|
|
133
133
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
134
|
-
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
|
|
134
|
+
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
135
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
135
136
|
};
|
|
136
137
|
}
|
|
137
138
|
function writeRepoConnection(projectRoot, state) {
|
|
@@ -142,13 +143,19 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
142
143
|
if (!repo)
|
|
143
144
|
return null;
|
|
144
145
|
if (repo.selected === "local")
|
|
145
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" } };
|
|
146
|
+
return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
|
|
146
147
|
const global = readGlobalConnections(options);
|
|
147
148
|
const connection = global.connections[repo.selected];
|
|
148
149
|
if (!connection) {
|
|
149
150
|
throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
150
151
|
}
|
|
151
|
-
return { alias: repo.selected, connection };
|
|
152
|
+
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
153
|
+
}
|
|
154
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
155
|
+
const repo = readRepoConnection(projectRoot);
|
|
156
|
+
if (!repo)
|
|
157
|
+
return;
|
|
158
|
+
writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
|
|
152
159
|
}
|
|
153
160
|
|
|
154
161
|
// packages/cli/src/commands/_server-client.ts
|
|
@@ -188,17 +195,21 @@ async function ensureServerForCli(projectRoot) {
|
|
|
188
195
|
try {
|
|
189
196
|
const selected = resolveSelectedConnection(projectRoot);
|
|
190
197
|
if (selected?.connection.kind === "remote") {
|
|
198
|
+
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
199
|
+
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
191
200
|
return {
|
|
192
201
|
baseUrl: selected.connection.baseUrl,
|
|
193
|
-
authToken
|
|
194
|
-
connectionKind: "remote"
|
|
202
|
+
authToken,
|
|
203
|
+
connectionKind: "remote",
|
|
204
|
+
serverProjectRoot
|
|
195
205
|
};
|
|
196
206
|
}
|
|
197
207
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
198
208
|
return {
|
|
199
209
|
baseUrl: connection.baseUrl,
|
|
200
210
|
authToken: connection.authToken,
|
|
201
|
-
connectionKind: "local"
|
|
211
|
+
connectionKind: "local",
|
|
212
|
+
serverProjectRoot: resolve2(projectRoot)
|
|
202
213
|
};
|
|
203
214
|
} catch (error) {
|
|
204
215
|
if (error instanceof Error) {
|
|
@@ -207,6 +218,28 @@ async function ensureServerForCli(projectRoot) {
|
|
|
207
218
|
throw error;
|
|
208
219
|
}
|
|
209
220
|
}
|
|
221
|
+
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
222
|
+
const repo = readRepoConnection(projectRoot);
|
|
223
|
+
const slug = repo?.project?.trim();
|
|
224
|
+
if (!slug)
|
|
225
|
+
return null;
|
|
226
|
+
try {
|
|
227
|
+
const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
|
|
228
|
+
headers: mergeHeaders(undefined, authToken)
|
|
229
|
+
});
|
|
230
|
+
if (!response.ok)
|
|
231
|
+
return null;
|
|
232
|
+
const payload = await response.json();
|
|
233
|
+
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
234
|
+
const checkout = project?.checkout && typeof project.checkout === "object" && !Array.isArray(project.checkout) ? project.checkout : null;
|
|
235
|
+
const path = typeof checkout?.path === "string" && checkout.path.trim() ? checkout.path.trim() : typeof project?.path === "string" && project.path.trim() ? project.path.trim() : null;
|
|
236
|
+
if (path)
|
|
237
|
+
writeRepoServerProjectRoot(projectRoot, path);
|
|
238
|
+
return path;
|
|
239
|
+
} catch {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
210
243
|
function mergeHeaders(headers, authToken) {
|
|
211
244
|
const merged = new Headers(headers);
|
|
212
245
|
if (authToken) {
|
|
@@ -231,9 +264,12 @@ function diagnosticMessage(payload) {
|
|
|
231
264
|
}
|
|
232
265
|
async function requestServerJson(context, pathname, init = {}) {
|
|
233
266
|
const server = await ensureServerForCli(context.projectRoot);
|
|
267
|
+
const headers = mergeHeaders(init.headers, server.authToken);
|
|
268
|
+
if (server.serverProjectRoot)
|
|
269
|
+
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
234
270
|
const response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
235
271
|
...init,
|
|
236
|
-
headers
|
|
272
|
+
headers
|
|
237
273
|
});
|
|
238
274
|
const text = await response.text();
|
|
239
275
|
const payload = text.trim().length > 0 ? (() => {
|
|
@@ -307,22 +343,12 @@ async function switchServerProjectRootViaServer(context, projectRoot, options =
|
|
|
307
343
|
if (!switched) {
|
|
308
344
|
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);
|
|
309
345
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
const record = status;
|
|
315
|
-
if (record.projectRoot === projectRoot) {
|
|
316
|
-
return { ok: true, switched, status: record };
|
|
317
|
-
}
|
|
318
|
-
lastError = `server projectRoot=${String(record.projectRoot ?? "unknown")}`;
|
|
319
|
-
}
|
|
320
|
-
} catch (error) {
|
|
321
|
-
lastError = error;
|
|
322
|
-
}
|
|
323
|
-
await sleep(pollMs);
|
|
346
|
+
const record = switched && typeof switched === "object" && !Array.isArray(switched) ? switched : {};
|
|
347
|
+
if (record.ok === true) {
|
|
348
|
+
writeRepoServerProjectRoot(context.projectRoot, projectRoot);
|
|
349
|
+
return { ok: true, switched: record };
|
|
324
350
|
}
|
|
325
|
-
throw new CliError2(`Rig server
|
|
351
|
+
throw new CliError2(`Rig server rejected project-root scope ${projectRoot}: ${String(record.message ?? record.error ?? "unknown error")}`, 1);
|
|
326
352
|
}
|
|
327
353
|
async function ensureTaskLabelsViaServer(context) {
|
|
328
354
|
const payload = await requestServerJson(context, "/api/workspace/task-labels", { method: "POST" });
|
|
@@ -84,6 +84,11 @@ function readJsonFile(path) {
|
|
|
84
84
|
throw new CliError2(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1);
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
+
function writeJsonFile(path, value) {
|
|
88
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
89
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
90
|
+
`, "utf8");
|
|
91
|
+
}
|
|
87
92
|
function normalizeConnection(value) {
|
|
88
93
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
89
94
|
return null;
|
|
@@ -124,21 +129,31 @@ function readRepoConnection(projectRoot) {
|
|
|
124
129
|
return {
|
|
125
130
|
selected,
|
|
126
131
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
127
|
-
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
|
|
132
|
+
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
133
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
128
134
|
};
|
|
129
135
|
}
|
|
136
|
+
function writeRepoConnection(projectRoot, state) {
|
|
137
|
+
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
138
|
+
}
|
|
130
139
|
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
131
140
|
const repo = readRepoConnection(projectRoot);
|
|
132
141
|
if (!repo)
|
|
133
142
|
return null;
|
|
134
143
|
if (repo.selected === "local")
|
|
135
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" } };
|
|
144
|
+
return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
|
|
136
145
|
const global = readGlobalConnections(options);
|
|
137
146
|
const connection = global.connections[repo.selected];
|
|
138
147
|
if (!connection) {
|
|
139
148
|
throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
140
149
|
}
|
|
141
|
-
return { alias: repo.selected, connection };
|
|
150
|
+
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
151
|
+
}
|
|
152
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
153
|
+
const repo = readRepoConnection(projectRoot);
|
|
154
|
+
if (!repo)
|
|
155
|
+
return;
|
|
156
|
+
writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
|
|
142
157
|
}
|
|
143
158
|
|
|
144
159
|
// packages/cli/src/commands/_server-client.ts
|
|
@@ -171,17 +186,21 @@ async function ensureServerForCli(projectRoot) {
|
|
|
171
186
|
try {
|
|
172
187
|
const selected = resolveSelectedConnection(projectRoot);
|
|
173
188
|
if (selected?.connection.kind === "remote") {
|
|
189
|
+
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
190
|
+
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
174
191
|
return {
|
|
175
192
|
baseUrl: selected.connection.baseUrl,
|
|
176
|
-
authToken
|
|
177
|
-
connectionKind: "remote"
|
|
193
|
+
authToken,
|
|
194
|
+
connectionKind: "remote",
|
|
195
|
+
serverProjectRoot
|
|
178
196
|
};
|
|
179
197
|
}
|
|
180
198
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
181
199
|
return {
|
|
182
200
|
baseUrl: connection.baseUrl,
|
|
183
201
|
authToken: connection.authToken,
|
|
184
|
-
connectionKind: "local"
|
|
202
|
+
connectionKind: "local",
|
|
203
|
+
serverProjectRoot: resolve2(projectRoot)
|
|
185
204
|
};
|
|
186
205
|
} catch (error) {
|
|
187
206
|
if (error instanceof Error) {
|
|
@@ -190,6 +209,28 @@ async function ensureServerForCli(projectRoot) {
|
|
|
190
209
|
throw error;
|
|
191
210
|
}
|
|
192
211
|
}
|
|
212
|
+
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
213
|
+
const repo = readRepoConnection(projectRoot);
|
|
214
|
+
const slug = repo?.project?.trim();
|
|
215
|
+
if (!slug)
|
|
216
|
+
return null;
|
|
217
|
+
try {
|
|
218
|
+
const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
|
|
219
|
+
headers: mergeHeaders(undefined, authToken)
|
|
220
|
+
});
|
|
221
|
+
if (!response.ok)
|
|
222
|
+
return null;
|
|
223
|
+
const payload = await response.json();
|
|
224
|
+
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
225
|
+
const checkout = project?.checkout && typeof project.checkout === "object" && !Array.isArray(project.checkout) ? project.checkout : null;
|
|
226
|
+
const path = typeof checkout?.path === "string" && checkout.path.trim() ? checkout.path.trim() : typeof project?.path === "string" && project.path.trim() ? project.path.trim() : null;
|
|
227
|
+
if (path)
|
|
228
|
+
writeRepoServerProjectRoot(projectRoot, path);
|
|
229
|
+
return path;
|
|
230
|
+
} catch {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
193
234
|
function mergeHeaders(headers, authToken) {
|
|
194
235
|
const merged = new Headers(headers);
|
|
195
236
|
if (authToken) {
|
|
@@ -214,9 +255,12 @@ function diagnosticMessage(payload) {
|
|
|
214
255
|
}
|
|
215
256
|
async function requestServerJson(context, pathname, init = {}) {
|
|
216
257
|
const server = await ensureServerForCli(context.projectRoot);
|
|
258
|
+
const headers = mergeHeaders(init.headers, server.authToken);
|
|
259
|
+
if (server.serverProjectRoot)
|
|
260
|
+
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
217
261
|
const response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
218
262
|
...init,
|
|
219
|
-
headers
|
|
263
|
+
headers
|
|
220
264
|
});
|
|
221
265
|
const text = await response.text();
|
|
222
266
|
const payload = text.trim().length > 0 ? (() => {
|
package/dist/src/commands/run.js
CHANGED
|
@@ -108,6 +108,11 @@ function readJsonFile(path) {
|
|
|
108
108
|
throw new CliError2(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1);
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
|
+
function writeJsonFile(path, value) {
|
|
112
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
113
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
114
|
+
`, "utf8");
|
|
115
|
+
}
|
|
111
116
|
function normalizeConnection(value) {
|
|
112
117
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
113
118
|
return null;
|
|
@@ -148,21 +153,31 @@ function readRepoConnection(projectRoot) {
|
|
|
148
153
|
return {
|
|
149
154
|
selected,
|
|
150
155
|
project: typeof record.project === "string" ? record.project : undefined,
|
|
151
|
-
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
|
|
156
|
+
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
|
|
157
|
+
serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
|
|
152
158
|
};
|
|
153
159
|
}
|
|
160
|
+
function writeRepoConnection(projectRoot, state) {
|
|
161
|
+
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
162
|
+
}
|
|
154
163
|
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
155
164
|
const repo = readRepoConnection(projectRoot);
|
|
156
165
|
if (!repo)
|
|
157
166
|
return null;
|
|
158
167
|
if (repo.selected === "local")
|
|
159
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" } };
|
|
168
|
+
return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
|
|
160
169
|
const global = readGlobalConnections(options);
|
|
161
170
|
const connection = global.connections[repo.selected];
|
|
162
171
|
if (!connection) {
|
|
163
172
|
throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
|
|
164
173
|
}
|
|
165
|
-
return { alias: repo.selected, connection };
|
|
174
|
+
return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
|
|
175
|
+
}
|
|
176
|
+
function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
|
|
177
|
+
const repo = readRepoConnection(projectRoot);
|
|
178
|
+
if (!repo)
|
|
179
|
+
return;
|
|
180
|
+
writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
|
|
166
181
|
}
|
|
167
182
|
|
|
168
183
|
// packages/cli/src/commands/_server-client.ts
|
|
@@ -195,17 +210,21 @@ async function ensureServerForCli(projectRoot) {
|
|
|
195
210
|
try {
|
|
196
211
|
const selected = resolveSelectedConnection(projectRoot);
|
|
197
212
|
if (selected?.connection.kind === "remote") {
|
|
213
|
+
const authToken = readGitHubBearerTokenForRemote(projectRoot);
|
|
214
|
+
const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
|
|
198
215
|
return {
|
|
199
216
|
baseUrl: selected.connection.baseUrl,
|
|
200
|
-
authToken
|
|
201
|
-
connectionKind: "remote"
|
|
217
|
+
authToken,
|
|
218
|
+
connectionKind: "remote",
|
|
219
|
+
serverProjectRoot
|
|
202
220
|
};
|
|
203
221
|
}
|
|
204
222
|
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
205
223
|
return {
|
|
206
224
|
baseUrl: connection.baseUrl,
|
|
207
225
|
authToken: connection.authToken,
|
|
208
|
-
connectionKind: "local"
|
|
226
|
+
connectionKind: "local",
|
|
227
|
+
serverProjectRoot: resolve2(projectRoot)
|
|
209
228
|
};
|
|
210
229
|
} catch (error) {
|
|
211
230
|
if (error instanceof Error) {
|
|
@@ -214,6 +233,28 @@ async function ensureServerForCli(projectRoot) {
|
|
|
214
233
|
throw error;
|
|
215
234
|
}
|
|
216
235
|
}
|
|
236
|
+
async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
|
|
237
|
+
const repo = readRepoConnection(projectRoot);
|
|
238
|
+
const slug = repo?.project?.trim();
|
|
239
|
+
if (!slug)
|
|
240
|
+
return null;
|
|
241
|
+
try {
|
|
242
|
+
const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
|
|
243
|
+
headers: mergeHeaders(undefined, authToken)
|
|
244
|
+
});
|
|
245
|
+
if (!response.ok)
|
|
246
|
+
return null;
|
|
247
|
+
const payload = await response.json();
|
|
248
|
+
const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
|
|
249
|
+
const checkout = project?.checkout && typeof project.checkout === "object" && !Array.isArray(project.checkout) ? project.checkout : null;
|
|
250
|
+
const path = typeof checkout?.path === "string" && checkout.path.trim() ? checkout.path.trim() : typeof project?.path === "string" && project.path.trim() ? project.path.trim() : null;
|
|
251
|
+
if (path)
|
|
252
|
+
writeRepoServerProjectRoot(projectRoot, path);
|
|
253
|
+
return path;
|
|
254
|
+
} catch {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
217
258
|
function mergeHeaders(headers, authToken) {
|
|
218
259
|
const merged = new Headers(headers);
|
|
219
260
|
if (authToken) {
|
|
@@ -238,9 +279,12 @@ function diagnosticMessage(payload) {
|
|
|
238
279
|
}
|
|
239
280
|
async function requestServerJson(context, pathname, init = {}) {
|
|
240
281
|
const server = await ensureServerForCli(context.projectRoot);
|
|
282
|
+
const headers = mergeHeaders(init.headers, server.authToken);
|
|
283
|
+
if (server.serverProjectRoot)
|
|
284
|
+
headers.set("x-rig-project-root", server.serverProjectRoot);
|
|
241
285
|
const response = await fetch(`${server.baseUrl}${pathname}`, {
|
|
242
286
|
...init,
|
|
243
|
-
headers
|
|
287
|
+
headers
|
|
244
288
|
});
|
|
245
289
|
const text = await response.text();
|
|
246
290
|
const payload = text.trim().length > 0 ? (() => {
|
|
@@ -365,6 +409,8 @@ async function buildRunPiEventsWebSocketUrl(context, runId) {
|
|
|
365
409
|
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
366
410
|
if (server.authToken)
|
|
367
411
|
url.searchParams.set("token", server.authToken);
|
|
412
|
+
if (server.serverProjectRoot)
|
|
413
|
+
url.searchParams.set("rigProjectRoot", server.serverProjectRoot);
|
|
368
414
|
return url.toString();
|
|
369
415
|
}
|
|
370
416
|
|