@h-rig/cli 0.0.6-alpha.21 → 0.0.6-alpha.23
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 +940 -387
- package/dist/src/commands/_operator-view.js +539 -4
- package/dist/src/commands/_pi-frontend.js +727 -0
- package/dist/src/commands/_pi-worker-bridge-extension.js +645 -0
- package/dist/src/commands/_preflight.js +1 -81
- package/dist/src/commands/_server-client.js +80 -1
- package/dist/src/commands/run.js +541 -115
- package/dist/src/commands/task-run-driver.js +141 -10
- package/dist/src/commands/task.js +544 -197
- package/dist/src/commands.js +940 -387
- package/dist/src/index.js +940 -387
- package/package.json +6 -5
- package/dist/src/commands/_pi-session.js +0 -253
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-rig/cli",
|
|
3
|
-
"version": "0.0.6-alpha.
|
|
3
|
+
"version": "0.0.6-alpha.23",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Rig package",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -23,10 +23,11 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@clack/prompts": "^1.2.0",
|
|
26
|
-
"@
|
|
27
|
-
"@rig/
|
|
28
|
-
"@rig/
|
|
29
|
-
"@rig/
|
|
26
|
+
"@earendil-works/pi-coding-agent": "npm:@h-rig/pi-coding-agent@0.0.6-alpha.23",
|
|
27
|
+
"@rig/core": "npm:@h-rig/core@0.0.6-alpha.23",
|
|
28
|
+
"@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.23",
|
|
29
|
+
"@rig/client": "npm:@h-rig/client@0.0.6-alpha.23",
|
|
30
|
+
"@rig/server": "npm:@h-rig/server@0.0.6-alpha.23",
|
|
30
31
|
"picocolors": "^1.1.1"
|
|
31
32
|
}
|
|
32
33
|
}
|
|
@@ -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
|
-
};
|