@h-rig/core 0.0.6-alpha.17 → 0.0.6-alpha.170
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/agent-role-registry.d.ts +4 -0
- package/dist/src/agent-role-registry.js +27 -0
- package/dist/src/authority-paths.d.ts +15 -0
- package/dist/src/authority-paths.js +80 -0
- package/dist/src/baked-secrets.d.ts +6 -0
- package/dist/src/baked-secrets.js +121 -0
- package/dist/src/build-time-config.d.ts +12 -0
- package/dist/src/build-time-config.js +25 -0
- package/dist/src/build-time-config.macro.d.ts +1 -0
- package/dist/src/capability-loaders.d.ts +51 -0
- package/dist/src/capability-loaders.js +758 -0
- package/dist/src/capability.d.ts +79 -0
- package/dist/src/capability.js +63 -0
- package/dist/src/checkout-root.d.ts +1 -0
- package/dist/src/checkout-root.js +30 -0
- package/dist/src/config-env.d.ts +4 -0
- package/dist/src/config-env.js +23 -0
- package/dist/src/config.d.ts +3 -0
- package/dist/src/config.js +44 -0
- package/dist/src/declarative-config.d.ts +14 -0
- package/dist/src/declarative-config.js +82 -0
- package/dist/src/default-kernel.d.ts +1 -0
- package/dist/src/default-kernel.js +12 -0
- package/dist/src/define-config.d.ts +20 -0
- package/dist/src/define-config.js +28 -15
- package/dist/src/define-plugin.d.ts +13 -0
- package/dist/src/define-plugin.js +4 -43
- package/dist/src/embedded-plugins.d.ts +59 -0
- package/dist/src/embedded-plugins.js +22 -0
- package/dist/src/exec.d.ts +13 -0
- package/dist/src/exec.js +101 -0
- package/dist/src/harness-paths.d.ts +18 -0
- package/dist/src/harness-paths.js +141 -0
- package/dist/src/hook-materializer.d.ts +72 -0
- package/dist/src/hook-materializer.js +281 -0
- package/dist/src/hook-protocol.d.ts +2 -0
- package/dist/src/hook-protocol.js +462 -0
- package/dist/src/hook-runner.d.ts +48 -0
- package/dist/src/hook-runner.js +756 -0
- package/dist/src/hook-runtime.d.ts +52 -0
- package/dist/src/hook-runtime.js +462 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.js +210 -2499
- package/dist/src/json-files.d.ts +9 -0
- package/dist/src/json-files.js +125 -0
- package/dist/src/kernel-boot.d.ts +2 -0
- package/dist/src/kernel-boot.js +10 -0
- package/dist/src/kernel-entrypoint.d.ts +22 -0
- package/dist/src/kernel-entrypoint.js +548 -0
- package/dist/src/kernel-plugin-abi.d.ts +1 -0
- package/dist/src/kernel-plugin-abi.js +1 -0
- package/dist/src/kernel-resolver.d.ts +2 -0
- package/dist/src/kernel-resolver.js +6 -0
- package/dist/src/layout.d.ts +10 -0
- package/dist/src/layout.js +144 -0
- package/dist/src/load-config.d.ts +2 -0
- package/dist/src/load-config.js +423 -30
- package/dist/src/placement.d.ts +50 -0
- package/dist/src/placement.js +996 -0
- package/dist/src/plugin-host-context.d.ts +66 -0
- package/dist/src/plugin-host-context.js +1292 -0
- package/dist/src/plugin-host-registries.d.ts +31 -0
- package/dist/src/plugin-host-registries.js +79 -0
- package/dist/src/plugin-host.d.ts +77 -0
- package/dist/src/plugin-host.js +127 -63
- package/dist/src/plugin-runtime.d.ts +173 -0
- package/dist/src/profile-ops.d.ts +9 -0
- package/dist/src/profile-ops.js +252 -0
- package/dist/src/project-plugins.d.ts +63 -0
- package/dist/src/project-plugins.js +793 -0
- package/dist/src/remote-config.d.ts +183 -0
- package/dist/src/remote-config.js +574 -0
- package/dist/src/root-resolver.d.ts +5 -0
- package/dist/src/root-resolver.js +69 -0
- package/dist/src/run-provisioning.d.ts +58 -0
- package/dist/src/run-provisioning.js +128 -0
- package/dist/src/runtime-context.d.ts +20 -0
- package/dist/src/runtime-context.js +257 -0
- package/dist/src/runtime-events.d.ts +44 -0
- package/dist/src/runtime-events.js +212 -0
- package/dist/src/runtime-overlay.d.ts +11 -0
- package/dist/src/runtime-overlay.js +71 -0
- package/dist/src/runtime-paths.d.ts +21 -0
- package/dist/src/runtime-paths.js +181 -0
- package/dist/src/runtime-provisioning-env.d.ts +5 -0
- package/dist/src/runtime-provisioning-env.js +217 -0
- package/dist/src/runtime-runner-context.d.ts +12 -0
- package/dist/src/runtime-runner-context.js +1 -0
- package/dist/src/safe-identifiers.d.ts +44 -0
- package/dist/src/safe-identifiers.js +96 -0
- package/dist/src/scope-rules.d.ts +4 -0
- package/dist/src/scope-rules.js +21 -0
- package/dist/src/server-paths.d.ts +26 -0
- package/dist/src/server-paths.js +308 -0
- package/dist/src/setup-version.d.ts +3 -0
- package/dist/src/setup-version.js +14 -0
- package/dist/src/task-record-reader.d.ts +3 -0
- package/dist/src/task-record-reader.js +9 -0
- package/dist/src/validator-registry.d.ts +27 -0
- package/dist/src/validator-registry.js +64 -0
- package/package.json +166 -10
- package/dist/src/engineReadModelReducer.js +0 -1780
- package/dist/src/rig-init-builder.js +0 -57
- package/dist/src/rigSelectors.js +0 -293
- package/dist/src/taskGraph.js +0 -64
- package/dist/src/taskGraphCodes.js +0 -26
- package/dist/src/taskGraphLayout.js +0 -374
|
@@ -0,0 +1,996 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/core/src/placement.ts
|
|
3
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
4
|
+
import { dirname as dirname4, resolve as resolve4 } from "path";
|
|
5
|
+
|
|
6
|
+
// packages/core/src/load-config.ts
|
|
7
|
+
import { existsSync as existsSync2, mkdirSync, mkdtempSync, readFileSync as readFileSync2, readdirSync, rmSync, statSync } from "fs";
|
|
8
|
+
import { isBuiltin } from "module";
|
|
9
|
+
import { dirname, isAbsolute, join as join2, relative, resolve } from "path";
|
|
10
|
+
import { pathToFileURL } from "url";
|
|
11
|
+
import { Schema as Schema3 } from "effect";
|
|
12
|
+
import { RigConfig as RigConfig3 } from "@rig/contracts";
|
|
13
|
+
|
|
14
|
+
// packages/core/src/define-config.ts
|
|
15
|
+
import { Schema } from "effect";
|
|
16
|
+
import { RigConfig } from "@rig/contracts";
|
|
17
|
+
function normalizeWorkspaceConfig(raw) {
|
|
18
|
+
const workspace = raw && typeof raw === "object" && !Array.isArray(raw) ? { ...raw } : {};
|
|
19
|
+
if (workspace.mainRepo === undefined)
|
|
20
|
+
workspace.mainRepo = ".";
|
|
21
|
+
if (workspace.checkout === undefined && workspace.isolation !== undefined)
|
|
22
|
+
workspace.checkout = workspace.isolation;
|
|
23
|
+
if (workspace.isolation === undefined && workspace.checkout !== undefined)
|
|
24
|
+
workspace.isolation = workspace.checkout;
|
|
25
|
+
return workspace;
|
|
26
|
+
}
|
|
27
|
+
function applyConfigDefaults(raw) {
|
|
28
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
29
|
+
return raw;
|
|
30
|
+
const record = raw;
|
|
31
|
+
return {
|
|
32
|
+
...record,
|
|
33
|
+
plugins: Array.isArray(record.plugins) ? record.plugins.flat() : [],
|
|
34
|
+
workspace: normalizeWorkspaceConfig(record.workspace)
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// packages/core/src/declarative-config.ts
|
|
39
|
+
import { existsSync, readFileSync } from "fs";
|
|
40
|
+
import { join } from "path";
|
|
41
|
+
import { parse as parseToml } from "smol-toml";
|
|
42
|
+
import { Schema as Schema2 } from "effect";
|
|
43
|
+
import { RigConfig as RigConfig2 } from "@rig/contracts";
|
|
44
|
+
|
|
45
|
+
// packages/core/src/embedded-plugins.ts
|
|
46
|
+
var registered = null;
|
|
47
|
+
function getStandardPluginsResolver() {
|
|
48
|
+
return registered;
|
|
49
|
+
}
|
|
50
|
+
var bakedProjectConfig = null;
|
|
51
|
+
function getEmbeddedProjectConfig() {
|
|
52
|
+
return bakedProjectConfig;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// packages/core/src/declarative-config.ts
|
|
56
|
+
var DECLARATIVE_CONFIG_NAMES = ["rigfig.toml", "rigfig.json"];
|
|
57
|
+
function findDeclarativeConfigPath(cwd) {
|
|
58
|
+
const dir = join(cwd, ".rig");
|
|
59
|
+
for (const name of DECLARATIVE_CONFIG_NAMES) {
|
|
60
|
+
const candidate = join(dir, name);
|
|
61
|
+
if (existsSync(candidate))
|
|
62
|
+
return candidate;
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
function parseDeclarativeFile(path) {
|
|
67
|
+
const raw = readFileSync(path, "utf8");
|
|
68
|
+
const parsed = path.endsWith(".json") ? JSON.parse(raw) : parseToml(raw);
|
|
69
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
70
|
+
throw new Error(`Declarative config ${path} must parse to an object.`);
|
|
71
|
+
}
|
|
72
|
+
return parsed;
|
|
73
|
+
}
|
|
74
|
+
function loadDeclarativeConfig(path) {
|
|
75
|
+
const data = parseDeclarativeFile(path);
|
|
76
|
+
const standardSection = data.standard && typeof data.standard === "object" && !Array.isArray(data.standard) ? data.standard : {};
|
|
77
|
+
const useStandard = standardSection.enabled !== false;
|
|
78
|
+
let plugins = [];
|
|
79
|
+
if (useStandard) {
|
|
80
|
+
const resolver = getStandardPluginsResolver();
|
|
81
|
+
if (!resolver) {
|
|
82
|
+
throw new Error(`Declarative config ${path} needs the embedded standard plugins, but none were registered. ` + `This is a seed/boot wiring error (the binary entrypoint must import the standard-plugin registration).`);
|
|
83
|
+
}
|
|
84
|
+
plugins = resolver(data);
|
|
85
|
+
}
|
|
86
|
+
const { standard: _standardDirective, ...configFields } = data;
|
|
87
|
+
const withDefaults = applyConfigDefaults({ ...configFields, plugins });
|
|
88
|
+
const explicitPlugins = Array.isArray(withDefaults.plugins) ? [...withDefaults.plugins] : [];
|
|
89
|
+
const decoded = Schema2.decodeUnknownSync(RigConfig2)({
|
|
90
|
+
...withDefaults,
|
|
91
|
+
plugins: explicitPlugins
|
|
92
|
+
});
|
|
93
|
+
return { ...decoded, plugins: explicitPlugins };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// packages/core/src/load-config.ts
|
|
97
|
+
var TS_NAMES = [".rig/rig.config.ts", ".rig/rig.config.mts"];
|
|
98
|
+
var JSON_NAMES = [".rig/rig.config.json"];
|
|
99
|
+
function isModuleResolutionError(error) {
|
|
100
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
101
|
+
return message.includes("Cannot find module") || message.includes("Could not resolve");
|
|
102
|
+
}
|
|
103
|
+
function runningFromCompiledBinary() {
|
|
104
|
+
return import.meta.url.includes("$bunfs");
|
|
105
|
+
}
|
|
106
|
+
function packageNameAndSubpath(specifier) {
|
|
107
|
+
if (specifier.startsWith(".") || specifier.startsWith("/") || /^[a-zA-Z]+:/.test(specifier))
|
|
108
|
+
return null;
|
|
109
|
+
const parts = specifier.split("/");
|
|
110
|
+
const packageName = specifier.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
|
|
111
|
+
if (!packageName)
|
|
112
|
+
return null;
|
|
113
|
+
const rest = parts.slice(specifier.startsWith("@") ? 2 : 1).join("/");
|
|
114
|
+
return { packageName, subpath: rest ? `./${rest}` : "." };
|
|
115
|
+
}
|
|
116
|
+
function exportTargetFromEntry(entry) {
|
|
117
|
+
if (typeof entry === "string")
|
|
118
|
+
return entry;
|
|
119
|
+
if (entry && typeof entry === "object" && !Array.isArray(entry)) {
|
|
120
|
+
const conditions = entry;
|
|
121
|
+
for (const key of ["bun", "import", "default", "require"]) {
|
|
122
|
+
if (typeof conditions[key] === "string")
|
|
123
|
+
return conditions[key];
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
function patternExportTarget(record, subpath) {
|
|
129
|
+
for (const [pattern, entry] of Object.entries(record)) {
|
|
130
|
+
if (!pattern.includes("*"))
|
|
131
|
+
continue;
|
|
132
|
+
const [prefix = "", suffix = ""] = pattern.split("*");
|
|
133
|
+
if (!subpath.startsWith(prefix) || !subpath.endsWith(suffix))
|
|
134
|
+
continue;
|
|
135
|
+
const replacement = subpath.slice(prefix.length, subpath.length - suffix.length);
|
|
136
|
+
const target = exportTargetFromEntry(entry);
|
|
137
|
+
if (target)
|
|
138
|
+
return target.replace("*", replacement);
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
function exportTargetFromPackageJson(pkg, subpath) {
|
|
143
|
+
const exportsField = pkg.exports;
|
|
144
|
+
const target = (() => {
|
|
145
|
+
if (typeof exportsField === "string" && subpath === ".")
|
|
146
|
+
return exportsField;
|
|
147
|
+
if (!exportsField || typeof exportsField !== "object" || Array.isArray(exportsField))
|
|
148
|
+
return null;
|
|
149
|
+
const record = exportsField;
|
|
150
|
+
return exportTargetFromEntry(record[subpath] ?? (subpath === "." ? record["."] : undefined)) ?? patternExportTarget(record, subpath);
|
|
151
|
+
})();
|
|
152
|
+
if (target)
|
|
153
|
+
return target;
|
|
154
|
+
return subpath === "." && typeof pkg.module === "string" ? pkg.module : subpath === "." && typeof pkg.main === "string" ? pkg.main : null;
|
|
155
|
+
}
|
|
156
|
+
function resolvePackageDirFromBunStore(packageName, nodeModulesDir) {
|
|
157
|
+
const storeDir = join2(nodeModulesDir, ".bun");
|
|
158
|
+
if (!existsSync2(storeDir))
|
|
159
|
+
return null;
|
|
160
|
+
const encoded = packageName.replace("/", "+");
|
|
161
|
+
try {
|
|
162
|
+
const candidates = readdirSync(storeDir).filter((entry) => entry.startsWith(`${encoded}@`)).map((entry) => {
|
|
163
|
+
const candidateDir = join2(storeDir, entry, "node_modules", packageName);
|
|
164
|
+
const packageJsonPath = join2(candidateDir, "package.json");
|
|
165
|
+
if (!existsSync2(packageJsonPath))
|
|
166
|
+
return null;
|
|
167
|
+
try {
|
|
168
|
+
const pkg = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
|
|
169
|
+
return {
|
|
170
|
+
dir: candidateDir,
|
|
171
|
+
sortKey: pkg.version?.trim() || entry
|
|
172
|
+
};
|
|
173
|
+
} catch {
|
|
174
|
+
return {
|
|
175
|
+
dir: candidateDir,
|
|
176
|
+
sortKey: entry
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}).filter((candidate) => candidate !== null).sort((a, b) => b.sortKey.localeCompare(a.sortKey, undefined, { numeric: true, sensitivity: "base" }));
|
|
180
|
+
return candidates[0]?.dir ?? null;
|
|
181
|
+
} catch {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function resolveDirectoryModulePath(directoryPath) {
|
|
186
|
+
const packageJsonPath = join2(directoryPath, "package.json");
|
|
187
|
+
if (existsSync2(packageJsonPath)) {
|
|
188
|
+
try {
|
|
189
|
+
const pkg = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
|
|
190
|
+
const target = exportTargetFromPackageJson(pkg, ".");
|
|
191
|
+
if (target) {
|
|
192
|
+
const resolved = resolveModulePath(join2(directoryPath, target));
|
|
193
|
+
if (resolved)
|
|
194
|
+
return resolved;
|
|
195
|
+
}
|
|
196
|
+
} catch {}
|
|
197
|
+
}
|
|
198
|
+
for (const candidate of ["index.js", "index.mjs", "index.cjs", "index.ts", "index.json"]) {
|
|
199
|
+
const resolved = resolveModulePath(join2(directoryPath, candidate));
|
|
200
|
+
if (resolved)
|
|
201
|
+
return resolved;
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
function resolveModulePath(candidatePath) {
|
|
206
|
+
if (!existsSync2(candidatePath)) {
|
|
207
|
+
for (const extension of [".ts", ".mts", ".tsx", ".js", ".mjs", ".cjs", ".json"]) {
|
|
208
|
+
const withExtension = `${candidatePath}${extension}`;
|
|
209
|
+
if (existsSync2(withExtension))
|
|
210
|
+
return resolveModulePath(withExtension);
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
try {
|
|
215
|
+
const stat = statSync(candidatePath);
|
|
216
|
+
if (stat.isFile())
|
|
217
|
+
return candidatePath;
|
|
218
|
+
if (stat.isDirectory())
|
|
219
|
+
return resolveDirectoryModulePath(candidatePath);
|
|
220
|
+
} catch {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
function resolvePackageExportFromDir(packageDir, subpath) {
|
|
226
|
+
const packageJsonPath = join2(packageDir, "package.json");
|
|
227
|
+
if (existsSync2(packageJsonPath)) {
|
|
228
|
+
try {
|
|
229
|
+
const pkg = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
|
|
230
|
+
const target = exportTargetFromPackageJson(pkg, subpath);
|
|
231
|
+
if (target) {
|
|
232
|
+
const resolved = resolveModulePath(join2(packageDir, target));
|
|
233
|
+
if (resolved)
|
|
234
|
+
return resolved;
|
|
235
|
+
}
|
|
236
|
+
} catch {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (subpath !== ".") {
|
|
241
|
+
const legacySubpath = subpath.replace(/^\.\//, "");
|
|
242
|
+
for (const candidate of [
|
|
243
|
+
join2(packageDir, legacySubpath),
|
|
244
|
+
join2(packageDir, `${legacySubpath}.js`),
|
|
245
|
+
join2(packageDir, `${legacySubpath}.mjs`),
|
|
246
|
+
join2(packageDir, `${legacySubpath}.cjs`),
|
|
247
|
+
join2(packageDir, `${legacySubpath}.ts`),
|
|
248
|
+
join2(packageDir, `${legacySubpath}.json`)
|
|
249
|
+
]) {
|
|
250
|
+
const resolved = resolveModulePath(candidate);
|
|
251
|
+
if (resolved)
|
|
252
|
+
return resolved;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return subpath === "." ? resolveDirectoryModulePath(packageDir) : null;
|
|
256
|
+
}
|
|
257
|
+
var runtimeBundleQueue = Promise.resolve();
|
|
258
|
+
function enqueueRuntimeBundle(operation) {
|
|
259
|
+
const next = runtimeBundleQueue.then(operation, operation);
|
|
260
|
+
runtimeBundleQueue = next.then(() => {
|
|
261
|
+
return;
|
|
262
|
+
}, () => {
|
|
263
|
+
return;
|
|
264
|
+
});
|
|
265
|
+
return next;
|
|
266
|
+
}
|
|
267
|
+
function isWithinDir(candidatePath, rootPath) {
|
|
268
|
+
const rel = relative(resolve(rootPath), resolve(candidatePath));
|
|
269
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
270
|
+
}
|
|
271
|
+
function resolvedFilePath(path, rootPath) {
|
|
272
|
+
if (!path || !isAbsolute(path))
|
|
273
|
+
return null;
|
|
274
|
+
const resolved = resolveModulePath(path);
|
|
275
|
+
if (!resolved)
|
|
276
|
+
return null;
|
|
277
|
+
return rootPath && !isWithinDir(resolved, rootPath) ? null : resolved;
|
|
278
|
+
}
|
|
279
|
+
function resolveProjectPackageImport(specifier, configDir) {
|
|
280
|
+
const parsed = packageNameAndSubpath(specifier);
|
|
281
|
+
if (!parsed)
|
|
282
|
+
return null;
|
|
283
|
+
const nodeModulesDir = join2(configDir, "node_modules");
|
|
284
|
+
const directPackageDir = join2(nodeModulesDir, parsed.packageName);
|
|
285
|
+
const packageDir = existsSync2(join2(directPackageDir, "package.json")) ? directPackageDir : resolvePackageDirFromBunStore(parsed.packageName, nodeModulesDir);
|
|
286
|
+
return packageDir ? resolvePackageExportFromDir(packageDir, parsed.subpath) : null;
|
|
287
|
+
}
|
|
288
|
+
function canImportRigWorkspacePackagesDirectly(source, configDir) {
|
|
289
|
+
const packageNames = new Set;
|
|
290
|
+
for (const match of source.matchAll(/(?:from\s*|import\s*\(\s*|import\s*)["'](@rig\/[^"']+)["']/g)) {
|
|
291
|
+
const parsed = packageNameAndSubpath(match[1] ?? "");
|
|
292
|
+
if (parsed?.packageName)
|
|
293
|
+
packageNames.add(parsed.packageName);
|
|
294
|
+
}
|
|
295
|
+
if (packageNames.size === 0)
|
|
296
|
+
return false;
|
|
297
|
+
for (const packageName of packageNames) {
|
|
298
|
+
const shortName = packageName.replace(/^@rig\//, "");
|
|
299
|
+
const manifestPath = join2(configDir, "packages", shortName, "package.json");
|
|
300
|
+
if (!existsSync2(manifestPath))
|
|
301
|
+
return false;
|
|
302
|
+
try {
|
|
303
|
+
const parsed = JSON.parse(readFileSync2(manifestPath, "utf8"));
|
|
304
|
+
if (parsed.name !== packageName)
|
|
305
|
+
return false;
|
|
306
|
+
} catch {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
async function importConfigViaRuntimeBundleUnserialized(configPath) {
|
|
313
|
+
const bun = globalThis.Bun;
|
|
314
|
+
if (!bun?.build) {
|
|
315
|
+
throw new Error(`Failed to import ${configPath}: bare imports could not be resolved and no Bun.build runtime bundler is available.`);
|
|
316
|
+
}
|
|
317
|
+
const RUNTIME_ONLY_EXTERNAL_PACKAGES = new Set(["effect", "mupdf", "fastembed", "onnxruntime-node", "markit-ai"]);
|
|
318
|
+
const configDir = dirname(configPath);
|
|
319
|
+
const UNRESOLVED_NAMESPACE = "rig-config-unresolved";
|
|
320
|
+
const unresolvedLocalPlugin = {
|
|
321
|
+
name: "rig-config-unresolved-local",
|
|
322
|
+
setup(build) {
|
|
323
|
+
build.onLoad({ filter: /\.(?:html|txt)$/ }, (args) => ({
|
|
324
|
+
loader: "js",
|
|
325
|
+
contents: `export default ${JSON.stringify(readFileSync2(args.path, "utf8"))};
|
|
326
|
+
`
|
|
327
|
+
}));
|
|
328
|
+
build.onResolve({ filter: /.*/ }, (args) => {
|
|
329
|
+
const directFilePath = resolvedFilePath(args.path, configDir);
|
|
330
|
+
if (directFilePath)
|
|
331
|
+
return { path: directFilePath };
|
|
332
|
+
const packageImport = packageNameAndSubpath(args.path);
|
|
333
|
+
if (packageImport && (packageImport.packageName.startsWith("@rig/") || RUNTIME_ONLY_EXTERNAL_PACKAGES.has(packageImport.packageName))) {
|
|
334
|
+
return { path: args.path, external: true };
|
|
335
|
+
}
|
|
336
|
+
const projectPackagePath = resolveProjectPackageImport(args.path, configDir);
|
|
337
|
+
if (projectPackagePath)
|
|
338
|
+
return { path: projectPackagePath };
|
|
339
|
+
if (/^(?:node|bun):/.test(args.path) || isBuiltin(args.path))
|
|
340
|
+
return;
|
|
341
|
+
if (packageImport)
|
|
342
|
+
return { path: args.path, external: true };
|
|
343
|
+
const parentCandidates = args.path.startsWith(".") ? [args.importer && isAbsolute(args.importer) ? dirname(args.importer) : null, configDir].filter((value) => Boolean(value)) : [args.importer && isAbsolute(args.importer) ? dirname(args.importer) : configDir];
|
|
344
|
+
for (const parent2 of parentCandidates) {
|
|
345
|
+
const filePath = resolvedFilePath(resolve(parent2, args.path), configDir);
|
|
346
|
+
if (filePath)
|
|
347
|
+
return { path: filePath };
|
|
348
|
+
}
|
|
349
|
+
const parent = parentCandidates[0] ?? configDir;
|
|
350
|
+
try {
|
|
351
|
+
const resolved = bun.resolveSync?.(args.path, parent) ?? resolve(parent, args.path);
|
|
352
|
+
const filePath = resolvedFilePath(resolved, configDir);
|
|
353
|
+
if (filePath)
|
|
354
|
+
return { path: filePath };
|
|
355
|
+
} catch {}
|
|
356
|
+
return { path: args.path, namespace: UNRESOLVED_NAMESPACE };
|
|
357
|
+
});
|
|
358
|
+
build.onLoad({ filter: /.*/, namespace: UNRESOLVED_NAMESPACE }, (args) => ({
|
|
359
|
+
loader: "js",
|
|
360
|
+
contents: `module.exports = {};
|
|
361
|
+
throw new Error(${JSON.stringify(`Failed to bundle ${configPath}: Could not resolve local import "${args.path}". Maybe you need to fix a relative import in rig.config.ts or install project deps.`)});
|
|
362
|
+
`
|
|
363
|
+
}));
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
const result = await bun.build({
|
|
367
|
+
entrypoints: [configPath],
|
|
368
|
+
target: "bun",
|
|
369
|
+
external: ["effect", "mupdf", "fastembed", "onnxruntime-node", "markit-ai"],
|
|
370
|
+
format: "esm",
|
|
371
|
+
throw: false,
|
|
372
|
+
packages: "bundle",
|
|
373
|
+
plugins: [unresolvedLocalPlugin]
|
|
374
|
+
});
|
|
375
|
+
if (!result.success || !result.outputs[0]) {
|
|
376
|
+
const detail = result.logs.map((log) => String(log)).join(`
|
|
377
|
+
`);
|
|
378
|
+
throw new Error(`Failed to bundle ${configPath}: ${detail || "unknown bundler error"}`);
|
|
379
|
+
}
|
|
380
|
+
const bundleParentDir = join2(configDir, ".rig", "tmp");
|
|
381
|
+
mkdirSync(bundleParentDir, { recursive: true });
|
|
382
|
+
const dir = mkdtempSync(join2(bundleParentDir, "rig-config-bundle-"));
|
|
383
|
+
try {
|
|
384
|
+
const bundledPath = join2(dir, "rig.config.bundled.js");
|
|
385
|
+
await bun.write(bundledPath, await result.outputs[0].text());
|
|
386
|
+
return await import(pathToFileURL(bundledPath).href);
|
|
387
|
+
} finally {
|
|
388
|
+
try {
|
|
389
|
+
rmSync(dir, { recursive: true, force: true });
|
|
390
|
+
} catch {}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
async function loadConfig(cwd) {
|
|
394
|
+
const baked = getEmbeddedProjectConfig();
|
|
395
|
+
if (baked && resolve(baked.projectRoot) === resolve(cwd)) {
|
|
396
|
+
return decodeExplicitPluginConfig(baked.raw);
|
|
397
|
+
}
|
|
398
|
+
for (const name of TS_NAMES) {
|
|
399
|
+
const p = join2(cwd, name);
|
|
400
|
+
if (existsSync2(p)) {
|
|
401
|
+
const mod = await enqueueRuntimeBundle(async () => {
|
|
402
|
+
if (runningFromCompiledBinary()) {
|
|
403
|
+
return importConfigViaRuntimeBundleUnserialized(p);
|
|
404
|
+
}
|
|
405
|
+
const source = readFileSync2(p, "utf8");
|
|
406
|
+
const importsRigHostPackages = /(?:import\s+[^;]*?from\s*|import\s*\()\s*["']@rig\//.test(source);
|
|
407
|
+
if (importsRigHostPackages && !canImportRigWorkspacePackagesDirectly(source, cwd)) {
|
|
408
|
+
return importConfigViaRuntimeBundleUnserialized(p);
|
|
409
|
+
}
|
|
410
|
+
try {
|
|
411
|
+
return await import(pathToFileURL(p).href);
|
|
412
|
+
} catch (error) {
|
|
413
|
+
if (!isModuleResolutionError(error))
|
|
414
|
+
throw error;
|
|
415
|
+
return importConfigViaRuntimeBundleUnserialized(p);
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
const raw = mod.default ?? mod.config;
|
|
419
|
+
return decodeExplicitPluginConfig(raw);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
const declarativePath = findDeclarativeConfigPath(cwd);
|
|
423
|
+
if (declarativePath) {
|
|
424
|
+
return loadDeclarativeConfig(declarativePath);
|
|
425
|
+
}
|
|
426
|
+
for (const name of JSON_NAMES) {
|
|
427
|
+
const p = join2(cwd, name);
|
|
428
|
+
if (existsSync2(p)) {
|
|
429
|
+
const raw = JSON.parse(readFileSync2(p, "utf-8"));
|
|
430
|
+
return decodeExplicitPluginConfig(raw);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
throw new Error(`no .rig/rig.config.{ts,mts,json} or .rig/rigfig.{toml,json} found in ${cwd}`);
|
|
434
|
+
}
|
|
435
|
+
function decodeExplicitPluginConfig(raw) {
|
|
436
|
+
const withDefaults = applyConfigDefaults(raw);
|
|
437
|
+
const explicitPlugins = Array.isArray(withDefaults.plugins) ? [...withDefaults.plugins] : [];
|
|
438
|
+
const decoded = Schema3.decodeUnknownSync(RigConfig3)({
|
|
439
|
+
...withDefaults,
|
|
440
|
+
plugins: explicitPlugins
|
|
441
|
+
});
|
|
442
|
+
return { ...decoded, plugins: explicitPlugins };
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// packages/core/src/remote-config.ts
|
|
446
|
+
import { randomUUID } from "crypto";
|
|
447
|
+
import { chmodSync, existsSync as existsSync4, mkdirSync as mkdirSync2, mkdtempSync as mkdtempSync2, readFileSync as readFileSync3, writeFileSync } from "fs";
|
|
448
|
+
import { homedir, tmpdir } from "os";
|
|
449
|
+
import { dirname as dirname3, join as join3, resolve as resolve3 } from "path";
|
|
450
|
+
import { parse as parseToml2, stringify as stringifyToml } from "smol-toml";
|
|
451
|
+
|
|
452
|
+
// packages/core/src/authority-paths.ts
|
|
453
|
+
import { existsSync as existsSync3 } from "fs";
|
|
454
|
+
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
455
|
+
function normalizeOptionalString(value) {
|
|
456
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
457
|
+
}
|
|
458
|
+
function resolveAuthorityPaths(projectRoot) {
|
|
459
|
+
const normalizedRoot = resolve2(projectRoot);
|
|
460
|
+
const stateRoot = resolveAuthorityStateRoot(normalizedRoot);
|
|
461
|
+
const stateDir = resolveAuthorityStateDir(normalizedRoot);
|
|
462
|
+
return {
|
|
463
|
+
projectRoot: normalizedRoot,
|
|
464
|
+
harnessRoot: resolve2(normalizedRoot, "rig"),
|
|
465
|
+
runsDir: resolve2(stateRoot, "runs"),
|
|
466
|
+
remoteDir: resolve2(stateRoot, "remote"),
|
|
467
|
+
stateDir,
|
|
468
|
+
remoteEndpointsPath: resolve2(stateRoot, "remote", "endpoints.toml"),
|
|
469
|
+
remoteSecretsPath: resolve2(stateDir, "remote-secrets.toml")
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
function resolveAuthorityStateRoot(projectRoot) {
|
|
473
|
+
const normalizedRoot = resolve2(projectRoot);
|
|
474
|
+
const taskWorkspace = normalizeOptionalString(process.env.RIG_TASK_WORKSPACE);
|
|
475
|
+
if (taskWorkspace) {
|
|
476
|
+
return resolve2(taskWorkspace, ".rig");
|
|
477
|
+
}
|
|
478
|
+
const stateDir = normalizeOptionalString(process.env.RIG_STATE_DIR);
|
|
479
|
+
if (stateDir) {
|
|
480
|
+
return dirname2(resolve2(stateDir));
|
|
481
|
+
}
|
|
482
|
+
const logsDir = normalizeOptionalString(process.env.RIG_LOGS_DIR);
|
|
483
|
+
if (logsDir) {
|
|
484
|
+
return dirname2(resolve2(logsDir));
|
|
485
|
+
}
|
|
486
|
+
const sessionFile = normalizeOptionalString(process.env.RIG_SESSION_FILE);
|
|
487
|
+
if (sessionFile) {
|
|
488
|
+
return dirname2(dirname2(resolve2(sessionFile)));
|
|
489
|
+
}
|
|
490
|
+
const projectStateRoot = resolve2(normalizedRoot, ".rig");
|
|
491
|
+
if (existsSync3(projectStateRoot)) {
|
|
492
|
+
return projectStateRoot;
|
|
493
|
+
}
|
|
494
|
+
return resolve2(normalizedRoot, ".rig");
|
|
495
|
+
}
|
|
496
|
+
function resolveAuthorityStateDir(projectRoot) {
|
|
497
|
+
const explicit = normalizeOptionalString(process.env.RIG_STATE_DIR);
|
|
498
|
+
if (explicit) {
|
|
499
|
+
return resolve2(explicit);
|
|
500
|
+
}
|
|
501
|
+
return resolve2(resolveAuthorityStateRoot(projectRoot), "state");
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// packages/core/src/remote-config.ts
|
|
505
|
+
var DEFAULT_REMOTE_PORT = 7890;
|
|
506
|
+
var BACKBONE_DEFAULTS_KEY = Symbol.for("rig.remote-config.backbone-defaults");
|
|
507
|
+
function backboneDefaultsState() {
|
|
508
|
+
const global = globalThis;
|
|
509
|
+
return global[BACKBONE_DEFAULTS_KEY] ??= {};
|
|
510
|
+
}
|
|
511
|
+
function resolveSshTarget(env = process.env) {
|
|
512
|
+
return normalizeString(env.RIG_SSH_TARGET) || backboneDefaultsState().sshTarget || "";
|
|
513
|
+
}
|
|
514
|
+
var REMOTES_CONFIG_PATH = join3(homedir(), ".config", "rig", "remotes.toml");
|
|
515
|
+
|
|
516
|
+
class RemoteCliError extends Error {
|
|
517
|
+
code;
|
|
518
|
+
exitCode;
|
|
519
|
+
details;
|
|
520
|
+
constructor(code, message, exitCode = 1, details) {
|
|
521
|
+
super(message);
|
|
522
|
+
this.name = "RemoteCliError";
|
|
523
|
+
this.code = code;
|
|
524
|
+
this.exitCode = exitCode;
|
|
525
|
+
this.details = details;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
function loadRemotesConfig(configPath = REMOTES_CONFIG_PATH) {
|
|
529
|
+
if (!existsSync4(configPath)) {
|
|
530
|
+
return { version: 1, remotes: {} };
|
|
531
|
+
}
|
|
532
|
+
try {
|
|
533
|
+
const content = readFileSync3(configPath, "utf-8");
|
|
534
|
+
if (!content.trim()) {
|
|
535
|
+
return { version: 1, remotes: {} };
|
|
536
|
+
}
|
|
537
|
+
const parsed = parseToml2(content);
|
|
538
|
+
return {
|
|
539
|
+
version: parsed.version ?? 1,
|
|
540
|
+
remotes: parsed.remotes ?? {}
|
|
541
|
+
};
|
|
542
|
+
} catch (error) {
|
|
543
|
+
throw new RemoteCliError("RIG_REMOTE_CONFIG_PARSE_ERROR", `Failed to parse remotes config at ${configPath}: ${error instanceof Error ? error.message : String(error)}`, 2, { configPath });
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
function saveRemotesConfig(config, configPath = REMOTES_CONFIG_PATH) {
|
|
547
|
+
mkdirSync2(dirname3(configPath), { recursive: true });
|
|
548
|
+
writeFileSync(configPath, `${stringifyToml(config).trimEnd()}
|
|
549
|
+
`, "utf-8");
|
|
550
|
+
try {
|
|
551
|
+
chmodSync(configPath, 384);
|
|
552
|
+
} catch {}
|
|
553
|
+
}
|
|
554
|
+
function readTomlFile(path, fallback) {
|
|
555
|
+
if (!existsSync4(path))
|
|
556
|
+
return fallback;
|
|
557
|
+
const raw = readFileSync3(path, "utf8");
|
|
558
|
+
if (!raw.trim())
|
|
559
|
+
return fallback;
|
|
560
|
+
return parseToml2(raw);
|
|
561
|
+
}
|
|
562
|
+
function writeTomlFile(path, value) {
|
|
563
|
+
mkdirSync2(dirname3(path), { recursive: true });
|
|
564
|
+
writeFileSync(path, `${stringifyToml(value).trimEnd()}
|
|
565
|
+
`, "utf8");
|
|
566
|
+
}
|
|
567
|
+
function normalizeStringArray(value) {
|
|
568
|
+
if (!Array.isArray(value))
|
|
569
|
+
return [];
|
|
570
|
+
return value.map((entry) => normalizeString(entry)).filter((entry) => entry !== "");
|
|
571
|
+
}
|
|
572
|
+
function normalizePort(value) {
|
|
573
|
+
const port = typeof value === "number" ? value : Number(value);
|
|
574
|
+
return Number.isInteger(port) && port > 0 && port <= 65535 ? port : DEFAULT_REMOTE_PORT;
|
|
575
|
+
}
|
|
576
|
+
function normalizeRegistryBaseUrl(raw) {
|
|
577
|
+
const trimmed = raw.replace(/\/+$/, "");
|
|
578
|
+
if (!trimmed)
|
|
579
|
+
return trimmed;
|
|
580
|
+
return /\/registry$/.test(trimmed) ? trimmed : `${trimmed}/registry`;
|
|
581
|
+
}
|
|
582
|
+
function loadRemoteEndpointsToml(projectRoot) {
|
|
583
|
+
const paths = resolveAuthorityPaths(projectRoot);
|
|
584
|
+
const parsed = readTomlFile(paths.remoteEndpointsPath, { version: 1, endpoints: {} });
|
|
585
|
+
return {
|
|
586
|
+
version: parsed.version ?? 1,
|
|
587
|
+
endpoints: parsed.endpoints ?? {}
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
function loadRemoteSecretsToml(projectRoot) {
|
|
591
|
+
const paths = resolveAuthorityPaths(projectRoot);
|
|
592
|
+
const parsed = readTomlFile(paths.remoteSecretsPath, { version: 1, secrets: {} });
|
|
593
|
+
return {
|
|
594
|
+
version: parsed.version ?? 1,
|
|
595
|
+
secrets: parsed.secrets ?? {}
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
function readJsonRecordFile(path) {
|
|
599
|
+
try {
|
|
600
|
+
if (!existsSync4(path))
|
|
601
|
+
return {};
|
|
602
|
+
const raw = readFileSync3(path, "utf8");
|
|
603
|
+
if (!raw.trim())
|
|
604
|
+
return {};
|
|
605
|
+
const parsed = JSON.parse(raw);
|
|
606
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
607
|
+
} catch {
|
|
608
|
+
return {};
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
function coerceString(value) {
|
|
612
|
+
return typeof value === "string" ? value.trim() : "";
|
|
613
|
+
}
|
|
614
|
+
function forceLocalTransport(env) {
|
|
615
|
+
return env.RIG_FORCE_LOCAL === "1" || env.RIG_FORCE_LOCAL === "true";
|
|
616
|
+
}
|
|
617
|
+
function resolveDispatchTransportPlacement(projectRoot, env = process.env) {
|
|
618
|
+
if (forceLocalTransport(env)) {
|
|
619
|
+
return { kind: "local", alias: "local", sshTarget: null, selected: null };
|
|
620
|
+
}
|
|
621
|
+
const stateDir = resolveAuthorityPaths(projectRoot).stateDir;
|
|
622
|
+
const conn = readJsonRecordFile(resolve3(stateDir, "connection.json"));
|
|
623
|
+
const selectedAlias = normalizeString(env.RIG_REMOTE_ALIAS) || coerceString(conn.selected);
|
|
624
|
+
if (selectedAlias === "local") {
|
|
625
|
+
return { kind: "local", alias: "local", sshTarget: null, selected: null };
|
|
626
|
+
}
|
|
627
|
+
const selected = resolveSelectedRemote(projectRoot, env);
|
|
628
|
+
const sshTarget = selected?.sshTarget ?? resolveSshTarget(env);
|
|
629
|
+
if (!sshTarget) {
|
|
630
|
+
return { kind: "local", alias: "local", sshTarget: null, selected: null };
|
|
631
|
+
}
|
|
632
|
+
return { kind: "remote", alias: selected?.alias ?? sshTarget, sshTarget, selected };
|
|
633
|
+
}
|
|
634
|
+
function resolveSelectedRemote(projectRoot, env = process.env) {
|
|
635
|
+
const stateDir = resolveAuthorityPaths(projectRoot).stateDir;
|
|
636
|
+
const conn = readJsonRecordFile(resolve3(stateDir, "connection.json"));
|
|
637
|
+
const selected = normalizeString(env.RIG_REMOTE_ALIAS) || coerceString(conn.selected);
|
|
638
|
+
if (!selected || selected === "local")
|
|
639
|
+
return null;
|
|
640
|
+
const endpoints = Object.values(loadRemoteEndpointsToml(projectRoot).endpoints ?? {});
|
|
641
|
+
const match = endpoints.find((entry) => normalizeString(entry.alias) === selected);
|
|
642
|
+
if (!match) {
|
|
643
|
+
if (selected === "remote") {
|
|
644
|
+
const sshTarget = resolveSshTarget(env);
|
|
645
|
+
if (!sshTarget)
|
|
646
|
+
return null;
|
|
647
|
+
return {
|
|
648
|
+
alias: "remote",
|
|
649
|
+
host: sshTarget,
|
|
650
|
+
port: 22,
|
|
651
|
+
sshTarget,
|
|
652
|
+
checkout: coerceString(conn.serverProjectRoot) || null,
|
|
653
|
+
registryBaseUrl: null,
|
|
654
|
+
secretRef: null
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
return null;
|
|
658
|
+
}
|
|
659
|
+
const host = normalizeString(match.host) || selected;
|
|
660
|
+
const explicitRegistryUrl = normalizeString(env.RIG_REGISTRY_URL) || normalizeString(env.REGISTRY_URL);
|
|
661
|
+
const registryBaseUrl = explicitRegistryUrl ? normalizeRegistryBaseUrl(explicitRegistryUrl) : null;
|
|
662
|
+
return {
|
|
663
|
+
alias: selected,
|
|
664
|
+
host,
|
|
665
|
+
port: normalizePort(match.port),
|
|
666
|
+
sshTarget: host || normalizeString(match.alias) || coerceString(conn.serverProjectRootAlias),
|
|
667
|
+
checkout: coerceString(conn.serverProjectRoot) || null,
|
|
668
|
+
registryBaseUrl,
|
|
669
|
+
secretRef: normalizeString(match.secret_ref) || null
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
function saveRemoteEndpointsToml(projectRoot, payload) {
|
|
673
|
+
writeTomlFile(resolveAuthorityPaths(projectRoot).remoteEndpointsPath, payload);
|
|
674
|
+
}
|
|
675
|
+
function saveRemoteSecretsToml(projectRoot, payload) {
|
|
676
|
+
const paths = resolveAuthorityPaths(projectRoot);
|
|
677
|
+
writeTomlFile(paths.remoteSecretsPath, payload);
|
|
678
|
+
try {
|
|
679
|
+
chmodSync(paths.remoteSecretsPath, 384);
|
|
680
|
+
} catch {}
|
|
681
|
+
}
|
|
682
|
+
function listAuthorityRemoteEndpoints(projectRoot) {
|
|
683
|
+
const endpoints = loadRemoteEndpointsToml(projectRoot).endpoints ?? {};
|
|
684
|
+
const secrets = loadRemoteSecretsToml(projectRoot).secrets ?? {};
|
|
685
|
+
return Object.values(endpoints).map((entry) => {
|
|
686
|
+
const token = secrets[entry.secret_ref] ?? "";
|
|
687
|
+
return {
|
|
688
|
+
id: entry.id,
|
|
689
|
+
alias: entry.alias,
|
|
690
|
+
host: entry.host,
|
|
691
|
+
port: normalizePort(entry.port),
|
|
692
|
+
token,
|
|
693
|
+
autoConnect: Boolean(entry.auto_connect),
|
|
694
|
+
addedAt: entry.created_at,
|
|
695
|
+
updatedAt: entry.updated_at,
|
|
696
|
+
lastConnectedAt: normalizeString(entry.last_connected_at) || null,
|
|
697
|
+
labels: normalizeStringArray(entry.labels),
|
|
698
|
+
capabilities: normalizeStringArray(entry.capabilities),
|
|
699
|
+
transport: normalizeString(entry.transport) || "websocket",
|
|
700
|
+
secretRef: entry.secret_ref
|
|
701
|
+
};
|
|
702
|
+
}).sort((left, right) => left.alias.localeCompare(right.alias));
|
|
703
|
+
}
|
|
704
|
+
function nextRemoteEndpointRecord(input) {
|
|
705
|
+
const timestamp = new Date().toISOString();
|
|
706
|
+
const secretRef = input.existing?.secret_ref ?? randomUUID();
|
|
707
|
+
return {
|
|
708
|
+
record: {
|
|
709
|
+
id: input.endpointId ?? input.existing?.id ?? randomUUID(),
|
|
710
|
+
alias: input.alias,
|
|
711
|
+
host: input.host,
|
|
712
|
+
port: normalizePort(input.port),
|
|
713
|
+
transport: normalizeString(input.transport) || normalizeString(input.existing?.transport) || "websocket",
|
|
714
|
+
auto_connect: input.autoConnect ?? input.existing?.auto_connect ?? false,
|
|
715
|
+
labels: input.labels ?? normalizeStringArray(input.existing?.labels),
|
|
716
|
+
capabilities: input.capabilities ?? normalizeStringArray(input.existing?.capabilities),
|
|
717
|
+
secret_ref: secretRef,
|
|
718
|
+
created_at: input.existing?.created_at ?? timestamp,
|
|
719
|
+
updated_at: timestamp,
|
|
720
|
+
last_connected_at: input.existing?.last_connected_at ?? null
|
|
721
|
+
},
|
|
722
|
+
secretRef
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
function upsertAuthorityRemoteEndpoint(projectRoot, input) {
|
|
726
|
+
const endpointsToml = loadRemoteEndpointsToml(projectRoot);
|
|
727
|
+
const secretsToml = loadRemoteSecretsToml(projectRoot);
|
|
728
|
+
const existing = Object.values(endpointsToml.endpoints ?? {}).find((entry) => entry.alias === input.alias) ?? null;
|
|
729
|
+
const { record, secretRef } = nextRemoteEndpointRecord({
|
|
730
|
+
existing,
|
|
731
|
+
alias: input.alias,
|
|
732
|
+
host: input.host,
|
|
733
|
+
port: input.port,
|
|
734
|
+
token: input.token,
|
|
735
|
+
...input.endpointId !== undefined ? { endpointId: input.endpointId } : {},
|
|
736
|
+
...input.autoConnect !== undefined ? { autoConnect: input.autoConnect } : {},
|
|
737
|
+
...input.transport !== undefined ? { transport: input.transport } : {},
|
|
738
|
+
...input.labels !== undefined ? { labels: input.labels } : {},
|
|
739
|
+
...input.capabilities !== undefined ? { capabilities: input.capabilities } : {}
|
|
740
|
+
});
|
|
741
|
+
endpointsToml.endpoints = {
|
|
742
|
+
...endpointsToml.endpoints ?? {},
|
|
743
|
+
[record.id]: record
|
|
744
|
+
};
|
|
745
|
+
secretsToml.secrets = {
|
|
746
|
+
...secretsToml.secrets ?? {},
|
|
747
|
+
[secretRef]: input.token
|
|
748
|
+
};
|
|
749
|
+
saveRemoteEndpointsToml(projectRoot, endpointsToml);
|
|
750
|
+
saveRemoteSecretsToml(projectRoot, secretsToml);
|
|
751
|
+
return listAuthorityRemoteEndpoints(projectRoot).find((entry) => entry.id === record.id);
|
|
752
|
+
}
|
|
753
|
+
function removeAuthorityRemoteEndpoint(projectRoot, endpointIdOrAlias) {
|
|
754
|
+
const endpointsToml = loadRemoteEndpointsToml(projectRoot);
|
|
755
|
+
const secretsToml = loadRemoteSecretsToml(projectRoot);
|
|
756
|
+
const entry = Object.values(endpointsToml.endpoints ?? {}).find((candidate) => candidate.id === endpointIdOrAlias || candidate.alias === endpointIdOrAlias);
|
|
757
|
+
if (!entry)
|
|
758
|
+
return false;
|
|
759
|
+
const nextEndpoints = { ...endpointsToml.endpoints ?? {} };
|
|
760
|
+
delete nextEndpoints[entry.id];
|
|
761
|
+
const nextSecrets = { ...secretsToml.secrets ?? {} };
|
|
762
|
+
delete nextSecrets[entry.secret_ref];
|
|
763
|
+
saveRemoteEndpointsToml(projectRoot, { version: endpointsToml.version ?? 1, endpoints: nextEndpoints });
|
|
764
|
+
saveRemoteSecretsToml(projectRoot, { version: secretsToml.version ?? 1, secrets: nextSecrets });
|
|
765
|
+
return true;
|
|
766
|
+
}
|
|
767
|
+
function listManagedRemoteEndpoints(configPath = REMOTES_CONFIG_PATH, projectRoot) {
|
|
768
|
+
if (projectRoot) {
|
|
769
|
+
return listAuthorityRemoteEndpoints(projectRoot).map((entry) => ({
|
|
770
|
+
id: entry.id,
|
|
771
|
+
alias: entry.alias,
|
|
772
|
+
host: entry.host,
|
|
773
|
+
port: entry.port,
|
|
774
|
+
token: entry.token,
|
|
775
|
+
addedAt: entry.addedAt,
|
|
776
|
+
lastConnected: entry.lastConnectedAt
|
|
777
|
+
}));
|
|
778
|
+
}
|
|
779
|
+
const config = loadRemotesConfig(configPath);
|
|
780
|
+
return Object.entries(config.remotes ?? {}).map(([alias, entry]) => ({
|
|
781
|
+
id: alias,
|
|
782
|
+
alias,
|
|
783
|
+
host: normalizeString(entry.host) || "",
|
|
784
|
+
port: Number.isFinite(entry.port) ? Number(entry.port) : DEFAULT_REMOTE_PORT,
|
|
785
|
+
token: normalizeString(entry.token) || "",
|
|
786
|
+
addedAt: normalizeString(entry.addedAt) || null,
|
|
787
|
+
lastConnected: normalizeString(entry.lastConnected) || null
|
|
788
|
+
})).sort((left, right) => left.alias.localeCompare(right.alias));
|
|
789
|
+
}
|
|
790
|
+
function upsertManagedRemoteEndpoint(input, configPath = REMOTES_CONFIG_PATH, projectRoot) {
|
|
791
|
+
if (projectRoot) {
|
|
792
|
+
const saved = upsertAuthorityRemoteEndpoint(projectRoot, {
|
|
793
|
+
...input,
|
|
794
|
+
token: input.token ?? ""
|
|
795
|
+
});
|
|
796
|
+
return {
|
|
797
|
+
id: saved.id,
|
|
798
|
+
alias: saved.alias,
|
|
799
|
+
host: saved.host,
|
|
800
|
+
port: saved.port,
|
|
801
|
+
token: saved.token,
|
|
802
|
+
addedAt: saved.addedAt,
|
|
803
|
+
lastConnected: saved.lastConnectedAt
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
const config = loadRemotesConfig(configPath);
|
|
807
|
+
const existing = config.remotes?.[input.alias];
|
|
808
|
+
const nextEntry = {
|
|
809
|
+
host: input.host,
|
|
810
|
+
port: input.port,
|
|
811
|
+
...input.token !== undefined ? { token: input.token } : {},
|
|
812
|
+
addedAt: normalizeString(existing?.addedAt) || new Date().toISOString(),
|
|
813
|
+
...normalizeString(existing?.lastConnected) ? { lastConnected: normalizeString(existing?.lastConnected) } : {}
|
|
814
|
+
};
|
|
815
|
+
const nextConfig = {
|
|
816
|
+
version: config.version ?? 1,
|
|
817
|
+
remotes: {
|
|
818
|
+
...config.remotes ?? {},
|
|
819
|
+
[input.alias]: nextEntry
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
saveRemotesConfig(nextConfig, configPath);
|
|
823
|
+
return {
|
|
824
|
+
id: input.alias,
|
|
825
|
+
alias: input.alias,
|
|
826
|
+
host: input.host,
|
|
827
|
+
port: input.port,
|
|
828
|
+
token: input.token ?? "",
|
|
829
|
+
addedAt: nextEntry.addedAt ?? null,
|
|
830
|
+
lastConnected: nextEntry.lastConnected ?? null
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
function removeManagedRemoteEndpoint(alias, configPath = REMOTES_CONFIG_PATH, projectRoot) {
|
|
834
|
+
if (projectRoot) {
|
|
835
|
+
return removeAuthorityRemoteEndpoint(projectRoot, alias);
|
|
836
|
+
}
|
|
837
|
+
const config = loadRemotesConfig(configPath);
|
|
838
|
+
if (!config.remotes?.[alias]) {
|
|
839
|
+
return false;
|
|
840
|
+
}
|
|
841
|
+
const nextRemotes = { ...config.remotes ?? {} };
|
|
842
|
+
delete nextRemotes[alias];
|
|
843
|
+
saveRemotesConfig({
|
|
844
|
+
version: config.version ?? 1,
|
|
845
|
+
remotes: nextRemotes
|
|
846
|
+
}, configPath);
|
|
847
|
+
return true;
|
|
848
|
+
}
|
|
849
|
+
function normalizeString(value) {
|
|
850
|
+
if (!value) {
|
|
851
|
+
return "";
|
|
852
|
+
}
|
|
853
|
+
return value.trim();
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// packages/core/src/placement.ts
|
|
857
|
+
var DEFAULT_REMOTE_PORT2 = 22;
|
|
858
|
+
function resolveRepoConnectionPath(projectRoot) {
|
|
859
|
+
return resolve4(projectRoot, ".rig", "state", "connection.json");
|
|
860
|
+
}
|
|
861
|
+
function readJsonFile(path) {
|
|
862
|
+
if (!existsSync5(path))
|
|
863
|
+
return null;
|
|
864
|
+
try {
|
|
865
|
+
return JSON.parse(readFileSync4(path, "utf8"));
|
|
866
|
+
} catch (error) {
|
|
867
|
+
throw new Error(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
function writeJsonFile(path, value) {
|
|
871
|
+
mkdirSync3(dirname4(path), { recursive: true });
|
|
872
|
+
writeFileSync2(path, `${JSON.stringify(value, null, 2)}
|
|
873
|
+
`, "utf8");
|
|
874
|
+
}
|
|
875
|
+
function readSelection(projectRoot) {
|
|
876
|
+
const payload = readJsonFile(resolveRepoConnectionPath(projectRoot));
|
|
877
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
878
|
+
return null;
|
|
879
|
+
const record = payload;
|
|
880
|
+
const selected = typeof record.selected === "string" ? record.selected.trim() : "";
|
|
881
|
+
if (!selected)
|
|
882
|
+
return null;
|
|
883
|
+
const serverProjectRoot = typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined;
|
|
884
|
+
const serverProjectRootAlias = typeof record.serverProjectRootAlias === "string" && record.serverProjectRootAlias.trim() ? record.serverProjectRootAlias.trim() : undefined;
|
|
885
|
+
const serverProjectRootBaseUrl = typeof record.serverProjectRootBaseUrl === "string" && record.serverProjectRootBaseUrl.trim() ? record.serverProjectRootBaseUrl.trim().replace(/\/+$/, "") : undefined;
|
|
886
|
+
return {
|
|
887
|
+
selected,
|
|
888
|
+
...typeof record.project === "string" ? { project: record.project } : {},
|
|
889
|
+
...typeof record.linkedAt === "string" ? { linkedAt: record.linkedAt } : {},
|
|
890
|
+
...serverProjectRoot !== undefined ? { serverProjectRoot } : {},
|
|
891
|
+
...serverProjectRootAlias !== undefined ? { serverProjectRootAlias } : {},
|
|
892
|
+
...serverProjectRootBaseUrl !== undefined ? { serverProjectRootBaseUrl } : {}
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
var readRepoConnection = readSelection;
|
|
896
|
+
function writeSelection(projectRoot, state) {
|
|
897
|
+
writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
|
|
898
|
+
}
|
|
899
|
+
var writeRepoConnection = writeSelection;
|
|
900
|
+
function endpointPlacement(endpoint, projectRoot, selected) {
|
|
901
|
+
return {
|
|
902
|
+
alias: endpoint.alias,
|
|
903
|
+
kind: "remote",
|
|
904
|
+
host: endpoint.host,
|
|
905
|
+
port: endpoint.port,
|
|
906
|
+
projectRoot,
|
|
907
|
+
status: selected === endpoint.alias ? "selected" : "ready"
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
async function readPlacement(projectRoot, env = process.env) {
|
|
911
|
+
const config = await loadConfig(resolve4(projectRoot));
|
|
912
|
+
const placement = resolveDispatchTransportPlacement(projectRoot, env);
|
|
913
|
+
const selected = placement.selected;
|
|
914
|
+
return {
|
|
915
|
+
alias: placement.alias,
|
|
916
|
+
kind: placement.kind,
|
|
917
|
+
host: placement.kind === "remote" ? selected?.host ?? placement.sshTarget : null,
|
|
918
|
+
port: placement.kind === "remote" ? selected?.port ?? DEFAULT_REMOTE_PORT2 : null,
|
|
919
|
+
projectRoot,
|
|
920
|
+
status: "ready",
|
|
921
|
+
taskSource: config.taskSource.kind
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
var readSelectedTarget = readPlacement;
|
|
925
|
+
function listPlacements(projectRoot) {
|
|
926
|
+
const selected = readSelection(projectRoot)?.selected ?? "local";
|
|
927
|
+
const builtins = [
|
|
928
|
+
{ alias: "local", kind: "local", projectRoot, status: selected === "local" ? "selected" : "ready" },
|
|
929
|
+
{ alias: "remote", kind: "remote", host: resolveSshTarget() || null, port: DEFAULT_REMOTE_PORT2, projectRoot, status: selected === "remote" ? "selected" : "ready" }
|
|
930
|
+
];
|
|
931
|
+
return [...builtins, ...listManagedRemoteEndpoints(undefined, projectRoot).map((endpoint) => endpointPlacement(endpoint, projectRoot, selected))];
|
|
932
|
+
}
|
|
933
|
+
var listServerTargets = listPlacements;
|
|
934
|
+
function selectPlacement(projectRoot, alias, options = {}) {
|
|
935
|
+
const cleanAlias = alias.trim();
|
|
936
|
+
if (!cleanAlias)
|
|
937
|
+
throw new Error("Placement alias is required.");
|
|
938
|
+
if (cleanAlias !== "local" && cleanAlias !== "remote") {
|
|
939
|
+
const known = listManagedRemoteEndpoints(undefined, projectRoot).some((endpoint) => endpoint.alias === cleanAlias);
|
|
940
|
+
if (!known)
|
|
941
|
+
throw new Error(`Unknown remote endpoint: ${cleanAlias}`);
|
|
942
|
+
}
|
|
943
|
+
if (!options.dryRun) {
|
|
944
|
+
const prev = readSelection(projectRoot);
|
|
945
|
+
writeSelection(projectRoot, { ...prev ?? { selected: "local" }, selected: cleanAlias });
|
|
946
|
+
}
|
|
947
|
+
return listPlacements(projectRoot).find((placement) => placement.alias === cleanAlias) ?? { alias: cleanAlias, kind: cleanAlias === "local" ? "local" : "remote", projectRoot };
|
|
948
|
+
}
|
|
949
|
+
var selectServerTarget = selectPlacement;
|
|
950
|
+
function addPlacement(projectRoot, input, options = {}) {
|
|
951
|
+
const alias = input.alias.trim();
|
|
952
|
+
const host = input.host.trim();
|
|
953
|
+
if (!alias || !host)
|
|
954
|
+
throw new Error("Remote placement requires alias and host.");
|
|
955
|
+
const port = input.port ?? DEFAULT_REMOTE_PORT2;
|
|
956
|
+
if (!Number.isFinite(port) || port <= 0 || port > 65535)
|
|
957
|
+
throw new Error(`Invalid remote port: ${port}`);
|
|
958
|
+
if (options.dryRun)
|
|
959
|
+
return { alias, kind: "remote", host, port, projectRoot, status: "dry-run" };
|
|
960
|
+
const saved = upsertManagedRemoteEndpoint({ alias, host, port, ...input.token ? { token: input.token } : {} }, undefined, projectRoot);
|
|
961
|
+
if (input.select)
|
|
962
|
+
selectPlacement(projectRoot, saved.alias);
|
|
963
|
+
return endpointPlacement(saved, projectRoot, readSelection(projectRoot)?.selected ?? "local");
|
|
964
|
+
}
|
|
965
|
+
var addRemoteTarget = addPlacement;
|
|
966
|
+
function removePlacement(projectRoot, alias, options = {}) {
|
|
967
|
+
const cleanAlias = alias.trim();
|
|
968
|
+
if (!cleanAlias)
|
|
969
|
+
throw new Error("Remote placement alias is required.");
|
|
970
|
+
if (cleanAlias === "local" || cleanAlias === "remote")
|
|
971
|
+
throw new Error(`Cannot remove built-in placement: ${cleanAlias}`);
|
|
972
|
+
const removed = options.dryRun ? true : removeManagedRemoteEndpoint(cleanAlias, undefined, projectRoot);
|
|
973
|
+
if (removed && !options.dryRun && readSelection(projectRoot)?.selected === cleanAlias) {
|
|
974
|
+
const prev = readSelection(projectRoot);
|
|
975
|
+
writeSelection(projectRoot, { ...prev ?? { selected: "local" }, selected: "local" });
|
|
976
|
+
}
|
|
977
|
+
return { alias: cleanAlias, removed };
|
|
978
|
+
}
|
|
979
|
+
var removeServerTarget = removePlacement;
|
|
980
|
+
export {
|
|
981
|
+
writeSelection,
|
|
982
|
+
writeRepoConnection,
|
|
983
|
+
selectServerTarget,
|
|
984
|
+
selectPlacement,
|
|
985
|
+
resolveRepoConnectionPath,
|
|
986
|
+
removeServerTarget,
|
|
987
|
+
removePlacement,
|
|
988
|
+
readSelection,
|
|
989
|
+
readSelectedTarget,
|
|
990
|
+
readRepoConnection,
|
|
991
|
+
readPlacement,
|
|
992
|
+
listServerTargets,
|
|
993
|
+
listPlacements,
|
|
994
|
+
addRemoteTarget,
|
|
995
|
+
addPlacement
|
|
996
|
+
};
|