@praneeth_54/agentdoctor 2.0.1 → 3.0.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 +123 -1
- package/README.md +510 -260
- package/dist/agent/approvals.d.ts +24 -0
- package/dist/agent/approvals.js +64 -0
- package/dist/agent/chat/deterministic.d.ts +6 -0
- package/dist/agent/chat/deterministic.js +180 -0
- package/dist/agent/chat/index.d.ts +7 -0
- package/dist/agent/chat/index.js +5 -0
- package/dist/agent/chat/memory.d.ts +44 -0
- package/dist/agent/chat/memory.js +103 -0
- package/dist/agent/chat/project-summary.d.ts +16 -0
- package/dist/agent/chat/project-summary.js +70 -0
- package/dist/agent/chat/prompts.d.ts +6 -0
- package/dist/agent/chat/prompts.js +39 -0
- package/dist/agent/chat/response.d.ts +19 -0
- package/dist/agent/chat/response.js +109 -0
- package/dist/agent/chat/service.d.ts +42 -0
- package/dist/agent/chat/service.js +246 -0
- package/dist/agent/chat/types.d.ts +48 -0
- package/dist/agent/chat/types.js +1 -0
- package/dist/agent/context/retrieve.d.ts +21 -0
- package/dist/agent/context/retrieve.js +117 -0
- package/dist/agent/context/truth.d.ts +6 -0
- package/dist/agent/context/truth.js +19 -0
- package/dist/agent/context/types.d.ts +23 -0
- package/dist/agent/context/types.js +4 -0
- package/dist/agent/index.d.ts +28 -0
- package/dist/agent/index.js +15 -0
- package/dist/agent/loop.d.ts +53 -0
- package/dist/agent/loop.js +253 -0
- package/dist/agent/modes.d.ts +18 -0
- package/dist/agent/modes.js +102 -0
- package/dist/agent/plan.d.ts +30 -0
- package/dist/agent/plan.js +121 -0
- package/dist/agent/roles.d.ts +12 -0
- package/dist/agent/roles.js +138 -0
- package/dist/agent/runtime.d.ts +83 -0
- package/dist/agent/runtime.js +293 -0
- package/dist/agent/state.d.ts +30 -0
- package/dist/agent/state.js +95 -0
- package/dist/agent/student.d.ts +56 -0
- package/dist/agent/student.js +230 -0
- package/dist/agent/tools/execute.d.ts +20 -0
- package/dist/agent/tools/execute.js +365 -0
- package/dist/agent/tools/index.d.ts +6 -0
- package/dist/agent/tools/index.js +5 -0
- package/dist/agent/tools/registry.d.ts +7 -0
- package/dist/agent/tools/registry.js +212 -0
- package/dist/agent/tools/run.d.ts +24 -0
- package/dist/agent/tools/run.js +44 -0
- package/dist/agent/tools/types.d.ts +32 -0
- package/dist/agent/tools/types.js +10 -0
- package/dist/agent/tools/write.d.ts +24 -0
- package/dist/agent/tools/write.js +121 -0
- package/dist/agent/verify.d.ts +29 -0
- package/dist/agent/verify.js +210 -0
- package/dist/ai/config.d.ts +22 -0
- package/dist/ai/config.js +69 -0
- package/dist/ai/index.d.ts +17 -0
- package/dist/ai/index.js +52 -0
- package/dist/ai/providers/mock.d.ts +20 -0
- package/dist/ai/providers/mock.js +84 -0
- package/dist/ai/providers/none.d.ts +6 -0
- package/dist/ai/providers/none.js +23 -0
- package/dist/ai/providers/openai-compatible.d.ts +21 -0
- package/dist/ai/providers/openai-compatible.js +151 -0
- package/dist/ai/redact.d.ts +9 -0
- package/dist/ai/redact.js +61 -0
- package/dist/ai/types.d.ts +71 -0
- package/dist/ai/types.js +6 -0
- package/dist/cli/commands/agent.d.ts +29 -0
- package/dist/cli/commands/agent.js +164 -0
- package/dist/cli/commands/chat.d.ts +14 -0
- package/dist/cli/commands/chat.js +153 -0
- package/dist/cli/commands/learn.d.ts +12 -0
- package/dist/cli/commands/learn.js +107 -0
- package/dist/cli/commands/product.d.ts +19 -0
- package/dist/cli/commands/product.js +147 -0
- package/dist/cli/commands/start.d.ts +15 -0
- package/dist/cli/commands/start.js +80 -0
- package/dist/cli/program.js +233 -0
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/dashboard/server.d.ts +6 -0
- package/dist/dashboard/server.js +333 -43
- package/dist/enforcement/runner.d.ts +5 -0
- package/dist/enforcement/runner.js +51 -4
- package/dist/index.d.ts +17 -0
- package/dist/index.js +10 -0
- package/dist/intelligence/graph/build.js +36 -8
- package/dist/intelligence/resolve/imports.js +1 -1
- package/dist/languages/dart.d.ts +10 -0
- package/dist/languages/dart.js +99 -0
- package/dist/languages/go.d.ts +13 -7
- package/dist/languages/go.js +91 -26
- package/dist/languages/index.d.ts +5 -1
- package/dist/languages/index.js +13 -36
- package/dist/languages/java.d.ts +10 -0
- package/dist/languages/java.js +80 -0
- package/dist/languages/kotlin.d.ts +10 -0
- package/dist/languages/kotlin.js +85 -0
- package/dist/languages/php.d.ts +1 -0
- package/dist/languages/php.js +11 -2
- package/dist/languages/python.d.ts +6 -2
- package/dist/languages/python.js +39 -9
- package/dist/languages/rust.d.ts +10 -0
- package/dist/languages/rust.js +93 -0
- package/dist/languages/types.d.ts +4 -3
- package/dist/mcp/agent/registry.d.ts +13 -0
- package/dist/mcp/agent/registry.js +320 -0
- package/dist/mcp/agentdoctor/server.js +8 -1
- package/dist/mcp/intelligence/handlers.d.ts +3 -0
- package/dist/mcp/intelligence/handlers.js +28 -0
- package/dist/mcp/intelligence/registry.d.ts +1 -1
- package/dist/mcp/intelligence/registry.js +30 -1
- package/dist/product/api/doctor.d.ts +14 -0
- package/dist/product/api/doctor.js +185 -0
- package/dist/product/api/openapi.d.ts +7 -0
- package/dist/product/api/openapi.js +122 -0
- package/dist/product/approval/model.d.ts +30 -0
- package/dist/product/approval/model.js +64 -0
- package/dist/product/approval/session.d.ts +49 -0
- package/dist/product/approval/session.js +134 -0
- package/dist/product/database/doctor.d.ts +30 -0
- package/dist/product/database/doctor.js +184 -0
- package/dist/product/decisions/ledger.d.ts +24 -0
- package/dist/product/decisions/ledger.js +110 -0
- package/dist/product/deps/analyze.d.ts +46 -0
- package/dist/product/deps/analyze.js +137 -0
- package/dist/product/deps/lockfiles.d.ts +25 -0
- package/dist/product/deps/lockfiles.js +200 -0
- package/dist/product/discovery/roots.d.ts +42 -0
- package/dist/product/discovery/roots.js +215 -0
- package/dist/product/dna/build.d.ts +50 -0
- package/dist/product/dna/build.js +255 -0
- package/dist/product/eval/lab.d.ts +17 -0
- package/dist/product/eval/lab.js +218 -0
- package/dist/product/events/doctor.d.ts +21 -0
- package/dist/product/events/doctor.js +147 -0
- package/dist/product/evidence-scan.d.ts +12 -0
- package/dist/product/evidence-scan.js +46 -0
- package/dist/product/evolution/timeline.d.ts +29 -0
- package/dist/product/evolution/timeline.js +123 -0
- package/dist/product/features/intelligence.d.ts +23 -0
- package/dist/product/features/intelligence.js +158 -0
- package/dist/product/forensic/mode.d.ts +25 -0
- package/dist/product/forensic/mode.js +70 -0
- package/dist/product/graph/enrich-languages.d.ts +20 -0
- package/dist/product/graph/enrich-languages.js +193 -0
- package/dist/product/health/code-health.d.ts +20 -0
- package/dist/product/health/code-health.js +149 -0
- package/dist/product/index.d.ts +69 -0
- package/dist/product/index.js +35 -0
- package/dist/product/ledger/change-ledger.d.ts +23 -0
- package/dist/product/ledger/change-ledger.js +64 -0
- package/dist/product/map/software-map.d.ts +17 -0
- package/dist/product/map/software-map.js +95 -0
- package/dist/product/memory/institutional.d.ts +16 -0
- package/dist/product/memory/institutional.js +87 -0
- package/dist/product/ops/incident.d.ts +20 -0
- package/dist/product/ops/incident.js +61 -0
- package/dist/product/ops/infra.d.ts +15 -0
- package/dist/product/ops/infra.js +112 -0
- package/dist/product/org/model.d.ts +34 -0
- package/dist/product/org/model.js +195 -0
- package/dist/product/privacy/doctor.d.ts +13 -0
- package/dist/product/privacy/doctor.js +90 -0
- package/dist/product/requirements/trace.d.ts +21 -0
- package/dist/product/requirements/trace.js +166 -0
- package/dist/product/search/index.d.ts +29 -0
- package/dist/product/search/index.js +116 -0
- package/dist/product/search/software-search.d.ts +19 -0
- package/dist/product/search/software-search.js +100 -0
- package/dist/product/security/doctor.d.ts +23 -0
- package/dist/product/security/doctor.js +124 -0
- package/dist/product/self/diagnose.d.ts +15 -0
- package/dist/product/self/diagnose.js +82 -0
- package/dist/product/techdebt/roadmap.d.ts +20 -0
- package/dist/product/techdebt/roadmap.js +118 -0
- package/dist/product/testbrain/analyze.d.ts +29 -0
- package/dist/product/testbrain/analyze.js +129 -0
- package/dist/product/truth.d.ts +12 -0
- package/dist/product/truth.js +30 -0
- package/dist/product/twin/digital-twin.d.ts +23 -0
- package/dist/product/twin/digital-twin.js +52 -0
- package/dist/product/twin/store.d.ts +21 -0
- package/dist/product/twin/store.js +70 -0
- package/dist/product/whatif/engine.d.ts +28 -0
- package/dist/product/whatif/engine.js +70 -0
- package/dist/security/paths.js +43 -15
- package/dist/utils/fs.js +10 -2
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ import { resolveRepoRoot, toPosixRelative } from "../../utils/path.js";
|
|
|
6
6
|
import { buildRepositoryGraph } from "../../platform/graph/build.js";
|
|
7
7
|
import { CONTRACTS_VERSION } from "../../contracts/index.js";
|
|
8
8
|
import { loadTsconfigPaths, resolveImportSpecifier, } from "../resolve/imports.js";
|
|
9
|
+
import { enrichGraphWithLanguageAdapters } from "../../product/graph/enrich-languages.js";
|
|
9
10
|
function evidenceForConfidence(confidence) {
|
|
10
11
|
if (confidence === "EXACT")
|
|
11
12
|
return "verified";
|
|
@@ -16,6 +17,33 @@ function evidenceForConfidence(confidence) {
|
|
|
16
17
|
export function nodeId(kind, key) {
|
|
17
18
|
return `${kind}:${createHash("sha1").update(key).digest("hex").slice(0, 12)}`;
|
|
18
19
|
}
|
|
20
|
+
async function applyLanguageEnrichment(graph, root) {
|
|
21
|
+
try {
|
|
22
|
+
const { graph: enriched, stats } = await enrichGraphWithLanguageAdapters(graph, root);
|
|
23
|
+
const extra = stats.filesParsed > 0
|
|
24
|
+
? [
|
|
25
|
+
`Language adapters enriched graph (+${stats.nodesAdded} nodes, +${stats.edgesAdded} edges, ${stats.filesParsed} files parsed)`,
|
|
26
|
+
]
|
|
27
|
+
: stats.filesAttempted > 0
|
|
28
|
+
? ["Language adapter enrichment: no supported parses in sampled .py/.php/.go files"]
|
|
29
|
+
: [];
|
|
30
|
+
return {
|
|
31
|
+
...enriched,
|
|
32
|
+
builder: graph.builder,
|
|
33
|
+
astFilesParsed: graph.astFilesParsed,
|
|
34
|
+
limitations: [...enriched.limitations, ...extra],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
return {
|
|
39
|
+
...graph,
|
|
40
|
+
limitations: [
|
|
41
|
+
...graph.limitations,
|
|
42
|
+
`Language adapter enrichment failed (${error instanceof Error ? error.message : String(error)})`,
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
19
47
|
export async function listTsFiles(root, limit = 400) {
|
|
20
48
|
const out = [];
|
|
21
49
|
const skip = new Set(["node_modules", ".git", "dist", "coverage", ".agentdoctor", "vendor"]);
|
|
@@ -56,13 +84,13 @@ export async function buildIntelligenceGraph(options) {
|
|
|
56
84
|
const mode = options.mode ?? "auto";
|
|
57
85
|
if (mode === "regex") {
|
|
58
86
|
const g = await buildRepositoryGraph(root);
|
|
59
|
-
return { ...g, builder: "regex", astFilesParsed: 0 };
|
|
87
|
+
return applyLanguageEnrichment({ ...g, builder: "regex", astFilesParsed: 0 }, root);
|
|
60
88
|
}
|
|
61
89
|
try {
|
|
62
90
|
const files = await listTsFiles(root);
|
|
63
91
|
if (files.length === 0) {
|
|
64
92
|
const g = await buildRepositoryGraph(root);
|
|
65
|
-
return {
|
|
93
|
+
return applyLanguageEnrichment({
|
|
66
94
|
...g,
|
|
67
95
|
builder: "regex",
|
|
68
96
|
astFilesParsed: 0,
|
|
@@ -70,7 +98,7 @@ export async function buildIntelligenceGraph(options) {
|
|
|
70
98
|
...g.limitations,
|
|
71
99
|
"No TypeScript sources found for AST builder; used regex fallback",
|
|
72
100
|
],
|
|
73
|
-
};
|
|
101
|
+
}, root);
|
|
74
102
|
}
|
|
75
103
|
const program = ts.createProgram({
|
|
76
104
|
rootNames: files,
|
|
@@ -228,7 +256,7 @@ export async function buildIntelligenceGraph(options) {
|
|
|
228
256
|
}
|
|
229
257
|
nodes.sort((a, b) => a.id.localeCompare(b.id));
|
|
230
258
|
edges.sort((a, b) => a.id.localeCompare(b.id));
|
|
231
|
-
return {
|
|
259
|
+
return applyLanguageEnrichment({
|
|
232
260
|
root,
|
|
233
261
|
generatedAt: new Date().toISOString(),
|
|
234
262
|
nodes,
|
|
@@ -239,14 +267,14 @@ export async function buildIntelligenceGraph(options) {
|
|
|
239
267
|
"TypeScript AST builder uses the TypeScript compiler API for .ts/.tsx only",
|
|
240
268
|
"Cross-file call resolution is identifier-based (not full type-checker binding)",
|
|
241
269
|
"Import edges use EXACT|RESOLVED|INFERRED confidence; UNRESOLVED never invents file targets",
|
|
242
|
-
"
|
|
270
|
+
"Additional .py/.php/.go nodes may be merged via language adapters when supported",
|
|
243
271
|
`analysisVersion=${CONTRACTS_VERSION}`,
|
|
244
272
|
],
|
|
245
|
-
};
|
|
273
|
+
}, root);
|
|
246
274
|
}
|
|
247
275
|
catch (error) {
|
|
248
276
|
const g = await buildRepositoryGraph(root);
|
|
249
|
-
return {
|
|
277
|
+
return applyLanguageEnrichment({
|
|
250
278
|
...g,
|
|
251
279
|
builder: "regex",
|
|
252
280
|
astFilesParsed: 0,
|
|
@@ -254,6 +282,6 @@ export async function buildIntelligenceGraph(options) {
|
|
|
254
282
|
...g.limitations,
|
|
255
283
|
`TypeScript AST builder failed; regex fallback used (${error instanceof Error ? error.message : String(error)})`,
|
|
256
284
|
],
|
|
257
|
-
};
|
|
285
|
+
}, root);
|
|
258
286
|
}
|
|
259
287
|
}
|
|
@@ -143,7 +143,7 @@ function matchTsconfigPath(specifier, config) {
|
|
|
143
143
|
specifier.endsWith(suffix)) {
|
|
144
144
|
const star = specifier.slice(prefix.length, specifier.length - suffix.length);
|
|
145
145
|
const target = targets[0];
|
|
146
|
-
const mapped = target.includes("*") ? target.
|
|
146
|
+
const mapped = target.includes("*") ? target.split("*").join(star) : target;
|
|
147
147
|
return { mapped, pattern };
|
|
148
148
|
}
|
|
149
149
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { LanguageAdapter, LanguageImport, LanguageSymbol } from "./types.js";
|
|
2
|
+
export interface DartParseSummary {
|
|
3
|
+
libraryName: string;
|
|
4
|
+
imports: LanguageImport[];
|
|
5
|
+
symbols: LanguageSymbol[];
|
|
6
|
+
limitations: string[];
|
|
7
|
+
}
|
|
8
|
+
/** Lightweight line-oriented Dart scan — not Dart analyzer APIs. */
|
|
9
|
+
export declare function parseDartSource(filePath: string, source: string): DartParseSummary;
|
|
10
|
+
export declare const dartAdapter: LanguageAdapter;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/** Lightweight line-oriented Dart scan — not Dart analyzer APIs. */
|
|
2
|
+
export function parseDartSource(filePath, source) {
|
|
3
|
+
const lines = source.split(/\r?\n/);
|
|
4
|
+
const limitations = [
|
|
5
|
+
"Dart parsing uses a lightweight line scanner — not the Dart analyzer; calls/types are partial.",
|
|
6
|
+
"Full Dart analyzer or tree-sitter-dart integration remains an EXTERNAL enhancement path (not bundled).",
|
|
7
|
+
];
|
|
8
|
+
let libraryName = "";
|
|
9
|
+
const imports = [];
|
|
10
|
+
const symbols = [];
|
|
11
|
+
for (let i = 0; i < lines.length; i++) {
|
|
12
|
+
const trimmed = lines[i].trim();
|
|
13
|
+
if (!libraryName && trimmed.startsWith("library ")) {
|
|
14
|
+
libraryName = trimmed.slice("library ".length).replace(/;$/, "").trim();
|
|
15
|
+
}
|
|
16
|
+
if (trimmed.startsWith("import ") && trimmed.endsWith(";")) {
|
|
17
|
+
const spec = trimmed
|
|
18
|
+
.slice("import ".length, -1)
|
|
19
|
+
.replace(/^['"]|['"]$/g, "")
|
|
20
|
+
.trim();
|
|
21
|
+
if (spec)
|
|
22
|
+
imports.push({ fromFile: filePath, specifier: spec, evidence: "ast" });
|
|
23
|
+
}
|
|
24
|
+
if (trimmed.startsWith("export ") && trimmed.endsWith(";")) {
|
|
25
|
+
const spec = trimmed
|
|
26
|
+
.slice("export ".length, -1)
|
|
27
|
+
.replace(/^['"]|['"]$/g, "")
|
|
28
|
+
.trim();
|
|
29
|
+
if (spec)
|
|
30
|
+
imports.push({ fromFile: filePath, specifier: spec, evidence: "ast" });
|
|
31
|
+
}
|
|
32
|
+
const typeMatch = /^(?:abstract\s+)?(?:class|mixin|extension)\s+(\w+)/.exec(trimmed);
|
|
33
|
+
if (typeMatch) {
|
|
34
|
+
let kind = "class";
|
|
35
|
+
if (trimmed.includes("mixin"))
|
|
36
|
+
kind = "mixin";
|
|
37
|
+
else if (trimmed.includes("extension"))
|
|
38
|
+
kind = "extension";
|
|
39
|
+
symbols.push({
|
|
40
|
+
id: `dart:${kind}:${filePath}:${typeMatch[1]}`,
|
|
41
|
+
name: typeMatch[1],
|
|
42
|
+
kind,
|
|
43
|
+
file: filePath,
|
|
44
|
+
line: i + 1,
|
|
45
|
+
evidence: "ast",
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
const fnMatch = /^(?:\w+\s+)?(\w+)\s*\([^)]*\)\s*(?:async\s*)?\{?\s*$/.exec(trimmed);
|
|
49
|
+
if (fnMatch &&
|
|
50
|
+
!trimmed.startsWith("if ") &&
|
|
51
|
+
!trimmed.startsWith("for ") &&
|
|
52
|
+
!trimmed.startsWith("while ") &&
|
|
53
|
+
!trimmed.startsWith("class ") &&
|
|
54
|
+
!trimmed.startsWith("return ")) {
|
|
55
|
+
const name = fnMatch[1];
|
|
56
|
+
if (!["void", "final", "const", "var", "late"].includes(name)) {
|
|
57
|
+
symbols.push({
|
|
58
|
+
id: `dart:function:${filePath}:${name}`,
|
|
59
|
+
name,
|
|
60
|
+
kind: "function",
|
|
61
|
+
file: filePath,
|
|
62
|
+
line: i + 1,
|
|
63
|
+
evidence: "ast",
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return { libraryName, imports, symbols, limitations };
|
|
69
|
+
}
|
|
70
|
+
const DART_CAPABILITIES = () => ({
|
|
71
|
+
parse: "supported",
|
|
72
|
+
symbols: "supported",
|
|
73
|
+
definitions: "unsupported",
|
|
74
|
+
references: "unsupported",
|
|
75
|
+
imports: "supported",
|
|
76
|
+
calls: "partial",
|
|
77
|
+
diagnostics: "unsupported",
|
|
78
|
+
types: "partial",
|
|
79
|
+
});
|
|
80
|
+
export const dartAdapter = {
|
|
81
|
+
id: "dart",
|
|
82
|
+
extensions: [".dart"],
|
|
83
|
+
capabilities: DART_CAPABILITIES,
|
|
84
|
+
async parse(filePath, source) {
|
|
85
|
+
const summary = parseDartSource(filePath, source);
|
|
86
|
+
const ok = Boolean(summary.libraryName || summary.symbols.length > 0 || summary.imports.length > 0);
|
|
87
|
+
return {
|
|
88
|
+
language: "dart",
|
|
89
|
+
file: filePath,
|
|
90
|
+
ok,
|
|
91
|
+
capabilities: dartAdapter.capabilities(),
|
|
92
|
+
symbols: summary.symbols,
|
|
93
|
+
imports: summary.imports,
|
|
94
|
+
calls: [],
|
|
95
|
+
diagnostics: ok ? [] : ["no library, import, or declarations detected"],
|
|
96
|
+
limitations: summary.limitations,
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
};
|
package/dist/languages/go.d.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import type { LanguageAdapter } from "./types.js";
|
|
2
|
-
/**
|
|
3
|
-
* Go toolchain bridge placeholder.
|
|
4
|
-
* Prefer real `go/ast` via `go run` when the Go toolchain is present; until an
|
|
5
|
-
* extractor is bundled, capability remains unsupported even if `go` exists.
|
|
6
|
-
* Today: always unsupported (no bundled extractor; avoids fake AST claims).
|
|
7
|
-
*/
|
|
1
|
+
import type { LanguageAdapter, LanguageSymbol, LanguageImport } from "./types.js";
|
|
8
2
|
export declare function goAvailable(): boolean;
|
|
3
|
+
export interface GoSourceRange {
|
|
4
|
+
startLine: number;
|
|
5
|
+
endLine: number;
|
|
6
|
+
}
|
|
7
|
+
export interface GoParseSummary {
|
|
8
|
+
packageName: string;
|
|
9
|
+
imports: LanguageImport[];
|
|
10
|
+
symbols: LanguageSymbol[];
|
|
11
|
+
limitations: string[];
|
|
12
|
+
}
|
|
13
|
+
/** Lightweight line-oriented Go scan (not go/ast). Honest partial call resolution. */
|
|
14
|
+
export declare function parseGoSource(filePath: string, source: string): GoParseSummary;
|
|
9
15
|
export declare const goAdapter: LanguageAdapter;
|
package/dist/languages/go.js
CHANGED
|
@@ -1,45 +1,110 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
-
|
|
3
|
-
* Go toolchain bridge placeholder.
|
|
4
|
-
* Prefer real `go/ast` via `go run` when the Go toolchain is present; until an
|
|
5
|
-
* extractor is bundled, capability remains unsupported even if `go` exists.
|
|
6
|
-
* Today: always unsupported (no bundled extractor; avoids fake AST claims).
|
|
7
|
-
*/
|
|
2
|
+
const GO_PROBE_TIMEOUT_MS = 5_000;
|
|
8
3
|
export function goAvailable() {
|
|
9
|
-
const r = spawnSync("go", ["version"], {
|
|
10
|
-
|
|
4
|
+
const r = spawnSync("go", ["version"], {
|
|
5
|
+
encoding: "utf8",
|
|
6
|
+
timeout: GO_PROBE_TIMEOUT_MS,
|
|
7
|
+
windowsHide: true,
|
|
8
|
+
});
|
|
9
|
+
return r.status === 0 && !r.error;
|
|
10
|
+
}
|
|
11
|
+
function lineTrimmed(source, lineIndex) {
|
|
12
|
+
const lines = source.split(/\r?\n/);
|
|
13
|
+
return lines[lineIndex]?.trim() ?? "";
|
|
14
|
+
}
|
|
15
|
+
/** Lightweight line-oriented Go scan (not go/ast). Honest partial call resolution. */
|
|
16
|
+
export function parseGoSource(filePath, source) {
|
|
17
|
+
const lines = source.split(/\r?\n/);
|
|
18
|
+
const limitations = [
|
|
19
|
+
"Go parsing uses a lightweight line scanner — not go/ast; calls are not resolved.",
|
|
20
|
+
goAvailable()
|
|
21
|
+
? "Go toolchain is present; full go/ast bridge remains EXTERNAL (not bundled)."
|
|
22
|
+
: "Go toolchain not on PATH; same lightweight scanner used.",
|
|
23
|
+
];
|
|
24
|
+
let packageName = "";
|
|
25
|
+
const imports = [];
|
|
26
|
+
const symbols = [];
|
|
27
|
+
for (let i = 0; i < lines.length; i++) {
|
|
28
|
+
const raw = lines[i];
|
|
29
|
+
const trimmed = raw.trim();
|
|
30
|
+
if (!packageName && trimmed.startsWith("package ") && !trimmed.startsWith("package (")) {
|
|
31
|
+
packageName = trimmed.slice("package ".length).split(/\s+/)[0] ?? "";
|
|
32
|
+
}
|
|
33
|
+
if (trimmed.startsWith("import ") || trimmed === "import (") {
|
|
34
|
+
if (trimmed === "import (") {
|
|
35
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
36
|
+
const inner = lines[j].trim();
|
|
37
|
+
if (inner === ")") {
|
|
38
|
+
i = j;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
const spec = inner.replace(/^"|"$/g, "").replace(/^'|'$/g, "");
|
|
42
|
+
if (spec && spec !== "") {
|
|
43
|
+
imports.push({ fromFile: filePath, specifier: spec, evidence: "ast" });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const spec = trimmed.slice("import ".length).replace(/^"|"$/g, "").trim();
|
|
49
|
+
if (spec)
|
|
50
|
+
imports.push({ fromFile: filePath, specifier: spec, evidence: "ast" });
|
|
51
|
+
}
|
|
52
|
+
if (trimmed.startsWith("func ")) {
|
|
53
|
+
const nameMatch = /^func\s+(?:\([^)]*\)\s+)?(\w+)/.exec(trimmed);
|
|
54
|
+
if (nameMatch) {
|
|
55
|
+
symbols.push({
|
|
56
|
+
id: `go:func:${filePath}:${nameMatch[1]}`,
|
|
57
|
+
name: nameMatch[1],
|
|
58
|
+
kind: "function",
|
|
59
|
+
file: filePath,
|
|
60
|
+
line: i + 1,
|
|
61
|
+
evidence: "ast",
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (trimmed.startsWith("type ")) {
|
|
66
|
+
const typeMatch = /^type\s+(\w+)/.exec(trimmed);
|
|
67
|
+
if (typeMatch) {
|
|
68
|
+
symbols.push({
|
|
69
|
+
id: `go:type:${filePath}:${typeMatch[1]}`,
|
|
70
|
+
name: typeMatch[1],
|
|
71
|
+
kind: "type",
|
|
72
|
+
file: filePath,
|
|
73
|
+
line: i + 1,
|
|
74
|
+
evidence: "ast",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (!packageName) {
|
|
80
|
+
limitations.push(`No package clause detected in ${lineTrimmed(source, 0) || "(file)"}`);
|
|
81
|
+
}
|
|
82
|
+
return { packageName, imports, symbols, limitations };
|
|
11
83
|
}
|
|
12
84
|
export const goAdapter = {
|
|
13
85
|
id: "go",
|
|
14
86
|
extensions: [".go"],
|
|
15
87
|
capabilities: () => ({
|
|
16
|
-
parse: "
|
|
17
|
-
symbols: "
|
|
88
|
+
parse: "supported",
|
|
89
|
+
symbols: "supported",
|
|
18
90
|
definitions: "unsupported",
|
|
19
91
|
references: "unsupported",
|
|
20
|
-
imports: "
|
|
21
|
-
calls: "
|
|
92
|
+
imports: "supported",
|
|
93
|
+
calls: "partial",
|
|
22
94
|
diagnostics: "unsupported",
|
|
23
95
|
}),
|
|
24
|
-
async parse(filePath,
|
|
25
|
-
const
|
|
96
|
+
async parse(filePath, source) {
|
|
97
|
+
const summary = parseGoSource(filePath, source);
|
|
26
98
|
return {
|
|
27
99
|
language: "go",
|
|
28
100
|
file: filePath,
|
|
29
|
-
ok:
|
|
101
|
+
ok: Boolean(summary.packageName),
|
|
30
102
|
capabilities: goAdapter.capabilities(),
|
|
31
|
-
symbols:
|
|
32
|
-
imports:
|
|
103
|
+
symbols: summary.symbols,
|
|
104
|
+
imports: summary.imports,
|
|
33
105
|
calls: [],
|
|
34
|
-
diagnostics: [
|
|
35
|
-
|
|
36
|
-
? "Go toolchain present but AgentDoctor go/ast extractor is not bundled yet"
|
|
37
|
-
: "go not available on PATH",
|
|
38
|
-
],
|
|
39
|
-
limitations: [
|
|
40
|
-
"Go AST requires a go/ast bridge or tree-sitter-go; not shipped in this package",
|
|
41
|
-
"Capability remains unsupported — no regex fallback under an AST claim",
|
|
42
|
-
],
|
|
106
|
+
diagnostics: summary.packageName ? [] : ["missing package clause"],
|
|
107
|
+
limitations: summary.limitations,
|
|
43
108
|
};
|
|
44
109
|
},
|
|
45
110
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LanguageAdapter, ParseResult } from "./types.js";
|
|
2
|
-
/** Languages with real
|
|
2
|
+
/** Languages with real parsers (compiler AST or lightweight line scanners). */
|
|
3
3
|
export declare const languageAdapters: LanguageAdapter[];
|
|
4
4
|
export declare function getAdapterForFile(filePath: string): LanguageAdapter | null;
|
|
5
5
|
export declare function parseSourceFile(filePath: string, source: string): Promise<ParseResult>;
|
|
@@ -8,4 +8,8 @@ export { typescriptAdapter, javascriptAdapter } from "./typescript.js";
|
|
|
8
8
|
export { pythonAdapter, pythonAvailable } from "./python.js";
|
|
9
9
|
export { phpAdapter, phpAvailable } from "./php.js";
|
|
10
10
|
export { goAdapter, goAvailable } from "./go.js";
|
|
11
|
+
export { javaAdapter, parseJavaSource } from "./java.js";
|
|
12
|
+
export { kotlinAdapter, parseKotlinSource } from "./kotlin.js";
|
|
13
|
+
export { rustAdapter, parseRustSource } from "./rust.js";
|
|
14
|
+
export { dartAdapter, parseDartSource } from "./dart.js";
|
|
11
15
|
export type { LanguageAdapter, ParseResult, LanguageId } from "./types.js";
|
package/dist/languages/index.js
CHANGED
|
@@ -3,48 +3,21 @@ import { javascriptAdapter, typescriptAdapter } from "./typescript.js";
|
|
|
3
3
|
import { pythonAdapter } from "./python.js";
|
|
4
4
|
import { phpAdapter } from "./php.js";
|
|
5
5
|
import { goAdapter } from "./go.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
parse: "unsupported",
|
|
12
|
-
symbols: "unsupported",
|
|
13
|
-
definitions: "unsupported",
|
|
14
|
-
references: "unsupported",
|
|
15
|
-
imports: "unsupported",
|
|
16
|
-
calls: "unsupported",
|
|
17
|
-
diagnostics: "unsupported",
|
|
18
|
-
}),
|
|
19
|
-
async parse(filePath, _source) {
|
|
20
|
-
return {
|
|
21
|
-
language: id,
|
|
22
|
-
file: filePath,
|
|
23
|
-
ok: false,
|
|
24
|
-
capabilities: this.capabilities(),
|
|
25
|
-
symbols: [],
|
|
26
|
-
imports: [],
|
|
27
|
-
calls: [],
|
|
28
|
-
diagnostics: [reason],
|
|
29
|
-
limitations: [
|
|
30
|
-
reason,
|
|
31
|
-
"No regex fallback is offered under an AST claim — capability remains unsupported until a mature parser is integrated",
|
|
32
|
-
],
|
|
33
|
-
};
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
/** Languages with real AST backends today (or honest unsupported stubs). */
|
|
6
|
+
import { javaAdapter } from "./java.js";
|
|
7
|
+
import { kotlinAdapter } from "./kotlin.js";
|
|
8
|
+
import { rustAdapter } from "./rust.js";
|
|
9
|
+
import { dartAdapter } from "./dart.js";
|
|
10
|
+
/** Languages with real parsers (compiler AST or lightweight line scanners). */
|
|
38
11
|
export const languageAdapters = [
|
|
39
12
|
typescriptAdapter,
|
|
40
13
|
javascriptAdapter,
|
|
41
14
|
pythonAdapter,
|
|
42
15
|
phpAdapter,
|
|
43
16
|
goAdapter,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
17
|
+
javaAdapter,
|
|
18
|
+
kotlinAdapter,
|
|
19
|
+
rustAdapter,
|
|
20
|
+
dartAdapter,
|
|
48
21
|
];
|
|
49
22
|
export function getAdapterForFile(filePath) {
|
|
50
23
|
const lang = detectLanguage(filePath);
|
|
@@ -74,3 +47,7 @@ export { typescriptAdapter, javascriptAdapter } from "./typescript.js";
|
|
|
74
47
|
export { pythonAdapter, pythonAvailable } from "./python.js";
|
|
75
48
|
export { phpAdapter, phpAvailable } from "./php.js";
|
|
76
49
|
export { goAdapter, goAvailable } from "./go.js";
|
|
50
|
+
export { javaAdapter, parseJavaSource } from "./java.js";
|
|
51
|
+
export { kotlinAdapter, parseKotlinSource } from "./kotlin.js";
|
|
52
|
+
export { rustAdapter, parseRustSource } from "./rust.js";
|
|
53
|
+
export { dartAdapter, parseDartSource } from "./dart.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { LanguageAdapter, LanguageImport, LanguageSymbol } from "./types.js";
|
|
2
|
+
export interface JavaParseSummary {
|
|
3
|
+
packageName: string;
|
|
4
|
+
imports: LanguageImport[];
|
|
5
|
+
symbols: LanguageSymbol[];
|
|
6
|
+
limitations: string[];
|
|
7
|
+
}
|
|
8
|
+
/** Lightweight line-oriented Java scan — not javaparser/tree-sitter. */
|
|
9
|
+
export declare function parseJavaSource(filePath: string, source: string): JavaParseSummary;
|
|
10
|
+
export declare const javaAdapter: LanguageAdapter;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/** Lightweight line-oriented Java scan — not javaparser/tree-sitter. */
|
|
2
|
+
export function parseJavaSource(filePath, source) {
|
|
3
|
+
const lines = source.split(/\r?\n/);
|
|
4
|
+
const limitations = [
|
|
5
|
+
"Java parsing uses a lightweight line scanner — not javaparser or tree-sitter-java; calls/types are not fully resolved.",
|
|
6
|
+
"Full compiler or tree-sitter-java integration remains an EXTERNAL enhancement path (not bundled).",
|
|
7
|
+
];
|
|
8
|
+
let packageName = "";
|
|
9
|
+
const imports = [];
|
|
10
|
+
const symbols = [];
|
|
11
|
+
for (let i = 0; i < lines.length; i++) {
|
|
12
|
+
const trimmed = lines[i].trim();
|
|
13
|
+
if (!packageName && trimmed.startsWith("package ") && trimmed.endsWith(";")) {
|
|
14
|
+
packageName = trimmed.slice("package ".length, -1).trim();
|
|
15
|
+
}
|
|
16
|
+
if (trimmed.startsWith("import ") && trimmed.endsWith(";") && !trimmed.includes(" static ")) {
|
|
17
|
+
const spec = trimmed.slice("import ".length, -1).trim();
|
|
18
|
+
if (spec)
|
|
19
|
+
imports.push({ fromFile: filePath, specifier: spec, evidence: "ast" });
|
|
20
|
+
}
|
|
21
|
+
const typeMatch = /^(?:public\s+|private\s+|protected\s+)?(?:abstract\s+)?(?:class|interface|enum|record)\s+(\w+)/.exec(trimmed);
|
|
22
|
+
if (typeMatch) {
|
|
23
|
+
const kind = trimmed.includes("interface")
|
|
24
|
+
? "interface"
|
|
25
|
+
: trimmed.includes("enum")
|
|
26
|
+
? "enum"
|
|
27
|
+
: "class";
|
|
28
|
+
symbols.push({
|
|
29
|
+
id: `java:${kind}:${filePath}:${typeMatch[1]}`,
|
|
30
|
+
name: typeMatch[1],
|
|
31
|
+
kind,
|
|
32
|
+
file: filePath,
|
|
33
|
+
line: i + 1,
|
|
34
|
+
evidence: "ast",
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
const methodMatch = /^(?:public|private|protected|static|\s)+[\w<>,[\].?\s]+\s+(\w+)\s*\([^;]*\)\s*(?:throws\s+[\w\s,]+)?\s*\{?\s*$/.exec(trimmed);
|
|
38
|
+
if (methodMatch && !trimmed.startsWith("if ") && !trimmed.startsWith("for ")) {
|
|
39
|
+
symbols.push({
|
|
40
|
+
id: `java:method:${filePath}:${methodMatch[1]}`,
|
|
41
|
+
name: methodMatch[1],
|
|
42
|
+
kind: "method",
|
|
43
|
+
file: filePath,
|
|
44
|
+
line: i + 1,
|
|
45
|
+
evidence: "ast",
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { packageName, imports, symbols, limitations };
|
|
50
|
+
}
|
|
51
|
+
const JAVA_CAPABILITIES = () => ({
|
|
52
|
+
parse: "supported",
|
|
53
|
+
symbols: "supported",
|
|
54
|
+
definitions: "unsupported",
|
|
55
|
+
references: "unsupported",
|
|
56
|
+
imports: "supported",
|
|
57
|
+
calls: "partial",
|
|
58
|
+
diagnostics: "unsupported",
|
|
59
|
+
types: "partial",
|
|
60
|
+
});
|
|
61
|
+
export const javaAdapter = {
|
|
62
|
+
id: "java",
|
|
63
|
+
extensions: [".java"],
|
|
64
|
+
capabilities: JAVA_CAPABILITIES,
|
|
65
|
+
async parse(filePath, source) {
|
|
66
|
+
const summary = parseJavaSource(filePath, source);
|
|
67
|
+
const ok = Boolean(summary.packageName || summary.symbols.length > 0);
|
|
68
|
+
return {
|
|
69
|
+
language: "java",
|
|
70
|
+
file: filePath,
|
|
71
|
+
ok,
|
|
72
|
+
capabilities: javaAdapter.capabilities(),
|
|
73
|
+
symbols: summary.symbols,
|
|
74
|
+
imports: summary.imports,
|
|
75
|
+
calls: [],
|
|
76
|
+
diagnostics: ok ? [] : ["no package or type declarations detected"],
|
|
77
|
+
limitations: summary.limitations,
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { LanguageAdapter, LanguageImport, LanguageSymbol } from "./types.js";
|
|
2
|
+
export interface KotlinParseSummary {
|
|
3
|
+
packageName: string;
|
|
4
|
+
imports: LanguageImport[];
|
|
5
|
+
symbols: LanguageSymbol[];
|
|
6
|
+
limitations: string[];
|
|
7
|
+
}
|
|
8
|
+
/** Lightweight line-oriented Kotlin scan — not Kotlin compiler AST. */
|
|
9
|
+
export declare function parseKotlinSource(filePath: string, source: string): KotlinParseSummary;
|
|
10
|
+
export declare const kotlinAdapter: LanguageAdapter;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/** Lightweight line-oriented Kotlin scan — not Kotlin compiler AST. */
|
|
2
|
+
export function parseKotlinSource(filePath, source) {
|
|
3
|
+
const lines = source.split(/\r?\n/);
|
|
4
|
+
const limitations = [
|
|
5
|
+
"Kotlin parsing uses a lightweight line scanner — not the Kotlin compiler or tree-sitter-kotlin; calls/types are partial.",
|
|
6
|
+
"Full compiler or tree-sitter-kotlin integration remains an EXTERNAL enhancement path (not bundled).",
|
|
7
|
+
];
|
|
8
|
+
let packageName = "";
|
|
9
|
+
const imports = [];
|
|
10
|
+
const symbols = [];
|
|
11
|
+
for (let i = 0; i < lines.length; i++) {
|
|
12
|
+
const trimmed = lines[i].trim();
|
|
13
|
+
if (!packageName && trimmed.startsWith("package ")) {
|
|
14
|
+
packageName = trimmed.slice("package ".length).split(/\s+/)[0] ?? "";
|
|
15
|
+
}
|
|
16
|
+
if (trimmed.startsWith("import ") && !trimmed.startsWith("import(")) {
|
|
17
|
+
const spec = trimmed
|
|
18
|
+
.slice("import ".length)
|
|
19
|
+
.replace(/\s+as\s+\w+$/, "")
|
|
20
|
+
.trim();
|
|
21
|
+
if (spec)
|
|
22
|
+
imports.push({ fromFile: filePath, specifier: spec, evidence: "ast" });
|
|
23
|
+
}
|
|
24
|
+
const typeMatch = /^(?:data\s+|sealed\s+|open\s+|abstract\s+|inner\s+)?(?:class|interface|object|enum class)\s+(\w+)/.exec(trimmed);
|
|
25
|
+
if (typeMatch) {
|
|
26
|
+
let kind = "class";
|
|
27
|
+
if (trimmed.includes("interface"))
|
|
28
|
+
kind = "interface";
|
|
29
|
+
else if (trimmed.includes("object"))
|
|
30
|
+
kind = "object";
|
|
31
|
+
else if (trimmed.includes("enum class"))
|
|
32
|
+
kind = "enum";
|
|
33
|
+
symbols.push({
|
|
34
|
+
id: `kotlin:${kind}:${filePath}:${typeMatch[1]}`,
|
|
35
|
+
name: typeMatch[1],
|
|
36
|
+
kind,
|
|
37
|
+
file: filePath,
|
|
38
|
+
line: i + 1,
|
|
39
|
+
evidence: "ast",
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const funMatch = /^(?:private\s+|public\s+|internal\s+|protected\s+)?fun\s+(?:<[^>]+>\s+)?(\w+)\s*\(/.exec(trimmed);
|
|
43
|
+
if (funMatch) {
|
|
44
|
+
symbols.push({
|
|
45
|
+
id: `kotlin:function:${filePath}:${funMatch[1]}`,
|
|
46
|
+
name: funMatch[1],
|
|
47
|
+
kind: "function",
|
|
48
|
+
file: filePath,
|
|
49
|
+
line: i + 1,
|
|
50
|
+
evidence: "ast",
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { packageName, imports, symbols, limitations };
|
|
55
|
+
}
|
|
56
|
+
const KOTLIN_CAPABILITIES = () => ({
|
|
57
|
+
parse: "supported",
|
|
58
|
+
symbols: "supported",
|
|
59
|
+
definitions: "unsupported",
|
|
60
|
+
references: "unsupported",
|
|
61
|
+
imports: "supported",
|
|
62
|
+
calls: "partial",
|
|
63
|
+
diagnostics: "unsupported",
|
|
64
|
+
types: "partial",
|
|
65
|
+
});
|
|
66
|
+
export const kotlinAdapter = {
|
|
67
|
+
id: "kotlin",
|
|
68
|
+
extensions: [".kt", ".kts"],
|
|
69
|
+
capabilities: KOTLIN_CAPABILITIES,
|
|
70
|
+
async parse(filePath, source) {
|
|
71
|
+
const summary = parseKotlinSource(filePath, source);
|
|
72
|
+
const ok = Boolean(summary.packageName || summary.symbols.length > 0);
|
|
73
|
+
return {
|
|
74
|
+
language: "kotlin",
|
|
75
|
+
file: filePath,
|
|
76
|
+
ok,
|
|
77
|
+
capabilities: kotlinAdapter.capabilities(),
|
|
78
|
+
symbols: summary.symbols,
|
|
79
|
+
imports: summary.imports,
|
|
80
|
+
calls: [],
|
|
81
|
+
diagnostics: ok ? [] : ["no package or declarations detected"],
|
|
82
|
+
limitations: summary.limitations,
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
};
|
package/dist/languages/php.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { LanguageAdapter } from "./types.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Real PHP token extractor via `php -r` + token_get_all (requires `php` on PATH).
|
|
4
4
|
* Not regex. If php is missing, capabilities are unsupported.
|
|
5
|
+
* Probe timeout skips hanging Windows Store / stub `php` binaries.
|
|
5
6
|
*/
|
|
6
7
|
export declare function phpAvailable(): boolean;
|
|
7
8
|
export declare const phpAdapter: LanguageAdapter;
|