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