@praneeth_54/agentdoctor 2.1.0 → 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.
Files changed (129) hide show
  1. package/CHANGELOG.md +57 -3
  2. package/README.md +489 -290
  3. package/dist/agent/chat/deterministic.d.ts +6 -0
  4. package/dist/agent/chat/deterministic.js +180 -0
  5. package/dist/agent/chat/service.js +8 -14
  6. package/dist/agent/index.d.ts +2 -0
  7. package/dist/agent/index.js +1 -0
  8. package/dist/agent/loop.d.ts +2 -0
  9. package/dist/agent/loop.js +31 -0
  10. package/dist/agent/roles.d.ts +12 -0
  11. package/dist/agent/roles.js +138 -0
  12. package/dist/agent/runtime.d.ts +21 -5
  13. package/dist/agent/runtime.js +141 -28
  14. package/dist/agent/tools/execute.d.ts +2 -0
  15. package/dist/agent/tools/execute.js +10 -0
  16. package/dist/ai/config.js +1 -0
  17. package/dist/ai/redact.d.ts +1 -0
  18. package/dist/ai/redact.js +47 -7
  19. package/dist/ai/types.d.ts +1 -1
  20. package/dist/cli/commands/agent.d.ts +2 -0
  21. package/dist/cli/commands/agent.js +19 -8
  22. package/dist/cli/commands/chat.js +2 -4
  23. package/dist/cli/commands/product.d.ts +19 -0
  24. package/dist/cli/commands/product.js +147 -0
  25. package/dist/cli/commands/start.d.ts +15 -0
  26. package/dist/cli/commands/start.js +80 -0
  27. package/dist/cli/program.js +141 -0
  28. package/dist/constants.d.ts +1 -1
  29. package/dist/constants.js +1 -1
  30. package/dist/dashboard/server.js +255 -53
  31. package/dist/index.d.ts +4 -0
  32. package/dist/index.js +2 -0
  33. package/dist/intelligence/graph/build.js +36 -8
  34. package/dist/intelligence/resolve/imports.js +1 -1
  35. package/dist/languages/dart.d.ts +10 -0
  36. package/dist/languages/dart.js +99 -0
  37. package/dist/languages/go.d.ts +13 -7
  38. package/dist/languages/go.js +84 -24
  39. package/dist/languages/index.d.ts +5 -1
  40. package/dist/languages/index.js +13 -36
  41. package/dist/languages/java.d.ts +10 -0
  42. package/dist/languages/java.js +80 -0
  43. package/dist/languages/kotlin.d.ts +10 -0
  44. package/dist/languages/kotlin.js +85 -0
  45. package/dist/languages/rust.d.ts +10 -0
  46. package/dist/languages/rust.js +93 -0
  47. package/dist/languages/types.d.ts +4 -3
  48. package/dist/mcp/agent/registry.d.ts +1 -1
  49. package/dist/mcp/agent/registry.js +109 -23
  50. package/dist/mcp/intelligence/handlers.d.ts +3 -0
  51. package/dist/mcp/intelligence/handlers.js +28 -0
  52. package/dist/mcp/intelligence/registry.d.ts +1 -1
  53. package/dist/mcp/intelligence/registry.js +30 -1
  54. package/dist/product/api/doctor.d.ts +14 -0
  55. package/dist/product/api/doctor.js +185 -0
  56. package/dist/product/api/openapi.d.ts +7 -0
  57. package/dist/product/api/openapi.js +122 -0
  58. package/dist/product/approval/model.d.ts +30 -0
  59. package/dist/product/approval/model.js +64 -0
  60. package/dist/product/approval/session.d.ts +49 -0
  61. package/dist/product/approval/session.js +134 -0
  62. package/dist/product/database/doctor.d.ts +30 -0
  63. package/dist/product/database/doctor.js +184 -0
  64. package/dist/product/decisions/ledger.d.ts +24 -0
  65. package/dist/product/decisions/ledger.js +110 -0
  66. package/dist/product/deps/analyze.d.ts +46 -0
  67. package/dist/product/deps/analyze.js +137 -0
  68. package/dist/product/deps/lockfiles.d.ts +25 -0
  69. package/dist/product/deps/lockfiles.js +200 -0
  70. package/dist/product/discovery/roots.d.ts +42 -0
  71. package/dist/product/discovery/roots.js +215 -0
  72. package/dist/product/dna/build.d.ts +50 -0
  73. package/dist/product/dna/build.js +255 -0
  74. package/dist/product/eval/lab.d.ts +17 -0
  75. package/dist/product/eval/lab.js +218 -0
  76. package/dist/product/events/doctor.d.ts +21 -0
  77. package/dist/product/events/doctor.js +147 -0
  78. package/dist/product/evidence-scan.d.ts +12 -0
  79. package/dist/product/evidence-scan.js +46 -0
  80. package/dist/product/evolution/timeline.d.ts +29 -0
  81. package/dist/product/evolution/timeline.js +123 -0
  82. package/dist/product/features/intelligence.d.ts +23 -0
  83. package/dist/product/features/intelligence.js +158 -0
  84. package/dist/product/forensic/mode.d.ts +25 -0
  85. package/dist/product/forensic/mode.js +70 -0
  86. package/dist/product/graph/enrich-languages.d.ts +20 -0
  87. package/dist/product/graph/enrich-languages.js +193 -0
  88. package/dist/product/health/code-health.d.ts +20 -0
  89. package/dist/product/health/code-health.js +149 -0
  90. package/dist/product/index.d.ts +69 -0
  91. package/dist/product/index.js +35 -0
  92. package/dist/product/ledger/change-ledger.d.ts +23 -0
  93. package/dist/product/ledger/change-ledger.js +64 -0
  94. package/dist/product/map/software-map.d.ts +17 -0
  95. package/dist/product/map/software-map.js +95 -0
  96. package/dist/product/memory/institutional.d.ts +16 -0
  97. package/dist/product/memory/institutional.js +87 -0
  98. package/dist/product/ops/incident.d.ts +20 -0
  99. package/dist/product/ops/incident.js +61 -0
  100. package/dist/product/ops/infra.d.ts +15 -0
  101. package/dist/product/ops/infra.js +112 -0
  102. package/dist/product/org/model.d.ts +34 -0
  103. package/dist/product/org/model.js +195 -0
  104. package/dist/product/privacy/doctor.d.ts +13 -0
  105. package/dist/product/privacy/doctor.js +90 -0
  106. package/dist/product/requirements/trace.d.ts +21 -0
  107. package/dist/product/requirements/trace.js +166 -0
  108. package/dist/product/search/index.d.ts +29 -0
  109. package/dist/product/search/index.js +116 -0
  110. package/dist/product/search/software-search.d.ts +19 -0
  111. package/dist/product/search/software-search.js +100 -0
  112. package/dist/product/security/doctor.d.ts +23 -0
  113. package/dist/product/security/doctor.js +124 -0
  114. package/dist/product/self/diagnose.d.ts +15 -0
  115. package/dist/product/self/diagnose.js +82 -0
  116. package/dist/product/techdebt/roadmap.d.ts +20 -0
  117. package/dist/product/techdebt/roadmap.js +118 -0
  118. package/dist/product/testbrain/analyze.d.ts +29 -0
  119. package/dist/product/testbrain/analyze.js +129 -0
  120. package/dist/product/truth.d.ts +12 -0
  121. package/dist/product/truth.js +30 -0
  122. package/dist/product/twin/digital-twin.d.ts +23 -0
  123. package/dist/product/twin/digital-twin.js +52 -0
  124. package/dist/product/twin/store.d.ts +21 -0
  125. package/dist/product/twin/store.js +70 -0
  126. package/dist/product/whatif/engine.d.ts +28 -0
  127. package/dist/product/whatif/engine.js +70 -0
  128. package/dist/utils/fs.js +10 -2
  129. 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
- "Non-TypeScript languages fall back to regex graph when requested via auto+empty TS set",
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.replace("*", star) : 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
+ };
@@ -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;
@@ -1,11 +1,5 @@
1
1
  import { spawnSync } from "node:child_process";
2
2
  const GO_PROBE_TIMEOUT_MS = 5_000;
3
- /**
4
- * Go toolchain bridge placeholder.
5
- * Prefer real `go/ast` via `go run` when the Go toolchain is present; until an
6
- * extractor is bundled, capability remains unsupported even if `go` exists.
7
- * Today: always unsupported (no bundled extractor; avoids fake AST claims).
8
- */
9
3
  export function goAvailable() {
10
4
  const r = spawnSync("go", ["version"], {
11
5
  encoding: "utf8",
@@ -14,37 +8,103 @@ export function goAvailable() {
14
8
  });
15
9
  return r.status === 0 && !r.error;
16
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 };
83
+ }
17
84
  export const goAdapter = {
18
85
  id: "go",
19
86
  extensions: [".go"],
20
87
  capabilities: () => ({
21
- parse: "unsupported",
22
- symbols: "unsupported",
88
+ parse: "supported",
89
+ symbols: "supported",
23
90
  definitions: "unsupported",
24
91
  references: "unsupported",
25
- imports: "unsupported",
26
- calls: "unsupported",
92
+ imports: "supported",
93
+ calls: "partial",
27
94
  diagnostics: "unsupported",
28
95
  }),
29
- async parse(filePath, _source) {
30
- const hasGo = goAvailable();
96
+ async parse(filePath, source) {
97
+ const summary = parseGoSource(filePath, source);
31
98
  return {
32
99
  language: "go",
33
100
  file: filePath,
34
- ok: false,
101
+ ok: Boolean(summary.packageName),
35
102
  capabilities: goAdapter.capabilities(),
36
- symbols: [],
37
- imports: [],
103
+ symbols: summary.symbols,
104
+ imports: summary.imports,
38
105
  calls: [],
39
- diagnostics: [
40
- hasGo
41
- ? "Go toolchain present but AgentDoctor go/ast extractor is not bundled yet"
42
- : "go not available on PATH",
43
- ],
44
- limitations: [
45
- "Go AST requires a go/ast bridge or tree-sitter-go; not shipped in this package",
46
- "Capability remains unsupported — no regex fallback under an AST claim",
47
- ],
106
+ diagnostics: summary.packageName ? [] : ["missing package clause"],
107
+ limitations: summary.limitations,
48
108
  };
49
109
  },
50
110
  };
@@ -1,5 +1,5 @@
1
1
  import type { LanguageAdapter, ParseResult } from "./types.js";
2
- /** Languages with real AST backends today (or honest unsupported stubs). */
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";
@@ -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
- function unsupportedAdapter(id, extensions, reason) {
7
- return {
8
- id,
9
- extensions,
10
- capabilities: () => ({
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
- unsupportedAdapter("java", [".java"], "Java AST requires an external parser (e.g. tree-sitter-java or javaparser); not bundled"),
45
- unsupportedAdapter("kotlin", [".kt", ".kts"], "Kotlin AST requires an external parser; not bundled"),
46
- unsupportedAdapter("rust", [".rs"], "Rust AST requires syn/rustc or tree-sitter-rust; not bundled"),
47
- unsupportedAdapter("dart", [".dart"], "Dart AST requires Dart analyzer APIs; not bundled"),
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
+ };
@@ -0,0 +1,10 @@
1
+ import type { LanguageAdapter, LanguageImport, LanguageSymbol } from "./types.js";
2
+ export interface RustParseSummary {
3
+ moduleName: string;
4
+ imports: LanguageImport[];
5
+ symbols: LanguageSymbol[];
6
+ limitations: string[];
7
+ }
8
+ /** Lightweight line-oriented Rust scan — not syn/rustc AST. */
9
+ export declare function parseRustSource(filePath: string, source: string): RustParseSummary;
10
+ export declare const rustAdapter: LanguageAdapter;