@h-rig/cli-surface-plugin 0.0.6-alpha.146
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 +1 -0
- package/dist/src/app/drone-ui.d.ts +34 -0
- package/dist/src/app/drone-ui.js +278 -0
- package/dist/src/commands/_async-ui.d.ts +10 -0
- package/dist/src/commands/_async-ui.js +121 -0
- package/dist/src/commands/_cli-format.d.ts +56 -0
- package/dist/src/commands/_cli-format.js +332 -0
- package/dist/src/commands/_connection-state.d.ts +54 -0
- package/dist/src/commands/_connection-state.js +187 -0
- package/dist/src/commands/_doctor-checks.d.ts +9 -0
- package/dist/src/commands/_doctor-checks.js +24 -0
- package/dist/src/commands/_help-catalog.d.ts +29 -0
- package/dist/src/commands/_help-catalog.js +157 -0
- package/dist/src/commands/_inprocess-services.d.ts +33 -0
- package/dist/src/commands/_inprocess-services.js +102 -0
- package/dist/src/commands/_json-output.d.ts +11 -0
- package/dist/src/commands/_json-output.js +54 -0
- package/dist/src/commands/_parsers.d.ts +15 -0
- package/dist/src/commands/_parsers.js +114 -0
- package/dist/src/commands/_paths.d.ts +11 -0
- package/dist/src/commands/_paths.js +50 -0
- package/dist/src/commands/_pi-frontend.d.ts +35 -0
- package/dist/src/commands/_pi-frontend.js +64 -0
- package/dist/src/commands/_pi-install.d.ts +42 -0
- package/dist/src/commands/_pi-install.js +167 -0
- package/dist/src/commands/_policy.d.ts +8 -0
- package/dist/src/commands/_policy.js +138 -0
- package/dist/src/commands/_probes.d.ts +1 -0
- package/dist/src/commands/_probes.js +13 -0
- package/dist/src/commands/_run-driver-helpers.d.ts +26 -0
- package/dist/src/commands/_run-driver-helpers.js +132 -0
- package/dist/src/commands/_run-subcommands.d.ts +3 -0
- package/dist/src/commands/_run-subcommands.js +31 -0
- package/dist/src/commands/_spinner.d.ts +25 -0
- package/dist/src/commands/_spinner.js +65 -0
- package/dist/src/commands/agent.d.ts +3 -0
- package/dist/src/commands/agent.js +322 -0
- package/dist/src/commands/config.d.ts +3 -0
- package/dist/src/commands/config.js +193 -0
- package/dist/src/commands/dist.d.ts +28 -0
- package/dist/src/commands/dist.js +435 -0
- package/dist/src/commands/doctor.d.ts +3 -0
- package/dist/src/commands/doctor.js +171 -0
- package/dist/src/commands/github.d.ts +3 -0
- package/dist/src/commands/github.js +342 -0
- package/dist/src/commands/inbox.d.ts +19 -0
- package/dist/src/commands/inbox.js +241 -0
- package/dist/src/commands/init.d.ts +64 -0
- package/dist/src/commands/init.js +1449 -0
- package/dist/src/commands/inspect.d.ts +20 -0
- package/dist/src/commands/inspect.js +337 -0
- package/dist/src/commands/pi.d.ts +3 -0
- package/dist/src/commands/pi.js +177 -0
- package/dist/src/commands/plugin.d.ts +20 -0
- package/dist/src/commands/plugin.js +238 -0
- package/dist/src/commands/profile-and-review.d.ts +4 -0
- package/dist/src/commands/profile-and-review.js +223 -0
- package/dist/src/commands/queue.d.ts +3 -0
- package/dist/src/commands/queue.js +197 -0
- package/dist/src/commands/remote.d.ts +3 -0
- package/dist/src/commands/remote.js +516 -0
- package/dist/src/commands/repo-git-harness.d.ts +5 -0
- package/dist/src/commands/repo-git-harness.js +282 -0
- package/dist/src/commands/run.d.ts +22 -0
- package/dist/src/commands/run.js +645 -0
- package/dist/src/commands/server.d.ts +3 -0
- package/dist/src/commands/server.js +155 -0
- package/dist/src/commands/setup.d.ts +16 -0
- package/dist/src/commands/setup.js +356 -0
- package/dist/src/commands/stats.d.ts +11 -0
- package/dist/src/commands/stats.js +219 -0
- package/dist/src/commands/task-run-driver.d.ts +93 -0
- package/dist/src/commands/task-run-driver.js +136 -0
- package/dist/src/commands/task.d.ts +46 -0
- package/dist/src/commands/task.js +555 -0
- package/dist/src/commands/test.d.ts +3 -0
- package/dist/src/commands/test.js +46 -0
- package/dist/src/commands/triage.d.ts +11 -0
- package/dist/src/commands/triage.js +224 -0
- package/dist/src/commands/workspace.d.ts +3 -0
- package/dist/src/commands/workspace.js +130 -0
- package/dist/src/kernel-dispatch.d.ts +15 -0
- package/dist/src/kernel-dispatch.js +16 -0
- package/dist/src/plugin.d.ts +3 -0
- package/dist/src/plugin.js +5440 -0
- package/dist/src/rig-config-package-deps.d.ts +10 -0
- package/dist/src/rig-config-package-deps.js +272 -0
- package/dist/src/runner.d.ts +47 -0
- package/dist/src/runner.js +267 -0
- package/dist/src/version.d.ts +8 -0
- package/dist/src/version.js +47 -0
- package/dist/src/withMutedConsole.d.ts +2 -0
- package/dist/src/withMutedConsole.js +42 -0
- package/package.json +34 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/cli-surface-plugin/src/commands/dist.ts
|
|
3
|
+
import {
|
|
4
|
+
chmodSync,
|
|
5
|
+
copyFileSync,
|
|
6
|
+
existsSync,
|
|
7
|
+
mkdirSync,
|
|
8
|
+
readdirSync,
|
|
9
|
+
readlinkSync,
|
|
10
|
+
rmSync,
|
|
11
|
+
statSync,
|
|
12
|
+
symlinkSync,
|
|
13
|
+
unlinkSync
|
|
14
|
+
} from "fs";
|
|
15
|
+
import { homedir as homedir2 } from "os";
|
|
16
|
+
import { resolve as resolve3 } from "path";
|
|
17
|
+
|
|
18
|
+
// packages/cli-surface-plugin/src/runner.ts
|
|
19
|
+
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
20
|
+
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
21
|
+
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
22
|
+
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
23
|
+
|
|
24
|
+
class CliError extends RuntimeCliError {
|
|
25
|
+
hint;
|
|
26
|
+
constructor(message, exitCode = 1, options = {}) {
|
|
27
|
+
super(message, exitCode);
|
|
28
|
+
if (options.hint?.trim()) {
|
|
29
|
+
this.hint = options.hint.trim();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function takeOption(args, option) {
|
|
34
|
+
const rest = [];
|
|
35
|
+
let value;
|
|
36
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
37
|
+
const current = args[index];
|
|
38
|
+
if (current === option) {
|
|
39
|
+
const next = args[index + 1];
|
|
40
|
+
if (!next || next.startsWith("-")) {
|
|
41
|
+
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
42
|
+
}
|
|
43
|
+
value = next;
|
|
44
|
+
index += 1;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (current !== undefined) {
|
|
48
|
+
rest.push(current);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return { value, rest };
|
|
52
|
+
}
|
|
53
|
+
function requireNoExtraArgs(args, usage) {
|
|
54
|
+
if (args.length > 0) {
|
|
55
|
+
throw new CliError(`Unexpected arguments: ${args.join(" ")}
|
|
56
|
+
Usage: ${usage}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// packages/cli-surface-plugin/src/commands/dist.ts
|
|
61
|
+
import {
|
|
62
|
+
computeRuntimeImageFingerprint,
|
|
63
|
+
computeRuntimeImageId
|
|
64
|
+
} from "@rig/runtime/control-plane/runtime/image/index";
|
|
65
|
+
import { buildBinary as buildBinary2 } from "@rig/runtime/control-plane/runtime/isolation";
|
|
66
|
+
|
|
67
|
+
// packages/cli-surface-plugin/src/commands/_parsers.ts
|
|
68
|
+
import { homedir } from "os";
|
|
69
|
+
import { resolve } from "path";
|
|
70
|
+
function parseInstallScope(value) {
|
|
71
|
+
if (!value || value === "user") {
|
|
72
|
+
return "user";
|
|
73
|
+
}
|
|
74
|
+
if (value === "system") {
|
|
75
|
+
return "system";
|
|
76
|
+
}
|
|
77
|
+
throw new CliError(`Invalid --scope value: ${value}. Use user|system.`);
|
|
78
|
+
}
|
|
79
|
+
function resolveInstallDir(scope, explicitPath) {
|
|
80
|
+
if (explicitPath) {
|
|
81
|
+
return resolve(explicitPath);
|
|
82
|
+
}
|
|
83
|
+
if (scope === "system") {
|
|
84
|
+
return "/usr/local/bin";
|
|
85
|
+
}
|
|
86
|
+
return resolve(homedir(), ".local/bin");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// packages/cli-surface-plugin/src/commands/_paths.ts
|
|
90
|
+
import { resolve as resolve2 } from "path";
|
|
91
|
+
import { resolveMonorepoRoot } from "@rig/runtime/layout";
|
|
92
|
+
function resolveControlPlaneMonorepoRoot(projectRoot) {
|
|
93
|
+
return resolveMonorepoRoot(projectRoot);
|
|
94
|
+
}
|
|
95
|
+
function resolveControlPlaneHostStateRoot(projectRoot) {
|
|
96
|
+
return resolve2(projectRoot, ".rig");
|
|
97
|
+
}
|
|
98
|
+
function resolveControlPlaneHostBinDir(projectRoot) {
|
|
99
|
+
return resolve2(resolveControlPlaneHostStateRoot(projectRoot), "bin");
|
|
100
|
+
}
|
|
101
|
+
function resolveControlPlaneHostDistDir(projectRoot) {
|
|
102
|
+
return resolve2(resolveControlPlaneHostStateRoot(projectRoot), "dist");
|
|
103
|
+
}
|
|
104
|
+
function resolveControlPlaneMonorepoStateRoot(projectRoot) {
|
|
105
|
+
return resolve2(resolveControlPlaneMonorepoRoot(projectRoot), ".rig");
|
|
106
|
+
}
|
|
107
|
+
function resolveControlPlaneMonorepoRuntimeDir(projectRoot) {
|
|
108
|
+
return resolve2(resolveControlPlaneMonorepoStateRoot(projectRoot), "runtime");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// packages/cli-surface-plugin/src/commands/_probes.ts
|
|
112
|
+
async function runQuietBinaryProbe(binaryPath, args, cwd) {
|
|
113
|
+
try {
|
|
114
|
+
const run = await Bun.$`${binaryPath} ${args}`.cwd(cwd).quiet().nothrow();
|
|
115
|
+
return run.exitCode === 0;
|
|
116
|
+
} catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// packages/cli-surface-plugin/src/commands/dist.ts
|
|
122
|
+
function collectRigValidatorBuildTargets(input) {
|
|
123
|
+
const validatorsRoot = resolve3(input.hostProjectRoot, "packages/runtime/src/control-plane/validators");
|
|
124
|
+
if (!existsSync(validatorsRoot))
|
|
125
|
+
return [];
|
|
126
|
+
const targets = [];
|
|
127
|
+
for (const category of readdirSync(validatorsRoot, { withFileTypes: true })) {
|
|
128
|
+
if (!category.isDirectory())
|
|
129
|
+
continue;
|
|
130
|
+
const categoryDir = resolve3(validatorsRoot, category.name);
|
|
131
|
+
for (const entry of readdirSync(categoryDir, { withFileTypes: true })) {
|
|
132
|
+
if (!entry.isFile() || !entry.name.endsWith(".ts"))
|
|
133
|
+
continue;
|
|
134
|
+
const check = entry.name.replace(/\.ts$/, "");
|
|
135
|
+
if (!check || check === "index" || check === "shared")
|
|
136
|
+
continue;
|
|
137
|
+
const validatorName = `${category.name}-${check}`;
|
|
138
|
+
targets.push({
|
|
139
|
+
source: `packages/runtime/src/control-plane/validators/${category.name}/${entry.name}`,
|
|
140
|
+
dest: resolve3(input.imageDir, `bin/validators/${validatorName}`),
|
|
141
|
+
cwd: input.hostProjectRoot
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return targets;
|
|
146
|
+
}
|
|
147
|
+
async function findLatestDistBinary(projectRoot) {
|
|
148
|
+
const distRoot = resolveControlPlaneHostDistDir(projectRoot);
|
|
149
|
+
if (!existsSync(distRoot)) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
const candidates = [];
|
|
153
|
+
for (const entry of readdirSync(distRoot, { withFileTypes: true })) {
|
|
154
|
+
if (!entry.name.startsWith("rig-") && entry.name !== "rig")
|
|
155
|
+
continue;
|
|
156
|
+
const entryPath = resolve3(distRoot, entry.name);
|
|
157
|
+
const binary = entry.isDirectory() ? resolve3(entryPath, "bin", "rig") : entryPath;
|
|
158
|
+
try {
|
|
159
|
+
const stat = statSync(binary);
|
|
160
|
+
if (stat.isFile())
|
|
161
|
+
candidates.push({ path: binary, mtimeMs: stat.mtimeMs });
|
|
162
|
+
} catch {}
|
|
163
|
+
}
|
|
164
|
+
candidates.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
165
|
+
for (const { path } of candidates) {
|
|
166
|
+
if (await isRunnableRigBinary(path, projectRoot))
|
|
167
|
+
return path;
|
|
168
|
+
}
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
async function isRunnableRigBinary(binaryPath, projectRoot) {
|
|
172
|
+
return runQuietBinaryProbe(binaryPath, ["help"], projectRoot);
|
|
173
|
+
}
|
|
174
|
+
async function runDistDoctor(projectRoot) {
|
|
175
|
+
const bunPath = Bun.which("bun");
|
|
176
|
+
const rigPath = Bun.which("rig");
|
|
177
|
+
const userBinDir = resolve3(homedir2(), ".local/bin");
|
|
178
|
+
const userBinInPath = (process.env.PATH || "").split(":").filter(Boolean).includes(userBinDir);
|
|
179
|
+
let rigRunnable = false;
|
|
180
|
+
if (rigPath) {
|
|
181
|
+
rigRunnable = await runQuietBinaryProbe(rigPath, ["help"], projectRoot);
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
bun: {
|
|
185
|
+
available: Boolean(bunPath),
|
|
186
|
+
path: bunPath || null,
|
|
187
|
+
version: Bun.version
|
|
188
|
+
},
|
|
189
|
+
rig: {
|
|
190
|
+
onPath: Boolean(rigPath),
|
|
191
|
+
path: rigPath || null,
|
|
192
|
+
runnable: rigRunnable
|
|
193
|
+
},
|
|
194
|
+
userBinDir,
|
|
195
|
+
userBinInPath,
|
|
196
|
+
latestDistBinary: await findLatestDistBinary(projectRoot)
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function rigRunSiblingOf(binaryPath) {
|
|
200
|
+
const name = binaryPath.split(/[\\/]/).pop() ?? "rig";
|
|
201
|
+
const suffix = name.toLowerCase().endsWith(".exe") ? ".exe" : "";
|
|
202
|
+
const stem = suffix ? name.slice(0, -suffix.length) : name;
|
|
203
|
+
const sibling = stem === "rig" ? `rig-run${suffix}` : stem.startsWith("rig-") ? `${stem.replace(/^rig/, "rig-run")}${suffix}` : `rig-run${suffix}`;
|
|
204
|
+
return resolve3(binaryPath, "..", sibling);
|
|
205
|
+
}
|
|
206
|
+
function installExecutable(source, target) {
|
|
207
|
+
if (resolve3(source) !== resolve3(target)) {
|
|
208
|
+
if (existsSync(target)) {
|
|
209
|
+
unlinkSync(target);
|
|
210
|
+
}
|
|
211
|
+
copyFileSync(source, target);
|
|
212
|
+
}
|
|
213
|
+
chmodSync(target, 493);
|
|
214
|
+
}
|
|
215
|
+
async function executeDist(context, args) {
|
|
216
|
+
const [command = "build", ...rest] = args;
|
|
217
|
+
switch (command) {
|
|
218
|
+
case "build": {
|
|
219
|
+
const { value: outputDir, rest: pending } = takeOption(rest, "--output-dir");
|
|
220
|
+
requireNoExtraArgs(pending, "rig dist build [--output-dir <dir>]");
|
|
221
|
+
const commandParts = ["bun", "run", "packages/cli/bin/build-rig-binaries.ts"];
|
|
222
|
+
if (outputDir)
|
|
223
|
+
commandParts.push("--output-dir", outputDir);
|
|
224
|
+
await context.runCommand(commandParts);
|
|
225
|
+
return { ok: true, group: "dist", command, details: { outputDir: outputDir || null } };
|
|
226
|
+
}
|
|
227
|
+
case "install": {
|
|
228
|
+
let pending = rest;
|
|
229
|
+
const scopeResult = takeOption(pending, "--scope");
|
|
230
|
+
pending = scopeResult.rest;
|
|
231
|
+
const pathResult = takeOption(pending, "--dir");
|
|
232
|
+
pending = pathResult.rest;
|
|
233
|
+
requireNoExtraArgs(pending, "rig dist install [--scope user|system] [--dir <dir>]");
|
|
234
|
+
const scope = parseInstallScope(scopeResult.value);
|
|
235
|
+
const installDir = resolveInstallDir(scope, pathResult.value);
|
|
236
|
+
mkdirSync(installDir, { recursive: true });
|
|
237
|
+
let source = await findLatestDistBinary(context.projectRoot);
|
|
238
|
+
let buildDir = null;
|
|
239
|
+
if (!source) {
|
|
240
|
+
buildDir = resolve3(resolveControlPlaneHostDistDir(context.projectRoot), `rig-install-${Date.now()}`);
|
|
241
|
+
await context.runCommand(["bun", "run", "packages/cli/bin/build-rig-binaries.ts", "--output-dir", buildDir]);
|
|
242
|
+
source = resolve3(buildDir, "bin", "rig");
|
|
243
|
+
}
|
|
244
|
+
if (!existsSync(source)) {
|
|
245
|
+
throw new CliError(`Unable to locate rig binary at ${source}.`, 2, { hint: "Build it first with `rig dist build`, then re-run `rig dist install`." });
|
|
246
|
+
}
|
|
247
|
+
const installedPath = resolve3(installDir, "rig");
|
|
248
|
+
const installedRigRunPath = rigRunSiblingOf(installedPath);
|
|
249
|
+
const sourceRigRun = rigRunSiblingOf(source);
|
|
250
|
+
installExecutable(source, installedPath);
|
|
251
|
+
installExecutable(existsSync(sourceRigRun) ? sourceRigRun : source, installedRigRunPath);
|
|
252
|
+
const pathEntries = (process.env.PATH || "").split(":").filter(Boolean);
|
|
253
|
+
const inPath = pathEntries.includes(installDir);
|
|
254
|
+
if (context.outputMode === "text") {
|
|
255
|
+
console.log(`Installed: ${installedPath}`);
|
|
256
|
+
console.log(`Installed: ${installedRigRunPath}`);
|
|
257
|
+
if (!inPath) {
|
|
258
|
+
console.log(`PATH note: add ${installDir} to PATH to run 'rig' directly.`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
ok: true,
|
|
263
|
+
group: "dist",
|
|
264
|
+
command,
|
|
265
|
+
details: {
|
|
266
|
+
scope,
|
|
267
|
+
installDir,
|
|
268
|
+
installedPath,
|
|
269
|
+
installedRigRunPath,
|
|
270
|
+
sourcePath: source,
|
|
271
|
+
sourceRigRunPath: existsSync(sourceRigRun) ? sourceRigRun : null,
|
|
272
|
+
builtNow: Boolean(buildDir),
|
|
273
|
+
inPath
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
case "doctor": {
|
|
278
|
+
requireNoExtraArgs(rest, "rig dist doctor");
|
|
279
|
+
const details = await runDistDoctor(context.projectRoot);
|
|
280
|
+
if (context.outputMode === "text") {
|
|
281
|
+
console.log(`bun: ${details.bun.available ? `ok (${details.bun.version})` : "missing"}`);
|
|
282
|
+
console.log(`rig on PATH: ${details.rig.onPath ? details.rig.path : "missing"}`);
|
|
283
|
+
console.log(`user bin dir: ${details.userBinDir} (${details.userBinInPath ? "in PATH" : "not in PATH"})`);
|
|
284
|
+
console.log(`latest dist binary: ${details.latestDistBinary || "none"}`);
|
|
285
|
+
}
|
|
286
|
+
return { ok: true, group: "dist", command, details };
|
|
287
|
+
}
|
|
288
|
+
case "rebuild-agent": {
|
|
289
|
+
requireNoExtraArgs(rest, "rig dist rebuild-agent");
|
|
290
|
+
const fp = await computeRuntimeImageFingerprint(context.projectRoot);
|
|
291
|
+
const currentId = computeRuntimeImageId(fp);
|
|
292
|
+
const imagesDir = resolve3(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "images");
|
|
293
|
+
mkdirSync(imagesDir, { recursive: true });
|
|
294
|
+
let pruned = 0;
|
|
295
|
+
for (const entry of readdirSync(imagesDir, { withFileTypes: true })) {
|
|
296
|
+
if (entry.isDirectory() && entry.name !== currentId) {
|
|
297
|
+
rmSync(resolve3(imagesDir, entry.name), { recursive: true, force: true });
|
|
298
|
+
pruned++;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (pruned > 0 && context.outputMode === "text") {
|
|
302
|
+
console.log(`Pruned ${pruned} stale image(s).`);
|
|
303
|
+
}
|
|
304
|
+
const imageDir = resolve3(imagesDir, currentId);
|
|
305
|
+
mkdirSync(resolve3(imageDir, "bin/hooks"), { recursive: true });
|
|
306
|
+
mkdirSync(resolve3(imageDir, "bin/plugins"), { recursive: true });
|
|
307
|
+
mkdirSync(resolve3(imageDir, "bin/validators"), { recursive: true });
|
|
308
|
+
const hookNames = [
|
|
309
|
+
"scope-guard",
|
|
310
|
+
"import-guard",
|
|
311
|
+
"safety-guard",
|
|
312
|
+
"test-integrity-guard",
|
|
313
|
+
"audit-trail",
|
|
314
|
+
"post-edit-lint",
|
|
315
|
+
"completion-verification",
|
|
316
|
+
"inject-context",
|
|
317
|
+
"task-runtime-start"
|
|
318
|
+
];
|
|
319
|
+
const targets = [];
|
|
320
|
+
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || context.projectRoot;
|
|
321
|
+
targets.push({ source: "packages/cli/bin/rig-agent.ts", dest: resolve3(imageDir, "bin/rig-agent"), cwd: hostProjectRoot });
|
|
322
|
+
targets.push({ source: "packages/runtime/bin/rig-agent-dispatch.ts", dest: resolve3(resolveControlPlaneHostBinDir(context.projectRoot), "rig-agent"), cwd: hostProjectRoot });
|
|
323
|
+
for (const hookName of hookNames) {
|
|
324
|
+
const src = `packages/runtime/src/control-plane/hooks/${hookName}.ts`;
|
|
325
|
+
targets.push({ source: src, dest: resolve3(imageDir, `bin/hooks/${hookName}`), cwd: hostProjectRoot });
|
|
326
|
+
targets.push({ source: src, dest: resolve3(resolveControlPlaneHostBinDir(context.projectRoot), `hooks/${hookName}`), cwd: hostProjectRoot });
|
|
327
|
+
}
|
|
328
|
+
const pluginsDir = resolve3(context.projectRoot, "rig/plugins");
|
|
329
|
+
const binPluginsDir = resolve3(resolveControlPlaneHostBinDir(context.projectRoot), "plugins");
|
|
330
|
+
const validatorsRoot = resolve3(hostProjectRoot, "packages/runtime/src/control-plane/validators");
|
|
331
|
+
const binValidatorsDir = resolve3(resolveControlPlaneHostBinDir(context.projectRoot), "validators");
|
|
332
|
+
mkdirSync(binPluginsDir, { recursive: true });
|
|
333
|
+
mkdirSync(binValidatorsDir, { recursive: true });
|
|
334
|
+
if (existsSync(pluginsDir)) {
|
|
335
|
+
for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
|
|
336
|
+
const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
337
|
+
if (!m)
|
|
338
|
+
continue;
|
|
339
|
+
targets.push({ source: `rig/plugins/${entry.name}`, dest: resolve3(imageDir, `bin/plugins/${m[1]}`), cwd: context.projectRoot });
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
targets.push(...collectRigValidatorBuildTargets({ contextProjectRoot: context.projectRoot, hostProjectRoot, imageDir }));
|
|
343
|
+
for (const { source, dest, cwd } of targets) {
|
|
344
|
+
if (context.outputMode === "text") {
|
|
345
|
+
console.log(`Building: ${dest}`);
|
|
346
|
+
}
|
|
347
|
+
const isValidator = dest.includes("/bin/validators/");
|
|
348
|
+
await buildBinary2(source, dest, cwd, isValidator ? { AGENT_BUN_PATH: Bun.which("bun") || "bun" } : { AGENT_PROJECT_ROOT: context.projectRoot });
|
|
349
|
+
}
|
|
350
|
+
if (existsSync(pluginsDir)) {
|
|
351
|
+
for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
|
|
352
|
+
const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
353
|
+
if (!m)
|
|
354
|
+
continue;
|
|
355
|
+
const pluginName = m[1];
|
|
356
|
+
const imageBin = resolve3(imageDir, `bin/plugins/${pluginName}`);
|
|
357
|
+
if (!pluginName)
|
|
358
|
+
continue;
|
|
359
|
+
const symlinkPath = resolve3(binPluginsDir, pluginName);
|
|
360
|
+
if (existsSync(imageBin)) {
|
|
361
|
+
try {
|
|
362
|
+
unlinkSync(symlinkPath);
|
|
363
|
+
} catch {}
|
|
364
|
+
symlinkSync(imageBin, symlinkPath);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (existsSync(validatorsRoot)) {
|
|
369
|
+
const categories = readdirSync(validatorsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|
|
370
|
+
for (const category of categories) {
|
|
371
|
+
const categoryDir = resolve3(validatorsRoot, category.name);
|
|
372
|
+
for (const entry of readdirSync(categoryDir, { withFileTypes: true })) {
|
|
373
|
+
if (!entry.isFile() || !entry.name.endsWith(".ts"))
|
|
374
|
+
continue;
|
|
375
|
+
const check = entry.name.replace(/\.ts$/, "");
|
|
376
|
+
if (!check || check === "index" || check === "shared")
|
|
377
|
+
continue;
|
|
378
|
+
const validatorName = `${category.name}-${check}`;
|
|
379
|
+
const imageBin = resolve3(imageDir, `bin/validators/${validatorName}`);
|
|
380
|
+
const symlinkPath = resolve3(binValidatorsDir, validatorName);
|
|
381
|
+
if (existsSync(imageBin)) {
|
|
382
|
+
try {
|
|
383
|
+
unlinkSync(symlinkPath);
|
|
384
|
+
} catch {}
|
|
385
|
+
symlinkSync(imageBin, symlinkPath);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
const agentsDir = resolve3(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "agents");
|
|
391
|
+
if (existsSync(agentsDir)) {
|
|
392
|
+
let relinkCount = 0;
|
|
393
|
+
for (const agentEntry of readdirSync(agentsDir, { withFileTypes: true })) {
|
|
394
|
+
if (!agentEntry.isDirectory())
|
|
395
|
+
continue;
|
|
396
|
+
const agentBinDir = resolve3(agentsDir, agentEntry.name, "worktree", ".rig", "bin");
|
|
397
|
+
if (!existsSync(agentBinDir))
|
|
398
|
+
continue;
|
|
399
|
+
const walkDir = (dir) => {
|
|
400
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
401
|
+
const fullPath = resolve3(dir, entry.name);
|
|
402
|
+
if (entry.isDirectory()) {
|
|
403
|
+
walkDir(fullPath);
|
|
404
|
+
} else if (entry.isSymbolicLink()) {
|
|
405
|
+
const target = readlinkSync(fullPath);
|
|
406
|
+
if (target.includes("/.rig/runtime/images/") && !target.includes(`/${currentId}/`)) {
|
|
407
|
+
const newTarget = target.replace(/\/\.rig\/runtime\/images\/[^/]+\//, `/.rig/runtime/images/${currentId}/`);
|
|
408
|
+
try {
|
|
409
|
+
unlinkSync(fullPath);
|
|
410
|
+
symlinkSync(newTarget, fullPath);
|
|
411
|
+
relinkCount++;
|
|
412
|
+
} catch {}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
walkDir(agentBinDir);
|
|
418
|
+
}
|
|
419
|
+
if (relinkCount > 0 && context.outputMode === "text") {
|
|
420
|
+
console.log(`Re-linked ${relinkCount} worktree symlink(s) to image ${currentId}.`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (context.outputMode === "text") {
|
|
424
|
+
console.log(`Rebuilt ${targets.length} binaries into image ${currentId}.`);
|
|
425
|
+
}
|
|
426
|
+
return { ok: true, group: "dist", command, details: { imageId: currentId, count: targets.length } };
|
|
427
|
+
}
|
|
428
|
+
default:
|
|
429
|
+
throw new CliError(`Unknown dist command: ${command}`, 1, { hint: "Run `rig dist --help` \u2014 commands are build|install|doctor|rebuild-agent." });
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
export {
|
|
433
|
+
executeDist,
|
|
434
|
+
collectRigValidatorBuildTargets
|
|
435
|
+
};
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/cli-surface-plugin/src/runner.ts
|
|
3
|
+
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
4
|
+
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
5
|
+
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
6
|
+
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
7
|
+
|
|
8
|
+
class CliError extends RuntimeCliError {
|
|
9
|
+
hint;
|
|
10
|
+
constructor(message, exitCode = 1, options = {}) {
|
|
11
|
+
super(message, exitCode);
|
|
12
|
+
if (options.hint?.trim()) {
|
|
13
|
+
this.hint = options.hint.trim();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function requireNoExtraArgs(args, usage) {
|
|
18
|
+
if (args.length > 0) {
|
|
19
|
+
throw new CliError(`Unexpected arguments: ${args.join(" ")}
|
|
20
|
+
Usage: ${usage}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// packages/cli-surface-plugin/src/commands/_doctor-checks.ts
|
|
25
|
+
import { countDoctorFailures, runDoctorChecks } from "@rig/client";
|
|
26
|
+
var runRigDoctorChecks = runDoctorChecks;
|
|
27
|
+
function formatDoctorChecks(checks) {
|
|
28
|
+
return checks.map((entry) => {
|
|
29
|
+
const status = String(entry.status ?? entry.level ?? "warn");
|
|
30
|
+
const marker = status === "pass" || status === "ok" ? "OK" : status === "warn" ? "WARN" : "FAIL";
|
|
31
|
+
return `${marker}: ${entry.label}${entry.detail ? ` \u2014 ${entry.detail}` : ""}${entry.remediation ? `
|
|
32
|
+
fix: ${entry.remediation}` : ""}`;
|
|
33
|
+
}).join(`
|
|
34
|
+
`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// packages/cli-surface-plugin/src/commands/_async-ui.ts
|
|
38
|
+
import pc from "picocolors";
|
|
39
|
+
|
|
40
|
+
// packages/cli-surface-plugin/src/commands/_spinner.ts
|
|
41
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
42
|
+
function createTtySpinner(input) {
|
|
43
|
+
const output = input.output ?? process.stdout;
|
|
44
|
+
const isTty = output.isTTY === true;
|
|
45
|
+
const frames = input.frames && input.frames.length > 0 ? input.frames : SPINNER_FRAMES;
|
|
46
|
+
let label = input.label;
|
|
47
|
+
let frame = 0;
|
|
48
|
+
let paused = false;
|
|
49
|
+
let stopped = false;
|
|
50
|
+
let lastPrintedLabel = "";
|
|
51
|
+
const render = () => {
|
|
52
|
+
if (stopped || paused)
|
|
53
|
+
return;
|
|
54
|
+
if (!isTty) {
|
|
55
|
+
if (label !== lastPrintedLabel) {
|
|
56
|
+
output.write(`${label}
|
|
57
|
+
`);
|
|
58
|
+
lastPrintedLabel = label;
|
|
59
|
+
}
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
frame = (frame + 1) % frames.length;
|
|
63
|
+
const glyph = frames[frame] ?? frames[0] ?? "";
|
|
64
|
+
output.write(`\r\x1B[2K${input.styleFrame ? input.styleFrame(glyph) : glyph} ${label}`);
|
|
65
|
+
};
|
|
66
|
+
const clearLine = () => {
|
|
67
|
+
if (isTty)
|
|
68
|
+
output.write("\r\x1B[2K");
|
|
69
|
+
};
|
|
70
|
+
render();
|
|
71
|
+
const timer = isTty ? setInterval(render, input.intervalMs ?? 16) : null;
|
|
72
|
+
return {
|
|
73
|
+
setLabel(next) {
|
|
74
|
+
label = next;
|
|
75
|
+
render();
|
|
76
|
+
},
|
|
77
|
+
pause() {
|
|
78
|
+
paused = true;
|
|
79
|
+
clearLine();
|
|
80
|
+
},
|
|
81
|
+
resume() {
|
|
82
|
+
if (stopped)
|
|
83
|
+
return;
|
|
84
|
+
paused = false;
|
|
85
|
+
render();
|
|
86
|
+
},
|
|
87
|
+
stop(finalLine) {
|
|
88
|
+
if (stopped)
|
|
89
|
+
return;
|
|
90
|
+
stopped = true;
|
|
91
|
+
if (timer)
|
|
92
|
+
clearInterval(timer);
|
|
93
|
+
clearLine();
|
|
94
|
+
if (finalLine)
|
|
95
|
+
output.write(`${finalLine}
|
|
96
|
+
`);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// packages/cli-surface-plugin/src/commands/_async-ui.ts
|
|
102
|
+
var FRAMES = ["\u25D0", "\u25D3", "\u25D1", "\u25D2"];
|
|
103
|
+
var DONE_SYMBOL = pc.green("\u25C7");
|
|
104
|
+
var FAIL_SYMBOL = pc.red("\u25A0");
|
|
105
|
+
var activeUpdate = null;
|
|
106
|
+
async function withSpinner(label, work, options = {}) {
|
|
107
|
+
if (options.outputMode === "json") {
|
|
108
|
+
return work(() => {
|
|
109
|
+
return;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (activeUpdate) {
|
|
113
|
+
activeUpdate(label);
|
|
114
|
+
return work(activeUpdate);
|
|
115
|
+
}
|
|
116
|
+
const output = options.output ?? process.stderr;
|
|
117
|
+
const isTty = output.isTTY === true;
|
|
118
|
+
let lastLabel = label;
|
|
119
|
+
if (!isTty) {
|
|
120
|
+
output.write(`${label}
|
|
121
|
+
`);
|
|
122
|
+
const update2 = (next) => {
|
|
123
|
+
lastLabel = next;
|
|
124
|
+
};
|
|
125
|
+
activeUpdate = update2;
|
|
126
|
+
try {
|
|
127
|
+
return await work(update2);
|
|
128
|
+
} finally {
|
|
129
|
+
activeUpdate = null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const spinner = createTtySpinner({
|
|
133
|
+
label,
|
|
134
|
+
output,
|
|
135
|
+
frames: FRAMES,
|
|
136
|
+
styleFrame: (frame) => pc.cyan(frame)
|
|
137
|
+
});
|
|
138
|
+
const update = (next) => {
|
|
139
|
+
lastLabel = next;
|
|
140
|
+
spinner.setLabel(next);
|
|
141
|
+
};
|
|
142
|
+
activeUpdate = update;
|
|
143
|
+
try {
|
|
144
|
+
const result = await work(update);
|
|
145
|
+
spinner.stop(options.doneLabel ? `${DONE_SYMBOL} ${options.doneLabel}` : undefined);
|
|
146
|
+
return result;
|
|
147
|
+
} catch (error) {
|
|
148
|
+
spinner.stop(`${FAIL_SYMBOL} ${lastLabel}`);
|
|
149
|
+
throw error;
|
|
150
|
+
} finally {
|
|
151
|
+
activeUpdate = null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// packages/cli-surface-plugin/src/commands/doctor.ts
|
|
156
|
+
async function executeDoctor(context, args) {
|
|
157
|
+
requireNoExtraArgs(args, "legacy diagnostic: rig doctor");
|
|
158
|
+
const checks = await withSpinner("Running doctor checks\u2026", (update) => runRigDoctorChecks({ projectRoot: context.projectRoot, onProgress: update }), { outputMode: context.outputMode });
|
|
159
|
+
if (context.outputMode === "text") {
|
|
160
|
+
console.log(formatDoctorChecks(checks));
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
ok: countDoctorFailures(checks) === 0,
|
|
164
|
+
group: "doctor",
|
|
165
|
+
command: "check",
|
|
166
|
+
details: { checks, failures: countDoctorFailures(checks) }
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
export {
|
|
170
|
+
executeDoctor
|
|
171
|
+
};
|