@h-rig/cli 0.0.6-alpha.63 → 0.0.6-alpha.65
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 +1349 -1599
- package/dist/src/commands/_connection-state.js +14 -5
- package/dist/src/commands/_doctor-checks.js +71 -11
- package/dist/src/commands/_help-catalog.js +99 -60
- package/dist/src/commands/_json-output.js +56 -0
- package/dist/src/commands/_operator-view.js +97 -784
- package/dist/src/commands/_parsers.js +18 -9
- package/dist/src/commands/_pi-frontend.js +96 -788
- package/dist/src/commands/_policy.js +12 -3
- package/dist/src/commands/_preflight.js +73 -13
- package/dist/src/commands/_run-driver-helpers.js +31 -5
- package/dist/src/commands/_run-replay.js +2 -2
- package/dist/src/commands/_server-client.js +76 -16
- package/dist/src/commands/_snapshot-upload.js +70 -10
- package/dist/src/commands/agent.js +21 -11
- package/dist/src/commands/browser.js +24 -15
- package/dist/src/commands/connect.js +22 -17
- package/dist/src/commands/dist.js +15 -6
- package/dist/src/commands/doctor.js +70 -10
- package/dist/src/commands/github.js +79 -19
- package/dist/src/commands/inbox.js +215 -131
- package/dist/src/commands/init.js +202 -35
- package/dist/src/commands/inspect.js +77 -17
- package/dist/src/commands/inspector.js +18 -9
- package/dist/src/commands/pi.js +18 -9
- package/dist/src/commands/plugin.js +19 -10
- package/dist/src/commands/profile-and-review.js +22 -13
- package/dist/src/commands/queue.js +19 -9
- package/dist/src/commands/remote.js +25 -16
- package/dist/src/commands/repo-git-harness.js +18 -9
- package/dist/src/commands/run.js +158 -805
- package/dist/src/commands/server.js +85 -25
- package/dist/src/commands/setup.js +73 -13
- package/dist/src/commands/stats.js +681 -0
- package/dist/src/commands/task-report-bug.js +24 -15
- package/dist/src/commands/task-run-driver.js +121 -49
- package/dist/src/commands/task.js +254 -893
- package/dist/src/commands/test.js +12 -3
- package/dist/src/commands/workspace.js +14 -5
- package/dist/src/commands.js +1339 -1650
- package/dist/src/index.js +1349 -1599
- package/dist/src/launcher.js +72 -10
- package/dist/src/runner.js +14 -5
- package/package.json +10 -7
- package/dist/src/commands/_pi-remote-session.js +0 -771
- package/dist/src/commands/_pi-worker-bridge-extension.js +0 -834
|
@@ -4,10 +4,19 @@ import { iterateServerSentEvents } from "@rig/client";
|
|
|
4
4
|
|
|
5
5
|
// packages/cli/src/runner.ts
|
|
6
6
|
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
7
|
-
import { CliError } from "@rig/runtime/control-plane/errors";
|
|
7
|
+
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
8
8
|
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
9
9
|
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
class CliError extends RuntimeCliError {
|
|
12
|
+
hint;
|
|
13
|
+
constructor(message, exitCode = 1, options = {}) {
|
|
14
|
+
super(message, exitCode);
|
|
15
|
+
if (options.hint?.trim()) {
|
|
16
|
+
this.hint = options.hint.trim();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
11
20
|
function takeFlag(args, flag) {
|
|
12
21
|
const rest = [];
|
|
13
22
|
let value = false;
|
|
@@ -28,7 +37,7 @@ function takeOption(args, option) {
|
|
|
28
37
|
if (current === option) {
|
|
29
38
|
const next = args[index + 1];
|
|
30
39
|
if (!next || next.startsWith("-")) {
|
|
31
|
-
throw new CliError(`Missing value for ${option}`);
|
|
40
|
+
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
32
41
|
}
|
|
33
42
|
value = next;
|
|
34
43
|
index += 1;
|
|
@@ -53,11 +62,11 @@ import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
|
53
62
|
// packages/cli/src/commands/_parsers.ts
|
|
54
63
|
function parseRequiredPositiveInt(value, option) {
|
|
55
64
|
if (!value) {
|
|
56
|
-
throw new
|
|
65
|
+
throw new CliError(`Missing value for ${option}.`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} 10\`.` });
|
|
57
66
|
}
|
|
58
67
|
const parsed = Number.parseInt(value, 10);
|
|
59
68
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
60
|
-
throw new
|
|
69
|
+
throw new CliError(`Invalid ${option} value: ${value}`, 1, { hint: `Pass a positive integer, e.g. \`${option} 10\`.` });
|
|
61
70
|
}
|
|
62
71
|
return parsed;
|
|
63
72
|
}
|
|
@@ -106,7 +115,7 @@ async function executeInspector(context, args) {
|
|
|
106
115
|
const seconds = secondsResult.value ? parseRequiredPositiveInt(secondsResult.value, "--seconds") : null;
|
|
107
116
|
const pollMs = pollMsResult.value ? parseRequiredPositiveInt(pollMsResult.value, "--poll-ms") : null;
|
|
108
117
|
if (context.outputMode === "json" && !onceResult.value && !seconds) {
|
|
109
|
-
throw new
|
|
118
|
+
throw new CliError("--json inspector stream requires --once or --seconds <n>.", 2, { hint: "Re-run as `rig inspector stream --once --json` or `rig inspector stream --seconds 10 --json`." });
|
|
110
119
|
}
|
|
111
120
|
const connection = await ensureLocalRigServerConnection(context.projectRoot);
|
|
112
121
|
const streamUrl = new URL("/api/inspector/stream", connection.baseUrl);
|
|
@@ -133,7 +142,7 @@ async function executeInspector(context, args) {
|
|
|
133
142
|
signal: controller.signal
|
|
134
143
|
});
|
|
135
144
|
if (!response.ok) {
|
|
136
|
-
throw new
|
|
145
|
+
throw new CliError(`Inspector stream request failed (${response.status}).`, response.status);
|
|
137
146
|
}
|
|
138
147
|
let received = 0;
|
|
139
148
|
let lastEvent = null;
|
|
@@ -210,7 +219,7 @@ async function executeInspector(context, args) {
|
|
|
210
219
|
})
|
|
211
220
|
});
|
|
212
221
|
if (!response.ok) {
|
|
213
|
-
throw new
|
|
222
|
+
throw new CliError(`Upstream drift scan request failed (${response.status}).`, response.status);
|
|
214
223
|
}
|
|
215
224
|
const result = await response.json();
|
|
216
225
|
if (context.outputMode === "text") {
|
|
@@ -246,7 +255,7 @@ async function executeInspector(context, args) {
|
|
|
246
255
|
};
|
|
247
256
|
}
|
|
248
257
|
default:
|
|
249
|
-
throw new
|
|
258
|
+
throw new CliError(`Unknown inspector command: ${command}`, 1, { hint: "Run `rig inspector --help` \u2014 commands are stream|scan-upstream-drift." });
|
|
250
259
|
}
|
|
251
260
|
}
|
|
252
261
|
export {
|
package/dist/src/commands/pi.js
CHANGED
|
@@ -6,10 +6,19 @@ import { dirname, resolve } from "path";
|
|
|
6
6
|
|
|
7
7
|
// packages/cli/src/runner.ts
|
|
8
8
|
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
9
|
-
import { CliError } from "@rig/runtime/control-plane/errors";
|
|
9
|
+
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
10
10
|
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
11
11
|
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
class CliError extends RuntimeCliError {
|
|
14
|
+
hint;
|
|
15
|
+
constructor(message, exitCode = 1, options = {}) {
|
|
16
|
+
super(message, exitCode);
|
|
17
|
+
if (options.hint?.trim()) {
|
|
18
|
+
this.hint = options.hint.trim();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
13
22
|
function requireNoExtraArgs(args, usage) {
|
|
14
23
|
if (args.length > 0) {
|
|
15
24
|
throw new CliError(`Unexpected arguments: ${args.join(" ")}
|
|
@@ -51,7 +60,7 @@ async function searchNpmForPiExtensions(term) {
|
|
|
51
60
|
const url = `https://registry.npmjs.org/-/v1/search?text=${query}&size=20`;
|
|
52
61
|
const response = await fetch(url);
|
|
53
62
|
if (!response.ok) {
|
|
54
|
-
throw new
|
|
63
|
+
throw new CliError(`npm registry search failed (${response.status}).`, 2, { hint: "Check network access to registry.npmjs.org, then retry `rig pi search <term>`." });
|
|
55
64
|
}
|
|
56
65
|
const payload = await response.json();
|
|
57
66
|
const results = [];
|
|
@@ -102,12 +111,12 @@ async function executePi(context, args) {
|
|
|
102
111
|
const [source, ...extra] = rest;
|
|
103
112
|
requireNoExtraArgs(extra, "rig pi add <package-source>");
|
|
104
113
|
if (!source) {
|
|
105
|
-
throw new
|
|
114
|
+
throw new CliError("Usage: rig pi add <package-source> (npm name, name@version, or git URL)", 2);
|
|
106
115
|
}
|
|
107
116
|
const settings = readJson(projectSettingsPath, {});
|
|
108
117
|
const packages = Array.isArray(settings.packages) ? settings.packages : [];
|
|
109
118
|
if (packages.some((entry) => packageKey(entry) === source)) {
|
|
110
|
-
throw new
|
|
119
|
+
throw new CliError(`"${source}" is already in ${projectSettingsPath}.`, 2, { hint: "Run `rig pi list` to see installed extensions." });
|
|
111
120
|
}
|
|
112
121
|
writeSettings(projectSettingsPath, { ...settings, packages: [...packages, source] });
|
|
113
122
|
if (context.outputMode === "text") {
|
|
@@ -120,17 +129,17 @@ async function executePi(context, args) {
|
|
|
120
129
|
const [source, ...extra] = rest;
|
|
121
130
|
requireNoExtraArgs(extra, "rig pi remove <package-source>");
|
|
122
131
|
if (!source) {
|
|
123
|
-
throw new
|
|
132
|
+
throw new CliError("Usage: rig pi remove <package-source>", 2);
|
|
124
133
|
}
|
|
125
134
|
const managed = new Set(readJson(managedRecordPath, []));
|
|
126
135
|
if (managed.has(source)) {
|
|
127
|
-
throw new
|
|
136
|
+
throw new CliError(`"${source}" is managed by rig.config.ts (runtime.pi.packages); remove it there instead.`, 2);
|
|
128
137
|
}
|
|
129
138
|
const settings = readJson(projectSettingsPath, {});
|
|
130
139
|
const packages = Array.isArray(settings.packages) ? settings.packages : [];
|
|
131
140
|
const next = packages.filter((entry) => packageKey(entry) !== source);
|
|
132
141
|
if (next.length === packages.length) {
|
|
133
|
-
throw new
|
|
142
|
+
throw new CliError(`"${source}" is not in ${projectSettingsPath}.`, 2, { hint: "Run `rig pi list` to see what is installed, then `rig pi remove <source>` with an exact entry." });
|
|
134
143
|
}
|
|
135
144
|
const nextSettings = { ...settings };
|
|
136
145
|
if (next.length > 0)
|
|
@@ -160,7 +169,7 @@ async function executePi(context, args) {
|
|
|
160
169
|
return { ok: true, group: "pi", command, details: { term, results } };
|
|
161
170
|
}
|
|
162
171
|
default:
|
|
163
|
-
throw new
|
|
172
|
+
throw new CliError(`Unknown pi command: ${command}. Use list|add|remove|search.`, 1, { hint: "Run `rig pi --help` for usage." });
|
|
164
173
|
}
|
|
165
174
|
}
|
|
166
175
|
export {
|
|
@@ -7,10 +7,19 @@ import { resolve } from "path";
|
|
|
7
7
|
|
|
8
8
|
// packages/cli/src/runner.ts
|
|
9
9
|
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
10
|
-
import { CliError } from "@rig/runtime/control-plane/errors";
|
|
10
|
+
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
11
11
|
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
12
12
|
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
class CliError extends RuntimeCliError {
|
|
15
|
+
hint;
|
|
16
|
+
constructor(message, exitCode = 1, options = {}) {
|
|
17
|
+
super(message, exitCode);
|
|
18
|
+
if (options.hint?.trim()) {
|
|
19
|
+
this.hint = options.hint.trim();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
14
23
|
function takeOption(args, option) {
|
|
15
24
|
const rest = [];
|
|
16
25
|
let value;
|
|
@@ -19,7 +28,7 @@ function takeOption(args, option) {
|
|
|
19
28
|
if (current === option) {
|
|
20
29
|
const next = args[index + 1];
|
|
21
30
|
if (!next || next.startsWith("-")) {
|
|
22
|
-
throw new CliError(`Missing value for ${option}`);
|
|
31
|
+
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
23
32
|
}
|
|
24
33
|
value = next;
|
|
25
34
|
index += 1;
|
|
@@ -126,7 +135,7 @@ async function executePlugin(context, args) {
|
|
|
126
135
|
const taskId = requireTask(task, "rig plugin validate --task <task-id>");
|
|
127
136
|
const hostCtx = await buildPluginHostContext(context.projectRoot);
|
|
128
137
|
if (!hostCtx) {
|
|
129
|
-
throw new
|
|
138
|
+
throw new CliError(`No rig.config found at ${context.projectRoot}. Run \`rig init\` to set up plugins.`, 2);
|
|
130
139
|
}
|
|
131
140
|
const validators = hostCtx.validatorRegistry.list();
|
|
132
141
|
const results = [];
|
|
@@ -162,7 +171,7 @@ async function executePlugin(context, args) {
|
|
|
162
171
|
}
|
|
163
172
|
}
|
|
164
173
|
if (failed > 0) {
|
|
165
|
-
throw new
|
|
174
|
+
throw new CliError(`Plugin validation failed for ${failed} validator(s).`, 2, { hint: "Fix the reported validators, then re-run `rig plugin validate --task <id>`." });
|
|
166
175
|
}
|
|
167
176
|
return {
|
|
168
177
|
ok: true,
|
|
@@ -179,16 +188,16 @@ async function executePlugin(context, args) {
|
|
|
179
188
|
case "run": {
|
|
180
189
|
const [commandId, ...commandArgs] = rest;
|
|
181
190
|
if (!commandId) {
|
|
182
|
-
throw new
|
|
191
|
+
throw new CliError("Usage: rig plugin run <command-id> [args...]", 1, { hint: "Run `rig plugin list` to see plugin-contributed command ids." });
|
|
183
192
|
}
|
|
184
193
|
const hostCtx = await buildPluginHostContext(context.projectRoot);
|
|
185
194
|
if (!hostCtx) {
|
|
186
|
-
throw new
|
|
195
|
+
throw new CliError(`No rig.config found at ${context.projectRoot}. Run \`rig init\` to set up plugins.`, 2);
|
|
187
196
|
}
|
|
188
197
|
const registration = resolvePluginCliCommand(hostCtx.pluginHost.listCliCommands(), commandId);
|
|
189
198
|
if (!registration) {
|
|
190
199
|
const available = hostCtx.pluginHost.listCliCommands().map((entry) => entry.id);
|
|
191
|
-
throw new
|
|
200
|
+
throw new CliError(available.length > 0 ? `Unknown plugin command "${commandId}". Available: ${available.join(", ")}` : `No plugin CLI commands are registered. Plugins contribute them via contributes.cliCommands.`, 2);
|
|
192
201
|
}
|
|
193
202
|
if (context.dryRun) {
|
|
194
203
|
if (context.outputMode === "text") {
|
|
@@ -205,12 +214,12 @@ async function executePlugin(context, args) {
|
|
|
205
214
|
});
|
|
206
215
|
const exitCode = await proc.exited;
|
|
207
216
|
if (exitCode !== 0) {
|
|
208
|
-
throw new
|
|
217
|
+
throw new CliError(`Plugin command "${registration.id}" exited with code ${exitCode}.`, exitCode, { hint: "Run `rig plugin list` to inspect the contributing plugin, or re-run with --json for details." });
|
|
209
218
|
}
|
|
210
219
|
return { ok: true, group: "plugin", command, details: { id: registration.id, exitCode } };
|
|
211
220
|
}
|
|
212
221
|
default:
|
|
213
|
-
throw new
|
|
222
|
+
throw new CliError(`Unknown plugin command: ${command}`, 1, { hint: "Run `rig plugin --help` \u2014 commands are list|validate|run." });
|
|
214
223
|
}
|
|
215
224
|
}
|
|
216
225
|
function resolvePluginCliCommand(commands, requested) {
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/cli/src/runner.ts
|
|
3
3
|
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
4
|
-
import { CliError } from "@rig/runtime/control-plane/errors";
|
|
4
|
+
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
5
5
|
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
6
6
|
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
7
|
-
|
|
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
|
+
}
|
|
8
17
|
function takeOption(args, option) {
|
|
9
18
|
const rest = [];
|
|
10
19
|
let value;
|
|
@@ -13,7 +22,7 @@ function takeOption(args, option) {
|
|
|
13
22
|
if (current === option) {
|
|
14
23
|
const next = args[index + 1];
|
|
15
24
|
if (!next || next.startsWith("-")) {
|
|
16
|
-
throw new CliError(`Missing value for ${option}`);
|
|
25
|
+
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
17
26
|
}
|
|
18
27
|
value = next;
|
|
19
28
|
index += 1;
|
|
@@ -89,17 +98,17 @@ async function executeProfile(context, args) {
|
|
|
89
98
|
return { ok: true, group: "profile", command };
|
|
90
99
|
case "set": {
|
|
91
100
|
if (rest.length === 0) {
|
|
92
|
-
throw new
|
|
101
|
+
throw new CliError("Usage: rig profile set <claude-code|codex-cli|pi> or set [--model ...] [--runtime ...] [--plugin ...]");
|
|
93
102
|
}
|
|
94
103
|
const preset = rest[0];
|
|
95
104
|
if (preset && !preset.startsWith("-")) {
|
|
96
105
|
if (rest.length !== 1) {
|
|
97
|
-
throw new
|
|
106
|
+
throw new CliError("Usage: rig profile set <claude-code|codex-cli|pi>");
|
|
98
107
|
}
|
|
99
108
|
try {
|
|
100
109
|
await withMutedConsole(context.outputMode === "json", () => setProfile(context.projectRoot, { preset }));
|
|
101
110
|
} catch (error) {
|
|
102
|
-
throw new
|
|
111
|
+
throw new CliError(error instanceof Error ? error.message : String(error), 2);
|
|
103
112
|
}
|
|
104
113
|
return { ok: true, group: "profile", command, details: { preset } };
|
|
105
114
|
}
|
|
@@ -112,7 +121,7 @@ async function executeProfile(context, args) {
|
|
|
112
121
|
pending = pluginResult.rest;
|
|
113
122
|
requireNoExtraArgs(pending, "rig profile set [--model ...] [--runtime ...] [--plugin ...]");
|
|
114
123
|
if (!modelResult.value && !runtimeResult.value && !pluginResult.value) {
|
|
115
|
-
throw new
|
|
124
|
+
throw new CliError("Provide at least one of --model, --runtime, or --plugin.", 1, { hint: "Example: `rig profile set --model claude-sonnet`. See current values with `rig profile show`." });
|
|
116
125
|
}
|
|
117
126
|
try {
|
|
118
127
|
await withMutedConsole(context.outputMode === "json", () => setProfile(context.projectRoot, {
|
|
@@ -121,7 +130,7 @@ async function executeProfile(context, args) {
|
|
|
121
130
|
plugin: pluginResult.value
|
|
122
131
|
}));
|
|
123
132
|
} catch (error) {
|
|
124
|
-
throw new
|
|
133
|
+
throw new CliError(error instanceof Error ? error.message : String(error), 2);
|
|
125
134
|
}
|
|
126
135
|
return {
|
|
127
136
|
ok: true,
|
|
@@ -135,7 +144,7 @@ async function executeProfile(context, args) {
|
|
|
135
144
|
};
|
|
136
145
|
}
|
|
137
146
|
default:
|
|
138
|
-
throw new
|
|
147
|
+
throw new CliError(`Unknown profile command: ${command}`, 1, { hint: "Run `rig profile --help` \u2014 commands are show|set." });
|
|
139
148
|
}
|
|
140
149
|
}
|
|
141
150
|
async function executeReview(context, args) {
|
|
@@ -147,11 +156,11 @@ async function executeReview(context, args) {
|
|
|
147
156
|
return { ok: true, group: "review", command };
|
|
148
157
|
case "set": {
|
|
149
158
|
if (rest.length === 0) {
|
|
150
|
-
throw new
|
|
159
|
+
throw new CliError("Usage: rig review set <off|advisory|required> [--provider greptile]");
|
|
151
160
|
}
|
|
152
161
|
const mode = rest[0];
|
|
153
162
|
if (!mode) {
|
|
154
|
-
throw new
|
|
163
|
+
throw new CliError("Usage: rig review set <off|advisory|required> [--provider greptile]");
|
|
155
164
|
}
|
|
156
165
|
let pending = rest.slice(1);
|
|
157
166
|
const providerResult = takeOption(pending, "--provider");
|
|
@@ -162,12 +171,12 @@ async function executeReview(context, args) {
|
|
|
162
171
|
return setReviewProfile(context.projectRoot, mode, providerResult.value);
|
|
163
172
|
});
|
|
164
173
|
} catch (error) {
|
|
165
|
-
throw new
|
|
174
|
+
throw new CliError(error instanceof Error ? error.message : String(error), 2);
|
|
166
175
|
}
|
|
167
176
|
return { ok: true, group: "review", command, details: { mode, provider: providerResult.value || null } };
|
|
168
177
|
}
|
|
169
178
|
default:
|
|
170
|
-
throw new
|
|
179
|
+
throw new CliError(`Unknown review command: ${command}`, 1, { hint: "Run `rig review --help` \u2014 commands are show|set." });
|
|
171
180
|
}
|
|
172
181
|
}
|
|
173
182
|
export {
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/cli/src/runner.ts
|
|
3
3
|
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
4
|
-
import { CliError } from "@rig/runtime/control-plane/errors";
|
|
4
|
+
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
5
5
|
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
6
6
|
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
7
|
-
|
|
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
|
+
}
|
|
8
17
|
function takeFlag(args, flag) {
|
|
9
18
|
const rest = [];
|
|
10
19
|
let value = false;
|
|
@@ -25,7 +34,7 @@ function takeOption(args, option) {
|
|
|
25
34
|
if (current === option) {
|
|
26
35
|
const next = args[index + 1];
|
|
27
36
|
if (!next || next.startsWith("-")) {
|
|
28
|
-
throw new CliError(`Missing value for ${option}`);
|
|
37
|
+
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
29
38
|
}
|
|
30
39
|
value = next;
|
|
31
40
|
index += 1;
|
|
@@ -54,7 +63,7 @@ function parsePositiveInt(value, option, fallback) {
|
|
|
54
63
|
}
|
|
55
64
|
const parsed = Number.parseInt(value, 10);
|
|
56
65
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
57
|
-
throw new
|
|
66
|
+
throw new CliError(`Invalid ${option} value: ${value}`, 1, { hint: `Pass a positive integer, e.g. \`${option} 10\`.` });
|
|
58
67
|
}
|
|
59
68
|
return parsed;
|
|
60
69
|
}
|
|
@@ -68,7 +77,7 @@ function parseAction(value) {
|
|
|
68
77
|
if (value === "pipeline") {
|
|
69
78
|
return "pipeline";
|
|
70
79
|
}
|
|
71
|
-
throw new
|
|
80
|
+
throw new CliError(`Invalid --action value: ${value}. Use validate, verify, or pipeline.`);
|
|
72
81
|
}
|
|
73
82
|
function parseIsolationMode(value, allowOff) {
|
|
74
83
|
if (!value) {
|
|
@@ -80,7 +89,7 @@ function parseIsolationMode(value, allowOff) {
|
|
|
80
89
|
if (allowOff && value === "off") {
|
|
81
90
|
return value;
|
|
82
91
|
}
|
|
83
|
-
throw new
|
|
92
|
+
throw new CliError(`Invalid isolation mode: ${value}. Use ${allowOff ? "off|" : ""}worktree.`);
|
|
84
93
|
}
|
|
85
94
|
|
|
86
95
|
// packages/cli/src/commands/_preflight.ts
|
|
@@ -89,6 +98,7 @@ import { ensureProjectMainFreshBeforeRun } from "@rig/runtime/control-plane/proj
|
|
|
89
98
|
// packages/cli/src/commands/_server-client.ts
|
|
90
99
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
91
100
|
var scopedGitHubBearerTokens = new Map;
|
|
101
|
+
var serverReachabilityCache = new Map;
|
|
92
102
|
|
|
93
103
|
// packages/cli/src/commands/_preflight.ts
|
|
94
104
|
async function runProjectMainSyncPreflight(context, options) {
|
|
@@ -104,7 +114,7 @@ async function runProjectMainSyncPreflight(context, options) {
|
|
|
104
114
|
runBootstrap: async () => {
|
|
105
115
|
const bootstrap = await context.runCommand(["bun", "run", "bootstrap"]);
|
|
106
116
|
if (bootstrap.exitCode !== 0) {
|
|
107
|
-
throw new
|
|
117
|
+
throw new CliError(bootstrap.stderr || bootstrap.stdout || "bun run bootstrap failed during project pre-run sync", bootstrap.exitCode || 1);
|
|
108
118
|
}
|
|
109
119
|
}
|
|
110
120
|
});
|
|
@@ -170,7 +180,7 @@ async function executeQueue(context, args) {
|
|
|
170
180
|
console.log(`Failed: ${summary.failed}`);
|
|
171
181
|
}
|
|
172
182
|
if (summary.failed > 0) {
|
|
173
|
-
throw new
|
|
183
|
+
throw new CliError(`Queue finished with ${summary.failed} failed task(s).`, 3, { hint: "Inspect the failures with `rig inspect failures`, then re-run `rig queue run`." });
|
|
174
184
|
}
|
|
175
185
|
return {
|
|
176
186
|
ok: true,
|
|
@@ -188,7 +198,7 @@ async function executeQueue(context, args) {
|
|
|
188
198
|
};
|
|
189
199
|
}
|
|
190
200
|
default:
|
|
191
|
-
throw new
|
|
201
|
+
throw new CliError(`Unknown queue command: ${command}`, 1, { hint: "Run `rig queue --help` \u2014 the primary command is `rig queue run`." });
|
|
192
202
|
}
|
|
193
203
|
}
|
|
194
204
|
export {
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/cli/src/runner.ts
|
|
3
3
|
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
4
|
-
import { CliError } from "@rig/runtime/control-plane/errors";
|
|
4
|
+
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
5
5
|
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
6
6
|
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
7
|
-
|
|
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
|
+
}
|
|
8
17
|
function takeFlag(args, flag) {
|
|
9
18
|
const rest = [];
|
|
10
19
|
let value = false;
|
|
@@ -25,7 +34,7 @@ function takeOption(args, option) {
|
|
|
25
34
|
if (current === option) {
|
|
26
35
|
const next = args[index + 1];
|
|
27
36
|
if (!next || next.startsWith("-")) {
|
|
28
|
-
throw new CliError(`Missing value for ${option}`);
|
|
37
|
+
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
29
38
|
}
|
|
30
39
|
value = next;
|
|
31
40
|
index += 1;
|
|
@@ -73,17 +82,17 @@ function parseOptionalPositiveInt(value, option) {
|
|
|
73
82
|
}
|
|
74
83
|
const parsed = Number.parseInt(value, 10);
|
|
75
84
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
76
|
-
throw new
|
|
85
|
+
throw new CliError(`Invalid ${option} value: ${value}`, 1, { hint: `Pass a positive integer, e.g. \`${option} 10\`.` });
|
|
77
86
|
}
|
|
78
87
|
return parsed;
|
|
79
88
|
}
|
|
80
89
|
function parseRequiredPositiveInt(value, option) {
|
|
81
90
|
if (!value) {
|
|
82
|
-
throw new
|
|
91
|
+
throw new CliError(`Missing value for ${option}.`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} 10\`.` });
|
|
83
92
|
}
|
|
84
93
|
const parsed = Number.parseInt(value, 10);
|
|
85
94
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
86
|
-
throw new
|
|
95
|
+
throw new CliError(`Invalid ${option} value: ${value}`, 1, { hint: `Pass a positive integer, e.g. \`${option} 10\`.` });
|
|
87
96
|
}
|
|
88
97
|
return parsed;
|
|
89
98
|
}
|
|
@@ -158,7 +167,7 @@ async function executeRemote(context, args) {
|
|
|
158
167
|
pending2 = token.rest;
|
|
159
168
|
requireNoExtraArgs(pending2, "rig remote endpoint add --alias <a> --host <h> --port <n> --token <t>");
|
|
160
169
|
if (!alias.value || !host.value || !token.value || !port.value) {
|
|
161
|
-
throw new
|
|
170
|
+
throw new CliError("remote endpoint add requires --alias, --host, --port, and --token.", 1, { hint: "Re-run as `rig remote endpoint add --alias <a> --host <h> --port <n> --token <t>`." });
|
|
162
171
|
}
|
|
163
172
|
const created = upsertManagedRemoteEndpoint({
|
|
164
173
|
alias: alias.value,
|
|
@@ -185,7 +194,7 @@ async function executeRemote(context, args) {
|
|
|
185
194
|
pending2 = token.rest;
|
|
186
195
|
requireNoExtraArgs(pending2, "rig remote endpoint update --id <id> [--alias <a>] [--host <h>] [--port <n>] [--token <t>]");
|
|
187
196
|
if (!endpointId.value && !alias.value) {
|
|
188
|
-
throw new
|
|
197
|
+
throw new CliError("remote endpoint update requires --id <id> or --alias <a>.", 1, { hint: "List endpoints with `rig remote endpoint list`, then pass --id or --alias." });
|
|
189
198
|
}
|
|
190
199
|
const updated = updateManagedRemoteEndpointInAuthority(context.projectRoot, {
|
|
191
200
|
endpointId: endpointId.value || undefined,
|
|
@@ -195,7 +204,7 @@ async function executeRemote(context, args) {
|
|
|
195
204
|
token: token.value || undefined
|
|
196
205
|
});
|
|
197
206
|
if (!updated) {
|
|
198
|
-
throw new
|
|
207
|
+
throw new CliError("Remote endpoint not found.", 2, { hint: "Run `rig remote endpoint list` to see configured endpoints." });
|
|
199
208
|
}
|
|
200
209
|
if (context.outputMode === "text") {
|
|
201
210
|
console.log(`Updated remote endpoint ${updated.alias} -> ${updated.host}:${updated.port}`);
|
|
@@ -208,11 +217,11 @@ async function executeRemote(context, args) {
|
|
|
208
217
|
pending2 = alias.rest;
|
|
209
218
|
requireNoExtraArgs(pending2, "rig remote endpoint remove --alias <a>");
|
|
210
219
|
if (!alias.value) {
|
|
211
|
-
throw new
|
|
220
|
+
throw new CliError("remote endpoint remove requires --alias.", 1, { hint: "Run `rig remote endpoint list` to find the alias, then `rig remote endpoint remove --alias <a>`." });
|
|
212
221
|
}
|
|
213
222
|
const removed = removeManagedRemoteEndpoint(alias.value, undefined, context.projectRoot);
|
|
214
223
|
if (!removed) {
|
|
215
|
-
throw new
|
|
224
|
+
throw new CliError(`Remote endpoint alias not found: ${alias.value}`, 2, { hint: "Run `rig remote endpoint list` to see configured endpoint aliases." });
|
|
216
225
|
}
|
|
217
226
|
if (context.outputMode === "text") {
|
|
218
227
|
console.log(`Removed remote endpoint ${alias.value}`);
|
|
@@ -225,7 +234,7 @@ async function executeRemote(context, args) {
|
|
|
225
234
|
pending2 = alias.rest;
|
|
226
235
|
requireNoExtraArgs(pending2, "rig remote endpoint test --alias <a>");
|
|
227
236
|
if (!alias.value) {
|
|
228
|
-
throw new
|
|
237
|
+
throw new CliError("remote endpoint test requires --alias.", 1, { hint: "Run `rig remote endpoint list` to find the alias, then `rig remote endpoint test --alias <a>`." });
|
|
229
238
|
}
|
|
230
239
|
const endpoint2 = resolveRemoteEndpoint({ remoteAlias: alias.value, projectRoot: context.projectRoot });
|
|
231
240
|
const client = new RemoteWsClient(endpoint2);
|
|
@@ -270,7 +279,7 @@ async function executeRemote(context, args) {
|
|
|
270
279
|
return { ok: true, group: "remote", command: "endpoint doctor", details: result };
|
|
271
280
|
}
|
|
272
281
|
default:
|
|
273
|
-
throw new
|
|
282
|
+
throw new CliError(`Unknown remote endpoint command: ${subcommand}`, 1, { hint: "Run `rig remote --help` for endpoint commands (list|add|update|remove|test)." });
|
|
274
283
|
}
|
|
275
284
|
}
|
|
276
285
|
let pending = rest;
|
|
@@ -339,7 +348,7 @@ async function executeRemote(context, args) {
|
|
|
339
348
|
const seconds = parseOptionalPositiveInt(secondsResult.value, "--seconds");
|
|
340
349
|
const eventFilter = eventResult.value || undefined;
|
|
341
350
|
if (context.outputMode === "json" && !seconds) {
|
|
342
|
-
throw new
|
|
351
|
+
throw new CliError("--json remote watch requires --seconds <n> to produce bounded output.", 2, { hint: "Re-run as `rig remote watch --seconds 10 --json`." });
|
|
343
352
|
}
|
|
344
353
|
const captured = [];
|
|
345
354
|
let dropped = 0;
|
|
@@ -491,11 +500,11 @@ async function executeRemote(context, args) {
|
|
|
491
500
|
return { ok: true, group: "remote", command, details: toDetails(response) };
|
|
492
501
|
}
|
|
493
502
|
default:
|
|
494
|
-
throw new
|
|
503
|
+
throw new CliError(`Unknown remote command: ${command}`, 1, { hint: "Run `rig remote --help` to list remote commands." });
|
|
495
504
|
}
|
|
496
505
|
} catch (error) {
|
|
497
506
|
if (error instanceof RemoteCliError) {
|
|
498
|
-
throw new
|
|
507
|
+
throw new CliError(`[${error.code}] ${error.message}`, error.exitCode);
|
|
499
508
|
}
|
|
500
509
|
throw error;
|
|
501
510
|
}
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/cli/src/runner.ts
|
|
3
3
|
import { EventBus } from "@rig/runtime/control-plane/runtime/events";
|
|
4
|
-
import { CliError } from "@rig/runtime/control-plane/errors";
|
|
4
|
+
import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
|
|
5
5
|
import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
|
|
6
6
|
import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
|
|
7
|
-
|
|
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
|
+
}
|
|
8
17
|
function formatCommand(parts) {
|
|
9
18
|
return parts.map((part) => /[^a-zA-Z0-9_./:-]/.test(part) ? JSON.stringify(part) : part).join(" ");
|
|
10
19
|
}
|
|
@@ -28,7 +37,7 @@ function takeOption(args, option) {
|
|
|
28
37
|
if (current === option) {
|
|
29
38
|
const next = args[index + 1];
|
|
30
39
|
if (!next || next.startsWith("-")) {
|
|
31
|
-
throw new CliError(`Missing value for ${option}`);
|
|
40
|
+
throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
|
|
32
41
|
}
|
|
33
42
|
value = next;
|
|
34
43
|
index += 1;
|
|
@@ -146,7 +155,7 @@ async function enforceNativeCommandPolicy(context, args, options) {
|
|
|
146
155
|
appendControlledBashAudit(context, mode, command, args, matchedRuleIds, action === "block" ? "blocked" : action === "warn" ? "warn" : undefined);
|
|
147
156
|
}
|
|
148
157
|
if (action === "block") {
|
|
149
|
-
throw new
|
|
158
|
+
throw new CliError(`Policy blocked command: ${command}`, 126, { hint: "Review rig/policy/policy.json, or re-run with `--policy-mode observe` to log instead of block." });
|
|
150
159
|
}
|
|
151
160
|
}
|
|
152
161
|
|
|
@@ -167,12 +176,12 @@ async function executeRepo(context, args) {
|
|
|
167
176
|
return { ok: true, group: "repo", command, details: { keepTaskStatus: keepTaskStatusFlag } };
|
|
168
177
|
}
|
|
169
178
|
default:
|
|
170
|
-
throw new
|
|
179
|
+
throw new CliError(`Unknown repo command: ${command}`, 1, { hint: "Run `rig repo --help` \u2014 commands are sync|reset-baseline." });
|
|
171
180
|
}
|
|
172
181
|
}
|
|
173
182
|
async function executeGit(context, args) {
|
|
174
183
|
if (args.length === 0) {
|
|
175
|
-
throw new
|
|
184
|
+
throw new CliError("Usage: rig git <git-flow args...>");
|
|
176
185
|
}
|
|
177
186
|
await enforceNativeCommandPolicy(context, args, {
|
|
178
187
|
commandPrefix: "rig-agent git",
|
|
@@ -187,13 +196,13 @@ async function executeGit(context, args) {
|
|
|
187
196
|
try {
|
|
188
197
|
await executeHarnessCommand(context.projectRoot, ["git", ...args]);
|
|
189
198
|
} catch (error) {
|
|
190
|
-
throw new
|
|
199
|
+
throw new CliError(error instanceof Error ? error.message : String(error), 2);
|
|
191
200
|
}
|
|
192
201
|
return { ok: true, group: "git", command: args[0] ?? "git" };
|
|
193
202
|
}
|
|
194
203
|
async function executeHarness(context, args) {
|
|
195
204
|
if (args.length === 0) {
|
|
196
|
-
throw new
|
|
205
|
+
throw new CliError("Usage: rig harness <harness args...>");
|
|
197
206
|
}
|
|
198
207
|
await enforceNativeCommandPolicy(context, args, {
|
|
199
208
|
commandPrefix: "rig-agent",
|
|
@@ -208,7 +217,7 @@ async function executeHarness(context, args) {
|
|
|
208
217
|
try {
|
|
209
218
|
await executeHarnessCommand(context.projectRoot, args);
|
|
210
219
|
} catch (error) {
|
|
211
|
-
throw new
|
|
220
|
+
throw new CliError(error instanceof Error ? error.message : String(error), 2);
|
|
212
221
|
}
|
|
213
222
|
return { ok: true, group: "harness", command: args[0] ?? "harness" };
|
|
214
223
|
}
|