@h-rig/cli 0.0.6-alpha.13 → 0.0.6-alpha.14
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
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/cli/src/commands/_server-client.ts
|
|
3
|
-
import { spawnSync } from "child_process";
|
|
4
3
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
5
4
|
import { resolve as resolve2 } from "path";
|
|
6
5
|
|
|
@@ -99,13 +98,14 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
99
98
|
}
|
|
100
99
|
|
|
101
100
|
// packages/cli/src/commands/_server-client.ts
|
|
102
|
-
var
|
|
101
|
+
var scopedGitHubBearerTokens = new Map;
|
|
103
102
|
function cleanToken(value) {
|
|
104
103
|
const trimmed = value?.trim();
|
|
105
104
|
return trimmed ? trimmed : null;
|
|
106
105
|
}
|
|
107
|
-
function setGitHubBearerTokenForCurrentProcess(token) {
|
|
108
|
-
|
|
106
|
+
function setGitHubBearerTokenForCurrentProcess(token, projectRoot) {
|
|
107
|
+
const scopedKey = resolve2(projectRoot ?? process.cwd());
|
|
108
|
+
scopedGitHubBearerTokens.set(scopedKey, cleanToken(token ?? undefined));
|
|
109
109
|
}
|
|
110
110
|
function readPrivateRemoteSessionToken(projectRoot) {
|
|
111
111
|
const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
|
|
@@ -119,25 +119,13 @@ function readPrivateRemoteSessionToken(projectRoot) {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
const scopedKey = resolve2(projectRoot);
|
|
123
|
+
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
124
|
+
return scopedGitHubBearerTokens.get(scopedKey) ?? null;
|
|
124
125
|
const privateSession = readPrivateRemoteSessionToken(projectRoot);
|
|
125
|
-
if (privateSession)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
|
|
130
|
-
if (envToken) {
|
|
131
|
-
cachedGitHubBearerToken = envToken;
|
|
132
|
-
return cachedGitHubBearerToken;
|
|
133
|
-
}
|
|
134
|
-
const result = spawnSync("gh", ["auth", "token"], {
|
|
135
|
-
encoding: "utf8",
|
|
136
|
-
timeout: 5000,
|
|
137
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
138
|
-
});
|
|
139
|
-
cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
|
|
140
|
-
return cachedGitHubBearerToken;
|
|
126
|
+
if (privateSession)
|
|
127
|
+
return privateSession;
|
|
128
|
+
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
141
129
|
}
|
|
142
130
|
async function ensureServerForCli(projectRoot) {
|
|
143
131
|
try {
|
|
@@ -335,6 +323,37 @@ async function getRunLogsViaServer(context, runId, options = {}) {
|
|
|
335
323
|
const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
|
|
336
324
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { entries: [] };
|
|
337
325
|
}
|
|
326
|
+
async function getRunTimelineViaServer(context, runId, options = {}) {
|
|
327
|
+
const url = new URL(`http://rig.local/api/runs/${encodeURIComponent(runId)}/timeline`);
|
|
328
|
+
if (options.limit !== undefined)
|
|
329
|
+
url.searchParams.set("limit", String(options.limit));
|
|
330
|
+
if (options.cursor)
|
|
331
|
+
url.searchParams.set("cursor", options.cursor);
|
|
332
|
+
const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
|
|
333
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { entries: [] };
|
|
334
|
+
}
|
|
335
|
+
async function ensureTaskLabelsViaServer(context) {
|
|
336
|
+
const payload = await requestServerJson(context, "/api/workspace/task-labels", { method: "POST" });
|
|
337
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
338
|
+
}
|
|
339
|
+
async function listGitHubProjectsViaServer(context, owner) {
|
|
340
|
+
const url = new URL("http://rig.local/api/github/projects");
|
|
341
|
+
url.searchParams.set("owner", owner);
|
|
342
|
+
const payload = await requestServerJson(context, `${url.pathname}${url.search}`);
|
|
343
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { projects: [] };
|
|
344
|
+
}
|
|
345
|
+
async function getGitHubProjectStatusFieldViaServer(context, projectId) {
|
|
346
|
+
const payload = await requestServerJson(context, `/api/github/projects/${encodeURIComponent(projectId)}/status-field`);
|
|
347
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
348
|
+
}
|
|
349
|
+
async function updateWorkspaceTaskViaServer(context, input) {
|
|
350
|
+
const payload = await requestServerJson(context, "/api/tasks/update", {
|
|
351
|
+
method: "POST",
|
|
352
|
+
headers: { "content-type": "application/json" },
|
|
353
|
+
body: JSON.stringify(input)
|
|
354
|
+
});
|
|
355
|
+
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { ok: true };
|
|
356
|
+
}
|
|
338
357
|
async function stopRunViaServer(context, runId) {
|
|
339
358
|
const payload = await requestServerJson(context, "/api/runs/stop", {
|
|
340
359
|
method: "POST",
|
|
@@ -383,6 +402,7 @@ async function submitTaskRunViaServer(context, input) {
|
|
|
383
402
|
return { runId };
|
|
384
403
|
}
|
|
385
404
|
export {
|
|
405
|
+
updateWorkspaceTaskViaServer,
|
|
386
406
|
switchServerProjectRootViaServer,
|
|
387
407
|
submitTaskRunViaServer,
|
|
388
408
|
stopRunViaServer,
|
|
@@ -394,9 +414,13 @@ export {
|
|
|
394
414
|
prepareRemoteCheckoutViaServer,
|
|
395
415
|
postGitHubTokenViaServer,
|
|
396
416
|
listWorkspaceTasksViaServer,
|
|
417
|
+
listGitHubProjectsViaServer,
|
|
397
418
|
getWorkspaceTaskViaServer,
|
|
419
|
+
getRunTimelineViaServer,
|
|
398
420
|
getRunLogsViaServer,
|
|
399
421
|
getRunDetailsViaServer,
|
|
422
|
+
getGitHubProjectStatusFieldViaServer,
|
|
400
423
|
getGitHubAuthStatusViaServer,
|
|
424
|
+
ensureTaskLabelsViaServer,
|
|
401
425
|
ensureServerForCli
|
|
402
426
|
};
|
|
@@ -4,7 +4,6 @@ import { mkdir, readdir, readFile, writeFile } from "fs/promises";
|
|
|
4
4
|
import { dirname as dirname2, resolve as resolve3, relative, sep } from "path";
|
|
5
5
|
|
|
6
6
|
// packages/cli/src/commands/_server-client.ts
|
|
7
|
-
import { spawnSync } from "child_process";
|
|
8
7
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
9
8
|
import { resolve as resolve2 } from "path";
|
|
10
9
|
|
|
@@ -103,7 +102,7 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
103
102
|
}
|
|
104
103
|
|
|
105
104
|
// packages/cli/src/commands/_server-client.ts
|
|
106
|
-
var
|
|
105
|
+
var scopedGitHubBearerTokens = new Map;
|
|
107
106
|
function cleanToken(value) {
|
|
108
107
|
const trimmed = value?.trim();
|
|
109
108
|
return trimmed ? trimmed : null;
|
|
@@ -120,25 +119,13 @@ function readPrivateRemoteSessionToken(projectRoot) {
|
|
|
120
119
|
}
|
|
121
120
|
}
|
|
122
121
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
const scopedKey = resolve2(projectRoot);
|
|
123
|
+
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
124
|
+
return scopedGitHubBearerTokens.get(scopedKey) ?? null;
|
|
125
125
|
const privateSession = readPrivateRemoteSessionToken(projectRoot);
|
|
126
|
-
if (privateSession)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
|
|
131
|
-
if (envToken) {
|
|
132
|
-
cachedGitHubBearerToken = envToken;
|
|
133
|
-
return cachedGitHubBearerToken;
|
|
134
|
-
}
|
|
135
|
-
const result = spawnSync("gh", ["auth", "token"], {
|
|
136
|
-
encoding: "utf8",
|
|
137
|
-
timeout: 5000,
|
|
138
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
139
|
-
});
|
|
140
|
-
cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
|
|
141
|
-
return cachedGitHubBearerToken;
|
|
126
|
+
if (privateSession)
|
|
127
|
+
return privateSession;
|
|
128
|
+
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
142
129
|
}
|
|
143
130
|
async function ensureServerForCli(projectRoot) {
|
|
144
131
|
try {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
// packages/cli/src/commands/
|
|
3
|
-
import { createInterface } from "readline/promises";
|
|
2
|
+
// packages/cli/src/commands/_operator-surface.ts
|
|
3
|
+
import { createInterface as createPromptInterface } from "readline/promises";
|
|
4
4
|
function taskId(task) {
|
|
5
5
|
return typeof task.id === "string" && task.id.trim() ? task.id : "<unknown>";
|
|
6
6
|
}
|
|
@@ -13,6 +13,19 @@ function taskStatus(task) {
|
|
|
13
13
|
function renderTaskPickerRows(tasks) {
|
|
14
14
|
return tasks.map((task, index) => `${index + 1}. ${taskId(task)} \xB7 ${taskStatus(task)} \xB7 ${taskTitle(task)}`);
|
|
15
15
|
}
|
|
16
|
+
async function promptForTaskSelection(question) {
|
|
17
|
+
const rl = createPromptInterface({ input: process.stdin, output: process.stdout });
|
|
18
|
+
try {
|
|
19
|
+
return await rl.question(question);
|
|
20
|
+
} finally {
|
|
21
|
+
rl.close();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// packages/cli/src/commands/_task-picker.ts
|
|
26
|
+
function taskId2(task) {
|
|
27
|
+
return typeof task.id === "string" && task.id.trim() ? task.id : "<unknown>";
|
|
28
|
+
}
|
|
16
29
|
async function selectTaskWithTextPicker(tasks, io = {}) {
|
|
17
30
|
if (tasks.length === 0)
|
|
18
31
|
return null;
|
|
@@ -22,17 +35,12 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
|
|
|
22
35
|
if (!isTty) {
|
|
23
36
|
throw new Error("task run requires an interactive terminal to pick a task; pass --task <id>, --next, or --detach with a task id.");
|
|
24
37
|
}
|
|
25
|
-
const prompt = io.prompt ??
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
} finally {
|
|
30
|
-
rl.close();
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
console.log("Select Rig task:");
|
|
38
|
+
const prompt = io.prompt ?? promptForTaskSelection;
|
|
39
|
+
const renderer = io.renderer ?? { writeLine: (line) => process.stdout.write(`${line}
|
|
40
|
+
`) };
|
|
41
|
+
renderer.writeLine("Select Rig task:");
|
|
34
42
|
for (const row of renderTaskPickerRows(tasks))
|
|
35
|
-
|
|
43
|
+
renderer.writeLine(` ${row}`);
|
|
36
44
|
const answer = (await prompt(`Task [1-${tasks.length}] or id: `)).trim();
|
|
37
45
|
if (!answer)
|
|
38
46
|
return null;
|
|
@@ -40,7 +48,7 @@ async function selectTaskWithTextPicker(tasks, io = {}) {
|
|
|
40
48
|
const index = Number.parseInt(answer, 10) - 1;
|
|
41
49
|
return tasks[index] ?? null;
|
|
42
50
|
}
|
|
43
|
-
return tasks.find((task) =>
|
|
51
|
+
return tasks.find((task) => taskId2(task) === answer) ?? null;
|
|
44
52
|
}
|
|
45
53
|
export {
|
|
46
54
|
selectTaskWithTextPicker,
|
|
@@ -221,6 +221,7 @@ import { ensureProjectMainFreshBeforeRun } from "@rig/runtime/control-plane/proj
|
|
|
221
221
|
|
|
222
222
|
// packages/cli/src/commands/_server-client.ts
|
|
223
223
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
224
|
+
var scopedGitHubBearerTokens = new Map;
|
|
224
225
|
|
|
225
226
|
// packages/cli/src/commands/_preflight.ts
|
|
226
227
|
async function runProjectMainSyncPreflight(context, options) {
|
|
@@ -104,11 +104,10 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
// packages/cli/src/commands/_server-client.ts
|
|
107
|
-
import { spawnSync } from "child_process";
|
|
108
107
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
109
108
|
import { resolve as resolve2 } from "path";
|
|
110
109
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
111
|
-
var
|
|
110
|
+
var scopedGitHubBearerTokens = new Map;
|
|
112
111
|
function cleanToken(value) {
|
|
113
112
|
const trimmed = value?.trim();
|
|
114
113
|
return trimmed ? trimmed : null;
|
|
@@ -125,25 +124,13 @@ function readPrivateRemoteSessionToken(projectRoot) {
|
|
|
125
124
|
}
|
|
126
125
|
}
|
|
127
126
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
const scopedKey = resolve2(projectRoot);
|
|
128
|
+
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
129
|
+
return scopedGitHubBearerTokens.get(scopedKey) ?? null;
|
|
130
130
|
const privateSession = readPrivateRemoteSessionToken(projectRoot);
|
|
131
|
-
if (privateSession)
|
|
132
|
-
|
|
133
|
-
|
|
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;
|
|
131
|
+
if (privateSession)
|
|
132
|
+
return privateSession;
|
|
133
|
+
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
147
134
|
}
|
|
148
135
|
async function ensureServerForCli(projectRoot) {
|
|
149
136
|
try {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/cli/src/commands/github.ts
|
|
3
|
-
import { spawnSync
|
|
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";
|
|
@@ -32,7 +32,6 @@ function takeOption(args, option) {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
// packages/cli/src/commands/_server-client.ts
|
|
35
|
-
import { spawnSync } from "child_process";
|
|
36
35
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
37
36
|
import { resolve as resolve2 } from "path";
|
|
38
37
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
@@ -120,7 +119,7 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
120
119
|
}
|
|
121
120
|
|
|
122
121
|
// packages/cli/src/commands/_server-client.ts
|
|
123
|
-
var
|
|
122
|
+
var scopedGitHubBearerTokens = new Map;
|
|
124
123
|
function cleanToken(value) {
|
|
125
124
|
const trimmed = value?.trim();
|
|
126
125
|
return trimmed ? trimmed : null;
|
|
@@ -137,25 +136,13 @@ function readPrivateRemoteSessionToken(projectRoot) {
|
|
|
137
136
|
}
|
|
138
137
|
}
|
|
139
138
|
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
const scopedKey = resolve2(projectRoot);
|
|
140
|
+
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
141
|
+
return scopedGitHubBearerTokens.get(scopedKey) ?? null;
|
|
142
142
|
const privateSession = readPrivateRemoteSessionToken(projectRoot);
|
|
143
|
-
if (privateSession)
|
|
144
|
-
|
|
145
|
-
|
|
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;
|
|
143
|
+
if (privateSession)
|
|
144
|
+
return privateSession;
|
|
145
|
+
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
159
146
|
}
|
|
160
147
|
async function ensureServerForCli(projectRoot) {
|
|
161
148
|
try {
|
|
@@ -244,7 +231,7 @@ function printPayload(context, payload, fallback) {
|
|
|
244
231
|
console.log(fallback);
|
|
245
232
|
}
|
|
246
233
|
function readGhToken() {
|
|
247
|
-
const result =
|
|
234
|
+
const result = spawnSync("gh", ["auth", "token"], { encoding: "utf8" });
|
|
248
235
|
if (result.status !== 0) {
|
|
249
236
|
const detail = result.stderr?.trim() || result.stdout?.trim() || "gh auth token failed";
|
|
250
237
|
throw new CliError2(`Could not import GitHub token from gh: ${detail}`, 1);
|