@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,978 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ProjectScannerTool = exports.MONOREPO_RULES = exports.TECH_RULES = void 0;
37
+ const zod_1 = require("zod");
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const core_1 = require("@thoughtflow/core");
41
+ /* ═══════════════════════════════════════════════════════════════
42
+ TECH RULES — sorted by category, then by specificity.
43
+ Framework rules should come AFTER language rules so the
44
+ output reads naturally (language first, then framework).
45
+ ═══════════════════════════════════════════════════════════════ */
46
+ exports.TECH_RULES = [
47
+ // ——— Languages ———————————————————————————————————————
48
+ {
49
+ id: "typescript",
50
+ name: "TypeScript",
51
+ category: "language",
52
+ fileMarkers: ["tsconfig.json", "tsconfig.base.json"],
53
+ dirMarkers: [],
54
+ ignoreDirs: ["node_modules", "dist", "build", ".tsbuildinfo"],
55
+ keyFiles: ["tsconfig.json"],
56
+ explorePatterns: [],
57
+ hints: [],
58
+ },
59
+ {
60
+ id: "nodejs",
61
+ name: "Node.js",
62
+ category: "language",
63
+ fileMarkers: ["package.json"],
64
+ dirMarkers: [],
65
+ ignoreDirs: ["node_modules", "dist", "build", ".cache", ".parcel-cache"],
66
+ keyFiles: ["package.json"],
67
+ explorePatterns: [],
68
+ hints: ["Check 'scripts' in package.json for build/start/test commands"],
69
+ },
70
+ {
71
+ id: "python",
72
+ name: "Python",
73
+ category: "language",
74
+ fileMarkers: [
75
+ "pyproject.toml",
76
+ "setup.py",
77
+ "requirements.txt",
78
+ "Pipfile",
79
+ "setup.cfg",
80
+ ],
81
+ dirMarkers: [],
82
+ ignoreDirs: [
83
+ "__pycache__",
84
+ ".venv",
85
+ "venv",
86
+ "env",
87
+ ".eggs",
88
+ ".mypy_cache",
89
+ ".pytest_cache",
90
+ ".ruff_cache",
91
+ ],
92
+ keyFiles: ["pyproject.toml", "requirements.txt", "setup.py"],
93
+ explorePatterns: ["**/*.py"],
94
+ hints: ["Entry points in pyproject.toml [project.scripts] or setup.py"],
95
+ },
96
+ {
97
+ id: "rust",
98
+ name: "Rust",
99
+ category: "language",
100
+ fileMarkers: ["Cargo.toml"],
101
+ dirMarkers: [],
102
+ ignoreDirs: ["target"],
103
+ keyFiles: ["Cargo.toml", "src/main.rs", "src/lib.rs"],
104
+ explorePatterns: ["**/*.rs"],
105
+ hints: ["Binaries in src/bin/, library in src/lib.rs"],
106
+ },
107
+ {
108
+ id: "go",
109
+ name: "Go",
110
+ category: "language",
111
+ fileMarkers: ["go.mod"],
112
+ dirMarkers: [],
113
+ ignoreDirs: ["vendor"],
114
+ keyFiles: ["go.mod"],
115
+ explorePatterns: ["**/*.go"],
116
+ hints: ["Binaries in cmd/, private libs in internal/"],
117
+ },
118
+ {
119
+ id: "php",
120
+ name: "PHP",
121
+ category: "language",
122
+ fileMarkers: ["composer.json"],
123
+ dirMarkers: [],
124
+ ignoreDirs: ["vendor", "storage/framework"],
125
+ keyFiles: ["composer.json"],
126
+ explorePatterns: ["**/*.php"],
127
+ hints: ["PSR-4 autoloading in composer.json"],
128
+ },
129
+ {
130
+ id: "java",
131
+ name: "Java",
132
+ category: "language",
133
+ fileMarkers: ["pom.xml", "build.gradle", "build.gradle.kts"],
134
+ dirMarkers: [],
135
+ ignoreDirs: ["target", "build", ".gradle", "out"],
136
+ keyFiles: ["pom.xml", "build.gradle", "build.gradle.kts"],
137
+ explorePatterns: ["**/*.java", "**/*.kt"],
138
+ hints: ["Source in src/main/java, tests in src/test/java"],
139
+ },
140
+ {
141
+ id: "dotnet",
142
+ name: ".NET/C#",
143
+ category: "language",
144
+ fileMarkers: [], // detected via extension scan in detectTechs
145
+ dirMarkers: [],
146
+ ignoreDirs: ["bin", "obj", ".vs"],
147
+ keyFiles: [],
148
+ explorePatterns: ["**/*.cs", "**/*.csproj"],
149
+ hints: [".sln defines project structure, .csproj defines build"],
150
+ },
151
+ {
152
+ id: "ruby",
153
+ name: "Ruby",
154
+ category: "language",
155
+ fileMarkers: ["Gemfile"],
156
+ dirMarkers: [],
157
+ ignoreDirs: ["vendor/bundle", ".bundle"],
158
+ keyFiles: ["Gemfile"],
159
+ explorePatterns: ["**/*.rb"],
160
+ hints: ["Application code in lib/ or app/"],
161
+ },
162
+ // ——— Frameworks ——————————————————————————————————————
163
+ {
164
+ id: "nestjs",
165
+ name: "NestJS",
166
+ category: "framework",
167
+ fileMarkers: ["nest-cli.json"],
168
+ dirMarkers: [],
169
+ packageDeps: ["@nestjs/core"],
170
+ ignoreDirs: [],
171
+ keyFiles: ["nest-cli.json", "src/main.ts", "src/app.module.ts"],
172
+ explorePatterns: [
173
+ "**/*.controller.ts",
174
+ "**/*.module.ts",
175
+ "**/*.service.ts",
176
+ "**/*.guard.ts",
177
+ "**/*.gateway.ts",
178
+ ],
179
+ hints: [
180
+ "Controllers: @Get/@Post/@Put/@Delete define HTTP endpoints",
181
+ "Modules: imports[] shows feature dependencies",
182
+ ],
183
+ },
184
+ {
185
+ id: "angular",
186
+ name: "Angular",
187
+ category: "framework",
188
+ fileMarkers: ["angular.json"],
189
+ dirMarkers: [],
190
+ packageDeps: ["@angular/core"],
191
+ ignoreDirs: [".angular"],
192
+ keyFiles: [
193
+ "angular.json",
194
+ "src/app/app.routes.ts",
195
+ "src/app/app.module.ts",
196
+ "src/app/app.config.ts",
197
+ ],
198
+ explorePatterns: [
199
+ "**/*.component.ts",
200
+ "**/*routing*",
201
+ "**/*.module.ts",
202
+ ],
203
+ hints: [
204
+ "Routes: app.routes.ts (standalone) or *-routing.module.ts",
205
+ "Components: @Component decorator, templates inline or .html",
206
+ ],
207
+ },
208
+ {
209
+ id: "react",
210
+ name: "React",
211
+ category: "framework",
212
+ fileMarkers: [],
213
+ dirMarkers: [],
214
+ packageDeps: ["react"],
215
+ ignoreDirs: [],
216
+ keyFiles: ["src/App.tsx", "src/App.jsx", "src/index.tsx"],
217
+ explorePatterns: ["**/*.tsx", "**/*.jsx"],
218
+ hints: ["Components in src/, routing often in App.tsx or routes/"],
219
+ },
220
+ {
221
+ id: "nextjs",
222
+ name: "Next.js",
223
+ category: "framework",
224
+ fileMarkers: ["next.config.js", "next.config.mjs", "next.config.ts"],
225
+ dirMarkers: [],
226
+ packageDeps: ["next"],
227
+ ignoreDirs: [".next"],
228
+ keyFiles: ["next.config.js", "next.config.mjs", "next.config.ts"],
229
+ explorePatterns: ["app/**/page.tsx", "app/**/route.ts", "pages/**/*.tsx"],
230
+ hints: [
231
+ "App Router: app/ dir, page.tsx=pages, route.ts=API",
232
+ "Pages Router: pages/ dir, file-based routing",
233
+ ],
234
+ },
235
+ {
236
+ id: "vue",
237
+ name: "Vue.js",
238
+ category: "framework",
239
+ fileMarkers: ["vue.config.js"],
240
+ dirMarkers: [],
241
+ packageDeps: ["vue"],
242
+ ignoreDirs: [],
243
+ keyFiles: ["src/App.vue", "src/main.ts", "src/router/index.ts"],
244
+ explorePatterns: ["**/*.vue"],
245
+ hints: ["Single-file components (.vue), routing in src/router/"],
246
+ },
247
+ {
248
+ id: "nuxt",
249
+ name: "Nuxt",
250
+ category: "framework",
251
+ fileMarkers: ["nuxt.config.ts", "nuxt.config.js"],
252
+ dirMarkers: [],
253
+ packageDeps: ["nuxt"],
254
+ ignoreDirs: [".nuxt", ".output"],
255
+ keyFiles: ["nuxt.config.ts"],
256
+ explorePatterns: ["pages/**/*.vue", "server/api/**/*.ts"],
257
+ hints: ["File-based routing in pages/, server API in server/api/"],
258
+ },
259
+ {
260
+ id: "express",
261
+ name: "Express.js",
262
+ category: "framework",
263
+ fileMarkers: [],
264
+ dirMarkers: [],
265
+ packageDeps: ["express"],
266
+ ignoreDirs: [],
267
+ keyFiles: ["src/app.ts", "src/app.js", "src/server.ts"],
268
+ explorePatterns: ["**/*route*", "**/*controller*", "**/*middleware*"],
269
+ hints: ["Routes in routes/ or src/routes/"],
270
+ },
271
+ {
272
+ id: "fastify",
273
+ name: "Fastify",
274
+ category: "framework",
275
+ fileMarkers: [],
276
+ dirMarkers: [],
277
+ packageDeps: ["fastify"],
278
+ ignoreDirs: [],
279
+ keyFiles: ["src/app.ts", "src/server.ts"],
280
+ explorePatterns: ["**/*route*", "**/*plugin*"],
281
+ hints: ["Routes as plugins, registered via app.register()"],
282
+ },
283
+ {
284
+ id: "hono",
285
+ name: "Hono",
286
+ category: "framework",
287
+ fileMarkers: [],
288
+ dirMarkers: [],
289
+ packageDeps: ["hono"],
290
+ ignoreDirs: [],
291
+ keyFiles: ["src/index.ts"],
292
+ explorePatterns: ["**/*route*"],
293
+ hints: ["Lightweight HTTP framework, routes via app.get/post"],
294
+ },
295
+ {
296
+ id: "django",
297
+ name: "Django",
298
+ category: "framework",
299
+ fileMarkers: ["manage.py"],
300
+ dirMarkers: [],
301
+ ignoreDirs: ["staticfiles", "media"],
302
+ keyFiles: ["manage.py"],
303
+ explorePatterns: [
304
+ "**/views.py",
305
+ "**/models.py",
306
+ "**/urls.py",
307
+ "**/serializers.py",
308
+ ],
309
+ hints: [
310
+ "Apps in INSTALLED_APPS (settings.py)",
311
+ "URLs in urls.py, views define endpoints, models define DB",
312
+ ],
313
+ },
314
+ {
315
+ id: "fastapi",
316
+ name: "FastAPI",
317
+ category: "framework",
318
+ fileMarkers: [],
319
+ dirMarkers: [],
320
+ packageDeps: ["fastapi"],
321
+ ignoreDirs: [],
322
+ keyFiles: ["main.py", "app/main.py"],
323
+ explorePatterns: ["**/*router*", "**/*route*"],
324
+ hints: ["Routes with @app.get/@app.post, routers in separate files"],
325
+ },
326
+ {
327
+ id: "flask",
328
+ name: "Flask",
329
+ category: "framework",
330
+ fileMarkers: [],
331
+ dirMarkers: [],
332
+ packageDeps: ["flask"],
333
+ ignoreDirs: [],
334
+ keyFiles: ["app.py", "wsgi.py"],
335
+ explorePatterns: ["**/*route*", "**/*view*"],
336
+ hints: ["Routes via @app.route or blueprints"],
337
+ },
338
+ {
339
+ id: "laravel",
340
+ name: "Laravel",
341
+ category: "framework",
342
+ fileMarkers: ["artisan"],
343
+ dirMarkers: ["app/Http/Controllers"],
344
+ ignoreDirs: ["vendor", "storage/framework", "bootstrap/cache"],
345
+ keyFiles: [
346
+ "routes/web.php",
347
+ "routes/api.php",
348
+ "app/Http/Kernel.php",
349
+ ".env.example",
350
+ ],
351
+ explorePatterns: [
352
+ "app/Http/Controllers/**/*.php",
353
+ "app/Models/**/*.php",
354
+ "database/migrations/*.php",
355
+ ],
356
+ hints: [
357
+ "Routes: routes/web.php + routes/api.php",
358
+ "Controllers: app/Http/Controllers, Models: app/Models",
359
+ ],
360
+ },
361
+ {
362
+ id: "rails",
363
+ name: "Ruby on Rails",
364
+ category: "framework",
365
+ fileMarkers: ["config/routes.rb"],
366
+ dirMarkers: ["app/controllers", "app/models"],
367
+ ignoreDirs: ["vendor/bundle", "tmp", "log"],
368
+ keyFiles: ["config/routes.rb", "Gemfile", "config/database.yml"],
369
+ explorePatterns: [
370
+ "app/controllers/**/*.rb",
371
+ "app/models/**/*.rb",
372
+ "db/migrate/*.rb",
373
+ ],
374
+ hints: ["Routes in config/routes.rb, MVC in app/"],
375
+ },
376
+ {
377
+ id: "spring",
378
+ name: "Spring Boot",
379
+ category: "framework",
380
+ fileMarkers: [
381
+ "src/main/resources/application.properties",
382
+ "src/main/resources/application.yml",
383
+ ],
384
+ dirMarkers: [],
385
+ ignoreDirs: ["target", "build"],
386
+ keyFiles: [
387
+ "src/main/resources/application.yml",
388
+ "src/main/resources/application.properties",
389
+ ],
390
+ explorePatterns: [
391
+ "**/*Controller.java",
392
+ "**/*Service.java",
393
+ "**/*Repository.java",
394
+ ],
395
+ hints: ["@RestController, @Service, @Entity, JPA for data access"],
396
+ },
397
+ // ——— Database / ORM ——————————————————————————————————
398
+ {
399
+ id: "prisma",
400
+ name: "Prisma",
401
+ category: "database",
402
+ fileMarkers: ["prisma/schema.prisma"],
403
+ dirMarkers: [],
404
+ packageDeps: ["prisma", "@prisma/client"],
405
+ ignoreDirs: [],
406
+ keyFiles: ["prisma/schema.prisma"],
407
+ explorePatterns: ["prisma/migrations/**/migration.sql"],
408
+ hints: ["All models in schema.prisma, migrations in prisma/migrations/"],
409
+ },
410
+ {
411
+ id: "typeorm",
412
+ name: "TypeORM",
413
+ category: "database",
414
+ fileMarkers: ["ormconfig.json", "ormconfig.ts"],
415
+ dirMarkers: [],
416
+ packageDeps: ["typeorm"],
417
+ ignoreDirs: [],
418
+ keyFiles: ["ormconfig.json", "ormconfig.ts"],
419
+ explorePatterns: ["**/*.entity.ts", "**/migration/*.ts"],
420
+ hints: ["Entities with @Entity, migrations in migrations/"],
421
+ },
422
+ {
423
+ id: "drizzle",
424
+ name: "Drizzle ORM",
425
+ category: "database",
426
+ fileMarkers: ["drizzle.config.ts"],
427
+ dirMarkers: [],
428
+ packageDeps: ["drizzle-orm"],
429
+ ignoreDirs: [],
430
+ keyFiles: ["drizzle.config.ts"],
431
+ explorePatterns: ["**/*schema*", "**/drizzle/**"],
432
+ hints: ["Schema in schema files, migrations in drizzle/"],
433
+ },
434
+ {
435
+ id: "sequelize",
436
+ name: "Sequelize",
437
+ category: "database",
438
+ fileMarkers: [".sequelizerc"],
439
+ dirMarkers: [],
440
+ packageDeps: ["sequelize"],
441
+ ignoreDirs: [],
442
+ keyFiles: [".sequelizerc"],
443
+ explorePatterns: ["**/models/**", "**/migrations/**"],
444
+ hints: ["Models in models/, migrations in migrations/"],
445
+ },
446
+ {
447
+ id: "mongoose",
448
+ name: "Mongoose",
449
+ category: "database",
450
+ fileMarkers: [],
451
+ dirMarkers: [],
452
+ packageDeps: ["mongoose"],
453
+ ignoreDirs: [],
454
+ keyFiles: [],
455
+ explorePatterns: ["**/*schema*", "**/*model*"],
456
+ hints: ["MongoDB schemas, usually in schemas/ or models/"],
457
+ },
458
+ // ——— Infrastructure ——————————————————————————————————
459
+ {
460
+ id: "docker",
461
+ name: "Docker",
462
+ category: "infra",
463
+ fileMarkers: [
464
+ "Dockerfile",
465
+ "docker-compose.yml",
466
+ "docker-compose.yaml",
467
+ "compose.yml",
468
+ "compose.yaml",
469
+ ],
470
+ dirMarkers: [],
471
+ ignoreDirs: [],
472
+ keyFiles: [
473
+ "Dockerfile",
474
+ "docker-compose.yml",
475
+ "docker-compose.yaml",
476
+ "compose.yml",
477
+ "compose.yaml",
478
+ ".dockerignore",
479
+ ],
480
+ explorePatterns: ["**/Dockerfile*"],
481
+ hints: ["docker-compose defines services, ports, volumes, networks"],
482
+ },
483
+ {
484
+ id: "kubernetes",
485
+ name: "Kubernetes",
486
+ category: "infra",
487
+ fileMarkers: ["kustomization.yaml", "skaffold.yaml"],
488
+ dirMarkers: ["k8s", "kubernetes", "manifests"],
489
+ ignoreDirs: [],
490
+ keyFiles: ["kustomization.yaml"],
491
+ explorePatterns: ["k8s/**/*.yaml", "kubernetes/**/*.yaml"],
492
+ hints: ["Manifests: deployments, services, configmaps, secrets"],
493
+ },
494
+ {
495
+ id: "terraform",
496
+ name: "Terraform",
497
+ category: "infra",
498
+ fileMarkers: ["main.tf"],
499
+ dirMarkers: [],
500
+ ignoreDirs: [".terraform"],
501
+ keyFiles: ["main.tf", "variables.tf", "outputs.tf"],
502
+ explorePatterns: ["**/*.tf"],
503
+ hints: ["main.tf=resources, variables.tf=inputs, outputs.tf=exports"],
504
+ },
505
+ // ——— Testing —————————————————————————————————————————
506
+ {
507
+ id: "jest",
508
+ name: "Jest",
509
+ category: "testing",
510
+ fileMarkers: ["jest.config.ts", "jest.config.js", "jest.config.mjs"],
511
+ dirMarkers: [],
512
+ packageDeps: ["jest"],
513
+ ignoreDirs: [],
514
+ keyFiles: ["jest.config.ts", "jest.config.js"],
515
+ explorePatterns: ["**/*.test.ts", "**/*.spec.ts"],
516
+ hints: ["Tests in *.test.ts / *.spec.ts"],
517
+ },
518
+ {
519
+ id: "vitest",
520
+ name: "Vitest",
521
+ category: "testing",
522
+ fileMarkers: ["vitest.config.ts", "vitest.config.js"],
523
+ dirMarkers: [],
524
+ packageDeps: ["vitest"],
525
+ ignoreDirs: [],
526
+ keyFiles: ["vitest.config.ts"],
527
+ explorePatterns: ["**/*.test.ts", "**/*.spec.ts"],
528
+ hints: ["Tests in *.test.ts / *.spec.ts"],
529
+ },
530
+ {
531
+ id: "pytest",
532
+ name: "pytest",
533
+ category: "testing",
534
+ fileMarkers: ["pytest.ini", "conftest.py"],
535
+ dirMarkers: [],
536
+ ignoreDirs: [".pytest_cache"],
537
+ keyFiles: ["pytest.ini", "conftest.py"],
538
+ explorePatterns: ["**/test_*.py", "**/*_test.py"],
539
+ hints: ["Tests in test_*.py, fixtures in conftest.py"],
540
+ },
541
+ {
542
+ id: "playwright",
543
+ name: "Playwright",
544
+ category: "testing",
545
+ fileMarkers: ["playwright.config.ts", "playwright.config.js"],
546
+ dirMarkers: [],
547
+ packageDeps: ["@playwright/test"],
548
+ ignoreDirs: ["test-results", "playwright-report"],
549
+ keyFiles: ["playwright.config.ts"],
550
+ explorePatterns: ["**/*.spec.ts"],
551
+ hints: ["E2E tests, config in playwright.config.ts"],
552
+ },
553
+ // ——— Build tools —————————————————————————————————————
554
+ {
555
+ id: "webpack",
556
+ name: "Webpack",
557
+ category: "build",
558
+ fileMarkers: ["webpack.config.js", "webpack.config.ts"],
559
+ dirMarkers: [],
560
+ packageDeps: ["webpack"],
561
+ ignoreDirs: [],
562
+ keyFiles: ["webpack.config.js", "webpack.config.ts"],
563
+ explorePatterns: [],
564
+ hints: [],
565
+ },
566
+ {
567
+ id: "vite",
568
+ name: "Vite",
569
+ category: "build",
570
+ fileMarkers: ["vite.config.ts", "vite.config.js"],
571
+ dirMarkers: [],
572
+ packageDeps: ["vite"],
573
+ ignoreDirs: [],
574
+ keyFiles: ["vite.config.ts", "vite.config.js"],
575
+ explorePatterns: [],
576
+ hints: [],
577
+ },
578
+ {
579
+ id: "esbuild",
580
+ name: "esbuild",
581
+ category: "build",
582
+ fileMarkers: [],
583
+ dirMarkers: [],
584
+ packageDeps: ["esbuild"],
585
+ ignoreDirs: [],
586
+ keyFiles: [],
587
+ explorePatterns: [],
588
+ hints: [],
589
+ },
590
+ ];
591
+ /* ═══════════════════════════════════════════════════════════════
592
+ MONOREPO RULES
593
+ ═══════════════════════════════════════════════════════════════ */
594
+ exports.MONOREPO_RULES = [
595
+ {
596
+ id: "nx",
597
+ name: "NX",
598
+ fileMarkers: ["nx.json"],
599
+ workspaceDirs: ["apps", "libs", "packages"],
600
+ ignoreDirs: [".nx", "node_modules"],
601
+ hints: [
602
+ "project.json in each sub-project defines targets (build/serve/test)",
603
+ "nx graph shows dependency graph",
604
+ ],
605
+ },
606
+ {
607
+ id: "turborepo",
608
+ name: "Turborepo",
609
+ fileMarkers: ["turbo.json"],
610
+ workspaceDirs: ["apps", "packages"],
611
+ ignoreDirs: [".turbo", "node_modules"],
612
+ hints: ["Pipeline in turbo.json, packages in packages/ and apps/"],
613
+ },
614
+ {
615
+ id: "lerna",
616
+ name: "Lerna",
617
+ fileMarkers: ["lerna.json"],
618
+ workspaceDirs: ["packages"],
619
+ ignoreDirs: ["node_modules"],
620
+ hints: ["Packages in packages/, version mgmt via lerna.json"],
621
+ },
622
+ {
623
+ id: "pnpm-workspaces",
624
+ name: "pnpm workspaces",
625
+ fileMarkers: ["pnpm-workspace.yaml"],
626
+ workspaceDirs: ["packages", "apps", "libs"],
627
+ ignoreDirs: ["node_modules"],
628
+ hints: ["Workspace members defined in pnpm-workspace.yaml"],
629
+ },
630
+ {
631
+ id: "go-workspaces",
632
+ name: "Go workspaces",
633
+ fileMarkers: ["go.work"],
634
+ workspaceDirs: ["cmd", "internal", "pkg"],
635
+ ignoreDirs: ["vendor"],
636
+ hints: ["Workspace modules in go.work"],
637
+ },
638
+ ];
639
+ /** Dirs always excluded regardless of detected tech. */
640
+ const ALWAYS_IGNORE = new Set([".git", "coverage", ".idea", ".vscode"]);
641
+ /* ═══════════════════════════════════════════════════════════════
642
+ TOOL
643
+ ═══════════════════════════════════════════════════════════════ */
644
+ class ProjectScannerTool extends core_1.ToolBase {
645
+ rootDir;
646
+ name = "projectScanner";
647
+ readonly = true;
648
+ description = "Fast structural scan of a project or monorepo. " +
649
+ "Detects languages, frameworks, databases, infrastructure, testing, build tools, " +
650
+ "and monorepo layout including sub-projects. " +
651
+ "Returns compact guidance: dirs to ignore, key files to read, " +
652
+ "patterns for find_files, and technology-specific hints. " +
653
+ "Use FIRST before any deep file exploration.";
654
+ constructor(rootDir) {
655
+ super(zod_1.z.object({
656
+ path: zod_1.z
657
+ .string()
658
+ .optional()
659
+ .describe("Path to scan, relative to project root. Defaults to root."),
660
+ }));
661
+ this.rootDir = rootDir;
662
+ }
663
+ async run(input, _ctx) {
664
+ const relPath = input.path || ".";
665
+ const scanDir = (0, core_1.resolveSafePath)(this.rootDir, relPath);
666
+ if (!scanDir) {
667
+ return { success: false, error: "Path traversal not allowed." };
668
+ }
669
+ if (!fs.existsSync(scanDir) || !fs.statSync(scanDir).isDirectory()) {
670
+ return { success: false, error: `Not a directory: ${relPath}` };
671
+ }
672
+ const result = this.scan(scanDir);
673
+ return { success: true, output: this.format(result, scanDir) };
674
+ }
675
+ /* ——— Scanning ——————————————————————————————————————— */
676
+ scan(dir) {
677
+ const rootDeps = this.readDeps(dir);
678
+ const rootTechs = this.detectTechs(dir, rootDeps);
679
+ // Monorepo detection
680
+ let monorepo = null;
681
+ for (const rule of exports.MONOREPO_RULES) {
682
+ if (rule.fileMarkers.some((f) => fs.existsSync(path.join(dir, f)))) {
683
+ monorepo = rule;
684
+ break;
685
+ }
686
+ }
687
+ // Yarn/npm workspaces (package.json "workspaces" field)
688
+ const yarnWorkspaceDirs = [];
689
+ const pkg = this.readPackageJson(dir);
690
+ if (pkg?.workspaces) {
691
+ const patterns = Array.isArray(pkg.workspaces)
692
+ ? pkg.workspaces
693
+ : pkg.workspaces.packages || [];
694
+ for (const pattern of patterns) {
695
+ const prefix = pattern.split(/[*{]/)[0].replace(/\/$/, "");
696
+ if (prefix && !yarnWorkspaceDirs.includes(prefix)) {
697
+ yarnWorkspaceDirs.push(prefix);
698
+ }
699
+ }
700
+ }
701
+ // Collect workspace dirs to scan
702
+ const wsDirs = new Set();
703
+ if (monorepo) {
704
+ for (const d of monorepo.workspaceDirs)
705
+ wsDirs.add(d);
706
+ }
707
+ for (const d of yarnWorkspaceDirs)
708
+ wsDirs.add(d);
709
+ // Detect sub-projects
710
+ const subProjects = [];
711
+ for (const wsDir of wsDirs) {
712
+ this.scanWorkspaceDir(dir, wsDir, rootDeps, subProjects);
713
+ }
714
+ // No monorepo tool detected — check for plain multi-project layout
715
+ if (!monorepo && yarnWorkspaceDirs.length === 0 && subProjects.length === 0) {
716
+ this.detectPlainSubProjects(dir, subProjects);
717
+ }
718
+ return { monorepo, yarnWorkspaceDirs, rootTechs, subProjects };
719
+ }
720
+ scanWorkspaceDir(rootDir, wsDir, rootDeps, out) {
721
+ const full = path.join(rootDir, wsDir);
722
+ if (!fs.existsSync(full) || !fs.statSync(full).isDirectory())
723
+ return;
724
+ let entries;
725
+ try {
726
+ entries = fs.readdirSync(full, { withFileTypes: true });
727
+ }
728
+ catch {
729
+ return;
730
+ }
731
+ for (const entry of entries) {
732
+ if (!entry.isDirectory() || entry.name.startsWith("."))
733
+ continue;
734
+ const projDir = path.join(full, entry.name);
735
+ const projDeps = this.readDeps(projDir, rootDeps);
736
+ const techs = this.detectTechs(projDir, projDeps);
737
+ if (techs.length > 0) {
738
+ out.push({ relPath: path.relative(rootDir, projDir), techs });
739
+ }
740
+ }
741
+ }
742
+ /**
743
+ * Fallback: scan top-level dirs that have their own config file
744
+ * (looks like independent projects grouped in a directory).
745
+ */
746
+ detectPlainSubProjects(dir, out) {
747
+ const PROJECT_CONFIGS = [
748
+ "package.json",
749
+ "Cargo.toml",
750
+ "go.mod",
751
+ "pyproject.toml",
752
+ "composer.json",
753
+ "Gemfile",
754
+ "pom.xml",
755
+ "build.gradle",
756
+ ];
757
+ let entries;
758
+ try {
759
+ entries = fs.readdirSync(dir, { withFileTypes: true });
760
+ }
761
+ catch {
762
+ return;
763
+ }
764
+ for (const entry of entries) {
765
+ if (!entry.isDirectory() || entry.name.startsWith("."))
766
+ continue;
767
+ if (ALWAYS_IGNORE.has(entry.name))
768
+ continue;
769
+ const subDir = path.join(dir, entry.name);
770
+ const hasOwnConfig = PROJECT_CONFIGS.some((f) => fs.existsSync(path.join(subDir, f)));
771
+ if (!hasOwnConfig)
772
+ continue;
773
+ const subDeps = this.readDeps(subDir);
774
+ const techs = this.detectTechs(subDir, subDeps);
775
+ if (techs.length > 0) {
776
+ out.push({ relPath: entry.name, techs });
777
+ }
778
+ }
779
+ }
780
+ /* ——— Tech detection ———————————————————————————————— */
781
+ detectTechs(dir, deps) {
782
+ const detected = [];
783
+ for (const rule of exports.TECH_RULES) {
784
+ const evidence = [];
785
+ for (const f of rule.fileMarkers) {
786
+ if (fs.existsSync(path.join(dir, f)))
787
+ evidence.push(f);
788
+ }
789
+ for (const d of rule.dirMarkers) {
790
+ const full = path.join(dir, d);
791
+ try {
792
+ if (fs.existsSync(full) && fs.statSync(full).isDirectory()) {
793
+ evidence.push(d + "/");
794
+ }
795
+ }
796
+ catch {
797
+ /* permission error etc. */
798
+ }
799
+ }
800
+ if (rule.packageDeps) {
801
+ for (const dep of rule.packageDeps) {
802
+ if (deps.has(dep))
803
+ evidence.push(`dep:${dep}`);
804
+ }
805
+ }
806
+ if (evidence.length > 0) {
807
+ detected.push({ rule, evidence });
808
+ }
809
+ }
810
+ // Special: .NET detection via extensions (no fixed filenames)
811
+ this.detectByExtension(dir, detected);
812
+ return detected;
813
+ }
814
+ detectByExtension(dir, detected) {
815
+ // Skip if .NET already detected
816
+ if (detected.some((d) => d.rule.id === "dotnet"))
817
+ return;
818
+ let entries;
819
+ try {
820
+ entries = fs.readdirSync(dir);
821
+ }
822
+ catch {
823
+ return;
824
+ }
825
+ const hasSln = entries.some((e) => e.endsWith(".sln"));
826
+ const hasCsproj = entries.some((e) => e.endsWith(".csproj"));
827
+ if (hasSln || hasCsproj) {
828
+ const rule = exports.TECH_RULES.find((r) => r.id === "dotnet");
829
+ const evidence = hasSln ? ["*.sln"] : ["*.csproj"];
830
+ detected.push({ rule, evidence });
831
+ }
832
+ }
833
+ /* ——— Dependency reading ————————————————————————————— */
834
+ readPackageJson(dir) {
835
+ const p = path.join(dir, "package.json");
836
+ try {
837
+ if (fs.existsSync(p)) {
838
+ return JSON.parse(fs.readFileSync(p, "utf-8"));
839
+ }
840
+ }
841
+ catch {
842
+ /* malformed JSON */
843
+ }
844
+ return null;
845
+ }
846
+ readDeps(dir, fallback) {
847
+ const deps = new Set(fallback ?? []);
848
+ // package.json
849
+ const pkg = this.readPackageJson(dir);
850
+ if (pkg) {
851
+ for (const section of [
852
+ "dependencies",
853
+ "devDependencies",
854
+ "peerDependencies",
855
+ ]) {
856
+ if (pkg[section]) {
857
+ for (const name of Object.keys(pkg[section]))
858
+ deps.add(name);
859
+ }
860
+ }
861
+ }
862
+ // Python: read requirements.txt package names
863
+ const reqTxt = path.join(dir, "requirements.txt");
864
+ try {
865
+ if (fs.existsSync(reqTxt)) {
866
+ const lines = fs.readFileSync(reqTxt, "utf-8").split("\n");
867
+ for (const line of lines) {
868
+ const trimmed = line.trim();
869
+ if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith("-"))
870
+ continue;
871
+ const name = trimmed.split(/[>=<!~\[;]/)[0].trim().toLowerCase();
872
+ if (name)
873
+ deps.add(name);
874
+ }
875
+ }
876
+ }
877
+ catch {
878
+ /* read error */
879
+ }
880
+ return deps;
881
+ }
882
+ /* ——— Output formatting ————————————————————————————— */
883
+ format(result, scanDir) {
884
+ const lines = [];
885
+ const hasSubProjects = result.subProjects.length > 0;
886
+ // Structure
887
+ if (result.monorepo) {
888
+ lines.push(`Structure: monorepo (${result.monorepo.name})`);
889
+ }
890
+ else if (result.yarnWorkspaceDirs.length > 0) {
891
+ lines.push(`Structure: monorepo (npm/yarn workspaces)`);
892
+ }
893
+ else if (hasSubProjects) {
894
+ lines.push(`Structure: multi-project`);
895
+ }
896
+ else {
897
+ lines.push(`Structure: single project`);
898
+ }
899
+ // Aggregate ignore dirs
900
+ const ignoreSet = new Set(ALWAYS_IGNORE);
901
+ const allTechs = [...result.rootTechs];
902
+ for (const sp of result.subProjects) {
903
+ for (const t of sp.techs)
904
+ allTechs.push(t);
905
+ }
906
+ if (result.monorepo) {
907
+ for (const d of result.monorepo.ignoreDirs)
908
+ ignoreSet.add(d);
909
+ }
910
+ for (const t of allTechs) {
911
+ for (const d of t.rule.ignoreDirs)
912
+ ignoreSet.add(d);
913
+ }
914
+ lines.push(`Ignore: ${[...ignoreSet].sort().join(", ")}`);
915
+ lines.push("");
916
+ // Root technologies
917
+ if (result.rootTechs.length > 0) {
918
+ const label = hasSubProjects ? "Root" : "Detected";
919
+ lines.push(this.formatSection(label, result.rootTechs, scanDir));
920
+ }
921
+ // Sub-projects
922
+ for (const sp of result.subProjects) {
923
+ const spDir = path.join(scanDir, sp.relPath);
924
+ lines.push(this.formatSection(sp.relPath, sp.techs, spDir));
925
+ }
926
+ // Monorepo-specific hints
927
+ if (result.monorepo && result.monorepo.hints.length > 0) {
928
+ lines.push("Monorepo:");
929
+ for (const h of result.monorepo.hints)
930
+ lines.push(` ${h}`);
931
+ }
932
+ return lines.join("\n").trimEnd();
933
+ }
934
+ formatSection(label, techs, dir) {
935
+ const lines = [];
936
+ // Tech names
937
+ const names = techs.map((t) => t.rule.name).join(", ");
938
+ lines.push(`${label}: ${names}`);
939
+ // Key files (only those that actually exist on disk)
940
+ const keyFiles = [];
941
+ for (const t of techs) {
942
+ for (const f of t.rule.keyFiles) {
943
+ if (!keyFiles.includes(f) && fs.existsSync(path.join(dir, f))) {
944
+ keyFiles.push(f);
945
+ }
946
+ }
947
+ }
948
+ if (keyFiles.length > 0) {
949
+ lines.push(` read: ${keyFiles.join(", ")}`);
950
+ }
951
+ // Explore patterns (deduplicated)
952
+ const patterns = [];
953
+ for (const t of techs) {
954
+ for (const p of t.rule.explorePatterns) {
955
+ if (!patterns.includes(p))
956
+ patterns.push(p);
957
+ }
958
+ }
959
+ if (patterns.length > 0) {
960
+ lines.push(` find: ${patterns.join(", ")}`);
961
+ }
962
+ // Hints — only from framework, database, and infra categories (skip generic language/build hints)
963
+ const hints = [];
964
+ for (const t of techs) {
965
+ if (["framework", "database", "infra"].includes(t.rule.category)) {
966
+ for (const h of t.rule.hints)
967
+ hints.push(h);
968
+ }
969
+ }
970
+ if (hints.length > 0) {
971
+ lines.push(` hints: ${hints.join(" · ")}`);
972
+ }
973
+ lines.push("");
974
+ return lines.join("\n");
975
+ }
976
+ }
977
+ exports.ProjectScannerTool = ProjectScannerTool;
978
+ //# sourceMappingURL=project-scanner.tool.js.map