@h-rig/cli 0.0.6-alpha.94 → 0.0.6-alpha.96
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 -17855
- 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/_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 -51
- package/dist/src/commands/_help-catalog.js +0 -502
- 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 -8837
- 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 -1337
- 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 -17847
- 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 -979
- 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 -17979
- package/dist/src/index.d.ts +0 -4
- package/dist/src/index.js +0 -17991
- 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 -17847
- 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,714 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
var __require = import.meta.require;
|
|
3
|
-
|
|
4
|
-
// packages/cli/src/commands/plugin.ts
|
|
5
|
-
import { existsSync as existsSync6 } from "fs";
|
|
6
|
-
import { resolve as resolve4 } from "path";
|
|
7
|
-
|
|
8
|
-
// packages/cli/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/runtime/src/control-plane/plugin-host-context.ts
|
|
58
|
-
import { existsSync as existsSync5 } from "fs";
|
|
59
|
-
import { resolve as resolvePath } from "path";
|
|
60
|
-
import {
|
|
61
|
-
createPluginHost
|
|
62
|
-
} from "@rig/core";
|
|
63
|
-
import { loadConfig } from "@rig/core/load-config";
|
|
64
|
-
|
|
65
|
-
// packages/runtime/src/control-plane/task-source.ts
|
|
66
|
-
function createTaskSourceRegistry() {
|
|
67
|
-
const byId = new Map;
|
|
68
|
-
const order = [];
|
|
69
|
-
return {
|
|
70
|
-
register(s) {
|
|
71
|
-
if (byId.has(s.id))
|
|
72
|
-
throw new Error(`task source already registered: ${s.id}`);
|
|
73
|
-
byId.set(s.id, s);
|
|
74
|
-
order.push(s);
|
|
75
|
-
},
|
|
76
|
-
resolveById(id) {
|
|
77
|
-
const s = byId.get(id);
|
|
78
|
-
if (!s)
|
|
79
|
-
throw new Error(`task source not registered: ${id}`);
|
|
80
|
-
return s;
|
|
81
|
-
},
|
|
82
|
-
resolveByKind(kind) {
|
|
83
|
-
for (const s of order)
|
|
84
|
-
if (s.kind === kind)
|
|
85
|
-
return s;
|
|
86
|
-
throw new Error(`no task source registered for kind: ${kind}`);
|
|
87
|
-
},
|
|
88
|
-
list: () => order
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// packages/runtime/src/control-plane/task-source-bootstrap.ts
|
|
93
|
-
function formatRegisteredKinds(pluginHost) {
|
|
94
|
-
const kinds = pluginHost ? pluginHost.listExecutableTaskSources().map((source) => source.kind) : [];
|
|
95
|
-
return kinds.length > 0 ? kinds.join(", ") : "none";
|
|
96
|
-
}
|
|
97
|
-
function buildTaskSourceRegistry(config, pluginHost, context) {
|
|
98
|
-
const registry = createTaskSourceRegistry();
|
|
99
|
-
const taskSourceConfig = config.taskSource;
|
|
100
|
-
const factory = pluginHost?.resolveTaskSourceFactoryByKind(taskSourceConfig.kind);
|
|
101
|
-
if (!factory) {
|
|
102
|
-
throw new Error(`No task source factory registered for kind "${taskSourceConfig.kind}". ` + `Registered kinds: ${formatRegisteredKinds(pluginHost)}. ` + "Load a plugin that contributes an executable task source factory for this kind.");
|
|
103
|
-
}
|
|
104
|
-
registry.register(factory.factory(taskSourceConfig, context ? { ...context, rigConfig: config } : undefined));
|
|
105
|
-
return registry;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// packages/runtime/src/control-plane/repos/registry.ts
|
|
109
|
-
function createRepoRegistry(entries) {
|
|
110
|
-
const map = new Map;
|
|
111
|
-
for (const e of entries) {
|
|
112
|
-
if (map.has(e.id))
|
|
113
|
-
throw new Error(`repo already registered: ${e.id}`);
|
|
114
|
-
map.set(e.id, { ...e });
|
|
115
|
-
}
|
|
116
|
-
const ordered = Array.from(map.values());
|
|
117
|
-
return {
|
|
118
|
-
getById: (id) => map.get(id),
|
|
119
|
-
list: () => ordered
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
var MANAGED_REPOS = new Map;
|
|
123
|
-
function setManagedRepos(entries) {
|
|
124
|
-
const next = new Map;
|
|
125
|
-
for (const e of entries) {
|
|
126
|
-
if (next.has(e.id)) {
|
|
127
|
-
throw new Error(`managed repo already registered: ${e.id}`);
|
|
128
|
-
}
|
|
129
|
-
next.set(e.id, e);
|
|
130
|
-
}
|
|
131
|
-
MANAGED_REPOS = next;
|
|
132
|
-
}
|
|
133
|
-
function repoRegistrationToManagedEntry(reg) {
|
|
134
|
-
if (!reg.defaultBranch) {
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
return {
|
|
138
|
-
id: reg.id,
|
|
139
|
-
alias: reg.defaultPath ?? reg.id,
|
|
140
|
-
defaultBranch: reg.defaultBranch,
|
|
141
|
-
defaultRemoteUrl: reg.url,
|
|
142
|
-
remoteEnvVar: reg.remoteEnvVar,
|
|
143
|
-
checkoutEnvVar: reg.checkoutEnvVar
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// packages/runtime/src/control-plane/agent-roles.ts
|
|
148
|
-
function createAgentRoleRegistry(pluginRoles, configOverrides) {
|
|
149
|
-
const map = new Map;
|
|
150
|
-
for (const r of pluginRoles) {
|
|
151
|
-
if (map.has(r.id))
|
|
152
|
-
throw new Error(`agent role already registered: ${r.id}`);
|
|
153
|
-
const override = configOverrides?.[r.id];
|
|
154
|
-
const model = override?.model ?? r.defaultModel;
|
|
155
|
-
if (!model) {
|
|
156
|
-
throw new Error(`agent role "${r.id}" has no model \u2014 provide defaultModel in plugin or model in config.runtime.agentRoles.${r.id}`);
|
|
157
|
-
}
|
|
158
|
-
map.set(r.id, { ...r, model });
|
|
159
|
-
}
|
|
160
|
-
return {
|
|
161
|
-
resolve(id) {
|
|
162
|
-
const r = map.get(id);
|
|
163
|
-
if (!r)
|
|
164
|
-
throw new Error(`agent role not registered: ${id}`);
|
|
165
|
-
return r;
|
|
166
|
-
},
|
|
167
|
-
list: () => Array.from(map.values())
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// packages/runtime/src/control-plane/task-fields.ts
|
|
172
|
-
function createTaskFieldRegistry(extensions) {
|
|
173
|
-
const byId = new Map;
|
|
174
|
-
for (const e of extensions) {
|
|
175
|
-
if (byId.has(e.id))
|
|
176
|
-
throw new Error(`task field extension already registered: ${e.id}`);
|
|
177
|
-
byId.set(e.id, e);
|
|
178
|
-
}
|
|
179
|
-
return {
|
|
180
|
-
get: (id) => byId.get(id),
|
|
181
|
-
list: () => Array.from(byId.values()),
|
|
182
|
-
fieldNames: () => Array.from(byId.values()).map((e) => e.fieldName),
|
|
183
|
-
validateTaskFields(task) {
|
|
184
|
-
const errors = [];
|
|
185
|
-
for (const ext of byId.values()) {
|
|
186
|
-
let schema;
|
|
187
|
-
try {
|
|
188
|
-
schema = JSON.parse(ext.schemaJson);
|
|
189
|
-
} catch {
|
|
190
|
-
errors.push(`task field "${ext.id}": schemaJson is not valid JSON`);
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
const isRequired = typeof schema === "object" && schema !== null && schema.required === true;
|
|
194
|
-
if (!isRequired)
|
|
195
|
-
continue;
|
|
196
|
-
const value = task[ext.fieldName];
|
|
197
|
-
if (value === undefined || value === null || value === "") {
|
|
198
|
-
errors.push(`task field "${ext.fieldName}" (from extension "${ext.id}") is required but missing`);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
return errors.length === 0 ? { ok: true } : { ok: false, errors };
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// packages/runtime/src/control-plane/validators/runtime-registration.ts
|
|
207
|
-
import { existsSync } from "fs";
|
|
208
|
-
import { join } from "path";
|
|
209
|
-
function createValidatorRegistry() {
|
|
210
|
-
const map = new Map;
|
|
211
|
-
const order = [];
|
|
212
|
-
const registry = {
|
|
213
|
-
register(v) {
|
|
214
|
-
if (map.has(v.id))
|
|
215
|
-
throw new Error(`validator already registered: ${v.id}`);
|
|
216
|
-
map.set(v.id, v);
|
|
217
|
-
order.push(v);
|
|
218
|
-
},
|
|
219
|
-
resolve(id) {
|
|
220
|
-
const v = map.get(id);
|
|
221
|
-
if (!v)
|
|
222
|
-
throw new Error(`validator not registered: ${id}`);
|
|
223
|
-
return v;
|
|
224
|
-
},
|
|
225
|
-
list: () => order
|
|
226
|
-
};
|
|
227
|
-
registerBuiltInValidators(registry);
|
|
228
|
-
return registry;
|
|
229
|
-
}
|
|
230
|
-
function registerBuiltInValidators(registry) {
|
|
231
|
-
registry.register({
|
|
232
|
-
id: "std:typecheck",
|
|
233
|
-
category: "custom",
|
|
234
|
-
description: "Runs the package typecheck script when present.",
|
|
235
|
-
run: async (ctx) => runStdTypecheck(ctx)
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
async function runStdTypecheck(ctx) {
|
|
239
|
-
const packageJsonPath = join(ctx.workspaceRoot, "package.json");
|
|
240
|
-
if (!existsSync(packageJsonPath)) {
|
|
241
|
-
return {
|
|
242
|
-
id: "std:typecheck",
|
|
243
|
-
passed: false,
|
|
244
|
-
summary: `package.json not found at ${packageJsonPath}`
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
const proc = Bun.spawn(["bun", "run", "typecheck"], {
|
|
248
|
-
cwd: ctx.workspaceRoot,
|
|
249
|
-
env: process.env,
|
|
250
|
-
stdout: "pipe",
|
|
251
|
-
stderr: "pipe"
|
|
252
|
-
});
|
|
253
|
-
const [exitCode, stdout, stderr] = await Promise.all([
|
|
254
|
-
proc.exited,
|
|
255
|
-
new Response(proc.stdout).text(),
|
|
256
|
-
new Response(proc.stderr).text()
|
|
257
|
-
]);
|
|
258
|
-
const output = `${stdout}${stderr}`.trim();
|
|
259
|
-
return {
|
|
260
|
-
id: "std:typecheck",
|
|
261
|
-
passed: exitCode === 0,
|
|
262
|
-
summary: exitCode === 0 ? "typecheck passed" : "typecheck failed",
|
|
263
|
-
...output ? { details: output.slice(0, 4000) } : {}
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// packages/runtime/src/control-plane/native/scope-rules.ts
|
|
268
|
-
var activeRules = null;
|
|
269
|
-
function setScopeRules(rules) {
|
|
270
|
-
activeRules = rules ?? null;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// packages/runtime/src/control-plane/hook-materializer.ts
|
|
274
|
-
import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
275
|
-
import { dirname, resolve } from "path";
|
|
276
|
-
import { resolveBunCliInvocation } from "@rig/hook-kit";
|
|
277
|
-
var MARKER_PLUGIN = "_rigPlugin";
|
|
278
|
-
var MARKER_HOOK_ID = "_rigHookId";
|
|
279
|
-
function matcherToString(matcher) {
|
|
280
|
-
if (matcher.kind === "all")
|
|
281
|
-
return;
|
|
282
|
-
if (matcher.kind === "tool")
|
|
283
|
-
return matcher.name;
|
|
284
|
-
return matcher.pattern;
|
|
285
|
-
}
|
|
286
|
-
function isPluginOwned(cmd) {
|
|
287
|
-
return typeof cmd[MARKER_PLUGIN] === "string";
|
|
288
|
-
}
|
|
289
|
-
function shellQuote(value) {
|
|
290
|
-
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
291
|
-
}
|
|
292
|
-
function resolveHookRunnerPath() {
|
|
293
|
-
const sibling = resolve(import.meta.dirname, "hook-runner.ts");
|
|
294
|
-
if (existsSync2(sibling)) {
|
|
295
|
-
return sibling;
|
|
296
|
-
}
|
|
297
|
-
return "$CLAUDE_PROJECT_DIR/node_modules/@rig/runtime/src/control-plane/hook-runner.ts";
|
|
298
|
-
}
|
|
299
|
-
function buildTypedHookShimCommand(pluginName, hook, projectRoot) {
|
|
300
|
-
const runnerPath = resolveHookRunnerPath();
|
|
301
|
-
const runnerArg = runnerPath.startsWith("$CLAUDE_PROJECT_DIR") ? `"${runnerPath}"` : shellQuote(runnerPath);
|
|
302
|
-
const bun = resolveBunCliInvocation();
|
|
303
|
-
const envPrefix = Object.entries(bun.env).map(([key, value]) => `${key}=${shellQuote(value)}`).join(" ");
|
|
304
|
-
const parts = [
|
|
305
|
-
envPrefix,
|
|
306
|
-
shellQuote(bun.command),
|
|
307
|
-
runnerArg,
|
|
308
|
-
"--plugin",
|
|
309
|
-
shellQuote(pluginName),
|
|
310
|
-
"--hook",
|
|
311
|
-
shellQuote(hook.id),
|
|
312
|
-
"--event",
|
|
313
|
-
shellQuote(hook.event),
|
|
314
|
-
"--project-root",
|
|
315
|
-
shellQuote(projectRoot)
|
|
316
|
-
].filter(Boolean);
|
|
317
|
-
return parts.join(" ");
|
|
318
|
-
}
|
|
319
|
-
function materializeHooks(projectRoot, entries) {
|
|
320
|
-
const settingsPath = resolve(projectRoot, ".claude", "settings.json");
|
|
321
|
-
const existing = existsSync2(settingsPath) ? safeReadJson(settingsPath) : {};
|
|
322
|
-
const hooks = existing.hooks ?? {};
|
|
323
|
-
for (const event of Object.keys(hooks)) {
|
|
324
|
-
const groups = hooks[event] ?? [];
|
|
325
|
-
const cleaned = [];
|
|
326
|
-
for (const group of groups) {
|
|
327
|
-
const operatorHooks = group.hooks.filter((h) => !isPluginOwned(h));
|
|
328
|
-
if (operatorHooks.length > 0) {
|
|
329
|
-
cleaned.push({ ...group, hooks: operatorHooks });
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
if (cleaned.length > 0) {
|
|
333
|
-
hooks[event] = cleaned;
|
|
334
|
-
} else {
|
|
335
|
-
delete hooks[event];
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
for (const { pluginName, hook, typed } of entries) {
|
|
339
|
-
const command = hook.command ?? (typed ? buildTypedHookShimCommand(pluginName, hook, projectRoot) : undefined);
|
|
340
|
-
if (!command) {
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
343
|
-
const event = hook.event;
|
|
344
|
-
const matcherString = matcherToString(hook.matcher);
|
|
345
|
-
const groups = hooks[event] ??= [];
|
|
346
|
-
let group = groups.find((g) => g.matcher === matcherString);
|
|
347
|
-
if (!group) {
|
|
348
|
-
group = matcherString === undefined ? { hooks: [] } : { matcher: matcherString, hooks: [] };
|
|
349
|
-
groups.push(group);
|
|
350
|
-
}
|
|
351
|
-
group.hooks.push({
|
|
352
|
-
type: "command",
|
|
353
|
-
command,
|
|
354
|
-
[MARKER_PLUGIN]: pluginName,
|
|
355
|
-
[MARKER_HOOK_ID]: hook.id
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
const next = { ...existing };
|
|
359
|
-
if (Object.keys(hooks).length > 0) {
|
|
360
|
-
next.hooks = hooks;
|
|
361
|
-
} else {
|
|
362
|
-
delete next.hooks;
|
|
363
|
-
}
|
|
364
|
-
mkdirSync(dirname(settingsPath), { recursive: true });
|
|
365
|
-
writeFileSync(settingsPath, `${JSON.stringify(next, null, 2)}
|
|
366
|
-
`, "utf-8");
|
|
367
|
-
return settingsPath;
|
|
368
|
-
}
|
|
369
|
-
function safeReadJson(path) {
|
|
370
|
-
try {
|
|
371
|
-
return JSON.parse(readFileSync(path, "utf-8"));
|
|
372
|
-
} catch {
|
|
373
|
-
return {};
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// packages/runtime/src/control-plane/skill-materializer.ts
|
|
378
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
379
|
-
import { resolve as resolve2 } from "path";
|
|
380
|
-
import { loadSkill } from "@rig/skill-loader";
|
|
381
|
-
var MARKER_FILENAME = ".rig-plugin";
|
|
382
|
-
function skillDirName(id) {
|
|
383
|
-
return id.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
384
|
-
}
|
|
385
|
-
async function materializeSkills(projectRoot, entries) {
|
|
386
|
-
const skillsRoot = resolve2(projectRoot, ".pi", "skills");
|
|
387
|
-
if (existsSync3(skillsRoot)) {
|
|
388
|
-
for (const name of readdirSync(skillsRoot)) {
|
|
389
|
-
const dir = resolve2(skillsRoot, name);
|
|
390
|
-
if (existsSync3(resolve2(dir, MARKER_FILENAME))) {
|
|
391
|
-
rmSync(dir, { recursive: true, force: true });
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
const written = [];
|
|
396
|
-
for (const { pluginName, skill } of entries) {
|
|
397
|
-
const sourcePath = resolve2(projectRoot, skill.path);
|
|
398
|
-
if (!existsSync3(sourcePath)) {
|
|
399
|
-
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${sourcePath} does not exist`);
|
|
400
|
-
continue;
|
|
401
|
-
}
|
|
402
|
-
let body;
|
|
403
|
-
try {
|
|
404
|
-
await loadSkill(sourcePath);
|
|
405
|
-
body = readFileSync2(sourcePath, "utf-8");
|
|
406
|
-
} catch (err) {
|
|
407
|
-
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${err instanceof Error ? err.message : err}`);
|
|
408
|
-
continue;
|
|
409
|
-
}
|
|
410
|
-
const dir = resolve2(skillsRoot, skillDirName(skill.id));
|
|
411
|
-
mkdirSync2(dir, { recursive: true });
|
|
412
|
-
writeFileSync2(resolve2(dir, "SKILL.md"), body, "utf-8");
|
|
413
|
-
writeFileSync2(resolve2(dir, MARKER_FILENAME), `${JSON.stringify({ plugin: pluginName, skillId: skill.id }, null, 2)}
|
|
414
|
-
`, "utf-8");
|
|
415
|
-
written.push({ id: skill.id, pluginName, directory: dir });
|
|
416
|
-
}
|
|
417
|
-
return written;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// packages/runtime/src/control-plane/pi-settings-materializer.ts
|
|
421
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
422
|
-
import { dirname as dirname2, resolve as resolve3 } from "path";
|
|
423
|
-
var SETTINGS_RELATIVE_PATH = ".pi/settings.json";
|
|
424
|
-
var MANAGED_RECORD_RELATIVE_PATH = ".rig/state/pi-managed-packages.json";
|
|
425
|
-
function readJson(path, fallback) {
|
|
426
|
-
if (!existsSync4(path))
|
|
427
|
-
return fallback;
|
|
428
|
-
try {
|
|
429
|
-
return JSON.parse(readFileSync3(path, "utf-8"));
|
|
430
|
-
} catch {
|
|
431
|
-
return fallback;
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
function packageKey(entry) {
|
|
435
|
-
if (typeof entry === "string")
|
|
436
|
-
return entry;
|
|
437
|
-
if (entry && typeof entry === "object" && typeof entry.source === "string") {
|
|
438
|
-
return entry.source;
|
|
439
|
-
}
|
|
440
|
-
return JSON.stringify(entry);
|
|
441
|
-
}
|
|
442
|
-
function materializePiPackages(projectRoot, declaredPackages) {
|
|
443
|
-
const settingsPath = resolve3(projectRoot, SETTINGS_RELATIVE_PATH);
|
|
444
|
-
const managedRecordPath = resolve3(projectRoot, MANAGED_RECORD_RELATIVE_PATH);
|
|
445
|
-
const settings = readJson(settingsPath, {});
|
|
446
|
-
const previouslyManaged = new Set(readJson(managedRecordPath, []));
|
|
447
|
-
const existing = Array.isArray(settings.packages) ? settings.packages : [];
|
|
448
|
-
const operatorEntries = existing.filter((entry) => !previouslyManaged.has(packageKey(entry)));
|
|
449
|
-
const operatorKeys = new Set(operatorEntries.map(packageKey));
|
|
450
|
-
const managedToAdd = declaredPackages.filter((pkg) => !operatorKeys.has(pkg));
|
|
451
|
-
const nextPackages = [...operatorEntries, ...managedToAdd];
|
|
452
|
-
if (nextPackages.length > 0 || existsSync4(settingsPath)) {
|
|
453
|
-
const nextSettings = { ...settings };
|
|
454
|
-
if (nextPackages.length > 0) {
|
|
455
|
-
nextSettings.packages = nextPackages;
|
|
456
|
-
} else {
|
|
457
|
-
delete nextSettings.packages;
|
|
458
|
-
}
|
|
459
|
-
mkdirSync3(dirname2(settingsPath), { recursive: true });
|
|
460
|
-
writeFileSync3(settingsPath, `${JSON.stringify(nextSettings, null, 2)}
|
|
461
|
-
`, "utf-8");
|
|
462
|
-
}
|
|
463
|
-
mkdirSync3(dirname2(managedRecordPath), { recursive: true });
|
|
464
|
-
writeFileSync3(managedRecordPath, `${JSON.stringify(managedToAdd, null, 2)}
|
|
465
|
-
`, "utf-8");
|
|
466
|
-
return { settingsPath, packages: managedToAdd };
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
470
|
-
async function buildPluginHostContext(projectRoot) {
|
|
471
|
-
let config;
|
|
472
|
-
try {
|
|
473
|
-
config = await loadConfig(projectRoot);
|
|
474
|
-
} catch (err) {
|
|
475
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
476
|
-
if (msg.includes("no rig.config")) {
|
|
477
|
-
return null;
|
|
478
|
-
}
|
|
479
|
-
throw err;
|
|
480
|
-
}
|
|
481
|
-
const pluginHost = createPluginHost(config.plugins);
|
|
482
|
-
setScopeRules(config.workspace.scopeNormalization);
|
|
483
|
-
if (config.workspace.sandbox && !process.env.RIG_RUNTIME_SANDBOX?.trim()) {
|
|
484
|
-
process.env.RIG_RUNTIME_SANDBOX = config.workspace.sandbox;
|
|
485
|
-
}
|
|
486
|
-
const validatorRegistry = createValidatorRegistry();
|
|
487
|
-
for (const impl of pluginHost.listExecutableValidators()) {
|
|
488
|
-
validatorRegistry.register(impl);
|
|
489
|
-
}
|
|
490
|
-
const taskSourceRegistry = buildTaskSourceRegistry(config, pluginHost, { projectRoot });
|
|
491
|
-
const repoRegistry = createRepoRegistry(pluginHost.listRepoSources());
|
|
492
|
-
const managedEntries = pluginHost.listRepoSources().map(repoRegistrationToManagedEntry).filter((e) => e !== null);
|
|
493
|
-
setManagedRepos(managedEntries);
|
|
494
|
-
const configRoleOverrides = config.runtime?.agentRoles;
|
|
495
|
-
const agentRoleRegistry = createAgentRoleRegistry(pluginHost.listAgentRoles(), configRoleOverrides);
|
|
496
|
-
const taskFieldRegistry = createTaskFieldRegistry(pluginHost.listTaskFieldExtensions());
|
|
497
|
-
try {
|
|
498
|
-
const hookEntries = config.plugins.flatMap((plugin) => (plugin.contributes?.hooks ?? []).map((hook) => ({
|
|
499
|
-
pluginName: plugin.name,
|
|
500
|
-
hook,
|
|
501
|
-
typed: Boolean(plugin.__runtime?.hooks?.[hook.id])
|
|
502
|
-
})));
|
|
503
|
-
if (hookEntries.length > 0) {
|
|
504
|
-
materializeHooks(projectRoot, hookEntries);
|
|
505
|
-
}
|
|
506
|
-
} catch (err) {
|
|
507
|
-
console.warn(`[plugin-host] hook materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
508
|
-
}
|
|
509
|
-
try {
|
|
510
|
-
const skillEntries = config.plugins.flatMap((plugin) => (plugin.contributes?.skills ?? []).map((skill) => ({
|
|
511
|
-
pluginName: plugin.name,
|
|
512
|
-
skill
|
|
513
|
-
})));
|
|
514
|
-
if (skillEntries.length > 0) {
|
|
515
|
-
await materializeSkills(projectRoot, skillEntries);
|
|
516
|
-
}
|
|
517
|
-
} catch (err) {
|
|
518
|
-
console.warn(`[plugin-host] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
519
|
-
}
|
|
520
|
-
try {
|
|
521
|
-
const piPackages = config.runtime?.pi?.packages ?? [];
|
|
522
|
-
if (piPackages.length > 0 || existsSync5(resolvePath(projectRoot, ".rig/state/pi-managed-packages.json"))) {
|
|
523
|
-
materializePiPackages(projectRoot, piPackages);
|
|
524
|
-
}
|
|
525
|
-
} catch (err) {
|
|
526
|
-
console.warn(`[plugin-host] Pi package materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
527
|
-
}
|
|
528
|
-
return {
|
|
529
|
-
config,
|
|
530
|
-
pluginHost,
|
|
531
|
-
validatorRegistry,
|
|
532
|
-
taskSourceRegistry,
|
|
533
|
-
repoRegistry,
|
|
534
|
-
agentRoleRegistry,
|
|
535
|
-
taskFieldRegistry
|
|
536
|
-
};
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
// packages/cli/src/commands/_parsers.ts
|
|
540
|
-
async function loadRigConfigOrNull(projectRoot) {
|
|
541
|
-
try {
|
|
542
|
-
const { loadConfig: loadConfig2 } = await import("@rig/core/load-config");
|
|
543
|
-
return await loadConfig2(projectRoot);
|
|
544
|
-
} catch {
|
|
545
|
-
return null;
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
// packages/cli/src/commands/plugin.ts
|
|
550
|
-
async function executePlugin(context, args) {
|
|
551
|
-
const [command = "list", ...rest] = args;
|
|
552
|
-
switch (command) {
|
|
553
|
-
case "list": {
|
|
554
|
-
requireNoExtraArgs(rest, "rig plugin list");
|
|
555
|
-
const declarative = [];
|
|
556
|
-
const config = await loadRigConfigOrNull(context.projectRoot);
|
|
557
|
-
if (config && Array.isArray(config.plugins)) {
|
|
558
|
-
for (const plugin of config.plugins) {
|
|
559
|
-
const c = plugin.contributes ?? {};
|
|
560
|
-
declarative.push({
|
|
561
|
-
name: plugin.name,
|
|
562
|
-
version: plugin.version,
|
|
563
|
-
validators: (c.validators ?? []).map((v) => v.id),
|
|
564
|
-
hooks: (c.hooks ?? []).map((h) => h.id),
|
|
565
|
-
agentRoles: (c.agentRoles ?? []).map((r) => r.id),
|
|
566
|
-
repoSources: (c.repoSources ?? []).map((r) => r.id),
|
|
567
|
-
taskSources: (c.taskSources ?? []).map((s) => s.id),
|
|
568
|
-
skills: (c.skills ?? []).map((s) => s.id),
|
|
569
|
-
taskFieldExtensions: (c.taskFieldSchemas ?? []).map((f) => f.id),
|
|
570
|
-
cliCommands: (c.cliCommands ?? []).map((entry) => entry.id)
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
if (context.outputMode === "text") {
|
|
575
|
-
if (declarative.length === 0) {
|
|
576
|
-
const configExists = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync6(resolve4(context.projectRoot, name)));
|
|
577
|
-
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.");
|
|
578
|
-
} else {
|
|
579
|
-
console.log("Plugins (rig.config.ts):");
|
|
580
|
-
for (const p of declarative) {
|
|
581
|
-
console.log(` ${p.name}@${p.version}`);
|
|
582
|
-
const lines = [];
|
|
583
|
-
if (p.validators.length)
|
|
584
|
-
lines.push(` validators: ${p.validators.join(", ")}`);
|
|
585
|
-
if (p.hooks.length)
|
|
586
|
-
lines.push(` hooks: ${p.hooks.join(", ")}`);
|
|
587
|
-
if (p.agentRoles.length)
|
|
588
|
-
lines.push(` agent-roles: ${p.agentRoles.join(", ")}`);
|
|
589
|
-
if (p.repoSources.length)
|
|
590
|
-
lines.push(` repo-sources: ${p.repoSources.join(", ")}`);
|
|
591
|
-
if (p.taskSources.length)
|
|
592
|
-
lines.push(` task-sources: ${p.taskSources.join(", ")}`);
|
|
593
|
-
if (p.skills.length)
|
|
594
|
-
lines.push(` skills: ${p.skills.join(", ")}`);
|
|
595
|
-
if (p.taskFieldExtensions.length)
|
|
596
|
-
lines.push(` task-fields: ${p.taskFieldExtensions.join(", ")}`);
|
|
597
|
-
if (p.cliCommands.length)
|
|
598
|
-
lines.push(` cli-commands: ${p.cliCommands.join(", ")} (run with \`rig plugin run <id>\`)`);
|
|
599
|
-
for (const line of lines)
|
|
600
|
-
console.log(line);
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
return {
|
|
605
|
-
ok: true,
|
|
606
|
-
group: "plugin",
|
|
607
|
-
command,
|
|
608
|
-
details: { declarative }
|
|
609
|
-
};
|
|
610
|
-
}
|
|
611
|
-
case "validate": {
|
|
612
|
-
const { value: task, rest: remaining } = takeOption(rest, "--task");
|
|
613
|
-
requireNoExtraArgs(remaining, "rig plugin validate --task <task-id>");
|
|
614
|
-
const taskId = requireTask(task, "rig plugin validate --task <task-id>");
|
|
615
|
-
const hostCtx = await buildPluginHostContext(context.projectRoot);
|
|
616
|
-
if (!hostCtx) {
|
|
617
|
-
throw new CliError(`No rig.config found at ${context.projectRoot}. Run \`rig init\` to set up plugins.`, 2);
|
|
618
|
-
}
|
|
619
|
-
const validators = hostCtx.validatorRegistry.list();
|
|
620
|
-
const results = [];
|
|
621
|
-
for (const validator of validators) {
|
|
622
|
-
try {
|
|
623
|
-
results.push(await validator.run({
|
|
624
|
-
taskId,
|
|
625
|
-
workspaceRoot: context.projectRoot,
|
|
626
|
-
scope: []
|
|
627
|
-
}));
|
|
628
|
-
} catch (error) {
|
|
629
|
-
results.push({
|
|
630
|
-
id: validator.id,
|
|
631
|
-
passed: false,
|
|
632
|
-
summary: `${validator.id} failed unexpectedly`,
|
|
633
|
-
details: `${error}`
|
|
634
|
-
});
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
const passed = results.filter((result) => result.passed).length;
|
|
638
|
-
const failed = results.length - passed;
|
|
639
|
-
if (context.outputMode === "text") {
|
|
640
|
-
if (results.length === 0) {
|
|
641
|
-
console.log("No plugin validators registered.");
|
|
642
|
-
} else {
|
|
643
|
-
for (const result of results) {
|
|
644
|
-
const icon = result.passed ? "PASS" : "FAIL";
|
|
645
|
-
console.log(`[${icon}] ${result.id}: ${result.summary}`);
|
|
646
|
-
if (result.details && !result.passed) {
|
|
647
|
-
console.log(result.details);
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
if (failed > 0) {
|
|
653
|
-
throw new CliError(`Plugin validation failed for ${failed} validator(s).`, 2, { hint: "Fix the reported validators, then re-run `rig plugin validate --task <id>`." });
|
|
654
|
-
}
|
|
655
|
-
return {
|
|
656
|
-
ok: true,
|
|
657
|
-
group: "plugin",
|
|
658
|
-
command,
|
|
659
|
-
details: {
|
|
660
|
-
taskId,
|
|
661
|
-
passed,
|
|
662
|
-
failed,
|
|
663
|
-
results
|
|
664
|
-
}
|
|
665
|
-
};
|
|
666
|
-
}
|
|
667
|
-
case "run": {
|
|
668
|
-
const [commandId, ...commandArgs] = rest;
|
|
669
|
-
if (!commandId) {
|
|
670
|
-
throw new CliError("Usage: rig plugin run <command-id> [args...]", 1, { hint: "Run `rig plugin list` to see plugin-contributed command ids." });
|
|
671
|
-
}
|
|
672
|
-
const hostCtx = await buildPluginHostContext(context.projectRoot);
|
|
673
|
-
if (!hostCtx) {
|
|
674
|
-
throw new CliError(`No rig.config found at ${context.projectRoot}. Run \`rig init\` to set up plugins.`, 2);
|
|
675
|
-
}
|
|
676
|
-
const registration = resolvePluginCliCommand(hostCtx.pluginHost.listCliCommands(), commandId);
|
|
677
|
-
if (!registration) {
|
|
678
|
-
const available = hostCtx.pluginHost.listCliCommands().map((entry) => entry.id);
|
|
679
|
-
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);
|
|
680
|
-
}
|
|
681
|
-
if (context.dryRun) {
|
|
682
|
-
if (context.outputMode === "text") {
|
|
683
|
-
console.log(`[dry-run] ${registration.command}${commandArgs.length ? ` ${commandArgs.join(" ")}` : ""}`);
|
|
684
|
-
}
|
|
685
|
-
return { ok: true, group: "plugin", command, details: { id: registration.id, dryRun: true } };
|
|
686
|
-
}
|
|
687
|
-
const proc = Bun.spawn(["bash", "-c", `${registration.command} "$@"`, registration.id, ...commandArgs], {
|
|
688
|
-
cwd: context.projectRoot,
|
|
689
|
-
env: process.env,
|
|
690
|
-
stdin: "inherit",
|
|
691
|
-
stdout: "inherit",
|
|
692
|
-
stderr: "inherit"
|
|
693
|
-
});
|
|
694
|
-
const exitCode = await proc.exited;
|
|
695
|
-
if (exitCode !== 0) {
|
|
696
|
-
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." });
|
|
697
|
-
}
|
|
698
|
-
return { ok: true, group: "plugin", command, details: { id: registration.id, exitCode } };
|
|
699
|
-
}
|
|
700
|
-
default:
|
|
701
|
-
throw new CliError(`Unknown plugin command: ${command}`, 1, { hint: "Run `rig plugin --help` \u2014 commands are list|validate|run." });
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
function resolvePluginCliCommand(commands, requested) {
|
|
705
|
-
const exact = commands.find((entry) => entry.id === requested);
|
|
706
|
-
if (exact)
|
|
707
|
-
return exact;
|
|
708
|
-
const byLocalPart = commands.filter((entry) => entry.id.split(":").slice(1).join(":") === requested);
|
|
709
|
-
return byLocalPart.length === 1 ? byLocalPart[0] : undefined;
|
|
710
|
-
}
|
|
711
|
-
export {
|
|
712
|
-
resolvePluginCliCommand,
|
|
713
|
-
executePlugin
|
|
714
|
-
};
|