@h-rig/cli 0.0.6-alpha.13 → 0.0.6-alpha.15
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 +710 -226
- package/dist/src/commands/_doctor-checks.js +7 -20
- package/dist/src/commands/_operator-surface.js +157 -0
- package/dist/src/commands/_operator-view.js +160 -51
- package/dist/src/commands/_preflight.js +30 -26
- package/dist/src/commands/_server-client.js +46 -22
- package/dist/src/commands/_snapshot-upload.js +7 -20
- package/dist/src/commands/_task-picker.js +21 -13
- package/dist/src/commands/agent.js +1 -0
- package/dist/src/commands/doctor.js +7 -20
- package/dist/src/commands/github.js +9 -22
- package/dist/src/commands/init.js +183 -44
- package/dist/src/commands/queue.js +1 -0
- package/dist/src/commands/run.js +172 -76
- package/dist/src/commands/server.js +7 -20
- package/dist/src/commands/setup.js +7 -20
- package/dist/src/commands/task-run-driver.js +446 -53
- package/dist/src/commands/task.js +231 -98
- package/dist/src/commands.js +702 -218
- package/dist/src/index.js +710 -226
- package/package.json +5 -5
package/dist/src/commands/run.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/cli/src/commands/run.ts
|
|
3
|
-
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
4
|
-
import { resolve as resolve3 } from "path";
|
|
5
3
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
6
4
|
|
|
7
5
|
// packages/cli/src/runner.ts
|
|
@@ -54,9 +52,7 @@ Usage: ${usage}`);
|
|
|
54
52
|
// packages/cli/src/commands/run.ts
|
|
55
53
|
import {
|
|
56
54
|
listAuthorityRuns,
|
|
57
|
-
readAuthorityRun
|
|
58
|
-
readJsonlFile,
|
|
59
|
-
resolveAuthorityRunDir
|
|
55
|
+
readAuthorityRun
|
|
60
56
|
} from "@rig/runtime/control-plane/authority-files";
|
|
61
57
|
import {
|
|
62
58
|
cleanupRunState,
|
|
@@ -85,7 +81,6 @@ function parsePositiveInt(value, option, fallback) {
|
|
|
85
81
|
}
|
|
86
82
|
|
|
87
83
|
// packages/cli/src/commands/_server-client.ts
|
|
88
|
-
import { spawnSync } from "child_process";
|
|
89
84
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
90
85
|
import { resolve as resolve2 } from "path";
|
|
91
86
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
@@ -173,7 +168,7 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
173
168
|
}
|
|
174
169
|
|
|
175
170
|
// packages/cli/src/commands/_server-client.ts
|
|
176
|
-
var
|
|
171
|
+
var scopedGitHubBearerTokens = new Map;
|
|
177
172
|
function cleanToken(value) {
|
|
178
173
|
const trimmed = value?.trim();
|
|
179
174
|
return trimmed ? trimmed : null;
|
|
@@ -190,25 +185,13 @@ function readPrivateRemoteSessionToken(projectRoot) {
|
|
|
190
185
|
}
|
|
191
186
|
}
|
|
192
187
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
193
|
-
|
|
194
|
-
|
|
188
|
+
const scopedKey = resolve2(projectRoot);
|
|
189
|
+
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
190
|
+
return scopedGitHubBearerTokens.get(scopedKey) ?? null;
|
|
195
191
|
const privateSession = readPrivateRemoteSessionToken(projectRoot);
|
|
196
|
-
if (privateSession)
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
|
|
201
|
-
if (envToken) {
|
|
202
|
-
cachedGitHubBearerToken = envToken;
|
|
203
|
-
return cachedGitHubBearerToken;
|
|
204
|
-
}
|
|
205
|
-
const result = spawnSync("gh", ["auth", "token"], {
|
|
206
|
-
encoding: "utf8",
|
|
207
|
-
timeout: 5000,
|
|
208
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
209
|
-
});
|
|
210
|
-
cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
|
|
211
|
-
return cachedGitHubBearerToken;
|
|
192
|
+
if (privateSession)
|
|
193
|
+
return privateSession;
|
|
194
|
+
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
212
195
|
}
|
|
213
196
|
async function ensureServerForCli(projectRoot) {
|
|
214
197
|
try {
|
|
@@ -289,6 +272,15 @@ async function getRunLogsViaServer(context, runId, options = {}) {
|
|
|
289
272
|
const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
|
|
290
273
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { entries: [] };
|
|
291
274
|
}
|
|
275
|
+
async function getRunTimelineViaServer(context, runId, options = {}) {
|
|
276
|
+
const url = new URL(`http://rig.local/api/runs/${encodeURIComponent(runId)}/timeline`);
|
|
277
|
+
if (options.limit !== undefined)
|
|
278
|
+
url.searchParams.set("limit", String(options.limit));
|
|
279
|
+
if (options.cursor)
|
|
280
|
+
url.searchParams.set("cursor", options.cursor);
|
|
281
|
+
const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
|
|
282
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { entries: [] };
|
|
283
|
+
}
|
|
292
284
|
async function stopRunViaServer(context, runId) {
|
|
293
285
|
const payload = await requestServerJson(context, "/api/runs/stop", {
|
|
294
286
|
method: "POST",
|
|
@@ -306,9 +298,8 @@ async function steerRunViaServer(context, runId, message) {
|
|
|
306
298
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { ok: true };
|
|
307
299
|
}
|
|
308
300
|
|
|
309
|
-
// packages/cli/src/commands/_operator-
|
|
301
|
+
// packages/cli/src/commands/_operator-surface.ts
|
|
310
302
|
import { createInterface } from "readline";
|
|
311
|
-
var TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
|
|
312
303
|
var CANONICAL_STAGES = [
|
|
313
304
|
"Connect",
|
|
314
305
|
"GitHub/task sync",
|
|
@@ -323,18 +314,121 @@ var CANONICAL_STAGES = [
|
|
|
323
314
|
"Merge",
|
|
324
315
|
"Complete"
|
|
325
316
|
];
|
|
317
|
+
function logDetail(log) {
|
|
318
|
+
return typeof log.detail === "string" ? log.detail.trim() : "";
|
|
319
|
+
}
|
|
320
|
+
function entryId(entry, fallback) {
|
|
321
|
+
return typeof entry.id === "string" && entry.id.trim() ? entry.id : fallback;
|
|
322
|
+
}
|
|
326
323
|
function renderOperatorSnapshot(snapshot) {
|
|
327
324
|
const run = snapshot.run.run && typeof snapshot.run.run === "object" ? snapshot.run.run : snapshot.run;
|
|
328
325
|
const runId = String(run.runId ?? run.id ?? "run");
|
|
329
326
|
const status = String(run.status ?? "unknown");
|
|
330
327
|
const logs = snapshot.logs ?? [];
|
|
328
|
+
const latestByStage = new Map;
|
|
329
|
+
for (const log of logs) {
|
|
330
|
+
const title = String(log.title ?? "").toLowerCase();
|
|
331
|
+
const stageName = String(log.stage ?? "").toLowerCase();
|
|
332
|
+
const stage = CANONICAL_STAGES.find((candidate) => candidate.toLowerCase() === title || candidate.toLowerCase() === stageName);
|
|
333
|
+
if (stage)
|
|
334
|
+
latestByStage.set(stage, log);
|
|
335
|
+
}
|
|
331
336
|
const stageLines = CANONICAL_STAGES.flatMap((stage) => {
|
|
332
|
-
const match =
|
|
333
|
-
return match ? [`${stage}: ${String(match.status ?? status)}`] : [];
|
|
337
|
+
const match = latestByStage.get(stage);
|
|
338
|
+
return match ? [`${stage}: ${String(match.status ?? status)}${logDetail(match) ? ` \u2014 ${logDetail(match)}` : ""}`] : [];
|
|
334
339
|
});
|
|
335
340
|
return [`Rig run ${runId}: ${status}`, ...stageLines].join(`
|
|
336
341
|
`);
|
|
337
342
|
}
|
|
343
|
+
function createPiRunStreamRenderer(output = process.stdout) {
|
|
344
|
+
let lastSnapshot = "";
|
|
345
|
+
const assistantTextById = new Map;
|
|
346
|
+
const seenTimeline = new Set;
|
|
347
|
+
const seenLogs = new Set;
|
|
348
|
+
const writeLine = (line) => output.write(`${line}
|
|
349
|
+
`);
|
|
350
|
+
return {
|
|
351
|
+
renderSnapshot(snapshot) {
|
|
352
|
+
const rendered = renderOperatorSnapshot(snapshot);
|
|
353
|
+
if (rendered && rendered !== lastSnapshot) {
|
|
354
|
+
writeLine(rendered);
|
|
355
|
+
lastSnapshot = rendered;
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
renderTimeline(entries) {
|
|
359
|
+
for (const [index, entry] of entries.entries()) {
|
|
360
|
+
const id = entryId(entry, `timeline:${index}:${String(entry.cursor ?? "")}`);
|
|
361
|
+
if (entry.type === "assistant_message" && typeof entry.text === "string") {
|
|
362
|
+
const text = entry.text;
|
|
363
|
+
const previousText = assistantTextById.get(id) ?? "";
|
|
364
|
+
if (text.startsWith(previousText)) {
|
|
365
|
+
const delta = text.slice(previousText.length);
|
|
366
|
+
if (delta)
|
|
367
|
+
output.write(delta);
|
|
368
|
+
} else if (text.trim() && text !== previousText) {
|
|
369
|
+
writeLine(`
|
|
370
|
+
[Pi assistant]`);
|
|
371
|
+
output.write(text);
|
|
372
|
+
}
|
|
373
|
+
assistantTextById.set(id, text);
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
if (seenTimeline.has(id))
|
|
377
|
+
continue;
|
|
378
|
+
seenTimeline.add(id);
|
|
379
|
+
if (entry.type === "tool_execution_start" || entry.type === "tool_execution_update" || entry.type === "tool_execution_end" || entry.type === "mcp_tool_call") {
|
|
380
|
+
writeLine(`[Pi tool] ${String(entry.toolName ?? entry.name ?? entry.title ?? entry.type)} ${String(entry.status ?? entry.state ?? "")}`.trim());
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
if (entry.type === "timeline_warning") {
|
|
384
|
+
writeLine(`[Rig timeline] ${String(entry.detail ?? entry.message ?? "timeline unavailable")}`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
renderLogs(entries) {
|
|
389
|
+
for (const [index, entry] of entries.entries()) {
|
|
390
|
+
const id = entryId(entry, `log:${index}:${String(entry.createdAt ?? "")}:${String(entry.title ?? "")}`);
|
|
391
|
+
if (seenLogs.has(id))
|
|
392
|
+
continue;
|
|
393
|
+
seenLogs.add(id);
|
|
394
|
+
const title = String(entry.title ?? "");
|
|
395
|
+
if (CANONICAL_STAGES.some((stage) => stage.toLowerCase() === title.toLowerCase()))
|
|
396
|
+
continue;
|
|
397
|
+
const detail = logDetail(entry);
|
|
398
|
+
if (!detail)
|
|
399
|
+
continue;
|
|
400
|
+
writeLine(`[${title || "Rig log"}] ${detail}`);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
function createOperatorSurface(options = {}) {
|
|
406
|
+
const input = options.input ?? process.stdin;
|
|
407
|
+
const output = options.output ?? process.stdout;
|
|
408
|
+
const errorOutput = options.errorOutput ?? process.stderr;
|
|
409
|
+
const renderer = createPiRunStreamRenderer(output);
|
|
410
|
+
const writeLine = (line) => output.write(`${line}
|
|
411
|
+
`);
|
|
412
|
+
return {
|
|
413
|
+
mode: "pi-compatible-text",
|
|
414
|
+
...renderer,
|
|
415
|
+
info: writeLine,
|
|
416
|
+
error: (message) => errorOutput.write(`${message}
|
|
417
|
+
`),
|
|
418
|
+
attachCommandInput(handler) {
|
|
419
|
+
if (options.interactive === false || !input.isTTY)
|
|
420
|
+
return null;
|
|
421
|
+
const rl = createInterface({ input, output: process.stdout, terminal: false });
|
|
422
|
+
rl.on("line", (line) => {
|
|
423
|
+
Promise.resolve(handler(line)).catch((error) => writeLine(`Operator command failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
424
|
+
});
|
|
425
|
+
return { close: () => rl.close() };
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// packages/cli/src/commands/_operator-view.ts
|
|
431
|
+
var TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
|
|
338
432
|
function runStatusFromPayload(payload) {
|
|
339
433
|
const run = payload.run && typeof payload.run === "object" && !Array.isArray(payload.run) ? payload.run : payload;
|
|
340
434
|
return String(run.status ?? "unknown").toLowerCase();
|
|
@@ -356,11 +450,22 @@ async function applyOperatorCommand(context, input, deps = {}) {
|
|
|
356
450
|
await (deps.steer ?? steerRunViaServer)(context, input.runId, userMessage);
|
|
357
451
|
return { action: "continue", message: "Steering message queued." };
|
|
358
452
|
}
|
|
359
|
-
async function readOperatorSnapshot(context, runId) {
|
|
453
|
+
async function readOperatorSnapshot(context, runId, options = {}) {
|
|
360
454
|
const run = await getRunDetailsViaServer(context, runId);
|
|
361
455
|
const logsPage = await getRunLogsViaServer(context, runId, { limit: 100 });
|
|
362
|
-
const
|
|
363
|
-
|
|
456
|
+
const timelinePage = await getRunTimelineViaServer(context, runId, { limit: 200, ...options.timelineCursor ? { cursor: options.timelineCursor } : {} }).catch((error) => ({
|
|
457
|
+
entries: [{
|
|
458
|
+
id: `timeline-unavailable:${runId}`,
|
|
459
|
+
type: "timeline_warning",
|
|
460
|
+
detail: `Selected Rig server did not provide run timeline events: ${error instanceof Error ? error.message : String(error)}`,
|
|
461
|
+
createdAt: new Date().toISOString()
|
|
462
|
+
}],
|
|
463
|
+
nextCursor: options.timelineCursor ?? null
|
|
464
|
+
}));
|
|
465
|
+
const logs = Array.isArray(logsPage.entries) ? logsPage.entries.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))).toReversed() : [];
|
|
466
|
+
const timeline = Array.isArray(timelinePage.entries) ? timelinePage.entries.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
|
|
467
|
+
const timelineCursor = typeof timelinePage.nextCursor === "string" ? timelinePage.nextCursor : options.timelineCursor ?? null;
|
|
468
|
+
return { run, logs, timeline, timelineCursor, rendered: renderOperatorSnapshot({ run, logs, timeline }) };
|
|
364
469
|
}
|
|
365
470
|
async function attachRunOperatorView(context, input) {
|
|
366
471
|
let steered = false;
|
|
@@ -368,40 +473,41 @@ async function attachRunOperatorView(context, input) {
|
|
|
368
473
|
await steerRunViaServer(context, input.runId, input.message.trim());
|
|
369
474
|
steered = true;
|
|
370
475
|
}
|
|
476
|
+
const surface = createOperatorSurface({ interactive: input.interactive !== false });
|
|
371
477
|
let snapshot = await readOperatorSnapshot(context, input.runId);
|
|
372
478
|
if (context.outputMode === "text") {
|
|
373
|
-
|
|
479
|
+
surface.renderSnapshot(snapshot);
|
|
480
|
+
surface.renderTimeline(snapshot.timeline);
|
|
481
|
+
surface.renderLogs(snapshot.logs);
|
|
374
482
|
if (steered)
|
|
375
|
-
|
|
483
|
+
surface.info("Steering message queued.");
|
|
376
484
|
}
|
|
377
485
|
let detached = false;
|
|
378
|
-
let
|
|
486
|
+
let commandInput = null;
|
|
379
487
|
if (input.follow && !input.once && context.outputMode === "text") {
|
|
380
488
|
if (input.interactive !== false && process.stdin.isTTY) {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
}
|
|
391
|
-
}).catch((error) => console.log(`Operator command failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
489
|
+
surface.info("Controls: /user <message>, /stop, /detach");
|
|
490
|
+
commandInput = surface.attachCommandInput(async (line) => {
|
|
491
|
+
const result = await applyOperatorCommand(context, { runId: input.runId, line });
|
|
492
|
+
if (result.message)
|
|
493
|
+
surface.info(result.message);
|
|
494
|
+
if (result.action === "detach" || result.action === "stopped") {
|
|
495
|
+
detached = true;
|
|
496
|
+
commandInput?.close();
|
|
497
|
+
}
|
|
392
498
|
});
|
|
393
499
|
}
|
|
394
|
-
let lastRendered = snapshot.rendered;
|
|
395
500
|
const pollMs = Math.max(250, Math.trunc(input.pollMs ?? 2000));
|
|
501
|
+
let timelineCursor = snapshot.timelineCursor;
|
|
396
502
|
while (!detached && !TERMINAL_RUN_STATUSES.has(runStatusFromPayload(snapshot.run))) {
|
|
397
503
|
await Bun.sleep(pollMs);
|
|
398
|
-
snapshot = await readOperatorSnapshot(context, input.runId);
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
504
|
+
snapshot = await readOperatorSnapshot(context, input.runId, { timelineCursor });
|
|
505
|
+
timelineCursor = snapshot.timelineCursor;
|
|
506
|
+
surface.renderSnapshot(snapshot);
|
|
507
|
+
surface.renderTimeline(snapshot.timeline);
|
|
508
|
+
surface.renderLogs(snapshot.logs);
|
|
403
509
|
}
|
|
404
|
-
|
|
510
|
+
commandInput?.close();
|
|
405
511
|
}
|
|
406
512
|
return { ...snapshot, steered, detached };
|
|
407
513
|
}
|
|
@@ -575,34 +681,24 @@ async function executeRun(context, args) {
|
|
|
575
681
|
if (!run.value) {
|
|
576
682
|
throw new CliError2("run timeline requires --run <id>.");
|
|
577
683
|
}
|
|
578
|
-
const
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
return events2;
|
|
587
|
-
};
|
|
588
|
-
const events = printEvents();
|
|
684
|
+
const renderer = createPiRunStreamRenderer();
|
|
685
|
+
let cursor = null;
|
|
686
|
+
const page = await getRunTimelineViaServer(context, run.value, { limit: 500 });
|
|
687
|
+
const events = Array.isArray(page.entries) ? page.entries.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
|
|
688
|
+
cursor = typeof page.nextCursor === "string" ? page.nextCursor : null;
|
|
689
|
+
if (context.outputMode === "text") {
|
|
690
|
+
renderer.renderTimeline(events);
|
|
691
|
+
}
|
|
589
692
|
if (follow.value && context.outputMode === "text") {
|
|
590
|
-
let lastLength = existsSync3(timelinePath) ? readFileSync3(timelinePath, "utf8").length : 0;
|
|
591
693
|
while (true) {
|
|
592
694
|
await Bun.sleep(1000);
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
continue;
|
|
598
|
-
const delta = next.slice(lastLength);
|
|
599
|
-
lastLength = next.length;
|
|
600
|
-
for (const line of delta.split(/\r?\n/).map((entry) => entry.trim()).filter(Boolean)) {
|
|
601
|
-
console.log(line);
|
|
602
|
-
}
|
|
695
|
+
const nextPage = await getRunTimelineViaServer(context, run.value, { limit: 500, ...cursor ? { cursor } : {} });
|
|
696
|
+
const nextEvents = Array.isArray(nextPage.entries) ? nextPage.entries.filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry))) : [];
|
|
697
|
+
cursor = typeof nextPage.nextCursor === "string" ? nextPage.nextCursor : cursor;
|
|
698
|
+
renderer.renderTimeline(nextEvents);
|
|
603
699
|
}
|
|
604
700
|
}
|
|
605
|
-
return { ok: true, group: "run", command, details: { runId: run.value, events } };
|
|
701
|
+
return { ok: true, group: "run", command, details: { runId: run.value, events, cursor } };
|
|
606
702
|
}
|
|
607
703
|
case "attach": {
|
|
608
704
|
let pending = rest;
|
|
@@ -61,7 +61,6 @@ function normalizeRuntimeAdapter(value) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
// packages/cli/src/commands/_server-client.ts
|
|
64
|
-
import { spawnSync } from "child_process";
|
|
65
64
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
66
65
|
import { resolve as resolve2 } from "path";
|
|
67
66
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
@@ -149,7 +148,7 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
149
148
|
}
|
|
150
149
|
|
|
151
150
|
// packages/cli/src/commands/_server-client.ts
|
|
152
|
-
var
|
|
151
|
+
var scopedGitHubBearerTokens = new Map;
|
|
153
152
|
function cleanToken(value) {
|
|
154
153
|
const trimmed = value?.trim();
|
|
155
154
|
return trimmed ? trimmed : null;
|
|
@@ -166,25 +165,13 @@ function readPrivateRemoteSessionToken(projectRoot) {
|
|
|
166
165
|
}
|
|
167
166
|
}
|
|
168
167
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
169
|
-
|
|
170
|
-
|
|
168
|
+
const scopedKey = resolve2(projectRoot);
|
|
169
|
+
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
170
|
+
return scopedGitHubBearerTokens.get(scopedKey) ?? null;
|
|
171
171
|
const privateSession = readPrivateRemoteSessionToken(projectRoot);
|
|
172
|
-
if (privateSession)
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
|
|
177
|
-
if (envToken) {
|
|
178
|
-
cachedGitHubBearerToken = envToken;
|
|
179
|
-
return cachedGitHubBearerToken;
|
|
180
|
-
}
|
|
181
|
-
const result = spawnSync("gh", ["auth", "token"], {
|
|
182
|
-
encoding: "utf8",
|
|
183
|
-
timeout: 5000,
|
|
184
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
185
|
-
});
|
|
186
|
-
cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
|
|
187
|
-
return cachedGitHubBearerToken;
|
|
172
|
+
if (privateSession)
|
|
173
|
+
return privateSession;
|
|
174
|
+
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
188
175
|
}
|
|
189
176
|
async function ensureServerForCli(projectRoot) {
|
|
190
177
|
try {
|
|
@@ -258,11 +258,10 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
// packages/cli/src/commands/_server-client.ts
|
|
261
|
-
import { spawnSync } from "child_process";
|
|
262
261
|
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
263
262
|
import { resolve as resolve4 } from "path";
|
|
264
263
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
265
|
-
var
|
|
264
|
+
var scopedGitHubBearerTokens = new Map;
|
|
266
265
|
function cleanToken(value) {
|
|
267
266
|
const trimmed = value?.trim();
|
|
268
267
|
return trimmed ? trimmed : null;
|
|
@@ -279,25 +278,13 @@ function readPrivateRemoteSessionToken(projectRoot) {
|
|
|
279
278
|
}
|
|
280
279
|
}
|
|
281
280
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
282
|
-
|
|
283
|
-
|
|
281
|
+
const scopedKey = resolve4(projectRoot);
|
|
282
|
+
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
283
|
+
return scopedGitHubBearerTokens.get(scopedKey) ?? null;
|
|
284
284
|
const privateSession = readPrivateRemoteSessionToken(projectRoot);
|
|
285
|
-
if (privateSession)
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}
|
|
289
|
-
const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
|
|
290
|
-
if (envToken) {
|
|
291
|
-
cachedGitHubBearerToken = envToken;
|
|
292
|
-
return cachedGitHubBearerToken;
|
|
293
|
-
}
|
|
294
|
-
const result = spawnSync("gh", ["auth", "token"], {
|
|
295
|
-
encoding: "utf8",
|
|
296
|
-
timeout: 5000,
|
|
297
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
298
|
-
});
|
|
299
|
-
cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
|
|
300
|
-
return cachedGitHubBearerToken;
|
|
285
|
+
if (privateSession)
|
|
286
|
+
return privateSession;
|
|
287
|
+
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
301
288
|
}
|
|
302
289
|
async function ensureServerForCli(projectRoot) {
|
|
303
290
|
try {
|