@h-rig/repos-plugin 0.0.6-alpha.156

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 ADDED
@@ -0,0 +1 @@
1
+ # @h-rig/repos-plugin
@@ -0,0 +1,7 @@
1
+ export * from "./registry";
2
+ export * from "./layout";
3
+ export * from "./mirror/state";
4
+ export * from "./mirror/bootstrap";
5
+ export * from "./mirror/refresh";
6
+ export * from "./service";
7
+ export * from "./plugin";
@@ -0,0 +1,491 @@
1
+ // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true,
12
+ configurable: true,
13
+ set: __exportSetter.bind(all, name)
14
+ });
15
+ };
16
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
+
18
+ // packages/repos-plugin/src/registry.ts
19
+ function createRepoRegistry(entries) {
20
+ const map = new Map;
21
+ for (const e of entries) {
22
+ if (map.has(e.id))
23
+ throw new Error(`repo already registered: ${e.id}`);
24
+ map.set(e.id, { ...e });
25
+ }
26
+ const ordered = Array.from(map.values());
27
+ return {
28
+ getById: (id) => map.get(id),
29
+ list: () => ordered
30
+ };
31
+ }
32
+ function setManagedRepos(entries) {
33
+ const next = new Map;
34
+ for (const e of entries) {
35
+ if (next.has(e.id)) {
36
+ throw new Error(`managed repo already registered: ${e.id}`);
37
+ }
38
+ next.set(e.id, e);
39
+ }
40
+ MANAGED_REPOS = next;
41
+ }
42
+ function clearManagedRepos() {
43
+ MANAGED_REPOS = new Map;
44
+ }
45
+ function getManagedRepoEntry(repoId) {
46
+ const entry = MANAGED_REPOS.get(repoId);
47
+ if (!entry) {
48
+ throw new Error(`managed repo not registered: ${repoId}. Plugins contribute repos via RigPlugin.contributes.repoSources; ` + `make sure a plugin declares this id and the plugin host has been initialized.`);
49
+ }
50
+ return entry;
51
+ }
52
+ function tryGetManagedRepoEntry(repoId) {
53
+ return MANAGED_REPOS.get(repoId);
54
+ }
55
+ function listManagedRepoEntries() {
56
+ return Array.from(MANAGED_REPOS.values());
57
+ }
58
+ function resolveManagedRepoIdByAlias(alias) {
59
+ for (const entry of MANAGED_REPOS.values()) {
60
+ if (entry.alias === alias) {
61
+ return entry.id;
62
+ }
63
+ }
64
+ return null;
65
+ }
66
+ function isManagedRepoAlias(alias) {
67
+ return resolveManagedRepoIdByAlias(alias) !== null;
68
+ }
69
+ function repoRegistrationToManagedEntry(reg) {
70
+ if (!reg.defaultBranch) {
71
+ return null;
72
+ }
73
+ return {
74
+ id: reg.id,
75
+ alias: reg.defaultPath ?? reg.id,
76
+ defaultBranch: reg.defaultBranch,
77
+ defaultRemoteUrl: reg.url,
78
+ remoteEnvVar: reg.remoteEnvVar,
79
+ checkoutEnvVar: reg.checkoutEnvVar
80
+ };
81
+ }
82
+ var MANAGED_REPOS;
83
+ var init_registry = __esm(() => {
84
+ MANAGED_REPOS = new Map;
85
+ });
86
+
87
+ // packages/repos-plugin/src/layout.ts
88
+ import { existsSync } from "fs";
89
+ import { basename, dirname, join, resolve } from "path";
90
+ import { resolveMonorepoRoot } from "@rig/runtime/layout";
91
+ function resolveRepoStateDir(projectRoot) {
92
+ const normalizedProjectRoot = resolve(projectRoot);
93
+ const projectParent = dirname(normalizedProjectRoot);
94
+ if (basename(projectParent) === ".worktrees") {
95
+ const ownerRoot = dirname(projectParent);
96
+ const ownerHasRepoMarkers = existsSync(resolve(ownerRoot, ".git")) || existsSync(resolve(ownerRoot, ".rig", "state"));
97
+ if (ownerHasRepoMarkers) {
98
+ return resolve(ownerRoot, ".rig", "state");
99
+ }
100
+ }
101
+ return resolve(projectRoot, ".rig", "state");
102
+ }
103
+ function resolveManagedRepoLayout(projectRoot, repoId) {
104
+ const normalizedProjectRoot = resolve(projectRoot);
105
+ const entry = getManagedRepoEntry(repoId);
106
+ const stateDir = resolveRepoStateDir(normalizedProjectRoot);
107
+ const metadataRelativePath = join("repos", entry.id);
108
+ const metadataRoot = resolve(stateDir, metadataRelativePath);
109
+ const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
110
+ const runsInsideTaskWorktree = runtimeWorkspace && resolve(runtimeWorkspace) === normalizedProjectRoot || basename(dirname(normalizedProjectRoot)) === ".worktrees";
111
+ const isPrimaryManagedRepo = listManagedRepoEntries()[0]?.id === repoId;
112
+ const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ? resolve(process.env[entry.checkoutEnvVar].trim()) : resolve(normalizedProjectRoot, entry.alias);
113
+ return {
114
+ projectRoot: normalizedProjectRoot,
115
+ repoId: entry.id,
116
+ alias: entry.alias,
117
+ defaultBranch: entry.defaultBranch,
118
+ remoteUrl: entry.remoteEnvVar && process.env[entry.remoteEnvVar]?.trim() ? process.env[entry.remoteEnvVar].trim() : entry.defaultRemoteUrl,
119
+ checkoutRoot,
120
+ worktreesRoot: resolve(checkoutRoot, ".worktrees"),
121
+ stateDir,
122
+ metadataRoot,
123
+ metadataRelativePath,
124
+ mirrorRoot: resolve(metadataRoot, "mirror.git"),
125
+ mirrorStatePath: resolve(metadataRoot, "mirror-state.json"),
126
+ mirrorStateRelativePath: join(metadataRelativePath, "mirror-state.json")
127
+ };
128
+ }
129
+ function resolveManagedRepoLayoutByAlias(projectRoot, alias) {
130
+ const repoId = resolveManagedRepoIdByAlias(alias);
131
+ return repoId ? resolveManagedRepoLayout(projectRoot, repoId) : null;
132
+ }
133
+ function resolveMonorepoRepoLayout(projectRoot) {
134
+ const entries = listManagedRepoEntries();
135
+ if (entries.length === 0) {
136
+ throw new Error("resolveMonorepoRepoLayout: no managed repos registered. Either contribute one via " + "RigPlugin.contributes.repoSources (with defaultBranch set), or avoid calling this " + "function for projects where the project root IS the monorepo.");
137
+ }
138
+ const primary = entries[0];
139
+ return resolveManagedRepoLayout(projectRoot, primary.id);
140
+ }
141
+ var init_layout = __esm(() => {
142
+ init_registry();
143
+ });
144
+
145
+ // packages/repos-plugin/src/mirror/state.ts
146
+ import { readAuthorityProjectStateJson, writeAuthorityProjectStateJson } from "@rig/runtime/control-plane/json-files";
147
+ function defaultMirrorState(projectRoot, repoId) {
148
+ const layout = resolveManagedRepoLayout(projectRoot, repoId);
149
+ return {
150
+ version: STATE_VERSION,
151
+ repoId,
152
+ remoteUrl: layout.remoteUrl,
153
+ defaultBranch: layout.defaultBranch
154
+ };
155
+ }
156
+ function readManagedRepoMirrorState(projectRoot, repoId) {
157
+ const layout = resolveManagedRepoLayout(projectRoot, repoId);
158
+ return readAuthorityProjectStateJson(projectRoot, layout.mirrorStateRelativePath, null);
159
+ }
160
+ function writeManagedRepoMirrorState(projectRoot, repoId, patch) {
161
+ const current = readManagedRepoMirrorState(projectRoot, repoId) || defaultMirrorState(projectRoot, repoId);
162
+ const next = {
163
+ ...current,
164
+ ...patch,
165
+ version: STATE_VERSION,
166
+ repoId
167
+ };
168
+ const layout = resolveManagedRepoLayout(projectRoot, repoId);
169
+ writeAuthorityProjectStateJson(projectRoot, layout.mirrorStateRelativePath, next);
170
+ return next;
171
+ }
172
+ var STATE_VERSION = 1;
173
+ var init_state = __esm(() => {
174
+ init_layout();
175
+ });
176
+
177
+ // packages/repos-plugin/src/mirror/bootstrap.ts
178
+ import { existsSync as existsSync2, mkdirSync, realpathSync } from "fs";
179
+ import { resolve as resolve2 } from "path";
180
+ function nowIso() {
181
+ return new Date().toISOString();
182
+ }
183
+ function runGit(command, cwd) {
184
+ const result = Bun.spawnSync(command, {
185
+ cwd,
186
+ stdout: "pipe",
187
+ stderr: "pipe",
188
+ env: process.env
189
+ });
190
+ return {
191
+ exitCode: result.exitCode,
192
+ stdout: result.stdout.toString(),
193
+ stderr: result.stderr.toString()
194
+ };
195
+ }
196
+ function ensureGitSuccess(result, command) {
197
+ if (result.exitCode !== 0) {
198
+ throw new Error(result.stderr || result.stdout || `git command failed: ${command.join(" ")}`);
199
+ }
200
+ }
201
+ function isUsableRemoteUrl(candidate, layout) {
202
+ return candidate.length > 0 && candidate !== layout.mirrorRoot && candidate !== layout.checkoutRoot;
203
+ }
204
+ function sameExistingPath(left, right) {
205
+ try {
206
+ return realpathSync(left) === realpathSync(right);
207
+ } catch {
208
+ return resolve2(left) === resolve2(right);
209
+ }
210
+ }
211
+ function repoLooksUsable(repoRoot, projectRoot) {
212
+ const probe = runGit(["git", "-C", repoRoot, "rev-parse", "--show-toplevel"], projectRoot);
213
+ return probe.exitCode === 0 && sameExistingPath(probe.stdout.trim(), repoRoot);
214
+ }
215
+ function checkoutLooksUsable(layout) {
216
+ return repoLooksUsable(layout.checkoutRoot, layout.projectRoot);
217
+ }
218
+ function resolveMirrorRemoteUrl(layout) {
219
+ const entry = getManagedRepoEntry(layout.repoId);
220
+ const explicit = entry.remoteEnvVar ? process.env[entry.remoteEnvVar]?.trim() : "";
221
+ if (explicit) {
222
+ return explicit;
223
+ }
224
+ const persisted = readManagedRepoMirrorState(layout.projectRoot, layout.repoId)?.remoteUrl?.trim();
225
+ if (persisted && isUsableRemoteUrl(persisted, layout)) {
226
+ return persisted;
227
+ }
228
+ const mirrorOrigin = runGit(["git", "--git-dir", layout.mirrorRoot, "remote", "get-url", "origin"], layout.projectRoot);
229
+ if (mirrorOrigin.exitCode === 0) {
230
+ const currentOrigin = mirrorOrigin.stdout.trim();
231
+ if (isUsableRemoteUrl(currentOrigin, layout)) {
232
+ return currentOrigin;
233
+ }
234
+ }
235
+ if (repoLooksUsable(layout.projectRoot, layout.projectRoot)) {
236
+ const projectOrigin = runGit(["git", "-C", layout.projectRoot, "remote", "get-url", "origin"], layout.projectRoot);
237
+ if (projectOrigin.exitCode === 0) {
238
+ const currentOrigin = projectOrigin.stdout.trim();
239
+ if (isUsableRemoteUrl(currentOrigin, layout)) {
240
+ return currentOrigin;
241
+ }
242
+ }
243
+ }
244
+ if (existsSync2(resolve2(layout.checkoutRoot, ".git")) && checkoutLooksUsable(layout)) {
245
+ const checkoutOrigin = runGit(["git", "-C", layout.checkoutRoot, "remote", "get-url", "origin"], layout.projectRoot);
246
+ if (checkoutOrigin.exitCode === 0) {
247
+ const currentOrigin = checkoutOrigin.stdout.trim();
248
+ if (isUsableRemoteUrl(currentOrigin, layout)) {
249
+ return currentOrigin;
250
+ }
251
+ }
252
+ }
253
+ return layout.remoteUrl;
254
+ }
255
+ function ensureManagedRepoMirror(projectRoot, repoId) {
256
+ const layout = resolveManagedRepoLayout(projectRoot, repoId);
257
+ mkdirSync(layout.metadataRoot, { recursive: true });
258
+ const remoteUrl = resolveMirrorRemoteUrl(layout);
259
+ if (!existsSync2(resolve2(layout.mirrorRoot, "HEAD"))) {
260
+ ensureGitSuccess(runGit(["git", "init", "--bare", layout.mirrorRoot], layout.projectRoot), ["git", "init", "--bare", layout.mirrorRoot]);
261
+ }
262
+ const getOrigin = runGit(["git", "--git-dir", layout.mirrorRoot, "remote", "get-url", "origin"], layout.projectRoot);
263
+ if (getOrigin.exitCode === 0) {
264
+ const currentOrigin = getOrigin.stdout.trim();
265
+ if (currentOrigin !== remoteUrl) {
266
+ ensureGitSuccess(runGit(["git", "--git-dir", layout.mirrorRoot, "remote", "set-url", "origin", remoteUrl], layout.projectRoot), ["git", "--git-dir", layout.mirrorRoot, "remote", "set-url", "origin", remoteUrl]);
267
+ }
268
+ } else {
269
+ ensureGitSuccess(runGit(["git", "--git-dir", layout.mirrorRoot, "remote", "add", "origin", remoteUrl], layout.projectRoot), ["git", "--git-dir", layout.mirrorRoot, "remote", "add", "origin", remoteUrl]);
270
+ }
271
+ writeManagedRepoMirrorState(projectRoot, repoId, {
272
+ remoteUrl,
273
+ defaultBranch: layout.defaultBranch,
274
+ initializedAt: nowIso()
275
+ });
276
+ return layout;
277
+ }
278
+ var init_bootstrap = __esm(() => {
279
+ init_registry();
280
+ init_layout();
281
+ init_state();
282
+ });
283
+
284
+ // packages/repos-plugin/src/mirror/refresh.ts
285
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, realpathSync as realpathSync2, rmSync } from "fs";
286
+ import { resolve as resolve3 } from "path";
287
+ function nowIso2() {
288
+ return new Date().toISOString();
289
+ }
290
+ function runGit2(command, cwd) {
291
+ const result = Bun.spawnSync(command, {
292
+ cwd,
293
+ stdout: "pipe",
294
+ stderr: "pipe",
295
+ env: process.env
296
+ });
297
+ return {
298
+ exitCode: result.exitCode,
299
+ stdout: result.stdout.toString(),
300
+ stderr: result.stderr.toString()
301
+ };
302
+ }
303
+ function ensureGitSuccess2(result, command) {
304
+ if (result.exitCode !== 0) {
305
+ throw new Error(result.stderr || result.stdout || `git command failed: ${command.join(" ")}`);
306
+ }
307
+ return result.stdout.trim();
308
+ }
309
+ function sameExistingPath2(left, right) {
310
+ try {
311
+ return realpathSync2(left) === realpathSync2(right);
312
+ } catch {
313
+ return resolve3(left) === resolve3(right);
314
+ }
315
+ }
316
+ function ensureMirrorHead(layout) {
317
+ ensureGitSuccess2(runGit2([
318
+ "git",
319
+ "--git-dir",
320
+ layout.mirrorRoot,
321
+ "fetch",
322
+ "--prune",
323
+ "origin",
324
+ "+refs/heads/*:refs/heads/*",
325
+ "+refs/tags/*:refs/tags/*"
326
+ ], layout.projectRoot), [
327
+ "git",
328
+ "--git-dir",
329
+ layout.mirrorRoot,
330
+ "fetch",
331
+ "--prune",
332
+ "origin",
333
+ "+refs/heads/*:refs/heads/*",
334
+ "+refs/tags/*:refs/tags/*"
335
+ ]);
336
+ const headRef = `refs/heads/${layout.defaultBranch}`;
337
+ const headCommit = ensureGitSuccess2(runGit2(["git", "--git-dir", layout.mirrorRoot, "rev-parse", headRef], layout.projectRoot), ["git", "--git-dir", layout.mirrorRoot, "rev-parse", headRef]);
338
+ const remoteUrl = ensureGitSuccess2(runGit2(["git", "--git-dir", layout.mirrorRoot, "remote", "get-url", "origin"], layout.projectRoot), ["git", "--git-dir", layout.mirrorRoot, "remote", "get-url", "origin"]);
339
+ ensureGitSuccess2(runGit2(["git", "--git-dir", layout.mirrorRoot, "symbolic-ref", "HEAD", headRef], layout.projectRoot), ["git", "--git-dir", layout.mirrorRoot, "symbolic-ref", "HEAD", headRef]);
340
+ writeManagedRepoMirrorState(layout.projectRoot, layout.repoId, {
341
+ remoteUrl,
342
+ defaultBranch: layout.defaultBranch,
343
+ lastSyncedAt: nowIso2(),
344
+ headRef,
345
+ headCommit
346
+ });
347
+ return headCommit;
348
+ }
349
+ function refreshManagedRepoMirror(projectRoot, repoId) {
350
+ const layout = ensureManagedRepoMirror(projectRoot, repoId);
351
+ const headCommit = ensureMirrorHead(layout);
352
+ return { layout, headCommit };
353
+ }
354
+ function checkoutLooksUsable2(layout) {
355
+ const probe = runGit2(["git", "-C", layout.checkoutRoot, "rev-parse", "--show-toplevel"], layout.projectRoot);
356
+ return probe.exitCode === 0 && sameExistingPath2(probe.stdout.trim(), layout.checkoutRoot);
357
+ }
358
+ function ensureCheckoutFromMirror(layout) {
359
+ mkdirSync2(resolve3(layout.checkoutRoot, ".."), { recursive: true });
360
+ const gitPath = resolve3(layout.checkoutRoot, ".git");
361
+ if (existsSync3(layout.checkoutRoot) && (!existsSync3(gitPath) || !checkoutLooksUsable2(layout))) {
362
+ rmSync(layout.checkoutRoot, { recursive: true, force: true });
363
+ }
364
+ if (!existsSync3(gitPath)) {
365
+ ensureGitSuccess2(runGit2(["git", "clone", layout.mirrorRoot, layout.checkoutRoot], layout.projectRoot), ["git", "clone", layout.mirrorRoot, layout.checkoutRoot]);
366
+ }
367
+ const getOrigin = runGit2(["git", "-C", layout.checkoutRoot, "remote", "get-url", "origin"], layout.projectRoot);
368
+ if (getOrigin.exitCode === 0) {
369
+ const currentOrigin = getOrigin.stdout.trim();
370
+ if (currentOrigin !== layout.mirrorRoot) {
371
+ ensureGitSuccess2(runGit2(["git", "-C", layout.checkoutRoot, "remote", "set-url", "origin", layout.mirrorRoot], layout.projectRoot), ["git", "-C", layout.checkoutRoot, "remote", "set-url", "origin", layout.mirrorRoot]);
372
+ }
373
+ } else {
374
+ ensureGitSuccess2(runGit2(["git", "-C", layout.checkoutRoot, "remote", "add", "origin", layout.mirrorRoot], layout.projectRoot), ["git", "-C", layout.checkoutRoot, "remote", "add", "origin", layout.mirrorRoot]);
375
+ }
376
+ ensureGitSuccess2(runGit2(["git", "-C", layout.checkoutRoot, "fetch", "origin", layout.defaultBranch], layout.projectRoot), ["git", "-C", layout.checkoutRoot, "fetch", "origin", layout.defaultBranch]);
377
+ ensureGitSuccess2(runGit2(["git", "-C", layout.checkoutRoot, "reset", "--hard"], layout.projectRoot), ["git", "-C", layout.checkoutRoot, "reset", "--hard"]);
378
+ ensureGitSuccess2(runGit2(["git", "-C", layout.checkoutRoot, "clean", "-fd"], layout.projectRoot), ["git", "-C", layout.checkoutRoot, "clean", "-fd"]);
379
+ ensureGitSuccess2(runGit2([
380
+ "git",
381
+ "-C",
382
+ layout.checkoutRoot,
383
+ "checkout",
384
+ "--force",
385
+ "-B",
386
+ layout.defaultBranch,
387
+ `origin/${layout.defaultBranch}`
388
+ ], layout.projectRoot), [
389
+ "git",
390
+ "-C",
391
+ layout.checkoutRoot,
392
+ "checkout",
393
+ "--force",
394
+ "-B",
395
+ layout.defaultBranch,
396
+ `origin/${layout.defaultBranch}`
397
+ ]);
398
+ ensureGitSuccess2(runGit2(["git", "-C", layout.checkoutRoot, "reset", "--hard", `origin/${layout.defaultBranch}`], layout.projectRoot), ["git", "-C", layout.checkoutRoot, "reset", "--hard", `origin/${layout.defaultBranch}`]);
399
+ ensureGitSuccess2(runGit2(["git", "-C", layout.checkoutRoot, "clean", "-fd"], layout.projectRoot), ["git", "-C", layout.checkoutRoot, "clean", "-fd"]);
400
+ return ensureGitSuccess2(runGit2(["git", "-C", layout.checkoutRoot, "rev-parse", "HEAD"], layout.projectRoot), ["git", "-C", layout.checkoutRoot, "rev-parse", "HEAD"]);
401
+ }
402
+ function syncManagedRepo(projectRoot, repoId) {
403
+ const { layout, headCommit } = refreshManagedRepoMirror(projectRoot, repoId);
404
+ const checkoutCommit = ensureCheckoutFromMirror(layout);
405
+ if (checkoutCommit !== headCommit) {
406
+ throw new Error(`Managed repo checkout ${layout.alias} is out of sync with mirror: expected ${headCommit}, got ${checkoutCommit}.`);
407
+ }
408
+ return { layout, headCommit };
409
+ }
410
+ var init_refresh = __esm(() => {
411
+ init_bootstrap();
412
+ init_state();
413
+ });
414
+
415
+ // packages/repos-plugin/src/service.ts
416
+ var exports_service = {};
417
+ __export(exports_service, {
418
+ svc: () => svc,
419
+ managedRepoService: () => managedRepoService
420
+ });
421
+ var managedRepoService, svc;
422
+ var init_service = __esm(() => {
423
+ init_registry();
424
+ init_layout();
425
+ init_refresh();
426
+ managedRepoService = {
427
+ setManagedRepos,
428
+ listManagedRepoEntries,
429
+ resolveManagedRepoIdByAlias,
430
+ repoRegistrationToManagedEntry,
431
+ createRepoRegistry,
432
+ resolveManagedRepoLayoutByAlias,
433
+ resolveMonorepoRepoLayout,
434
+ syncManagedRepo
435
+ };
436
+ svc = managedRepoService;
437
+ });
438
+
439
+ // packages/repos-plugin/src/index.ts
440
+ init_registry();
441
+ init_layout();
442
+ init_state();
443
+ init_bootstrap();
444
+ init_refresh();
445
+ init_service();
446
+
447
+ // packages/repos-plugin/src/plugin.ts
448
+ import { definePlugin } from "@rig/core/config";
449
+ import { MANAGED_REPO_SERVICE_CAPABILITY_ID } from "@rig/contracts";
450
+ var REPOS_PLUGIN_NAME = "@rig/repos-plugin";
451
+ var reposPlugin = definePlugin({
452
+ name: REPOS_PLUGIN_NAME,
453
+ version: "0.0.0-alpha.1",
454
+ contributes: {
455
+ capabilities: [
456
+ {
457
+ id: MANAGED_REPO_SERVICE_CAPABILITY_ID,
458
+ title: "Managed repositories",
459
+ description: "Registry, on-disk layout, and mirror/sync for plugin-contributed managed repos.",
460
+ run: async () => (await Promise.resolve().then(() => (init_service(), exports_service))).svc
461
+ }
462
+ ]
463
+ }
464
+ });
465
+ function createReposPlugin() {
466
+ return reposPlugin;
467
+ }
468
+ export {
469
+ writeManagedRepoMirrorState,
470
+ tryGetManagedRepoEntry,
471
+ syncManagedRepo,
472
+ svc,
473
+ setManagedRepos,
474
+ resolveMonorepoRepoLayout,
475
+ resolveManagedRepoLayoutByAlias,
476
+ resolveManagedRepoLayout,
477
+ resolveManagedRepoIdByAlias,
478
+ reposPlugin,
479
+ repoRegistrationToManagedEntry,
480
+ refreshManagedRepoMirror,
481
+ readManagedRepoMirrorState,
482
+ managedRepoService,
483
+ listManagedRepoEntries,
484
+ isManagedRepoAlias,
485
+ getManagedRepoEntry,
486
+ ensureManagedRepoMirror,
487
+ createReposPlugin,
488
+ createRepoRegistry,
489
+ clearManagedRepos,
490
+ REPOS_PLUGIN_NAME
491
+ };
@@ -0,0 +1,10 @@
1
+ import type { ManagedRepoAlias, ManagedRepoId, ManagedRepoLayout } from "@rig/contracts";
2
+ export declare function resolveManagedRepoLayout(projectRoot: string, repoId: ManagedRepoId): ManagedRepoLayout;
3
+ export declare function resolveManagedRepoLayoutByAlias(projectRoot: string, alias: ManagedRepoAlias | string): ManagedRepoLayout | null;
4
+ /**
5
+ * Resolve the layout for the project's primary monorepo. Picks the first
6
+ * managed repo entry; throws if none are registered. New projects without
7
+ * a separate managed monorepo don't call this — they live in the flat
8
+ * layout where the project root IS the monorepo.
9
+ */
10
+ export declare function resolveMonorepoRepoLayout(projectRoot: string): ManagedRepoLayout;
@@ -0,0 +1,83 @@
1
+ // @bun
2
+ // packages/repos-plugin/src/layout.ts
3
+ import { existsSync } from "fs";
4
+ import { basename, dirname, join, resolve } from "path";
5
+ import { resolveMonorepoRoot } from "@rig/runtime/layout";
6
+
7
+ // packages/repos-plugin/src/registry.ts
8
+ var MANAGED_REPOS = new Map;
9
+ function getManagedRepoEntry(repoId) {
10
+ const entry = MANAGED_REPOS.get(repoId);
11
+ if (!entry) {
12
+ throw new Error(`managed repo not registered: ${repoId}. Plugins contribute repos via RigPlugin.contributes.repoSources; ` + `make sure a plugin declares this id and the plugin host has been initialized.`);
13
+ }
14
+ return entry;
15
+ }
16
+ function listManagedRepoEntries() {
17
+ return Array.from(MANAGED_REPOS.values());
18
+ }
19
+ function resolveManagedRepoIdByAlias(alias) {
20
+ for (const entry of MANAGED_REPOS.values()) {
21
+ if (entry.alias === alias) {
22
+ return entry.id;
23
+ }
24
+ }
25
+ return null;
26
+ }
27
+
28
+ // packages/repos-plugin/src/layout.ts
29
+ function resolveRepoStateDir(projectRoot) {
30
+ const normalizedProjectRoot = resolve(projectRoot);
31
+ const projectParent = dirname(normalizedProjectRoot);
32
+ if (basename(projectParent) === ".worktrees") {
33
+ const ownerRoot = dirname(projectParent);
34
+ const ownerHasRepoMarkers = existsSync(resolve(ownerRoot, ".git")) || existsSync(resolve(ownerRoot, ".rig", "state"));
35
+ if (ownerHasRepoMarkers) {
36
+ return resolve(ownerRoot, ".rig", "state");
37
+ }
38
+ }
39
+ return resolve(projectRoot, ".rig", "state");
40
+ }
41
+ function resolveManagedRepoLayout(projectRoot, repoId) {
42
+ const normalizedProjectRoot = resolve(projectRoot);
43
+ const entry = getManagedRepoEntry(repoId);
44
+ const stateDir = resolveRepoStateDir(normalizedProjectRoot);
45
+ const metadataRelativePath = join("repos", entry.id);
46
+ const metadataRoot = resolve(stateDir, metadataRelativePath);
47
+ const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
48
+ const runsInsideTaskWorktree = runtimeWorkspace && resolve(runtimeWorkspace) === normalizedProjectRoot || basename(dirname(normalizedProjectRoot)) === ".worktrees";
49
+ const isPrimaryManagedRepo = listManagedRepoEntries()[0]?.id === repoId;
50
+ const checkoutRoot = isPrimaryManagedRepo && runsInsideTaskWorktree ? resolveMonorepoRoot(normalizedProjectRoot) : entry.checkoutEnvVar && process.env[entry.checkoutEnvVar]?.trim() ? resolve(process.env[entry.checkoutEnvVar].trim()) : resolve(normalizedProjectRoot, entry.alias);
51
+ return {
52
+ projectRoot: normalizedProjectRoot,
53
+ repoId: entry.id,
54
+ alias: entry.alias,
55
+ defaultBranch: entry.defaultBranch,
56
+ remoteUrl: entry.remoteEnvVar && process.env[entry.remoteEnvVar]?.trim() ? process.env[entry.remoteEnvVar].trim() : entry.defaultRemoteUrl,
57
+ checkoutRoot,
58
+ worktreesRoot: resolve(checkoutRoot, ".worktrees"),
59
+ stateDir,
60
+ metadataRoot,
61
+ metadataRelativePath,
62
+ mirrorRoot: resolve(metadataRoot, "mirror.git"),
63
+ mirrorStatePath: resolve(metadataRoot, "mirror-state.json"),
64
+ mirrorStateRelativePath: join(metadataRelativePath, "mirror-state.json")
65
+ };
66
+ }
67
+ function resolveManagedRepoLayoutByAlias(projectRoot, alias) {
68
+ const repoId = resolveManagedRepoIdByAlias(alias);
69
+ return repoId ? resolveManagedRepoLayout(projectRoot, repoId) : null;
70
+ }
71
+ function resolveMonorepoRepoLayout(projectRoot) {
72
+ const entries = listManagedRepoEntries();
73
+ if (entries.length === 0) {
74
+ throw new Error("resolveMonorepoRepoLayout: no managed repos registered. Either contribute one via " + "RigPlugin.contributes.repoSources (with defaultBranch set), or avoid calling this " + "function for projects where the project root IS the monorepo.");
75
+ }
76
+ const primary = entries[0];
77
+ return resolveManagedRepoLayout(projectRoot, primary.id);
78
+ }
79
+ export {
80
+ resolveMonorepoRepoLayout,
81
+ resolveManagedRepoLayoutByAlias,
82
+ resolveManagedRepoLayout
83
+ };
@@ -0,0 +1,2 @@
1
+ import type { ManagedRepoId, ManagedRepoLayout } from "@rig/contracts";
2
+ export declare function ensureManagedRepoMirror(projectRoot: string, repoId: ManagedRepoId): ManagedRepoLayout;