@orquentra/codebuddy 2.9.0 → 2.14.0
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/CLAUDE_CODEX.md +33 -0
- package/README.md +27 -3
- package/dist/{adapters-S4HHTWJW.js → adapters-OJRSVFV3.js} +2 -2
- package/dist/{chunk-GKNYMNFM.js → chunk-4DKYKDHI.js} +6 -1
- package/dist/chunk-4DKYKDHI.js.map +1 -0
- package/dist/{chunk-SRA4MDVG.js → chunk-7QMHIJBA.js} +30 -3
- package/dist/chunk-7QMHIJBA.js.map +1 -0
- package/dist/{chunk-6NZEZJYD.js → chunk-ESC4Y3L7.js} +3 -5
- package/dist/{chunk-6NZEZJYD.js.map → chunk-ESC4Y3L7.js.map} +1 -1
- package/dist/chunk-GQKWUHMA.js +20 -0
- package/dist/chunk-GQKWUHMA.js.map +1 -0
- package/dist/{chunk-J4T6HHI4.js → chunk-L6BRYZ6G.js} +537 -316
- package/dist/chunk-L6BRYZ6G.js.map +1 -0
- package/dist/{chunk-UK6XTS2Y.js → chunk-LRQNPYCK.js} +13 -19
- package/dist/chunk-LRQNPYCK.js.map +1 -0
- package/dist/{chunk-GXOML4UZ.js → chunk-LW75SKZR.js} +2 -2
- package/dist/{chunk-ENKDFLOO.js → chunk-UOTKHSQ5.js} +25 -8
- package/dist/chunk-UOTKHSQ5.js.map +1 -0
- package/dist/{chunk-W7GAXL6C.js → chunk-V7PT6ER5.js} +6 -5
- package/dist/chunk-V7PT6ER5.js.map +1 -0
- package/dist/{chunk-F4BJ3DXW.js → chunk-XSNW6Y3X.js} +1253 -315
- package/dist/chunk-XSNW6Y3X.js.map +1 -0
- package/dist/{chunk-2WH2Q4TA.js → chunk-YJPCS2GP.js} +256 -68
- package/dist/chunk-YJPCS2GP.js.map +1 -0
- package/dist/{chunk-TLWGZVPC.js → chunk-YNSTIMCF.js} +746 -66
- package/dist/chunk-YNSTIMCF.js.map +1 -0
- package/dist/{chunk-QN76UJP7.js → chunk-YWDH6DQ6.js} +70 -4
- package/dist/chunk-YWDH6DQ6.js.map +1 -0
- package/dist/cli/index.js +23 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/{codebuddy-DO7ZhoWn.d.ts → codebuddy-CHqMptZB.d.ts} +35 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +8 -8
- package/dist/install-EU35ERK5.js +30 -0
- package/dist/langgraph/index.d.ts +1 -1
- package/dist/lean-43ADYTBW.js +28 -0
- package/dist/{main-YJKSYFPT.js → main-SFC5LV4E.js} +704 -242
- package/dist/main-SFC5LV4E.js.map +1 -0
- package/dist/{operations-OG4ISWIM.js → operations-6Z6ZDVBP.js} +3 -3
- package/dist/{pretool-command-PRFOIHMW.js → pretool-command-B5GY5T6E.js} +2 -2
- package/dist/prompt-gate-TDTFFQW2.js +8 -0
- package/dist/{runtime-GCSEIAVD.js → runtime-W5AW32SD.js} +14 -6
- package/dist/{summaries-ML53R7EL.js → summaries-32PHOB6L.js} +3 -4
- package/dist/{zvec-XDZNZ2OL.js → zvec-24HLAFGN.js} +3 -4
- package/dist/zvec-24HLAFGN.js.map +1 -0
- package/package.json +11 -2
- package/dist/chunk-2WH2Q4TA.js.map +0 -1
- package/dist/chunk-ENKDFLOO.js.map +0 -1
- package/dist/chunk-F4BJ3DXW.js.map +0 -1
- package/dist/chunk-GKNYMNFM.js.map +0 -1
- package/dist/chunk-ITQO632W.js +0 -673
- package/dist/chunk-ITQO632W.js.map +0 -1
- package/dist/chunk-J4T6HHI4.js.map +0 -1
- package/dist/chunk-QN76UJP7.js.map +0 -1
- package/dist/chunk-SRA4MDVG.js.map +0 -1
- package/dist/chunk-TLWGZVPC.js.map +0 -1
- package/dist/chunk-UK6XTS2Y.js.map +0 -1
- package/dist/chunk-W7GAXL6C.js.map +0 -1
- package/dist/install-BXM56QCD.js +0 -19
- package/dist/lean-command-7DFW32MA.js +0 -19
- package/dist/main-YJKSYFPT.js.map +0 -1
- /package/dist/{adapters-S4HHTWJW.js.map → adapters-OJRSVFV3.js.map} +0 -0
- /package/dist/{chunk-GXOML4UZ.js.map → chunk-LW75SKZR.js.map} +0 -0
- /package/dist/{install-BXM56QCD.js.map → install-EU35ERK5.js.map} +0 -0
- /package/dist/{lean-command-7DFW32MA.js.map → lean-43ADYTBW.js.map} +0 -0
- /package/dist/{operations-OG4ISWIM.js.map → operations-6Z6ZDVBP.js.map} +0 -0
- /package/dist/{pretool-command-PRFOIHMW.js.map → pretool-command-B5GY5T6E.js.map} +0 -0
- /package/dist/{runtime-GCSEIAVD.js.map → prompt-gate-TDTFFQW2.js.map} +0 -0
- /package/dist/{summaries-ML53R7EL.js.map → runtime-W5AW32SD.js.map} +0 -0
- /package/dist/{zvec-XDZNZ2OL.js.map → summaries-32PHOB6L.js.map} +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
extractPythonImports,
|
|
3
|
+
extractSymbolTable,
|
|
4
|
+
supportsSymbols
|
|
5
|
+
} from "./chunk-Y7D7PUBE.js";
|
|
5
6
|
import {
|
|
6
7
|
isCredentialPath
|
|
7
8
|
} from "./chunk-AL6VBTNA.js";
|
|
@@ -12,26 +13,681 @@ import {
|
|
|
12
13
|
readConfigFile
|
|
13
14
|
} from "./chunk-KNR2P2UY.js";
|
|
14
15
|
import {
|
|
16
|
+
assertNoSymlinkBetween,
|
|
15
17
|
writeAtomic
|
|
16
18
|
} from "./chunk-CG5B3LYG.js";
|
|
17
19
|
|
|
20
|
+
// src/map/indexer.ts
|
|
21
|
+
import { readdir, readFile, stat } from "fs/promises";
|
|
22
|
+
import { dirname, extname, join, relative, resolve } from "path";
|
|
23
|
+
var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py"]);
|
|
24
|
+
var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
25
|
+
".git",
|
|
26
|
+
"node_modules",
|
|
27
|
+
"dist",
|
|
28
|
+
"build",
|
|
29
|
+
"coverage",
|
|
30
|
+
".codebuddy",
|
|
31
|
+
// Python virtualenvs and caches would otherwise map site-packages.
|
|
32
|
+
".venv",
|
|
33
|
+
"venv",
|
|
34
|
+
".tox",
|
|
35
|
+
"__pycache__"
|
|
36
|
+
]);
|
|
37
|
+
async function buildArchitectureMap(repositoryRoot = process.cwd()) {
|
|
38
|
+
const root = resolve(repositoryRoot);
|
|
39
|
+
const files = await listSourceFiles(root);
|
|
40
|
+
const fileSet = new Set(files.map((file) => normalize(relative(root, file))));
|
|
41
|
+
const modules = [];
|
|
42
|
+
const edges = [];
|
|
43
|
+
for (const absolutePath of files) {
|
|
44
|
+
const source = await readFile(absolutePath, "utf8");
|
|
45
|
+
const from = normalize(relative(root, absolutePath));
|
|
46
|
+
const resolvedImports = moduleImports(root, from, source, fileSet);
|
|
47
|
+
edges.push(...resolvedImports.map(({ to, kind }) => ({ from, to, kind })));
|
|
48
|
+
modules.push({
|
|
49
|
+
path: from,
|
|
50
|
+
language: moduleLanguage(from),
|
|
51
|
+
imports: [...new Set(resolvedImports.map(({ to }) => to))].sort()
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
modules: modules.sort((left, right) => left.path.localeCompare(right.path)),
|
|
56
|
+
edges: edges.sort(
|
|
57
|
+
(left, right) => `${left.from}:${left.to}`.localeCompare(`${right.from}:${right.to}`)
|
|
58
|
+
)
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async function updateArchitectureMap(repositoryRoot, sourcePaths, previous, changedPaths) {
|
|
62
|
+
const root = resolve(repositoryRoot);
|
|
63
|
+
const normalizedPaths = sourcePaths.map(normalize).sort();
|
|
64
|
+
const fileSet = new Set(normalizedPaths);
|
|
65
|
+
const changed = new Set(changedPaths.map(normalize));
|
|
66
|
+
const retainedModules = (previous?.modules ?? []).filter(
|
|
67
|
+
(module) => fileSet.has(module.path) && !changed.has(module.path)
|
|
68
|
+
);
|
|
69
|
+
const retainedEdges = (previous?.edges ?? []).filter(
|
|
70
|
+
(edge) => fileSet.has(edge.from) && fileSet.has(edge.to) && !changed.has(edge.from)
|
|
71
|
+
);
|
|
72
|
+
const modules = [...retainedModules];
|
|
73
|
+
const edges = [...retainedEdges];
|
|
74
|
+
for (const path of normalizedPaths) {
|
|
75
|
+
if (!changed.has(path)) continue;
|
|
76
|
+
const source = await readFile(join(root, path), "utf8");
|
|
77
|
+
const resolvedImports = moduleImports(root, path, source, fileSet);
|
|
78
|
+
edges.push(...resolvedImports.map(({ to, kind }) => ({ from: path, to, kind })));
|
|
79
|
+
modules.push({
|
|
80
|
+
path,
|
|
81
|
+
language: moduleLanguage(path),
|
|
82
|
+
imports: [...new Set(resolvedImports.map(({ to }) => to))].sort()
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
map: {
|
|
87
|
+
modules: modules.sort((left, right) => left.path.localeCompare(right.path)),
|
|
88
|
+
edges: edges.sort(
|
|
89
|
+
(left, right) => `${left.from}:${left.to}`.localeCompare(`${right.from}:${right.to}`)
|
|
90
|
+
)
|
|
91
|
+
},
|
|
92
|
+
stats: {
|
|
93
|
+
readFiles: changed.size,
|
|
94
|
+
reusedFiles: retainedModules.length,
|
|
95
|
+
rebuilt: previous === null || changed.size === normalizedPaths.length
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function queryMap(map, query) {
|
|
100
|
+
const limit = query.limit ?? 50;
|
|
101
|
+
return map.edges.filter((edge) => query.from ? edge.from === normalize(query.from) : true).filter((edge) => query.to ? edge.to === normalize(query.to) : true).slice(0, limit);
|
|
102
|
+
}
|
|
103
|
+
function neighbours(map, modulePath, direction = "both") {
|
|
104
|
+
const target = normalize(modulePath);
|
|
105
|
+
const edges = map.edges.filter((edge) => {
|
|
106
|
+
if (direction === "in") return edge.to === target;
|
|
107
|
+
if (direction === "out") return edge.from === target;
|
|
108
|
+
return edge.from === target || edge.to === target;
|
|
109
|
+
});
|
|
110
|
+
const paths = /* @__PURE__ */ new Set([target]);
|
|
111
|
+
for (const edge of edges) {
|
|
112
|
+
paths.add(edge.from);
|
|
113
|
+
paths.add(edge.to);
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
modules: map.modules.filter((module) => paths.has(module.path)),
|
|
117
|
+
edges
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async function listSourceFiles(root) {
|
|
121
|
+
const files = [];
|
|
122
|
+
await walk(root, files);
|
|
123
|
+
return files.sort();
|
|
124
|
+
}
|
|
125
|
+
async function walk(directory, files) {
|
|
126
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
127
|
+
for (const entry of entries) {
|
|
128
|
+
const absolute = join(directory, entry.name);
|
|
129
|
+
if (entry.isDirectory()) {
|
|
130
|
+
if (IGNORED_DIRECTORIES.has(entry.name)) continue;
|
|
131
|
+
await walk(absolute, files);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (!entry.isFile()) continue;
|
|
135
|
+
if (!SUPPORTED_EXTENSIONS.has(extname(entry.name))) continue;
|
|
136
|
+
const info = await stat(absolute);
|
|
137
|
+
if (info.size > 5e5) continue;
|
|
138
|
+
files.push(absolute);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function moduleLanguage(path) {
|
|
142
|
+
const extension = extname(path);
|
|
143
|
+
if (extension === ".py") return "py";
|
|
144
|
+
return extension.includes("ts") ? "ts" : "js";
|
|
145
|
+
}
|
|
146
|
+
function moduleImports(root, from, source, fileSet) {
|
|
147
|
+
if (extname(from) === ".py") {
|
|
148
|
+
return pythonImports(from, source, fileSet).map((to) => ({ to, kind: "import" }));
|
|
149
|
+
}
|
|
150
|
+
return extractImports(source).flatMap((specifier) => {
|
|
151
|
+
const to = resolveImport(root, from, specifier.value, fileSet);
|
|
152
|
+
return to ? [{ to, kind: specifier.kind }] : [];
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
var PYTHON_ROOTS = ["", "src/"];
|
|
156
|
+
function pythonImports(from, source, fileSet) {
|
|
157
|
+
const pick = (...candidates) => candidates.find((candidate) => fileSet.has(candidate)) ?? null;
|
|
158
|
+
const moduleFile = (base) => pick(`${base}.py`, `${base}/__init__.py`);
|
|
159
|
+
const packageDir = from.split("/").slice(0, -1);
|
|
160
|
+
const targets = [];
|
|
161
|
+
for (const statement of extractPythonImports(source)) {
|
|
162
|
+
const parts = statement.module ? statement.module.split(".") : [];
|
|
163
|
+
let bases;
|
|
164
|
+
if (statement.level > 0) {
|
|
165
|
+
const up = statement.level - 1;
|
|
166
|
+
if (up > packageDir.length) continue;
|
|
167
|
+
bases = [[...packageDir.slice(0, packageDir.length - up), ...parts].join("/")];
|
|
168
|
+
} else {
|
|
169
|
+
bases = PYTHON_ROOTS.map((prefix) => `${prefix}${parts.join("/")}`);
|
|
170
|
+
}
|
|
171
|
+
for (const base of bases) {
|
|
172
|
+
const prefix = base ? `${base}/` : "";
|
|
173
|
+
const module = parts.length > 0 ? moduleFile(base) : pick(`${prefix}__init__.py`);
|
|
174
|
+
const submodules = statement.names.flatMap((name) => moduleFile(`${prefix}${name}`) ?? []);
|
|
175
|
+
if (!module && submodules.length === 0) continue;
|
|
176
|
+
targets.push(...submodules);
|
|
177
|
+
if (module && submodules.length < Math.max(1, statement.names.length)) targets.push(module);
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return [...new Set(targets)].filter((target) => target !== from);
|
|
182
|
+
}
|
|
183
|
+
function extractImports(source) {
|
|
184
|
+
const imports = [];
|
|
185
|
+
const stripped = source.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/(^|[^:])\/\/[^\n]*/g, "$1 ");
|
|
186
|
+
const staticImport = /\bimport\s+(?:type\s+)?(?:[^'"()+]+?\s+from\s+)?["']([^"']+)["']/g;
|
|
187
|
+
const exportFrom = /\bexport\s+[^'"()+]+?\s+from\s+["']([^"']+)["']/g;
|
|
188
|
+
const dynamicImport = /\bimport\s*\(\s*["']([^"']+)["']\s*\)/g;
|
|
189
|
+
for (const match of stripped.matchAll(staticImport)) {
|
|
190
|
+
if (match[1]) imports.push({ value: match[1], kind: "import" });
|
|
191
|
+
}
|
|
192
|
+
for (const match of stripped.matchAll(exportFrom)) {
|
|
193
|
+
if (match[1]) imports.push({ value: match[1], kind: "import" });
|
|
194
|
+
}
|
|
195
|
+
for (const match of stripped.matchAll(dynamicImport)) {
|
|
196
|
+
if (match[1]) imports.push({ value: match[1], kind: "dynamic_import" });
|
|
197
|
+
}
|
|
198
|
+
return imports;
|
|
199
|
+
}
|
|
200
|
+
function resolveImport(root, from, specifier, fileSet) {
|
|
201
|
+
if (!specifier.startsWith(".")) return null;
|
|
202
|
+
const base = normalize(relative(root, resolve(root, dirname(from), specifier)));
|
|
203
|
+
const stem = base.replace(/\.(js|jsx|mjs|cjs)$/, "");
|
|
204
|
+
const bases = stem === base ? [base] : [base, stem];
|
|
205
|
+
const candidates = bases.flatMap((b) => [
|
|
206
|
+
b,
|
|
207
|
+
`${b}.ts`,
|
|
208
|
+
`${b}.tsx`,
|
|
209
|
+
`${b}.js`,
|
|
210
|
+
`${b}.jsx`,
|
|
211
|
+
`${b}.mjs`,
|
|
212
|
+
`${b}.cjs`,
|
|
213
|
+
`${b}/index.ts`,
|
|
214
|
+
`${b}/index.tsx`,
|
|
215
|
+
`${b}/index.js`,
|
|
216
|
+
`${b}/index.jsx`
|
|
217
|
+
]);
|
|
218
|
+
return candidates.find((candidate) => fileSet.has(candidate)) ?? null;
|
|
219
|
+
}
|
|
220
|
+
function normalize(path) {
|
|
221
|
+
return path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/indexer/engine.ts
|
|
225
|
+
import { createHash } from "crypto";
|
|
226
|
+
import { readFile as readFile4, stat as stat2 } from "fs/promises";
|
|
227
|
+
import { join as join5, resolve as resolve4 } from "path";
|
|
228
|
+
|
|
229
|
+
// src/map/cache.ts
|
|
230
|
+
import { mkdir as mkdir2, readFile as readFile3 } from "fs/promises";
|
|
231
|
+
import { dirname as dirname3, extname as extname2, join as join3, resolve as resolve3 } from "path";
|
|
232
|
+
|
|
233
|
+
// src/indexer/store.ts
|
|
234
|
+
import { mkdir, readFile as readFile2 } from "fs/promises";
|
|
235
|
+
import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
|
|
236
|
+
import { z } from "zod";
|
|
237
|
+
|
|
238
|
+
// src/indexer/types.ts
|
|
239
|
+
var INDEX_MANIFEST_VERSION = 3;
|
|
240
|
+
|
|
241
|
+
// src/indexer/store.ts
|
|
242
|
+
var symbolSpanSchema = z.object({
|
|
243
|
+
name: z.string(),
|
|
244
|
+
kind: z.enum(["function", "method", "class", "interface", "type", "enum", "const", "heading"]),
|
|
245
|
+
startLine: z.number().int().nonnegative(),
|
|
246
|
+
endLine: z.number().int().nonnegative(),
|
|
247
|
+
signature: z.string(),
|
|
248
|
+
exported: z.boolean()
|
|
249
|
+
});
|
|
250
|
+
var entrySchema = z.object({
|
|
251
|
+
path: z.string(),
|
|
252
|
+
hash: z.string(),
|
|
253
|
+
size: z.number().int().nonnegative(),
|
|
254
|
+
mtimeMs: z.number().optional(),
|
|
255
|
+
ctimeMs: z.number().optional(),
|
|
256
|
+
language: z.string(),
|
|
257
|
+
lines: z.number().int().nonnegative(),
|
|
258
|
+
symbols: z.array(z.string()),
|
|
259
|
+
symbolTable: z.array(symbolSpanSchema).optional(),
|
|
260
|
+
summary: z.string(),
|
|
261
|
+
indexedAt: z.string()
|
|
262
|
+
});
|
|
263
|
+
var manifestSchema = z.object({
|
|
264
|
+
version: z.literal(INDEX_MANIFEST_VERSION),
|
|
265
|
+
generatedAt: z.string(),
|
|
266
|
+
entries: z.record(z.string(), entrySchema)
|
|
267
|
+
});
|
|
268
|
+
var IndexStore = class {
|
|
269
|
+
repositoryRoot;
|
|
270
|
+
cacheDirectory;
|
|
271
|
+
manifestPath;
|
|
272
|
+
constructor(repositoryRoot = process.cwd()) {
|
|
273
|
+
this.repositoryRoot = resolve2(repositoryRoot);
|
|
274
|
+
this.cacheDirectory = join2(this.repositoryRoot, ".codebuddy", "cache");
|
|
275
|
+
this.manifestPath = join2(this.cacheDirectory, "index.json");
|
|
276
|
+
}
|
|
277
|
+
/** Read the manifest, or an empty one if absent/corrupt/version-mismatched. */
|
|
278
|
+
async read() {
|
|
279
|
+
try {
|
|
280
|
+
const raw = await readFile2(this.manifestPath, "utf8");
|
|
281
|
+
const parsed = manifestSchema.safeParse(JSON.parse(raw));
|
|
282
|
+
if (!parsed.success) return emptyManifest();
|
|
283
|
+
return parsed.data;
|
|
284
|
+
} catch (error) {
|
|
285
|
+
if (error.code === "ENOENT") return emptyManifest();
|
|
286
|
+
return emptyManifest();
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
async write(manifest) {
|
|
290
|
+
await assertNoSymlinkBetween(this.repositoryRoot, dirname2(this.manifestPath));
|
|
291
|
+
await mkdir(this.cacheDirectory, { recursive: true, mode: 448 });
|
|
292
|
+
await writeAtomic(this.manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
293
|
+
`);
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
function emptyManifest() {
|
|
297
|
+
return { version: INDEX_MANIFEST_VERSION, generatedAt: (/* @__PURE__ */ new Date(0)).toISOString(), entries: {} };
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// src/map/cache.ts
|
|
301
|
+
var CACHE_VERSION = 1;
|
|
302
|
+
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py"]);
|
|
303
|
+
async function loadArchitectureMap(repositoryRoot = process.cwd(), suppliedManifest) {
|
|
304
|
+
const root = resolve3(repositoryRoot);
|
|
305
|
+
const manifest = suppliedManifest ?? await new IndexStore(root).read();
|
|
306
|
+
if (Object.keys(manifest.entries).length === 0) {
|
|
307
|
+
const map = await buildArchitectureMap(root);
|
|
308
|
+
return {
|
|
309
|
+
map,
|
|
310
|
+
stats: { readFiles: map.modules.length, reusedFiles: 0, rebuilt: true },
|
|
311
|
+
source: "fallback"
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
return refreshArchitectureCache(root, manifest);
|
|
315
|
+
}
|
|
316
|
+
async function refreshArchitectureCache(repositoryRoot, manifest) {
|
|
317
|
+
const root = resolve3(repositoryRoot);
|
|
318
|
+
const path = join3(root, ".codebuddy", "cache", "architecture.json");
|
|
319
|
+
const currentHashes = sourceHashes(manifest);
|
|
320
|
+
const currentPaths = Object.keys(currentHashes).sort();
|
|
321
|
+
const cached = await readCache(path);
|
|
322
|
+
const cachedPaths = cached ? Object.keys(cached.sourceHashes).sort() : [];
|
|
323
|
+
const fileSetChanged = cachedPaths.join("\n") !== currentPaths.join("\n");
|
|
324
|
+
const changedPaths = !cached || fileSetChanged ? currentPaths : currentPaths.filter(
|
|
325
|
+
(sourcePath) => cached.sourceHashes[sourcePath] !== currentHashes[sourcePath]
|
|
326
|
+
);
|
|
327
|
+
if (cached && changedPaths.length === 0) {
|
|
328
|
+
return {
|
|
329
|
+
map: cached.map,
|
|
330
|
+
stats: { readFiles: 0, reusedFiles: cached.map.modules.length, rebuilt: false },
|
|
331
|
+
source: "cache"
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
const updated = await updateArchitectureMap(
|
|
335
|
+
root,
|
|
336
|
+
currentPaths,
|
|
337
|
+
fileSetChanged ? null : cached?.map ?? null,
|
|
338
|
+
changedPaths
|
|
339
|
+
);
|
|
340
|
+
const next = {
|
|
341
|
+
version: CACHE_VERSION,
|
|
342
|
+
generatedAt: manifest.generatedAt,
|
|
343
|
+
sourceHashes: currentHashes,
|
|
344
|
+
map: updated.map
|
|
345
|
+
};
|
|
346
|
+
await assertNoSymlinkBetween(root, dirname3(path));
|
|
347
|
+
await mkdir2(dirname3(path), { recursive: true, mode: 448 });
|
|
348
|
+
await writeAtomic(path, `${JSON.stringify(next, null, 2)}
|
|
349
|
+
`);
|
|
350
|
+
return { ...updated, source: fileSetChanged || !cached ? "rebuild" : "incremental" };
|
|
351
|
+
}
|
|
352
|
+
async function readCache(path) {
|
|
353
|
+
try {
|
|
354
|
+
const parsed = JSON.parse(await readFile3(path, "utf8"));
|
|
355
|
+
if (parsed.version !== CACHE_VERSION || !parsed.map || !parsed.sourceHashes) return null;
|
|
356
|
+
if (!Array.isArray(parsed.map.modules) || !Array.isArray(parsed.map.edges)) return null;
|
|
357
|
+
if (!parsed.map.modules.every(
|
|
358
|
+
(module) => module && typeof module.path === "string" && typeof module.language === "string" && Array.isArray(module.imports)
|
|
359
|
+
) || !parsed.map.edges.every(
|
|
360
|
+
(edge) => edge && typeof edge.from === "string" && typeof edge.to === "string"
|
|
361
|
+
)) {
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
return parsed;
|
|
365
|
+
} catch {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
function sourceHashes(manifest) {
|
|
370
|
+
return Object.fromEntries(
|
|
371
|
+
Object.values(manifest.entries).filter((entry) => SOURCE_EXTENSIONS.has(extname2(entry.path).toLowerCase())).map((entry) => [entry.path, entry.hash])
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// src/indexer/scan.ts
|
|
376
|
+
import { spawn } from "child_process";
|
|
377
|
+
import { readdir as readdir2 } from "fs/promises";
|
|
378
|
+
import { extname as extname4, join as join4, relative as relative2, sep } from "path";
|
|
379
|
+
|
|
380
|
+
// src/indexer/summary.ts
|
|
381
|
+
import { extname as extname3 } from "path";
|
|
382
|
+
var LANGUAGE_BY_EXTENSION = {
|
|
383
|
+
".ts": "ts",
|
|
384
|
+
".tsx": "tsx",
|
|
385
|
+
".js": "js",
|
|
386
|
+
".jsx": "jsx",
|
|
387
|
+
".mjs": "js",
|
|
388
|
+
".cjs": "js",
|
|
389
|
+
".json": "json",
|
|
390
|
+
".md": "md",
|
|
391
|
+
".mdx": "md",
|
|
392
|
+
".rst": "rst",
|
|
393
|
+
".yaml": "yaml",
|
|
394
|
+
".yml": "yaml",
|
|
395
|
+
".toml": "toml",
|
|
396
|
+
".css": "css",
|
|
397
|
+
".scss": "scss",
|
|
398
|
+
".html": "html",
|
|
399
|
+
".py": "py",
|
|
400
|
+
".go": "go",
|
|
401
|
+
".rs": "rust",
|
|
402
|
+
".java": "java",
|
|
403
|
+
".rb": "ruby",
|
|
404
|
+
".php": "php",
|
|
405
|
+
".sh": "shell",
|
|
406
|
+
".sql": "sql",
|
|
407
|
+
".txt": "text"
|
|
408
|
+
};
|
|
409
|
+
var SUPPORTED_EXTENSIONS2 = new Set(Object.keys(LANGUAGE_BY_EXTENSION));
|
|
410
|
+
var CODE_LANGUAGES = /* @__PURE__ */ new Set(["ts", "tsx", "js", "jsx"]);
|
|
411
|
+
var SYMBOL_LIMIT = 8;
|
|
412
|
+
var SUMMARY_COMMENT_MAX = 80;
|
|
413
|
+
function languageFor(path) {
|
|
414
|
+
return LANGUAGE_BY_EXTENSION[extname3(path).toLowerCase()] ?? "text";
|
|
415
|
+
}
|
|
416
|
+
function summarizeSource(path, content) {
|
|
417
|
+
const language = languageFor(path);
|
|
418
|
+
const lines = countLines(content);
|
|
419
|
+
const symbols = CODE_LANGUAGES.has(language) ? extractSymbols(content) : language === "py" ? pythonPublicNames(content) : [];
|
|
420
|
+
const summary = composeSummary(language, lines, symbols, content);
|
|
421
|
+
return { language, lines, symbols, summary };
|
|
422
|
+
}
|
|
423
|
+
function countLines(content) {
|
|
424
|
+
if (content.length === 0) return 0;
|
|
425
|
+
return content.replace(/\r/g, "").replace(/\n$/, "").split("\n").length;
|
|
426
|
+
}
|
|
427
|
+
function extractSymbols(content) {
|
|
428
|
+
const names = [];
|
|
429
|
+
const push = (name) => {
|
|
430
|
+
const trimmed = name?.trim();
|
|
431
|
+
if (trimmed && /^[A-Za-z_$][\w$]*$/.test(trimmed) && !names.includes(trimmed)) {
|
|
432
|
+
names.push(trimmed);
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
const declaration = /^export\s+(?:default\s+)?(?:async\s+)?(?:abstract\s+)?(?:const|let|var|function|class|interface|type|enum)\s+([A-Za-z_$][\w$]*)/gm;
|
|
436
|
+
for (const match of content.matchAll(declaration)) push(match[1]);
|
|
437
|
+
const namedExports = /^export\s*\{([^}]*)\}/gm;
|
|
438
|
+
for (const match of content.matchAll(namedExports)) {
|
|
439
|
+
for (const part of (match[1] ?? "").split(",")) {
|
|
440
|
+
const alias = part.includes(" as ") ? part.split(" as ").pop() : part;
|
|
441
|
+
push(alias);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return names.slice(0, SYMBOL_LIMIT);
|
|
445
|
+
}
|
|
446
|
+
function pythonPublicNames(content) {
|
|
447
|
+
return extractSymbolTable(content, "x.py").filter((symbol) => symbol.exported && symbol.kind !== "method").map((symbol) => symbol.name).slice(0, SYMBOL_LIMIT);
|
|
448
|
+
}
|
|
449
|
+
function composeSummary(language, lines, symbols, content) {
|
|
450
|
+
const head = `${language} \u2022 ${lines} line${lines === 1 ? "" : "s"}`;
|
|
451
|
+
if (symbols.length > 0) return `${head} \u2022 exports ${symbols.join(", ")}`;
|
|
452
|
+
const comment = leadingComment(content);
|
|
453
|
+
if (comment) return `${head} \u2022 ${comment}`;
|
|
454
|
+
return head;
|
|
455
|
+
}
|
|
456
|
+
function leadingComment(content) {
|
|
457
|
+
for (const raw of content.split(/\r?\n/)) {
|
|
458
|
+
const line = raw.trim();
|
|
459
|
+
if (line === "") continue;
|
|
460
|
+
const stripped = line.replace(/^\/\/+/, "").replace(/^\/\*+/, "").replace(/\*+\/$/, "").replace(/^[#*]+/, "").trim();
|
|
461
|
+
if (line.startsWith("//") || line.startsWith("/*") || line.startsWith("#") || line.startsWith("*")) {
|
|
462
|
+
if (stripped) return truncate(stripped, SUMMARY_COMMENT_MAX);
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
function truncate(value, max) {
|
|
470
|
+
return value.length <= max ? value : `${value.slice(0, max - 1)}\u2026`;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/indexer/scan.ts
|
|
474
|
+
var FALLBACK_IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
475
|
+
".git",
|
|
476
|
+
"node_modules",
|
|
477
|
+
"dist",
|
|
478
|
+
"build",
|
|
479
|
+
"coverage",
|
|
480
|
+
".codebuddy",
|
|
481
|
+
"graphify-out",
|
|
482
|
+
".next",
|
|
483
|
+
".turbo",
|
|
484
|
+
"out",
|
|
485
|
+
".venv",
|
|
486
|
+
"venv",
|
|
487
|
+
"__pycache__"
|
|
488
|
+
]);
|
|
489
|
+
async function listIndexableFiles(repositoryRoot) {
|
|
490
|
+
const tracked = await gitListFiles(repositoryRoot);
|
|
491
|
+
const paths = tracked ?? await walkFiles(repositoryRoot);
|
|
492
|
+
return paths.map(normalize2).filter((path) => !path.startsWith(".codebuddy/") && !path.startsWith("graphify-out/")).filter((path) => SUPPORTED_EXTENSIONS2.has(extname4(path).toLowerCase())).sort();
|
|
493
|
+
}
|
|
494
|
+
async function gitListFiles(repositoryRoot) {
|
|
495
|
+
const result = await runGit(repositoryRoot, [
|
|
496
|
+
"ls-files",
|
|
497
|
+
"-z",
|
|
498
|
+
"--cached",
|
|
499
|
+
"--others",
|
|
500
|
+
"--exclude-standard"
|
|
501
|
+
]);
|
|
502
|
+
if (result.code !== 0) return null;
|
|
503
|
+
return result.stdout.split("\0").filter(Boolean);
|
|
504
|
+
}
|
|
505
|
+
async function walkFiles(root) {
|
|
506
|
+
const files = [];
|
|
507
|
+
const walk2 = async (directory) => {
|
|
508
|
+
const entries = await readdir2(directory, { withFileTypes: true });
|
|
509
|
+
for (const entry of entries) {
|
|
510
|
+
const absolute = join4(directory, entry.name);
|
|
511
|
+
if (entry.isDirectory()) {
|
|
512
|
+
if (FALLBACK_IGNORED_DIRECTORIES.has(entry.name)) continue;
|
|
513
|
+
await walk2(absolute);
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
if (entry.isFile()) files.push(relative2(root, absolute));
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
await walk2(root);
|
|
520
|
+
return files;
|
|
521
|
+
}
|
|
522
|
+
function runGit(cwd, args) {
|
|
523
|
+
return new Promise((resolveResult) => {
|
|
524
|
+
const child = spawn("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
525
|
+
let stdout = "";
|
|
526
|
+
let stderr = "";
|
|
527
|
+
child.stdout.setEncoding("utf8");
|
|
528
|
+
child.stdout.on("data", (chunk2) => {
|
|
529
|
+
stdout += String(chunk2);
|
|
530
|
+
});
|
|
531
|
+
child.stderr.on("data", (chunk2) => {
|
|
532
|
+
stderr += String(chunk2);
|
|
533
|
+
});
|
|
534
|
+
child.on("error", () => resolveResult({ code: -1, stdout: "", stderr: "git unavailable" }));
|
|
535
|
+
child.on("close", (code) => resolveResult({ code: code ?? 0, stdout, stderr }));
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
function normalize2(path) {
|
|
539
|
+
return (sep === "\\" ? path.replace(/\\/g, "/") : path).replace(/^\.\//, "");
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// src/indexer/engine.ts
|
|
543
|
+
var MAX_FILE_BYTES = 512e3;
|
|
544
|
+
var RACY_WINDOW_MS = 3e3;
|
|
545
|
+
async function indexRepository(options = {}) {
|
|
546
|
+
return (await refreshIndex(options)).result;
|
|
547
|
+
}
|
|
548
|
+
async function loadFreshIndex(repositoryRoot) {
|
|
549
|
+
try {
|
|
550
|
+
const { result, manifest } = await refreshIndex({ repositoryRoot });
|
|
551
|
+
const delta = result.added + result.changed + result.removed;
|
|
552
|
+
const failures = result.errors.length > 0 ? `; ${result.errors.length} file(s) could not be validated and were omitted` : "";
|
|
553
|
+
return {
|
|
554
|
+
manifest,
|
|
555
|
+
explain: delta === 0 ? `index: ${result.totalIndexed} indexed file(s) match current source${failures}` : `index: refreshed against current source (${result.changed} changed, ${result.added} added, ${result.removed} removed; ${result.totalIndexed} indexed)${failures}`
|
|
556
|
+
};
|
|
557
|
+
} catch (error) {
|
|
558
|
+
return {
|
|
559
|
+
manifest: emptyManifest(),
|
|
560
|
+
explain: `index: freshness check failed (${error.message}); indexed evidence omitted`
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
var passes = /* @__PURE__ */ new Map();
|
|
565
|
+
function refreshIndex(options) {
|
|
566
|
+
const key = resolve4(options.repositoryRoot ?? process.cwd());
|
|
567
|
+
const next = (passes.get(key) ?? Promise.resolve()).catch(() => void 0).then(() => runIndexPass(options));
|
|
568
|
+
passes.set(key, next);
|
|
569
|
+
void next.finally(() => {
|
|
570
|
+
if (passes.get(key) === next) passes.delete(key);
|
|
571
|
+
}).catch(() => void 0);
|
|
572
|
+
return next;
|
|
573
|
+
}
|
|
574
|
+
async function runIndexPass(options) {
|
|
575
|
+
const start = Date.now();
|
|
576
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
577
|
+
const repositoryRoot = resolve4(options.repositoryRoot ?? process.cwd());
|
|
578
|
+
const store = new IndexStore(repositoryRoot);
|
|
579
|
+
const [files, previous] = await Promise.all([listIndexableFiles(repositoryRoot), store.read()]);
|
|
580
|
+
const entries = {};
|
|
581
|
+
const errors = [];
|
|
582
|
+
let added = 0;
|
|
583
|
+
let changed = 0;
|
|
584
|
+
let unchanged = 0;
|
|
585
|
+
let skipped = 0;
|
|
586
|
+
let dirty = previous.generatedAt === emptyManifest().generatedAt;
|
|
587
|
+
for (const path of files) {
|
|
588
|
+
try {
|
|
589
|
+
const info = await stat2(join5(repositoryRoot, path));
|
|
590
|
+
if (!info.isFile()) continue;
|
|
591
|
+
if (info.size > MAX_FILE_BYTES) {
|
|
592
|
+
skipped++;
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
const existing = previous.entries[path];
|
|
596
|
+
if (!options.full && existing && statUnchanged(existing, info)) {
|
|
597
|
+
entries[path] = existing;
|
|
598
|
+
unchanged++;
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
const content = await readFile4(join5(repositoryRoot, path), "utf8");
|
|
602
|
+
const hash = hashContent(content);
|
|
603
|
+
const metadata = trustedMetadata(info);
|
|
604
|
+
dirty = true;
|
|
605
|
+
if (!options.full && existing && existing.hash === hash) {
|
|
606
|
+
const { mtimeMs: _mtime, ctimeMs: _ctime, ...rest } = existing;
|
|
607
|
+
entries[path] = { ...rest, size: info.size, ...metadata };
|
|
608
|
+
unchanged++;
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
const { language, lines, symbols, summary } = summarizeSource(path, content);
|
|
612
|
+
const symbolTable = supportsSymbols(path) ? extractSymbolTable(content, path) : [];
|
|
613
|
+
entries[path] = {
|
|
614
|
+
path,
|
|
615
|
+
hash,
|
|
616
|
+
size: info.size,
|
|
617
|
+
...metadata,
|
|
618
|
+
language,
|
|
619
|
+
lines,
|
|
620
|
+
symbols,
|
|
621
|
+
...symbolTable.length > 0 ? { symbolTable } : {},
|
|
622
|
+
summary,
|
|
623
|
+
indexedAt: now().toISOString()
|
|
624
|
+
};
|
|
625
|
+
if (existing) changed++;
|
|
626
|
+
else added++;
|
|
627
|
+
} catch (error) {
|
|
628
|
+
errors.push({ path, error: error.message });
|
|
629
|
+
skipped++;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
const removed = Object.keys(previous.entries).filter((path) => !(path in entries)).length;
|
|
633
|
+
const manifest = {
|
|
634
|
+
version: INDEX_MANIFEST_VERSION,
|
|
635
|
+
generatedAt: now().toISOString(),
|
|
636
|
+
entries: sortEntries(entries)
|
|
637
|
+
};
|
|
638
|
+
if (dirty || removed > 0) await store.write(manifest);
|
|
639
|
+
const architecture = await refreshArchitectureCache(repositoryRoot, manifest);
|
|
640
|
+
const result = {
|
|
641
|
+
scanned: files.length,
|
|
642
|
+
added,
|
|
643
|
+
changed,
|
|
644
|
+
unchanged,
|
|
645
|
+
removed,
|
|
646
|
+
skipped,
|
|
647
|
+
errors,
|
|
648
|
+
durationMs: Date.now() - start,
|
|
649
|
+
totalIndexed: Object.keys(entries).length,
|
|
650
|
+
architecture: {
|
|
651
|
+
source: architecture.source,
|
|
652
|
+
readFiles: architecture.stats.readFiles,
|
|
653
|
+
reusedFiles: architecture.stats.reusedFiles
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
return { result, manifest };
|
|
657
|
+
}
|
|
658
|
+
function statUnchanged(entry, info) {
|
|
659
|
+
return entry.mtimeMs !== void 0 && entry.size === info.size && entry.mtimeMs === info.mtimeMs && entry.ctimeMs === info.ctimeMs;
|
|
660
|
+
}
|
|
661
|
+
function trustedMetadata(info) {
|
|
662
|
+
if (Date.now() - Math.max(info.mtimeMs, info.ctimeMs) < RACY_WINDOW_MS) return {};
|
|
663
|
+
return { mtimeMs: info.mtimeMs, ctimeMs: info.ctimeMs };
|
|
664
|
+
}
|
|
665
|
+
function hashContent(content) {
|
|
666
|
+
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
667
|
+
}
|
|
668
|
+
function sortEntries(entries) {
|
|
669
|
+
return Object.fromEntries(
|
|
670
|
+
Object.keys(entries).sort().map((key) => [key, entries[key]])
|
|
671
|
+
);
|
|
672
|
+
}
|
|
673
|
+
|
|
18
674
|
// src/integrations/graphify.ts
|
|
19
675
|
import { execFile } from "child_process";
|
|
20
|
-
import { mkdir, mkdtemp, readFile as
|
|
676
|
+
import { mkdir as mkdir3, mkdtemp, readFile as readFile6, rm, stat as stat3, utimes } from "fs/promises";
|
|
21
677
|
import { tmpdir } from "os";
|
|
22
|
-
import { dirname, join, relative, resolve, sep } from "path";
|
|
678
|
+
import { dirname as dirname4, join as join6, relative as relative3, resolve as resolve5, sep as sep2 } from "path";
|
|
23
679
|
import { promisify } from "util";
|
|
24
680
|
|
|
25
681
|
// src/map/graph-freshness.ts
|
|
26
|
-
import { createHash } from "crypto";
|
|
27
|
-
import { readFile } from "fs/promises";
|
|
28
|
-
var digest = (value) =>
|
|
682
|
+
import { createHash as createHash2 } from "crypto";
|
|
683
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
684
|
+
var digest = (value) => createHash2("sha256").update(value).digest("hex");
|
|
29
685
|
async function writeGraphSourceSnapshot(path, manifest) {
|
|
30
686
|
await writeAtomic(
|
|
31
687
|
`${path}.sources.json`,
|
|
32
688
|
JSON.stringify({
|
|
33
689
|
version: 1,
|
|
34
|
-
graphHash: digest(await
|
|
690
|
+
graphHash: digest(await readFile5(path, "utf8")),
|
|
35
691
|
sources: Object.fromEntries(
|
|
36
692
|
Object.values(manifest.entries).map((entry) => [entry.path, entry.hash])
|
|
37
693
|
)
|
|
@@ -41,13 +697,13 @@ async function writeGraphSourceSnapshot(path, manifest) {
|
|
|
41
697
|
async function readGraphSourceSnapshot(path) {
|
|
42
698
|
let raw;
|
|
43
699
|
try {
|
|
44
|
-
raw = await
|
|
700
|
+
raw = await readFile5(`${path}.sources.json`, "utf8");
|
|
45
701
|
} catch (error) {
|
|
46
702
|
return error.code === "ENOENT" ? null : {};
|
|
47
703
|
}
|
|
48
704
|
try {
|
|
49
705
|
const snapshot = JSON.parse(raw);
|
|
50
|
-
if (snapshot.version !== 1 || snapshot.graphHash !== digest(await
|
|
706
|
+
if (snapshot.version !== 1 || snapshot.graphHash !== digest(await readFile5(path, "utf8")) || !snapshot.sources || typeof snapshot.sources !== "object" || Array.isArray(snapshot.sources))
|
|
51
707
|
return {};
|
|
52
708
|
return Object.fromEntries(
|
|
53
709
|
Object.entries(snapshot.sources).filter(
|
|
@@ -134,17 +790,17 @@ async function graphifyGraphExists(repositoryRoot, graphPath = DEFAULT_GRAPH_PAT
|
|
|
134
790
|
}
|
|
135
791
|
async function generateGraphifyGraph(options) {
|
|
136
792
|
const run = options.run ?? runCommand;
|
|
137
|
-
const repositoryRoot =
|
|
793
|
+
const repositoryRoot = resolve5(options.repositoryRoot);
|
|
138
794
|
const graphPath = options.graphPath ?? DEFAULT_GRAPH_PATH;
|
|
139
795
|
const destination = resolveGraphPath(repositoryRoot, graphPath);
|
|
140
|
-
await
|
|
141
|
-
await ignoreGeneratedGraphDirectory(
|
|
796
|
+
await mkdir3(dirname4(destination), { recursive: true });
|
|
797
|
+
await ignoreGeneratedGraphDirectory(dirname4(destination));
|
|
142
798
|
const { manifest: sourceSnapshot } = await loadFreshIndex(repositoryRoot);
|
|
143
799
|
const current = await readGraphFileIfPresent(destination);
|
|
144
800
|
const isDefaultPath = graphPath === DEFAULT_GRAPH_PATH;
|
|
145
801
|
if (current && isDefaultPath) {
|
|
146
|
-
const backup = await
|
|
147
|
-
const backupStat = await
|
|
802
|
+
const backup = await readFile6(destination, "utf8");
|
|
803
|
+
const backupStat = await stat3(destination);
|
|
148
804
|
try {
|
|
149
805
|
await run("graphify", ["update", repositoryRoot, "--force", "--no-cluster"], repositoryRoot);
|
|
150
806
|
const updated = await readGraphFile(destination);
|
|
@@ -158,16 +814,16 @@ async function generateGraphifyGraph(options) {
|
|
|
158
814
|
);
|
|
159
815
|
}
|
|
160
816
|
}
|
|
161
|
-
const stagingRoot = await mkdtemp(
|
|
817
|
+
const stagingRoot = await mkdtemp(join6(tmpdir(), "codebuddy-graphify-"));
|
|
162
818
|
try {
|
|
163
819
|
await run(
|
|
164
820
|
"graphify",
|
|
165
821
|
["extract", repositoryRoot, "--out", stagingRoot, "--code-only", "--no-cluster"],
|
|
166
822
|
repositoryRoot
|
|
167
823
|
);
|
|
168
|
-
const stagedPath =
|
|
824
|
+
const stagedPath = join6(stagingRoot, DEFAULT_GRAPH_PATH);
|
|
169
825
|
const staged = await readGraphFile(stagedPath);
|
|
170
|
-
await writeAtomic(destination, await
|
|
826
|
+
await writeAtomic(destination, await readFile6(stagedPath, "utf8"));
|
|
171
827
|
await writeGraphSourceSnapshot(destination, sourceSnapshot);
|
|
172
828
|
return { graphPath, generated: true, ...staged };
|
|
173
829
|
} finally {
|
|
@@ -175,17 +831,17 @@ async function generateGraphifyGraph(options) {
|
|
|
175
831
|
}
|
|
176
832
|
}
|
|
177
833
|
async function ignoreGeneratedGraphDirectory(directory) {
|
|
178
|
-
const path =
|
|
834
|
+
const path = join6(directory, ".gitignore");
|
|
179
835
|
try {
|
|
180
|
-
await
|
|
836
|
+
await stat3(path);
|
|
181
837
|
} catch {
|
|
182
838
|
await writeAtomic(path, "# CodeBuddy-generated Graphify output (derived, rebuildable)\n*\n");
|
|
183
839
|
}
|
|
184
840
|
}
|
|
185
841
|
function resolveGraphPath(repositoryRoot, graphPath) {
|
|
186
|
-
const absolute =
|
|
187
|
-
const relativePath =
|
|
188
|
-
if (relativePath === "" || relativePath === ".." || relativePath.startsWith(`..${
|
|
842
|
+
const absolute = resolve5(repositoryRoot, graphPath);
|
|
843
|
+
const relativePath = relative3(repositoryRoot, absolute);
|
|
844
|
+
if (relativePath === "" || relativePath === ".." || relativePath.startsWith(`..${sep2}`)) {
|
|
189
845
|
throw new Error(`Graph path must be inside the project root: ${graphPath}`);
|
|
190
846
|
}
|
|
191
847
|
return absolute;
|
|
@@ -198,10 +854,10 @@ async function readGraphFileIfPresent(path) {
|
|
|
198
854
|
}
|
|
199
855
|
}
|
|
200
856
|
async function readGraphFile(path) {
|
|
201
|
-
const info = await
|
|
857
|
+
const info = await stat3(path);
|
|
202
858
|
if (!info.isFile() || info.size === 0)
|
|
203
859
|
throw new Error(`Graphify graph is missing or empty: ${path}`);
|
|
204
|
-
const raw = JSON.parse(await
|
|
860
|
+
const raw = JSON.parse(await readFile6(path, "utf8"));
|
|
205
861
|
const nodes = arrayLength(raw.nodes ?? raw.entities);
|
|
206
862
|
const edges = arrayLength(raw.edges ?? raw.links ?? raw.relationships);
|
|
207
863
|
if (nodes === 0) throw new Error(`Graphify graph contains no nodes: ${path}`);
|
|
@@ -212,16 +868,16 @@ function arrayLength(value) {
|
|
|
212
868
|
}
|
|
213
869
|
|
|
214
870
|
// src/context/file-vectors.ts
|
|
215
|
-
import { mkdir as
|
|
216
|
-
import { dirname as
|
|
871
|
+
import { mkdir as mkdir5, readFile as readFile10 } from "fs/promises";
|
|
872
|
+
import { dirname as dirname6, join as join9 } from "path";
|
|
217
873
|
|
|
218
874
|
// src/context/discovery.ts
|
|
219
|
-
import { readFile as
|
|
220
|
-
import { isAbsolute as isAbsolute3, join as
|
|
875
|
+
import { readFile as readFile9, realpath, stat as stat4 } from "fs/promises";
|
|
876
|
+
import { isAbsolute as isAbsolute3, join as join8, relative as relative6 } from "path";
|
|
221
877
|
|
|
222
878
|
// src/map/graphify.ts
|
|
223
|
-
import { readFile as
|
|
224
|
-
import { isAbsolute, relative as
|
|
879
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
880
|
+
import { isAbsolute, relative as relative4, resolve as resolve6 } from "path";
|
|
225
881
|
var NON_DEPENDENCY_RELATIONS = /* @__PURE__ */ new Set([
|
|
226
882
|
"contains",
|
|
227
883
|
"part_of",
|
|
@@ -255,7 +911,7 @@ var DIRECT_DEPENDENCY_RELATIONS = /* @__PURE__ */ new Set([
|
|
|
255
911
|
]);
|
|
256
912
|
var MAX_EDGE_SYMBOLS = 8;
|
|
257
913
|
async function loadGraphifyMap(graphPath, repositoryRoot = process.cwd()) {
|
|
258
|
-
const raw = JSON.parse(await
|
|
914
|
+
const raw = JSON.parse(await readFile7(graphPath, "utf8"));
|
|
259
915
|
const nodes = arrayRecord(raw.nodes ?? raw.entities);
|
|
260
916
|
const edges = arrayRecord(raw.edges ?? raw.links ?? raw.relationships);
|
|
261
917
|
const nodePaths = /* @__PURE__ */ new Map();
|
|
@@ -268,7 +924,7 @@ async function loadGraphifyMap(graphPath, repositoryRoot = process.cwd()) {
|
|
|
268
924
|
nodePaths.set(id, path);
|
|
269
925
|
const label = stringValue(node.label ?? node.name);
|
|
270
926
|
if (label && label !== path && !path.endsWith(`/${label}`)) nodeLabels.set(id, label);
|
|
271
|
-
modules.push({ path, language:
|
|
927
|
+
modules.push({ path, language: languageFor2(path), imports: [] });
|
|
272
928
|
}
|
|
273
929
|
const modulePaths = new Set(modules.map((module) => module.path));
|
|
274
930
|
const importedEdges = [];
|
|
@@ -348,21 +1004,21 @@ function graphifyPath(node, repositoryRoot) {
|
|
|
348
1004
|
return candidate ? normalizeGraphPath(candidate, repositoryRoot) : null;
|
|
349
1005
|
}
|
|
350
1006
|
function normalizeGraphPath(path, repositoryRoot) {
|
|
351
|
-
const absolute = isAbsolute(path) ?
|
|
352
|
-
const relativePath =
|
|
1007
|
+
const absolute = isAbsolute(path) ? resolve6(path) : resolve6(repositoryRoot, path);
|
|
1008
|
+
const relativePath = relative4(resolve6(repositoryRoot), absolute).replace(/\\/g, "/");
|
|
353
1009
|
if (relativePath === "" || relativePath === ".." || relativePath.startsWith("../")) return null;
|
|
354
1010
|
return relativePath.replace(/^\.\//, "");
|
|
355
1011
|
}
|
|
356
1012
|
function stringValue(value) {
|
|
357
1013
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
358
1014
|
}
|
|
359
|
-
function
|
|
1015
|
+
function languageFor2(path) {
|
|
360
1016
|
if (/\.py$/.test(path)) return "py";
|
|
361
1017
|
return /\.tsx?$/.test(path) ? "ts" : "js";
|
|
362
1018
|
}
|
|
363
1019
|
|
|
364
1020
|
// src/context/anchors.ts
|
|
365
|
-
import { isAbsolute as isAbsolute2, relative as
|
|
1021
|
+
import { isAbsolute as isAbsolute2, relative as relative5, resolve as resolve7, sep as sep3 } from "path";
|
|
366
1022
|
var MAX_ANCHORS = 3;
|
|
367
1023
|
var MAX_ERROR_SEARCH_FILES = 2e3;
|
|
368
1024
|
var JS_FRAME = /\bat\s+(?:[^\s()]+\s+\()?([^\s()]+?):(\d+):\d+\)?/g;
|
|
@@ -370,7 +1026,7 @@ var PY_FRAME = /\bFile\s+"([^"]+)",\s+line\s+(\d+)/g;
|
|
|
370
1026
|
var PATH_TOKEN = /(?:^|[\s(`'"[])((?:\.{0,2}\/)?[\w@.-]+(?:\/[\w@.-]+)*\.[A-Za-z0-9]+)(?::(\d+))?/g;
|
|
371
1027
|
var QUOTED = /"([^"\n]{8,200})"|'([^'\n]{8,200})'|`([^`\n]{8,200})`/g;
|
|
372
1028
|
async function extractTaskAnchors(repositoryRoot, task, paths) {
|
|
373
|
-
const root =
|
|
1029
|
+
const root = resolve7(repositoryRoot);
|
|
374
1030
|
const found = [];
|
|
375
1031
|
const add = (raw, line, kind, at) => {
|
|
376
1032
|
const path = toIndexedPath(root, raw, paths);
|
|
@@ -398,9 +1054,9 @@ async function extractTaskAnchors(repositoryRoot, task, paths) {
|
|
|
398
1054
|
return anchors.slice(0, MAX_ANCHORS);
|
|
399
1055
|
}
|
|
400
1056
|
function toIndexedPath(root, raw, paths) {
|
|
401
|
-
const absolute = isAbsolute2(raw) ? raw :
|
|
402
|
-
const rel =
|
|
403
|
-
if (rel === "" || rel.startsWith(`..${
|
|
1057
|
+
const absolute = isAbsolute2(raw) ? raw : resolve7(root, raw);
|
|
1058
|
+
const rel = relative5(root, absolute);
|
|
1059
|
+
if (rel === "" || rel.startsWith(`..${sep3}`) || rel === ".." || isAbsolute2(rel)) return null;
|
|
404
1060
|
const normalized = rel.replace(/\\/g, "/");
|
|
405
1061
|
return paths.has(normalized) ? normalized : null;
|
|
406
1062
|
}
|
|
@@ -426,8 +1082,8 @@ async function errorAnchors(root, task, paths) {
|
|
|
426
1082
|
}
|
|
427
1083
|
|
|
428
1084
|
// src/context/content-index.ts
|
|
429
|
-
import { mkdir as
|
|
430
|
-
import { dirname as
|
|
1085
|
+
import { mkdir as mkdir4, readFile as readFile8 } from "fs/promises";
|
|
1086
|
+
import { dirname as dirname5, join as join7 } from "path";
|
|
431
1087
|
var PASSAGE_LINES = 40;
|
|
432
1088
|
var K1 = 1.2;
|
|
433
1089
|
var B = 0.75;
|
|
@@ -520,11 +1176,11 @@ function idfCoverage(text, terms, idf) {
|
|
|
520
1176
|
return terms.reduce((sum, term) => sum + (words.has(term) ? idf.get(term) ?? 0 : 0), 0) / total;
|
|
521
1177
|
}
|
|
522
1178
|
function cachePath(repositoryRoot) {
|
|
523
|
-
return
|
|
1179
|
+
return join7(repositoryRoot, ".codebuddy", "cache", "content-terms.json");
|
|
524
1180
|
}
|
|
525
1181
|
async function loadCache(repositoryRoot) {
|
|
526
1182
|
try {
|
|
527
|
-
const parsed = JSON.parse(await
|
|
1183
|
+
const parsed = JSON.parse(await readFile8(cachePath(repositoryRoot), "utf8"));
|
|
528
1184
|
if (parsed.version === 2 && parsed.files && typeof parsed.files === "object") return parsed;
|
|
529
1185
|
} catch {
|
|
530
1186
|
}
|
|
@@ -533,7 +1189,7 @@ async function loadCache(repositoryRoot) {
|
|
|
533
1189
|
async function saveCache(repositoryRoot, cache) {
|
|
534
1190
|
try {
|
|
535
1191
|
const path = cachePath(repositoryRoot);
|
|
536
|
-
await
|
|
1192
|
+
await mkdir4(dirname5(path), { recursive: true });
|
|
537
1193
|
await writeAtomic(path, JSON.stringify(cache));
|
|
538
1194
|
} catch {
|
|
539
1195
|
}
|
|
@@ -547,15 +1203,16 @@ var MAX_EVIDENCE_BYTES = 512e3;
|
|
|
547
1203
|
async function readBoundedSource(repositoryRoot, path) {
|
|
548
1204
|
if (isCredentialPath(path)) return null;
|
|
549
1205
|
try {
|
|
550
|
-
const absolute =
|
|
551
|
-
if ((await
|
|
552
|
-
const source = await
|
|
1206
|
+
const absolute = join8(repositoryRoot, path);
|
|
1207
|
+
if ((await stat4(absolute)).size > MAX_EVIDENCE_BYTES) return null;
|
|
1208
|
+
const source = await readFile9(absolute, "utf8");
|
|
553
1209
|
return source.includes("\0") ? null : source;
|
|
554
1210
|
} catch {
|
|
555
1211
|
return null;
|
|
556
1212
|
}
|
|
557
1213
|
}
|
|
558
1214
|
async function discoverTaskPaths(repositoryRoot, task, manifest, mapSource, options = {}) {
|
|
1215
|
+
task = stripIssueTemplate(task);
|
|
559
1216
|
const anchors = await extractTaskAnchors(
|
|
560
1217
|
repositoryRoot,
|
|
561
1218
|
task,
|
|
@@ -597,7 +1254,7 @@ async function withLlmSummaries(repositoryRoot, manifest) {
|
|
|
597
1254
|
const { resolveLlmConfig } = await import("./config-GEZFLXK6.js");
|
|
598
1255
|
const config = await resolveLlmConfig(repositoryRoot);
|
|
599
1256
|
if (!config.enabled || !config.features.summaries) return entries;
|
|
600
|
-
const { loadLlmSummaries } = await import("./summaries-
|
|
1257
|
+
const { loadLlmSummaries } = await import("./summaries-32PHOB6L.js");
|
|
601
1258
|
const summaries = await loadLlmSummaries(repositoryRoot, manifest);
|
|
602
1259
|
if (summaries.size === 0) return entries;
|
|
603
1260
|
return entries.map((entry) => {
|
|
@@ -614,9 +1271,13 @@ async function rankTaskFiles(repositoryRoot, task, manifest, mapSource, options)
|
|
|
614
1271
|
(entry) => wantsChangelog || !CHANGELOG_PATH.test(entry.path)
|
|
615
1272
|
);
|
|
616
1273
|
const wantsTests = /\b(tests?|spec)\b/i.test(task);
|
|
617
|
-
const identifiers = identifierTokens(task).filter(
|
|
1274
|
+
const identifiers = identifierTokens(task).filter(
|
|
1275
|
+
(token) => CODE_IDENTIFIER.test(token) && !ABBREVIATION.test(token)
|
|
1276
|
+
);
|
|
618
1277
|
if (identifiers.length > 0) {
|
|
619
|
-
const exact = entries.filter(
|
|
1278
|
+
const exact = entries.filter(
|
|
1279
|
+
(entry) => (wantsTests || !TEST_PATH.test(entry.path)) && countsAsSource(entry.path, task) && !EXCEPTION_MODULE.test(entry.path)
|
|
1280
|
+
).map((entry) => ({
|
|
620
1281
|
path: entry.path,
|
|
621
1282
|
named: new Set(
|
|
622
1283
|
(entry.symbolTable ?? []).flatMap(
|
|
@@ -664,7 +1325,7 @@ async function rankTaskFiles(repositoryRoot, task, manifest, mapSource, options)
|
|
|
664
1325
|
reason: "semantic retrieval off",
|
|
665
1326
|
stale: 0,
|
|
666
1327
|
changed: 0
|
|
667
|
-
} : await import("./zvec-
|
|
1328
|
+
} : await import("./zvec-24HLAFGN.js").then(
|
|
668
1329
|
({ zvecCandidates }) => zvecCandidates(
|
|
669
1330
|
repositoryRoot,
|
|
670
1331
|
task,
|
|
@@ -888,7 +1549,7 @@ async function commandFiles(repositoryRoot, task, entries) {
|
|
|
888
1549
|
var COMMAND_DIR = /(^|\/)(cli|cmd|commands?)\//;
|
|
889
1550
|
async function packageBins(repositoryRoot) {
|
|
890
1551
|
try {
|
|
891
|
-
const manifest = JSON.parse(await
|
|
1552
|
+
const manifest = JSON.parse(await readFile9(join8(repositoryRoot, "package.json"), "utf8"));
|
|
892
1553
|
if (typeof manifest.bin === "string" && typeof manifest.name === "string") {
|
|
893
1554
|
return [manifest.name.slice(manifest.name.lastIndexOf("/") + 1)];
|
|
894
1555
|
}
|
|
@@ -1058,6 +1719,17 @@ function foldPlural(word) {
|
|
|
1058
1719
|
if (/(ss|sh|ch|x|z)es$/.test(word)) return word.slice(0, -2);
|
|
1059
1720
|
return word.slice(0, -1);
|
|
1060
1721
|
}
|
|
1722
|
+
var ISSUE_TEMPLATE = [
|
|
1723
|
+
/_No response_/gi,
|
|
1724
|
+
/\(Please specify[^)]*\)/gi,
|
|
1725
|
+
/-\s*\[[ xX]\]\s*[\w.+-]+/g,
|
|
1726
|
+
/\d+\.\s*(?:Go to|Click on|Scroll down to)\s*'\.+'|\bSee error\b/gi,
|
|
1727
|
+
/#{1,6}\s*[\w-]+ Version\b(?:\s*v?\d+(?:\.\d+)+[\w.-]*,?)*/gi,
|
|
1728
|
+
/#{1,6}\s*(?:Description|Summary|URL to code causing the issue|MCVE|Minimal reproducible example|Steps to reproduce|Expected behaviou?r|Actual behaviou?r|Screenshots|Logs|Environment|Platform|Additional context)\b/gi
|
|
1729
|
+
];
|
|
1730
|
+
function stripIssueTemplate(task) {
|
|
1731
|
+
return ISSUE_TEMPLATE.reduce((text, pattern) => text.replace(pattern, " "), task);
|
|
1732
|
+
}
|
|
1061
1733
|
function taskTerms(task) {
|
|
1062
1734
|
return [
|
|
1063
1735
|
...new Set(
|
|
@@ -1070,6 +1742,8 @@ function countTerms(text, terms) {
|
|
|
1070
1742
|
const words = new Set(splitWords(text));
|
|
1071
1743
|
return terms.filter((term) => words.has(term)).length;
|
|
1072
1744
|
}
|
|
1745
|
+
var ABBREVIATION = /^[a-z](?:\.[a-z])+$/i;
|
|
1746
|
+
var EXCEPTION_MODULE = /(^|\/)(exceptions?|errors?)(\/|\.[a-z]+$)/i;
|
|
1073
1747
|
var CODE_IDENTIFIER = /[a-z0-9][A-Z]|[_$.]/;
|
|
1074
1748
|
function identifierTokens(task) {
|
|
1075
1749
|
const tokens = task.match(/[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*/g) ?? [];
|
|
@@ -1083,24 +1757,24 @@ async function loadProjectArchitectureMap(repositoryRoot, manifestSource) {
|
|
|
1083
1757
|
const builtIn = (await loadArchitectureMap(repositoryRoot, manifest)).map;
|
|
1084
1758
|
if (config.graphify?.enabled && await graphifyGraphExists(repositoryRoot, config.graphify.graphPath)) {
|
|
1085
1759
|
try {
|
|
1086
|
-
const graphPath =
|
|
1760
|
+
const graphPath = join8(
|
|
1087
1761
|
repositoryRoot,
|
|
1088
1762
|
config.graphify.graphPath ?? "graphify-out/graph.json"
|
|
1089
1763
|
);
|
|
1090
|
-
const [graph, graphFile,
|
|
1764
|
+
const [graph, graphFile, sourceHashes2] = await Promise.all([
|
|
1091
1765
|
loadGraphifyMap(graphPath, repositoryRoot),
|
|
1092
|
-
|
|
1766
|
+
stat4(graphPath),
|
|
1093
1767
|
readGraphSourceSnapshot(graphPath)
|
|
1094
1768
|
]);
|
|
1095
1769
|
const livePaths = new Set(
|
|
1096
1770
|
(await Promise.all(
|
|
1097
1771
|
graph.modules.map(async (module) => {
|
|
1098
1772
|
try {
|
|
1099
|
-
const absolute = await realpath(
|
|
1100
|
-
const inside =
|
|
1773
|
+
const absolute = await realpath(join8(repositoryRoot, module.path));
|
|
1774
|
+
const inside = relative6(await realpath(repositoryRoot), absolute);
|
|
1101
1775
|
if (inside.startsWith("..") || isAbsolute3(inside)) return null;
|
|
1102
|
-
const source = await
|
|
1103
|
-
const fresh =
|
|
1776
|
+
const source = await stat4(absolute);
|
|
1777
|
+
const fresh = sourceHashes2 === null ? source.mtimeMs <= graphFile.mtimeMs : sourceHashes2[module.path] !== void 0 && sourceHashes2[module.path] === manifest.entries[module.path]?.hash;
|
|
1104
1778
|
return source.isFile() && fresh ? module.path : null;
|
|
1105
1779
|
} catch {
|
|
1106
1780
|
return null;
|
|
@@ -1251,11 +1925,11 @@ function dot(left, right) {
|
|
|
1251
1925
|
return sum;
|
|
1252
1926
|
}
|
|
1253
1927
|
function storePath(repositoryRoot) {
|
|
1254
|
-
return
|
|
1928
|
+
return join9(repositoryRoot, ".codebuddy", "cache", "file-vectors.json");
|
|
1255
1929
|
}
|
|
1256
1930
|
async function loadStore(repositoryRoot) {
|
|
1257
1931
|
try {
|
|
1258
|
-
const parsed = JSON.parse(await
|
|
1932
|
+
const parsed = JSON.parse(await readFile10(storePath(repositoryRoot), "utf8"));
|
|
1259
1933
|
if (parsed.version === 1 && parsed.model === MODEL && parsed.files) return parsed;
|
|
1260
1934
|
} catch {
|
|
1261
1935
|
}
|
|
@@ -1263,11 +1937,17 @@ async function loadStore(repositoryRoot) {
|
|
|
1263
1937
|
}
|
|
1264
1938
|
async function saveStore(repositoryRoot, store) {
|
|
1265
1939
|
const path = storePath(repositoryRoot);
|
|
1266
|
-
await
|
|
1940
|
+
await mkdir5(dirname6(path), { recursive: true });
|
|
1267
1941
|
await writeAtomic(path, JSON.stringify(store));
|
|
1268
1942
|
}
|
|
1269
1943
|
|
|
1270
1944
|
export {
|
|
1945
|
+
buildArchitectureMap,
|
|
1946
|
+
queryMap,
|
|
1947
|
+
neighbours,
|
|
1948
|
+
indexRepository,
|
|
1949
|
+
loadFreshIndex,
|
|
1950
|
+
hashContent,
|
|
1271
1951
|
setupGraphify,
|
|
1272
1952
|
generateGraphifyGraph,
|
|
1273
1953
|
loadGraphifyMap,
|
|
@@ -1284,4 +1964,4 @@ export {
|
|
|
1284
1964
|
namedSegments,
|
|
1285
1965
|
loadProjectArchitectureMap
|
|
1286
1966
|
};
|
|
1287
|
-
//# sourceMappingURL=chunk-
|
|
1967
|
+
//# sourceMappingURL=chunk-YNSTIMCF.js.map
|