@thoughtflow/codebase 0.2.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 (278) hide show
  1. package/dist/contexts/context-decomposer.d.ts +13 -0
  2. package/dist/contexts/context-decomposer.d.ts.map +1 -0
  3. package/dist/contexts/context-decomposer.js +97 -0
  4. package/dist/contexts/context-decomposer.js.map +1 -0
  5. package/dist/contexts/context-document-manager.d.ts +21 -0
  6. package/dist/contexts/context-document-manager.d.ts.map +1 -0
  7. package/dist/contexts/context-document-manager.js +69 -0
  8. package/dist/contexts/context-document-manager.js.map +1 -0
  9. package/dist/contexts/context-router.d.ts +13 -0
  10. package/dist/contexts/context-router.d.ts.map +1 -0
  11. package/dist/contexts/context-router.js +94 -0
  12. package/dist/contexts/context-router.js.map +1 -0
  13. package/dist/index.d.ts +53 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +76 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/libs/codebase/deep-analyzer.d.ts +58 -0
  18. package/dist/libs/codebase/deep-analyzer.d.ts.map +1 -0
  19. package/dist/libs/codebase/deep-analyzer.js +239 -0
  20. package/dist/libs/codebase/deep-analyzer.js.map +1 -0
  21. package/dist/libs/codebase/graph/dependency-extractor.d.ts +20 -0
  22. package/dist/libs/codebase/graph/dependency-extractor.d.ts.map +1 -0
  23. package/dist/libs/codebase/graph/dependency-extractor.js +174 -0
  24. package/dist/libs/codebase/graph/dependency-extractor.js.map +1 -0
  25. package/dist/libs/codebase/graph/graph-analysis.d.ts +42 -0
  26. package/dist/libs/codebase/graph/graph-analysis.d.ts.map +1 -0
  27. package/dist/libs/codebase/graph/graph-analysis.js +222 -0
  28. package/dist/libs/codebase/graph/graph-analysis.js.map +1 -0
  29. package/dist/libs/codebase/graph/graph-visualizer.d.ts +12 -0
  30. package/dist/libs/codebase/graph/graph-visualizer.d.ts.map +1 -0
  31. package/dist/libs/codebase/graph/graph-visualizer.js +99 -0
  32. package/dist/libs/codebase/graph/graph-visualizer.js.map +1 -0
  33. package/dist/libs/codebase/indexer/batch-processor.d.ts +18 -0
  34. package/dist/libs/codebase/indexer/batch-processor.d.ts.map +1 -0
  35. package/dist/libs/codebase/indexer/batch-processor.js +39 -0
  36. package/dist/libs/codebase/indexer/batch-processor.js.map +1 -0
  37. package/dist/libs/codebase/indexer/chunker-markdown.d.ts +19 -0
  38. package/dist/libs/codebase/indexer/chunker-markdown.d.ts.map +1 -0
  39. package/dist/libs/codebase/indexer/chunker-markdown.js +138 -0
  40. package/dist/libs/codebase/indexer/chunker-markdown.js.map +1 -0
  41. package/dist/libs/codebase/indexer/chunker.d.ts +21 -0
  42. package/dist/libs/codebase/indexer/chunker.d.ts.map +1 -0
  43. package/dist/libs/codebase/indexer/chunker.js +133 -0
  44. package/dist/libs/codebase/indexer/chunker.js.map +1 -0
  45. package/dist/libs/codebase/indexer/explorer.d.ts +29 -0
  46. package/dist/libs/codebase/indexer/explorer.d.ts.map +1 -0
  47. package/dist/libs/codebase/indexer/explorer.js +278 -0
  48. package/dist/libs/codebase/indexer/explorer.js.map +1 -0
  49. package/dist/libs/codebase/indexer/indexer.d.ts +35 -0
  50. package/dist/libs/codebase/indexer/indexer.d.ts.map +1 -0
  51. package/dist/libs/codebase/indexer/indexer.js +172 -0
  52. package/dist/libs/codebase/indexer/indexer.js.map +1 -0
  53. package/dist/libs/codebase/knowledge/cross-referencer.d.ts +32 -0
  54. package/dist/libs/codebase/knowledge/cross-referencer.d.ts.map +1 -0
  55. package/dist/libs/codebase/knowledge/cross-referencer.js +132 -0
  56. package/dist/libs/codebase/knowledge/cross-referencer.js.map +1 -0
  57. package/dist/libs/codebase/knowledge/markdown-extractor.d.ts +34 -0
  58. package/dist/libs/codebase/knowledge/markdown-extractor.d.ts.map +1 -0
  59. package/dist/libs/codebase/knowledge/markdown-extractor.js +273 -0
  60. package/dist/libs/codebase/knowledge/markdown-extractor.js.map +1 -0
  61. package/dist/libs/codebase/knowledge/summarizer.d.ts +25 -0
  62. package/dist/libs/codebase/knowledge/summarizer.d.ts.map +1 -0
  63. package/dist/libs/codebase/knowledge/summarizer.js +61 -0
  64. package/dist/libs/codebase/knowledge/summarizer.js.map +1 -0
  65. package/dist/libs/codebase/search/bm25.d.ts +23 -0
  66. package/dist/libs/codebase/search/bm25.d.ts.map +1 -0
  67. package/dist/libs/codebase/search/bm25.js +93 -0
  68. package/dist/libs/codebase/search/bm25.js.map +1 -0
  69. package/dist/libs/codebase/search/hybrid-search.d.ts +22 -0
  70. package/dist/libs/codebase/search/hybrid-search.d.ts.map +1 -0
  71. package/dist/libs/codebase/search/hybrid-search.js +80 -0
  72. package/dist/libs/codebase/search/hybrid-search.js.map +1 -0
  73. package/dist/libs/codebase-index.class.d.ts +66 -0
  74. package/dist/libs/codebase-index.class.d.ts.map +1 -0
  75. package/dist/libs/codebase-index.class.js +595 -0
  76. package/dist/libs/codebase-index.class.js.map +1 -0
  77. package/dist/tools/codebase/codebase-analyze.tool.d.ts +8 -0
  78. package/dist/tools/codebase/codebase-analyze.tool.d.ts.map +1 -0
  79. package/dist/tools/codebase/codebase-analyze.tool.js +20 -0
  80. package/dist/tools/codebase/codebase-analyze.tool.js.map +1 -0
  81. package/dist/tools/codebase/codebase-crossref.tool.d.ts +8 -0
  82. package/dist/tools/codebase/codebase-crossref.tool.d.ts.map +1 -0
  83. package/dist/tools/codebase/codebase-crossref.tool.js +20 -0
  84. package/dist/tools/codebase/codebase-crossref.tool.js.map +1 -0
  85. package/dist/tools/codebase/codebase-flow.tool.d.ts +8 -0
  86. package/dist/tools/codebase/codebase-flow.tool.d.ts.map +1 -0
  87. package/dist/tools/codebase/codebase-flow.tool.js +20 -0
  88. package/dist/tools/codebase/codebase-flow.tool.js.map +1 -0
  89. package/dist/tools/codebase/codebase-graph-circular.tool.d.ts +8 -0
  90. package/dist/tools/codebase/codebase-graph-circular.tool.d.ts.map +1 -0
  91. package/dist/tools/codebase/codebase-graph-circular.tool.js +17 -0
  92. package/dist/tools/codebase/codebase-graph-circular.tool.js.map +1 -0
  93. package/dist/tools/codebase/codebase-graph-query.tool.d.ts +8 -0
  94. package/dist/tools/codebase/codebase-graph-query.tool.d.ts.map +1 -0
  95. package/dist/tools/codebase/codebase-graph-query.tool.js +21 -0
  96. package/dist/tools/codebase/codebase-graph-query.tool.js.map +1 -0
  97. package/dist/tools/codebase/codebase-graph-stats.tool.d.ts +8 -0
  98. package/dist/tools/codebase/codebase-graph-stats.tool.d.ts.map +1 -0
  99. package/dist/tools/codebase/codebase-graph-stats.tool.js +17 -0
  100. package/dist/tools/codebase/codebase-graph-stats.tool.js.map +1 -0
  101. package/dist/tools/codebase/codebase-graph-visualize.tool.d.ts +8 -0
  102. package/dist/tools/codebase/codebase-graph-visualize.tool.d.ts.map +1 -0
  103. package/dist/tools/codebase/codebase-graph-visualize.tool.js +21 -0
  104. package/dist/tools/codebase/codebase-graph-visualize.tool.js.map +1 -0
  105. package/dist/tools/codebase/codebase-impact.tool.d.ts +8 -0
  106. package/dist/tools/codebase/codebase-impact.tool.d.ts.map +1 -0
  107. package/dist/tools/codebase/codebase-impact.tool.js +21 -0
  108. package/dist/tools/codebase/codebase-impact.tool.js.map +1 -0
  109. package/dist/tools/codebase/codebase-index.tool.d.ts +8 -0
  110. package/dist/tools/codebase/codebase-index.tool.d.ts.map +1 -0
  111. package/dist/tools/codebase/codebase-index.tool.js +21 -0
  112. package/dist/tools/codebase/codebase-index.tool.js.map +1 -0
  113. package/dist/tools/codebase/codebase-knowledge.tool.d.ts +8 -0
  114. package/dist/tools/codebase/codebase-knowledge.tool.d.ts.map +1 -0
  115. package/dist/tools/codebase/codebase-knowledge.tool.js +22 -0
  116. package/dist/tools/codebase/codebase-knowledge.tool.js.map +1 -0
  117. package/dist/tools/codebase/codebase-search.tool.d.ts +8 -0
  118. package/dist/tools/codebase/codebase-search.tool.d.ts.map +1 -0
  119. package/dist/tools/codebase/codebase-search.tool.js +24 -0
  120. package/dist/tools/codebase/codebase-search.tool.js.map +1 -0
  121. package/dist/tools/codebase/codebase-status.tool.d.ts +8 -0
  122. package/dist/tools/codebase/codebase-status.tool.d.ts.map +1 -0
  123. package/dist/tools/codebase/codebase-status.tool.js +19 -0
  124. package/dist/tools/codebase/codebase-status.tool.js.map +1 -0
  125. package/dist/tools/neural/comparative-analysis.tool.d.ts +37 -0
  126. package/dist/tools/neural/comparative-analysis.tool.d.ts.map +1 -0
  127. package/dist/tools/neural/comparative-analysis.tool.js +241 -0
  128. package/dist/tools/neural/comparative-analysis.tool.js.map +1 -0
  129. package/dist/tools/neural/index.d.ts +12 -0
  130. package/dist/tools/neural/index.d.ts.map +1 -0
  131. package/dist/tools/neural/index.js +28 -0
  132. package/dist/tools/neural/index.js.map +1 -0
  133. package/dist/tools/neural/neural-deadcode.tool.d.ts +10 -0
  134. package/dist/tools/neural/neural-deadcode.tool.d.ts.map +1 -0
  135. package/dist/tools/neural/neural-deadcode.tool.js +133 -0
  136. package/dist/tools/neural/neural-deadcode.tool.js.map +1 -0
  137. package/dist/tools/neural/neural-debug.tool.d.ts +11 -0
  138. package/dist/tools/neural/neural-debug.tool.d.ts.map +1 -0
  139. package/dist/tools/neural/neural-debug.tool.js +205 -0
  140. package/dist/tools/neural/neural-debug.tool.js.map +1 -0
  141. package/dist/tools/neural/neural-explain.tool.d.ts +9 -0
  142. package/dist/tools/neural/neural-explain.tool.d.ts.map +1 -0
  143. package/dist/tools/neural/neural-explain.tool.js +100 -0
  144. package/dist/tools/neural/neural-explain.tool.js.map +1 -0
  145. package/dist/tools/neural/neural-optimize.tool.d.ts +9 -0
  146. package/dist/tools/neural/neural-optimize.tool.d.ts.map +1 -0
  147. package/dist/tools/neural/neural-optimize.tool.js +117 -0
  148. package/dist/tools/neural/neural-optimize.tool.js.map +1 -0
  149. package/dist/tools/neural/neural-pattern.tool.d.ts +10 -0
  150. package/dist/tools/neural/neural-pattern.tool.d.ts.map +1 -0
  151. package/dist/tools/neural/neural-pattern.tool.js +169 -0
  152. package/dist/tools/neural/neural-pattern.tool.js.map +1 -0
  153. package/dist/tools/neural/neural-review.tool.d.ts +11 -0
  154. package/dist/tools/neural/neural-review.tool.d.ts.map +1 -0
  155. package/dist/tools/neural/neural-review.tool.js +152 -0
  156. package/dist/tools/neural/neural-review.tool.js.map +1 -0
  157. package/dist/tools/neural/neural-security.tool.d.ts +16 -0
  158. package/dist/tools/neural/neural-security.tool.d.ts.map +1 -0
  159. package/dist/tools/neural/neural-security.tool.js +256 -0
  160. package/dist/tools/neural/neural-security.tool.js.map +1 -0
  161. package/dist/tools/neural/neural-similar.tool.d.ts +9 -0
  162. package/dist/tools/neural/neural-similar.tool.d.ts.map +1 -0
  163. package/dist/tools/neural/neural-similar.tool.js +139 -0
  164. package/dist/tools/neural/neural-similar.tool.js.map +1 -0
  165. package/dist/tools/neural/neural-smells.tool.d.ts +9 -0
  166. package/dist/tools/neural/neural-smells.tool.d.ts.map +1 -0
  167. package/dist/tools/neural/neural-smells.tool.js +123 -0
  168. package/dist/tools/neural/neural-smells.tool.js.map +1 -0
  169. package/dist/tools/neural/neural-suggest.tool.d.ts +9 -0
  170. package/dist/tools/neural/neural-suggest.tool.d.ts.map +1 -0
  171. package/dist/tools/neural/neural-suggest.tool.js +64 -0
  172. package/dist/tools/neural/neural-suggest.tool.js.map +1 -0
  173. package/dist/tools/quality/index.d.ts +8 -0
  174. package/dist/tools/quality/index.d.ts.map +1 -0
  175. package/dist/tools/quality/index.js +24 -0
  176. package/dist/tools/quality/index.js.map +1 -0
  177. package/dist/tools/quality/quality-complexity.tool.d.ts +11 -0
  178. package/dist/tools/quality/quality-complexity.tool.d.ts.map +1 -0
  179. package/dist/tools/quality/quality-complexity.tool.js +152 -0
  180. package/dist/tools/quality/quality-complexity.tool.js.map +1 -0
  181. package/dist/tools/quality/quality-coupling.tool.d.ts +9 -0
  182. package/dist/tools/quality/quality-coupling.tool.d.ts.map +1 -0
  183. package/dist/tools/quality/quality-coupling.tool.js +51 -0
  184. package/dist/tools/quality/quality-coupling.tool.js.map +1 -0
  185. package/dist/tools/quality/quality-coverage.tool.d.ts +9 -0
  186. package/dist/tools/quality/quality-coverage.tool.d.ts.map +1 -0
  187. package/dist/tools/quality/quality-coverage.tool.js +104 -0
  188. package/dist/tools/quality/quality-coverage.tool.js.map +1 -0
  189. package/dist/tools/quality/quality-deps.tool.d.ts +11 -0
  190. package/dist/tools/quality/quality-deps.tool.d.ts.map +1 -0
  191. package/dist/tools/quality/quality-deps.tool.js +119 -0
  192. package/dist/tools/quality/quality-deps.tool.js.map +1 -0
  193. package/dist/tools/quality/quality-duplication.tool.d.ts +9 -0
  194. package/dist/tools/quality/quality-duplication.tool.d.ts.map +1 -0
  195. package/dist/tools/quality/quality-duplication.tool.js +100 -0
  196. package/dist/tools/quality/quality-duplication.tool.js.map +1 -0
  197. package/dist/tools/quality/quality-size.tool.d.ts +9 -0
  198. package/dist/tools/quality/quality-size.tool.d.ts.map +1 -0
  199. package/dist/tools/quality/quality-size.tool.js +94 -0
  200. package/dist/tools/quality/quality-size.tool.js.map +1 -0
  201. package/dist/tools/quality/quality-types.tool.d.ts +9 -0
  202. package/dist/tools/quality/quality-types.tool.d.ts.map +1 -0
  203. package/dist/tools/quality/quality-types.tool.js +95 -0
  204. package/dist/tools/quality/quality-types.tool.js.map +1 -0
  205. package/dist/tools/workspace/analyze-project.tool.d.ts +36 -0
  206. package/dist/tools/workspace/analyze-project.tool.d.ts.map +1 -0
  207. package/dist/tools/workspace/analyze-project.tool.js +454 -0
  208. package/dist/tools/workspace/analyze-project.tool.js.map +1 -0
  209. package/dist/tools/workspace/codebase-research.tool.d.ts +10 -0
  210. package/dist/tools/workspace/codebase-research.tool.d.ts.map +1 -0
  211. package/dist/tools/workspace/codebase-research.tool.js +89 -0
  212. package/dist/tools/workspace/codebase-research.tool.js.map +1 -0
  213. package/dist/tools/workspace/project-scanner.tool.d.ts +55 -0
  214. package/dist/tools/workspace/project-scanner.tool.d.ts.map +1 -0
  215. package/dist/tools/workspace/project-scanner.tool.js +978 -0
  216. package/dist/tools/workspace/project-scanner.tool.js.map +1 -0
  217. package/dist/tools/workspace/search-code.tool.d.ts +14 -0
  218. package/dist/tools/workspace/search-code.tool.d.ts.map +1 -0
  219. package/dist/tools/workspace/search-code.tool.js +286 -0
  220. package/dist/tools/workspace/search-code.tool.js.map +1 -0
  221. package/package.json +17 -0
  222. package/src/contexts/context-decomposer.ts +113 -0
  223. package/src/contexts/context-document-manager.ts +70 -0
  224. package/src/contexts/context-router.ts +121 -0
  225. package/src/index.ts +65 -0
  226. package/src/libs/codebase/deep-analyzer.ts +287 -0
  227. package/src/libs/codebase/graph/dependency-extractor.ts +165 -0
  228. package/src/libs/codebase/graph/graph-analysis.ts +231 -0
  229. package/src/libs/codebase/graph/graph-visualizer.ts +124 -0
  230. package/src/libs/codebase/indexer/batch-processor.ts +47 -0
  231. package/src/libs/codebase/indexer/chunker-markdown.ts +175 -0
  232. package/src/libs/codebase/indexer/chunker.ts +126 -0
  233. package/src/libs/codebase/indexer/explorer.ts +269 -0
  234. package/src/libs/codebase/indexer/indexer.ts +174 -0
  235. package/src/libs/codebase/knowledge/cross-referencer.ts +182 -0
  236. package/src/libs/codebase/knowledge/markdown-extractor.ts +270 -0
  237. package/src/libs/codebase/knowledge/summarizer.ts +85 -0
  238. package/src/libs/codebase/search/bm25.ts +109 -0
  239. package/src/libs/codebase/search/hybrid-search.ts +109 -0
  240. package/src/libs/codebase-index.class.ts +715 -0
  241. package/src/tools/codebase/codebase-analyze.tool.ts +18 -0
  242. package/src/tools/codebase/codebase-crossref.tool.ts +18 -0
  243. package/src/tools/codebase/codebase-flow.tool.ts +18 -0
  244. package/src/tools/codebase/codebase-graph-circular.tool.ts +15 -0
  245. package/src/tools/codebase/codebase-graph-query.tool.ts +19 -0
  246. package/src/tools/codebase/codebase-graph-stats.tool.ts +15 -0
  247. package/src/tools/codebase/codebase-graph-visualize.tool.ts +19 -0
  248. package/src/tools/codebase/codebase-impact.tool.ts +19 -0
  249. package/src/tools/codebase/codebase-index.tool.ts +19 -0
  250. package/src/tools/codebase/codebase-knowledge.tool.ts +20 -0
  251. package/src/tools/codebase/codebase-search.tool.ts +22 -0
  252. package/src/tools/codebase/codebase-status.tool.ts +17 -0
  253. package/src/tools/neural/comparative-analysis.tool.ts +309 -0
  254. package/src/tools/neural/index.ts +11 -0
  255. package/src/tools/neural/neural-deadcode.tool.ts +105 -0
  256. package/src/tools/neural/neural-debug.tool.ts +199 -0
  257. package/src/tools/neural/neural-explain.tool.ts +67 -0
  258. package/src/tools/neural/neural-optimize.tool.ts +93 -0
  259. package/src/tools/neural/neural-pattern.tool.ts +141 -0
  260. package/src/tools/neural/neural-review.tool.ts +145 -0
  261. package/src/tools/neural/neural-security.tool.ts +226 -0
  262. package/src/tools/neural/neural-similar.tool.ts +113 -0
  263. package/src/tools/neural/neural-smells.tool.ts +98 -0
  264. package/src/tools/neural/neural-suggest.tool.ts +65 -0
  265. package/src/tools/quality/index.ts +7 -0
  266. package/src/tools/quality/quality-complexity.tool.ts +132 -0
  267. package/src/tools/quality/quality-coupling.tool.ts +57 -0
  268. package/src/tools/quality/quality-coverage.tool.ts +78 -0
  269. package/src/tools/quality/quality-deps.tool.ts +89 -0
  270. package/src/tools/quality/quality-duplication.tool.ts +71 -0
  271. package/src/tools/quality/quality-size.tool.ts +66 -0
  272. package/src/tools/quality/quality-types.tool.ts +66 -0
  273. package/src/tools/workspace/analyze-project.tool.ts +429 -0
  274. package/src/tools/workspace/codebase-research.tool.ts +100 -0
  275. package/src/tools/workspace/project-scanner.tool.ts +1058 -0
  276. package/src/tools/workspace/search-code.tool.ts +344 -0
  277. package/tsconfig.build.json +12 -0
  278. package/tsconfig.json +9 -0
@@ -0,0 +1,199 @@
1
+ import { z } from "zod";
2
+ import { ToolBase, ToolContext, ToolExecutionResult } from "@thoughtflow/core";
3
+ import { DependencyExtractor } from "../../libs/codebase/graph/dependency-extractor";
4
+ import { CodebaseExplorer } from "../../libs/codebase/indexer/explorer";
5
+ import * as fs from "node:fs";
6
+ import * as path from "node:path";
7
+
8
+ const DebugResultSchema = z.object({
9
+ errorType: z.string(),
10
+ rootCause: z.string(),
11
+ suggestedFix: z.string(),
12
+ codeFixExample: z.string().optional(),
13
+ affectedFiles: z.array(z.string()),
14
+ confidence: z.enum(["high", "medium", "low"]),
15
+ });
16
+
17
+ type DebugResult = z.infer<typeof DebugResultSchema>;
18
+
19
+ export class NeuralDebugTool extends ToolBase {
20
+ readonly name = "neuralDebug";
21
+ readonly description = "Analyze a stack trace or error against the codebase to suggest a fix. Parses stack frames, finds relevant source files, extracts context, and uses LLM to propose solutions.";
22
+ override readonly readonly = true;
23
+
24
+ constructor() {
25
+ super(z.object({
26
+ error: z.string().describe("Stack trace or error message"),
27
+ projectPath: z.string().optional(),
28
+ maxFrames: z.number().optional().describe("Max stack frames to analyze"),
29
+ }));
30
+ }
31
+
32
+ async run(input: Record<string, unknown>, ctx: ToolContext): Promise<ToolExecutionResult> {
33
+ const { error, maxFrames } = input as { error: string; projectPath?: string; maxFrames?: number };
34
+ const rootPath = (input.projectPath as string) ?? process.cwd();
35
+ const max = maxFrames ?? 5;
36
+
37
+ const frames = this.parseStackTrace(error, rootPath);
38
+ const relevantFrames = frames.slice(0, max);
39
+
40
+ const analysis: Array<{ file: string; line: number; column?: number; context: string; suggestions: string[] }> = [];
41
+
42
+ for (const frame of relevantFrames) {
43
+ const absolutePath = path.join(rootPath, frame.file);
44
+ if (!fs.existsSync(absolutePath)) continue;
45
+
46
+ const content = fs.readFileSync(absolutePath, "utf8");
47
+ const lines = content.split("\n");
48
+ const start = Math.max(0, frame.line - 10);
49
+ const end = Math.min(lines.length, frame.line + 10);
50
+ const context = lines.slice(start, end)
51
+ .map((l, i) => `${start + i + 1}: ${l}`)
52
+ .join("\n");
53
+
54
+ const suggestions = this.staticAnalyzeContext(lines, frame.line, frame.message);
55
+
56
+ analysis.push({ file: frame.file, line: frame.line, column: frame.column, context, suggestions });
57
+ }
58
+
59
+ const explorer = new CodebaseExplorer();
60
+ const files = explorer.explore({ rootPath });
61
+ const codeFiles = files.filter((f) => f.classification === "source-code")
62
+ .map((f) => ({ relativePath: f.relativePath, absolutePath: f.absolutePath }));
63
+
64
+ const depExtractor = new DependencyExtractor();
65
+ const graph = await depExtractor.buildGraph(codeFiles, rootPath);
66
+
67
+ const affectedFiles = new Set<string>();
68
+ for (const frame of relevantFrames) {
69
+ affectedFiles.add(frame.file);
70
+ const dependents = graph.edges.filter((e) => e.to === frame.file);
71
+ for (const dep of dependents.slice(0, 5)) {
72
+ affectedFiles.add(dep.from);
73
+ }
74
+ }
75
+
76
+ const callStructured = ctx.conversation?.callStructured;
77
+ if (!callStructured) {
78
+ return {
79
+ success: true,
80
+ output: JSON.stringify({
81
+ error: error.split("\n")[0],
82
+ framesAnalyzed: analysis.length,
83
+ totalFrames: frames.length,
84
+ affectedFiles: Array.from(affectedFiles).slice(0, 15),
85
+ analysis,
86
+ llmUsed: false,
87
+ }),
88
+ };
89
+ }
90
+
91
+ const codeContext = analysis
92
+ .map((a) => `=== ${a.file}:${a.line} ===\n${a.context}`)
93
+ .join("\n\n")
94
+ .slice(0, 8000);
95
+
96
+ const prompt = `You are an expert software debugger. Analyze the stack trace and source code context, then provide a structured root cause analysis, a concrete suggested fix with code example, and list of affected files.
97
+
98
+ ERROR:
99
+ ${error}
100
+
101
+ RELEVANT SOURCE CODE:
102
+ ${codeContext}
103
+
104
+ STATIC ANALYSIS HINTS:
105
+ ${analysis.map((a) => `- ${a.file}:${a.line}: ${a.suggestions.join("; ")}`).join("\n")}`;
106
+
107
+ try {
108
+ const result = await callStructured(prompt, DebugResultSchema);
109
+
110
+ return {
111
+ success: true,
112
+ output: JSON.stringify({
113
+ ...result,
114
+ stackFrames: frames.length,
115
+ relevantFiles: relevantFrames.map((f) => f.file),
116
+ affectedFiles: Array.from(affectedFiles).slice(0, 15),
117
+ filesAnalyzed: analysis.length,
118
+ llmUsed: true,
119
+ }),
120
+ };
121
+ } catch {
122
+ return {
123
+ success: true,
124
+ output: JSON.stringify({
125
+ error: error.split("\n")[0],
126
+ stackFrames: frames.length,
127
+ relevantFiles: relevantFrames.map((f) => f.file),
128
+ affectedFiles: Array.from(affectedFiles).slice(0, 15),
129
+ analysis,
130
+ llmUsed: false,
131
+ }),
132
+ };
133
+ }
134
+ }
135
+
136
+ private parseStackTrace(error: string, rootPath: string): Array<{ file: string; line: number; column?: number; message: string }> {
137
+ const frames: Array<{ file: string; line: number; column?: number; message: string }> = [];
138
+ const lines = error.split("\n");
139
+ const message = lines[0];
140
+
141
+ const patterns = [
142
+ /at\s+(?:async\s+)?(?:\S+\s+)?\(?(.+?):(\d+):(\d+)\)?/g,
143
+ /at\s+(.+?):(\d+):(\d+)/g,
144
+ ];
145
+
146
+ for (const line of lines) {
147
+ for (const pattern of patterns) {
148
+ pattern.lastIndex = 0;
149
+ let match;
150
+ while ((match = pattern.exec(line)) !== null) {
151
+ const file = match[1].replace(/^file:\/\//, "");
152
+ const lineNum = parseInt(match[2], 10);
153
+ const col = match[3] ? parseInt(match[3], 10) : undefined;
154
+
155
+ if (file.includes("node_modules") || file.includes("node:")) continue;
156
+
157
+ const relative = file.startsWith(rootPath)
158
+ ? path.relative(rootPath, file)
159
+ : file;
160
+
161
+ frames.push({ file: relative, line: lineNum, column: col, message });
162
+ }
163
+ }
164
+ }
165
+
166
+ return frames;
167
+ }
168
+
169
+ private staticAnalyzeContext(lines: string[], lineNum: number, errorMsg: string): string[] {
170
+ const suggestions: string[] = [];
171
+ const targetLine = lines[lineNum - 1] ?? "";
172
+
173
+ if (targetLine.trim().startsWith("//") || targetLine.trim().startsWith("/*")) {
174
+ suggestions.push("Error on a comment line — check preceding/succeeding code");
175
+ }
176
+
177
+ if (targetLine.includes("undefined") || targetLine.includes("null")) {
178
+ suggestions.push("Possible null/undefined access — add null check or optional chaining");
179
+ }
180
+
181
+ if (targetLine.includes(".map(") || targetLine.includes(".filter(") || targetLine.includes(".find(")) {
182
+ suggestions.push("Array method may be called on undefined — ensure array is initialized");
183
+ }
184
+
185
+ if (targetLine.includes("await")) {
186
+ suggestions.push("Async operation — verify error handling with try/catch or .catch()");
187
+ }
188
+
189
+ if (targetLine.includes("import")) {
190
+ suggestions.push("Import resolution error — check file path, extension, and module existence");
191
+ }
192
+
193
+ if (suggestions.length === 0) {
194
+ suggestions.push("Review the surrounding context for variable initialization and error handling");
195
+ }
196
+
197
+ return suggestions;
198
+ }
199
+ }
@@ -0,0 +1,67 @@
1
+ import { z } from "zod";
2
+ import { ToolBase, ToolContext, ToolExecutionResult } from "@thoughtflow/core";
3
+ import * as fs from "node:fs";
4
+ import * as path from "node:path";
5
+
6
+ export class NeuralExplainTool extends ToolBase {
7
+ readonly name = "neuralExplain";
8
+ readonly description = "Explain any code snippet, function, or file in natural language. Uses LLM to provide clear, educational explanations of what the code does, its purpose, and how it works.";
9
+ override readonly readonly = true;
10
+
11
+ constructor() {
12
+ super(z.object({
13
+ target: z.string().describe("File path, function name, or code snippet to explain"),
14
+ detail: z.enum(["brief", "detailed", "tutorial"]).optional().describe("Level of detail (default: detailed)"),
15
+ projectPath: z.string().optional(),
16
+ }));
17
+ }
18
+
19
+ async run(input: Record<string, unknown>, ctx: ToolContext): Promise<ToolExecutionResult> {
20
+ const { target, detail } = input as { target: string; detail?: string };
21
+ const rootPath = (input.projectPath as string) ?? process.cwd();
22
+ const level = detail ?? "detailed";
23
+
24
+ let codeToExplain = target;
25
+ const fullPath = path.join(rootPath, target);
26
+ try {
27
+ if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
28
+ codeToExplain = fs.readFileSync(fullPath, "utf8").slice(0, 8000);
29
+ }
30
+ } catch {
31
+ /* use target as-is */
32
+ }
33
+
34
+ const callStructured = ctx.conversation?.callStructured;
35
+ if (!callStructured) {
36
+ return {
37
+ success: true,
38
+ output: JSON.stringify({
39
+ explanation: "LLM not available — raw code provided for manual review",
40
+ code: codeToExplain.slice(0, 500),
41
+ level,
42
+ }),
43
+ };
44
+ }
45
+
46
+ const prompt = level === "brief"
47
+ ? `Explain this code in 1-2 sentences:\n\n\`\`\`\n${codeToExplain}\n\`\`\``
48
+ : level === "tutorial"
49
+ ? `Explain this code as a step-by-step tutorial for beginners. Cover what it does, why each part exists, and how each piece works together:\n\n\`\`\`\n${codeToExplain}\n\`\`\``
50
+ : `Explain this code in detail — what it does, its purpose, key design decisions, and how it fits into the larger system. Cover the logic flow, data transformations, and any notable patterns:\n\n\`\`\`\n${codeToExplain}\n\`\`\``;
51
+
52
+ try {
53
+ const result = await callStructured(prompt, z.object({ explanation: z.string() }));
54
+ const data = result as { explanation?: string };
55
+ return { success: true, output: data.explanation ?? "No explanation generated" };
56
+ } catch (err) {
57
+ return {
58
+ success: true,
59
+ output: JSON.stringify({
60
+ explanation: `Failed to generate explanation: ${err instanceof Error ? err.message : "Unknown error"}`,
61
+ code: codeToExplain.slice(0, 500),
62
+ level,
63
+ }),
64
+ };
65
+ }
66
+ }
67
+ }
@@ -0,0 +1,93 @@
1
+ import { z } from "zod";
2
+ import { ToolBase, ToolContext, ToolExecutionResult } from "@thoughtflow/core";
3
+ import { CodebaseExplorer } from "../../libs/codebase/indexer/explorer";
4
+ import * as fs from "node:fs";
5
+ import * as path from "node:path";
6
+
7
+ const OptimizeSuggestionSchema = z.object({
8
+ category: z.string(),
9
+ severity: z.enum(["high", "medium", "low"]),
10
+ message: z.string(),
11
+ fix: z.string(),
12
+ estimatedImpact: z.string(),
13
+ });
14
+
15
+ export class NeuralOptimizeTool extends ToolBase {
16
+ readonly name = "neuralOptimize";
17
+ readonly description = "AI-powered performance optimization. Combines static pattern detection (N+1 queries, sync-in-async, missing memoization) with LLM semantic analysis of hot-path inefficiencies. Provides concrete fix suggestions with estimated impact.";
18
+ override readonly readonly = true;
19
+
20
+ constructor() {
21
+ super(z.object({
22
+ target: z.string().optional().describe("File path or leave empty for worst offenders"),
23
+ projectPath: z.string().optional(),
24
+ }));
25
+ }
26
+
27
+ async run(input: Record<string, unknown>, ctx: ToolContext): Promise<ToolExecutionResult> {
28
+ const rootPath = (input.projectPath as string) ?? process.cwd();
29
+ const target = (input.target as string) || undefined;
30
+
31
+ const explorer = new CodebaseExplorer();
32
+ const files = explorer.explore({ rootPath });
33
+ const scanFiles = target
34
+ ? files.filter((f) => f.relativePath.includes(target)).slice(0, 5)
35
+ : files.filter((f) => f.classification === "source-code").slice(0, 20);
36
+
37
+ const staticIssues: Array<{ category: string; severity: string; file: string; line?: number; message: string; fix: string; estimatedImpact: string }> = [];
38
+
39
+ for (const file of scanFiles) {
40
+ const content = fs.readFileSync(file.absolutePath, "utf8");
41
+ const lines = content.split("\n");
42
+
43
+ for (let i = 0; i < lines.length; i++) {
44
+ const surrounding = lines.slice(Math.max(0, i - 3), i + 3).join("\n");
45
+ if (lines[i].match(/\.findMany|\.findFirst|\.findUnique|\.query|\.execute/) && surrounding.match(/for\s*\(|forEach|\.map\s*\(/)) {
46
+ staticIssues.push({ category: "n+1", severity: "high", file: file.relativePath, line: i + 1, message: "Database query inside loop — potential N+1 problem", fix: "Use batch query, eager loading (include), or DataLoader", estimatedImpact: "Can reduce DB calls from N to 1" });
47
+ }
48
+ if (lines[i].includes("await") && surrounding.match(/for\s*\(.*of/) && lines[i].match(/await\s+\w+/)) {
49
+ staticIssues.push({ category: "sequential-async", severity: "medium", file: file.relativePath, line: i + 1, message: "Sequential awaits in loop — can parallelize", fix: "Use Promise.all() for independent async operations", estimatedImpact: "Can reduce total time by factor of N" });
50
+ }
51
+ }
52
+
53
+ if (content.match(/\.filter|\.sort|\.reduce/) && !content.includes("useMemo") && !content.includes("useCallback") && (file.relativePath.endsWith(".tsx") || file.relativePath.endsWith(".jsx"))) {
54
+ staticIssues.push({ category: "missing-memo", severity: "medium", file: file.relativePath, message: "Expensive computation in render without memoization", fix: "Wrap in useMemo/useCallback", estimatedImpact: "Can prevent unnecessary re-renders" });
55
+ }
56
+ }
57
+
58
+ const cs = ctx.conversation?.callStructured;
59
+ if (!cs) {
60
+ return { success: true, output: JSON.stringify({ filesScanned: scanFiles.length, issuesFound: staticIssues.length, issues: staticIssues }) };
61
+ }
62
+
63
+ const codeSnippets = scanFiles.filter((f) => {
64
+ const c = fs.readFileSync(f.absolutePath, "utf8");
65
+ return c.includes("await") || c.includes(".find") || c.includes(".map") || c.includes("for");
66
+ }).slice(0, 3).map((f) => {
67
+ const c = fs.readFileSync(f.absolutePath, "utf8").slice(0, 3000);
68
+ return `--- ${f.relativePath} ---\n${c}`;
69
+ }).join("\n\n");
70
+
71
+ if (!codeSnippets) {
72
+ return { success: true, output: JSON.stringify({ filesScanned: scanFiles.length, issuesFound: staticIssues.length, issues: staticIssues }) };
73
+ }
74
+
75
+ const prompt = `Analyze this code for performance optimization opportunities: N+1 queries, missing caching/memoization, unnecessary re-renders, expensive operations in hot paths, sync operations in async contexts, large dependency imports, unnecessary closures, unbatched state updates, premature materialization of large collections, missing lazy evaluation.\n\n${codeSnippets}\n\nReturn structured suggestions with severity and estimated impact.`;
76
+
77
+ try {
78
+ const result = await cs(prompt, z.object({ suggestions: z.array(OptimizeSuggestionSchema) }));
79
+ const llmIssues = (result.suggestions ?? []).map((s) => ({
80
+ category: s.category,
81
+ severity: s.severity,
82
+ file: target ?? "",
83
+ message: s.message,
84
+ fix: s.fix,
85
+ estimatedImpact: s.estimatedImpact,
86
+ }));
87
+ const allIssues = [...staticIssues, ...llmIssues];
88
+ return { success: true, output: JSON.stringify({ filesScanned: scanFiles.length, issuesFound: allIssues.length, issues: allIssues.slice(0, 20) }) };
89
+ } catch {
90
+ return { success: true, output: JSON.stringify({ filesScanned: scanFiles.length, issuesFound: staticIssues.length, issues: staticIssues }) };
91
+ }
92
+ }
93
+ }
@@ -0,0 +1,141 @@
1
+ import { z } from "zod";
2
+ import { ToolBase, ToolContext, ToolExecutionResult } from "@thoughtflow/core";
3
+ import * as fs from "node:fs";
4
+ import * as path from "node:path";
5
+
6
+ export class NeuralPatternTool extends ToolBase {
7
+ readonly name = "neuralPattern";
8
+ readonly description = "Recognize design patterns used in the codebase using static analysis and LLM verification. Detects Singleton, Factory, Observer, Strategy, Decorator, Repository, Adapter, Builder, Command, Mediator, Chain of Responsibility, and more.";
9
+ override readonly readonly = true;
10
+
11
+ constructor() {
12
+ super(z.object({
13
+ target: z.string().optional().describe("File or directory to scan"),
14
+ projectPath: z.string().optional(),
15
+ verifyWithLLM: z.boolean().optional().describe("Use LLM to verify ambiguous pattern detections"),
16
+ }));
17
+ }
18
+
19
+ async run(input: Record<string, unknown>, ctx: ToolContext): Promise<ToolExecutionResult> {
20
+ const rootPath = (input.projectPath as string) ?? process.cwd();
21
+ const target = (input.target as string) || "src";
22
+ const verify = (input.verifyWithLLM as boolean) ?? false;
23
+ const targetPath = path.join(rootPath, target);
24
+
25
+ let files: string[] = [];
26
+ if (fs.statSync(targetPath).isDirectory()) {
27
+ const walk = (dir: string) => {
28
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
29
+ if (e.name.startsWith(".") || e.name === "node_modules") continue;
30
+ const fp = path.join(dir, e.name);
31
+ if (e.isDirectory()) walk(fp);
32
+ else if (e.name.endsWith(".ts")) files.push(fp);
33
+ }
34
+ };
35
+ walk(targetPath);
36
+ } else {
37
+ files = [targetPath];
38
+ }
39
+
40
+ const patterns: Array<{ pattern: string; confidence: string; file: string; evidence: string; llmVerified?: boolean }> = [];
41
+
42
+ for (const file of files) {
43
+ const content = fs.readFileSync(file, "utf8");
44
+ const rel = path.relative(rootPath, file);
45
+
46
+ const detections = this.detectPatterns(rel, content);
47
+ for (const d of detections) {
48
+ patterns.push({ ...d, file: rel });
49
+ }
50
+ }
51
+
52
+ let llmResult: { verified?: boolean; corrections?: string[] } | null = null;
53
+ const callStructured = ctx.conversation?.callStructured;
54
+ if (verify && callStructured && patterns.length > 0) {
55
+ const ambiguous = patterns.filter((p) => p.confidence === "medium");
56
+ const toVerify = ambiguous.length > 0 ? ambiguous : patterns.slice(0, 10);
57
+ const patternList = toVerify.map((p) => `- ${p.file}: ${p.pattern} (${p.confidence})`).join("\n");
58
+ const prompt = `Verify these design pattern detections in a codebase:\n${patternList}\n\nAre these correct? Flag any false positives. Return: { verified: boolean, corrections: string[] }`;
59
+ try {
60
+ llmResult = await callStructured(prompt, z.object({ verified: z.boolean(), corrections: z.array(z.string()) }));
61
+ } catch {
62
+ /* skip LLM verification */
63
+ }
64
+ }
65
+
66
+ if (llmResult?.verified && patterns.length > 0) {
67
+ for (const p of patterns) {
68
+ if (p.confidence === "medium") {
69
+ p.llmVerified = true;
70
+ }
71
+ }
72
+ }
73
+
74
+ const patternCounts: Record<string, number> = {};
75
+ for (const p of patterns) {
76
+ patternCounts[p.pattern] = (patternCounts[p.pattern] ?? 0) + 1;
77
+ }
78
+
79
+ return {
80
+ success: true,
81
+ output: JSON.stringify({
82
+ filesScanned: files.length,
83
+ patternsFound: patterns.length,
84
+ byType: patternCounts,
85
+ llmVerified: llmResult?.verified ?? false,
86
+ llmCorrections: llmResult?.corrections,
87
+ patterns: patterns.slice(0, 30),
88
+ }),
89
+ };
90
+ }
91
+
92
+ private detectPatterns(rel: string, content: string): Array<{ pattern: string; confidence: string; evidence: string }> {
93
+ const results: Array<{ pattern: string; confidence: string; evidence: string }> = [];
94
+
95
+ if (rel.toLowerCase().includes("factory")) {
96
+ results.push({ pattern: "Factory", confidence: "high", evidence: "File name indicates Factory pattern" });
97
+ }
98
+ if (rel.toLowerCase().includes("singleton")) {
99
+ results.push({ pattern: "Singleton", confidence: "high", evidence: "File name indicates Singleton" });
100
+ }
101
+ if (rel.toLowerCase().includes("observer") || rel.toLowerCase().includes("listener") || rel.toLowerCase().includes("subscriber")) {
102
+ results.push({ pattern: "Observer", confidence: "high", evidence: "File name indicates Observer pattern" });
103
+ }
104
+ if (rel.toLowerCase().includes("strategy")) {
105
+ results.push({ pattern: "Strategy", confidence: "high", evidence: "File name indicates Strategy pattern" });
106
+ }
107
+ if (rel.toLowerCase().includes("decorator")) {
108
+ results.push({ pattern: "Decorator", confidence: "high", evidence: "File name indicates Decorator" });
109
+ }
110
+ if (rel.toLowerCase().includes("adapter") || rel.toLowerCase().includes("wrapper")) {
111
+ results.push({ pattern: "Adapter", confidence: "high", evidence: "File name indicates Adapter" });
112
+ }
113
+ if (rel.toLowerCase().includes("repository") || rel.toLowerCase().includes("repo")) {
114
+ results.push({ pattern: "Repository", confidence: "high", evidence: "File name indicates Repository" });
115
+ }
116
+ if (rel.toLowerCase().includes("builder")) {
117
+ results.push({ pattern: "Builder", confidence: "high", evidence: "File name indicates Builder" });
118
+ }
119
+ if (rel.toLowerCase().includes("command") || rel.toLowerCase().includes("handler")) {
120
+ results.push({ pattern: "Command", confidence: "medium", evidence: "File name suggests Command pattern" });
121
+ }
122
+ if (rel.toLowerCase().includes("mediator") || rel.toLowerCase().includes("coordinator") || rel.toLowerCase().includes("orchestrator")) {
123
+ results.push({ pattern: "Mediator", confidence: "medium", evidence: "File name suggests Mediator/Coordinator" });
124
+ }
125
+ if (rel.toLowerCase().includes("middleware")) {
126
+ results.push({ pattern: "Chain of Responsibility", confidence: "medium", evidence: "Middleware suggests Chain of Responsibility" });
127
+ }
128
+
129
+ if (content.includes("class ") && content.includes("private static") && content.includes("instance")) {
130
+ results.push({ pattern: "Singleton", confidence: "medium", evidence: "private static instance field detected" });
131
+ }
132
+ if (content.match(/abstract\s+class\s+\w+\s*\{/)) {
133
+ results.push({ pattern: "Template Method", confidence: "medium", evidence: "Abstract class found" });
134
+ }
135
+ if (content.match(/interface\s+\w+/)) {
136
+ results.push({ pattern: "Strategy", confidence: "low", evidence: "Interface suggests potential Strategy pattern" });
137
+ }
138
+
139
+ return results;
140
+ }
141
+ }
@@ -0,0 +1,145 @@
1
+ import { z } from "zod";
2
+ import { ToolBase, ToolContext, ToolExecutionResult } from "@thoughtflow/core";
3
+ import * as fs from "node:fs";
4
+ import * as path from "node:path";
5
+
6
+ const ReviewIssueSchema = z.object({
7
+ severity: z.enum(["critical", "high", "medium", "low", "info"]),
8
+ category: z.enum(["bug", "security", "performance", "style", "types", "architecture", "naming", "maintainability"]),
9
+ line: z.number().optional(),
10
+ message: z.string(),
11
+ suggestion: z.string(),
12
+ });
13
+
14
+ const ReviewResultSchema = z.object({
15
+ summary: z.string(),
16
+ issues: z.array(ReviewIssueSchema),
17
+ overallScore: z.number().min(0).max(100),
18
+ });
19
+
20
+ type ReviewIssue = z.infer<typeof ReviewIssueSchema>;
21
+
22
+ export class NeuralReviewTool extends ToolBase {
23
+ readonly name = "neuralReview";
24
+ readonly description = "AI-powered code review. Analyzes code for bugs, anti-patterns, style issues, type safety, and correctness. Returns issues with severity levels and fix suggestions.";
25
+ override readonly readonly = true;
26
+
27
+ constructor() {
28
+ super(z.object({
29
+ target: z.string().describe("File path or code to review"),
30
+ focus: z.enum(["all", "bugs", "security", "performance", "style", "types"]).optional(),
31
+ projectPath: z.string().optional(),
32
+ }));
33
+ }
34
+
35
+ async run(input: Record<string, unknown>, ctx: ToolContext): Promise<ToolExecutionResult> {
36
+ const { target, focus } = input as { target: string; focus?: string };
37
+ const rootPath = (input.projectPath as string) ?? process.cwd();
38
+ const reviewFocus = focus ?? "all";
39
+
40
+ let code = target;
41
+ let filePath = "(inline)";
42
+ const fullPath = path.join(rootPath, target);
43
+ try {
44
+ if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
45
+ code = fs.readFileSync(fullPath, "utf8").slice(0, 12000);
46
+ filePath = target;
47
+ }
48
+ } catch {
49
+ /* use target as-is */
50
+ }
51
+
52
+ const staticIssues = this.runStaticChecks(code);
53
+
54
+ const callStructured = ctx.conversation?.callStructured;
55
+ if (!callStructured) {
56
+ return this.buildResult(filePath, staticIssues, "Static analysis only — no LLM available", 50);
57
+ }
58
+
59
+ const focusInstruction = reviewFocus !== "all"
60
+ ? `Focus exclusively on ${reviewFocus} issues. Ignore other categories.`
61
+ : "Comprehensively review all aspects.";
62
+
63
+ const prompt = `You are a senior code reviewer. ${focusInstruction}
64
+
65
+ File: ${filePath}
66
+
67
+ \`\`\`
68
+ ${code.slice(0, 8000)}
69
+ \`\`\`
70
+
71
+ Provide a structured review with issues ordered by severity. Consider: bugs, security vulnerabilities, performance problems, type safety gaps, code style violations, architectural issues, poor naming, and maintainability concerns. Be specific — cite exact line numbers where possible. For each issue provide a concrete, actionable fix suggestion.`;
72
+
73
+ try {
74
+ const result = await callStructured(prompt, ReviewResultSchema);
75
+ const data = result as { summary?: string; issues?: ReviewIssue[]; overallScore?: number };
76
+ const allIssues = [...staticIssues, ...(data.issues ?? [])];
77
+ return this.buildResult(
78
+ filePath,
79
+ allIssues.slice(0, 30),
80
+ data.summary ?? "Review complete",
81
+ data.overallScore ?? 50,
82
+ );
83
+ } catch {
84
+ return this.buildResult(filePath, staticIssues.slice(0, 20), "LLM review failed — static analysis only", 40);
85
+ }
86
+ }
87
+
88
+ private runStaticChecks(code: string): ReviewIssue[] {
89
+ const issues: ReviewIssue[] = [];
90
+ const lines = code.split("\n");
91
+
92
+ for (let i = 0; i < lines.length; i++) {
93
+ const line = lines[i];
94
+
95
+ if (line.includes("console.log") || line.includes("console.warn") || line.includes("console.error") || line.includes("console.debug")) {
96
+ issues.push({ severity: "low", category: "style", line: i + 1, message: "Console statement in code", suggestion: "Replace with proper logger" });
97
+ }
98
+
99
+ if (line.match(/eval\s*\(/)) {
100
+ issues.push({ severity: "critical", category: "security", line: i + 1, message: "eval() usage — code injection risk", suggestion: "Avoid eval(); use safer alternatives" });
101
+ }
102
+
103
+ if (line.match(/password|secret|api[_-]?key/i) && line.includes("=") && !line.includes("process.env") && !line.trim().startsWith("//")) {
104
+ issues.push({ severity: "critical", category: "security", line: i + 1, message: "Potential hardcoded secret", suggestion: "Move to environment variable" });
105
+ }
106
+
107
+ if (line.match(/==\s*(true|false|null|undefined)/) && !line.includes("===")) {
108
+ issues.push({ severity: "medium", category: "bug", line: i + 1, message: "Loose equality with boolean/null/undefined", suggestion: "Use === instead of ==" });
109
+ }
110
+
111
+ if (line.length > 150) {
112
+ issues.push({ severity: "low", category: "style", line: i + 1, message: `Line too long (${line.length} chars)`, suggestion: "Split into multiple lines" });
113
+ }
114
+ }
115
+
116
+ return issues;
117
+ }
118
+
119
+ private buildResult(
120
+ filePath: string,
121
+ issues: ReviewIssue[],
122
+ summary: string,
123
+ overallScore: number,
124
+ ): ToolExecutionResult {
125
+ const severityCounts = {
126
+ critical: issues.filter((i) => i.severity === "critical").length,
127
+ high: issues.filter((i) => i.severity === "high").length,
128
+ medium: issues.filter((i) => i.severity === "medium").length,
129
+ low: issues.filter((i) => i.severity === "low").length,
130
+ info: issues.filter((i) => i.severity === "info").length,
131
+ };
132
+
133
+ return {
134
+ success: true,
135
+ output: JSON.stringify({
136
+ file: filePath,
137
+ summary,
138
+ overallScore,
139
+ issueCount: issues.length,
140
+ bySeverity: severityCounts,
141
+ issues,
142
+ }),
143
+ };
144
+ }
145
+ }