@h-rig/cli 0.0.6-alpha.100 → 0.0.6-alpha.102
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 -27
- package/bin/rig.js +16 -0
- package/package.json +14 -40
- package/dist/bin/build-rig-binaries.d.ts +0 -2
- package/dist/bin/build-rig-binaries.js +0 -119
- package/dist/bin/rig.d.ts +0 -72
- package/dist/bin/rig.js +0 -17875
- package/dist/config/rig-default-config.yml +0 -5
- package/dist/src/app/drone-ui.d.ts +0 -34
- package/dist/src/app/drone-ui.js +0 -278
- package/dist/src/commands/_async-ui.d.ts +0 -10
- package/dist/src/commands/_async-ui.js +0 -121
- package/dist/src/commands/_cli-format.d.ts +0 -56
- package/dist/src/commands/_cli-format.js +0 -319
- package/dist/src/commands/_config-env.d.ts +0 -18
- package/dist/src/commands/_config-env.js +0 -22
- package/dist/src/commands/_connection-state.d.ts +0 -54
- package/dist/src/commands/_connection-state.js +0 -187
- package/dist/src/commands/_doctor-checks.d.ts +0 -46
- package/dist/src/commands/_doctor-checks.js +0 -352
- package/dist/src/commands/_help-catalog.d.ts +0 -29
- package/dist/src/commands/_help-catalog.js +0 -146
- package/dist/src/commands/_inprocess-services.d.ts +0 -33
- package/dist/src/commands/_inprocess-services.js +0 -102
- package/dist/src/commands/_json-output.d.ts +0 -11
- package/dist/src/commands/_json-output.js +0 -60
- package/dist/src/commands/_lazy-reconcile.d.ts +0 -34
- package/dist/src/commands/_lazy-reconcile.js +0 -102
- package/dist/src/commands/_parsers.d.ts +0 -15
- package/dist/src/commands/_parsers.js +0 -114
- package/dist/src/commands/_paths.d.ts +0 -11
- package/dist/src/commands/_paths.js +0 -50
- package/dist/src/commands/_pi-frontend.d.ts +0 -35
- package/dist/src/commands/_pi-frontend.js +0 -64
- package/dist/src/commands/_pi-install.d.ts +0 -42
- package/dist/src/commands/_pi-install.js +0 -167
- package/dist/src/commands/_policy.d.ts +0 -8
- package/dist/src/commands/_policy.js +0 -127
- package/dist/src/commands/_probes.d.ts +0 -1
- package/dist/src/commands/_probes.js +0 -13
- package/dist/src/commands/_run-bridge.d.ts +0 -114
- package/dist/src/commands/_run-bridge.js +0 -387
- package/dist/src/commands/_run-diagnostics.d.ts +0 -9
- package/dist/src/commands/_run-diagnostics.js +0 -51
- package/dist/src/commands/_run-driver-helpers.d.ts +0 -26
- package/dist/src/commands/_run-driver-helpers.js +0 -138
- package/dist/src/commands/_run-projection.d.ts +0 -50
- package/dist/src/commands/_run-projection.js +0 -349
- package/dist/src/commands/_run-subcommands.d.ts +0 -3
- package/dist/src/commands/_run-subcommands.js +0 -31
- package/dist/src/commands/_spinner.d.ts +0 -25
- package/dist/src/commands/_spinner.js +0 -65
- package/dist/src/commands/agent.d.ts +0 -3
- package/dist/src/commands/agent.js +0 -8952
- package/dist/src/commands/config.d.ts +0 -3
- package/dist/src/commands/config.js +0 -181
- package/dist/src/commands/dist.d.ts +0 -28
- package/dist/src/commands/dist.js +0 -417
- package/dist/src/commands/doctor.d.ts +0 -3
- package/dist/src/commands/doctor.js +0 -480
- package/dist/src/commands/github.d.ts +0 -3
- package/dist/src/commands/github.js +0 -342
- package/dist/src/commands/inbox.d.ts +0 -28
- package/dist/src/commands/inbox.js +0 -579
- package/dist/src/commands/init.d.ts +0 -64
- package/dist/src/commands/init.js +0 -1541
- package/dist/src/commands/inspect.d.ts +0 -20
- package/dist/src/commands/inspect.js +0 -764
- package/dist/src/commands/pi.d.ts +0 -3
- package/dist/src/commands/pi.js +0 -177
- package/dist/src/commands/plugin.d.ts +0 -16
- package/dist/src/commands/plugin.js +0 -714
- package/dist/src/commands/profile-and-review.d.ts +0 -4
- package/dist/src/commands/profile-and-review.js +0 -223
- package/dist/src/commands/queue.d.ts +0 -3
- package/dist/src/commands/queue.js +0 -197
- package/dist/src/commands/remote.d.ts +0 -3
- package/dist/src/commands/remote.js +0 -1340
- package/dist/src/commands/repo-git-harness.d.ts +0 -5
- package/dist/src/commands/repo-git-harness.js +0 -271
- package/dist/src/commands/run.d.ts +0 -21
- package/dist/src/commands/run.js +0 -17867
- package/dist/src/commands/server.d.ts +0 -3
- package/dist/src/commands/server.js +0 -249
- package/dist/src/commands/setup.d.ts +0 -16
- package/dist/src/commands/setup.js +0 -644
- package/dist/src/commands/stats.d.ts +0 -15
- package/dist/src/commands/stats.js +0 -632
- package/dist/src/commands/task-run-driver.d.ts +0 -94
- package/dist/src/commands/task-run-driver.js +0 -203
- package/dist/src/commands/task.d.ts +0 -35
- package/dist/src/commands/task.js +0 -818
- package/dist/src/commands/test.d.ts +0 -3
- package/dist/src/commands/test.js +0 -46
- package/dist/src/commands/triage.d.ts +0 -11
- package/dist/src/commands/triage.js +0 -227
- package/dist/src/commands/workspace.d.ts +0 -3
- package/dist/src/commands/workspace.js +0 -130
- package/dist/src/commands.d.ts +0 -13
- package/dist/src/commands.js +0 -17999
- package/dist/src/index.d.ts +0 -4
- package/dist/src/index.js +0 -18011
- package/dist/src/launcher.d.ts +0 -61
- package/dist/src/launcher.js +0 -199
- package/dist/src/operator-cli.d.ts +0 -2
- package/dist/src/operator-cli.js +0 -17867
- package/dist/src/operator-entry.d.ts +0 -1
- package/dist/src/operator-entry.js +0 -3
- package/dist/src/runner.d.ts +0 -47
- package/dist/src/runner.js +0 -267
- package/dist/src/withMutedConsole.d.ts +0 -2
- package/dist/src/withMutedConsole.js +0 -42
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// packages/cli/src/commands/config.ts
|
|
3
|
-
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
4
|
-
import { resolve } from "path";
|
|
5
|
-
import { loadConfig } from "@rig/core/load-config";
|
|
6
|
-
import {
|
|
7
|
-
DEFAULT_RIG_RELAY_URL,
|
|
8
|
-
DEFAULT_RIG_REGISTRY_URL,
|
|
9
|
-
resolveRegistryBaseUrl,
|
|
10
|
-
resolveRegistrySecret,
|
|
11
|
-
resolveRelayUrl
|
|
12
|
-
} from "@rig/runtime/control-plane/remote";
|
|
13
|
-
|
|
14
|
-
// packages/cli/src/runner.ts
|
|
15
|
-
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
16
|
-
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
17
|
-
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
18
|
-
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
19
|
-
|
|
20
|
-
class CliError extends RuntimeCliError {
|
|
21
|
-
hint;
|
|
22
|
-
constructor(message, exitCode = 1, options = {}) {
|
|
23
|
-
super(message, exitCode);
|
|
24
|
-
if (options.hint?.trim()) {
|
|
25
|
-
this.hint = options.hint.trim();
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
function requireNoExtraArgs(args, usage) {
|
|
30
|
-
if (args.length > 0) {
|
|
31
|
-
throw new CliError(`Unexpected arguments: ${args.join(" ")}
|
|
32
|
-
Usage: ${usage}`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// packages/cli/src/commands/_cli-format.ts
|
|
37
|
-
import pc from "picocolors";
|
|
38
|
-
var dim = pc.dim;
|
|
39
|
-
var faintBar = pc.dim("\u2502");
|
|
40
|
-
var accent = pc.cyan;
|
|
41
|
-
function printFormattedOutput(message) {
|
|
42
|
-
console.log(message);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// packages/cli/src/commands/config.ts
|
|
46
|
-
var KNOBS = {
|
|
47
|
-
"runtime.server.relayUrl": { env: "RIG_COLLAB_RELAY", effective: () => resolveRelayUrl(), def: DEFAULT_RIG_RELAY_URL },
|
|
48
|
-
"runtime.server.registryUrl": { env: "RIG_REGISTRY_URL", effective: (r) => resolveRegistryBaseUrl(r), def: DEFAULT_RIG_REGISTRY_URL },
|
|
49
|
-
"runtime.server.registrySecret": { env: "RIG_REGISTRY_SHARED_SECRET", effective: (r) => resolveRegistrySecret(r), def: "(built-in default)" },
|
|
50
|
-
"runtime.server.sshTarget": { env: "RIG_SSH_TARGET", effective: () => process.env.RIG_SSH_TARGET?.trim() ?? "(none \u2014 local placement)", def: "(none)" }
|
|
51
|
-
};
|
|
52
|
-
var ALIASES = {
|
|
53
|
-
relayUrl: "runtime.server.relayUrl",
|
|
54
|
-
registryUrl: "runtime.server.registryUrl",
|
|
55
|
-
registrySecret: "runtime.server.registrySecret",
|
|
56
|
-
sshTarget: "runtime.server.sshTarget"
|
|
57
|
-
};
|
|
58
|
-
function canonicalKey(key) {
|
|
59
|
-
return ALIASES[key] ?? key;
|
|
60
|
-
}
|
|
61
|
-
async function loadProjectConfig(root) {
|
|
62
|
-
try {
|
|
63
|
-
return await loadConfig(root);
|
|
64
|
-
} catch {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function configHasKnob(config, canonical, envKey) {
|
|
69
|
-
if (!config)
|
|
70
|
-
return false;
|
|
71
|
-
const server = config.runtime?.server;
|
|
72
|
-
const field = canonical.replace("runtime.server.", "");
|
|
73
|
-
if (server && server[field] !== undefined)
|
|
74
|
-
return true;
|
|
75
|
-
if (server && server.host !== undefined && (field === "relayUrl" || field === "registryUrl"))
|
|
76
|
-
return true;
|
|
77
|
-
const envMap = config.env;
|
|
78
|
-
return Boolean(envMap && envMap[envKey] !== undefined);
|
|
79
|
-
}
|
|
80
|
-
function describe(root, config, canonical) {
|
|
81
|
-
const knob = KNOBS[canonical];
|
|
82
|
-
if (!knob) {
|
|
83
|
-
const val = process.env[canonical];
|
|
84
|
-
const fromConfig = Boolean(config?.env?.[canonical]);
|
|
85
|
-
return `${canonical} = ${val ?? "(unset)"} [${val === undefined ? "default" : fromConfig ? "rig.config.ts" : "env"}]`;
|
|
86
|
-
}
|
|
87
|
-
const value = knob.effective(root);
|
|
88
|
-
const inConfig = configHasKnob(config, canonical, knob.env);
|
|
89
|
-
const ambient = Boolean(process.env[knob.env]);
|
|
90
|
-
const source = inConfig ? "rig.config.ts" : ambient ? "env" : "default";
|
|
91
|
-
return `${canonical} = ${value} [${source}]`;
|
|
92
|
-
}
|
|
93
|
-
async function configGet(context, args) {
|
|
94
|
-
const root = context.projectRoot;
|
|
95
|
-
const config = await loadProjectConfig(root);
|
|
96
|
-
const text = context.outputMode === "text";
|
|
97
|
-
if (args[0]) {
|
|
98
|
-
const canonical = canonicalKey(args[0]);
|
|
99
|
-
requireNoExtraArgs(args.slice(1), "rig config get [<key>]");
|
|
100
|
-
if (text)
|
|
101
|
-
printFormattedOutput(describe(root, config, canonical));
|
|
102
|
-
return { ok: true, group: "config", command: "get", details: { key: canonical } };
|
|
103
|
-
}
|
|
104
|
-
const lines = ["\u25C6 Rig config \u2014 effective values (ambient env \u2192 rig.config.ts \u2192 default)"];
|
|
105
|
-
for (const canonical of Object.keys(KNOBS))
|
|
106
|
-
lines.push(` ${describe(root, config, canonical)}`);
|
|
107
|
-
const envMap = config?.env ?? {};
|
|
108
|
-
const envKeys = Object.keys(envMap);
|
|
109
|
-
lines.push(envKeys.length ? ` env overrides: ${envKeys.join(", ")}` : " env overrides: (none)");
|
|
110
|
-
if (text)
|
|
111
|
-
printFormattedOutput(lines.join(`
|
|
112
|
-
`));
|
|
113
|
-
return { ok: true, group: "config", command: "get", details: {} };
|
|
114
|
-
}
|
|
115
|
-
function writeEnvOverride(source, envKey, value) {
|
|
116
|
-
const entry = ` ${JSON.stringify(envKey)}: ${JSON.stringify(value)},`;
|
|
117
|
-
const envBlock = /env\s*:\s*\{([\s\S]*?)\}/m;
|
|
118
|
-
const m = envBlock.exec(source);
|
|
119
|
-
if (m) {
|
|
120
|
-
const body = m[1] ?? "";
|
|
121
|
-
const keyRe = new RegExp(`(^|\\n)\\s*${envKey.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")}\\s*:\\s*[^,\\n]*,?`, "m");
|
|
122
|
-
const quotedRe = new RegExp(`(^|\\n)\\s*["']${envKey}["']\\s*:\\s*[^,\\n]*,?`, "m");
|
|
123
|
-
if (keyRe.test(body) || quotedRe.test(body)) {
|
|
124
|
-
const newBody = body.replace(quotedRe, `
|
|
125
|
-
${entry}`).replace(keyRe, `
|
|
126
|
-
${entry}`);
|
|
127
|
-
return source.replace(envBlock, `env: {${newBody}
|
|
128
|
-
}`);
|
|
129
|
-
}
|
|
130
|
-
return source.replace(envBlock, `env: {
|
|
131
|
-
${entry}${body}}`);
|
|
132
|
-
}
|
|
133
|
-
const defRe = /defineConfig\s*\(\s*\{/m;
|
|
134
|
-
if (!defRe.test(source)) {
|
|
135
|
-
throw new CliError("Could not find `defineConfig({` in rig.config.ts to insert an env override.", 2, {
|
|
136
|
-
hint: `Add manually: env: { ${JSON.stringify(envKey)}: ${JSON.stringify(value)} }`
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
return source.replace(defRe, (match) => `${match}
|
|
140
|
-
env: {
|
|
141
|
-
${entry}
|
|
142
|
-
},`);
|
|
143
|
-
}
|
|
144
|
-
async function configSet(context, args) {
|
|
145
|
-
const [rawKey, ...valueParts] = args;
|
|
146
|
-
if (!rawKey || valueParts.length === 0) {
|
|
147
|
-
throw new CliError("Usage: rig config set <key> <value>", 2, {
|
|
148
|
-
hint: `Keys: ${Object.keys(ALIASES).join(", ")}, or any RIG_* env var.`
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
const value = valueParts.join(" ");
|
|
152
|
-
const canonical = canonicalKey(rawKey);
|
|
153
|
-
const envKey = KNOBS[canonical]?.env ?? canonical;
|
|
154
|
-
const configPath = resolve(context.projectRoot, "rig.config.ts");
|
|
155
|
-
if (!existsSync(configPath)) {
|
|
156
|
-
throw new CliError(`No rig.config.ts at ${context.projectRoot}.`, 2, { hint: "Run `rig init` first." });
|
|
157
|
-
}
|
|
158
|
-
const source = readFileSync(configPath, "utf8");
|
|
159
|
-
const updated = writeEnvOverride(source, envKey, value);
|
|
160
|
-
writeFileSync(configPath, updated);
|
|
161
|
-
if (context.outputMode === "text") {
|
|
162
|
-
printFormattedOutput(`Set ${canonical} (env ${envKey}) = ${value} in rig.config.ts`);
|
|
163
|
-
}
|
|
164
|
-
return { ok: true, group: "config", command: "set", details: { key: canonical, env: envKey, value } };
|
|
165
|
-
}
|
|
166
|
-
async function executeConfig(context, args) {
|
|
167
|
-
const [sub, ...rest] = args;
|
|
168
|
-
switch (sub) {
|
|
169
|
-
case "get":
|
|
170
|
-
return configGet(context, rest);
|
|
171
|
-
case "set":
|
|
172
|
-
return configSet(context, rest);
|
|
173
|
-
default:
|
|
174
|
-
throw new CliError("Usage: rig config <get|set>", 2, {
|
|
175
|
-
hint: "rig config get [<key>] \u2014 effective value + source; rig config set <key> <value> \u2014 write to rig.config.ts"
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
export {
|
|
180
|
-
executeConfig
|
|
181
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { type RunnerContext } from "../runner";
|
|
2
|
-
import type { CommandOutcome } from "@rig/runtime";
|
|
3
|
-
export type DistDoctorDetails = {
|
|
4
|
-
bun: {
|
|
5
|
-
available: boolean;
|
|
6
|
-
path: string | null;
|
|
7
|
-
version: string;
|
|
8
|
-
};
|
|
9
|
-
rig: {
|
|
10
|
-
onPath: boolean;
|
|
11
|
-
path: string | null;
|
|
12
|
-
runnable: boolean;
|
|
13
|
-
};
|
|
14
|
-
userBinDir: string;
|
|
15
|
-
userBinInPath: boolean;
|
|
16
|
-
latestDistBinary: string | null;
|
|
17
|
-
};
|
|
18
|
-
export type BuildTarget = {
|
|
19
|
-
source: string;
|
|
20
|
-
dest: string;
|
|
21
|
-
cwd: string;
|
|
22
|
-
};
|
|
23
|
-
export declare function collectRigValidatorBuildTargets(input: {
|
|
24
|
-
contextProjectRoot: string;
|
|
25
|
-
hostProjectRoot: string;
|
|
26
|
-
imageDir: string;
|
|
27
|
-
}): BuildTarget[];
|
|
28
|
-
export declare function executeDist(context: RunnerContext, args: string[]): Promise<CommandOutcome>;
|
|
@@ -1,417 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// packages/cli/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/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/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/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/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/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/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
|
-
async function executeDist(context, args) {
|
|
200
|
-
const [command = "build", ...rest] = args;
|
|
201
|
-
switch (command) {
|
|
202
|
-
case "build": {
|
|
203
|
-
const { value: outputDir, rest: pending } = takeOption(rest, "--output-dir");
|
|
204
|
-
requireNoExtraArgs(pending, "rig dist build [--output-dir <dir>]");
|
|
205
|
-
const commandParts = ["bun", "run", "packages/cli/bin/build-rig-binaries.ts"];
|
|
206
|
-
if (outputDir)
|
|
207
|
-
commandParts.push("--output-dir", outputDir);
|
|
208
|
-
await context.runCommand(commandParts);
|
|
209
|
-
return { ok: true, group: "dist", command, details: { outputDir: outputDir || null } };
|
|
210
|
-
}
|
|
211
|
-
case "install": {
|
|
212
|
-
let pending = rest;
|
|
213
|
-
const scopeResult = takeOption(pending, "--scope");
|
|
214
|
-
pending = scopeResult.rest;
|
|
215
|
-
const pathResult = takeOption(pending, "--dir");
|
|
216
|
-
pending = pathResult.rest;
|
|
217
|
-
requireNoExtraArgs(pending, "rig dist install [--scope user|system] [--dir <dir>]");
|
|
218
|
-
const scope = parseInstallScope(scopeResult.value);
|
|
219
|
-
const installDir = resolveInstallDir(scope, pathResult.value);
|
|
220
|
-
mkdirSync(installDir, { recursive: true });
|
|
221
|
-
let source = await findLatestDistBinary(context.projectRoot);
|
|
222
|
-
let buildDir = null;
|
|
223
|
-
if (!source) {
|
|
224
|
-
buildDir = resolve3(resolveControlPlaneHostDistDir(context.projectRoot), `rig-install-${Date.now()}`);
|
|
225
|
-
await context.runCommand(["bun", "run", "packages/cli/bin/build-rig-binaries.ts", "--output-dir", buildDir]);
|
|
226
|
-
source = resolve3(buildDir, "bin", "rig");
|
|
227
|
-
}
|
|
228
|
-
if (!existsSync(source)) {
|
|
229
|
-
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`." });
|
|
230
|
-
}
|
|
231
|
-
const installedPath = resolve3(installDir, "rig");
|
|
232
|
-
if (existsSync(installedPath)) {
|
|
233
|
-
unlinkSync(installedPath);
|
|
234
|
-
}
|
|
235
|
-
copyFileSync(source, installedPath);
|
|
236
|
-
chmodSync(installedPath, 493);
|
|
237
|
-
const pathEntries = (process.env.PATH || "").split(":").filter(Boolean);
|
|
238
|
-
const inPath = pathEntries.includes(installDir);
|
|
239
|
-
if (context.outputMode === "text") {
|
|
240
|
-
console.log(`Installed: ${installedPath}`);
|
|
241
|
-
if (!inPath) {
|
|
242
|
-
console.log(`PATH note: add ${installDir} to PATH to run 'rig' directly.`);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
return {
|
|
246
|
-
ok: true,
|
|
247
|
-
group: "dist",
|
|
248
|
-
command,
|
|
249
|
-
details: {
|
|
250
|
-
scope,
|
|
251
|
-
installDir,
|
|
252
|
-
installedPath,
|
|
253
|
-
sourcePath: source,
|
|
254
|
-
builtNow: Boolean(buildDir),
|
|
255
|
-
inPath
|
|
256
|
-
}
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
case "doctor": {
|
|
260
|
-
requireNoExtraArgs(rest, "rig dist doctor");
|
|
261
|
-
const details = await runDistDoctor(context.projectRoot);
|
|
262
|
-
if (context.outputMode === "text") {
|
|
263
|
-
console.log(`bun: ${details.bun.available ? `ok (${details.bun.version})` : "missing"}`);
|
|
264
|
-
console.log(`rig on PATH: ${details.rig.onPath ? details.rig.path : "missing"}`);
|
|
265
|
-
console.log(`user bin dir: ${details.userBinDir} (${details.userBinInPath ? "in PATH" : "not in PATH"})`);
|
|
266
|
-
console.log(`latest dist binary: ${details.latestDistBinary || "none"}`);
|
|
267
|
-
}
|
|
268
|
-
return { ok: true, group: "dist", command, details };
|
|
269
|
-
}
|
|
270
|
-
case "rebuild-agent": {
|
|
271
|
-
requireNoExtraArgs(rest, "rig dist rebuild-agent");
|
|
272
|
-
const fp = await computeRuntimeImageFingerprint(context.projectRoot);
|
|
273
|
-
const currentId = computeRuntimeImageId(fp);
|
|
274
|
-
const imagesDir = resolve3(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "images");
|
|
275
|
-
mkdirSync(imagesDir, { recursive: true });
|
|
276
|
-
let pruned = 0;
|
|
277
|
-
for (const entry of readdirSync(imagesDir, { withFileTypes: true })) {
|
|
278
|
-
if (entry.isDirectory() && entry.name !== currentId) {
|
|
279
|
-
rmSync(resolve3(imagesDir, entry.name), { recursive: true, force: true });
|
|
280
|
-
pruned++;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
if (pruned > 0 && context.outputMode === "text") {
|
|
284
|
-
console.log(`Pruned ${pruned} stale image(s).`);
|
|
285
|
-
}
|
|
286
|
-
const imageDir = resolve3(imagesDir, currentId);
|
|
287
|
-
mkdirSync(resolve3(imageDir, "bin/hooks"), { recursive: true });
|
|
288
|
-
mkdirSync(resolve3(imageDir, "bin/plugins"), { recursive: true });
|
|
289
|
-
mkdirSync(resolve3(imageDir, "bin/validators"), { recursive: true });
|
|
290
|
-
const hookNames = [
|
|
291
|
-
"scope-guard",
|
|
292
|
-
"import-guard",
|
|
293
|
-
"safety-guard",
|
|
294
|
-
"test-integrity-guard",
|
|
295
|
-
"audit-trail",
|
|
296
|
-
"post-edit-lint",
|
|
297
|
-
"completion-verification",
|
|
298
|
-
"inject-context",
|
|
299
|
-
"task-runtime-start"
|
|
300
|
-
];
|
|
301
|
-
const targets = [];
|
|
302
|
-
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || context.projectRoot;
|
|
303
|
-
targets.push({ source: "packages/runtime/bin/rig-agent.ts", dest: resolve3(imageDir, "bin/rig-agent"), cwd: hostProjectRoot });
|
|
304
|
-
targets.push({ source: "packages/runtime/bin/rig-agent-dispatch.ts", dest: resolve3(resolveControlPlaneHostBinDir(context.projectRoot), "rig-agent"), cwd: hostProjectRoot });
|
|
305
|
-
for (const hookName of hookNames) {
|
|
306
|
-
const src = `packages/runtime/src/control-plane/hooks/${hookName}.ts`;
|
|
307
|
-
targets.push({ source: src, dest: resolve3(imageDir, `bin/hooks/${hookName}`), cwd: hostProjectRoot });
|
|
308
|
-
targets.push({ source: src, dest: resolve3(resolveControlPlaneHostBinDir(context.projectRoot), `hooks/${hookName}`), cwd: hostProjectRoot });
|
|
309
|
-
}
|
|
310
|
-
const pluginsDir = resolve3(context.projectRoot, "rig/plugins");
|
|
311
|
-
const binPluginsDir = resolve3(resolveControlPlaneHostBinDir(context.projectRoot), "plugins");
|
|
312
|
-
const validatorsRoot = resolve3(hostProjectRoot, "packages/runtime/src/control-plane/validators");
|
|
313
|
-
const binValidatorsDir = resolve3(resolveControlPlaneHostBinDir(context.projectRoot), "validators");
|
|
314
|
-
mkdirSync(binPluginsDir, { recursive: true });
|
|
315
|
-
mkdirSync(binValidatorsDir, { recursive: true });
|
|
316
|
-
if (existsSync(pluginsDir)) {
|
|
317
|
-
for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
|
|
318
|
-
const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
319
|
-
if (!m)
|
|
320
|
-
continue;
|
|
321
|
-
targets.push({ source: `rig/plugins/${entry.name}`, dest: resolve3(imageDir, `bin/plugins/${m[1]}`), cwd: context.projectRoot });
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
targets.push(...collectRigValidatorBuildTargets({ contextProjectRoot: context.projectRoot, hostProjectRoot, imageDir }));
|
|
325
|
-
for (const { source, dest, cwd } of targets) {
|
|
326
|
-
if (context.outputMode === "text") {
|
|
327
|
-
console.log(`Building: ${dest}`);
|
|
328
|
-
}
|
|
329
|
-
const isValidator = dest.includes("/bin/validators/");
|
|
330
|
-
await buildBinary2(source, dest, cwd, isValidator ? { AGENT_BUN_PATH: Bun.which("bun") || "bun" } : { AGENT_PROJECT_ROOT: context.projectRoot });
|
|
331
|
-
}
|
|
332
|
-
if (existsSync(pluginsDir)) {
|
|
333
|
-
for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
|
|
334
|
-
const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
335
|
-
if (!m)
|
|
336
|
-
continue;
|
|
337
|
-
const pluginName = m[1];
|
|
338
|
-
const imageBin = resolve3(imageDir, `bin/plugins/${pluginName}`);
|
|
339
|
-
if (!pluginName)
|
|
340
|
-
continue;
|
|
341
|
-
const symlinkPath = resolve3(binPluginsDir, pluginName);
|
|
342
|
-
if (existsSync(imageBin)) {
|
|
343
|
-
try {
|
|
344
|
-
unlinkSync(symlinkPath);
|
|
345
|
-
} catch {}
|
|
346
|
-
symlinkSync(imageBin, symlinkPath);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
if (existsSync(validatorsRoot)) {
|
|
351
|
-
const categories = readdirSync(validatorsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|
|
352
|
-
for (const category of categories) {
|
|
353
|
-
const categoryDir = resolve3(validatorsRoot, category.name);
|
|
354
|
-
for (const entry of readdirSync(categoryDir, { withFileTypes: true })) {
|
|
355
|
-
if (!entry.isFile() || !entry.name.endsWith(".ts"))
|
|
356
|
-
continue;
|
|
357
|
-
const check = entry.name.replace(/\.ts$/, "");
|
|
358
|
-
if (!check || check === "index" || check === "shared")
|
|
359
|
-
continue;
|
|
360
|
-
const validatorName = `${category.name}-${check}`;
|
|
361
|
-
const imageBin = resolve3(imageDir, `bin/validators/${validatorName}`);
|
|
362
|
-
const symlinkPath = resolve3(binValidatorsDir, validatorName);
|
|
363
|
-
if (existsSync(imageBin)) {
|
|
364
|
-
try {
|
|
365
|
-
unlinkSync(symlinkPath);
|
|
366
|
-
} catch {}
|
|
367
|
-
symlinkSync(imageBin, symlinkPath);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
const agentsDir = resolve3(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "agents");
|
|
373
|
-
if (existsSync(agentsDir)) {
|
|
374
|
-
let relinkCount = 0;
|
|
375
|
-
for (const agentEntry of readdirSync(agentsDir, { withFileTypes: true })) {
|
|
376
|
-
if (!agentEntry.isDirectory())
|
|
377
|
-
continue;
|
|
378
|
-
const agentBinDir = resolve3(agentsDir, agentEntry.name, "worktree", ".rig", "bin");
|
|
379
|
-
if (!existsSync(agentBinDir))
|
|
380
|
-
continue;
|
|
381
|
-
const walkDir = (dir) => {
|
|
382
|
-
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
383
|
-
const fullPath = resolve3(dir, entry.name);
|
|
384
|
-
if (entry.isDirectory()) {
|
|
385
|
-
walkDir(fullPath);
|
|
386
|
-
} else if (entry.isSymbolicLink()) {
|
|
387
|
-
const target = readlinkSync(fullPath);
|
|
388
|
-
if (target.includes("/.rig/runtime/images/") && !target.includes(`/${currentId}/`)) {
|
|
389
|
-
const newTarget = target.replace(/\/\.rig\/runtime\/images\/[^/]+\//, `/.rig/runtime/images/${currentId}/`);
|
|
390
|
-
try {
|
|
391
|
-
unlinkSync(fullPath);
|
|
392
|
-
symlinkSync(newTarget, fullPath);
|
|
393
|
-
relinkCount++;
|
|
394
|
-
} catch {}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
};
|
|
399
|
-
walkDir(agentBinDir);
|
|
400
|
-
}
|
|
401
|
-
if (relinkCount > 0 && context.outputMode === "text") {
|
|
402
|
-
console.log(`Re-linked ${relinkCount} worktree symlink(s) to image ${currentId}.`);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
if (context.outputMode === "text") {
|
|
406
|
-
console.log(`Rebuilt ${targets.length} binaries into image ${currentId}.`);
|
|
407
|
-
}
|
|
408
|
-
return { ok: true, group: "dist", command, details: { imageId: currentId, count: targets.length } };
|
|
409
|
-
}
|
|
410
|
-
default:
|
|
411
|
-
throw new CliError(`Unknown dist command: ${command}`, 1, { hint: "Run `rig dist --help` \u2014 commands are build|install|doctor|rebuild-agent." });
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
export {
|
|
415
|
-
executeDist,
|
|
416
|
-
collectRigValidatorBuildTargets
|
|
417
|
-
};
|