@vibgrate/cli 2026.722.2 → 2026.727.1
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/DOCS.md +418 -196
- package/README.md +34 -7
- package/dist/baseline-K7YBFKZI.js +7 -0
- package/dist/{baseline-BD3A7EXD.js.map → baseline-K7YBFKZI.js.map} +1 -1
- package/dist/chunk-3BVSDMHV.js +2496 -0
- package/dist/chunk-3BVSDMHV.js.map +1 -0
- package/dist/{chunk-PY3DNX5H.js → chunk-3Q7QBWFW.js} +13 -2
- package/dist/chunk-3Q7QBWFW.js.map +1 -0
- package/dist/chunk-4CQ3MGNN.js +136 -0
- package/dist/chunk-4CQ3MGNN.js.map +1 -0
- package/dist/chunk-5I4VSBWQ.js +764 -0
- package/dist/chunk-5I4VSBWQ.js.map +1 -0
- package/dist/chunk-5Q54GEHM.js +29 -0
- package/dist/chunk-5Q54GEHM.js.map +1 -0
- package/dist/{chunk-2O5YZVZV.js → chunk-65MEOA4E.js} +21 -18
- package/dist/chunk-65MEOA4E.js.map +1 -0
- package/dist/{chunk-WNIIKCNF.js → chunk-6IOQJGFT.js} +29 -238
- package/dist/chunk-6IOQJGFT.js.map +1 -0
- package/dist/{chunk-CS37OBE3.js → chunk-7JHPQ6WF.js} +791 -783
- package/dist/chunk-7JHPQ6WF.js.map +1 -0
- package/dist/chunk-BPF3YX2U.js +64 -0
- package/dist/chunk-BPF3YX2U.js.map +1 -0
- package/dist/chunk-BWPBB45M.js +88 -0
- package/dist/chunk-BWPBB45M.js.map +1 -0
- package/dist/chunk-C4CKTAZP.js +1695 -0
- package/dist/chunk-C4CKTAZP.js.map +1 -0
- package/dist/chunk-EDAAG7BL.js +612 -0
- package/dist/chunk-EDAAG7BL.js.map +1 -0
- package/dist/chunk-EDBV33B7.js +57 -0
- package/dist/chunk-EDBV33B7.js.map +1 -0
- package/dist/chunk-HABUT7HW.js +233 -0
- package/dist/chunk-HABUT7HW.js.map +1 -0
- package/dist/{chunk-NONYJLOJ.js → chunk-HYZVHJ3Q.js} +3 -3
- package/dist/{chunk-NONYJLOJ.js.map → chunk-HYZVHJ3Q.js.map} +1 -1
- package/dist/chunk-IS7VTH2Q.js +627 -0
- package/dist/chunk-IS7VTH2Q.js.map +1 -0
- package/dist/chunk-IZDH67DX.js +289 -0
- package/dist/chunk-IZDH67DX.js.map +1 -0
- package/dist/chunk-J7LKEB2R.js +51 -0
- package/dist/chunk-J7LKEB2R.js.map +1 -0
- package/dist/chunk-JIBOJTGS.js +313 -0
- package/dist/chunk-JIBOJTGS.js.map +1 -0
- package/dist/chunk-JZYGEZTU.js +82 -0
- package/dist/chunk-JZYGEZTU.js.map +1 -0
- package/dist/chunk-K7REHDQS.js +776 -0
- package/dist/chunk-K7REHDQS.js.map +1 -0
- package/dist/chunk-KHJO4D5N.js +108 -0
- package/dist/chunk-KHJO4D5N.js.map +1 -0
- package/dist/chunk-NDMDSPFX.js +69 -0
- package/dist/chunk-NDMDSPFX.js.map +1 -0
- package/dist/chunk-OOIG3RUM.js +276 -0
- package/dist/chunk-OOIG3RUM.js.map +1 -0
- package/dist/{chunk-6CXTPC74.js → chunk-OXQNQW5J.js} +27 -6
- package/dist/chunk-OXQNQW5J.js.map +1 -0
- package/dist/chunk-PMYWZRRS.js +62 -0
- package/dist/chunk-PMYWZRRS.js.map +1 -0
- package/dist/chunk-PXHNTC6D.js +382 -0
- package/dist/chunk-PXHNTC6D.js.map +1 -0
- package/dist/{chunk-3MXNNBLI.js → chunk-S6CYDZEW.js} +1395 -1975
- package/dist/chunk-S6CYDZEW.js.map +1 -0
- package/dist/chunk-SZLF66FJ.js +843 -0
- package/dist/chunk-SZLF66FJ.js.map +1 -0
- package/dist/chunk-VXGV6NTD.js +476 -0
- package/dist/chunk-VXGV6NTD.js.map +1 -0
- package/dist/{chunk-5BDHQ7DD.js → chunk-WLETRGAC.js} +16 -9
- package/dist/chunk-WLETRGAC.js.map +1 -0
- package/dist/{chunk-I7GY7MVN.js → chunk-YDAT7LD2.js} +51 -11
- package/dist/chunk-YDAT7LD2.js.map +1 -0
- package/dist/cli.js +3412 -513
- package/dist/cli.js.map +1 -1
- package/dist/execution-env-3BN7Z737.js +3 -0
- package/dist/execution-env-3BN7Z737.js.map +1 -0
- package/dist/federation-EPZDUWCK.js +6 -0
- package/dist/federation-EPZDUWCK.js.map +1 -0
- package/dist/git-ref-HPRLUFFW.js +3 -0
- package/dist/git-ref-HPRLUFFW.js.map +1 -0
- package/dist/graph-backend-ZMSYOZMW.js +10 -0
- package/dist/graph-backend-ZMSYOZMW.js.map +1 -0
- package/dist/index.d.ts +432 -126
- package/dist/index.js +14 -7
- package/dist/index.js.map +1 -1
- package/dist/{interactive-A4DISSIW.js → interactive-ICL7D7LO.js} +185 -226
- package/dist/interactive-ICL7D7LO.js.map +1 -0
- package/dist/llm-host-2RAYQSDQ.js +8 -0
- package/dist/llm-host-2RAYQSDQ.js.map +1 -0
- package/dist/load-OHVKDX4R.js +7 -0
- package/dist/load-OHVKDX4R.js.map +1 -0
- package/dist/local-runtime-OJFLX2HI.js +4 -0
- package/dist/local-runtime-OJFLX2HI.js.map +1 -0
- package/dist/model-execution-profile-MQ2QCP24.js +3 -0
- package/dist/model-execution-profile-MQ2QCP24.js.map +1 -0
- package/dist/model-orchestrator-FFTZI3U2.js +8 -0
- package/dist/model-orchestrator-FFTZI3U2.js.map +1 -0
- package/dist/parse-worker.d.ts +1 -1
- package/dist/parse-worker.js +1 -1
- package/dist/paths-MCH75O3G.js +5 -0
- package/dist/paths-MCH75O3G.js.map +1 -0
- package/dist/resolve-gguf-4UPIGPEE.js +7 -0
- package/dist/resolve-gguf-4UPIGPEE.js.map +1 -0
- package/dist/runtime-session-IDU5BDUJ.js +17 -0
- package/dist/runtime-session-IDU5BDUJ.js.map +1 -0
- package/dist/session-L2OSDRPI.js +10 -0
- package/dist/{session-POJUDFPH.js.map → session-L2OSDRPI.js.map} +1 -1
- package/dist/{stream-json-Q2JGWPHB.js → stream-json-F74W5FCK.js} +16 -6
- package/dist/stream-json-F74W5FCK.js.map +1 -0
- package/dist/{types-Jl6RJ175.d.ts → types-ZMg1mSuu.d.ts} +3 -1
- package/dist/vgd-EGBQD7BW.js +16 -0
- package/dist/vgd-EGBQD7BW.js.map +1 -0
- package/package.json +9 -6
- package/dist/baseline-BD3A7EXD.js +0 -7
- package/dist/chunk-2O5YZVZV.js.map +0 -1
- package/dist/chunk-3MXNNBLI.js.map +0 -1
- package/dist/chunk-5BDHQ7DD.js.map +0 -1
- package/dist/chunk-6CXTPC74.js.map +0 -1
- package/dist/chunk-CS37OBE3.js.map +0 -1
- package/dist/chunk-GGJZA3Q6.js +0 -961
- package/dist/chunk-GGJZA3Q6.js.map +0 -1
- package/dist/chunk-I7GY7MVN.js.map +0 -1
- package/dist/chunk-JBXNQCGE.js +0 -484
- package/dist/chunk-JBXNQCGE.js.map +0 -1
- package/dist/chunk-PY3DNX5H.js.map +0 -1
- package/dist/chunk-WNIIKCNF.js.map +0 -1
- package/dist/interactive-A4DISSIW.js.map +0 -1
- package/dist/session-POJUDFPH.js +0 -6
- package/dist/stream-json-Q2JGWPHB.js.map +0 -1
|
@@ -0,0 +1,764 @@
|
|
|
1
|
+
import { repositoryIdFromRoot, globalGraphPathForRef, globalGraphPath } from './chunk-BWPBB45M.js';
|
|
2
|
+
import { detectGitRef } from './chunk-BPF3YX2U.js';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import * as path5 from 'path';
|
|
5
|
+
|
|
6
|
+
function normalizeWorkspaceRoots(roots, base = process.cwd()) {
|
|
7
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8
|
+
const out = [];
|
|
9
|
+
const baseAbs = path5.resolve(base);
|
|
10
|
+
for (const r of roots) {
|
|
11
|
+
if (typeof r !== "string" || !r.trim()) continue;
|
|
12
|
+
const abs = path5.resolve(baseAbs, r.trim());
|
|
13
|
+
const id = repositoryIdFromRoot(abs);
|
|
14
|
+
if (seen.has(id)) continue;
|
|
15
|
+
seen.add(id);
|
|
16
|
+
out.push({
|
|
17
|
+
root: abs,
|
|
18
|
+
id,
|
|
19
|
+
label: path5.basename(abs) || abs
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return out.sort((a, b) => a.root.localeCompare(b.root));
|
|
23
|
+
}
|
|
24
|
+
var BRIDGE_EDGE_SCHEMA_VERSION = "bridge-edge/0";
|
|
25
|
+
function discoverBridgeEdges(members, readPackageJson, options = {}) {
|
|
26
|
+
const min = options.minConfidence ?? 0;
|
|
27
|
+
const packages = /* @__PURE__ */ new Map();
|
|
28
|
+
for (const m of members) {
|
|
29
|
+
const root = path5.resolve(m.root);
|
|
30
|
+
const pkg = readPackageJson(root);
|
|
31
|
+
const name = typeof pkg?.name === "string" ? pkg.name.trim() : "";
|
|
32
|
+
if (!name) continue;
|
|
33
|
+
const repositoryId = m.repositoryId ?? repositoryIdFromRoot(root);
|
|
34
|
+
packages.set(name, { root, repositoryId, name });
|
|
35
|
+
}
|
|
36
|
+
const edges = [];
|
|
37
|
+
const seen = /* @__PURE__ */ new Set();
|
|
38
|
+
for (const m of members) {
|
|
39
|
+
const fromRoot = path5.resolve(m.root);
|
|
40
|
+
const fromId = m.repositoryId ?? repositoryIdFromRoot(fromRoot);
|
|
41
|
+
const pkg = readPackageJson(fromRoot);
|
|
42
|
+
if (!pkg) continue;
|
|
43
|
+
const deps = collectDeps(pkg);
|
|
44
|
+
for (const [depName, range] of deps) {
|
|
45
|
+
const target = packages.get(depName);
|
|
46
|
+
if (!target) continue;
|
|
47
|
+
if (target.root === fromRoot) continue;
|
|
48
|
+
const { kind, confidence } = classifyDependency(range, fromRoot, target.root);
|
|
49
|
+
if (confidence < min) continue;
|
|
50
|
+
const key = `${fromId}->${target.repositoryId}:${depName}`;
|
|
51
|
+
if (seen.has(key)) continue;
|
|
52
|
+
seen.add(key);
|
|
53
|
+
edges.push({
|
|
54
|
+
schemaVersion: BRIDGE_EDGE_SCHEMA_VERSION,
|
|
55
|
+
fromRepositoryId: fromId,
|
|
56
|
+
toRepositoryId: target.repositoryId,
|
|
57
|
+
fromRoot,
|
|
58
|
+
toRoot: target.root,
|
|
59
|
+
kind,
|
|
60
|
+
confidence,
|
|
61
|
+
evidence: `${path5.basename(fromRoot)} depends on ${depName} (${range})`,
|
|
62
|
+
packageName: depName
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return edges.sort(
|
|
67
|
+
(a, b) => a.fromRoot.localeCompare(b.fromRoot) || a.toRoot.localeCompare(b.toRoot) || (a.packageName ?? "").localeCompare(b.packageName ?? "")
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
function highConfidenceBridges(edges) {
|
|
71
|
+
return edges.filter((e) => e.confidence >= 0.8);
|
|
72
|
+
}
|
|
73
|
+
function collectDeps(pkg) {
|
|
74
|
+
const out = [];
|
|
75
|
+
for (const field of ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"]) {
|
|
76
|
+
const block = pkg[field];
|
|
77
|
+
if (!block || typeof block !== "object") continue;
|
|
78
|
+
for (const [name, range] of Object.entries(block)) {
|
|
79
|
+
if (typeof name === "string" && typeof range === "string") out.push([name, range]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return out.sort((a, b) => a[0].localeCompare(b[0]) || a[1].localeCompare(b[1]));
|
|
83
|
+
}
|
|
84
|
+
function classifyDependency(range, fromRoot, toRoot) {
|
|
85
|
+
const r = range.trim();
|
|
86
|
+
if (r.startsWith("workspace:") || r.startsWith("link:")) {
|
|
87
|
+
return { kind: "workspace-package", confidence: 0.95 };
|
|
88
|
+
}
|
|
89
|
+
if (r.startsWith("file:")) {
|
|
90
|
+
const rel = r.slice("file:".length).trim();
|
|
91
|
+
try {
|
|
92
|
+
const resolved = path5.resolve(fromRoot, rel);
|
|
93
|
+
if (path5.resolve(resolved) === path5.resolve(toRoot)) {
|
|
94
|
+
return { kind: "path-dependency", confidence: 0.9 };
|
|
95
|
+
}
|
|
96
|
+
} catch {
|
|
97
|
+
}
|
|
98
|
+
return { kind: "path-dependency", confidence: 0.75 };
|
|
99
|
+
}
|
|
100
|
+
return { kind: "workspace-package", confidence: 0.55 };
|
|
101
|
+
}
|
|
102
|
+
function parsePackageManifest(raw) {
|
|
103
|
+
try {
|
|
104
|
+
const o = JSON.parse(raw);
|
|
105
|
+
if (!o || typeof o !== "object") return null;
|
|
106
|
+
return o;
|
|
107
|
+
} catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function discoverInterfaceBridges(members, fs2, options = {}) {
|
|
112
|
+
const min = options.minConfidence ?? 0;
|
|
113
|
+
const maxFiles = options.maxFilesPerMember ?? 40;
|
|
114
|
+
const resolved = members.map((m) => ({
|
|
115
|
+
root: path5.resolve(m.root),
|
|
116
|
+
repositoryId: m.repositoryId ?? repositoryIdFromRoot(m.root)
|
|
117
|
+
}));
|
|
118
|
+
const edges = [];
|
|
119
|
+
const seen = /* @__PURE__ */ new Set();
|
|
120
|
+
const push = (edge) => {
|
|
121
|
+
if (edge.confidence < min) return;
|
|
122
|
+
if (edge.fromRoot === edge.toRoot) return;
|
|
123
|
+
const key = `${edge.fromRepositoryId}->${edge.toRepositoryId}:${edge.kind}:${edge.evidence}`;
|
|
124
|
+
if (seen.has(key)) return;
|
|
125
|
+
seen.add(key);
|
|
126
|
+
edges.push(edge);
|
|
127
|
+
};
|
|
128
|
+
for (const from of resolved) {
|
|
129
|
+
const files = listCandidateFiles(from.root, fs2, maxFiles);
|
|
130
|
+
for (const file of files) {
|
|
131
|
+
const rel = path5.relative(from.root, file).replace(/\\/g, "/");
|
|
132
|
+
const raw = fs2.readFile(file);
|
|
133
|
+
if (!raw) continue;
|
|
134
|
+
if (isOpenApiCandidate(rel, raw)) {
|
|
135
|
+
for (const refPath of extractOpenApiRefs(raw)) {
|
|
136
|
+
const target = resolvePathToMember(from.root, refPath, resolved);
|
|
137
|
+
if (!target || target.root === from.root) continue;
|
|
138
|
+
push({
|
|
139
|
+
schemaVersion: BRIDGE_EDGE_SCHEMA_VERSION,
|
|
140
|
+
fromRepositoryId: from.repositoryId,
|
|
141
|
+
toRepositoryId: target.repositoryId,
|
|
142
|
+
fromRoot: from.root,
|
|
143
|
+
toRoot: target.root,
|
|
144
|
+
kind: "openapi-ref",
|
|
145
|
+
confidence: 0.7,
|
|
146
|
+
evidence: `openapi $ref in ${rel} \u2192 ${refPath}`
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (isComposeCandidate(rel)) {
|
|
151
|
+
for (const ctx of extractComposeBuildContexts(raw)) {
|
|
152
|
+
const target = resolvePathToMember(from.root, ctx, resolved);
|
|
153
|
+
if (!target || target.root === from.root) continue;
|
|
154
|
+
push({
|
|
155
|
+
schemaVersion: BRIDGE_EDGE_SCHEMA_VERSION,
|
|
156
|
+
fromRepositoryId: from.repositoryId,
|
|
157
|
+
toRepositoryId: target.repositoryId,
|
|
158
|
+
fromRoot: from.root,
|
|
159
|
+
toRoot: target.root,
|
|
160
|
+
kind: "compose-service",
|
|
161
|
+
confidence: 0.75,
|
|
162
|
+
evidence: `compose build context in ${rel} \u2192 ${ctx}`
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (isProtoCandidate(rel)) {
|
|
167
|
+
for (const imp of extractProtoImports(raw)) {
|
|
168
|
+
const target = resolveProtoImportToMember(from.root, imp, resolved, fs2);
|
|
169
|
+
if (!target || target.root === from.root) continue;
|
|
170
|
+
push({
|
|
171
|
+
schemaVersion: BRIDGE_EDGE_SCHEMA_VERSION,
|
|
172
|
+
fromRepositoryId: from.repositoryId,
|
|
173
|
+
toRepositoryId: target.repositoryId,
|
|
174
|
+
fromRoot: from.root,
|
|
175
|
+
toRoot: target.root,
|
|
176
|
+
kind: "protobuf-import",
|
|
177
|
+
confidence: 0.72,
|
|
178
|
+
evidence: `protobuf import in ${rel} \u2192 ${imp}`
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (isGraphqlCandidate(rel, raw)) {
|
|
183
|
+
for (const refPath of extractGraphqlRefs(raw)) {
|
|
184
|
+
const target = resolvePathToMember(from.root, refPath, resolved);
|
|
185
|
+
if (!target || target.root === from.root) continue;
|
|
186
|
+
push({
|
|
187
|
+
schemaVersion: BRIDGE_EDGE_SCHEMA_VERSION,
|
|
188
|
+
fromRepositoryId: from.repositoryId,
|
|
189
|
+
toRepositoryId: target.repositoryId,
|
|
190
|
+
fromRoot: from.root,
|
|
191
|
+
toRoot: target.root,
|
|
192
|
+
kind: "graphql-ref",
|
|
193
|
+
confidence: 0.68,
|
|
194
|
+
evidence: `graphql import in ${rel} \u2192 ${refPath}`
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return edges.sort(
|
|
201
|
+
(a, b) => a.fromRoot.localeCompare(b.fromRoot) || a.toRoot.localeCompare(b.toRoot) || a.kind.localeCompare(b.kind) || a.evidence.localeCompare(b.evidence)
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
function listCandidateFiles(root, fs2, maxFiles) {
|
|
205
|
+
const out = [];
|
|
206
|
+
const walk = (dir, depth) => {
|
|
207
|
+
if (out.length >= maxFiles || depth > 4) return;
|
|
208
|
+
let names;
|
|
209
|
+
try {
|
|
210
|
+
names = fs2.readdir(dir);
|
|
211
|
+
} catch {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
for (const name of names.sort((a, b) => a.localeCompare(b))) {
|
|
215
|
+
if (out.length >= maxFiles) return;
|
|
216
|
+
if (name === "node_modules" || name === ".git" || name === "dist" || name === "build" || name === "coverage" || name === ".next") {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
const abs = path5.join(dir, name);
|
|
220
|
+
if (fs2.isDirectory(abs)) {
|
|
221
|
+
walk(abs, depth + 1);
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
const lower = name.toLowerCase();
|
|
225
|
+
if (lower.endsWith(".proto") || lower.endsWith(".graphql") || lower.endsWith(".gql") || lower.endsWith(".yaml") || lower.endsWith(".yml") || lower.endsWith(".json") || lower.includes("openapi") || lower.includes("swagger") || lower.includes("compose")) {
|
|
226
|
+
out.push(abs);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
walk(root, 0);
|
|
231
|
+
return out.sort((a, b) => a.localeCompare(b));
|
|
232
|
+
}
|
|
233
|
+
function isOpenApiCandidate(rel, raw) {
|
|
234
|
+
const lower = rel.toLowerCase();
|
|
235
|
+
if (lower.includes("openapi") || lower.includes("swagger")) return true;
|
|
236
|
+
if (/"openapi"\s*:/.test(raw) || /openapi:\s*['"]?\d/.test(raw)) return true;
|
|
237
|
+
if (/"swagger"\s*:/.test(raw) || /swagger:\s*['"]?\d/.test(raw)) return true;
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
function extractOpenApiRefs(raw) {
|
|
241
|
+
const out = /* @__PURE__ */ new Set();
|
|
242
|
+
const jsonRef = /"\$ref"\s*:\s*"([^"#][^"]*)"/g;
|
|
243
|
+
let m;
|
|
244
|
+
while ((m = jsonRef.exec(raw)) !== null) {
|
|
245
|
+
if (m[1] && !m[1].startsWith("http")) out.add(m[1]);
|
|
246
|
+
}
|
|
247
|
+
const yamlRef = /\$ref:\s*['"]?([^'"#\s][^'"\s]*)/g;
|
|
248
|
+
while ((m = yamlRef.exec(raw)) !== null) {
|
|
249
|
+
if (m[1] && !m[1].startsWith("http") && !m[1].startsWith("#")) out.add(m[1]);
|
|
250
|
+
}
|
|
251
|
+
return [...out].sort((a, b) => a.localeCompare(b));
|
|
252
|
+
}
|
|
253
|
+
function isComposeCandidate(rel) {
|
|
254
|
+
const base = path5.basename(rel).toLowerCase();
|
|
255
|
+
return base === "docker-compose.yml" || base === "docker-compose.yaml" || base === "compose.yml" || base === "compose.yaml" || base.includes("docker-compose");
|
|
256
|
+
}
|
|
257
|
+
function extractComposeBuildContexts(raw) {
|
|
258
|
+
const out = /* @__PURE__ */ new Set();
|
|
259
|
+
const lines = raw.split(/\r?\n/);
|
|
260
|
+
for (let i = 0; i < lines.length; i++) {
|
|
261
|
+
const line = lines[i] ?? "";
|
|
262
|
+
const simple = line.match(/^\s*build:\s*['"]?([^'"#\s][^'"#]*?)['"]?\s*(?:#.*)?$/);
|
|
263
|
+
if (simple?.[1] && !simple[1].startsWith("{") && !/^\s*$/.test(simple[1])) {
|
|
264
|
+
const v = simple[1].trim();
|
|
265
|
+
if (v && v !== "null" && !v.includes(":")) out.add(v);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (/^\s*build:\s*$/.test(line) || /^\s*build:\s*\{\s*$/.test(line)) {
|
|
269
|
+
for (let j = i + 1; j < Math.min(i + 8, lines.length); j++) {
|
|
270
|
+
const ctx = (lines[j] ?? "").match(/^\s*context:\s*['"]?([^'"#\s][^'"#]*?)['"]?\s*(?:#.*)?$/);
|
|
271
|
+
if (ctx?.[1]) {
|
|
272
|
+
out.add(ctx[1].trim());
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
if (/^\S/.test(lines[j] ?? "") || /^\s{0,2}\w/.test(lines[j] ?? "")) {
|
|
276
|
+
if ((lines[j] ?? "").match(/^\s{0,2}\S/) && !(lines[j] ?? "").match(/^\s{4,}/)) break;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return [...out].sort((a, b) => a.localeCompare(b));
|
|
282
|
+
}
|
|
283
|
+
function isProtoCandidate(rel) {
|
|
284
|
+
return rel.toLowerCase().endsWith(".proto");
|
|
285
|
+
}
|
|
286
|
+
function isGraphqlCandidate(rel, raw) {
|
|
287
|
+
const lower = rel.toLowerCase();
|
|
288
|
+
if (lower.endsWith(".graphql") || lower.endsWith(".gql")) return true;
|
|
289
|
+
if (lower.includes("schema") && /#\s*import\b/.test(raw)) return true;
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
function extractGraphqlRefs(raw) {
|
|
293
|
+
const out = /* @__PURE__ */ new Set();
|
|
294
|
+
const re = /#\s*import\s+(?:\*\s+from\s+)?["']([^"']+)["']/g;
|
|
295
|
+
let m;
|
|
296
|
+
while ((m = re.exec(raw)) !== null) {
|
|
297
|
+
if (m[1] && !m[1].startsWith("http")) out.add(m[1]);
|
|
298
|
+
}
|
|
299
|
+
return [...out].sort((a, b) => a.localeCompare(b));
|
|
300
|
+
}
|
|
301
|
+
function extractProtoImports(raw) {
|
|
302
|
+
const out = /* @__PURE__ */ new Set();
|
|
303
|
+
const re = /^\s*import\s+(?:public\s+|weak\s+)?["']([^"']+)["']\s*;/gm;
|
|
304
|
+
let m;
|
|
305
|
+
while ((m = re.exec(raw)) !== null) {
|
|
306
|
+
if (m[1] && !m[1].startsWith("google/protobuf/")) out.add(m[1]);
|
|
307
|
+
}
|
|
308
|
+
return [...out].sort((a, b) => a.localeCompare(b));
|
|
309
|
+
}
|
|
310
|
+
function resolvePathToMember(fromRoot, relOrAbs, members) {
|
|
311
|
+
let abs;
|
|
312
|
+
try {
|
|
313
|
+
abs = path5.isAbsolute(relOrAbs) ? path5.resolve(relOrAbs) : path5.resolve(fromRoot, relOrAbs);
|
|
314
|
+
} catch {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
let best = null;
|
|
318
|
+
for (const m of members) {
|
|
319
|
+
if (abs === m.root || abs.startsWith(m.root + path5.sep)) {
|
|
320
|
+
if (!best || m.root.length > best.root.length) best = m;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return best;
|
|
324
|
+
}
|
|
325
|
+
function resolveProtoImportToMember(fromRoot, importPath, members, fs2) {
|
|
326
|
+
const candidates = [
|
|
327
|
+
path5.resolve(fromRoot, importPath),
|
|
328
|
+
...members.map((m) => path5.resolve(m.root, importPath))
|
|
329
|
+
];
|
|
330
|
+
for (const abs of candidates) {
|
|
331
|
+
const hit = resolvePathToMember(fromRoot, abs, members);
|
|
332
|
+
if (!hit) continue;
|
|
333
|
+
if (fs2.readFile(abs) !== null || pathIsUnder(abs, hit.root)) {
|
|
334
|
+
if (hit.root !== path5.resolve(fromRoot)) return hit;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const parts = importPath.replace(/\\/g, "/").split("/");
|
|
338
|
+
if (parts.length >= 2) {
|
|
339
|
+
const prefix = parts[0];
|
|
340
|
+
for (const m of members) {
|
|
341
|
+
if (path5.basename(m.root) === prefix && m.root !== path5.resolve(fromRoot)) return m;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
function pathIsUnder(child, parent) {
|
|
347
|
+
const rel = path5.relative(path5.resolve(parent), path5.resolve(child));
|
|
348
|
+
return rel === "" || !rel.startsWith("..") && !path5.isAbsolute(rel);
|
|
349
|
+
}
|
|
350
|
+
var DISCOVER_WORKSPACES_VERSION = "discover-workspaces/0";
|
|
351
|
+
function discoverWorkspaceRoots(primaryRoot, fs2, options = {}) {
|
|
352
|
+
const primary = path5.resolve(primaryRoot);
|
|
353
|
+
const maxDepth = options.maxDepth ?? 4;
|
|
354
|
+
const maxRoots = options.maxRoots ?? 64;
|
|
355
|
+
const byRoot = /* @__PURE__ */ new Map();
|
|
356
|
+
const add = (abs, source, label) => {
|
|
357
|
+
const root = path5.resolve(abs);
|
|
358
|
+
if (byRoot.has(root)) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
if (byRoot.size >= maxRoots) return;
|
|
362
|
+
byRoot.set(root, {
|
|
363
|
+
root,
|
|
364
|
+
label: label ?? (path5.basename(root) || root),
|
|
365
|
+
source
|
|
366
|
+
});
|
|
367
|
+
};
|
|
368
|
+
add(primary, "explicit", path5.basename(primary) || primary);
|
|
369
|
+
for (const dir of expandPackageWorkspaces(primary, fs2, maxDepth)) {
|
|
370
|
+
add(dir, "package-workspaces");
|
|
371
|
+
}
|
|
372
|
+
for (const dir of expandPnpmWorkspace(primary, fs2, maxDepth)) {
|
|
373
|
+
add(dir, "pnpm-workspace");
|
|
374
|
+
}
|
|
375
|
+
for (const dir of expandGitSubmodules(primary, fs2)) {
|
|
376
|
+
add(dir, "git-submodule");
|
|
377
|
+
}
|
|
378
|
+
for (const dir of expandCodeWorkspace(primary, fs2)) {
|
|
379
|
+
add(dir, "code-workspace");
|
|
380
|
+
}
|
|
381
|
+
const roots = [...byRoot.values()].sort((a, b) => a.root.localeCompare(b.root));
|
|
382
|
+
return {
|
|
383
|
+
schemaVersion: DISCOVER_WORKSPACES_VERSION,
|
|
384
|
+
primaryRoot: primary,
|
|
385
|
+
roots
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
function expandPackageWorkspaces(primary, fs2, maxDepth) {
|
|
389
|
+
const pkgPath = path5.join(primary, "package.json");
|
|
390
|
+
const raw = fs2.readFile(pkgPath);
|
|
391
|
+
if (!raw) return [];
|
|
392
|
+
let pkg;
|
|
393
|
+
try {
|
|
394
|
+
pkg = JSON.parse(raw);
|
|
395
|
+
} catch {
|
|
396
|
+
return [];
|
|
397
|
+
}
|
|
398
|
+
const patterns = workspacePatterns(pkg.workspaces);
|
|
399
|
+
return expandGlobPatterns(primary, patterns, fs2, maxDepth);
|
|
400
|
+
}
|
|
401
|
+
function workspacePatterns(workspaces) {
|
|
402
|
+
if (Array.isArray(workspaces)) {
|
|
403
|
+
return workspaces.filter((p) => typeof p === "string" && p.trim().length > 0);
|
|
404
|
+
}
|
|
405
|
+
if (workspaces && typeof workspaces === "object" && Array.isArray(workspaces.packages)) {
|
|
406
|
+
return workspaces.packages.filter(
|
|
407
|
+
(p) => typeof p === "string" && p.trim().length > 0
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
return [];
|
|
411
|
+
}
|
|
412
|
+
function expandPnpmWorkspace(primary, fs2, maxDepth) {
|
|
413
|
+
const raw = fs2.readFile(path5.join(primary, "pnpm-workspace.yaml"));
|
|
414
|
+
if (!raw) return [];
|
|
415
|
+
const patterns = [];
|
|
416
|
+
let inPackages = false;
|
|
417
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
418
|
+
if (/^packages\s*:/.test(line)) {
|
|
419
|
+
inPackages = true;
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
if (inPackages) {
|
|
423
|
+
if (/^\S/.test(line) && !/^\s/.test(line)) break;
|
|
424
|
+
const m = line.match(/^\s*-\s*['"]?([^'"]+)['"]?\s*$/);
|
|
425
|
+
if (m?.[1]) patterns.push(m[1].trim());
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return expandGlobPatterns(primary, patterns, fs2, maxDepth);
|
|
429
|
+
}
|
|
430
|
+
function expandGitSubmodules(primary, fs2) {
|
|
431
|
+
const raw = fs2.readFile(path5.join(primary, ".gitmodules"));
|
|
432
|
+
if (!raw) return [];
|
|
433
|
+
const out = [];
|
|
434
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
435
|
+
const m = line.match(/^\s*path\s*=\s*(.+)\s*$/);
|
|
436
|
+
if (!m?.[1]) continue;
|
|
437
|
+
const abs = path5.resolve(primary, m[1].trim());
|
|
438
|
+
if (fs2.exists(abs) && fs2.isDirectory(abs)) out.push(abs);
|
|
439
|
+
}
|
|
440
|
+
return out.sort((a, b) => a.localeCompare(b));
|
|
441
|
+
}
|
|
442
|
+
function expandCodeWorkspace(primary, fs2) {
|
|
443
|
+
const out = [];
|
|
444
|
+
const candidates = [
|
|
445
|
+
...fs2.readdir(primary).filter((n) => n.endsWith(".code-workspace")).map((n) => path5.join(primary, n))
|
|
446
|
+
];
|
|
447
|
+
for (const file of candidates) {
|
|
448
|
+
const raw = fs2.readFile(file);
|
|
449
|
+
if (!raw) continue;
|
|
450
|
+
let doc;
|
|
451
|
+
try {
|
|
452
|
+
doc = JSON.parse(raw);
|
|
453
|
+
} catch {
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
const base = path5.dirname(file);
|
|
457
|
+
for (const folder of doc.folders ?? []) {
|
|
458
|
+
if (typeof folder.path !== "string" || !folder.path.trim()) continue;
|
|
459
|
+
const abs = path5.resolve(base, folder.path.trim());
|
|
460
|
+
if (fs2.exists(abs) && fs2.isDirectory(abs)) out.push(abs);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return out.sort((a, b) => a.localeCompare(b));
|
|
464
|
+
}
|
|
465
|
+
function expandGlobPatterns(primary, patterns, fs2, maxDepth) {
|
|
466
|
+
const out = /* @__PURE__ */ new Set();
|
|
467
|
+
for (const pattern of patterns) {
|
|
468
|
+
const p = pattern.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
469
|
+
if (!p || p.startsWith("..")) continue;
|
|
470
|
+
if (p.includes("*")) {
|
|
471
|
+
for (const hit of expandSimpleGlob(primary, p, fs2, maxDepth)) {
|
|
472
|
+
if (looksLikePackageRoot(hit, fs2)) out.add(hit);
|
|
473
|
+
}
|
|
474
|
+
} else {
|
|
475
|
+
const abs = path5.resolve(primary, p);
|
|
476
|
+
if (fs2.exists(abs) && fs2.isDirectory(abs) && looksLikePackageRoot(abs, fs2)) out.add(abs);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return [...out].sort((a, b) => a.localeCompare(b));
|
|
480
|
+
}
|
|
481
|
+
function expandSimpleGlob(primary, pattern, fs2, maxDepth) {
|
|
482
|
+
const parts = pattern.split("/").filter(Boolean);
|
|
483
|
+
let currents = [primary];
|
|
484
|
+
for (let i = 0; i < parts.length; i++) {
|
|
485
|
+
const part = parts[i];
|
|
486
|
+
const next = [];
|
|
487
|
+
const isLast = i === parts.length - 1;
|
|
488
|
+
for (const cur of currents) {
|
|
489
|
+
if (part === "**") {
|
|
490
|
+
for (const d of walkDirs(cur, fs2, Math.min(maxDepth, 3))) next.push(d);
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
if (part === "*") {
|
|
494
|
+
for (const name of fs2.readdir(cur)) {
|
|
495
|
+
const abs2 = path5.join(cur, name);
|
|
496
|
+
if (fs2.isDirectory(abs2)) next.push(abs2);
|
|
497
|
+
}
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
const abs = path5.join(cur, part);
|
|
501
|
+
if (fs2.exists(abs) && (isLast ? fs2.isDirectory(abs) || fs2.exists(abs) : fs2.isDirectory(abs))) {
|
|
502
|
+
next.push(abs);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
currents = next;
|
|
506
|
+
if (!currents.length) break;
|
|
507
|
+
}
|
|
508
|
+
return currents.filter((d) => fs2.isDirectory(d));
|
|
509
|
+
}
|
|
510
|
+
function walkDirs(root, fs2, depth) {
|
|
511
|
+
if (depth <= 0) return [];
|
|
512
|
+
const out = [];
|
|
513
|
+
for (const name of fs2.readdir(root)) {
|
|
514
|
+
if (name === "node_modules" || name === ".git" || name === "dist" || name === "build") continue;
|
|
515
|
+
const abs = path5.join(root, name);
|
|
516
|
+
if (!fs2.isDirectory(abs)) continue;
|
|
517
|
+
out.push(abs);
|
|
518
|
+
out.push(...walkDirs(abs, fs2, depth - 1));
|
|
519
|
+
}
|
|
520
|
+
return out;
|
|
521
|
+
}
|
|
522
|
+
function looksLikePackageRoot(dir, fs2) {
|
|
523
|
+
return fs2.exists(path5.join(dir, "package.json"));
|
|
524
|
+
}
|
|
525
|
+
function nodeDiscoverFs() {
|
|
526
|
+
return {
|
|
527
|
+
readFile(absPath) {
|
|
528
|
+
try {
|
|
529
|
+
return fs.readFileSync(absPath, "utf8");
|
|
530
|
+
} catch {
|
|
531
|
+
return null;
|
|
532
|
+
}
|
|
533
|
+
},
|
|
534
|
+
readdir(absPath) {
|
|
535
|
+
try {
|
|
536
|
+
return fs.readdirSync(absPath).sort((a, b) => a.localeCompare(b));
|
|
537
|
+
} catch {
|
|
538
|
+
return [];
|
|
539
|
+
}
|
|
540
|
+
},
|
|
541
|
+
isDirectory(absPath) {
|
|
542
|
+
try {
|
|
543
|
+
return fs.statSync(absPath).isDirectory();
|
|
544
|
+
} catch {
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
},
|
|
548
|
+
exists(absPath) {
|
|
549
|
+
try {
|
|
550
|
+
return fs.existsSync(absPath);
|
|
551
|
+
} catch {
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// src/runtime/federation.ts
|
|
559
|
+
var FEDERATION_SCHEMA_VERSION = "federation/0";
|
|
560
|
+
function loadFederation(primaryRoot, options = {}) {
|
|
561
|
+
const primary = path5.resolve(primaryRoot);
|
|
562
|
+
const file = federationPath(primary);
|
|
563
|
+
if (!fs.existsSync(file)) {
|
|
564
|
+
if (options.requireFile) return null;
|
|
565
|
+
return singleMemberFederation(primary);
|
|
566
|
+
}
|
|
567
|
+
let raw;
|
|
568
|
+
try {
|
|
569
|
+
raw = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
570
|
+
} catch {
|
|
571
|
+
return null;
|
|
572
|
+
}
|
|
573
|
+
return parseFederationFile(primary, raw);
|
|
574
|
+
}
|
|
575
|
+
function loadOrDiscoverFederation(primaryRoot, options = {}) {
|
|
576
|
+
const primary = path5.resolve(primaryRoot);
|
|
577
|
+
const existing = loadFederation(primary, { requireFile: true });
|
|
578
|
+
if (existing) {
|
|
579
|
+
if (!existing.bridges?.length) {
|
|
580
|
+
existing.bridges = bridgesForMembers(existing.members, options.minBridgeConfidence);
|
|
581
|
+
}
|
|
582
|
+
return existing;
|
|
583
|
+
}
|
|
584
|
+
const dfs = options.discoverFs ?? nodeDiscoverFs();
|
|
585
|
+
const discovered = discoverWorkspaceRoots(primary, dfs);
|
|
586
|
+
const roots = discovered.roots.map((r) => r.root);
|
|
587
|
+
const fed = federationFromWorkspaceRoots(roots, { preferredPrimary: primary });
|
|
588
|
+
fed.bridges = bridgesForMembers(fed.members, options.minBridgeConfidence);
|
|
589
|
+
return fed;
|
|
590
|
+
}
|
|
591
|
+
function bridgesForMembers(members, minConfidence = 0.5) {
|
|
592
|
+
const memberRefs = members.map((m) => ({ root: m.root, repositoryId: m.repositoryId }));
|
|
593
|
+
const pkgEdges = discoverBridgeEdges(
|
|
594
|
+
memberRefs,
|
|
595
|
+
(root) => {
|
|
596
|
+
try {
|
|
597
|
+
const raw = fs.readFileSync(path5.join(root, "package.json"), "utf8");
|
|
598
|
+
return parsePackageManifest(raw);
|
|
599
|
+
} catch {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
},
|
|
603
|
+
{ minConfidence }
|
|
604
|
+
);
|
|
605
|
+
const ifaceEdges = discoverInterfaceBridges(
|
|
606
|
+
memberRefs,
|
|
607
|
+
{
|
|
608
|
+
readFile(absPath) {
|
|
609
|
+
try {
|
|
610
|
+
return fs.readFileSync(absPath, "utf8");
|
|
611
|
+
} catch {
|
|
612
|
+
return null;
|
|
613
|
+
}
|
|
614
|
+
},
|
|
615
|
+
readdir(absPath) {
|
|
616
|
+
try {
|
|
617
|
+
return fs.readdirSync(absPath).sort((a, b) => a.localeCompare(b));
|
|
618
|
+
} catch {
|
|
619
|
+
return [];
|
|
620
|
+
}
|
|
621
|
+
},
|
|
622
|
+
isDirectory(absPath) {
|
|
623
|
+
try {
|
|
624
|
+
return fs.statSync(absPath).isDirectory();
|
|
625
|
+
} catch {
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
{ minConfidence }
|
|
631
|
+
);
|
|
632
|
+
const seen = /* @__PURE__ */ new Set();
|
|
633
|
+
const out = [];
|
|
634
|
+
for (const e of [...pkgEdges, ...ifaceEdges].sort(
|
|
635
|
+
(a, b) => a.fromRoot.localeCompare(b.fromRoot) || a.toRoot.localeCompare(b.toRoot) || a.kind.localeCompare(b.kind) || a.evidence.localeCompare(b.evidence)
|
|
636
|
+
)) {
|
|
637
|
+
const key = `${e.fromRepositoryId}|${e.toRepositoryId}|${e.kind}|${e.evidence}`;
|
|
638
|
+
if (seen.has(key)) continue;
|
|
639
|
+
seen.add(key);
|
|
640
|
+
out.push(e);
|
|
641
|
+
}
|
|
642
|
+
return out;
|
|
643
|
+
}
|
|
644
|
+
function federationPath(primaryRoot) {
|
|
645
|
+
return path5.join(path5.resolve(primaryRoot), ".vibgrate", "federation.json");
|
|
646
|
+
}
|
|
647
|
+
function singleMemberFederation(primaryRoot) {
|
|
648
|
+
const primary = path5.resolve(primaryRoot);
|
|
649
|
+
const [ws] = normalizeWorkspaceRoots([primary], primary);
|
|
650
|
+
return {
|
|
651
|
+
schemaVersion: FEDERATION_SCHEMA_VERSION,
|
|
652
|
+
primaryRoot: primary,
|
|
653
|
+
members: [
|
|
654
|
+
memberFromRoot(ws?.root ?? primary, "primary", ws?.label ?? (path5.basename(primary) || primary))
|
|
655
|
+
]
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
function parseFederationFile(primaryRoot, raw) {
|
|
659
|
+
const primary = path5.resolve(primaryRoot);
|
|
660
|
+
if (!raw || typeof raw !== "object") return null;
|
|
661
|
+
const list = Array.isArray(raw.members) ? raw.members : [];
|
|
662
|
+
if (!list.length) return singleMemberFederation(primary);
|
|
663
|
+
const members = [];
|
|
664
|
+
const seen = /* @__PURE__ */ new Set();
|
|
665
|
+
let hasPrimary = false;
|
|
666
|
+
for (const entry of list) {
|
|
667
|
+
if (!entry || typeof entry.root !== "string" || !entry.root.trim()) continue;
|
|
668
|
+
const abs = path5.resolve(primary, entry.root.trim());
|
|
669
|
+
const id = repositoryIdFromRoot(abs);
|
|
670
|
+
if (seen.has(id)) continue;
|
|
671
|
+
seen.add(id);
|
|
672
|
+
const role = entry.role === "primary" || abs === primary ? "primary" : "member";
|
|
673
|
+
if (role === "primary") hasPrimary = true;
|
|
674
|
+
members.push(memberFromRoot(abs, role, typeof entry.label === "string" && entry.label.trim() ? entry.label.trim() : path5.basename(abs) || abs));
|
|
675
|
+
}
|
|
676
|
+
if (!members.length) return singleMemberFederation(primary);
|
|
677
|
+
if (!hasPrimary) {
|
|
678
|
+
const id = repositoryIdFromRoot(primary);
|
|
679
|
+
if (!seen.has(id)) {
|
|
680
|
+
members.unshift(memberFromRoot(primary, "primary", path5.basename(primary) || primary));
|
|
681
|
+
} else {
|
|
682
|
+
const existing = members.find((m) => m.repositoryId === id);
|
|
683
|
+
if (existing) existing.role = "primary";
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
members.sort((a, b) => {
|
|
687
|
+
if (a.role !== b.role) return a.role === "primary" ? -1 : 1;
|
|
688
|
+
return a.root.localeCompare(b.root);
|
|
689
|
+
});
|
|
690
|
+
const fed = {
|
|
691
|
+
schemaVersion: FEDERATION_SCHEMA_VERSION,
|
|
692
|
+
primaryRoot: primary,
|
|
693
|
+
members
|
|
694
|
+
};
|
|
695
|
+
if (Array.isArray(raw.bridges) && raw.bridges.length) {
|
|
696
|
+
fed.bridges = raw.bridges.filter((b) => b && typeof b === "object" && typeof b.fromRoot === "string" && typeof b.toRoot === "string").map((b) => ({
|
|
697
|
+
...b,
|
|
698
|
+
fromRoot: path5.resolve(primary, b.fromRoot),
|
|
699
|
+
toRoot: path5.resolve(primary, b.toRoot)
|
|
700
|
+
}));
|
|
701
|
+
}
|
|
702
|
+
return fed;
|
|
703
|
+
}
|
|
704
|
+
function memberFromRoot(root, role, label) {
|
|
705
|
+
const git = detectGitRef(root);
|
|
706
|
+
const graphPath = git.kind !== "none" && git.ref ? globalGraphPathForRef(root, git.ref) : globalGraphPath(root);
|
|
707
|
+
return {
|
|
708
|
+
root,
|
|
709
|
+
label,
|
|
710
|
+
role,
|
|
711
|
+
repositoryId: repositoryIdFromRoot(root),
|
|
712
|
+
graphPath
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
function federationFromWorkspaceRoots(roots, options = {}) {
|
|
716
|
+
const normalized = normalizeWorkspaceRoots(roots, options.preferredPrimary ?? roots[0] ?? process.cwd());
|
|
717
|
+
if (!normalized.length) {
|
|
718
|
+
const fallback = path5.resolve(options.preferredPrimary ?? process.cwd());
|
|
719
|
+
return singleMemberFederation(fallback);
|
|
720
|
+
}
|
|
721
|
+
const preferred = options.preferredPrimary?.trim() ? path5.resolve(options.preferredPrimary.trim()) : normalized[0].root;
|
|
722
|
+
const primaryHit = normalized.find((r) => r.root === preferred) ?? normalized.find((r) => r.id === repositoryIdFromRoot(preferred)) ?? normalized[0];
|
|
723
|
+
const primaryRoot = primaryHit.root;
|
|
724
|
+
const members = normalized.map(
|
|
725
|
+
(ws) => memberFromRoot(ws.root, ws.root === primaryRoot ? "primary" : "member", ws.label)
|
|
726
|
+
);
|
|
727
|
+
members.sort((a, b) => {
|
|
728
|
+
if (a.role !== b.role) return a.role === "primary" ? -1 : 1;
|
|
729
|
+
return a.root.localeCompare(b.root);
|
|
730
|
+
});
|
|
731
|
+
return {
|
|
732
|
+
schemaVersion: FEDERATION_SCHEMA_VERSION,
|
|
733
|
+
primaryRoot,
|
|
734
|
+
members
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
function writeFederationFile(primaryRoot, federation) {
|
|
738
|
+
const primary = path5.resolve(primaryRoot);
|
|
739
|
+
const file = federationPath(primary);
|
|
740
|
+
fs.mkdirSync(path5.dirname(file), { recursive: true });
|
|
741
|
+
const body = {
|
|
742
|
+
schemaVersion: FEDERATION_SCHEMA_VERSION,
|
|
743
|
+
members: federation.members.map((m) => ({
|
|
744
|
+
// Prefer path relative to primary when possible so the file is portable.
|
|
745
|
+
root: path5.relative(primary, m.root) || ".",
|
|
746
|
+
label: m.label,
|
|
747
|
+
role: m.role
|
|
748
|
+
}))
|
|
749
|
+
};
|
|
750
|
+
if (federation.bridges?.length) {
|
|
751
|
+
body.bridges = federation.bridges.map((b) => ({
|
|
752
|
+
...b,
|
|
753
|
+
fromRoot: path5.relative(primary, b.fromRoot) || ".",
|
|
754
|
+
toRoot: path5.relative(primary, b.toRoot) || "."
|
|
755
|
+
}));
|
|
756
|
+
}
|
|
757
|
+
fs.writeFileSync(file, `${JSON.stringify(body, null, 2)}
|
|
758
|
+
`, "utf8");
|
|
759
|
+
return file;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
export { FEDERATION_SCHEMA_VERSION, federationFromWorkspaceRoots, federationPath, highConfidenceBridges, loadFederation, loadOrDiscoverFederation, parseFederationFile, singleMemberFederation, writeFederationFile };
|
|
763
|
+
//# sourceMappingURL=chunk-5I4VSBWQ.js.map
|
|
764
|
+
//# sourceMappingURL=chunk-5I4VSBWQ.js.map
|