@h-rig/core 0.0.6-alpha.10 → 0.0.6-alpha.100
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/src/define-config.d.ts +18 -0
- package/dist/src/define-config.js +20 -2
- package/dist/src/define-plugin.d.ts +9 -0
- package/dist/src/define-plugin.js +17 -0
- package/dist/src/engineReadModelReducer.d.ts +12 -0
- package/dist/src/engineReadModelReducer.js +6 -3
- package/dist/src/index.d.ts +12 -0
- package/dist/src/index.js +354 -22
- package/dist/src/load-config.d.ts +2 -0
- package/dist/src/load-config.js +257 -5
- package/dist/src/plugin-host.d.ts +40 -0
- package/dist/src/plugin-host.js +18 -0
- package/dist/src/plugin-runtime.d.ts +64 -0
- package/dist/src/rig-init-builder.d.ts +30 -0
- package/dist/src/rig-init-builder.js +3 -2
- package/dist/src/rigSelectors.d.ts +220 -0
- package/dist/src/rigSelectors.js +125 -4
- package/dist/src/taskGraph.d.ts +41 -0
- package/dist/src/taskGraph.js +164 -8
- package/dist/src/taskGraphCodes.d.ts +3 -0
- package/dist/src/taskGraphLayout.d.ts +60 -0
- package/dist/src/taskGraphLayout.js +22 -3
- package/package.json +6 -12
package/dist/src/load-config.js
CHANGED
|
@@ -1,17 +1,269 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/core/src/load-config.ts
|
|
3
|
-
import { existsSync, readFileSync } from "fs";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { existsSync, mkdtempSync, readFileSync, readdirSync, rmSync } from "fs";
|
|
4
|
+
import { tmpdir } from "os";
|
|
5
|
+
import { dirname, join } from "path";
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
7
|
+
import { Schema as Schema2 } from "effect";
|
|
8
|
+
import { RigConfig as RigConfig2 } from "@rig/contracts";
|
|
9
|
+
|
|
10
|
+
// packages/core/src/define-config.ts
|
|
6
11
|
import { Schema } from "effect";
|
|
7
12
|
import { RigConfig } from "@rig/contracts";
|
|
13
|
+
function normalizeWorkspaceConfig(raw) {
|
|
14
|
+
const workspace = raw && typeof raw === "object" && !Array.isArray(raw) ? { ...raw } : { mainRepo: "." };
|
|
15
|
+
workspace.checkout = workspace.checkout ?? workspace.isolation ?? "worktree";
|
|
16
|
+
workspace.isolation = workspace.isolation ?? workspace.checkout;
|
|
17
|
+
workspace.sandbox = workspace.sandbox ?? "enforce";
|
|
18
|
+
return workspace;
|
|
19
|
+
}
|
|
20
|
+
function applyConfigDefaults(raw) {
|
|
21
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
22
|
+
return raw;
|
|
23
|
+
const record = raw;
|
|
24
|
+
return {
|
|
25
|
+
...record,
|
|
26
|
+
plugins: Array.isArray(record.plugins) ? record.plugins : [],
|
|
27
|
+
workspace: normalizeWorkspaceConfig(record.workspace)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// packages/core/src/load-config.ts
|
|
8
32
|
var TS_NAMES = ["rig.config.ts", "rig.config.mts"];
|
|
9
33
|
var JSON_NAMES = ["rig.config.json"];
|
|
34
|
+
function isModuleResolutionError(error) {
|
|
35
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
36
|
+
return message.includes("Cannot find module") || message.includes("Could not resolve");
|
|
37
|
+
}
|
|
38
|
+
function runningFromCompiledBinary() {
|
|
39
|
+
return import.meta.url.includes("$bunfs");
|
|
40
|
+
}
|
|
41
|
+
function packageNameAndSubpath(specifier) {
|
|
42
|
+
if (specifier.startsWith(".") || specifier.startsWith("/") || /^[a-zA-Z]+:/.test(specifier))
|
|
43
|
+
return null;
|
|
44
|
+
const parts = specifier.split("/");
|
|
45
|
+
const packageName = specifier.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
|
|
46
|
+
if (!packageName)
|
|
47
|
+
return null;
|
|
48
|
+
const rest = parts.slice(specifier.startsWith("@") ? 2 : 1).join("/");
|
|
49
|
+
return { packageName, subpath: rest ? `./${rest}` : "." };
|
|
50
|
+
}
|
|
51
|
+
function exportTargetFromEntry(entry) {
|
|
52
|
+
if (typeof entry === "string")
|
|
53
|
+
return entry;
|
|
54
|
+
if (entry && typeof entry === "object" && !Array.isArray(entry)) {
|
|
55
|
+
const conditions = entry;
|
|
56
|
+
for (const key of ["bun", "import", "default", "require"]) {
|
|
57
|
+
if (typeof conditions[key] === "string")
|
|
58
|
+
return conditions[key];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
function patternExportTarget(record, subpath) {
|
|
64
|
+
for (const [pattern, entry] of Object.entries(record)) {
|
|
65
|
+
if (!pattern.includes("*"))
|
|
66
|
+
continue;
|
|
67
|
+
const [prefix = "", suffix = ""] = pattern.split("*");
|
|
68
|
+
if (!subpath.startsWith(prefix) || !subpath.endsWith(suffix))
|
|
69
|
+
continue;
|
|
70
|
+
const replacement = subpath.slice(prefix.length, subpath.length - suffix.length);
|
|
71
|
+
const target = exportTargetFromEntry(entry);
|
|
72
|
+
if (target)
|
|
73
|
+
return target.replace("*", replacement);
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
function exportTargetFromPackageJson(pkg, subpath) {
|
|
78
|
+
const exportsField = pkg.exports;
|
|
79
|
+
const target = (() => {
|
|
80
|
+
if (typeof exportsField === "string" && subpath === ".")
|
|
81
|
+
return exportsField;
|
|
82
|
+
if (!exportsField || typeof exportsField !== "object" || Array.isArray(exportsField))
|
|
83
|
+
return null;
|
|
84
|
+
const record = exportsField;
|
|
85
|
+
return exportTargetFromEntry(record[subpath] ?? (subpath === "." ? record["."] : undefined)) ?? patternExportTarget(record, subpath);
|
|
86
|
+
})();
|
|
87
|
+
if (target)
|
|
88
|
+
return target;
|
|
89
|
+
return subpath === "." && typeof pkg.module === "string" ? pkg.module : subpath === "." && typeof pkg.main === "string" ? pkg.main : null;
|
|
90
|
+
}
|
|
91
|
+
function resolvePackageDirFromBunStore(packageName, nodeModulesDir) {
|
|
92
|
+
const storeDir = join(nodeModulesDir, ".bun");
|
|
93
|
+
if (!existsSync(storeDir))
|
|
94
|
+
return null;
|
|
95
|
+
const encoded = packageName.replace("/", "+");
|
|
96
|
+
try {
|
|
97
|
+
for (const entry of readdirSync(storeDir).sort()) {
|
|
98
|
+
if (!entry.startsWith(`${encoded}@`))
|
|
99
|
+
continue;
|
|
100
|
+
const candidate = join(storeDir, entry, "node_modules", packageName);
|
|
101
|
+
if (existsSync(join(candidate, "package.json")))
|
|
102
|
+
return candidate;
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
function resolvePackageExportFromDir(packageDir, subpath) {
|
|
110
|
+
const packageJsonPath = join(packageDir, "package.json");
|
|
111
|
+
if (!existsSync(packageJsonPath))
|
|
112
|
+
return null;
|
|
113
|
+
try {
|
|
114
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
115
|
+
const target = exportTargetFromPackageJson(pkg, subpath);
|
|
116
|
+
if (target) {
|
|
117
|
+
const resolved = join(packageDir, target);
|
|
118
|
+
if (existsSync(resolved))
|
|
119
|
+
return resolved;
|
|
120
|
+
}
|
|
121
|
+
} catch {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
function resolveBarePackageExport(specifier, parentDir) {
|
|
127
|
+
const parsed = packageNameAndSubpath(specifier);
|
|
128
|
+
if (!parsed)
|
|
129
|
+
return null;
|
|
130
|
+
const packageNames = parsed.packageName.startsWith("@rig/") ? [parsed.packageName, parsed.packageName.replace(/^@rig\//, "@h-rig/")] : [parsed.packageName];
|
|
131
|
+
let current = parentDir;
|
|
132
|
+
while (true) {
|
|
133
|
+
const nodeModulesDir = join(current, "node_modules");
|
|
134
|
+
for (const packageName of packageNames) {
|
|
135
|
+
const directPackageDir = join(nodeModulesDir, packageName);
|
|
136
|
+
const resolvedDirect = resolvePackageExportFromDir(directPackageDir, parsed.subpath);
|
|
137
|
+
if (resolvedDirect)
|
|
138
|
+
return resolvedDirect;
|
|
139
|
+
const bunStorePackageDir = resolvePackageDirFromBunStore(packageName, nodeModulesDir);
|
|
140
|
+
if (bunStorePackageDir) {
|
|
141
|
+
const resolvedFromStore = resolvePackageExportFromDir(bunStorePackageDir, parsed.subpath);
|
|
142
|
+
if (resolvedFromStore)
|
|
143
|
+
return resolvedFromStore;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const next = dirname(current);
|
|
147
|
+
if (next === current)
|
|
148
|
+
break;
|
|
149
|
+
current = next;
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
var runtimeBundleQueue = Promise.resolve();
|
|
154
|
+
function enqueueRuntimeBundle(operation) {
|
|
155
|
+
const next = runtimeBundleQueue.then(operation, operation);
|
|
156
|
+
runtimeBundleQueue = next.then(() => {
|
|
157
|
+
return;
|
|
158
|
+
}, () => {
|
|
159
|
+
return;
|
|
160
|
+
});
|
|
161
|
+
return next;
|
|
162
|
+
}
|
|
163
|
+
async function importConfigViaRuntimeBundleUnserialized(configPath) {
|
|
164
|
+
const bun = globalThis.Bun;
|
|
165
|
+
if (!bun?.build) {
|
|
166
|
+
throw new Error(`Failed to import ${configPath}: bare imports could not be resolved and no Bun.build runtime bundler is available.`);
|
|
167
|
+
}
|
|
168
|
+
const hostDir = (() => {
|
|
169
|
+
try {
|
|
170
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
171
|
+
} catch {
|
|
172
|
+
return process.cwd();
|
|
173
|
+
}
|
|
174
|
+
})();
|
|
175
|
+
const configDir = dirname(configPath);
|
|
176
|
+
const UNRESOLVED_NAMESPACE = "rig-config-unresolved";
|
|
177
|
+
const hostResolverPlugin = {
|
|
178
|
+
name: "rig-host-package-resolver",
|
|
179
|
+
setup(build) {
|
|
180
|
+
build.onResolve({ filter: /^@rig\// }, (args) => {
|
|
181
|
+
const candidates = [
|
|
182
|
+
[args.path, hostDir],
|
|
183
|
+
[args.path.replace(/^@rig\//, "@h-rig/"), hostDir],
|
|
184
|
+
[args.path, configDir]
|
|
185
|
+
];
|
|
186
|
+
for (const [specifier, parent] of candidates) {
|
|
187
|
+
try {
|
|
188
|
+
const resolved = bun.resolveSync?.(specifier, parent) ?? resolveBarePackageExport(specifier, parent);
|
|
189
|
+
if (resolved)
|
|
190
|
+
return { path: resolved };
|
|
191
|
+
} catch {
|
|
192
|
+
const resolved = resolveBarePackageExport(specifier, parent);
|
|
193
|
+
if (resolved)
|
|
194
|
+
return { path: resolved };
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return;
|
|
198
|
+
});
|
|
199
|
+
build.onResolve({ filter: /.*/ }, (args) => {
|
|
200
|
+
if (/^(?:node|bun):/.test(args.path))
|
|
201
|
+
return;
|
|
202
|
+
const parent = args.importer ? dirname(args.importer) : configDir;
|
|
203
|
+
try {
|
|
204
|
+
const resolved = bun.resolveSync?.(args.path, parent) ?? resolveBarePackageExport(args.path, parent);
|
|
205
|
+
if (resolved)
|
|
206
|
+
return { path: resolved };
|
|
207
|
+
} catch {
|
|
208
|
+
const resolved = resolveBarePackageExport(args.path, parent);
|
|
209
|
+
if (resolved)
|
|
210
|
+
return { path: resolved };
|
|
211
|
+
return { path: args.path, namespace: UNRESOLVED_NAMESPACE };
|
|
212
|
+
}
|
|
213
|
+
return;
|
|
214
|
+
});
|
|
215
|
+
build.onLoad({ filter: /.*/, namespace: UNRESOLVED_NAMESPACE }, (args) => ({
|
|
216
|
+
loader: "js",
|
|
217
|
+
contents: `module.exports = {};
|
|
218
|
+
throw new Error(${JSON.stringify(`Failed to bundle ${configPath}: Could not resolve: "${args.path}". Maybe you need to "bun install"?`)});
|
|
219
|
+
`
|
|
220
|
+
}));
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const result = await bun.build({
|
|
224
|
+
entrypoints: [configPath],
|
|
225
|
+
target: "bun",
|
|
226
|
+
format: "esm",
|
|
227
|
+
throw: false,
|
|
228
|
+
plugins: [hostResolverPlugin]
|
|
229
|
+
});
|
|
230
|
+
if (!result.success || !result.outputs[0]) {
|
|
231
|
+
const detail = result.logs.map((log) => String(log)).join(`
|
|
232
|
+
`);
|
|
233
|
+
throw new Error(`Failed to bundle ${configPath}: ${detail || "unknown bundler error"}`);
|
|
234
|
+
}
|
|
235
|
+
const dir = mkdtempSync(join(tmpdir(), "rig-config-bundle-"));
|
|
236
|
+
try {
|
|
237
|
+
const bundledPath = join(dir, "rig.config.bundled.js");
|
|
238
|
+
await bun.write(bundledPath, await result.outputs[0].text());
|
|
239
|
+
return await import(pathToFileURL(bundledPath).href);
|
|
240
|
+
} finally {
|
|
241
|
+
try {
|
|
242
|
+
rmSync(dir, { recursive: true, force: true });
|
|
243
|
+
} catch {}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
10
246
|
async function loadConfig(cwd) {
|
|
11
247
|
for (const name of TS_NAMES) {
|
|
12
248
|
const p = join(cwd, name);
|
|
13
249
|
if (existsSync(p)) {
|
|
14
|
-
const mod = await
|
|
250
|
+
const mod = await enqueueRuntimeBundle(async () => {
|
|
251
|
+
if (runningFromCompiledBinary()) {
|
|
252
|
+
return importConfigViaRuntimeBundleUnserialized(p);
|
|
253
|
+
}
|
|
254
|
+
const source = readFileSync(p, "utf8");
|
|
255
|
+
const importsRigHostPackages = /(?:import\s+[^;]*?from\s*|import\s*\()\s*["']@rig\//.test(source);
|
|
256
|
+
if (importsRigHostPackages) {
|
|
257
|
+
return importConfigViaRuntimeBundleUnserialized(p);
|
|
258
|
+
}
|
|
259
|
+
try {
|
|
260
|
+
return await import(pathToFileURL(p).href);
|
|
261
|
+
} catch (error) {
|
|
262
|
+
if (!isModuleResolutionError(error))
|
|
263
|
+
throw error;
|
|
264
|
+
return importConfigViaRuntimeBundleUnserialized(p);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
15
267
|
const raw = mod.default ?? mod.config;
|
|
16
268
|
return decodePreservingRuntime(raw);
|
|
17
269
|
}
|
|
@@ -35,7 +287,7 @@ function decodePreservingRuntime(raw) {
|
|
|
35
287
|
}
|
|
36
288
|
}
|
|
37
289
|
}
|
|
38
|
-
const decoded =
|
|
290
|
+
const decoded = Schema2.decodeUnknownSync(RigConfig2)(applyConfigDefaults(raw));
|
|
39
291
|
const plugins = decoded.plugins.map((p) => {
|
|
40
292
|
const runtime = runtimeByName.get(p.name);
|
|
41
293
|
if (!runtime)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ValidatorRegistration, HookRegistration, SkillRegistration, RepoSourceRegistration, AgentRoleRegistration, TaskFieldExtension, TaskSourceRegistration, CliCommandRegistration } from "@rig/contracts";
|
|
2
|
+
import type { RegisteredValidator, RigPluginWithRuntime, TaskSourceFactoryEntry } from "./plugin-runtime";
|
|
3
|
+
export interface PluginHost {
|
|
4
|
+
getValidator(id: string): ValidatorRegistration | undefined;
|
|
5
|
+
getHook(id: string): HookRegistration | undefined;
|
|
6
|
+
getSkill(id: string): SkillRegistration | undefined;
|
|
7
|
+
getRepoSource(id: string): RepoSourceRegistration | undefined;
|
|
8
|
+
getAgentRole(id: string): AgentRoleRegistration | undefined;
|
|
9
|
+
getTaskFieldExtension(id: string): TaskFieldExtension | undefined;
|
|
10
|
+
getTaskSource(id: string): TaskSourceRegistration | undefined;
|
|
11
|
+
getCliCommand(id: string): CliCommandRegistration | undefined;
|
|
12
|
+
listValidators(): readonly ValidatorRegistration[];
|
|
13
|
+
listHooks(): readonly HookRegistration[];
|
|
14
|
+
listSkills(): readonly SkillRegistration[];
|
|
15
|
+
listRepoSources(): readonly RepoSourceRegistration[];
|
|
16
|
+
listAgentRoles(): readonly AgentRoleRegistration[];
|
|
17
|
+
listTaskFieldExtensions(): readonly TaskFieldExtension[];
|
|
18
|
+
listTaskSources(): readonly TaskSourceRegistration[];
|
|
19
|
+
listCliCommands(): readonly CliCommandRegistration[];
|
|
20
|
+
/**
|
|
21
|
+
* Executable validators contributed by plugins. Only validators whose
|
|
22
|
+
* metadata appears in `listValidators()` and whose plugin shipped a runtime
|
|
23
|
+
* implementation via `definePlugin(meta, { validators: [...] })` appear here.
|
|
24
|
+
* Validators registered metadata-only (no run() implementation) are absent.
|
|
25
|
+
*/
|
|
26
|
+
listExecutableValidators(): readonly RegisteredValidator[];
|
|
27
|
+
/**
|
|
28
|
+
* Executable task source factories contributed by plugins. Used by the
|
|
29
|
+
* runtime's `buildTaskSourceRegistry` to instantiate non-standard task
|
|
30
|
+
* source kinds (Linear, Jira, custom) declared by plugins.
|
|
31
|
+
*/
|
|
32
|
+
listExecutableTaskSources(): readonly TaskSourceFactoryEntry[];
|
|
33
|
+
/**
|
|
34
|
+
* Look up an executable task source factory by its `kind` (the value in
|
|
35
|
+
* `config.taskSource.kind`). Returns undefined when no plugin provides
|
|
36
|
+
* a factory for that kind.
|
|
37
|
+
*/
|
|
38
|
+
resolveTaskSourceFactoryByKind(kind: string): TaskSourceFactoryEntry | undefined;
|
|
39
|
+
}
|
|
40
|
+
export declare function createPluginHost(plugins: readonly RigPluginWithRuntime[]): PluginHost;
|
package/dist/src/plugin-host.js
CHANGED
|
@@ -58,6 +58,24 @@ function assertRuntimeMatchesMetadata(plugin) {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
+
const declaredHooks = new Map((plugin.contributes?.hooks ?? []).map((hook) => [hook.id, hook]));
|
|
62
|
+
const runtimeHooks = plugin.__runtime?.hooks;
|
|
63
|
+
for (const hookId of Object.keys(runtimeHooks ?? {})) {
|
|
64
|
+
const metadata = declaredHooks.get(hookId);
|
|
65
|
+
if (!metadata) {
|
|
66
|
+
throw new Error(`plugin "${plugin.name}" typed hook "${hookId}" has no matching metadata entry in contributes.hooks`);
|
|
67
|
+
}
|
|
68
|
+
if (metadata.command) {
|
|
69
|
+
throw new Error(`plugin "${plugin.name}" hook "${hookId}" has both a typed implementation and a command string \u2014 pick one`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (runtimeHooks) {
|
|
73
|
+
for (const hook of declaredHooks.values()) {
|
|
74
|
+
if (!runtimeHooks[hook.id] && !hook.command) {
|
|
75
|
+
throw new Error(`plugin "${plugin.name}" hook metadata "${hook.id}" has no implementation (typed function or command)`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
61
79
|
}
|
|
62
80
|
function createPluginHost(plugins) {
|
|
63
81
|
assertUniquePluginNames(plugins);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { HookImplementation, RegisteredTaskSource, RigConfig, RigPlugin, TaskSourceConfig, TaskSourceRegistration, ValidatorRegistration } from "@rig/contracts";
|
|
2
|
+
export interface ValidatorResult {
|
|
3
|
+
id: string;
|
|
4
|
+
passed: boolean;
|
|
5
|
+
summary: string;
|
|
6
|
+
details?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ValidatorContext {
|
|
9
|
+
taskId: string;
|
|
10
|
+
workspaceRoot: string;
|
|
11
|
+
scope: readonly string[];
|
|
12
|
+
monorepoRoot?: string;
|
|
13
|
+
artifactsDir?: string;
|
|
14
|
+
taskConfig?: unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface RegisteredValidator extends ValidatorRegistration {
|
|
17
|
+
run(ctx: ValidatorContext): Promise<ValidatorResult>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Project context handed to task-source factories at instantiation. The
|
|
21
|
+
* server process's cwd is NOT necessarily the project root (workspace-spawned
|
|
22
|
+
* servers run from the engine checkout), so factories that touch the
|
|
23
|
+
* filesystem must resolve relative config paths against `projectRoot`,
|
|
24
|
+
* never cwd.
|
|
25
|
+
*/
|
|
26
|
+
export interface TaskSourceFactoryContext {
|
|
27
|
+
projectRoot: string;
|
|
28
|
+
/**
|
|
29
|
+
* Full project config for adapters that need source-adjacent top-level
|
|
30
|
+
* settings (for example github.projects). Factories should still treat
|
|
31
|
+
* TaskSourceConfig as the primary adapter config.
|
|
32
|
+
*/
|
|
33
|
+
rigConfig?: RigConfig;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Executable task-source factory contributed by a plugin. A plugin
|
|
37
|
+
* registers a TaskSourceRegistration metadata entry (with `id` and `kind`)
|
|
38
|
+
* AND a factory here that turns a TaskSourceConfig into a RegisteredTaskSource.
|
|
39
|
+
*
|
|
40
|
+
* `kind` is matched against `config.taskSource.kind` at boot. The first
|
|
41
|
+
* matching plugin factory wins; if multiple plugins claim the same kind,
|
|
42
|
+
* `createPluginHost` throws a duplicate-kind error.
|
|
43
|
+
*/
|
|
44
|
+
export interface TaskSourceFactoryEntry extends TaskSourceRegistration {
|
|
45
|
+
factory(config: TaskSourceConfig, context?: TaskSourceFactoryContext): RegisteredTaskSource;
|
|
46
|
+
}
|
|
47
|
+
export interface RigPluginRuntime {
|
|
48
|
+
validators?: readonly RegisteredValidator[];
|
|
49
|
+
taskSources?: readonly TaskSourceFactoryEntry[];
|
|
50
|
+
/**
|
|
51
|
+
* Typed hook implementations keyed by hook id. Each key must match a
|
|
52
|
+
* declared `contributes.hooks` entry on the same plugin. A typed hook and
|
|
53
|
+
* a metadata `command` string are mutually exclusive per hook — and when
|
|
54
|
+
* this channel is present, every declared hook must be implemented one way
|
|
55
|
+
* or the other (same all-or-none rule as validators). The runtime's
|
|
56
|
+
* hook-materializer generates the shim command that routes Claude Code's
|
|
57
|
+
* hook invocation to the typed function (see
|
|
58
|
+
* `@rig/runtime/control-plane/hook-runner`).
|
|
59
|
+
*/
|
|
60
|
+
hooks?: Record<string, HookImplementation>;
|
|
61
|
+
}
|
|
62
|
+
export type RigPluginWithRuntime = RigPlugin & {
|
|
63
|
+
__runtime?: RigPluginRuntime;
|
|
64
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure builder that turns a small input shape into the source text of a
|
|
3
|
+
* `rig.config.ts` file. Shared between the CLI `rig init` wizard and the
|
|
4
|
+
* desktop app's in-app setup wizard so both surfaces produce identical
|
|
5
|
+
* output.
|
|
6
|
+
*
|
|
7
|
+
* Pure — no fs, no node, no imports outside this file. Safe to bundle into
|
|
8
|
+
* a renderer (Vite, esbuild, webpack).
|
|
9
|
+
*/
|
|
10
|
+
export type RigInitConfigInput = {
|
|
11
|
+
projectName: string;
|
|
12
|
+
projectRepo?: string;
|
|
13
|
+
taskSource: {
|
|
14
|
+
kind: "github-issues";
|
|
15
|
+
owner: string;
|
|
16
|
+
repo: string;
|
|
17
|
+
assignee?: string;
|
|
18
|
+
} | {
|
|
19
|
+
kind: "files";
|
|
20
|
+
path: string;
|
|
21
|
+
};
|
|
22
|
+
useStandardPlugin: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Remote run placement (ssh target, e.g. `ubuntu@host`). Omit / empty = local
|
|
25
|
+
* placement (runs execute where `rig` starts) — the default. Surfaced as a
|
|
26
|
+
* dedicated `rig init` step; written to `runtime.server.sshTarget`.
|
|
27
|
+
*/
|
|
28
|
+
sshTarget?: string;
|
|
29
|
+
};
|
|
30
|
+
export declare function buildRigInitConfigSource(input: RigInitConfigInput): string;
|
|
@@ -37,13 +37,14 @@ function buildRigInitConfigSource(input) {
|
|
|
37
37
|
lines.push(` },`);
|
|
38
38
|
}
|
|
39
39
|
lines.push(` workspace: { mainRepo: ".", isolation: "worktree" },`);
|
|
40
|
-
|
|
40
|
+
const sshTarget = input.sshTarget?.trim();
|
|
41
|
+
lines.push(sshTarget ? ` runtime: { harness: "pi", mode: "yolo", server: { sshTarget: ${JSON.stringify(sshTarget)} } },` : ` runtime: { harness: "pi", mode: "yolo" }, // server.sshTarget unset = local placement`);
|
|
41
42
|
lines.push(` planning: { mode: "auto" },`);
|
|
42
43
|
lines.push(` github: {`);
|
|
43
44
|
lines.push(` issueUpdates: "lifecycle",`);
|
|
44
45
|
lines.push(` projects: { enabled: false },`);
|
|
45
46
|
lines.push(` },`);
|
|
46
|
-
lines.push(` automation: { maxValidationAttempts: 30, maxPrFixIterations:
|
|
47
|
+
lines.push(` automation: { maxValidationAttempts: 30, maxPrFixIterations: 100500 },`);
|
|
47
48
|
lines.push(` pr: { mode: "auto", watchChecks: true, autoFixChecks: true, autoFixReview: true },`);
|
|
48
49
|
lines.push(` merge: { mode: "auto", method: "repo-default", deleteBranch: "repo-default", bypass: false },`);
|
|
49
50
|
lines.push(` issueAnalysis: { enabled: true, harness: "pi", mode: "continuous" },`);
|