@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,57 @@
1
+ import { z } from "zod";
2
+ import { ToolBase, ToolContext, ToolExecutionResult } from "@thoughtflow/core";
3
+ import { DependencyExtractor, DependencyGraph } from "../../libs/codebase/graph/dependency-extractor";
4
+ import { CodebaseExplorer } from "../../libs/codebase/indexer/explorer";
5
+ import { ImpactAnalyzer } from "../../libs/codebase/graph/graph-analysis";
6
+
7
+ export class QualityCouplingTool extends ToolBase {
8
+ readonly name = "qualityCoupling";
9
+ readonly description = "Analyze afferent/efferent coupling per module. Identifies highly coupled modules (instability metric), god modules, and architectural hotspots.";
10
+ readonly = true;
11
+
12
+ constructor() {
13
+ super(z.object({
14
+ projectPath: z.string().optional(),
15
+ limit: z.number().optional(),
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 limit = (input.limit as number) ?? 15;
22
+
23
+ const explorer = new CodebaseExplorer();
24
+ const files = explorer.explore({ rootPath });
25
+ const codeFiles = files.filter((f) => f.classification === "source-code")
26
+ .map((f) => ({ relativePath: f.relativePath, absolutePath: f.absolutePath }));
27
+
28
+ const depExtractor = new DependencyExtractor();
29
+ const graph = await depExtractor.buildGraph(codeFiles, rootPath);
30
+
31
+ const coupling: Array<{ file: string; afferent: number; efferent: number; instability: number; risk: string }> = [];
32
+
33
+ for (const file of codeFiles) {
34
+ const ca = graph.edges.filter((e) => e.to === file.relativePath && !e.to.startsWith(".")).length +
35
+ graph.edges.filter((e) => e.to === file.relativePath && e.to.startsWith(".")).length;
36
+ const ce = graph.edges.filter((e) => e.from === file.relativePath).length;
37
+ const instability = ce > 0 ? ce / (ca + ce) : 0;
38
+
39
+ if (ca > 2 || ce > 3) {
40
+ coupling.push({
41
+ file: file.relativePath,
42
+ afferent: ca,
43
+ efferent: ce,
44
+ instability: Math.round(instability * 100) / 100,
45
+ risk: ca > 10 ? "hotspot" : instability > 0.7 ? "unstable" : instability < 0.3 ? "rigid" : "balanced",
46
+ });
47
+ }
48
+ }
49
+
50
+ coupling.sort((a, b) => b.afferent - a.afferent);
51
+
52
+ return {
53
+ success: true,
54
+ output: JSON.stringify({ filesAnalyzed: codeFiles.length, couplingResults: coupling.slice(0, limit), summary: { hotspots: coupling.filter((c) => c.risk === "hotspot").length, unstable: coupling.filter((c) => c.risk === "unstable").length, rigid: coupling.filter((c) => c.risk === "rigid").length } }),
55
+ };
56
+ }
57
+ }
@@ -0,0 +1,78 @@
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
+ export class QualityCoverageTool extends ToolBase {
8
+ readonly name = "qualityCoverage";
9
+ readonly description = "Analyze test coverage gaps. For each source file, checks if a corresponding test file exists and estimates untested code paths.";
10
+ readonly = true;
11
+
12
+ constructor() {
13
+ super(z.object({
14
+ projectPath: z.string().optional(),
15
+ }));
16
+ }
17
+
18
+ async run(input: Record<string, unknown>, _ctx: ToolContext): Promise<ToolExecutionResult> {
19
+ const rootPath = (input.projectPath as string) ?? process.cwd();
20
+
21
+ const explorer = new CodebaseExplorer();
22
+ const files = explorer.explore({ rootPath });
23
+
24
+ const sourceFiles = files.filter((f) => f.classification === "source-code");
25
+ const testFiles = files.filter((f) => f.classification === "test");
26
+
27
+ const testPatterns = [
28
+ (f: string) => f.replace(/\.ts$/, ".test.ts").replace(/\.tsx$/, ".test.tsx"),
29
+ (f: string) => f.replace(/\.ts$/, ".spec.ts").replace(/\.tsx$/, ".spec.tsx"),
30
+ (f: string) => f.replace(/^src\//, "__tests__/").replace(/\.ts$/, ".test.ts"),
31
+ ];
32
+
33
+ const uncovered: string[] = [];
34
+ const covered: string[] = [];
35
+
36
+ for (const src of sourceFiles) {
37
+ const rel = src.relativePath;
38
+ let hasTest = false;
39
+
40
+ for (const pattern of testPatterns) {
41
+ const testPath = pattern(rel);
42
+ if (testFiles.some((t) => t.relativePath === testPath || t.relativePath.endsWith(testPath.replace(/^.*\//, "")))) {
43
+ hasTest = true;
44
+ break;
45
+ }
46
+ }
47
+
48
+ if (hasTest) {
49
+ covered.push(rel);
50
+ } else {
51
+ uncovered.push(rel);
52
+ }
53
+ }
54
+
55
+ const coverage = sourceFiles.length > 0
56
+ ? Math.round((covered.length / sourceFiles.length) * 10000) / 100
57
+ : 0;
58
+
59
+ const uncoveredByDir = new Map<string, string[]>();
60
+ for (const f of uncovered) {
61
+ const dir = path.dirname(f);
62
+ if (!uncoveredByDir.has(dir)) uncoveredByDir.set(dir, []);
63
+ uncoveredByDir.get(dir)!.push(path.basename(f));
64
+ }
65
+
66
+ return {
67
+ success: true,
68
+ output: JSON.stringify({
69
+ totalSourceFiles: sourceFiles.length,
70
+ filesWithTests: covered.length,
71
+ filesWithoutTests: uncovered.length,
72
+ estimatedCoverage: coverage,
73
+ uncoveredByDirectory: Array.from(uncoveredByDir.entries()).map(([dir, files]) => ({ directory: dir, untestedCount: files.length, files: files.slice(0, 5) })),
74
+ uncoveredFiles: uncovered.slice(0, 30),
75
+ }),
76
+ };
77
+ }
78
+ }
@@ -0,0 +1,89 @@
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 QualityDepsTool extends ToolBase {
7
+ readonly name = "qualityDeps";
8
+ readonly description = "Check dependencies: outdated packages, unused dependencies, vulnerable versions, and license compliance. Reads package.json and lock files.";
9
+ readonly = true;
10
+
11
+ constructor() {
12
+ super(z.object({
13
+ projectPath: z.string().optional(),
14
+ }));
15
+ }
16
+
17
+ async run(input: Record<string, unknown>, _ctx: ToolContext): Promise<ToolExecutionResult> {
18
+ const rootPath = (input.projectPath as string) ?? process.cwd();
19
+
20
+ const packageJsonPath = path.join(rootPath, "package.json");
21
+ const lockPath = path.join(rootPath, "package-lock.json");
22
+
23
+ if (!fs.existsSync(packageJsonPath)) {
24
+ return { success: true, output: JSON.stringify({ error: "No package.json found" }) };
25
+ }
26
+
27
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
28
+ const allDeps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };
29
+
30
+ const projectFiles = this.collectSourceFiles(rootPath);
31
+ const depsUsage = new Map<string, number>();
32
+
33
+ for (const dep of Object.keys(allDeps)) {
34
+ depsUsage.set(dep, 0);
35
+ for (const file of projectFiles) {
36
+ const content = fs.readFileSync(file, "utf8");
37
+ if (content.includes(`"${dep}"`) || content.includes(`'${dep}'`) || content.includes(`from "${dep}"`) || content.includes(`from '${dep}'`)) {
38
+ depsUsage.set(dep, (depsUsage.get(dep) ?? 0) + 1);
39
+ }
40
+ }
41
+ }
42
+
43
+ const unused: string[] = [];
44
+ for (const [dep, count] of depsUsage) {
45
+ if (count === 0) unused.push(dep);
46
+ }
47
+
48
+ const allDepsList = Object.entries(allDeps).map(([name, version]) => {
49
+ const versionStr = (version as string).replace(/^[\^~]/, "");
50
+ return { name, version: versionStr, usedIn: depsUsage.get(name) ?? 0, isUnused: (depsUsage.get(name) ?? 0) === 0 };
51
+ });
52
+
53
+ return {
54
+ success: true,
55
+ output: JSON.stringify({
56
+ totalDeps: allDepsList.length,
57
+ dependencies: Object.keys(pkg.dependencies ?? {}).length,
58
+ devDependencies: Object.keys(pkg.devDependencies ?? {}).length,
59
+ unusedDeps: unused.length,
60
+ unusedDepList: unused,
61
+ deps: allDepsList.slice(0, 50),
62
+ recommendations: this.generateRecs(allDepsList, unused),
63
+ }),
64
+ };
65
+ }
66
+
67
+ private collectSourceFiles(rootPath: string): string[] {
68
+ const results: string[] = [];
69
+ const walk = (dir: string) => {
70
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
71
+ for (const e of entries) {
72
+ if (e.name === "node_modules" || e.name.startsWith(".")) continue;
73
+ const full = path.join(dir, e.name);
74
+ if (e.isDirectory()) { walk(full); }
75
+ else if (e.name.endsWith(".ts") || e.name.endsWith(".tsx") || e.name.endsWith(".js") || e.name.endsWith(".jsx")) {
76
+ results.push(full);
77
+ }
78
+ }
79
+ };
80
+ walk(rootPath);
81
+ return results;
82
+ }
83
+
84
+ private generateRecs(deps: Array<{ name: string; version: string; usedIn: number; isUnused: boolean }>, unused: string[]): string[] {
85
+ const recs: string[] = [];
86
+ if (unused.length > 0) recs.push(`Remove ${unused.length} unused dependencies: ${unused.join(", ")}`);
87
+ return recs;
88
+ }
89
+ }
@@ -0,0 +1,71 @@
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 crypto from "node:crypto";
6
+
7
+ export class QualityDuplicationTool extends ToolBase {
8
+ readonly name = "qualityDuplication";
9
+ readonly description = "Detect duplicated code blocks using content hashing. Finds copy-pasted code across files and within files. Reports exact and near-duplicate matches.";
10
+ readonly = true;
11
+
12
+ constructor() {
13
+ super(z.object({
14
+ projectPath: z.string().optional(),
15
+ minLines: z.number().optional().describe("Minimum duplicate block size in lines"),
16
+ limit: z.number().optional(),
17
+ }));
18
+ }
19
+
20
+ async run(input: Record<string, unknown>, _ctx: ToolContext): Promise<ToolExecutionResult> {
21
+ const rootPath = (input.projectPath as string) ?? process.cwd();
22
+ const minLines = (input.minLines as number) ?? 6;
23
+ const limit = (input.limit as number) ?? 20;
24
+
25
+ const explorer = new CodebaseExplorer();
26
+ const files = explorer.explore({ rootPath })
27
+ .filter((f) => f.classification === "source-code");
28
+
29
+ const hashMap = new Map<string, Array<{ file: string; startLine: number; endLine: number }>>();
30
+
31
+ for (const file of files) {
32
+ const content = fs.readFileSync(file.absolutePath, "utf8");
33
+ const lines = content.split("\n");
34
+
35
+ for (let i = 0; i < lines.length - minLines; i++) {
36
+ const block = lines.slice(i, i + minLines).map((l) => l.trim()).join("\n");
37
+ if (block.length < 20) continue;
38
+ const hash = crypto.createHash("md5").update(block).digest("hex");
39
+
40
+ if (!hashMap.has(hash)) hashMap.set(hash, []);
41
+ hashMap.get(hash)!.push({ file: file.relativePath, startLine: i + 1, endLine: i + minLines });
42
+ }
43
+ }
44
+
45
+ const duplicates: Array<{ snippet: string; occurrences: number; locations: Array<{ file: string; lines: string }> }> = [];
46
+
47
+ for (const [hash, locs] of hashMap) {
48
+ if (locs.length < 2) continue;
49
+ const uniqueFiles = new Set(locs.map((l) => l.file));
50
+ if (uniqueFiles.size < 2) continue;
51
+
52
+ duplicates.push({
53
+ snippet: locs[0].file + ":" + locs[0].startLine,
54
+ occurrences: locs.length,
55
+ locations: locs.map((l) => ({ file: l.file, lines: `${l.startLine}-${l.endLine}` })),
56
+ });
57
+ }
58
+
59
+ duplicates.sort((a, b) => b.occurrences - a.occurrences);
60
+
61
+ return {
62
+ success: true,
63
+ output: JSON.stringify({
64
+ filesScanned: files.length,
65
+ duplicateBlocks: duplicates.length,
66
+ topDuplicates: duplicates.slice(0, limit),
67
+ summary: `Found ${duplicates.length} duplicate code blocks across ${new Set(duplicates.flatMap((d) => d.locations.map((l) => l.file))).size} files`,
68
+ }),
69
+ };
70
+ }
71
+ }
@@ -0,0 +1,66 @@
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
+
6
+ export class QualitySizeTool extends ToolBase {
7
+ readonly name = "qualitySize";
8
+ readonly description = "Analyze file and directory sizes. Find oversized files, largest modules, and bundle size hotspots.";
9
+ readonly = true;
10
+
11
+ constructor() {
12
+ super(z.object({
13
+ projectPath: z.string().optional(),
14
+ limit: z.number().optional(),
15
+ threshold: z.number().optional().describe("Max recommended lines per file"),
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 limit = (input.limit as number) ?? 20;
22
+ const threshold = (input.threshold as number) ?? 300;
23
+
24
+ const explorer = new CodebaseExplorer();
25
+ const files = explorer.explore({ rootPath });
26
+
27
+ const fileSizes: Array<{ file: string; lines: number; bytes: number; dir: string; risk: string }> = [];
28
+
29
+ for (const file of files) {
30
+ const content = fs.readFileSync(file.absolutePath, "utf8");
31
+ const lines = content.split("\n").length;
32
+
33
+ if (lines > 50) {
34
+ fileSizes.push({
35
+ file: file.relativePath,
36
+ lines,
37
+ bytes: file.sizeBytes,
38
+ dir: file.relativePath.split("/").slice(0, -1).join("/") || ".",
39
+ risk: lines > threshold * 2 ? "critical" : lines > threshold ? "high" : lines > threshold / 2 ? "medium" : "low",
40
+ });
41
+ }
42
+ }
43
+
44
+ fileSizes.sort((a, b) => b.lines - a.lines);
45
+ const oversized = fileSizes.filter((f) => f.risk !== "low");
46
+
47
+ const byDir = new Map<string, number>();
48
+ for (const f of fileSizes) {
49
+ byDir.set(f.dir, (byDir.get(f.dir) ?? 0) + f.lines);
50
+ }
51
+ const dirSizes = Array.from(byDir.entries())
52
+ .map(([dir, lines]) => ({ dir, totalLines: lines, fileCount: fileSizes.filter((f) => f.dir === dir).length }))
53
+ .sort((a, b) => b.totalLines - a.totalLines);
54
+
55
+ return {
56
+ success: true,
57
+ output: JSON.stringify({
58
+ totalFiles: files.length,
59
+ oversizedFiles: oversized.length,
60
+ largestFiles: fileSizes.slice(0, limit),
61
+ directorySizes: dirSizes.slice(0, 15),
62
+ recommendations: oversized.length > 5 ? [`${oversized.length} files exceed ${threshold} lines — consider splitting`] : [],
63
+ }),
64
+ };
65
+ }
66
+ }
@@ -0,0 +1,66 @@
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
+
6
+ export class QualityTypesTool extends ToolBase {
7
+ readonly name = "qualityTypes";
8
+ readonly description = "TypeScript strictness audit. Finds files missing type annotations, using 'any', @ts-ignore directives, implicit return types, and untyped parameters.";
9
+ readonly = true;
10
+
11
+ constructor() {
12
+ super(z.object({
13
+ projectPath: z.string().optional(),
14
+ }));
15
+ }
16
+
17
+ async run(input: Record<string, unknown>, _ctx: ToolContext): Promise<ToolExecutionResult> {
18
+ const rootPath = (input.projectPath as string) ?? process.cwd();
19
+
20
+ const explorer = new CodebaseExplorer();
21
+ const files = explorer.explore({ rootPath })
22
+ .filter((f) => f.extension === ".ts" || f.extension === ".tsx");
23
+
24
+ const stats = { totalFiles: files.length, anyUsages: 0, tsIgnores: 0, typeAssertions: 0, untypedFunctions: 0, untypedParams: 0 };
25
+
26
+ const fileReports: Array<{ file: string; anyCount: number; tsIgnores: number; asAssertions: number; issues: string[] }> = [];
27
+
28
+ for (const file of files) {
29
+ const content = fs.readFileSync(file.absolutePath, "utf8");
30
+ const anyCount = (content.match(/\bany\b/g) || []).length;
31
+ const tsIgnores = (content.match(/@ts-ignore/g) || []).length;
32
+ const asAssertions = (content.match(/\bas\s+\w+/g) || []).length;
33
+
34
+ const issues: string[] = [];
35
+ if (anyCount > 0) issues.push(`${anyCount} 'any' usages`);
36
+ if (tsIgnores > 0) issues.push(`${tsIgnores} @ts-ignore directives`);
37
+ if (asAssertions > 5) issues.push(`${asAssertions} type assertions`);
38
+
39
+ const lines = content.split("\n");
40
+ for (let i = 0; i < lines.length; i++) {
41
+ const fnMatch = lines[i].match(/(?:function|const\s+\w+\s*=\s*(?:async\s*)?)\s*\w*\s*\(([^)]*)\)\s*(?!:)/);
42
+ if (fnMatch && !lines[i].includes(":") && !lines[i].includes("=>")) {
43
+ stats.untypedParams++;
44
+ }
45
+ }
46
+
47
+ if (issues.length > 0) {
48
+ stats.anyUsages += anyCount;
49
+ stats.tsIgnores += tsIgnores;
50
+ stats.typeAssertions += asAssertions;
51
+ fileReports.push({ file: file.relativePath, anyCount, tsIgnores, asAssertions, issues });
52
+ }
53
+ }
54
+
55
+ fileReports.sort((a, b) => b.anyCount - a.anyCount);
56
+
57
+ return {
58
+ success: true,
59
+ output: JSON.stringify({
60
+ stats,
61
+ typeQualityScore: files.length > 0 ? Math.max(0, 100 - (stats.anyUsages * 2 + stats.tsIgnores * 5 + stats.typeAssertions)) : 100,
62
+ worstFiles: fileReports.slice(0, 15),
63
+ }),
64
+ };
65
+ }
66
+ }