@praneeth_54/agentdoctor 1.0.0 → 1.1.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/CHANGELOG.md +34 -5
- package/README.md +15 -12
- package/dist/cli/commands/brain-mcp.d.ts +9 -0
- package/dist/cli/commands/brain-mcp.js +38 -0
- package/dist/cli/program.js +13 -0
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/core/understanding/architecture/index.d.ts +4 -0
- package/dist/core/understanding/architecture/index.js +3 -0
- package/dist/core/understanding/architecture/infer.d.ts +6 -0
- package/dist/core/understanding/architecture/infer.js +39 -0
- package/dist/core/understanding/architecture/models.d.ts +23 -0
- package/dist/core/understanding/architecture/models.js +127 -0
- package/dist/core/understanding/architecture/patterns/distribution.d.ts +2 -0
- package/dist/core/understanding/architecture/patterns/distribution.js +115 -0
- package/dist/core/understanding/architecture/patterns/index.d.ts +2 -0
- package/dist/core/understanding/architecture/patterns/index.js +8 -0
- package/dist/core/understanding/architecture/patterns/layered.d.ts +2 -0
- package/dist/core/understanding/architecture/patterns/layered.js +279 -0
- package/dist/core/understanding/architecture/patterns/structural.d.ts +2 -0
- package/dist/core/understanding/architecture/patterns/structural.js +197 -0
- package/dist/core/understanding/architecture/rules.d.ts +4 -0
- package/dist/core/understanding/architecture/rules.js +6 -0
- package/dist/core/understanding/architecture/types.d.ts +52 -0
- package/dist/core/understanding/architecture/types.js +1 -0
- package/dist/core/understanding/brain/build.d.ts +13 -0
- package/dist/core/understanding/brain/build.js +158 -0
- package/dist/core/understanding/brain/claims/index.d.ts +3 -0
- package/dist/core/understanding/brain/claims/index.js +2 -0
- package/dist/core/understanding/brain/claims/lifecycle.d.ts +16 -0
- package/dist/core/understanding/brain/claims/lifecycle.js +78 -0
- package/dist/core/understanding/brain/claims/types.d.ts +32 -0
- package/dist/core/understanding/brain/claims/types.js +25 -0
- package/dist/core/understanding/brain/components/index.d.ts +17 -0
- package/dist/core/understanding/brain/components/index.js +97 -0
- package/dist/core/understanding/brain/components/types.d.ts +16 -0
- package/dist/core/understanding/brain/components/types.js +8 -0
- package/dist/core/understanding/brain/confidence.d.ts +19 -0
- package/dist/core/understanding/brain/confidence.js +39 -0
- package/dist/core/understanding/brain/contract.d.ts +17 -0
- package/dist/core/understanding/brain/contract.js +100 -0
- package/dist/core/understanding/brain/contradictions/index.d.ts +12 -0
- package/dist/core/understanding/brain/contradictions/index.js +57 -0
- package/dist/core/understanding/brain/contradictions/types.d.ts +12 -0
- package/dist/core/understanding/brain/contradictions/types.js +8 -0
- package/dist/core/understanding/brain/delta.d.ts +25 -0
- package/dist/core/understanding/brain/delta.js +116 -0
- package/dist/core/understanding/brain/evidence/index.d.ts +3 -0
- package/dist/core/understanding/brain/evidence/index.js +2 -0
- package/dist/core/understanding/brain/evidence/redact.d.ts +4 -0
- package/dist/core/understanding/brain/evidence/redact.js +36 -0
- package/dist/core/understanding/brain/evidence/types.d.ts +34 -0
- package/dist/core/understanding/brain/evidence/types.js +35 -0
- package/dist/core/understanding/brain/explain.d.ts +17 -0
- package/dist/core/understanding/brain/explain.js +33 -0
- package/dist/core/understanding/brain/index.d.ts +28 -0
- package/dist/core/understanding/brain/index.js +16 -0
- package/dist/core/understanding/brain/migrate.d.ts +21 -0
- package/dist/core/understanding/brain/migrate.js +47 -0
- package/dist/core/understanding/brain/query.d.ts +60 -0
- package/dist/core/understanding/brain/query.js +92 -0
- package/dist/core/understanding/brain/security.d.ts +3 -0
- package/dist/core/understanding/brain/security.js +43 -0
- package/dist/core/understanding/brain/storage/index.d.ts +2 -0
- package/dist/core/understanding/brain/storage/index.js +1 -0
- package/dist/core/understanding/brain/storage/store.d.ts +53 -0
- package/dist/core/understanding/brain/storage/store.js +305 -0
- package/dist/core/understanding/brain/trace.d.ts +24 -0
- package/dist/core/understanding/brain/trace.js +207 -0
- package/dist/core/understanding/brain/types.d.ts +32 -0
- package/dist/core/understanding/brain/types.js +8 -0
- package/dist/core/understanding/brain/version.d.ts +13 -0
- package/dist/core/understanding/brain/version.js +7 -0
- package/dist/core/understanding/delta/compare.d.ts +26 -0
- package/dist/core/understanding/delta/compare.js +74 -0
- package/dist/core/understanding/delta/index.d.ts +2 -0
- package/dist/core/understanding/delta/index.js +1 -0
- package/dist/core/understanding/dependencies/discover.d.ts +7 -0
- package/dist/core/understanding/dependencies/discover.js +550 -0
- package/dist/core/understanding/dependencies/extract.d.ts +10 -0
- package/dist/core/understanding/dependencies/extract.js +189 -0
- package/dist/core/understanding/dependencies/index.d.ts +4 -0
- package/dist/core/understanding/dependencies/index.js +3 -0
- package/dist/core/understanding/dependencies/models.d.ts +12 -0
- package/dist/core/understanding/dependencies/models.js +125 -0
- package/dist/core/understanding/dependencies/types.d.ts +27 -0
- package/dist/core/understanding/dependencies/types.js +1 -0
- package/dist/core/understanding/domain/discover.d.ts +14 -0
- package/dist/core/understanding/domain/discover.js +90 -0
- package/dist/core/understanding/domain/index.d.ts +2 -0
- package/dist/core/understanding/domain/index.js +1 -0
- package/dist/core/understanding/entrypoints/discover.d.ts +6 -0
- package/dist/core/understanding/entrypoints/discover.js +62 -0
- package/dist/core/understanding/entrypoints/extract.d.ts +19 -0
- package/dist/core/understanding/entrypoints/extract.js +43 -0
- package/dist/core/understanding/entrypoints/index.d.ts +4 -0
- package/dist/core/understanding/entrypoints/index.js +3 -0
- package/dist/core/understanding/entrypoints/models.d.ts +26 -0
- package/dist/core/understanding/entrypoints/models.js +216 -0
- package/dist/core/understanding/entrypoints/types.d.ts +20 -0
- package/dist/core/understanding/entrypoints/types.js +1 -0
- package/dist/core/understanding/index.d.ts +32 -0
- package/dist/core/understanding/index.js +18 -0
- package/dist/core/understanding/mind/build.d.ts +16 -0
- package/dist/core/understanding/mind/build.js +134 -0
- package/dist/core/understanding/mind/index.d.ts +6 -0
- package/dist/core/understanding/mind/index.js +3 -0
- package/dist/core/understanding/mind/query.d.ts +33 -0
- package/dist/core/understanding/mind/query.js +39 -0
- package/dist/core/understanding/mind/types.d.ts +24 -0
- package/dist/core/understanding/mind/types.js +7 -0
- package/dist/core/understanding/model/builder.d.ts +9 -0
- package/dist/core/understanding/model/builder.js +209 -0
- package/dist/core/understanding/model/ids.d.ts +7 -0
- package/dist/core/understanding/model/ids.js +48 -0
- package/dist/core/understanding/model/index.d.ts +7 -0
- package/dist/core/understanding/model/index.js +6 -0
- package/dist/core/understanding/model/schema.d.ts +12 -0
- package/dist/core/understanding/model/schema.js +33 -0
- package/dist/core/understanding/model/serializer.d.ts +9 -0
- package/dist/core/understanding/model/serializer.js +46 -0
- package/dist/core/understanding/model/types.d.ts +110 -0
- package/dist/core/understanding/model/types.js +1 -0
- package/dist/core/understanding/model/validator.d.ts +5 -0
- package/dist/core/understanding/model/validator.js +126 -0
- package/dist/core/understanding/model/version.d.ts +9 -0
- package/dist/core/understanding/model/version.js +7 -0
- package/dist/core/understanding/ownership/discover.d.ts +12 -0
- package/dist/core/understanding/ownership/discover.js +242 -0
- package/dist/core/understanding/ownership/index.d.ts +2 -0
- package/dist/core/understanding/ownership/index.js +1 -0
- package/dist/core/understanding/ownership/types.d.ts +23 -0
- package/dist/core/understanding/ownership/types.js +1 -0
- package/dist/core/understanding/query/engine.d.ts +24 -0
- package/dist/core/understanding/query/engine.js +35 -0
- package/dist/core/understanding/query/errors.d.ts +13 -0
- package/dist/core/understanding/query/errors.js +26 -0
- package/dist/core/understanding/query/executor.d.ts +8 -0
- package/dist/core/understanding/query/executor.js +34 -0
- package/dist/core/understanding/query/index.d.ts +7 -0
- package/dist/core/understanding/query/index.js +5 -0
- package/dist/core/understanding/query/models.d.ts +102 -0
- package/dist/core/understanding/query/models.js +1 -0
- package/dist/core/understanding/query/query.d.ts +68 -0
- package/dist/core/understanding/query/query.js +145 -0
- package/dist/core/understanding/query/registry.d.ts +8 -0
- package/dist/core/understanding/query/registry.js +340 -0
- package/dist/core/understanding/query/types.d.ts +63 -0
- package/dist/core/understanding/query/types.js +1 -0
- package/dist/core/understanding/relationships/discover.d.ts +11 -0
- package/dist/core/understanding/relationships/discover.js +517 -0
- package/dist/core/understanding/relationships/extract.d.ts +14 -0
- package/dist/core/understanding/relationships/extract.js +165 -0
- package/dist/core/understanding/relationships/index.d.ts +4 -0
- package/dist/core/understanding/relationships/index.js +3 -0
- package/dist/core/understanding/relationships/models.d.ts +21 -0
- package/dist/core/understanding/relationships/models.js +185 -0
- package/dist/core/understanding/relationships/types.d.ts +42 -0
- package/dist/core/understanding/relationships/types.js +1 -0
- package/dist/core/understanding/risks/discover.d.ts +8 -0
- package/dist/core/understanding/risks/discover.js +155 -0
- package/dist/core/understanding/risks/index.d.ts +2 -0
- package/dist/core/understanding/risks/index.js +1 -0
- package/dist/core/understanding/risks/types.d.ts +26 -0
- package/dist/core/understanding/risks/types.js +1 -0
- package/dist/core/understanding/shared/domain-lexicon.d.ts +9 -0
- package/dist/core/understanding/shared/domain-lexicon.js +107 -0
- package/dist/core/understanding/shared/index.d.ts +2 -0
- package/dist/core/understanding/shared/index.js +2 -0
- package/dist/core/understanding/shared/tokens.d.ts +7 -0
- package/dist/core/understanding/shared/tokens.js +141 -0
- package/dist/core/understanding/snapshot/identity.d.ts +24 -0
- package/dist/core/understanding/snapshot/identity.js +79 -0
- package/dist/core/understanding/snapshot/index.d.ts +2 -0
- package/dist/core/understanding/snapshot/index.js +1 -0
- package/dist/core/understanding/types/index.d.ts +22 -0
- package/dist/core/understanding/types/index.js +1 -0
- package/dist/core/understanding/understand/formatter.d.ts +10 -0
- package/dist/core/understanding/understand/formatter.js +115 -0
- package/dist/core/understanding/understand/index.d.ts +4 -0
- package/dist/core/understanding/understand/index.js +3 -0
- package/dist/core/understanding/understand/service.d.ts +17 -0
- package/dist/core/understanding/understand/service.js +76 -0
- package/dist/core/understanding/understand/summary.d.ts +14 -0
- package/dist/core/understanding/understand/summary.js +39 -0
- package/dist/core/understanding/understand/types.d.ts +31 -0
- package/dist/core/understanding/understand/types.js +1 -0
- package/dist/mcp/brain/compile.d.ts +9 -0
- package/dist/mcp/brain/compile.js +42 -0
- package/dist/mcp/brain/errors.d.ts +12 -0
- package/dist/mcp/brain/errors.js +23 -0
- package/dist/mcp/brain/index.d.ts +11 -0
- package/dist/mcp/brain/index.js +8 -0
- package/dist/mcp/brain/provenance.d.ts +29 -0
- package/dist/mcp/brain/provenance.js +59 -0
- package/dist/mcp/brain/schemas.d.ts +13 -0
- package/dist/mcp/brain/schemas.js +105 -0
- package/dist/mcp/brain/security/root.d.ts +6 -0
- package/dist/mcp/brain/security/root.js +66 -0
- package/dist/mcp/brain/server.d.ts +12 -0
- package/dist/mcp/brain/server.js +46 -0
- package/dist/mcp/brain/session.d.ts +33 -0
- package/dist/mcp/brain/session.js +117 -0
- package/dist/mcp/brain/tools/handlers.d.ts +13 -0
- package/dist/mcp/brain/tools/handlers.js +483 -0
- package/dist/mcp/brain/tools/registry.d.ts +9 -0
- package/dist/mcp/brain/tools/registry.js +191 -0
- package/package.json +5 -1
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { RELATION_CONFIDENCE, extensionOf, isSourceFile } from "./models.js";
|
|
2
|
+
const STRING = `["'\`]([^"'\`]+)["'\`]`;
|
|
3
|
+
function pushUnique(out, specifier, type) {
|
|
4
|
+
const trimmed = specifier.trim();
|
|
5
|
+
if (!trimmed || trimmed.startsWith("node:") || trimmed === ".") {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
// Skip bare relative current-dir noise without a path
|
|
9
|
+
if (trimmed === "./" || trimmed === "../") {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
out.push({
|
|
13
|
+
specifier: trimmed,
|
|
14
|
+
type,
|
|
15
|
+
confidence: RELATION_CONFIDENCE[type],
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function extractJsFamily(content) {
|
|
19
|
+
const out = [];
|
|
20
|
+
const fromImport = new RegExp(`\\bimport\\s+(?:type\\s+)?(?:[\\w*{}$,\\s]+\\s+from\\s+)?${STRING}`, "g");
|
|
21
|
+
for (const match of content.matchAll(fromImport)) {
|
|
22
|
+
pushUnique(out, match[1] ?? "", "import");
|
|
23
|
+
}
|
|
24
|
+
const sideEffect = new RegExp(`\\bimport\\s+${STRING}`, "g");
|
|
25
|
+
for (const match of content.matchAll(sideEffect)) {
|
|
26
|
+
pushUnique(out, match[1] ?? "", "import");
|
|
27
|
+
}
|
|
28
|
+
const exportFrom = new RegExp(`\\bexport\\s+(?:\\*|\\{[^}]*\\})\\s+from\\s+${STRING}`, "g");
|
|
29
|
+
for (const match of content.matchAll(exportFrom)) {
|
|
30
|
+
pushUnique(out, match[1] ?? "", "export");
|
|
31
|
+
}
|
|
32
|
+
const requireCall = new RegExp(`\\brequire\\s*\\(\\s*${STRING}\\s*\\)`, "g");
|
|
33
|
+
for (const match of content.matchAll(requireCall)) {
|
|
34
|
+
pushUnique(out, match[1] ?? "", "require");
|
|
35
|
+
}
|
|
36
|
+
const dynamicImport = new RegExp(`\\bimport\\s*\\(\\s*${STRING}\\s*\\)`, "g");
|
|
37
|
+
for (const match of content.matchAll(dynamicImport)) {
|
|
38
|
+
pushUnique(out, match[1] ?? "", "dynamic-import");
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
function extractDart(content) {
|
|
43
|
+
const out = [];
|
|
44
|
+
const importRe = /\bimport\s+['"]([^'"]+)['"]/g;
|
|
45
|
+
for (const match of content.matchAll(importRe)) {
|
|
46
|
+
pushUnique(out, match[1] ?? "", "import");
|
|
47
|
+
}
|
|
48
|
+
const exportRe = /\bexport\s+['"]([^'"]+)['"]/g;
|
|
49
|
+
for (const match of content.matchAll(exportRe)) {
|
|
50
|
+
pushUnique(out, match[1] ?? "", "export");
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
function extractJava(content) {
|
|
55
|
+
const out = [];
|
|
56
|
+
const importRe = /\bimport\s+(?:static\s+)?([a-zA-Z_][\w.]*)\s*;/g;
|
|
57
|
+
for (const match of content.matchAll(importRe)) {
|
|
58
|
+
const pkg = match[1] ?? "";
|
|
59
|
+
if (pkg.startsWith("java.") || pkg.startsWith("javax.") || pkg.startsWith("jakarta.")) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
pushUnique(out, pkg, "import");
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
function extractGo(content) {
|
|
67
|
+
const out = [];
|
|
68
|
+
const single = /\bimport\s+"([^"]+)"/g;
|
|
69
|
+
for (const match of content.matchAll(single)) {
|
|
70
|
+
pushUnique(out, match[1] ?? "", "import");
|
|
71
|
+
}
|
|
72
|
+
const block = /\bimport\s*\(([\s\S]*?)\)/g;
|
|
73
|
+
for (const match of content.matchAll(block)) {
|
|
74
|
+
const body = match[1] ?? "";
|
|
75
|
+
for (const line of body.matchAll(/"([^"]+)"/g)) {
|
|
76
|
+
pushUnique(out, line[1] ?? "", "import");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
function extractPython(content) {
|
|
82
|
+
const out = [];
|
|
83
|
+
const fromImport = /^\s*from\s+([.\w]+)\s+import\s+/gm;
|
|
84
|
+
for (const match of content.matchAll(fromImport)) {
|
|
85
|
+
pushUnique(out, match[1] ?? "", "import");
|
|
86
|
+
}
|
|
87
|
+
const plainImport = /^\s*import\s+([.\w]+(?:\s*,\s*[.\w]+)*)/gm;
|
|
88
|
+
for (const match of content.matchAll(plainImport)) {
|
|
89
|
+
const group = match[1] ?? "";
|
|
90
|
+
for (const part of group.split(",")) {
|
|
91
|
+
const name = part
|
|
92
|
+
.trim()
|
|
93
|
+
.split(/\s+as\s+/)[0]
|
|
94
|
+
?.trim() ?? "";
|
|
95
|
+
pushUnique(out, name, "import");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
function extractRust(content) {
|
|
101
|
+
const out = [];
|
|
102
|
+
const useRe = /\buse\s+((?:crate|super|self)::[\w:]+|[\w]+(?:::[\w]+)+)\s*(?:;|::\{)/g;
|
|
103
|
+
for (const match of content.matchAll(useRe)) {
|
|
104
|
+
pushUnique(out, match[1] ?? "", "import");
|
|
105
|
+
}
|
|
106
|
+
const modRe = /\bmod\s+([a-zA-Z_][\w]*)\s*;/g;
|
|
107
|
+
for (const match of content.matchAll(modRe)) {
|
|
108
|
+
pushUnique(out, match[1] ?? "", "module");
|
|
109
|
+
}
|
|
110
|
+
return out;
|
|
111
|
+
}
|
|
112
|
+
function extractPhp(content) {
|
|
113
|
+
const out = [];
|
|
114
|
+
const useRe = /\buse\s+([A-Za-z_\\][\w\\]*)\s*;/g;
|
|
115
|
+
for (const match of content.matchAll(useRe)) {
|
|
116
|
+
pushUnique(out, (match[1] ?? "").replace(/\\/g, "/"), "import");
|
|
117
|
+
}
|
|
118
|
+
const requireRe = /\b(?:require|include)(?:_once)?\s*\(?\s*['"]([^'"]+)['"]/g;
|
|
119
|
+
for (const match of content.matchAll(requireRe)) {
|
|
120
|
+
pushUnique(out, match[1] ?? "", "require");
|
|
121
|
+
}
|
|
122
|
+
// Route::… Controller class references
|
|
123
|
+
const routeClass = /\[([A-Za-z_\\][\w\\]*)\s*::\s*class/g;
|
|
124
|
+
for (const match of content.matchAll(routeClass)) {
|
|
125
|
+
pushUnique(out, (match[1] ?? "").replace(/\\/g, "/"), "route");
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Extract dependency references from source text using deterministic regex heuristics.
|
|
131
|
+
*/
|
|
132
|
+
export function extractReferences(relativePath, content) {
|
|
133
|
+
if (!isSourceFile(relativePath)) {
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
const ext = extensionOf(relativePath);
|
|
137
|
+
switch (ext) {
|
|
138
|
+
case ".ts":
|
|
139
|
+
case ".tsx":
|
|
140
|
+
case ".js":
|
|
141
|
+
case ".jsx":
|
|
142
|
+
case ".mjs":
|
|
143
|
+
case ".cjs":
|
|
144
|
+
return extractJsFamily(content);
|
|
145
|
+
case ".dart":
|
|
146
|
+
return extractDart(content);
|
|
147
|
+
case ".java":
|
|
148
|
+
return extractJava(content);
|
|
149
|
+
case ".go":
|
|
150
|
+
return extractGo(content);
|
|
151
|
+
case ".py":
|
|
152
|
+
return extractPython(content);
|
|
153
|
+
case ".rs":
|
|
154
|
+
return extractRust(content);
|
|
155
|
+
case ".php":
|
|
156
|
+
return extractPhp(content);
|
|
157
|
+
default:
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
export function refineRelationType(options) {
|
|
162
|
+
const { base, sourcePath, targetPath } = options;
|
|
163
|
+
if (base === "dynamic-import" ||
|
|
164
|
+
base === "require" ||
|
|
165
|
+
base === "export" ||
|
|
166
|
+
base === "package" ||
|
|
167
|
+
base === "route" ||
|
|
168
|
+
base === "module") {
|
|
169
|
+
return base;
|
|
170
|
+
}
|
|
171
|
+
const source = sourcePath.toLowerCase();
|
|
172
|
+
const target = targetPath.toLowerCase();
|
|
173
|
+
if (/(^|\/)routes?\//.test(source) || /(^|\/)pages?\//.test(source)) {
|
|
174
|
+
return "route";
|
|
175
|
+
}
|
|
176
|
+
if (/controller/.test(source) && /service/.test(target)) {
|
|
177
|
+
return "service";
|
|
178
|
+
}
|
|
179
|
+
if (/service/.test(source) && /repositor/.test(target)) {
|
|
180
|
+
return "repository";
|
|
181
|
+
}
|
|
182
|
+
if (/repositor/.test(target)) {
|
|
183
|
+
return "repository";
|
|
184
|
+
}
|
|
185
|
+
if (/service/.test(target) && /controller|handler|route/.test(source)) {
|
|
186
|
+
return "service";
|
|
187
|
+
}
|
|
188
|
+
return base;
|
|
189
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { discoverDependencies, scoreDependencyConfidence } from "./discover.js";
|
|
2
|
+
export { extractReferences, refineRelationType } from "./extract.js";
|
|
3
|
+
export { RELATION_CONFIDENCE } from "./models.js";
|
|
4
|
+
export type { DependencyDiscoveryOptions, DependencyDiscoveryResult, DependencyMatch, DependencyRelationType, ExtractedReference, } from "./types.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DependencyRelationType } from "./types.js";
|
|
2
|
+
/** Base confidence by relation type. Dynamic imports are intentionally lower. */
|
|
3
|
+
export declare const RELATION_CONFIDENCE: Readonly<Record<DependencyRelationType, number>>;
|
|
4
|
+
export declare const SOURCE_EXTENSIONS: Set<string>;
|
|
5
|
+
export declare const RESOLVE_EXTENSIONS: readonly ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".dart", ".java", ".go", ".py", ".rs", ".php", "/index.ts", "/index.tsx", "/index.js", "/index.jsx", "/index.mjs", "/index.dart", "/__init__.py", "/mod.rs"];
|
|
6
|
+
export declare const MANIFEST_FILES: Set<string>;
|
|
7
|
+
/** Path segments skipped when deriving module labels. */
|
|
8
|
+
export declare const LABEL_STOP_SEGMENTS: Set<string>;
|
|
9
|
+
export declare function extensionOf(relativePath: string): string;
|
|
10
|
+
export declare function isSourceFile(relativePath: string): boolean;
|
|
11
|
+
export declare function titleCaseSegment(segment: string): string;
|
|
12
|
+
export declare function clampConfidence(value: number): number;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/** Base confidence by relation type. Dynamic imports are intentionally lower. */
|
|
2
|
+
export const RELATION_CONFIDENCE = {
|
|
3
|
+
import: 0.97,
|
|
4
|
+
export: 0.96,
|
|
5
|
+
require: 0.95,
|
|
6
|
+
"dynamic-import": 0.75,
|
|
7
|
+
package: 0.9,
|
|
8
|
+
module: 0.85,
|
|
9
|
+
route: 0.8,
|
|
10
|
+
service: 0.88,
|
|
11
|
+
repository: 0.88,
|
|
12
|
+
};
|
|
13
|
+
export const SOURCE_EXTENSIONS = new Set([
|
|
14
|
+
".ts",
|
|
15
|
+
".tsx",
|
|
16
|
+
".js",
|
|
17
|
+
".jsx",
|
|
18
|
+
".mjs",
|
|
19
|
+
".cjs",
|
|
20
|
+
".dart",
|
|
21
|
+
".java",
|
|
22
|
+
".go",
|
|
23
|
+
".py",
|
|
24
|
+
".rs",
|
|
25
|
+
".php",
|
|
26
|
+
]);
|
|
27
|
+
export const RESOLVE_EXTENSIONS = [
|
|
28
|
+
"",
|
|
29
|
+
".ts",
|
|
30
|
+
".tsx",
|
|
31
|
+
".js",
|
|
32
|
+
".jsx",
|
|
33
|
+
".mjs",
|
|
34
|
+
".cjs",
|
|
35
|
+
".dart",
|
|
36
|
+
".java",
|
|
37
|
+
".go",
|
|
38
|
+
".py",
|
|
39
|
+
".rs",
|
|
40
|
+
".php",
|
|
41
|
+
"/index.ts",
|
|
42
|
+
"/index.tsx",
|
|
43
|
+
"/index.js",
|
|
44
|
+
"/index.jsx",
|
|
45
|
+
"/index.mjs",
|
|
46
|
+
"/index.dart",
|
|
47
|
+
"/__init__.py",
|
|
48
|
+
"/mod.rs",
|
|
49
|
+
];
|
|
50
|
+
export const MANIFEST_FILES = new Set([
|
|
51
|
+
"package.json",
|
|
52
|
+
"tsconfig.json",
|
|
53
|
+
"tsconfig.base.json",
|
|
54
|
+
"jsconfig.json",
|
|
55
|
+
"pubspec.yaml",
|
|
56
|
+
"go.mod",
|
|
57
|
+
"cargo.toml",
|
|
58
|
+
"pyproject.toml",
|
|
59
|
+
]);
|
|
60
|
+
/** Path segments skipped when deriving module labels. */
|
|
61
|
+
export const LABEL_STOP_SEGMENTS = new Set([
|
|
62
|
+
"src",
|
|
63
|
+
"lib",
|
|
64
|
+
"libs",
|
|
65
|
+
"app",
|
|
66
|
+
"apps",
|
|
67
|
+
"packages",
|
|
68
|
+
"package",
|
|
69
|
+
"services",
|
|
70
|
+
"service",
|
|
71
|
+
"modules",
|
|
72
|
+
"module",
|
|
73
|
+
"internal",
|
|
74
|
+
"cmd",
|
|
75
|
+
"bin",
|
|
76
|
+
"dist",
|
|
77
|
+
"build",
|
|
78
|
+
"out",
|
|
79
|
+
"public",
|
|
80
|
+
"static",
|
|
81
|
+
"assets",
|
|
82
|
+
"test",
|
|
83
|
+
"tests",
|
|
84
|
+
"spec",
|
|
85
|
+
"specs",
|
|
86
|
+
"__tests__",
|
|
87
|
+
"fixtures",
|
|
88
|
+
"node_modules",
|
|
89
|
+
"vendor",
|
|
90
|
+
"main",
|
|
91
|
+
"java",
|
|
92
|
+
"kotlin",
|
|
93
|
+
"resources",
|
|
94
|
+
]);
|
|
95
|
+
export function extensionOf(relativePath) {
|
|
96
|
+
const base = relativePath.split("/").pop() ?? relativePath;
|
|
97
|
+
const dot = base.lastIndexOf(".");
|
|
98
|
+
if (dot <= 0) {
|
|
99
|
+
return "";
|
|
100
|
+
}
|
|
101
|
+
return base.slice(dot).toLowerCase();
|
|
102
|
+
}
|
|
103
|
+
export function isSourceFile(relativePath) {
|
|
104
|
+
return SOURCE_EXTENSIONS.has(extensionOf(relativePath));
|
|
105
|
+
}
|
|
106
|
+
export function titleCaseSegment(segment) {
|
|
107
|
+
if (!segment) {
|
|
108
|
+
return segment;
|
|
109
|
+
}
|
|
110
|
+
const cleaned = segment.replace(/^@/, "").replace(/[^a-zA-Z0-9_-]/g, "");
|
|
111
|
+
const parts = cleaned.split(/[-_]+/).filter(Boolean);
|
|
112
|
+
if (parts.length === 0) {
|
|
113
|
+
return segment;
|
|
114
|
+
}
|
|
115
|
+
return parts.map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
|
|
116
|
+
}
|
|
117
|
+
export function clampConfidence(value) {
|
|
118
|
+
if (value < 0) {
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
if (value > 1) {
|
|
122
|
+
return 1;
|
|
123
|
+
}
|
|
124
|
+
return Math.round(value * 100) / 100;
|
|
125
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type DependencyRelationType = "import" | "require" | "dynamic-import" | "export" | "package" | "module" | "route" | "service" | "repository";
|
|
2
|
+
export interface DependencyMatch {
|
|
3
|
+
from: string;
|
|
4
|
+
to: string;
|
|
5
|
+
type: DependencyRelationType;
|
|
6
|
+
confidence: number;
|
|
7
|
+
evidence: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface DependencyDiscoveryResult {
|
|
10
|
+
dependencies: DependencyMatch[];
|
|
11
|
+
timingMs: number;
|
|
12
|
+
filesConsidered: number;
|
|
13
|
+
filesInspected: number;
|
|
14
|
+
}
|
|
15
|
+
export interface DependencyDiscoveryOptions {
|
|
16
|
+
/** Repository root. Defaults to process.cwd(). */
|
|
17
|
+
cwd?: string;
|
|
18
|
+
/** Minimum confidence to include (0–1). Default 0.7. */
|
|
19
|
+
minConfidence?: number;
|
|
20
|
+
/** Max bytes to read from a source file. Default 256 KiB. */
|
|
21
|
+
maxReadBytes?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface ExtractedReference {
|
|
24
|
+
specifier: string;
|
|
25
|
+
type: DependencyRelationType;
|
|
26
|
+
confidence: number;
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DomainDiscoveryOptions, DomainDiscoveryResult } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Score a domain from evidence count and token hit density.
|
|
4
|
+
* Deterministic; no LLM.
|
|
5
|
+
*/
|
|
6
|
+
export declare function scoreDomainConfidence(options: {
|
|
7
|
+
evidenceCount: number;
|
|
8
|
+
tokenHits: number;
|
|
9
|
+
}): number;
|
|
10
|
+
/**
|
|
11
|
+
* Discover coarse product domains from repository path/filename heuristics.
|
|
12
|
+
* Isolated from scan — call explicitly via the understanding API.
|
|
13
|
+
*/
|
|
14
|
+
export declare function discoverDomains(options?: DomainDiscoveryOptions): Promise<DomainDiscoveryResult>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { discoverFiles } from "../../../discovery/files.js";
|
|
2
|
+
import { domainForToken, tokenizeRelativePath } from "../shared/index.js";
|
|
3
|
+
function clampConfidence(value) {
|
|
4
|
+
if (value < 0) {
|
|
5
|
+
return 0;
|
|
6
|
+
}
|
|
7
|
+
if (value > 1) {
|
|
8
|
+
return 1;
|
|
9
|
+
}
|
|
10
|
+
return Math.round(value * 100) / 100;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Score a domain from evidence count and token hit density.
|
|
14
|
+
* Deterministic; no LLM.
|
|
15
|
+
*/
|
|
16
|
+
export function scoreDomainConfidence(options) {
|
|
17
|
+
const { evidenceCount, tokenHits } = options;
|
|
18
|
+
if (evidenceCount <= 0) {
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
// Base rises with distinct files; bonus for repeated token hits in those files.
|
|
22
|
+
const base = 0.45 + Math.min(evidenceCount, 8) * 0.06;
|
|
23
|
+
const densityBonus = Math.min(tokenHits / Math.max(evidenceCount, 1), 3) * 0.05;
|
|
24
|
+
return clampConfidence(base + densityBonus);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Discover coarse product domains from repository path/filename heuristics.
|
|
28
|
+
* Isolated from scan — call explicitly via the understanding API.
|
|
29
|
+
*/
|
|
30
|
+
export async function discoverDomains(options = {}) {
|
|
31
|
+
const started = performance.now();
|
|
32
|
+
const cwd = options.cwd ?? process.cwd();
|
|
33
|
+
const minConfidence = options.minConfidence ?? 0.5;
|
|
34
|
+
const minEvidence = options.minEvidence ?? 1;
|
|
35
|
+
const discovery = await discoverFiles({ root: cwd });
|
|
36
|
+
const byDomain = new Map();
|
|
37
|
+
for (const file of discovery.files) {
|
|
38
|
+
const tokens = tokenizeRelativePath(file.relativePath);
|
|
39
|
+
if (tokens.length === 0) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const matchedDomains = new Set();
|
|
43
|
+
for (const token of tokens) {
|
|
44
|
+
const domain = domainForToken(token);
|
|
45
|
+
if (!domain) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
matchedDomains.add(domain);
|
|
49
|
+
const bucket = byDomain.get(domain) ?? { evidence: new Set(), tokenHits: 0 };
|
|
50
|
+
bucket.tokenHits += 1;
|
|
51
|
+
byDomain.set(domain, bucket);
|
|
52
|
+
}
|
|
53
|
+
for (const domain of matchedDomains) {
|
|
54
|
+
const bucket = byDomain.get(domain);
|
|
55
|
+
if (!bucket) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
bucket.evidence.add(file.relativePath);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const domains = [];
|
|
62
|
+
for (const [name, bucket] of byDomain) {
|
|
63
|
+
if (bucket.evidence.size < minEvidence) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const confidence = scoreDomainConfidence({
|
|
67
|
+
evidenceCount: bucket.evidence.size,
|
|
68
|
+
tokenHits: bucket.tokenHits,
|
|
69
|
+
});
|
|
70
|
+
if (confidence < minConfidence) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
domains.push({
|
|
74
|
+
name,
|
|
75
|
+
confidence,
|
|
76
|
+
evidence: [...bucket.evidence].sort((a, b) => a.localeCompare(b)),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
domains.sort((a, b) => {
|
|
80
|
+
if (b.confidence !== a.confidence) {
|
|
81
|
+
return b.confidence - a.confidence;
|
|
82
|
+
}
|
|
83
|
+
return a.name.localeCompare(b.name);
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
domains,
|
|
87
|
+
timingMs: Math.round(performance.now() - started),
|
|
88
|
+
filesConsidered: discovery.files.length,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { discoverDomains, scoreDomainConfidence } from "./discover.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { EntrypointDiscoveryOptions, EntrypointDiscoveryResult } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Discover likely application entrypoints via deterministic path + content heuristics.
|
|
4
|
+
* Isolated from scan — internal understanding API only.
|
|
5
|
+
*/
|
|
6
|
+
export declare function discoverEntrypoints(options?: EntrypointDiscoveryOptions): Promise<EntrypointDiscoveryResult>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { discoverFiles } from "../../../discovery/files.js";
|
|
2
|
+
import { ENTRYPOINT_MODELS } from "./models.js";
|
|
3
|
+
import { extractEntrypointSignals, scoreEntrypointConfidence } from "./extract.js";
|
|
4
|
+
const DEFAULT_MAX_READ_BYTES = 256 * 1024;
|
|
5
|
+
/**
|
|
6
|
+
* Discover likely application entrypoints via deterministic path + content heuristics.
|
|
7
|
+
* Isolated from scan — internal understanding API only.
|
|
8
|
+
*/
|
|
9
|
+
export async function discoverEntrypoints(options = {}) {
|
|
10
|
+
const started = performance.now();
|
|
11
|
+
const cwd = options.cwd ?? process.cwd();
|
|
12
|
+
const minConfidence = options.minConfidence ?? 0.55;
|
|
13
|
+
const maxReadBytes = options.maxReadBytes ?? DEFAULT_MAX_READ_BYTES;
|
|
14
|
+
const discovery = await discoverFiles({ root: cwd });
|
|
15
|
+
const entrypoints = [];
|
|
16
|
+
let filesInspected = 0;
|
|
17
|
+
for (const file of discovery.files) {
|
|
18
|
+
for (const model of ENTRYPOINT_MODELS) {
|
|
19
|
+
if (!model.pathTest(file.relativePath)) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
filesInspected += 1;
|
|
23
|
+
const extracted = await extractEntrypointSignals({
|
|
24
|
+
absolutePath: file.absolutePath,
|
|
25
|
+
model,
|
|
26
|
+
maxReadBytes,
|
|
27
|
+
});
|
|
28
|
+
const confidence = scoreEntrypointConfidence({
|
|
29
|
+
pathConfidence: model.pathConfidence,
|
|
30
|
+
signalBoost: model.signalBoost,
|
|
31
|
+
signalHits: extracted.signalHits,
|
|
32
|
+
requireSignal: model.requireSignal,
|
|
33
|
+
});
|
|
34
|
+
if (confidence === null || confidence < minConfidence) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const evidence = [`path:${file.relativePath}`, ...extracted.evidence];
|
|
38
|
+
entrypoints.push({
|
|
39
|
+
framework: model.framework,
|
|
40
|
+
file: file.relativePath,
|
|
41
|
+
confidence,
|
|
42
|
+
evidence,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
entrypoints.sort((a, b) => {
|
|
47
|
+
if (b.confidence !== a.confidence) {
|
|
48
|
+
return b.confidence - a.confidence;
|
|
49
|
+
}
|
|
50
|
+
const frameworkCmp = a.framework.localeCompare(b.framework);
|
|
51
|
+
if (frameworkCmp !== 0) {
|
|
52
|
+
return frameworkCmp;
|
|
53
|
+
}
|
|
54
|
+
return a.file.localeCompare(b.file);
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
entrypoints,
|
|
58
|
+
timingMs: Math.round(performance.now() - started),
|
|
59
|
+
filesConsidered: discovery.files.length,
|
|
60
|
+
filesInspected,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { EntrypointModel } from "./models.js";
|
|
2
|
+
export interface ExtractedEntrypointSignals {
|
|
3
|
+
evidence: string[];
|
|
4
|
+
signalHits: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Read a bounded slice of a candidate file and collect matching content signals.
|
|
8
|
+
*/
|
|
9
|
+
export declare function extractEntrypointSignals(options: {
|
|
10
|
+
absolutePath: string;
|
|
11
|
+
model: EntrypointModel;
|
|
12
|
+
maxReadBytes: number;
|
|
13
|
+
}): Promise<ExtractedEntrypointSignals>;
|
|
14
|
+
export declare function scoreEntrypointConfidence(options: {
|
|
15
|
+
pathConfidence: number;
|
|
16
|
+
signalBoost: number;
|
|
17
|
+
signalHits: number;
|
|
18
|
+
requireSignal: boolean;
|
|
19
|
+
}): number | null;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
/**
|
|
3
|
+
* Read a bounded slice of a candidate file and collect matching content signals.
|
|
4
|
+
*/
|
|
5
|
+
export async function extractEntrypointSignals(options) {
|
|
6
|
+
const { absolutePath, model, maxReadBytes } = options;
|
|
7
|
+
let content;
|
|
8
|
+
try {
|
|
9
|
+
const handle = await fs.open(absolutePath, "r");
|
|
10
|
+
try {
|
|
11
|
+
const stat = await handle.stat();
|
|
12
|
+
const size = Math.min(Number(stat.size), maxReadBytes);
|
|
13
|
+
if (size <= 0) {
|
|
14
|
+
return { evidence: [], signalHits: 0 };
|
|
15
|
+
}
|
|
16
|
+
const buffer = Buffer.alloc(size);
|
|
17
|
+
const { bytesRead } = await handle.read(buffer, 0, size, 0);
|
|
18
|
+
content = buffer.subarray(0, bytesRead).toString("utf8");
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
await handle.close();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return { evidence: [], signalHits: 0 };
|
|
26
|
+
}
|
|
27
|
+
const evidence = [];
|
|
28
|
+
for (const signal of model.signals) {
|
|
29
|
+
if (signal.pattern.test(content)) {
|
|
30
|
+
evidence.push(signal.label);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { evidence, signalHits: evidence.length };
|
|
34
|
+
}
|
|
35
|
+
export function scoreEntrypointConfidence(options) {
|
|
36
|
+
const { pathConfidence, signalBoost, signalHits, requireSignal } = options;
|
|
37
|
+
if (requireSignal && signalHits === 0) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const raw = pathConfidence + signalHits * signalBoost;
|
|
41
|
+
const clamped = Math.min(0.99, Math.max(0, raw));
|
|
42
|
+
return Math.round(clamped * 100) / 100;
|
|
43
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { discoverEntrypoints } from "./discover.js";
|
|
2
|
+
export { scoreEntrypointConfidence, extractEntrypointSignals } from "./extract.js";
|
|
3
|
+
export { ENTRYPOINT_MODELS } from "./models.js";
|
|
4
|
+
export type { EntrypointDiscoveryOptions, EntrypointDiscoveryResult, EntrypointFramework, EntrypointMatch, } from "./types.js";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { EntrypointFramework } from "./types.js";
|
|
2
|
+
export interface ContentSignal {
|
|
3
|
+
/** Stable evidence label returned in JSON (e.g. "runApp()"). */
|
|
4
|
+
label: string;
|
|
5
|
+
pattern: RegExp;
|
|
6
|
+
}
|
|
7
|
+
export interface EntrypointModel {
|
|
8
|
+
framework: EntrypointFramework;
|
|
9
|
+
/** Path must match before we inspect content (except contentOnly models). */
|
|
10
|
+
pathTest: (relativePath: string) => boolean;
|
|
11
|
+
signals: ContentSignal[];
|
|
12
|
+
/** Confidence when only the path convention matches. */
|
|
13
|
+
pathConfidence: number;
|
|
14
|
+
/** Added per distinct content signal hit, capped with pathConfidence at 0.99. */
|
|
15
|
+
signalBoost: number;
|
|
16
|
+
/**
|
|
17
|
+
* When true, pathTest alone is insufficient — at least one content signal required.
|
|
18
|
+
* Prevents guessing from generic names like main.ts / app.ts.
|
|
19
|
+
*/
|
|
20
|
+
requireSignal: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Deterministic entrypoint models. Order matters for stable multi-match preference
|
|
24
|
+
* when the same file could qualify under multiple frameworks (NestJS before Node).
|
|
25
|
+
*/
|
|
26
|
+
export declare const ENTRYPOINT_MODELS: readonly EntrypointModel[];
|