@h-rig/cli 0.0.6-alpha.21 → 0.0.6-alpha.210
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/README.md +6 -28
- package/package.json +9 -28
- package/dist/bin/build-rig-binaries.js +0 -107
- package/dist/bin/rig.js +0 -10443
- package/dist/src/commands/_authority-runs.js +0 -111
- package/dist/src/commands/_cli-format.js +0 -106
- package/dist/src/commands/_connection-state.js +0 -123
- package/dist/src/commands/_doctor-checks.js +0 -507
- package/dist/src/commands/_operator-surface.js +0 -204
- package/dist/src/commands/_operator-view.js +0 -496
- package/dist/src/commands/_parsers.js +0 -107
- package/dist/src/commands/_paths.js +0 -50
- package/dist/src/commands/_pi-install.js +0 -185
- package/dist/src/commands/_pi-session.js +0 -253
- package/dist/src/commands/_policy.js +0 -79
- package/dist/src/commands/_preflight.js +0 -483
- package/dist/src/commands/_probes.js +0 -13
- package/dist/src/commands/_run-driver-helpers.js +0 -289
- package/dist/src/commands/_server-client.js +0 -435
- package/dist/src/commands/_snapshot-upload.js +0 -318
- package/dist/src/commands/_task-picker.js +0 -76
- package/dist/src/commands/agent.js +0 -499
- package/dist/src/commands/browser.js +0 -890
- package/dist/src/commands/connect.js +0 -180
- package/dist/src/commands/dist.js +0 -402
- package/dist/src/commands/doctor.js +0 -517
- package/dist/src/commands/github.js +0 -281
- package/dist/src/commands/inbox.js +0 -160
- package/dist/src/commands/init.js +0 -1563
- package/dist/src/commands/inspect.js +0 -174
- package/dist/src/commands/inspector.js +0 -256
- package/dist/src/commands/plugin.js +0 -167
- package/dist/src/commands/profile-and-review.js +0 -178
- package/dist/src/commands/queue.js +0 -198
- package/dist/src/commands/remote.js +0 -507
- package/dist/src/commands/repo-git-harness.js +0 -221
- package/dist/src/commands/run.js +0 -1132
- package/dist/src/commands/server.js +0 -373
- package/dist/src/commands/setup.js +0 -687
- package/dist/src/commands/task-report-bug.js +0 -1083
- package/dist/src/commands/task-run-driver.js +0 -2469
- package/dist/src/commands/task.js +0 -1715
- package/dist/src/commands/test.js +0 -39
- package/dist/src/commands/workspace.js +0 -123
- package/dist/src/commands.js +0 -10122
- package/dist/src/index.js +0 -10461
- package/dist/src/launcher.js +0 -133
- package/dist/src/report-bug.js +0 -260
- package/dist/src/runner.js +0 -273
- package/dist/src/withMutedConsole.js +0 -42
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// packages/cli/src/commands/_pi-install.ts
|
|
3
|
-
import { existsSync, readFileSync, rmSync } from "fs";
|
|
4
|
-
import { homedir } from "os";
|
|
5
|
-
import { resolve } from "path";
|
|
6
|
-
var PI_RIG_PACKAGE_NAME = "@h-rig/pi-rig";
|
|
7
|
-
var LEGACY_PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
|
|
8
|
-
var LEGACY_PI_RIG_MARKER = `// Managed by Rig. Source package: @rig/pi-rig.
|
|
9
|
-
export { default } from '@rig/pi-rig';
|
|
10
|
-
`;
|
|
11
|
-
async function defaultCommandRunner(command, options = {}) {
|
|
12
|
-
const proc = Bun.spawn(command, { cwd: options.cwd, stdout: "pipe", stderr: "pipe" });
|
|
13
|
-
const [stdout, stderr, exitCode] = await Promise.all([
|
|
14
|
-
new Response(proc.stdout).text(),
|
|
15
|
-
new Response(proc.stderr).text(),
|
|
16
|
-
proc.exited
|
|
17
|
-
]);
|
|
18
|
-
return { exitCode, stdout, stderr };
|
|
19
|
-
}
|
|
20
|
-
function resolvePiRigExtensionPath(homeDir) {
|
|
21
|
-
return resolve(homeDir, ".pi", "agent", "extensions", "pi-rig");
|
|
22
|
-
}
|
|
23
|
-
function resolvePiRigPackageSource(projectRoot, exists = existsSync) {
|
|
24
|
-
const localPackage = resolve(projectRoot, "packages", "pi-rig");
|
|
25
|
-
if (exists(resolve(localPackage, "package.json")))
|
|
26
|
-
return localPackage;
|
|
27
|
-
return `npm:${PI_RIG_PACKAGE_NAME}`;
|
|
28
|
-
}
|
|
29
|
-
function resolvePiHomeDir(inputHomeDir) {
|
|
30
|
-
return inputHomeDir ?? process.env.RIG_PI_HOME_DIR?.trim() ?? homedir();
|
|
31
|
-
}
|
|
32
|
-
function piListContainsPiRig(output) {
|
|
33
|
-
return output.split(/\r?\n/).some((line) => {
|
|
34
|
-
const normalized = line.trim();
|
|
35
|
-
return normalized.includes(PI_RIG_PACKAGE_NAME) || normalized.includes(LEGACY_PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
async function safeRun(runner, command, options) {
|
|
39
|
-
try {
|
|
40
|
-
return await runner(command, options);
|
|
41
|
-
} catch (error) {
|
|
42
|
-
return { exitCode: 1, stdout: "", stderr: error instanceof Error ? error.message : String(error) };
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
function splitInstallCommand(value) {
|
|
46
|
-
return value.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g)?.map((part) => part.replace(/^['"]|['"]$/g, "")) ?? [];
|
|
47
|
-
}
|
|
48
|
-
async function ensurePiBinaryAvailable(input) {
|
|
49
|
-
const current = await safeRun(input.runner, ["pi", "--version"]);
|
|
50
|
-
if (current.exitCode === 0) {
|
|
51
|
-
const updateCommand = process.env.RIG_PI_UPDATE_COMMAND?.trim();
|
|
52
|
-
if (updateCommand) {
|
|
53
|
-
const parts2 = splitInstallCommand(updateCommand);
|
|
54
|
-
if (parts2.length > 0)
|
|
55
|
-
await safeRun(input.runner, parts2, input.projectRoot ? { cwd: input.projectRoot } : undefined);
|
|
56
|
-
}
|
|
57
|
-
return { ok: true, detail: (current.stdout || current.stderr).trim() || undefined };
|
|
58
|
-
}
|
|
59
|
-
const installCommand = process.env.RIG_PI_INSTALL_COMMAND?.trim() || "bunx @earendil-works/pi@latest install";
|
|
60
|
-
const parts = splitInstallCommand(installCommand);
|
|
61
|
-
if (parts.length === 0) {
|
|
62
|
-
return { ok: false, error: (current.stderr || current.stdout).trim() || "pi --version failed" };
|
|
63
|
-
}
|
|
64
|
-
const install = await safeRun(input.runner, parts, input.projectRoot ? { cwd: input.projectRoot } : undefined);
|
|
65
|
-
if (install.exitCode !== 0) {
|
|
66
|
-
return { ok: false, installedOrUpdated: true, error: (install.stderr || install.stdout).trim() || `Pi install command failed (${install.exitCode})` };
|
|
67
|
-
}
|
|
68
|
-
const next = await safeRun(input.runner, ["pi", "--version"]);
|
|
69
|
-
return {
|
|
70
|
-
ok: next.exitCode === 0,
|
|
71
|
-
installedOrUpdated: true,
|
|
72
|
-
detail: (next.stdout || next.stderr).trim() || undefined,
|
|
73
|
-
...next.exitCode === 0 ? {} : { error: (next.stderr || next.stdout).trim() || "pi --version failed after install" }
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
function removeManagedLegacyPiRigBridge(homeDir, exists = existsSync) {
|
|
77
|
-
const extensionPath = resolvePiRigExtensionPath(homeDir);
|
|
78
|
-
const indexPath = resolve(extensionPath, "index.ts");
|
|
79
|
-
if (!exists(indexPath))
|
|
80
|
-
return;
|
|
81
|
-
try {
|
|
82
|
-
const content = readFileSync(indexPath, "utf8");
|
|
83
|
-
if (content === LEGACY_PI_RIG_MARKER || content.includes("Managed by Rig. Source package: @rig/pi-rig")) {
|
|
84
|
-
rmSync(extensionPath, { recursive: true, force: true });
|
|
85
|
-
}
|
|
86
|
-
} catch {}
|
|
87
|
-
}
|
|
88
|
-
async function checkPiRigInstall(input = {}) {
|
|
89
|
-
const home = resolvePiHomeDir(input.homeDir);
|
|
90
|
-
const extensionPath = resolvePiRigExtensionPath(home);
|
|
91
|
-
if (process.env.RIG_TEST_FAKE_PI_INSTALL === "1") {
|
|
92
|
-
return {
|
|
93
|
-
extensionPath,
|
|
94
|
-
pi: { ok: true, label: "pi", detail: "fake-pi" },
|
|
95
|
-
piRig: { ok: true, label: "pi-rig global extension", detail: extensionPath }
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
const exists = input.exists ?? existsSync;
|
|
99
|
-
const runner = input.commandRunner ?? defaultCommandRunner;
|
|
100
|
-
const piResult = await safeRun(runner, ["pi", "--version"]);
|
|
101
|
-
const piListResult = piResult.exitCode === 0 ? await safeRun(runner, ["pi", "list"]) : { exitCode: 1, stdout: "", stderr: "" };
|
|
102
|
-
const listedPiRig = piListResult.exitCode === 0 && piListContainsPiRig(`${piListResult.stdout}
|
|
103
|
-
${piListResult.stderr}`);
|
|
104
|
-
const legacyBridge = exists(resolve(extensionPath, "index.ts"));
|
|
105
|
-
const hasPiRig = listedPiRig;
|
|
106
|
-
return {
|
|
107
|
-
extensionPath,
|
|
108
|
-
pi: {
|
|
109
|
-
ok: piResult.exitCode === 0,
|
|
110
|
-
label: "pi",
|
|
111
|
-
detail: (piResult.stdout || piResult.stderr).trim() || undefined,
|
|
112
|
-
hint: piResult.exitCode === 0 ? undefined : "Install Pi or run `rig init --yes` to install/update the Pi runtime."
|
|
113
|
-
},
|
|
114
|
-
piRig: {
|
|
115
|
-
ok: hasPiRig,
|
|
116
|
-
label: "pi-rig global extension",
|
|
117
|
-
detail: hasPiRig ? piListResult.stdout.trim() || PI_RIG_PACKAGE_NAME : legacyBridge ? `${extensionPath} (legacy bridge; reinstall required)` : undefined,
|
|
118
|
-
hint: hasPiRig ? undefined : "Run `rig init --yes` to install/enable the global pi-rig package with `pi install`."
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
async function ensurePiRigInstalled(input) {
|
|
123
|
-
const home = resolvePiHomeDir(input.homeDir);
|
|
124
|
-
if (process.env.RIG_TEST_FAKE_PI_INSTALL === "1") {
|
|
125
|
-
const status2 = await checkPiRigInstall({ homeDir: home, commandRunner: input.commandRunner });
|
|
126
|
-
return { ...status2, installedPath: status2.extensionPath };
|
|
127
|
-
}
|
|
128
|
-
const runner = input.commandRunner ?? defaultCommandRunner;
|
|
129
|
-
const piAvailable = await ensurePiBinaryAvailable({ runner, projectRoot: input.projectRoot });
|
|
130
|
-
const status = piAvailable.ok ? await checkPiRigInstall({ homeDir: home, commandRunner: runner }) : {
|
|
131
|
-
extensionPath: resolvePiRigExtensionPath(home),
|
|
132
|
-
pi: { ok: false, label: "pi", detail: piAvailable.error, hint: "Install/update Pi with RIG_PI_INSTALL_COMMAND or install Pi manually." },
|
|
133
|
-
piRig: { ok: false, label: "pi-rig global extension", hint: "Pi is required before pi-rig can be installed." }
|
|
134
|
-
};
|
|
135
|
-
if (!piAvailable.ok) {
|
|
136
|
-
throw new Error(`Pi install/update failed: ${piAvailable.error ?? "pi unavailable"}`);
|
|
137
|
-
}
|
|
138
|
-
const packageSource = resolvePiRigPackageSource(input.projectRoot);
|
|
139
|
-
removeManagedLegacyPiRigBridge(home);
|
|
140
|
-
const install = await runner(["pi", "install", packageSource], { cwd: input.projectRoot });
|
|
141
|
-
if (install.exitCode !== 0) {
|
|
142
|
-
throw new Error(`pi-rig install failed: ${(install.stderr || install.stdout).trim() || `exit ${install.exitCode}`}`);
|
|
143
|
-
}
|
|
144
|
-
const next = await checkPiRigInstall({ homeDir: home, commandRunner: runner });
|
|
145
|
-
return { ...next, installedPath: packageSource };
|
|
146
|
-
}
|
|
147
|
-
async function ensureRemotePiRigInstalled(input) {
|
|
148
|
-
const payload = await input.requestJson("/api/pi-rig/install", {
|
|
149
|
-
method: "POST",
|
|
150
|
-
headers: { "content-type": "application/json" },
|
|
151
|
-
body: JSON.stringify({ package: PI_RIG_PACKAGE_NAME, scope: "global" })
|
|
152
|
-
});
|
|
153
|
-
const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
154
|
-
const piOk = record.piOk === true || record.ok === true;
|
|
155
|
-
const piRigOk = record.piRigOk === true || record.installed === true || record.ok === true;
|
|
156
|
-
const extensionPath = typeof record.extensionPath === "string" ? record.extensionPath : "remote:~/.pi/agent/extensions/pi-rig";
|
|
157
|
-
return {
|
|
158
|
-
remote: true,
|
|
159
|
-
extensionPath,
|
|
160
|
-
pi: {
|
|
161
|
-
ok: piOk,
|
|
162
|
-
label: "pi",
|
|
163
|
-
detail: typeof record.piVersion === "string" ? record.piVersion : undefined,
|
|
164
|
-
hint: piOk ? undefined : "Install/update Pi on the selected remote Rig server."
|
|
165
|
-
},
|
|
166
|
-
piRig: {
|
|
167
|
-
ok: piRigOk,
|
|
168
|
-
label: "pi-rig global extension",
|
|
169
|
-
detail: extensionPath,
|
|
170
|
-
hint: piRigOk ? undefined : "Install/enable pi-rig on the selected remote Rig server."
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
async function buildPiSetupChecks(input = {}) {
|
|
175
|
-
const status = await checkPiRigInstall(input);
|
|
176
|
-
return [status.pi, status.piRig];
|
|
177
|
-
}
|
|
178
|
-
export {
|
|
179
|
-
resolvePiRigPackageSource,
|
|
180
|
-
resolvePiRigExtensionPath,
|
|
181
|
-
ensureRemotePiRigInstalled,
|
|
182
|
-
ensurePiRigInstalled,
|
|
183
|
-
checkPiRigInstall,
|
|
184
|
-
buildPiSetupChecks
|
|
185
|
-
};
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// packages/cli/src/commands/_pi-session.ts
|
|
3
|
-
import { spawn } from "child_process";
|
|
4
|
-
|
|
5
|
-
// packages/cli/src/runner.ts
|
|
6
|
-
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
7
|
-
import { CliError } from "@rig/runtime/control-plane/errors";
|
|
8
|
-
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
9
|
-
import { PluginManager } from "@rig/runtime/control-plane/runtime/plugins";
|
|
10
|
-
import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/context";
|
|
11
|
-
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
12
|
-
import { CliError as CliError2 } from "@rig/runtime/control-plane/errors";
|
|
13
|
-
function formatCommand(parts) {
|
|
14
|
-
return parts.map((part) => /[^a-zA-Z0-9_./:-]/.test(part) ? JSON.stringify(part) : part).join(" ");
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// packages/cli/src/commands/_server-client.ts
|
|
18
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
19
|
-
import { resolve as resolve2 } from "path";
|
|
20
|
-
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
21
|
-
|
|
22
|
-
// packages/cli/src/commands/_connection-state.ts
|
|
23
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
24
|
-
import { homedir } from "os";
|
|
25
|
-
import { dirname, resolve } from "path";
|
|
26
|
-
function resolveGlobalConnectionsPath(env = process.env) {
|
|
27
|
-
const explicit = env.RIG_CONNECTIONS_FILE?.trim();
|
|
28
|
-
if (explicit)
|
|
29
|
-
return resolve(explicit);
|
|
30
|
-
const stateDir = env.RIG_GLOBAL_STATE_DIR?.trim();
|
|
31
|
-
if (stateDir)
|
|
32
|
-
return resolve(stateDir, "connections.json");
|
|
33
|
-
return resolve(homedir(), ".rig", "connections.json");
|
|
34
|
-
}
|
|
35
|
-
function resolveRepoConnectionPath(projectRoot) {
|
|
36
|
-
return resolve(projectRoot, ".rig", "state", "connection.json");
|
|
37
|
-
}
|
|
38
|
-
function readJsonFile(path) {
|
|
39
|
-
if (!existsSync(path))
|
|
40
|
-
return null;
|
|
41
|
-
try {
|
|
42
|
-
return JSON.parse(readFileSync(path, "utf8"));
|
|
43
|
-
} catch (error) {
|
|
44
|
-
throw new CliError2(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
function normalizeConnection(value) {
|
|
48
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
49
|
-
return null;
|
|
50
|
-
const record = value;
|
|
51
|
-
if (record.kind === "local")
|
|
52
|
-
return { kind: "local", mode: "auto" };
|
|
53
|
-
if (record.kind === "remote" && typeof record.baseUrl === "string" && record.baseUrl.trim()) {
|
|
54
|
-
const baseUrl = record.baseUrl.trim().replace(/\/+$/, "");
|
|
55
|
-
return { kind: "remote", baseUrl };
|
|
56
|
-
}
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
function readGlobalConnections(options = {}) {
|
|
60
|
-
const path = resolveGlobalConnectionsPath(options.env ?? process.env);
|
|
61
|
-
const payload = readJsonFile(path);
|
|
62
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
63
|
-
return { connections: {} };
|
|
64
|
-
}
|
|
65
|
-
const rawConnections = payload.connections;
|
|
66
|
-
const connections = {};
|
|
67
|
-
if (rawConnections && typeof rawConnections === "object" && !Array.isArray(rawConnections)) {
|
|
68
|
-
for (const [alias, raw] of Object.entries(rawConnections)) {
|
|
69
|
-
const connection = normalizeConnection(raw);
|
|
70
|
-
if (connection)
|
|
71
|
-
connections[alias] = connection;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return { connections };
|
|
75
|
-
}
|
|
76
|
-
function readRepoConnection(projectRoot) {
|
|
77
|
-
const payload = readJsonFile(resolveRepoConnectionPath(projectRoot));
|
|
78
|
-
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
79
|
-
return null;
|
|
80
|
-
const record = payload;
|
|
81
|
-
const selected = typeof record.selected === "string" ? record.selected.trim() : "";
|
|
82
|
-
if (!selected)
|
|
83
|
-
return null;
|
|
84
|
-
return {
|
|
85
|
-
selected,
|
|
86
|
-
project: typeof record.project === "string" ? record.project : undefined,
|
|
87
|
-
linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
function resolveSelectedConnection(projectRoot, options = {}) {
|
|
91
|
-
const repo = readRepoConnection(projectRoot);
|
|
92
|
-
if (!repo)
|
|
93
|
-
return null;
|
|
94
|
-
if (repo.selected === "local")
|
|
95
|
-
return { alias: "local", connection: { kind: "local", mode: "auto" } };
|
|
96
|
-
const global = readGlobalConnections(options);
|
|
97
|
-
const connection = global.connections[repo.selected];
|
|
98
|
-
if (!connection) {
|
|
99
|
-
throw new CliError2(`Selected Rig connection "${repo.selected}" was not found. Run \`rig connect list\` or \`rig connect use local\`.`, 1);
|
|
100
|
-
}
|
|
101
|
-
return { alias: repo.selected, connection };
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// packages/cli/src/commands/_server-client.ts
|
|
105
|
-
var scopedGitHubBearerTokens = new Map;
|
|
106
|
-
function cleanToken(value) {
|
|
107
|
-
const trimmed = value?.trim();
|
|
108
|
-
return trimmed ? trimmed : null;
|
|
109
|
-
}
|
|
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) {
|
|
122
|
-
const scopedKey = resolve2(projectRoot);
|
|
123
|
-
if (scopedGitHubBearerTokens.has(scopedKey))
|
|
124
|
-
return scopedGitHubBearerTokens.get(scopedKey) ?? null;
|
|
125
|
-
const privateSession = readPrivateRemoteSessionToken(projectRoot);
|
|
126
|
-
if (privateSession)
|
|
127
|
-
return privateSession;
|
|
128
|
-
return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
|
|
129
|
-
}
|
|
130
|
-
async function ensureServerForCli(projectRoot) {
|
|
131
|
-
try {
|
|
132
|
-
const selected = resolveSelectedConnection(projectRoot);
|
|
133
|
-
if (selected?.connection.kind === "remote") {
|
|
134
|
-
return {
|
|
135
|
-
baseUrl: selected.connection.baseUrl,
|
|
136
|
-
authToken: readGitHubBearerTokenForRemote(projectRoot),
|
|
137
|
-
connectionKind: "remote"
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
const connection = await ensureLocalRigServerConnection(projectRoot);
|
|
141
|
-
return {
|
|
142
|
-
baseUrl: connection.baseUrl,
|
|
143
|
-
authToken: connection.authToken,
|
|
144
|
-
connectionKind: "local"
|
|
145
|
-
};
|
|
146
|
-
} catch (error) {
|
|
147
|
-
if (error instanceof Error) {
|
|
148
|
-
throw new CliError2(error.message, 1);
|
|
149
|
-
}
|
|
150
|
-
throw error;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// packages/cli/src/commands/_pi-install.ts
|
|
155
|
-
import { existsSync as existsSync3, readFileSync as readFileSync3, rmSync } from "fs";
|
|
156
|
-
import { resolve as resolve3 } from "path";
|
|
157
|
-
var PI_RIG_PACKAGE_NAME = "@h-rig/pi-rig";
|
|
158
|
-
function resolvePiRigPackageSource(projectRoot, exists = existsSync3) {
|
|
159
|
-
const localPackage = resolve3(projectRoot, "packages", "pi-rig");
|
|
160
|
-
if (exists(resolve3(localPackage, "package.json")))
|
|
161
|
-
return localPackage;
|
|
162
|
-
return `npm:${PI_RIG_PACKAGE_NAME}`;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// packages/cli/src/commands/_pi-session.ts
|
|
166
|
-
function buildPiRigSessionEnv(input) {
|
|
167
|
-
return {
|
|
168
|
-
RIG_PROJECT_ROOT: input.projectRoot,
|
|
169
|
-
PROJECT_RIG_ROOT: input.projectRoot,
|
|
170
|
-
RIG_RUN_ID: input.runId,
|
|
171
|
-
RIG_SERVER_RUN_ID: input.runId,
|
|
172
|
-
RIG_RUNTIME_ADAPTER: "pi",
|
|
173
|
-
RIG_SERVER_URL: input.serverUrl,
|
|
174
|
-
RIG_SERVER_BASE_URL: input.serverUrl,
|
|
175
|
-
RIG_STEERING_POLL_MS: process.env.RIG_STEERING_POLL_MS?.trim() || "1000",
|
|
176
|
-
RIG_PI_OPERATOR_SESSION: "1",
|
|
177
|
-
...input.taskId ? { RIG_TASK_ID: input.taskId } : {},
|
|
178
|
-
...input.authToken ? { RIG_AUTH_TOKEN: input.authToken } : {}
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
function shellBinary(name) {
|
|
182
|
-
const explicit = process.env.RIG_PI_BINARY?.trim();
|
|
183
|
-
if (explicit)
|
|
184
|
-
return explicit;
|
|
185
|
-
return Bun.which(name) || name;
|
|
186
|
-
}
|
|
187
|
-
function buildPiRigSessionCommand(input) {
|
|
188
|
-
const configuredExtension = input.extensionSource ?? process.env.RIG_PI_RIG_EXTENSION_SOURCE?.trim();
|
|
189
|
-
const extensionSource = configuredExtension && configuredExtension.length > 0 ? configuredExtension : resolvePiRigPackageSource(input.projectRoot);
|
|
190
|
-
const initialCommand = `/rig attach ${input.runId}`;
|
|
191
|
-
return [
|
|
192
|
-
shellBinary("pi"),
|
|
193
|
-
"--no-extensions",
|
|
194
|
-
"--extension",
|
|
195
|
-
extensionSource,
|
|
196
|
-
initialCommand
|
|
197
|
-
];
|
|
198
|
-
}
|
|
199
|
-
async function launchPiRigSession(context, input) {
|
|
200
|
-
if (context.outputMode !== "text" || !process.stdin.isTTY || !process.stdout.isTTY) {
|
|
201
|
-
return { launched: false, exitCode: null, command: [] };
|
|
202
|
-
}
|
|
203
|
-
if (process.env.RIG_DISABLE_PI_LAUNCH === "1") {
|
|
204
|
-
return { launched: false, exitCode: null, command: [] };
|
|
205
|
-
}
|
|
206
|
-
const server = await ensureServerForCli(context.projectRoot);
|
|
207
|
-
const command = buildPiRigSessionCommand({ ...input, projectRoot: context.projectRoot });
|
|
208
|
-
const env = {
|
|
209
|
-
...process.env,
|
|
210
|
-
...buildPiRigSessionEnv({
|
|
211
|
-
projectRoot: context.projectRoot,
|
|
212
|
-
runId: input.runId,
|
|
213
|
-
taskId: input.taskId,
|
|
214
|
-
serverUrl: server.baseUrl,
|
|
215
|
-
authToken: server.authToken
|
|
216
|
-
})
|
|
217
|
-
};
|
|
218
|
-
process.stdout.write(`Launching Pi for Rig run ${input.runId}\u2026
|
|
219
|
-
`);
|
|
220
|
-
process.stdout.write(`Pi command: ${formatCommand(command)}
|
|
221
|
-
`);
|
|
222
|
-
const launchedAt = Date.now();
|
|
223
|
-
const child = spawn(command[0], command.slice(1), {
|
|
224
|
-
cwd: context.projectRoot,
|
|
225
|
-
env,
|
|
226
|
-
stdio: "inherit"
|
|
227
|
-
});
|
|
228
|
-
const launchError = await new Promise((resolve4) => {
|
|
229
|
-
child.once("error", (error) => {
|
|
230
|
-
resolve4({ error: error.message });
|
|
231
|
-
});
|
|
232
|
-
child.once("close", (code) => resolve4({ code }));
|
|
233
|
-
});
|
|
234
|
-
if ("error" in launchError) {
|
|
235
|
-
process.stderr.write(`Failed to launch Pi; falling back to Rig attach view: ${launchError.error}
|
|
236
|
-
`);
|
|
237
|
-
return { launched: false, exitCode: null, command, error: launchError.error };
|
|
238
|
-
}
|
|
239
|
-
const exitCode = launchError.code;
|
|
240
|
-
const elapsedMs = Date.now() - launchedAt;
|
|
241
|
-
if (typeof exitCode === "number" && exitCode !== 0 && elapsedMs < 5000) {
|
|
242
|
-
const error = `Pi exited during startup with code ${exitCode}.`;
|
|
243
|
-
process.stderr.write(`${error} Falling back to Rig attach view.
|
|
244
|
-
`);
|
|
245
|
-
return { launched: false, exitCode, command, error };
|
|
246
|
-
}
|
|
247
|
-
return { launched: true, exitCode, command };
|
|
248
|
-
}
|
|
249
|
-
export {
|
|
250
|
-
launchPiRigSession,
|
|
251
|
-
buildPiRigSessionEnv,
|
|
252
|
-
buildPiRigSessionCommand
|
|
253
|
-
};
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// packages/cli/src/commands/_policy.ts
|
|
3
|
-
import { appendFileSync, mkdirSync } from "fs";
|
|
4
|
-
import { resolve } from "path";
|
|
5
|
-
|
|
6
|
-
// packages/cli/src/runner.ts
|
|
7
|
-
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
8
|
-
import { CliError } from "@rig/runtime/control-plane/errors";
|
|
9
|
-
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
10
|
-
import { PluginManager } from "@rig/runtime/control-plane/runtime/plugins";
|
|
11
|
-
import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/context";
|
|
12
|
-
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
13
|
-
import { CliError as CliError2 } from "@rig/runtime/control-plane/errors";
|
|
14
|
-
function formatCommand(parts) {
|
|
15
|
-
return parts.map((part) => /[^a-zA-Z0-9_./:-]/.test(part) ? JSON.stringify(part) : part).join(" ");
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// packages/cli/src/commands/_policy.ts
|
|
19
|
-
import { evaluate as evaluate2, loadPolicy as loadPolicy2, resolveAction as resolveAction2 } from "@rig/runtime/control-plane/runtime/guard";
|
|
20
|
-
import { resolveHarnessPaths } from "@rig/runtime/control-plane/native/utils";
|
|
21
|
-
function resolveEffectivePolicyMode(context) {
|
|
22
|
-
const envMode = process.env.RIG_BASH_MODE;
|
|
23
|
-
if (envMode === "off" || envMode === "observe" || envMode === "enforce") {
|
|
24
|
-
return envMode;
|
|
25
|
-
}
|
|
26
|
-
return context.policyMode || loadPolicy2(context.projectRoot).mode;
|
|
27
|
-
}
|
|
28
|
-
function appendControlledBashAudit(context, mode, command, args, matchedRuleIds, action) {
|
|
29
|
-
if (mode === "off") {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
const logsDir = resolveHarnessPaths(context.projectRoot).logsDir;
|
|
33
|
-
const logFile = resolve(logsDir, "controlled-bash.jsonl");
|
|
34
|
-
mkdirSync(logsDir, { recursive: true });
|
|
35
|
-
const payload = {
|
|
36
|
-
timestamp: new Date().toISOString(),
|
|
37
|
-
mode,
|
|
38
|
-
cwd: process.cwd(),
|
|
39
|
-
pid: process.pid,
|
|
40
|
-
ppid: process.ppid,
|
|
41
|
-
argv: args,
|
|
42
|
-
command,
|
|
43
|
-
matchedRuleIds
|
|
44
|
-
};
|
|
45
|
-
if (action) {
|
|
46
|
-
payload.action = action;
|
|
47
|
-
}
|
|
48
|
-
appendFileSync(logFile, `${JSON.stringify(payload)}
|
|
49
|
-
`, "utf-8");
|
|
50
|
-
}
|
|
51
|
-
async function enforceNativeCommandPolicy(context, args, options) {
|
|
52
|
-
const mode = resolveEffectivePolicyMode(context);
|
|
53
|
-
const command = formatCommand([options.commandPrefix, ...args]);
|
|
54
|
-
const decision = evaluate2({
|
|
55
|
-
projectRoot: context.projectRoot,
|
|
56
|
-
evaluation: { type: "command", command }
|
|
57
|
-
});
|
|
58
|
-
const action = resolveAction2(mode, decision.matchedRules);
|
|
59
|
-
const matchedRuleIds = decision.matchedRules.map((rule) => rule.id);
|
|
60
|
-
await context.emitEvent("policy.decision", {
|
|
61
|
-
target: "command",
|
|
62
|
-
command,
|
|
63
|
-
mode,
|
|
64
|
-
allowed: action !== "block",
|
|
65
|
-
matchedRuleIds,
|
|
66
|
-
reasons: decision.matchedRules.map((rule) => rule.reason)
|
|
67
|
-
});
|
|
68
|
-
if (options.writeAuditLog) {
|
|
69
|
-
appendControlledBashAudit(context, mode, command, args, matchedRuleIds, action === "block" ? "blocked" : action === "warn" ? "warn" : undefined);
|
|
70
|
-
}
|
|
71
|
-
if (action === "block") {
|
|
72
|
-
throw new CliError2(`Policy blocked command: ${command}`, 126);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
export {
|
|
76
|
-
resolveEffectivePolicyMode,
|
|
77
|
-
enforceNativeCommandPolicy,
|
|
78
|
-
appendControlledBashAudit
|
|
79
|
-
};
|