@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.
Files changed (94) hide show
  1. package/README.md +1 -0
  2. package/dist/src/app/drone-ui.d.ts +34 -0
  3. package/dist/src/app/drone-ui.js +278 -0
  4. package/dist/src/commands/_async-ui.d.ts +10 -0
  5. package/dist/src/commands/_async-ui.js +121 -0
  6. package/dist/src/commands/_cli-format.d.ts +56 -0
  7. package/dist/src/commands/_cli-format.js +332 -0
  8. package/dist/src/commands/_connection-state.d.ts +54 -0
  9. package/dist/src/commands/_connection-state.js +187 -0
  10. package/dist/src/commands/_doctor-checks.d.ts +9 -0
  11. package/dist/src/commands/_doctor-checks.js +24 -0
  12. package/dist/src/commands/_help-catalog.d.ts +29 -0
  13. package/dist/src/commands/_help-catalog.js +157 -0
  14. package/dist/src/commands/_inprocess-services.d.ts +33 -0
  15. package/dist/src/commands/_inprocess-services.js +102 -0
  16. package/dist/src/commands/_json-output.d.ts +11 -0
  17. package/dist/src/commands/_json-output.js +54 -0
  18. package/dist/src/commands/_parsers.d.ts +15 -0
  19. package/dist/src/commands/_parsers.js +114 -0
  20. package/dist/src/commands/_paths.d.ts +11 -0
  21. package/dist/src/commands/_paths.js +50 -0
  22. package/dist/src/commands/_pi-frontend.d.ts +35 -0
  23. package/dist/src/commands/_pi-frontend.js +64 -0
  24. package/dist/src/commands/_pi-install.d.ts +42 -0
  25. package/dist/src/commands/_pi-install.js +167 -0
  26. package/dist/src/commands/_policy.d.ts +8 -0
  27. package/dist/src/commands/_policy.js +138 -0
  28. package/dist/src/commands/_probes.d.ts +1 -0
  29. package/dist/src/commands/_probes.js +13 -0
  30. package/dist/src/commands/_run-driver-helpers.d.ts +26 -0
  31. package/dist/src/commands/_run-driver-helpers.js +132 -0
  32. package/dist/src/commands/_run-subcommands.d.ts +3 -0
  33. package/dist/src/commands/_run-subcommands.js +31 -0
  34. package/dist/src/commands/_spinner.d.ts +25 -0
  35. package/dist/src/commands/_spinner.js +65 -0
  36. package/dist/src/commands/agent.d.ts +3 -0
  37. package/dist/src/commands/agent.js +322 -0
  38. package/dist/src/commands/config.d.ts +3 -0
  39. package/dist/src/commands/config.js +193 -0
  40. package/dist/src/commands/dist.d.ts +28 -0
  41. package/dist/src/commands/dist.js +435 -0
  42. package/dist/src/commands/doctor.d.ts +3 -0
  43. package/dist/src/commands/doctor.js +171 -0
  44. package/dist/src/commands/github.d.ts +3 -0
  45. package/dist/src/commands/github.js +342 -0
  46. package/dist/src/commands/inbox.d.ts +19 -0
  47. package/dist/src/commands/inbox.js +241 -0
  48. package/dist/src/commands/init.d.ts +64 -0
  49. package/dist/src/commands/init.js +1449 -0
  50. package/dist/src/commands/inspect.d.ts +20 -0
  51. package/dist/src/commands/inspect.js +337 -0
  52. package/dist/src/commands/pi.d.ts +3 -0
  53. package/dist/src/commands/pi.js +177 -0
  54. package/dist/src/commands/plugin.d.ts +20 -0
  55. package/dist/src/commands/plugin.js +238 -0
  56. package/dist/src/commands/profile-and-review.d.ts +4 -0
  57. package/dist/src/commands/profile-and-review.js +223 -0
  58. package/dist/src/commands/queue.d.ts +3 -0
  59. package/dist/src/commands/queue.js +197 -0
  60. package/dist/src/commands/remote.d.ts +3 -0
  61. package/dist/src/commands/remote.js +516 -0
  62. package/dist/src/commands/repo-git-harness.d.ts +5 -0
  63. package/dist/src/commands/repo-git-harness.js +282 -0
  64. package/dist/src/commands/run.d.ts +22 -0
  65. package/dist/src/commands/run.js +645 -0
  66. package/dist/src/commands/server.d.ts +3 -0
  67. package/dist/src/commands/server.js +155 -0
  68. package/dist/src/commands/setup.d.ts +16 -0
  69. package/dist/src/commands/setup.js +356 -0
  70. package/dist/src/commands/stats.d.ts +11 -0
  71. package/dist/src/commands/stats.js +219 -0
  72. package/dist/src/commands/task-run-driver.d.ts +93 -0
  73. package/dist/src/commands/task-run-driver.js +136 -0
  74. package/dist/src/commands/task.d.ts +46 -0
  75. package/dist/src/commands/task.js +555 -0
  76. package/dist/src/commands/test.d.ts +3 -0
  77. package/dist/src/commands/test.js +46 -0
  78. package/dist/src/commands/triage.d.ts +11 -0
  79. package/dist/src/commands/triage.js +224 -0
  80. package/dist/src/commands/workspace.d.ts +3 -0
  81. package/dist/src/commands/workspace.js +130 -0
  82. package/dist/src/kernel-dispatch.d.ts +15 -0
  83. package/dist/src/kernel-dispatch.js +16 -0
  84. package/dist/src/plugin.d.ts +3 -0
  85. package/dist/src/plugin.js +5440 -0
  86. package/dist/src/rig-config-package-deps.d.ts +10 -0
  87. package/dist/src/rig-config-package-deps.js +272 -0
  88. package/dist/src/runner.d.ts +47 -0
  89. package/dist/src/runner.js +267 -0
  90. package/dist/src/version.d.ts +8 -0
  91. package/dist/src/version.js +47 -0
  92. package/dist/src/withMutedConsole.d.ts +2 -0
  93. package/dist/src/withMutedConsole.js +42 -0
  94. package/package.json +34 -0
@@ -0,0 +1,238 @@
1
+ // @bun
2
+ var __require = import.meta.require;
3
+
4
+ // packages/cli-surface-plugin/src/commands/plugin.ts
5
+ import { existsSync } from "fs";
6
+ import { resolve } from "path";
7
+
8
+ // packages/cli-surface-plugin/src/runner.ts
9
+ import { EventBus } from "@rig/runtime/control-plane/runtime/events";
10
+ import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
11
+ import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
12
+ import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
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
+ }
23
+ function takeOption(args, option) {
24
+ const rest = [];
25
+ let value;
26
+ for (let index = 0;index < args.length; index += 1) {
27
+ const current = args[index];
28
+ if (current === option) {
29
+ const next = args[index + 1];
30
+ if (!next || next.startsWith("-")) {
31
+ throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
32
+ }
33
+ value = next;
34
+ index += 1;
35
+ continue;
36
+ }
37
+ if (current !== undefined) {
38
+ rest.push(current);
39
+ }
40
+ }
41
+ return { value, rest };
42
+ }
43
+ function requireNoExtraArgs(args, usage) {
44
+ if (args.length > 0) {
45
+ throw new CliError(`Unexpected arguments: ${args.join(" ")}
46
+ Usage: ${usage}`);
47
+ }
48
+ }
49
+ function requireTask(taskId, usage) {
50
+ if (!taskId) {
51
+ throw new CliError(`Missing --task option.
52
+ Usage: ${usage}`);
53
+ }
54
+ return taskId;
55
+ }
56
+
57
+ // packages/cli-surface-plugin/src/commands/plugin.ts
58
+ import { buildPluginHostContext } from "@rig/runtime/control-plane/plugin-host-context";
59
+
60
+ // packages/cli-surface-plugin/src/commands/_parsers.ts
61
+ async function loadRigConfigOrNull(projectRoot) {
62
+ try {
63
+ const { loadConfig } = await import("@rig/core/load-config");
64
+ return await loadConfig(projectRoot);
65
+ } catch {
66
+ return null;
67
+ }
68
+ }
69
+
70
+ // packages/cli-surface-plugin/src/commands/plugin.ts
71
+ async function executePlugin(context, args) {
72
+ const [command = "list", ...rest] = args;
73
+ switch (command) {
74
+ case "list": {
75
+ requireNoExtraArgs(rest, "rig plugin list");
76
+ const declarative = [];
77
+ const config = await loadRigConfigOrNull(context.projectRoot);
78
+ if (config && Array.isArray(config.plugins)) {
79
+ for (const plugin of config.plugins) {
80
+ const c = plugin.contributes ?? {};
81
+ declarative.push({
82
+ name: plugin.name,
83
+ version: plugin.version,
84
+ validators: (c.validators ?? []).map((v) => v.id),
85
+ hooks: (c.hooks ?? []).map((h) => h.id),
86
+ agentRoles: (c.agentRoles ?? []).map((r) => r.id),
87
+ repoSources: (c.repoSources ?? []).map((r) => r.id),
88
+ taskSources: (c.taskSources ?? []).map((s) => s.id),
89
+ skills: (c.skills ?? []).map((s) => s.id),
90
+ taskFieldExtensions: (c.taskFieldSchemas ?? []).map((f) => f.id),
91
+ cliCommands: (c.cliCommands ?? []).map((entry) => entry.family ?? entry.id)
92
+ });
93
+ }
94
+ }
95
+ if (context.outputMode === "text") {
96
+ if (declarative.length === 0) {
97
+ const configExists = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync(resolve(context.projectRoot, name)));
98
+ console.log(configExists ? "rig.config found but no plugins could be loaded. If the config imports @rig/* packages, run `bun install` in this project first." : "No plugins loaded. Declare plugins in rig.config.ts.");
99
+ } else {
100
+ console.log("Plugins (rig.config.ts):");
101
+ for (const p of declarative) {
102
+ console.log(` ${p.name}@${p.version}`);
103
+ const lines = [];
104
+ if (p.validators.length)
105
+ lines.push(` validators: ${p.validators.join(", ")}`);
106
+ if (p.hooks.length)
107
+ lines.push(` hooks: ${p.hooks.join(", ")}`);
108
+ if (p.agentRoles.length)
109
+ lines.push(` agent-roles: ${p.agentRoles.join(", ")}`);
110
+ if (p.repoSources.length)
111
+ lines.push(` repo-sources: ${p.repoSources.join(", ")}`);
112
+ if (p.taskSources.length)
113
+ lines.push(` task-sources: ${p.taskSources.join(", ")}`);
114
+ if (p.skills.length)
115
+ lines.push(` skills: ${p.skills.join(", ")}`);
116
+ if (p.taskFieldExtensions.length)
117
+ lines.push(` task-fields: ${p.taskFieldExtensions.join(", ")}`);
118
+ if (p.cliCommands.length)
119
+ lines.push(` cli-families: ${p.cliCommands.join(", ")}`);
120
+ for (const line of lines)
121
+ console.log(line);
122
+ }
123
+ }
124
+ }
125
+ return {
126
+ ok: true,
127
+ group: "plugin",
128
+ command,
129
+ details: { declarative }
130
+ };
131
+ }
132
+ case "validate": {
133
+ const { value: task, rest: remaining } = takeOption(rest, "--task");
134
+ requireNoExtraArgs(remaining, "rig plugin validate --task <task-id>");
135
+ const taskId = requireTask(task, "rig plugin validate --task <task-id>");
136
+ const hostCtx = await buildPluginHostContext(context.projectRoot);
137
+ if (!hostCtx) {
138
+ throw new CliError(`No rig.config found at ${context.projectRoot}. Run \`rig init\` to set up plugins.`, 2);
139
+ }
140
+ const validators = hostCtx.validatorRegistry.list();
141
+ const results = [];
142
+ for (const validator of validators) {
143
+ try {
144
+ results.push(await validator.run({
145
+ taskId,
146
+ workspaceRoot: context.projectRoot,
147
+ scope: []
148
+ }));
149
+ } catch (error) {
150
+ results.push({
151
+ id: validator.id,
152
+ passed: false,
153
+ summary: `${validator.id} failed unexpectedly`,
154
+ details: `${error}`
155
+ });
156
+ }
157
+ }
158
+ const passed = results.filter((result) => result.passed).length;
159
+ const failed = results.length - passed;
160
+ if (context.outputMode === "text") {
161
+ if (results.length === 0) {
162
+ console.log("No plugin validators registered.");
163
+ } else {
164
+ for (const result of results) {
165
+ const icon = result.passed ? "PASS" : "FAIL";
166
+ console.log(`[${icon}] ${result.id}: ${result.summary}`);
167
+ if (result.details && !result.passed) {
168
+ console.log(result.details);
169
+ }
170
+ }
171
+ }
172
+ }
173
+ if (failed > 0) {
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>`." });
175
+ }
176
+ return {
177
+ ok: true,
178
+ group: "plugin",
179
+ command,
180
+ details: {
181
+ taskId,
182
+ passed,
183
+ failed,
184
+ results
185
+ }
186
+ };
187
+ }
188
+ case "run": {
189
+ const [commandId, ...commandArgs] = rest;
190
+ if (!commandId) {
191
+ throw new CliError("Usage: rig plugin run <command-id> [args...]", 1, { hint: "Run `rig plugin list` to see plugin-contributed command ids." });
192
+ }
193
+ const hostCtx = await buildPluginHostContext(context.projectRoot);
194
+ if (!hostCtx) {
195
+ throw new CliError(`No rig.config found at ${context.projectRoot}. Run \`rig init\` to set up plugins.`, 2);
196
+ }
197
+ const registration = resolvePluginCliCommand(hostCtx.pluginHost.listCliCommands(), commandId);
198
+ if (!registration) {
199
+ const available = hostCtx.pluginHost.listCliCommands().map((entry) => entry.id);
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);
201
+ }
202
+ if (!registration.command) {
203
+ throw new CliError(`Plugin CLI family "${registration.id}" is an in-process command; invoke it as \`rig ${registration.family ?? registration.id}\`, not through \`rig plugin run\`.`, 1);
204
+ }
205
+ if (context.dryRun) {
206
+ if (context.outputMode === "text") {
207
+ console.log(`[dry-run] ${registration.command}${commandArgs.length ? ` ${commandArgs.join(" ")}` : ""}`);
208
+ }
209
+ return { ok: true, group: "plugin", command, details: { id: registration.id, dryRun: true } };
210
+ }
211
+ const proc = Bun.spawn(["bash", "-c", `${registration.command} "$@"`, registration.id, ...commandArgs], {
212
+ cwd: context.projectRoot,
213
+ env: process.env,
214
+ stdin: "inherit",
215
+ stdout: "inherit",
216
+ stderr: "inherit"
217
+ });
218
+ const exitCode = await proc.exited;
219
+ if (exitCode !== 0) {
220
+ 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." });
221
+ }
222
+ return { ok: true, group: "plugin", command, details: { id: registration.id, exitCode } };
223
+ }
224
+ default:
225
+ throw new CliError(`Unknown plugin command: ${command}`, 1, { hint: "Run `rig plugin --help` \u2014 commands are list|validate|run." });
226
+ }
227
+ }
228
+ function resolvePluginCliCommand(commands, requested) {
229
+ const exact = commands.find((entry) => entry.id === requested || entry.family === requested || (entry.aliases ?? []).includes(requested));
230
+ if (exact)
231
+ return exact;
232
+ const byLocalPart = commands.filter((entry) => entry.id.split(":").slice(1).join(":") === requested);
233
+ return byLocalPart.length === 1 ? byLocalPart[0] : undefined;
234
+ }
235
+ export {
236
+ resolvePluginCliCommand,
237
+ executePlugin
238
+ };
@@ -0,0 +1,4 @@
1
+ import { type RunnerContext } from "../runner";
2
+ import type { CommandOutcome } from "@rig/runtime";
3
+ export declare function executeProfile(context: RunnerContext, args: string[]): Promise<CommandOutcome>;
4
+ export declare function executeReview(context: RunnerContext, args: string[]): Promise<CommandOutcome>;
@@ -0,0 +1,223 @@
1
+ // @bun
2
+ // packages/cli-surface-plugin/src/commands/profile-and-review.ts
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
4
+
5
+ // packages/cli-surface-plugin/src/runner.ts
6
+ import { EventBus } from "@rig/runtime/control-plane/runtime/events";
7
+ import { CliError as RuntimeCliError } from "@rig/runtime/control-plane/errors";
8
+ import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
9
+ import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
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
+ }
20
+ function takeOption(args, option) {
21
+ const rest = [];
22
+ let value;
23
+ for (let index = 0;index < args.length; index += 1) {
24
+ const current = args[index];
25
+ if (current === option) {
26
+ const next = args[index + 1];
27
+ if (!next || next.startsWith("-")) {
28
+ throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
29
+ }
30
+ value = next;
31
+ index += 1;
32
+ continue;
33
+ }
34
+ if (current !== undefined) {
35
+ rest.push(current);
36
+ }
37
+ }
38
+ return { value, rest };
39
+ }
40
+ function requireNoExtraArgs(args, usage) {
41
+ if (args.length > 0) {
42
+ throw new CliError(`Unexpected arguments: ${args.join(" ")}
43
+ Usage: ${usage}`);
44
+ }
45
+ }
46
+
47
+ // packages/cli-surface-plugin/src/withMutedConsole.ts
48
+ function isPromise(value) {
49
+ if (typeof value !== "object" && typeof value !== "function") {
50
+ return false;
51
+ }
52
+ return value !== null && typeof value.then === "function";
53
+ }
54
+ function withMutedConsole(mute, fn) {
55
+ if (!mute) {
56
+ return fn();
57
+ }
58
+ const originalLog = console.log;
59
+ const originalWarn = console.warn;
60
+ const originalInfo = console.info;
61
+ const restore = () => {
62
+ console.log = originalLog;
63
+ console.warn = originalWarn;
64
+ console.info = originalInfo;
65
+ };
66
+ console.log = () => {};
67
+ console.warn = () => {};
68
+ console.info = () => {};
69
+ try {
70
+ const result = fn();
71
+ if (isPromise(result)) {
72
+ return result.finally(restore);
73
+ }
74
+ restore();
75
+ return result;
76
+ } catch (error) {
77
+ restore();
78
+ throw error;
79
+ } finally {
80
+ if (console.log === originalLog) {
81
+ restore();
82
+ }
83
+ }
84
+ }
85
+
86
+ // packages/cli-surface-plugin/src/commands/_paths.ts
87
+ import { resolve } from "path";
88
+ import { resolveMonorepoRoot } from "@rig/runtime/layout";
89
+ function resolveControlPlaneHostStateRoot(projectRoot) {
90
+ return resolve(projectRoot, ".rig");
91
+ }
92
+ function resolveControlPlaneHostStateDir(projectRoot) {
93
+ return resolve(resolveControlPlaneHostStateRoot(projectRoot), "state");
94
+ }
95
+
96
+ // packages/cli-surface-plugin/src/commands/profile-and-review.ts
97
+ var DEFAULT_AGENT_PROFILE = {
98
+ model: "pi",
99
+ runtime: "pi",
100
+ agent_plugin: "pi",
101
+ updated_at: new Date().toISOString()
102
+ };
103
+ function agentProfilePath(projectRoot) {
104
+ return `${resolveControlPlaneHostStateDir(projectRoot)}/agent-profile.json`;
105
+ }
106
+ function reviewProfilePath(projectRoot) {
107
+ return `${resolveControlPlaneHostStateDir(projectRoot)}/review-profile.json`;
108
+ }
109
+ function readJson(path) {
110
+ if (!existsSync(path))
111
+ return null;
112
+ try {
113
+ return JSON.parse(readFileSync(path, "utf8"));
114
+ } catch {
115
+ return null;
116
+ }
117
+ }
118
+ async function showProfile(projectRoot) {
119
+ const profile = { ...DEFAULT_AGENT_PROFILE, ...readJson(agentProfilePath(projectRoot)), model: "pi", runtime: "pi", agent_plugin: "pi" };
120
+ console.log("Execution Profile:");
121
+ console.log(` model: ${profile.model}`);
122
+ console.log(` runtime: ${profile.runtime}`);
123
+ console.log(` plugin: ${profile.agent_plugin}`);
124
+ }
125
+ async function setProfile(projectRoot) {
126
+ mkdirSync(resolveControlPlaneHostStateDir(projectRoot), { recursive: true });
127
+ writeFileSync(agentProfilePath(projectRoot), `${JSON.stringify({ ...DEFAULT_AGENT_PROFILE, updated_at: new Date().toISOString() }, null, 2)}
128
+ `, "utf8");
129
+ await showProfile(projectRoot);
130
+ }
131
+ async function showReviewProfile(projectRoot) {
132
+ const parsed = readJson(reviewProfilePath(projectRoot));
133
+ const profile = {
134
+ mode: parsed?.mode === "off" || parsed?.mode === "required" || parsed?.mode === "advisory" ? parsed.mode : "advisory",
135
+ provider: "greptile",
136
+ updated_at: typeof parsed?.updated_at === "string" ? parsed.updated_at : new Date().toISOString()
137
+ };
138
+ console.log("AI Review Profile:");
139
+ console.log(` mode: ${profile.mode}`);
140
+ console.log(` provider: ${profile.provider}`);
141
+ console.log(` file: ${reviewProfilePath(projectRoot)}`);
142
+ }
143
+ async function setReviewProfile(projectRoot, mode, provider) {
144
+ if (mode !== "off" && mode !== "advisory" && mode !== "required") {
145
+ throw new Error(`Invalid mode: ${mode}. Use off|advisory|required.`);
146
+ }
147
+ if (provider && provider !== "greptile") {
148
+ throw new Error(`Invalid provider: ${provider}. Supported: greptile.`);
149
+ }
150
+ mkdirSync(resolveControlPlaneHostStateDir(projectRoot), { recursive: true });
151
+ writeFileSync(reviewProfilePath(projectRoot), `${JSON.stringify({ mode, provider: "greptile", updated_at: new Date().toISOString() }, null, 2)}
152
+ `, "utf8");
153
+ await showReviewProfile(projectRoot);
154
+ }
155
+ async function executeProfile(context, args) {
156
+ const [command = "show", ...rest] = args;
157
+ switch (command) {
158
+ case "show":
159
+ requireNoExtraArgs(rest, "rig profile show");
160
+ await withMutedConsole(context.outputMode === "json", () => showProfile(context.projectRoot));
161
+ return { ok: true, group: "profile", command };
162
+ case "set": {
163
+ let pending = rest;
164
+ const presetResult = takeOption(pending, "--preset");
165
+ pending = presetResult.rest;
166
+ const modelResult = takeOption(pending, "--model");
167
+ pending = modelResult.rest;
168
+ const runtimeResult = takeOption(pending, "--runtime");
169
+ pending = runtimeResult.rest;
170
+ const pluginResult = takeOption(pending, "--plugin");
171
+ pending = pluginResult.rest;
172
+ requireNoExtraArgs(pending, "rig profile set [--model ...] [--runtime ...] [--plugin ...]");
173
+ if (!presetResult.value && !modelResult.value && !runtimeResult.value && !pluginResult.value && rest.length === 0) {
174
+ throw new CliError("Provide at least one of --model, --runtime, or --plugin.", 1, {
175
+ hint: "Example: `rig profile set --model pi`. See current values with `rig profile show`."
176
+ });
177
+ }
178
+ await withMutedConsole(context.outputMode === "json", () => setProfile(context.projectRoot));
179
+ return { ok: true, group: "profile", command, details: { lockedTo: "pi" } };
180
+ }
181
+ default:
182
+ throw new CliError(`Unknown profile command: ${command}`, 1, { hint: "Run `rig profile --help` \u2014 commands are show|set." });
183
+ }
184
+ }
185
+ async function executeReview(context, args) {
186
+ const [command = "show", ...rest] = args;
187
+ switch (command) {
188
+ case "show":
189
+ requireNoExtraArgs(rest, "rig review show");
190
+ await withMutedConsole(context.outputMode === "json", () => showReviewProfile(context.projectRoot));
191
+ return { ok: true, group: "review", command };
192
+ case "set": {
193
+ let pending = rest;
194
+ const modeResult = takeOption(pending, "--mode");
195
+ pending = modeResult.rest;
196
+ const providerResult = takeOption(pending, "--provider");
197
+ pending = providerResult.rest;
198
+ const positionalMode = pending[0];
199
+ if (modeResult.value && positionalMode) {
200
+ throw new CliError("Usage: rig review set <off|advisory|required> [--provider greptile]", 1, {
201
+ hint: "Pass the mode positionally, or use --mode as a compatibility alias, but not both."
202
+ });
203
+ }
204
+ requireNoExtraArgs(positionalMode ? pending.slice(1) : pending, "rig review set <off|advisory|required> [--provider greptile]");
205
+ const mode = modeResult.value ?? positionalMode;
206
+ if (!mode) {
207
+ throw new CliError("Usage: rig review set <off|advisory|required> [--provider greptile]", 1);
208
+ }
209
+ try {
210
+ await withMutedConsole(context.outputMode === "json", () => setReviewProfile(context.projectRoot, mode, providerResult.value));
211
+ } catch (error) {
212
+ throw new CliError(error instanceof Error ? error.message : String(error), 2);
213
+ }
214
+ return { ok: true, group: "review", command, details: { mode, provider: "greptile" } };
215
+ }
216
+ default:
217
+ throw new CliError(`Unknown review command: ${command}`, 1, { hint: "Run `rig review --help` \u2014 commands are show|set." });
218
+ }
219
+ }
220
+ export {
221
+ executeReview,
222
+ executeProfile
223
+ };
@@ -0,0 +1,3 @@
1
+ import { type RunnerContext } from "../runner";
2
+ import type { CommandOutcome } from "@rig/runtime/control-plane/runtime/types";
3
+ export declare function executeQueue(context: RunnerContext, args: string[]): Promise<CommandOutcome>;
@@ -0,0 +1,197 @@
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 takeFlag(args, flag) {
18
+ const rest = [];
19
+ let value = false;
20
+ for (const arg of args) {
21
+ if (arg === flag) {
22
+ value = true;
23
+ continue;
24
+ }
25
+ rest.push(arg);
26
+ }
27
+ return { value, rest };
28
+ }
29
+ function takeOption(args, option) {
30
+ const rest = [];
31
+ let value;
32
+ for (let index = 0;index < args.length; index += 1) {
33
+ const current = args[index];
34
+ if (current === option) {
35
+ const next = args[index + 1];
36
+ if (!next || next.startsWith("-")) {
37
+ throw new CliError(`Missing value for ${option}`, 1, { hint: `Provide a value after ${option}, e.g. \`${option} <value>\`.` });
38
+ }
39
+ value = next;
40
+ index += 1;
41
+ continue;
42
+ }
43
+ if (current !== undefined) {
44
+ rest.push(current);
45
+ }
46
+ }
47
+ return { value, rest };
48
+ }
49
+ function requireNoExtraArgs(args, usage) {
50
+ if (args.length > 0) {
51
+ throw new CliError(`Unexpected arguments: ${args.join(" ")}
52
+ Usage: ${usage}`);
53
+ }
54
+ }
55
+
56
+ // packages/cli-surface-plugin/src/commands/queue.ts
57
+ import { runPriorityQueue } from "@rig/runtime/control-plane/runtime/queue";
58
+
59
+ // packages/cli-surface-plugin/src/commands/_parsers.ts
60
+ function parsePositiveInt(value, option, fallback) {
61
+ if (!value) {
62
+ return fallback;
63
+ }
64
+ const parsed = Number.parseInt(value, 10);
65
+ if (!Number.isFinite(parsed) || parsed <= 0) {
66
+ throw new CliError(`Invalid ${option} value: ${value}`, 1, { hint: `Pass a positive integer, e.g. \`${option} 10\`.` });
67
+ }
68
+ return parsed;
69
+ }
70
+ function parseAction(value) {
71
+ if (!value || value === "validate") {
72
+ return "validate";
73
+ }
74
+ if (value === "verify") {
75
+ return "verify";
76
+ }
77
+ if (value === "pipeline") {
78
+ return "pipeline";
79
+ }
80
+ throw new CliError(`Invalid --action value: ${value}. Use validate, verify, or pipeline.`);
81
+ }
82
+ function parseIsolationMode(value, allowOff) {
83
+ if (!value) {
84
+ return "worktree";
85
+ }
86
+ if (value === "worktree") {
87
+ return value;
88
+ }
89
+ if (allowOff && value === "off") {
90
+ return value;
91
+ }
92
+ throw new CliError(`Invalid isolation mode: ${value}. Use ${allowOff ? "off|" : ""}worktree.`);
93
+ }
94
+
95
+ // packages/cli-surface-plugin/src/commands/queue.ts
96
+ import { ensureProjectMainFreshBeforeRun } from "@rig/runtime/control-plane/project-main-pre-run-sync";
97
+ async function runProjectMainSyncPreflight(context, options) {
98
+ if (context.dryRun) {
99
+ if (context.outputMode === "text" && !options.disabled) {
100
+ console.log("[dry-run] project-rig pre-run sync check");
101
+ }
102
+ return;
103
+ }
104
+ const result = await ensureProjectMainFreshBeforeRun({
105
+ projectRoot: context.projectRoot,
106
+ disabled: options.disabled,
107
+ runBootstrap: async () => {
108
+ const bootstrap = await context.runCommand(["bun", "run", "bootstrap"]);
109
+ if (bootstrap.exitCode !== 0) {
110
+ throw new CliError(bootstrap.stderr || bootstrap.stdout || "bun run bootstrap failed during project pre-run sync", bootstrap.exitCode || 1);
111
+ }
112
+ }
113
+ });
114
+ if (context.outputMode !== "text") {
115
+ return;
116
+ }
117
+ switch (result.status) {
118
+ case "disabled":
119
+ console.log("Project pre-run sync skipped (--skip-project-sync).");
120
+ break;
121
+ case "skipped_not_main":
122
+ console.log(`Project pre-run sync skipped (current branch: ${result.branch}).`);
123
+ break;
124
+ case "up_to_date":
125
+ break;
126
+ case "local_ahead":
127
+ console.log(`Project pre-run sync skipped (local main ahead by ${result.localAhead} commit(s)).`);
128
+ break;
129
+ case "updated":
130
+ console.log(`Project pre-run sync updated local main from origin/main (+${result.remoteAhead}) and bootstrapped.`);
131
+ break;
132
+ }
133
+ }
134
+ async function executeQueue(context, args) {
135
+ const [command = "run", ...rest] = args;
136
+ switch (command) {
137
+ case "run": {
138
+ let pending = rest;
139
+ const workersResult = takeOption(pending, "--workers");
140
+ pending = workersResult.rest;
141
+ const maxTasksResult = takeOption(pending, "--max-tasks");
142
+ pending = maxTasksResult.rest;
143
+ const actionResult = takeOption(pending, "--action");
144
+ pending = actionResult.rest;
145
+ const isolationResult = takeOption(pending, "--isolation");
146
+ pending = isolationResult.rest;
147
+ const noRuntimeReuseResult = takeFlag(pending, "--no-runtime-reuse");
148
+ pending = noRuntimeReuseResult.rest;
149
+ const failFastResult = takeFlag(pending, "--fail-fast");
150
+ pending = failFastResult.rest;
151
+ const skipProjectSyncResult = takeFlag(pending, "--skip-project-sync");
152
+ pending = skipProjectSyncResult.rest;
153
+ requireNoExtraArgs(pending, "rig queue run [--workers <n>] [--max-tasks <n>] [--action validate|verify|pipeline] [--isolation off|worktree] [--no-runtime-reuse] [--fail-fast] [--skip-project-sync]");
154
+ const workers = parsePositiveInt(workersResult.value, "--workers", 2);
155
+ const maxTasks = parsePositiveInt(maxTasksResult.value, "--max-tasks", 10);
156
+ const action = parseAction(actionResult.value);
157
+ const isolation = parseIsolationMode(isolationResult.value, true);
158
+ const reuseRuntime = !noRuntimeReuseResult.value;
159
+ await runProjectMainSyncPreflight(context, { disabled: skipProjectSyncResult.value });
160
+ const summary = await runPriorityQueue(context, {
161
+ workers,
162
+ maxTasks,
163
+ action,
164
+ isolation,
165
+ reuseRuntime,
166
+ failFast: failFastResult.value
167
+ });
168
+ if (context.outputMode === "text") {
169
+ console.log(`Processed: ${summary.processed}`);
170
+ console.log(`Succeeded: ${summary.succeeded}`);
171
+ console.log(`Failed: ${summary.failed}`);
172
+ }
173
+ if (summary.failed > 0) {
174
+ 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`." });
175
+ }
176
+ return {
177
+ ok: true,
178
+ group: "queue",
179
+ command,
180
+ details: {
181
+ workers,
182
+ maxTasks,
183
+ action,
184
+ isolation,
185
+ reuseRuntime,
186
+ failFast: failFastResult.value,
187
+ summary
188
+ }
189
+ };
190
+ }
191
+ default:
192
+ throw new CliError(`Unknown queue command: ${command}`, 1, { hint: "Run `rig queue --help` \u2014 the primary command is `rig queue run`." });
193
+ }
194
+ }
195
+ export {
196
+ executeQueue
197
+ };
@@ -0,0 +1,3 @@
1
+ import { type RunnerContext } from "../runner";
2
+ import type { CommandOutcome } from "@rig/runtime";
3
+ export declare function executeRemote(context: RunnerContext, args: string[]): Promise<CommandOutcome>;