@orquentra/codebuddy 2.9.0 → 2.15.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/ARCHITECTURE.md +98 -0
- package/CLAUDE_CODEX.md +33 -0
- package/README.md +114 -9
- package/dist/{adapters-S4HHTWJW.js → adapters-OJRSVFV3.js} +2 -2
- package/dist/{chunk-GXOML4UZ.js → chunk-4BSO3HST.js} +126 -18
- package/dist/chunk-4BSO3HST.js.map +1 -0
- package/dist/{chunk-CAEPHLHC.js → chunk-57642NGU.js} +2 -44
- package/dist/chunk-57642NGU.js.map +1 -0
- package/dist/{chunk-ESZXCZIN.js → chunk-6YI2D5F5.js} +33 -5
- package/dist/chunk-6YI2D5F5.js.map +1 -0
- package/dist/{chunk-GKNYMNFM.js → chunk-7IPSDDO5.js} +10 -3
- package/dist/chunk-7IPSDDO5.js.map +1 -0
- package/dist/chunk-BTTQWSDS.js +372 -0
- package/dist/chunk-BTTQWSDS.js.map +1 -0
- package/dist/{chunk-2WH2Q4TA.js → chunk-D5E7SGI5.js} +304 -77
- package/dist/chunk-D5E7SGI5.js.map +1 -0
- package/dist/chunk-EMWGLKPR.js +45 -0
- package/dist/chunk-EMWGLKPR.js.map +1 -0
- package/dist/chunk-GQKWUHMA.js +20 -0
- package/dist/chunk-GQKWUHMA.js.map +1 -0
- package/dist/chunk-ITXE27SZ.js +358 -0
- package/dist/chunk-ITXE27SZ.js.map +1 -0
- package/dist/{chunk-UK6XTS2Y.js → chunk-JJQDVGF7.js} +23 -23
- package/dist/chunk-JJQDVGF7.js.map +1 -0
- package/dist/{chunk-F4BJ3DXW.js → chunk-KQCP3ZYH.js} +1273 -331
- package/dist/chunk-KQCP3ZYH.js.map +1 -0
- package/dist/{chunk-QN76UJP7.js → chunk-KYRM3HPP.js} +89 -21
- package/dist/chunk-KYRM3HPP.js.map +1 -0
- package/dist/{chunk-KNR2P2UY.js → chunk-M75SN4D4.js} +19 -4
- package/dist/chunk-M75SN4D4.js.map +1 -0
- package/dist/{chunk-J4T6HHI4.js → chunk-RZ266NHE.js} +538 -317
- package/dist/chunk-RZ266NHE.js.map +1 -0
- package/dist/chunk-U7KDM62P.js +43 -0
- package/dist/chunk-U7KDM62P.js.map +1 -0
- package/dist/chunk-UATJCD2T.js +368 -0
- package/dist/chunk-UATJCD2T.js.map +1 -0
- package/dist/{chunk-ENKDFLOO.js → chunk-UOTKHSQ5.js} +25 -8
- package/dist/chunk-UOTKHSQ5.js.map +1 -0
- package/dist/{chunk-TLWGZVPC.js → chunk-UR3DF74I.js} +1007 -132
- package/dist/chunk-UR3DF74I.js.map +1 -0
- package/dist/chunk-UTPC66MV.js +128 -0
- package/dist/chunk-UTPC66MV.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-WHKXUXHE.js +156 -0
- package/dist/chunk-WHKXUXHE.js.map +1 -0
- package/dist/{chunk-SRA4MDVG.js → chunk-YMXFSHXT.js} +978 -950
- package/dist/chunk-YMXFSHXT.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/config-TXQJCCVI.js +15 -0
- package/dist/expand-KWYGNCKZ.js +98 -0
- package/dist/expand-KWYGNCKZ.js.map +1 -0
- package/dist/file-vectors-MKXTSGGH.js +19 -0
- package/dist/index-facts-4MTEHKMN.js +38 -0
- package/dist/index-pass-TBDUEZCB.js +14 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +25 -23
- package/dist/install-E3JWINTN.js +31 -0
- package/dist/langgraph/index.d.ts +1 -1
- package/dist/lean-MLTAFS5L.js +29 -0
- package/dist/local-75DJECVR.js +48 -0
- package/dist/local-llm-MECVJTVU.js +19 -0
- package/dist/{main-YJKSYFPT.js → main-RLMKQZW4.js} +999 -328
- package/dist/main-RLMKQZW4.js.map +1 -0
- package/dist/{memory-TGHVTBME.js → memory-PFFVMTCH.js} +9 -6
- package/dist/{memory-TGHVTBME.js.map → memory-PFFVMTCH.js.map} +1 -1
- package/dist/{operations-OG4ISWIM.js → operations-STR7S5UO.js} +8 -7
- package/dist/operations-STR7S5UO.js.map +1 -0
- package/dist/{pretool-command-PRFOIHMW.js → pretool-command-B5GY5T6E.js} +2 -2
- package/dist/pretool-command-B5GY5T6E.js.map +1 -0
- package/dist/prompt-gate-TDTFFQW2.js +8 -0
- package/dist/prompt-gate-TDTFFQW2.js.map +1 -0
- package/dist/{rerank-IQAEWLQR.js → rerank-XXKWDI5Q.js} +7 -4
- package/dist/{rerank-IQAEWLQR.js.map → rerank-XXKWDI5Q.js.map} +1 -1
- package/dist/{runtime-GCSEIAVD.js → runtime-SWFWGTQ4.js} +18 -9
- package/dist/runtime-SWFWGTQ4.js.map +1 -0
- package/dist/summaries-QXWFFDUZ.js +31 -0
- package/dist/summaries-QXWFFDUZ.js.map +1 -0
- package/dist/{zvec-XDZNZ2OL.js → zvec-F73IBWO5.js} +13 -6
- package/dist/zvec-F73IBWO5.js.map +1 -0
- package/package.json +13 -3
- package/dist/chunk-2WH2Q4TA.js.map +0 -1
- package/dist/chunk-6NZEZJYD.js +0 -206
- package/dist/chunk-6NZEZJYD.js.map +0 -1
- package/dist/chunk-CAEPHLHC.js.map +0 -1
- package/dist/chunk-ENKDFLOO.js.map +0 -1
- package/dist/chunk-ESZXCZIN.js.map +0 -1
- package/dist/chunk-F4BJ3DXW.js.map +0 -1
- package/dist/chunk-GKNYMNFM.js.map +0 -1
- package/dist/chunk-GXOML4UZ.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-KNR2P2UY.js.map +0 -1
- package/dist/chunk-QN76UJP7.js.map +0 -1
- package/dist/chunk-SFMIMLXR.js +0 -63
- package/dist/chunk-SFMIMLXR.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/config-GEZFLXK6.js +0 -12
- 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/summaries-ML53R7EL.js +0 -21
- /package/dist/{adapters-S4HHTWJW.js.map → adapters-OJRSVFV3.js.map} +0 -0
- /package/dist/{config-GEZFLXK6.js.map → config-TXQJCCVI.js.map} +0 -0
- /package/dist/{install-BXM56QCD.js.map → file-vectors-MKXTSGGH.js.map} +0 -0
- /package/dist/{lean-command-7DFW32MA.js.map → index-facts-4MTEHKMN.js.map} +0 -0
- /package/dist/{operations-OG4ISWIM.js.map → index-pass-TBDUEZCB.js.map} +0 -0
- /package/dist/{pretool-command-PRFOIHMW.js.map → install-E3JWINTN.js.map} +0 -0
- /package/dist/{runtime-GCSEIAVD.js.map → lean-MLTAFS5L.js.map} +0 -0
- /package/dist/{summaries-ML53R7EL.js.map → local-75DJECVR.js.map} +0 -0
- /package/dist/{zvec-XDZNZ2OL.js.map → local-llm-MECVJTVU.js.map} +0 -0
package/dist/chunk-ITQO632W.js
DELETED
|
@@ -1,673 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
extractPythonImports,
|
|
3
|
-
extractSymbolTable,
|
|
4
|
-
supportsSymbols
|
|
5
|
-
} from "./chunk-Y7D7PUBE.js";
|
|
6
|
-
import {
|
|
7
|
-
assertNoSymlinkBetween,
|
|
8
|
-
writeAtomic
|
|
9
|
-
} from "./chunk-CG5B3LYG.js";
|
|
10
|
-
|
|
11
|
-
// src/map/indexer.ts
|
|
12
|
-
import { readdir, readFile, stat } from "fs/promises";
|
|
13
|
-
import { dirname, extname, join, relative, resolve } from "path";
|
|
14
|
-
var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py"]);
|
|
15
|
-
var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
16
|
-
".git",
|
|
17
|
-
"node_modules",
|
|
18
|
-
"dist",
|
|
19
|
-
"build",
|
|
20
|
-
"coverage",
|
|
21
|
-
".codebuddy",
|
|
22
|
-
// Python virtualenvs and caches would otherwise map site-packages.
|
|
23
|
-
".venv",
|
|
24
|
-
"venv",
|
|
25
|
-
".tox",
|
|
26
|
-
"__pycache__"
|
|
27
|
-
]);
|
|
28
|
-
async function buildArchitectureMap(repositoryRoot = process.cwd()) {
|
|
29
|
-
const root = resolve(repositoryRoot);
|
|
30
|
-
const files = await listSourceFiles(root);
|
|
31
|
-
const fileSet = new Set(files.map((file) => normalize(relative(root, file))));
|
|
32
|
-
const modules = [];
|
|
33
|
-
const edges = [];
|
|
34
|
-
for (const absolutePath of files) {
|
|
35
|
-
const source = await readFile(absolutePath, "utf8");
|
|
36
|
-
const from = normalize(relative(root, absolutePath));
|
|
37
|
-
const resolvedImports = moduleImports(root, from, source, fileSet);
|
|
38
|
-
edges.push(...resolvedImports.map(({ to, kind }) => ({ from, to, kind })));
|
|
39
|
-
modules.push({
|
|
40
|
-
path: from,
|
|
41
|
-
language: moduleLanguage(from),
|
|
42
|
-
imports: [...new Set(resolvedImports.map(({ to }) => to))].sort()
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
return {
|
|
46
|
-
modules: modules.sort((left, right) => left.path.localeCompare(right.path)),
|
|
47
|
-
edges: edges.sort(
|
|
48
|
-
(left, right) => `${left.from}:${left.to}`.localeCompare(`${right.from}:${right.to}`)
|
|
49
|
-
)
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
async function updateArchitectureMap(repositoryRoot, sourcePaths, previous, changedPaths) {
|
|
53
|
-
const root = resolve(repositoryRoot);
|
|
54
|
-
const normalizedPaths = sourcePaths.map(normalize).sort();
|
|
55
|
-
const fileSet = new Set(normalizedPaths);
|
|
56
|
-
const changed = new Set(changedPaths.map(normalize));
|
|
57
|
-
const retainedModules = (previous?.modules ?? []).filter(
|
|
58
|
-
(module) => fileSet.has(module.path) && !changed.has(module.path)
|
|
59
|
-
);
|
|
60
|
-
const retainedEdges = (previous?.edges ?? []).filter(
|
|
61
|
-
(edge) => fileSet.has(edge.from) && fileSet.has(edge.to) && !changed.has(edge.from)
|
|
62
|
-
);
|
|
63
|
-
const modules = [...retainedModules];
|
|
64
|
-
const edges = [...retainedEdges];
|
|
65
|
-
for (const path of normalizedPaths) {
|
|
66
|
-
if (!changed.has(path)) continue;
|
|
67
|
-
const source = await readFile(join(root, path), "utf8");
|
|
68
|
-
const resolvedImports = moduleImports(root, path, source, fileSet);
|
|
69
|
-
edges.push(...resolvedImports.map(({ to, kind }) => ({ from: path, to, kind })));
|
|
70
|
-
modules.push({
|
|
71
|
-
path,
|
|
72
|
-
language: moduleLanguage(path),
|
|
73
|
-
imports: [...new Set(resolvedImports.map(({ to }) => to))].sort()
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
return {
|
|
77
|
-
map: {
|
|
78
|
-
modules: modules.sort((left, right) => left.path.localeCompare(right.path)),
|
|
79
|
-
edges: edges.sort(
|
|
80
|
-
(left, right) => `${left.from}:${left.to}`.localeCompare(`${right.from}:${right.to}`)
|
|
81
|
-
)
|
|
82
|
-
},
|
|
83
|
-
stats: {
|
|
84
|
-
readFiles: changed.size,
|
|
85
|
-
reusedFiles: retainedModules.length,
|
|
86
|
-
rebuilt: previous === null || changed.size === normalizedPaths.length
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
function queryMap(map, query) {
|
|
91
|
-
const limit = query.limit ?? 50;
|
|
92
|
-
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);
|
|
93
|
-
}
|
|
94
|
-
function neighbours(map, modulePath, direction = "both") {
|
|
95
|
-
const target = normalize(modulePath);
|
|
96
|
-
const edges = map.edges.filter((edge) => {
|
|
97
|
-
if (direction === "in") return edge.to === target;
|
|
98
|
-
if (direction === "out") return edge.from === target;
|
|
99
|
-
return edge.from === target || edge.to === target;
|
|
100
|
-
});
|
|
101
|
-
const paths = /* @__PURE__ */ new Set([target]);
|
|
102
|
-
for (const edge of edges) {
|
|
103
|
-
paths.add(edge.from);
|
|
104
|
-
paths.add(edge.to);
|
|
105
|
-
}
|
|
106
|
-
return {
|
|
107
|
-
modules: map.modules.filter((module) => paths.has(module.path)),
|
|
108
|
-
edges
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
async function listSourceFiles(root) {
|
|
112
|
-
const files = [];
|
|
113
|
-
await walk(root, files);
|
|
114
|
-
return files.sort();
|
|
115
|
-
}
|
|
116
|
-
async function walk(directory, files) {
|
|
117
|
-
const entries = await readdir(directory, { withFileTypes: true });
|
|
118
|
-
for (const entry of entries) {
|
|
119
|
-
const absolute = join(directory, entry.name);
|
|
120
|
-
if (entry.isDirectory()) {
|
|
121
|
-
if (IGNORED_DIRECTORIES.has(entry.name)) continue;
|
|
122
|
-
await walk(absolute, files);
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
if (!entry.isFile()) continue;
|
|
126
|
-
if (!SUPPORTED_EXTENSIONS.has(extname(entry.name))) continue;
|
|
127
|
-
const info = await stat(absolute);
|
|
128
|
-
if (info.size > 5e5) continue;
|
|
129
|
-
files.push(absolute);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
function moduleLanguage(path) {
|
|
133
|
-
const extension = extname(path);
|
|
134
|
-
if (extension === ".py") return "py";
|
|
135
|
-
return extension.includes("ts") ? "ts" : "js";
|
|
136
|
-
}
|
|
137
|
-
function moduleImports(root, from, source, fileSet) {
|
|
138
|
-
if (extname(from) === ".py") {
|
|
139
|
-
return pythonImports(from, source, fileSet).map((to) => ({ to, kind: "import" }));
|
|
140
|
-
}
|
|
141
|
-
return extractImports(source).flatMap((specifier) => {
|
|
142
|
-
const to = resolveImport(root, from, specifier.value, fileSet);
|
|
143
|
-
return to ? [{ to, kind: specifier.kind }] : [];
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
var PYTHON_ROOTS = ["", "src/"];
|
|
147
|
-
function pythonImports(from, source, fileSet) {
|
|
148
|
-
const pick = (...candidates) => candidates.find((candidate) => fileSet.has(candidate)) ?? null;
|
|
149
|
-
const moduleFile = (base) => pick(`${base}.py`, `${base}/__init__.py`);
|
|
150
|
-
const packageDir = from.split("/").slice(0, -1);
|
|
151
|
-
const targets = [];
|
|
152
|
-
for (const statement of extractPythonImports(source)) {
|
|
153
|
-
const parts = statement.module ? statement.module.split(".") : [];
|
|
154
|
-
let bases;
|
|
155
|
-
if (statement.level > 0) {
|
|
156
|
-
const up = statement.level - 1;
|
|
157
|
-
if (up > packageDir.length) continue;
|
|
158
|
-
bases = [[...packageDir.slice(0, packageDir.length - up), ...parts].join("/")];
|
|
159
|
-
} else {
|
|
160
|
-
bases = PYTHON_ROOTS.map((prefix) => `${prefix}${parts.join("/")}`);
|
|
161
|
-
}
|
|
162
|
-
for (const base of bases) {
|
|
163
|
-
const prefix = base ? `${base}/` : "";
|
|
164
|
-
const module = parts.length > 0 ? moduleFile(base) : pick(`${prefix}__init__.py`);
|
|
165
|
-
const submodules = statement.names.flatMap((name) => moduleFile(`${prefix}${name}`) ?? []);
|
|
166
|
-
if (!module && submodules.length === 0) continue;
|
|
167
|
-
targets.push(...submodules);
|
|
168
|
-
if (module && submodules.length < Math.max(1, statement.names.length)) targets.push(module);
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
return [...new Set(targets)].filter((target) => target !== from);
|
|
173
|
-
}
|
|
174
|
-
function extractImports(source) {
|
|
175
|
-
const imports = [];
|
|
176
|
-
const stripped = source.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/(^|[^:])\/\/[^\n]*/g, "$1 ");
|
|
177
|
-
const staticImport = /\bimport\s+(?:type\s+)?(?:[^'"()+]+?\s+from\s+)?["']([^"']+)["']/g;
|
|
178
|
-
const exportFrom = /\bexport\s+[^'"()+]+?\s+from\s+["']([^"']+)["']/g;
|
|
179
|
-
const dynamicImport = /\bimport\s*\(\s*["']([^"']+)["']\s*\)/g;
|
|
180
|
-
for (const match of stripped.matchAll(staticImport)) {
|
|
181
|
-
if (match[1]) imports.push({ value: match[1], kind: "import" });
|
|
182
|
-
}
|
|
183
|
-
for (const match of stripped.matchAll(exportFrom)) {
|
|
184
|
-
if (match[1]) imports.push({ value: match[1], kind: "import" });
|
|
185
|
-
}
|
|
186
|
-
for (const match of stripped.matchAll(dynamicImport)) {
|
|
187
|
-
if (match[1]) imports.push({ value: match[1], kind: "dynamic_import" });
|
|
188
|
-
}
|
|
189
|
-
return imports;
|
|
190
|
-
}
|
|
191
|
-
function resolveImport(root, from, specifier, fileSet) {
|
|
192
|
-
if (!specifier.startsWith(".")) return null;
|
|
193
|
-
const base = normalize(relative(root, resolve(root, dirname(from), specifier)));
|
|
194
|
-
const stem = base.replace(/\.(js|jsx|mjs|cjs)$/, "");
|
|
195
|
-
const bases = stem === base ? [base] : [base, stem];
|
|
196
|
-
const candidates = bases.flatMap((b) => [
|
|
197
|
-
b,
|
|
198
|
-
`${b}.ts`,
|
|
199
|
-
`${b}.tsx`,
|
|
200
|
-
`${b}.js`,
|
|
201
|
-
`${b}.jsx`,
|
|
202
|
-
`${b}.mjs`,
|
|
203
|
-
`${b}.cjs`,
|
|
204
|
-
`${b}/index.ts`,
|
|
205
|
-
`${b}/index.tsx`,
|
|
206
|
-
`${b}/index.js`,
|
|
207
|
-
`${b}/index.jsx`
|
|
208
|
-
]);
|
|
209
|
-
return candidates.find((candidate) => fileSet.has(candidate)) ?? null;
|
|
210
|
-
}
|
|
211
|
-
function normalize(path) {
|
|
212
|
-
return path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// src/indexer/engine.ts
|
|
216
|
-
import { createHash } from "crypto";
|
|
217
|
-
import { readFile as readFile4, stat as stat2 } from "fs/promises";
|
|
218
|
-
import { join as join5, resolve as resolve4 } from "path";
|
|
219
|
-
|
|
220
|
-
// src/map/cache.ts
|
|
221
|
-
import { mkdir as mkdir2, readFile as readFile3 } from "fs/promises";
|
|
222
|
-
import { dirname as dirname3, extname as extname2, join as join3, resolve as resolve3 } from "path";
|
|
223
|
-
|
|
224
|
-
// src/indexer/store.ts
|
|
225
|
-
import { mkdir, readFile as readFile2 } from "fs/promises";
|
|
226
|
-
import { dirname as dirname2, join as join2, resolve as resolve2 } from "path";
|
|
227
|
-
import { z } from "zod";
|
|
228
|
-
|
|
229
|
-
// src/indexer/types.ts
|
|
230
|
-
var INDEX_MANIFEST_VERSION = 3;
|
|
231
|
-
|
|
232
|
-
// src/indexer/store.ts
|
|
233
|
-
var symbolSpanSchema = z.object({
|
|
234
|
-
name: z.string(),
|
|
235
|
-
kind: z.enum(["function", "method", "class", "interface", "type", "enum", "const", "heading"]),
|
|
236
|
-
startLine: z.number().int().nonnegative(),
|
|
237
|
-
endLine: z.number().int().nonnegative(),
|
|
238
|
-
signature: z.string(),
|
|
239
|
-
exported: z.boolean()
|
|
240
|
-
});
|
|
241
|
-
var entrySchema = z.object({
|
|
242
|
-
path: z.string(),
|
|
243
|
-
hash: z.string(),
|
|
244
|
-
size: z.number().int().nonnegative(),
|
|
245
|
-
mtimeMs: z.number().optional(),
|
|
246
|
-
ctimeMs: z.number().optional(),
|
|
247
|
-
language: z.string(),
|
|
248
|
-
lines: z.number().int().nonnegative(),
|
|
249
|
-
symbols: z.array(z.string()),
|
|
250
|
-
symbolTable: z.array(symbolSpanSchema).optional(),
|
|
251
|
-
summary: z.string(),
|
|
252
|
-
indexedAt: z.string()
|
|
253
|
-
});
|
|
254
|
-
var manifestSchema = z.object({
|
|
255
|
-
version: z.literal(INDEX_MANIFEST_VERSION),
|
|
256
|
-
generatedAt: z.string(),
|
|
257
|
-
entries: z.record(z.string(), entrySchema)
|
|
258
|
-
});
|
|
259
|
-
var IndexStore = class {
|
|
260
|
-
repositoryRoot;
|
|
261
|
-
cacheDirectory;
|
|
262
|
-
manifestPath;
|
|
263
|
-
constructor(repositoryRoot = process.cwd()) {
|
|
264
|
-
this.repositoryRoot = resolve2(repositoryRoot);
|
|
265
|
-
this.cacheDirectory = join2(this.repositoryRoot, ".codebuddy", "cache");
|
|
266
|
-
this.manifestPath = join2(this.cacheDirectory, "index.json");
|
|
267
|
-
}
|
|
268
|
-
/** Read the manifest, or an empty one if absent/corrupt/version-mismatched. */
|
|
269
|
-
async read() {
|
|
270
|
-
try {
|
|
271
|
-
const raw = await readFile2(this.manifestPath, "utf8");
|
|
272
|
-
const parsed = manifestSchema.safeParse(JSON.parse(raw));
|
|
273
|
-
if (!parsed.success) return emptyManifest();
|
|
274
|
-
return parsed.data;
|
|
275
|
-
} catch (error) {
|
|
276
|
-
if (error.code === "ENOENT") return emptyManifest();
|
|
277
|
-
return emptyManifest();
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
async write(manifest) {
|
|
281
|
-
await assertNoSymlinkBetween(this.repositoryRoot, dirname2(this.manifestPath));
|
|
282
|
-
await mkdir(this.cacheDirectory, { recursive: true, mode: 448 });
|
|
283
|
-
await writeAtomic(this.manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
284
|
-
`);
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
|
-
function emptyManifest() {
|
|
288
|
-
return { version: INDEX_MANIFEST_VERSION, generatedAt: (/* @__PURE__ */ new Date(0)).toISOString(), entries: {} };
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// src/map/cache.ts
|
|
292
|
-
var CACHE_VERSION = 1;
|
|
293
|
-
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py"]);
|
|
294
|
-
async function loadArchitectureMap(repositoryRoot = process.cwd(), suppliedManifest) {
|
|
295
|
-
const root = resolve3(repositoryRoot);
|
|
296
|
-
const manifest = suppliedManifest ?? await new IndexStore(root).read();
|
|
297
|
-
if (Object.keys(manifest.entries).length === 0) {
|
|
298
|
-
const map = await buildArchitectureMap(root);
|
|
299
|
-
return {
|
|
300
|
-
map,
|
|
301
|
-
stats: { readFiles: map.modules.length, reusedFiles: 0, rebuilt: true },
|
|
302
|
-
source: "fallback"
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
return refreshArchitectureCache(root, manifest);
|
|
306
|
-
}
|
|
307
|
-
async function refreshArchitectureCache(repositoryRoot, manifest) {
|
|
308
|
-
const root = resolve3(repositoryRoot);
|
|
309
|
-
const path = join3(root, ".codebuddy", "cache", "architecture.json");
|
|
310
|
-
const currentHashes = sourceHashes(manifest);
|
|
311
|
-
const currentPaths = Object.keys(currentHashes).sort();
|
|
312
|
-
const cached = await readCache(path);
|
|
313
|
-
const cachedPaths = cached ? Object.keys(cached.sourceHashes).sort() : [];
|
|
314
|
-
const fileSetChanged = cachedPaths.join("\n") !== currentPaths.join("\n");
|
|
315
|
-
const changedPaths = !cached || fileSetChanged ? currentPaths : currentPaths.filter(
|
|
316
|
-
(sourcePath) => cached.sourceHashes[sourcePath] !== currentHashes[sourcePath]
|
|
317
|
-
);
|
|
318
|
-
if (cached && changedPaths.length === 0) {
|
|
319
|
-
return {
|
|
320
|
-
map: cached.map,
|
|
321
|
-
stats: { readFiles: 0, reusedFiles: cached.map.modules.length, rebuilt: false },
|
|
322
|
-
source: "cache"
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
const updated = await updateArchitectureMap(
|
|
326
|
-
root,
|
|
327
|
-
currentPaths,
|
|
328
|
-
fileSetChanged ? null : cached?.map ?? null,
|
|
329
|
-
changedPaths
|
|
330
|
-
);
|
|
331
|
-
const next = {
|
|
332
|
-
version: CACHE_VERSION,
|
|
333
|
-
generatedAt: manifest.generatedAt,
|
|
334
|
-
sourceHashes: currentHashes,
|
|
335
|
-
map: updated.map
|
|
336
|
-
};
|
|
337
|
-
await assertNoSymlinkBetween(root, dirname3(path));
|
|
338
|
-
await mkdir2(dirname3(path), { recursive: true, mode: 448 });
|
|
339
|
-
await writeAtomic(path, `${JSON.stringify(next, null, 2)}
|
|
340
|
-
`);
|
|
341
|
-
return { ...updated, source: fileSetChanged || !cached ? "rebuild" : "incremental" };
|
|
342
|
-
}
|
|
343
|
-
async function readCache(path) {
|
|
344
|
-
try {
|
|
345
|
-
const parsed = JSON.parse(await readFile3(path, "utf8"));
|
|
346
|
-
if (parsed.version !== CACHE_VERSION || !parsed.map || !parsed.sourceHashes) return null;
|
|
347
|
-
if (!Array.isArray(parsed.map.modules) || !Array.isArray(parsed.map.edges)) return null;
|
|
348
|
-
if (!parsed.map.modules.every(
|
|
349
|
-
(module) => module && typeof module.path === "string" && typeof module.language === "string" && Array.isArray(module.imports)
|
|
350
|
-
) || !parsed.map.edges.every(
|
|
351
|
-
(edge) => edge && typeof edge.from === "string" && typeof edge.to === "string"
|
|
352
|
-
)) {
|
|
353
|
-
return null;
|
|
354
|
-
}
|
|
355
|
-
return parsed;
|
|
356
|
-
} catch {
|
|
357
|
-
return null;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
function sourceHashes(manifest) {
|
|
361
|
-
return Object.fromEntries(
|
|
362
|
-
Object.values(manifest.entries).filter((entry) => SOURCE_EXTENSIONS.has(extname2(entry.path).toLowerCase())).map((entry) => [entry.path, entry.hash])
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// src/indexer/scan.ts
|
|
367
|
-
import { spawn } from "child_process";
|
|
368
|
-
import { readdir as readdir2 } from "fs/promises";
|
|
369
|
-
import { extname as extname4, join as join4, relative as relative2, sep } from "path";
|
|
370
|
-
|
|
371
|
-
// src/indexer/summary.ts
|
|
372
|
-
import { extname as extname3 } from "path";
|
|
373
|
-
var LANGUAGE_BY_EXTENSION = {
|
|
374
|
-
".ts": "ts",
|
|
375
|
-
".tsx": "tsx",
|
|
376
|
-
".js": "js",
|
|
377
|
-
".jsx": "jsx",
|
|
378
|
-
".mjs": "js",
|
|
379
|
-
".cjs": "js",
|
|
380
|
-
".json": "json",
|
|
381
|
-
".md": "md",
|
|
382
|
-
".mdx": "md",
|
|
383
|
-
".rst": "rst",
|
|
384
|
-
".yaml": "yaml",
|
|
385
|
-
".yml": "yaml",
|
|
386
|
-
".toml": "toml",
|
|
387
|
-
".css": "css",
|
|
388
|
-
".scss": "scss",
|
|
389
|
-
".html": "html",
|
|
390
|
-
".py": "py",
|
|
391
|
-
".go": "go",
|
|
392
|
-
".rs": "rust",
|
|
393
|
-
".java": "java",
|
|
394
|
-
".rb": "ruby",
|
|
395
|
-
".php": "php",
|
|
396
|
-
".sh": "shell",
|
|
397
|
-
".sql": "sql",
|
|
398
|
-
".txt": "text"
|
|
399
|
-
};
|
|
400
|
-
var SUPPORTED_EXTENSIONS2 = new Set(Object.keys(LANGUAGE_BY_EXTENSION));
|
|
401
|
-
var CODE_LANGUAGES = /* @__PURE__ */ new Set(["ts", "tsx", "js", "jsx"]);
|
|
402
|
-
var SYMBOL_LIMIT = 8;
|
|
403
|
-
var SUMMARY_COMMENT_MAX = 80;
|
|
404
|
-
function languageFor(path) {
|
|
405
|
-
return LANGUAGE_BY_EXTENSION[extname3(path).toLowerCase()] ?? "text";
|
|
406
|
-
}
|
|
407
|
-
function summarizeSource(path, content) {
|
|
408
|
-
const language = languageFor(path);
|
|
409
|
-
const lines = countLines(content);
|
|
410
|
-
const symbols = CODE_LANGUAGES.has(language) ? extractSymbols(content) : language === "py" ? pythonPublicNames(content) : [];
|
|
411
|
-
const summary = composeSummary(language, lines, symbols, content);
|
|
412
|
-
return { language, lines, symbols, summary };
|
|
413
|
-
}
|
|
414
|
-
function countLines(content) {
|
|
415
|
-
if (content.length === 0) return 0;
|
|
416
|
-
return content.replace(/\r/g, "").replace(/\n$/, "").split("\n").length;
|
|
417
|
-
}
|
|
418
|
-
function extractSymbols(content) {
|
|
419
|
-
const names = [];
|
|
420
|
-
const push = (name) => {
|
|
421
|
-
const trimmed = name?.trim();
|
|
422
|
-
if (trimmed && /^[A-Za-z_$][\w$]*$/.test(trimmed) && !names.includes(trimmed)) {
|
|
423
|
-
names.push(trimmed);
|
|
424
|
-
}
|
|
425
|
-
};
|
|
426
|
-
const declaration = /^export\s+(?:default\s+)?(?:async\s+)?(?:abstract\s+)?(?:const|let|var|function|class|interface|type|enum)\s+([A-Za-z_$][\w$]*)/gm;
|
|
427
|
-
for (const match of content.matchAll(declaration)) push(match[1]);
|
|
428
|
-
const namedExports = /^export\s*\{([^}]*)\}/gm;
|
|
429
|
-
for (const match of content.matchAll(namedExports)) {
|
|
430
|
-
for (const part of (match[1] ?? "").split(",")) {
|
|
431
|
-
const alias = part.includes(" as ") ? part.split(" as ").pop() : part;
|
|
432
|
-
push(alias);
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
return names.slice(0, SYMBOL_LIMIT);
|
|
436
|
-
}
|
|
437
|
-
function pythonPublicNames(content) {
|
|
438
|
-
return extractSymbolTable(content, "x.py").filter((symbol) => symbol.exported && symbol.kind !== "method").map((symbol) => symbol.name).slice(0, SYMBOL_LIMIT);
|
|
439
|
-
}
|
|
440
|
-
function composeSummary(language, lines, symbols, content) {
|
|
441
|
-
const head = `${language} \u2022 ${lines} line${lines === 1 ? "" : "s"}`;
|
|
442
|
-
if (symbols.length > 0) return `${head} \u2022 exports ${symbols.join(", ")}`;
|
|
443
|
-
const comment = leadingComment(content);
|
|
444
|
-
if (comment) return `${head} \u2022 ${comment}`;
|
|
445
|
-
return head;
|
|
446
|
-
}
|
|
447
|
-
function leadingComment(content) {
|
|
448
|
-
for (const raw of content.split(/\r?\n/)) {
|
|
449
|
-
const line = raw.trim();
|
|
450
|
-
if (line === "") continue;
|
|
451
|
-
const stripped = line.replace(/^\/\/+/, "").replace(/^\/\*+/, "").replace(/\*+\/$/, "").replace(/^[#*]+/, "").trim();
|
|
452
|
-
if (line.startsWith("//") || line.startsWith("/*") || line.startsWith("#") || line.startsWith("*")) {
|
|
453
|
-
if (stripped) return truncate(stripped, SUMMARY_COMMENT_MAX);
|
|
454
|
-
continue;
|
|
455
|
-
}
|
|
456
|
-
return null;
|
|
457
|
-
}
|
|
458
|
-
return null;
|
|
459
|
-
}
|
|
460
|
-
function truncate(value, max) {
|
|
461
|
-
return value.length <= max ? value : `${value.slice(0, max - 1)}\u2026`;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// src/indexer/scan.ts
|
|
465
|
-
var FALLBACK_IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
466
|
-
".git",
|
|
467
|
-
"node_modules",
|
|
468
|
-
"dist",
|
|
469
|
-
"build",
|
|
470
|
-
"coverage",
|
|
471
|
-
".codebuddy",
|
|
472
|
-
"graphify-out",
|
|
473
|
-
".next",
|
|
474
|
-
".turbo",
|
|
475
|
-
"out",
|
|
476
|
-
".venv",
|
|
477
|
-
"venv",
|
|
478
|
-
"__pycache__"
|
|
479
|
-
]);
|
|
480
|
-
async function listIndexableFiles(repositoryRoot) {
|
|
481
|
-
const tracked = await gitListFiles(repositoryRoot);
|
|
482
|
-
const paths = tracked ?? await walkFiles(repositoryRoot);
|
|
483
|
-
return paths.map(normalize2).filter((path) => !path.startsWith(".codebuddy/") && !path.startsWith("graphify-out/")).filter((path) => SUPPORTED_EXTENSIONS2.has(extname4(path).toLowerCase())).sort();
|
|
484
|
-
}
|
|
485
|
-
async function gitListFiles(repositoryRoot) {
|
|
486
|
-
const result = await runGit(repositoryRoot, [
|
|
487
|
-
"ls-files",
|
|
488
|
-
"-z",
|
|
489
|
-
"--cached",
|
|
490
|
-
"--others",
|
|
491
|
-
"--exclude-standard"
|
|
492
|
-
]);
|
|
493
|
-
if (result.code !== 0) return null;
|
|
494
|
-
return result.stdout.split("\0").filter(Boolean);
|
|
495
|
-
}
|
|
496
|
-
async function walkFiles(root) {
|
|
497
|
-
const files = [];
|
|
498
|
-
const walk2 = async (directory) => {
|
|
499
|
-
const entries = await readdir2(directory, { withFileTypes: true });
|
|
500
|
-
for (const entry of entries) {
|
|
501
|
-
const absolute = join4(directory, entry.name);
|
|
502
|
-
if (entry.isDirectory()) {
|
|
503
|
-
if (FALLBACK_IGNORED_DIRECTORIES.has(entry.name)) continue;
|
|
504
|
-
await walk2(absolute);
|
|
505
|
-
continue;
|
|
506
|
-
}
|
|
507
|
-
if (entry.isFile()) files.push(relative2(root, absolute));
|
|
508
|
-
}
|
|
509
|
-
};
|
|
510
|
-
await walk2(root);
|
|
511
|
-
return files;
|
|
512
|
-
}
|
|
513
|
-
function runGit(cwd, args) {
|
|
514
|
-
return new Promise((resolveResult) => {
|
|
515
|
-
const child = spawn("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
516
|
-
let stdout = "";
|
|
517
|
-
let stderr = "";
|
|
518
|
-
child.stdout.setEncoding("utf8");
|
|
519
|
-
child.stdout.on("data", (chunk) => {
|
|
520
|
-
stdout += String(chunk);
|
|
521
|
-
});
|
|
522
|
-
child.stderr.on("data", (chunk) => {
|
|
523
|
-
stderr += String(chunk);
|
|
524
|
-
});
|
|
525
|
-
child.on("error", () => resolveResult({ code: -1, stdout: "", stderr: "git unavailable" }));
|
|
526
|
-
child.on("close", (code) => resolveResult({ code: code ?? 0, stdout, stderr }));
|
|
527
|
-
});
|
|
528
|
-
}
|
|
529
|
-
function normalize2(path) {
|
|
530
|
-
return (sep === "\\" ? path.replace(/\\/g, "/") : path).replace(/^\.\//, "");
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
// src/indexer/engine.ts
|
|
534
|
-
var MAX_FILE_BYTES = 512e3;
|
|
535
|
-
var RACY_WINDOW_MS = 3e3;
|
|
536
|
-
async function indexRepository(options = {}) {
|
|
537
|
-
return (await refreshIndex(options)).result;
|
|
538
|
-
}
|
|
539
|
-
async function loadFreshIndex(repositoryRoot) {
|
|
540
|
-
try {
|
|
541
|
-
const { result, manifest } = await refreshIndex({ repositoryRoot });
|
|
542
|
-
const delta = result.added + result.changed + result.removed;
|
|
543
|
-
const failures = result.errors.length > 0 ? `; ${result.errors.length} file(s) could not be validated and were omitted` : "";
|
|
544
|
-
return {
|
|
545
|
-
manifest,
|
|
546
|
-
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}`
|
|
547
|
-
};
|
|
548
|
-
} catch (error) {
|
|
549
|
-
return {
|
|
550
|
-
manifest: emptyManifest(),
|
|
551
|
-
explain: `index: freshness check failed (${error.message}); indexed evidence omitted`
|
|
552
|
-
};
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
var passes = /* @__PURE__ */ new Map();
|
|
556
|
-
function refreshIndex(options) {
|
|
557
|
-
const key = resolve4(options.repositoryRoot ?? process.cwd());
|
|
558
|
-
const next = (passes.get(key) ?? Promise.resolve()).catch(() => void 0).then(() => runIndexPass(options));
|
|
559
|
-
passes.set(key, next);
|
|
560
|
-
void next.finally(() => {
|
|
561
|
-
if (passes.get(key) === next) passes.delete(key);
|
|
562
|
-
}).catch(() => void 0);
|
|
563
|
-
return next;
|
|
564
|
-
}
|
|
565
|
-
async function runIndexPass(options) {
|
|
566
|
-
const start = Date.now();
|
|
567
|
-
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
568
|
-
const repositoryRoot = resolve4(options.repositoryRoot ?? process.cwd());
|
|
569
|
-
const store = new IndexStore(repositoryRoot);
|
|
570
|
-
const [files, previous] = await Promise.all([listIndexableFiles(repositoryRoot), store.read()]);
|
|
571
|
-
const entries = {};
|
|
572
|
-
const errors = [];
|
|
573
|
-
let added = 0;
|
|
574
|
-
let changed = 0;
|
|
575
|
-
let unchanged = 0;
|
|
576
|
-
let skipped = 0;
|
|
577
|
-
let dirty = previous.generatedAt === emptyManifest().generatedAt;
|
|
578
|
-
for (const path of files) {
|
|
579
|
-
try {
|
|
580
|
-
const info = await stat2(join5(repositoryRoot, path));
|
|
581
|
-
if (!info.isFile()) continue;
|
|
582
|
-
if (info.size > MAX_FILE_BYTES) {
|
|
583
|
-
skipped++;
|
|
584
|
-
continue;
|
|
585
|
-
}
|
|
586
|
-
const existing = previous.entries[path];
|
|
587
|
-
if (!options.full && existing && statUnchanged(existing, info)) {
|
|
588
|
-
entries[path] = existing;
|
|
589
|
-
unchanged++;
|
|
590
|
-
continue;
|
|
591
|
-
}
|
|
592
|
-
const content = await readFile4(join5(repositoryRoot, path), "utf8");
|
|
593
|
-
const hash = hashContent(content);
|
|
594
|
-
const metadata = trustedMetadata(info);
|
|
595
|
-
dirty = true;
|
|
596
|
-
if (!options.full && existing && existing.hash === hash) {
|
|
597
|
-
const { mtimeMs: _mtime, ctimeMs: _ctime, ...rest } = existing;
|
|
598
|
-
entries[path] = { ...rest, size: info.size, ...metadata };
|
|
599
|
-
unchanged++;
|
|
600
|
-
continue;
|
|
601
|
-
}
|
|
602
|
-
const { language, lines, symbols, summary } = summarizeSource(path, content);
|
|
603
|
-
const symbolTable = supportsSymbols(path) ? extractSymbolTable(content, path) : [];
|
|
604
|
-
entries[path] = {
|
|
605
|
-
path,
|
|
606
|
-
hash,
|
|
607
|
-
size: info.size,
|
|
608
|
-
...metadata,
|
|
609
|
-
language,
|
|
610
|
-
lines,
|
|
611
|
-
symbols,
|
|
612
|
-
...symbolTable.length > 0 ? { symbolTable } : {},
|
|
613
|
-
summary,
|
|
614
|
-
indexedAt: now().toISOString()
|
|
615
|
-
};
|
|
616
|
-
if (existing) changed++;
|
|
617
|
-
else added++;
|
|
618
|
-
} catch (error) {
|
|
619
|
-
errors.push({ path, error: error.message });
|
|
620
|
-
skipped++;
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
const removed = Object.keys(previous.entries).filter((path) => !(path in entries)).length;
|
|
624
|
-
const manifest = {
|
|
625
|
-
version: INDEX_MANIFEST_VERSION,
|
|
626
|
-
generatedAt: now().toISOString(),
|
|
627
|
-
entries: sortEntries(entries)
|
|
628
|
-
};
|
|
629
|
-
if (dirty || removed > 0) await store.write(manifest);
|
|
630
|
-
const architecture = await refreshArchitectureCache(repositoryRoot, manifest);
|
|
631
|
-
const result = {
|
|
632
|
-
scanned: files.length,
|
|
633
|
-
added,
|
|
634
|
-
changed,
|
|
635
|
-
unchanged,
|
|
636
|
-
removed,
|
|
637
|
-
skipped,
|
|
638
|
-
errors,
|
|
639
|
-
durationMs: Date.now() - start,
|
|
640
|
-
totalIndexed: Object.keys(entries).length,
|
|
641
|
-
architecture: {
|
|
642
|
-
source: architecture.source,
|
|
643
|
-
readFiles: architecture.stats.readFiles,
|
|
644
|
-
reusedFiles: architecture.stats.reusedFiles
|
|
645
|
-
}
|
|
646
|
-
};
|
|
647
|
-
return { result, manifest };
|
|
648
|
-
}
|
|
649
|
-
function statUnchanged(entry, info) {
|
|
650
|
-
return entry.mtimeMs !== void 0 && entry.size === info.size && entry.mtimeMs === info.mtimeMs && entry.ctimeMs === info.ctimeMs;
|
|
651
|
-
}
|
|
652
|
-
function trustedMetadata(info) {
|
|
653
|
-
if (Date.now() - Math.max(info.mtimeMs, info.ctimeMs) < RACY_WINDOW_MS) return {};
|
|
654
|
-
return { mtimeMs: info.mtimeMs, ctimeMs: info.ctimeMs };
|
|
655
|
-
}
|
|
656
|
-
function hashContent(content) {
|
|
657
|
-
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
658
|
-
}
|
|
659
|
-
function sortEntries(entries) {
|
|
660
|
-
return Object.fromEntries(
|
|
661
|
-
Object.keys(entries).sort().map((key) => [key, entries[key]])
|
|
662
|
-
);
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
export {
|
|
666
|
-
buildArchitectureMap,
|
|
667
|
-
queryMap,
|
|
668
|
-
neighbours,
|
|
669
|
-
loadArchitectureMap,
|
|
670
|
-
indexRepository,
|
|
671
|
-
loadFreshIndex
|
|
672
|
-
};
|
|
673
|
-
//# sourceMappingURL=chunk-ITQO632W.js.map
|