codebase-onboarder 0.6.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (526) hide show
  1. package/README.md +284 -53
  2. package/bin/build-if-source.js +23 -0
  3. package/bin/onboarder.js +0 -0
  4. package/cli/agent/command.d.ts +71 -0
  5. package/cli/agent/command.js +177 -0
  6. package/cli/agent/command.js.map +1 -0
  7. package/cli/agent/config.d.ts +31 -0
  8. package/cli/agent/config.js +98 -0
  9. package/cli/agent/config.js.map +1 -0
  10. package/cli/agent/contracts.d.ts +77 -0
  11. package/cli/agent/contracts.js +2 -0
  12. package/cli/agent/contracts.js.map +1 -0
  13. package/cli/agent/files.d.ts +19 -0
  14. package/cli/agent/files.js +109 -0
  15. package/cli/agent/files.js.map +1 -0
  16. package/cli/agent/gitSource.d.ts +18 -0
  17. package/cli/agent/gitSource.js +69 -0
  18. package/cli/agent/gitSource.js.map +1 -0
  19. package/cli/agent/github.d.ts +21 -0
  20. package/cli/agent/github.js +94 -0
  21. package/cli/agent/github.js.map +1 -0
  22. package/cli/agent/mcp.d.ts +15 -0
  23. package/cli/agent/mcp.js +78 -0
  24. package/cli/agent/mcp.js.map +1 -0
  25. package/cli/agent/process.d.ts +18 -0
  26. package/cli/agent/process.js +118 -0
  27. package/cli/agent/process.js.map +1 -0
  28. package/cli/agent/protocol.d.ts +3 -0
  29. package/cli/agent/protocol.js +26 -0
  30. package/cli/agent/protocol.js.map +1 -0
  31. package/cli/agent/runner.d.ts +34 -0
  32. package/cli/agent/runner.js +152 -0
  33. package/cli/agent/runner.js.map +1 -0
  34. package/cli/agent/stdio.d.ts +1 -0
  35. package/cli/agent/stdio.js +62 -0
  36. package/cli/agent/stdio.js.map +1 -0
  37. package/cli/agent/tools.d.ts +7 -0
  38. package/cli/agent/tools.js +201 -0
  39. package/cli/agent/tools.js.map +1 -0
  40. package/cli/chat/app.d.ts +16 -0
  41. package/cli/chat/app.js +345 -0
  42. package/cli/chat/app.js.map +1 -0
  43. package/cli/chat/commands.d.ts +11 -0
  44. package/cli/chat/commands.js +120 -0
  45. package/cli/chat/commands.js.map +1 -0
  46. package/cli/chat/composer.d.ts +75 -0
  47. package/cli/chat/composer.js +467 -0
  48. package/cli/chat/composer.js.map +1 -0
  49. package/cli/chat/controller.d.ts +60 -0
  50. package/cli/chat/controller.js +393 -0
  51. package/cli/chat/controller.js.map +1 -0
  52. package/cli/chat/logo.d.ts +3 -0
  53. package/cli/chat/logo.js +14 -0
  54. package/cli/chat/logo.js.map +1 -0
  55. package/cli/chat/models.d.ts +18 -0
  56. package/cli/chat/models.js +88 -0
  57. package/cli/chat/models.js.map +1 -0
  58. package/cli/chat/profile.d.ts +5 -0
  59. package/cli/chat/profile.js +98 -0
  60. package/cli/chat/profile.js.map +1 -0
  61. package/cli/chat/render.d.ts +40 -0
  62. package/cli/chat/render.js +259 -0
  63. package/cli/chat/render.js.map +1 -0
  64. package/cli/chat/screen.d.ts +26 -0
  65. package/cli/chat/screen.js +117 -0
  66. package/cli/chat/screen.js.map +1 -0
  67. package/cli/chat/source.d.ts +29 -0
  68. package/cli/chat/source.js +116 -0
  69. package/cli/chat/source.js.map +1 -0
  70. package/cli/chat/store.d.ts +43 -0
  71. package/cli/chat/store.js +94 -0
  72. package/cli/chat/store.js.map +1 -0
  73. package/cli/chat/text.d.ts +4 -0
  74. package/cli/chat/text.js +27 -0
  75. package/cli/chat/text.js.map +1 -0
  76. package/cli/commands.d.ts +26 -0
  77. package/cli/commands.js +836 -811
  78. package/cli/commands.js.map +1 -0
  79. package/cli/explorer/advanced.d.ts +14 -0
  80. package/cli/explorer/advanced.js +321 -329
  81. package/cli/explorer/advanced.js.map +1 -0
  82. package/cli/explorer/app.d.ts +2 -0
  83. package/cli/explorer/app.js +404 -314
  84. package/cli/explorer/app.js.map +1 -0
  85. package/cli/explorer/assistant.d.ts +9 -0
  86. package/cli/explorer/assistant.js +58 -0
  87. package/cli/explorer/assistant.js.map +1 -0
  88. package/cli/explorer/commands.d.ts +17 -0
  89. package/cli/explorer/commands.js +373 -302
  90. package/cli/explorer/commands.js.map +1 -0
  91. package/cli/explorer/featureViews.d.ts +124 -0
  92. package/cli/explorer/featureViews.js +179 -0
  93. package/cli/explorer/featureViews.js.map +1 -0
  94. package/cli/explorer/github.d.ts +21 -0
  95. package/cli/explorer/github.js +42 -44
  96. package/cli/explorer/github.js.map +1 -0
  97. package/cli/explorer/graphs.d.ts +7 -0
  98. package/cli/explorer/graphs.js +90 -95
  99. package/cli/explorer/graphs.js.map +1 -0
  100. package/cli/explorer/picker.d.ts +22 -0
  101. package/cli/explorer/picker.js +150 -0
  102. package/cli/explorer/picker.js.map +1 -0
  103. package/cli/explorer/report.d.ts +85 -0
  104. package/cli/explorer/report.js +60 -0
  105. package/cli/explorer/report.js.map +1 -0
  106. package/cli/explorer/session.d.ts +449 -0
  107. package/cli/explorer/session.js +143 -144
  108. package/cli/explorer/session.js.map +1 -0
  109. package/cli/explorer/views.d.ts +19 -0
  110. package/cli/explorer/views.js +465 -482
  111. package/cli/explorer/views.js.map +1 -0
  112. package/cli/explorer/wrap.d.ts +1 -0
  113. package/cli/explorer/wrap.js +28 -44
  114. package/cli/explorer/wrap.js.map +1 -0
  115. package/cli/main.d.ts +1 -0
  116. package/cli/main.js +251 -164
  117. package/cli/main.js.map +1 -0
  118. package/cli/prompt.d.ts +5 -0
  119. package/cli/prompt.js +84 -80
  120. package/cli/prompt.js.map +1 -0
  121. package/cli/scanOptions.d.ts +2 -0
  122. package/cli/scanOptions.js +11 -0
  123. package/cli/scanOptions.js.map +1 -0
  124. package/cli/ui.d.ts +33 -0
  125. package/cli/ui.js +35 -44
  126. package/cli/ui.js.map +1 -0
  127. package/cli/wizard.d.ts +187 -0
  128. package/cli/wizard.js +304 -284
  129. package/cli/wizard.js.map +1 -0
  130. package/docs/HERMES_RESEARCH.md +51 -0
  131. package/package.json +16 -4
  132. package/public/app.d.ts +1 -0
  133. package/public/app.js +1133 -1011
  134. package/public/app.js.map +1 -0
  135. package/public/assets/onboarder-mark.svg +11 -0
  136. package/public/browser.d.ts +71 -0
  137. package/public/browser.js +2 -0
  138. package/public/browser.js.map +1 -0
  139. package/public/index.html +54 -20
  140. package/public/js/about.d.ts +6 -0
  141. package/public/js/about.js +152 -172
  142. package/public/js/about.js.map +1 -0
  143. package/public/js/aiDraft.d.ts +4 -0
  144. package/public/js/aiDraft.js +166 -125
  145. package/public/js/aiDraft.js.map +1 -0
  146. package/public/js/analysisPanel.d.ts +7 -0
  147. package/public/js/analysisPanel.js +166 -166
  148. package/public/js/analysisPanel.js.map +1 -0
  149. package/public/js/analysisReport.d.ts +38 -0
  150. package/public/js/analysisReport.js +105 -110
  151. package/public/js/analysisReport.js.map +1 -0
  152. package/public/js/api.d.ts +29 -0
  153. package/public/js/api.js +198 -166
  154. package/public/js/api.js.map +1 -0
  155. package/public/js/atlas.d.ts +6 -0
  156. package/public/js/atlas.js +50 -58
  157. package/public/js/atlas.js.map +1 -0
  158. package/public/js/blameView.d.ts +2 -0
  159. package/public/js/blameView.js +36 -37
  160. package/public/js/blameView.js.map +1 -0
  161. package/public/js/codeTab.d.ts +3 -0
  162. package/public/js/codeTab.js +175 -180
  163. package/public/js/codeTab.js.map +1 -0
  164. package/public/js/codeViewer.d.ts +5 -0
  165. package/public/js/codeViewer.js +162 -150
  166. package/public/js/codeViewer.js.map +1 -0
  167. package/public/js/components/FileChip.d.ts +9 -0
  168. package/public/js/components/FileChip.js +45 -49
  169. package/public/js/components/FileChip.js.map +1 -0
  170. package/public/js/components/MetricSparkline.d.ts +7 -0
  171. package/public/js/components/MetricSparkline.js +35 -44
  172. package/public/js/components/MetricSparkline.js.map +1 -0
  173. package/public/js/components/RiskBadge.d.ts +9 -0
  174. package/public/js/components/RiskBadge.js +55 -63
  175. package/public/js/components/RiskBadge.js.map +1 -0
  176. package/public/js/deepAnalysisView.d.ts +99 -0
  177. package/public/js/deepAnalysisView.js +282 -302
  178. package/public/js/deepAnalysisView.js.map +1 -0
  179. package/public/js/diagramPane.d.ts +9 -0
  180. package/public/js/diagramPane.js +138 -135
  181. package/public/js/diagramPane.js.map +1 -0
  182. package/public/js/diffView.d.ts +6 -0
  183. package/public/js/diffView.js +222 -209
  184. package/public/js/diffView.js.map +1 -0
  185. package/public/js/docsView.d.ts +2 -0
  186. package/public/js/docsView.js +441 -442
  187. package/public/js/docsView.js.map +1 -0
  188. package/public/js/dom.d.ts +197 -0
  189. package/public/js/dom.js +5 -0
  190. package/public/js/dom.js.map +1 -0
  191. package/public/js/fileSourceBrowser.d.ts +5 -0
  192. package/public/js/fileSourceBrowser.js +33 -41
  193. package/public/js/fileSourceBrowser.js.map +1 -0
  194. package/public/js/flameGraph.d.ts +5 -0
  195. package/public/js/flameGraph.js +62 -72
  196. package/public/js/flameGraph.js.map +1 -0
  197. package/public/js/forceGraph.d.ts +10 -0
  198. package/public/js/forceGraph.js +581 -556
  199. package/public/js/forceGraph.js.map +1 -0
  200. package/public/js/heatmap.d.ts +4 -0
  201. package/public/js/heatmap.js +142 -164
  202. package/public/js/heatmap.js.map +1 -0
  203. package/public/js/highlight.d.ts +2 -0
  204. package/public/js/highlight.js +116 -107
  205. package/public/js/highlight.js.map +1 -0
  206. package/public/js/html.d.ts +2 -0
  207. package/public/js/html.js +14 -44
  208. package/public/js/html.js.map +1 -0
  209. package/public/js/insightsView.d.ts +5 -0
  210. package/public/js/insightsView.js +93 -111
  211. package/public/js/insightsView.js.map +1 -0
  212. package/public/js/inspector.d.ts +37 -0
  213. package/public/js/inspector.js +416 -445
  214. package/public/js/inspector.js.map +1 -0
  215. package/public/js/llm.d.ts +115 -0
  216. package/public/js/llm.js +246 -278
  217. package/public/js/llm.js.map +1 -0
  218. package/public/js/mapView.d.ts +3 -0
  219. package/public/js/mapView.js +121 -120
  220. package/public/js/mapView.js.map +1 -0
  221. package/public/js/markdown.d.ts +3 -0
  222. package/public/js/markdown.js +84 -91
  223. package/public/js/markdown.js.map +1 -0
  224. package/public/js/mindmap.d.ts +32 -0
  225. package/public/js/mindmap.js +244 -259
  226. package/public/js/mindmap.js.map +1 -0
  227. package/public/js/mobilePanels.d.ts +5 -0
  228. package/public/js/mobilePanels.js +50 -0
  229. package/public/js/mobilePanels.js.map +1 -0
  230. package/public/js/repoFiles.d.ts +12 -0
  231. package/public/js/repoFiles.js +29 -28
  232. package/public/js/repoFiles.js.map +1 -0
  233. package/public/js/reviewView.d.ts +28 -0
  234. package/public/js/reviewView.js +256 -0
  235. package/public/js/reviewView.js.map +1 -0
  236. package/public/js/sbomView.d.ts +3 -0
  237. package/public/js/sbomView.js +59 -67
  238. package/public/js/sbomView.js.map +1 -0
  239. package/public/js/scanCache.d.ts +16 -0
  240. package/public/js/scanCache.js +67 -65
  241. package/public/js/scanCache.js.map +1 -0
  242. package/public/js/search.d.ts +7 -0
  243. package/public/js/search.js +868 -800
  244. package/public/js/search.js.map +1 -0
  245. package/public/js/searchLocal.d.ts +42 -0
  246. package/public/js/searchLocal.js +87 -0
  247. package/public/js/searchLocal.js.map +1 -0
  248. package/public/js/serverSettings.d.ts +5 -0
  249. package/public/js/serverSettings.js +153 -164
  250. package/public/js/serverSettings.js.map +1 -0
  251. package/public/js/state.d.ts +798 -0
  252. package/public/js/state.js +114 -122
  253. package/public/js/state.js.map +1 -0
  254. package/public/js/tour.d.ts +6 -0
  255. package/public/js/tour.js +5 -7
  256. package/public/js/tour.js.map +1 -0
  257. package/public/js/transitions.d.ts +2 -0
  258. package/public/js/transitions.js +9 -10
  259. package/public/js/transitions.js.map +1 -0
  260. package/public/js/tree.d.ts +12 -0
  261. package/public/js/tree.js +157 -154
  262. package/public/js/tree.js.map +1 -0
  263. package/public/js/workflowsView.d.ts +3 -0
  264. package/public/js/workflowsView.js +15 -22
  265. package/public/js/workflowsView.js.map +1 -0
  266. package/public/search.css +495 -0
  267. package/public/styles.css +188 -346
  268. package/public/workbench.css +166 -0
  269. package/server/apiAuth.d.ts +3 -0
  270. package/server/apiAuth.js +18 -20
  271. package/server/apiAuth.js.map +1 -0
  272. package/server/apiDiff.d.ts +2 -0
  273. package/server/apiDiff.js +20 -18
  274. package/server/apiDiff.js.map +1 -0
  275. package/server/apiDocs.d.ts +2 -0
  276. package/server/apiDocs.js +38 -40
  277. package/server/apiDocs.js.map +1 -0
  278. package/server/apiFile.d.ts +1 -0
  279. package/server/apiFile.js +14 -17
  280. package/server/apiFile.js.map +1 -0
  281. package/server/apiGitBlame.d.ts +2 -0
  282. package/server/apiGitBlame.js +50 -51
  283. package/server/apiGitBlame.js.map +1 -0
  284. package/server/apiMcp.d.ts +4 -0
  285. package/server/apiMcp.js +64 -66
  286. package/server/apiMcp.js.map +1 -0
  287. package/server/apiReview.d.ts +2 -0
  288. package/server/apiReview.js +45 -0
  289. package/server/apiReview.js.map +1 -0
  290. package/server/apiScan.d.ts +5 -0
  291. package/server/apiScan.js +90 -71
  292. package/server/apiScan.js.map +1 -0
  293. package/server/apiSearch.d.ts +33 -0
  294. package/server/apiSearch.js +184 -200
  295. package/server/apiSearch.js.map +1 -0
  296. package/server/apiSettings.d.ts +4 -0
  297. package/server/apiSettings.js +84 -85
  298. package/server/apiSettings.js.map +1 -0
  299. package/server/apiTools.d.ts +3 -0
  300. package/server/apiTools.js +55 -56
  301. package/server/apiTools.js.map +1 -0
  302. package/server/auth.d.ts +5 -0
  303. package/server/auth.js +54 -51
  304. package/server/auth.js.map +1 -0
  305. package/server/config.d.ts +42 -0
  306. package/server/config.js +189 -194
  307. package/server/config.js.map +1 -0
  308. package/server/daemon.d.ts +12 -0
  309. package/server/daemon.js +124 -114
  310. package/server/daemon.js.map +1 -0
  311. package/server/fileSourceNode.d.ts +2 -0
  312. package/server/fileSourceNode.js +34 -36
  313. package/server/fileSourceNode.js.map +1 -0
  314. package/server/gitClone.d.ts +9 -0
  315. package/server/gitClone.js +59 -61
  316. package/server/gitClone.js.map +1 -0
  317. package/server/gitDiff.d.ts +36 -0
  318. package/server/gitDiff.js +271 -169
  319. package/server/gitDiff.js.map +1 -0
  320. package/server/gitHistory.d.ts +12 -0
  321. package/server/gitHistory.js +80 -80
  322. package/server/gitHistory.js.map +1 -0
  323. package/server/gitRemote.d.ts +12 -0
  324. package/server/gitRemote.js +37 -38
  325. package/server/gitRemote.js.map +1 -0
  326. package/server/hermesChat.d.ts +13 -0
  327. package/server/hermesChat.js +145 -0
  328. package/server/hermesChat.js.map +1 -0
  329. package/server/htmlText.d.ts +4 -0
  330. package/server/htmlText.js +16 -23
  331. package/server/htmlText.js.map +1 -0
  332. package/server/http.d.ts +6 -0
  333. package/server/http.js +27 -34
  334. package/server/http.js.map +1 -0
  335. package/server/httpGuards.d.ts +2 -0
  336. package/server/httpGuards.js +47 -43
  337. package/server/httpGuards.js.map +1 -0
  338. package/server/https.d.ts +34 -0
  339. package/server/https.js +121 -111
  340. package/server/https.js.map +1 -0
  341. package/server/index.d.ts +40 -0
  342. package/server/index.js +139 -147
  343. package/server/index.js.map +1 -0
  344. package/server/layout.d.ts +26 -0
  345. package/server/layout.js +59 -64
  346. package/server/layout.js.map +1 -0
  347. package/server/llmProxy.d.ts +3 -0
  348. package/server/llmProxy.js +137 -135
  349. package/server/llmProxy.js.map +1 -0
  350. package/server/logger.d.ts +38 -0
  351. package/server/logger.js +198 -211
  352. package/server/logger.js.map +1 -0
  353. package/server/mcp/analysis.d.ts +29 -0
  354. package/server/mcp/analysis.js +99 -120
  355. package/server/mcp/analysis.js.map +1 -0
  356. package/server/mcp/http.d.ts +9 -0
  357. package/server/mcp/http.js +128 -137
  358. package/server/mcp/http.js.map +1 -0
  359. package/server/mcp/runner.d.ts +68 -0
  360. package/server/mcp/runner.js +208 -218
  361. package/server/mcp/runner.js.map +1 -0
  362. package/server/mcp/server.d.ts +29 -0
  363. package/server/mcp/server.js +167 -180
  364. package/server/mcp/server.js.map +1 -0
  365. package/server/mcp/standalone.d.ts +1 -0
  366. package/server/mcp/standalone.js +8 -10
  367. package/server/mcp/standalone.js.map +1 -0
  368. package/server/mcp/tools.d.ts +2020 -0
  369. package/server/mcp/tools.js +523 -574
  370. package/server/mcp/tools.js.map +1 -0
  371. package/server/paths.d.ts +3 -0
  372. package/server/paths.js +17 -15
  373. package/server/paths.js.map +1 -0
  374. package/server/pidfile.d.ts +9 -0
  375. package/server/pidfile.js +43 -45
  376. package/server/pidfile.js.map +1 -0
  377. package/server/review.d.ts +5 -0
  378. package/server/review.js +35 -0
  379. package/server/review.js.map +1 -0
  380. package/server/router.d.ts +33 -0
  381. package/server/router.js +195 -197
  382. package/server/router.js.map +1 -0
  383. package/server/scanRequest.d.ts +3 -0
  384. package/server/scanRequest.js +36 -0
  385. package/server/scanRequest.js.map +1 -0
  386. package/server/searchIndex.d.ts +17 -0
  387. package/server/searchIndex.js +83 -80
  388. package/server/searchIndex.js.map +1 -0
  389. package/server/sessions.d.ts +14 -0
  390. package/server/sessions.js +62 -70
  391. package/server/sessions.js.map +1 -0
  392. package/server/startup.d.ts +118 -0
  393. package/server/startup.js +143 -148
  394. package/server/startup.js.map +1 -0
  395. package/server/static.d.ts +6 -0
  396. package/server/static.js +28 -31
  397. package/server/static.js.map +1 -0
  398. package/server/tools/install.d.ts +4 -0
  399. package/server/tools/install.js +176 -185
  400. package/server/tools/install.js.map +1 -0
  401. package/server/tools/parse.d.ts +8 -0
  402. package/server/tools/parse.js +112 -114
  403. package/server/tools/parse.js.map +1 -0
  404. package/server/tools/platform.d.ts +9 -0
  405. package/server/tools/platform.js +49 -47
  406. package/server/tools/platform.js.map +1 -0
  407. package/server/tools/registry.d.ts +137 -0
  408. package/server/tools/registry.js +173 -172
  409. package/server/tools/registry.js.map +1 -0
  410. package/server/tools/scan.d.ts +34 -0
  411. package/server/tools/scan.js +89 -98
  412. package/server/tools/scan.js.map +1 -0
  413. package/server/tools.d.ts +34 -0
  414. package/server/tools.js +94 -107
  415. package/server/tools.js.map +1 -0
  416. package/server/tunnel.d.ts +29 -0
  417. package/server/tunnel.js +61 -66
  418. package/server/tunnel.js.map +1 -0
  419. package/shared/analyzer/docs.d.ts +16 -0
  420. package/shared/analyzer/docs.js +99 -93
  421. package/shared/analyzer/docs.js.map +1 -0
  422. package/shared/analyzer/explainLocal.d.ts +4 -0
  423. package/shared/analyzer/explainLocal.js +122 -142
  424. package/shared/analyzer/explainLocal.js.map +1 -0
  425. package/shared/analyzer/github.d.ts +37 -0
  426. package/shared/analyzer/github.js +41 -43
  427. package/shared/analyzer/github.js.map +1 -0
  428. package/shared/analyzer/graph.d.ts +41 -0
  429. package/shared/analyzer/graph.js +393 -400
  430. package/shared/analyzer/graph.js.map +1 -0
  431. package/shared/analyzer/health.d.ts +33 -0
  432. package/shared/analyzer/health.js +197 -193
  433. package/shared/analyzer/health.js.map +1 -0
  434. package/shared/analyzer/history.d.ts +29 -0
  435. package/shared/analyzer/history.js +110 -111
  436. package/shared/analyzer/history.js.map +1 -0
  437. package/shared/analyzer/jsonConfig.d.ts +2 -0
  438. package/shared/analyzer/jsonConfig.js +61 -0
  439. package/shared/analyzer/jsonConfig.js.map +1 -0
  440. package/shared/analyzer/languages/csharp.d.ts +26 -0
  441. package/shared/analyzer/languages/csharp.js +83 -88
  442. package/shared/analyzer/languages/csharp.js.map +1 -0
  443. package/shared/analyzer/languages/generic.d.ts +23 -0
  444. package/shared/analyzer/languages/generic.js +94 -105
  445. package/shared/analyzer/languages/generic.js.map +1 -0
  446. package/shared/analyzer/languages/go.d.ts +24 -0
  447. package/shared/analyzer/languages/go.js +45 -54
  448. package/shared/analyzer/languages/go.js.map +1 -0
  449. package/shared/analyzer/languages/index.d.ts +6 -0
  450. package/shared/analyzer/languages/index.js +19 -20
  451. package/shared/analyzer/languages/index.js.map +1 -0
  452. package/shared/analyzer/languages/java.d.ts +20 -0
  453. package/shared/analyzer/languages/java.js +73 -78
  454. package/shared/analyzer/languages/java.js.map +1 -0
  455. package/shared/analyzer/languages/javascript.d.ts +12 -0
  456. package/shared/analyzer/languages/javascript.js +258 -209
  457. package/shared/analyzer/languages/javascript.js.map +1 -0
  458. package/shared/analyzer/languages/python.d.ts +23 -0
  459. package/shared/analyzer/languages/python.js +92 -100
  460. package/shared/analyzer/languages/python.js.map +1 -0
  461. package/shared/analyzer/languages/rust.d.ts +17 -0
  462. package/shared/analyzer/languages/rust.js +96 -98
  463. package/shared/analyzer/languages/rust.js.map +1 -0
  464. package/shared/analyzer/languages/typescript.d.ts +11 -0
  465. package/shared/analyzer/languages/typescript.js +117 -116
  466. package/shared/analyzer/languages/typescript.js.map +1 -0
  467. package/shared/analyzer/licenses.d.ts +18 -0
  468. package/shared/analyzer/licenses.js +130 -133
  469. package/shared/analyzer/licenses.js.map +1 -0
  470. package/shared/analyzer/metrics.d.ts +20 -0
  471. package/shared/analyzer/metrics.js +112 -104
  472. package/shared/analyzer/metrics.js.map +1 -0
  473. package/shared/analyzer/pathUtil.d.ts +10 -0
  474. package/shared/analyzer/pathUtil.js +29 -35
  475. package/shared/analyzer/pathUtil.js.map +1 -0
  476. package/shared/analyzer/patterns.d.ts +11 -0
  477. package/shared/analyzer/patterns.js +231 -253
  478. package/shared/analyzer/patterns.js.map +1 -0
  479. package/shared/analyzer/scan.d.ts +62 -0
  480. package/shared/analyzer/scan.js +451 -442
  481. package/shared/analyzer/scan.js.map +1 -0
  482. package/shared/analyzer/scanControl.d.ts +11 -0
  483. package/shared/analyzer/scanControl.js +62 -0
  484. package/shared/analyzer/scanControl.js.map +1 -0
  485. package/shared/analyzer/security.d.ts +18 -0
  486. package/shared/analyzer/security.js +159 -159
  487. package/shared/analyzer/security.js.map +1 -0
  488. package/shared/analyzer/services.d.ts +5 -0
  489. package/shared/analyzer/services.js +141 -138
  490. package/shared/analyzer/services.js.map +1 -0
  491. package/shared/analyzer/stack.d.ts +6 -0
  492. package/shared/analyzer/stack.js +134 -141
  493. package/shared/analyzer/stack.js.map +1 -0
  494. package/shared/analyzer/tour.d.ts +2 -0
  495. package/shared/analyzer/tour.js +45 -53
  496. package/shared/analyzer/tour.js.map +1 -0
  497. package/shared/analyzer/util.d.ts +8 -0
  498. package/shared/analyzer/util.js +130 -76
  499. package/shared/analyzer/util.js.map +1 -0
  500. package/shared/analyzer/workflows.d.ts +8 -0
  501. package/shared/analyzer/workflows.js +139 -134
  502. package/shared/analyzer/workflows.js.map +1 -0
  503. package/shared/contracts.d.ts +250 -0
  504. package/shared/contracts.js +2 -0
  505. package/shared/contracts.js.map +1 -0
  506. package/shared/diagram/aiFacts.d.ts +35 -0
  507. package/shared/diagram/aiFacts.js +102 -105
  508. package/shared/diagram/aiFacts.js.map +1 -0
  509. package/shared/diagram/aiMermaid.d.ts +5 -0
  510. package/shared/diagram/aiMermaid.js +50 -46
  511. package/shared/diagram/aiMermaid.js.map +1 -0
  512. package/shared/diagram/atlas.d.ts +16 -0
  513. package/shared/diagram/atlas.js +51 -60
  514. package/shared/diagram/atlas.js.map +1 -0
  515. package/shared/diagram/mermaid.d.ts +43 -0
  516. package/shared/diagram/mermaid.js +348 -370
  517. package/shared/diagram/mermaid.js.map +1 -0
  518. package/shared/review/contracts.d.ts +95 -0
  519. package/shared/review/contracts.js +2 -0
  520. package/shared/review/contracts.js.map +1 -0
  521. package/shared/review/review.d.ts +10 -0
  522. package/shared/review/review.js +184 -0
  523. package/shared/review/review.js.map +1 -0
  524. package/shared/search/query.d.ts +32 -0
  525. package/shared/search/query.js +395 -388
  526. package/shared/search/query.js.map +1 -0
@@ -1,270 +1,264 @@
1
1
  // Graph facts: entry points, hubs, orphans, cycles, fan-in/fan-out.
2
2
  // Pure functions over the scan result — no I/O here.
3
-
4
- import { topFolderOf } from './pathUtil.js';
5
-
3
+ import { isTestPath, topFolderOf } from './pathUtil.js';
6
4
  const ENTRY_NAMES = new Set([
7
- 'index', 'main', 'app', 'server', 'cli', 'manage', 'mod', '__main__',
8
- 'run', 'start', 'cmd',
5
+ 'index', 'main', 'app', 'server', 'cli', 'manage', 'mod', '__main__',
6
+ 'run', 'start', 'cmd',
9
7
  ]);
10
-
11
- const TEST_RE = /(^|[._-])(test|spec|tests|__tests__)([._-]|\/|$)/i;
12
-
13
8
  export function computeFacts(scan, manifest = {}) {
14
- const { files, edges } = scan;
15
- const fanIn = new Map();
16
- const fanOut = new Map();
17
- const importers = new Map();
18
- const importsOf = new Map();
19
-
20
- for (const f of files) {
21
- fanIn.set(f.path, 0);
22
- fanOut.set(f.path, 0);
23
- importers.set(f.path, []);
24
- importsOf.set(f.path, []);
25
- }
26
- for (const e of edges) {
27
- if (!fanIn.has(e.to) || !fanOut.has(e.from)) continue;
28
- fanIn.set(e.to, fanIn.get(e.to) + 1);
29
- fanOut.set(e.from, fanOut.get(e.from) + 1);
30
- importers.get(e.to).push(e.from);
31
- importsOf.get(e.from).push(e.to);
32
- }
33
-
34
- const entrySet = new Set();
35
- for (const f of files) {
36
- const stem = (f.name || f.path || '').replace(/\.[^.]+$/, '');
37
- if (ENTRY_NAMES.has(stem) || f.hasMain) entrySet.add(f.path);
38
- }
39
- for (const p of manifest.entryPoints || []) entrySet.add(p);
40
-
41
- // Tarjan is the most expensive thing in this function, and one run answers
42
- // both questions asked of it: which files sit in a cycle, and what the
43
- // largest cycles are. It used to run twice on identical input.
44
- const sccs = stronglyConnected(files.map((f) => f.path), edges);
45
- const multi = sccs.filter((scc) => scc.length > 1);
46
-
47
- const inCycle = new Set();
48
- for (const scc of multi) for (const p of scc) inCycle.add(p);
49
-
50
- const entries = files
51
- .filter((f) => entrySet.has(f.path))
52
- .map((f) => f.path)
53
- .sort();
54
-
55
- // A hub is a file other files depend on. The threshold is 2, not 3: in a
56
- // repo with 20 files, "imported by two others" *is* the most-depended-upon
57
- // file, and a threshold of 3 reported no hubs at all for a whole small project
58
- // — the map of a small repo is exactly where a hub is most useful. Two is the
59
- // lowest value that still means "more than one other file reaches for this".
60
- const hubs = files
61
- .map((f) => ({ path: f.path, fanIn: fanIn.get(f.path) || 0, fanOut: fanOut.get(f.path) || 0 }))
62
- .filter((h) => h.fanIn >= 2)
63
- .sort((a, b) => b.fanIn - a.fanIn);
64
-
65
- const orphans = files
66
- .filter((f) => (fanIn.get(f.path) || 0) === 0 && !entrySet.has(f.path) && !TEST_RE.test(f.path))
67
- .map((f) => f.path)
68
- .sort();
69
-
70
- const cycles = multi
71
- .slice()
72
- .sort((a, b) => b.length - a.length)
73
- .slice(0, 10);
74
-
75
- // Collect all imported symbols per target file
76
- const importedSymbolsByTarget = new Map();
77
- const wildcards = new Set();
78
- for (const e of edges) {
79
- if (!e.to) continue;
80
- if (!importedSymbolsByTarget.has(e.to)) importedSymbolsByTarget.set(e.to, new Set());
81
- const set = importedSymbolsByTarget.get(e.to);
82
- if (!e.symbols || !e.symbols.length || e.symbols.includes('*')) {
83
- wildcards.add(e.to);
84
- } else {
85
- for (const s of e.symbols) set.add(s);
9
+ const { files, edges } = scan;
10
+ const fanIn = new Map();
11
+ const fanOut = new Map();
12
+ const importers = new Map();
13
+ const importsOf = new Map();
14
+ for (const f of files) {
15
+ fanIn.set(f.path, 0);
16
+ fanOut.set(f.path, 0);
17
+ importers.set(f.path, []);
18
+ importsOf.set(f.path, []);
86
19
  }
87
- }
88
-
89
- const deadExports = [];
90
- for (const f of files) {
91
- if (!f.exports || !f.exports.length) continue;
92
- if (entrySet.has(f.path) || TEST_RE.test(f.path) || wildcards.has(f.path)) continue;
93
- const importedSet = importedSymbolsByTarget.get(f.path);
94
- if (!importedSet || importedSet.size === 0) {
95
- for (const exp of f.exports) {
96
- deadExports.push({ file: f.path, name: exp.name, kind: exp.kind });
97
- }
98
- } else {
99
- for (const exp of f.exports) {
100
- if (!importedSet.has(exp.name) && exp.name !== 'default') {
101
- deadExports.push({ file: f.path, name: exp.name, kind: exp.kind });
20
+ for (const e of edges) {
21
+ if (!fanIn.has(e.to) || !fanOut.has(e.from))
22
+ continue;
23
+ fanIn.set(e.to, fanIn.get(e.to) + 1);
24
+ fanOut.set(e.from, fanOut.get(e.from) + 1);
25
+ importers.get(e.to).push(e.from);
26
+ importsOf.get(e.from).push(e.to);
27
+ }
28
+ const entrySet = new Set();
29
+ for (const f of files) {
30
+ const stem = (f.name || f.path || '').replace(/\.[^.]+$/, '');
31
+ if (ENTRY_NAMES.has(stem) || f.hasMain)
32
+ entrySet.add(f.path);
33
+ }
34
+ for (const p of manifest.entryPoints || [])
35
+ entrySet.add(p);
36
+ // Tarjan is the most expensive thing in this function, and one run answers
37
+ // both questions asked of it: which files sit in a cycle, and what the
38
+ // largest cycles are. It used to run twice on identical input.
39
+ const sccs = stronglyConnected(files.map((f) => f.path), edges);
40
+ const multi = sccs.filter((scc) => scc.length > 1);
41
+ const inCycle = new Set();
42
+ for (const scc of multi)
43
+ for (const p of scc)
44
+ inCycle.add(p);
45
+ const entries = files
46
+ .filter((f) => entrySet.has(f.path))
47
+ .map((f) => f.path)
48
+ .sort();
49
+ // A hub is a file other files depend on. The threshold is 2, not 3: in a
50
+ // repo with 20 files, "imported by two others" *is* the most-depended-upon
51
+ // file, and a threshold of 3 reported no hubs at all for a whole small project
52
+ // — the map of a small repo is exactly where a hub is most useful. Two is the
53
+ // lowest value that still means "more than one other file reaches for this".
54
+ const hubs = files
55
+ .map((f) => ({ path: f.path, fanIn: fanIn.get(f.path) || 0, fanOut: fanOut.get(f.path) || 0 }))
56
+ .filter((h) => h.fanIn >= 2)
57
+ .sort((a, b) => b.fanIn - a.fanIn);
58
+ const orphans = files
59
+ .filter((f) => (fanIn.get(f.path) || 0) === 0 && !entrySet.has(f.path) && !isTestPath(f.path))
60
+ .map((f) => f.path)
61
+ .sort();
62
+ const cycles = multi
63
+ .slice()
64
+ .sort((a, b) => b.length - a.length)
65
+ .slice(0, 10);
66
+ // Collect all imported symbols per target file
67
+ const importedSymbolsByTarget = new Map();
68
+ const wildcards = new Set();
69
+ for (const e of edges) {
70
+ if (!e.to)
71
+ continue;
72
+ if (!importedSymbolsByTarget.has(e.to))
73
+ importedSymbolsByTarget.set(e.to, new Set());
74
+ const set = importedSymbolsByTarget.get(e.to);
75
+ if (!e.symbols || !e.symbols.length || e.symbols.includes('*')) {
76
+ wildcards.add(e.to);
77
+ }
78
+ else {
79
+ for (const s of e.symbols)
80
+ set.add(s);
81
+ }
82
+ }
83
+ const deadExports = [];
84
+ for (const f of files) {
85
+ if (!f.exports || !f.exports.length)
86
+ continue;
87
+ if (entrySet.has(f.path) || isTestPath(f.path) || wildcards.has(f.path))
88
+ continue;
89
+ const importedSet = importedSymbolsByTarget.get(f.path);
90
+ if (!importedSet || importedSet.size === 0) {
91
+ for (const exp of f.exports) {
92
+ deadExports.push({ file: f.path, name: exp.name, kind: exp.kind });
93
+ }
94
+ }
95
+ else {
96
+ for (const exp of f.exports) {
97
+ if (!importedSet.has(exp.name)) {
98
+ deadExports.push({ file: f.path, name: exp.name, kind: exp.kind });
99
+ }
100
+ }
101
+ }
102
+ }
103
+ // Test coverage & untested hubs
104
+ const testFiles = files.filter((f) => isTestPath(f.path));
105
+ const testedSet = new Set();
106
+ const testQueue = [];
107
+ for (const tf of testFiles) {
108
+ for (const target of importsOf.get(tf.path) || []) {
109
+ if (!isTestPath(target) && !testedSet.has(target)) {
110
+ testedSet.add(target);
111
+ testQueue.push(target);
112
+ }
102
113
  }
103
- }
104
114
  }
105
- }
106
-
107
- // Test coverage & untested hubs
108
- const testFiles = files.filter((f) => TEST_RE.test(f.path));
109
- const testedSet = new Set();
110
- const testQueue = [];
111
- for (const tf of testFiles) {
112
- for (const target of importsOf.get(tf.path) || []) {
113
- if (!TEST_RE.test(target) && !testedSet.has(target)) {
114
- testedSet.add(target);
115
- testQueue.push(target);
116
- }
115
+ // Each file is enqueued once, so an index gives a complete O(V + E) walk.
116
+ // The old 500-step ceiling silently undercounted coverage in large repos.
117
+ for (let cursor = 0; cursor < testQueue.length; cursor++) {
118
+ const curr = testQueue[cursor];
119
+ for (const next of importsOf.get(curr) || []) {
120
+ if (!isTestPath(next) && !testedSet.has(next)) {
121
+ testedSet.add(next);
122
+ testQueue.push(next);
123
+ }
124
+ }
125
+ }
126
+ const nonTestFiles = files.filter((f) => !isTestPath(f.path));
127
+ const untestedHubs = hubs.filter((h) => !isTestPath(h.path) && !testedSet.has(h.path));
128
+ const testCoverage = {
129
+ testedCount: testedSet.size,
130
+ totalNonTest: nonTestFiles.length,
131
+ ratio: nonTestFiles.length ? Math.round((testedSet.size / nonTestFiles.length) * 100) : 100,
132
+ };
133
+ // Dependency drift
134
+ const declaredDeps = new Set([
135
+ ...Object.keys(manifest.deps?.npm || {}),
136
+ ...Object.keys(manifest.deps?.dev || {}),
137
+ ...(manifest.deps?.pip || []),
138
+ ...(manifest.deps?.go || []),
139
+ ...(manifest.deps?.cargo || []),
140
+ ]);
141
+ const importedExternals = new Set((scan.externals || []).map((x) => x.name));
142
+ const unusedDeclared = [...declaredDeps].filter((d) => !importedExternals.has(d)).sort();
143
+ const BUILTIN_MODULES = new Set([
144
+ 'fs', 'path', 'http', 'https', 'url', 'crypto', 'os', 'stream', 'util',
145
+ 'events', 'child_process', 'buffer', 'assert', 'net', 'zlib', 'tls', 'dns',
146
+ 'perf_hooks', 'worker_threads',
147
+ ]);
148
+ const undeclaredImported = [...importedExternals]
149
+ .filter((i) => !declaredDeps.has(i) && !BUILTIN_MODULES.has(i))
150
+ .sort();
151
+ const depsDrift = { unusedDeclared, undeclaredImported };
152
+ const folderEdges = new Map();
153
+ for (const e of edges) {
154
+ const a = topFolderOf(e.from);
155
+ const b = topFolderOf(e.to);
156
+ if (a === b)
157
+ continue;
158
+ const key = a + '->' + b;
159
+ folderEdges.set(key, (folderEdges.get(key) || 0) + 1);
117
160
  }
118
- }
119
- let hop = 0;
120
- while (testQueue.length && hop < 500) {
121
- hop++;
122
- const curr = testQueue.shift();
123
- for (const next of importsOf.get(curr) || []) {
124
- if (!TEST_RE.test(next) && !testedSet.has(next)) {
125
- testedSet.add(next);
126
- testQueue.push(next);
127
- }
161
+ const paths = files.map(f => f.path);
162
+ const communitiesMap = louvainCommunities(paths, edges);
163
+ const commGroups = new Map();
164
+ for (const [n, c] of communitiesMap.entries()) {
165
+ if (!commGroups.has(c))
166
+ commGroups.set(c, []);
167
+ commGroups.get(c).push(n);
128
168
  }
129
- }
130
- const nonTestFiles = files.filter((f) => !TEST_RE.test(f.path));
131
- const untestedHubs = hubs.filter((h) => !TEST_RE.test(h.path) && !testedSet.has(h.path));
132
- const testCoverage = {
133
- testedCount: testedSet.size,
134
- totalNonTest: nonTestFiles.length,
135
- ratio: nonTestFiles.length ? Math.round((testedSet.size / nonTestFiles.length) * 100) : 100,
136
- };
137
-
138
- // Dependency drift
139
- const declaredDeps = new Set([
140
- ...Object.keys(manifest.deps?.npm || {}),
141
- ...Object.keys(manifest.deps?.dev || {}),
142
- ...(manifest.deps?.pip || []),
143
- ...(manifest.deps?.go || []),
144
- ...(manifest.deps?.cargo || []),
145
- ]);
146
- const importedExternals = new Set((scan.externals || []).map((x) => x.name));
147
- const unusedDeclared = [...declaredDeps].filter((d) => !importedExternals.has(d)).sort();
148
- const BUILTIN_MODULES = new Set([
149
- 'fs', 'path', 'http', 'https', 'url', 'crypto', 'os', 'stream', 'util',
150
- 'events', 'child_process', 'buffer', 'assert', 'net', 'zlib', 'tls', 'dns',
151
- 'perf_hooks', 'worker_threads',
152
- ]);
153
- const undeclaredImported = [...importedExternals]
154
- .filter((i) => !declaredDeps.has(i) && !BUILTIN_MODULES.has(i))
155
- .sort();
156
- const depsDrift = { unusedDeclared, undeclaredImported };
157
-
158
- const folderEdges = new Map();
159
- for (const e of edges) {
160
- const a = topFolderOf(e.from);
161
- const b = topFolderOf(e.to);
162
- if (a === b) continue;
163
- const key = a + '->' + b;
164
- folderEdges.set(key, (folderEdges.get(key) || 0) + 1);
165
- }
166
-
167
- const paths = files.map(f => f.path);
168
- const communitiesMap = louvainCommunities(paths, edges);
169
- const commGroups = new Map();
170
- for (const [n, c] of communitiesMap.entries()) {
171
- if (!commGroups.has(c)) commGroups.set(c, []);
172
- commGroups.get(c).push(n);
173
- }
174
- const communities = [...commGroups.entries()]
175
- .map(([id, members]) => ({ id, members, size: members.length }))
176
- .sort((a, b) => b.size - a.size);
177
-
178
- const betweennessResult = brandesBetweenness(paths, edges);
179
- const betweenness = Object.fromEntries(betweennessResult.map);
180
-
181
- return {
182
- communities,
183
- betweenness,
184
- // Whether `betweenness` above is a real measurement or all zeros
185
- // because the graph was over the Brandes cap. The UI uses this the
186
- // same way it uses `health.blastExact`: it shows an honest
187
- // "not computed for repos of this size" instead of pretending the
188
- // zeros are a finding.
189
- betweennessExact: betweennessResult.exact,
190
- fanIn: Object.fromEntries(fanIn),
191
- fanOut: Object.fromEntries(fanOut),
192
- importers: Object.fromEntries(importers),
193
- importsOf: Object.fromEntries(importsOf),
194
- entries,
195
- hubs,
196
- orphans,
197
- cycles,
198
- inCycle: [...inCycle],
199
- deadExports,
200
- testCoverage,
201
- untestedHubs,
202
- depsDrift,
203
- folderEdges: [...folderEdges.entries()].map(([key, count]) => {
204
- const [from, to] = key.split('->');
205
- return { from, to, count };
206
- }),
207
- entrySet: entries,
208
- };
169
+ const communities = [...commGroups.entries()]
170
+ .map(([id, members]) => ({ id, members, size: members.length }))
171
+ .sort((a, b) => b.size - a.size);
172
+ const betweennessResult = brandesBetweenness(paths, edges);
173
+ const betweenness = Object.fromEntries(betweennessResult.map);
174
+ return {
175
+ communities,
176
+ betweenness,
177
+ // Whether `betweenness` above is a real measurement or all zeros
178
+ // because the graph was over the Brandes cap. The UI uses this the
179
+ // same way it uses `health.blastExact`: it shows an honest
180
+ // "not computed for repos of this size" instead of pretending the
181
+ // zeros are a finding.
182
+ betweennessExact: betweennessResult.exact,
183
+ fanIn: Object.fromEntries(fanIn),
184
+ fanOut: Object.fromEntries(fanOut),
185
+ importers: Object.fromEntries(importers),
186
+ importsOf: Object.fromEntries(importsOf),
187
+ entries,
188
+ hubs,
189
+ orphans,
190
+ cycles,
191
+ inCycle: [...inCycle],
192
+ deadExports,
193
+ testCoverage,
194
+ untestedHubs,
195
+ depsDrift,
196
+ folderEdges: [...folderEdges.entries()].map(([key, count]) => {
197
+ const [from, to] = key.split('->');
198
+ return { from, to, count };
199
+ }),
200
+ entrySet: entries,
201
+ };
209
202
  }
210
-
211
203
  // Tarjan's strongly connected components, iterative so deep graphs don't
212
204
  // blow the stack.
213
205
  function stronglyConnected(nodes, edges) {
214
- const adj = new Map(nodes.map((n) => [n, []]));
215
- for (const e of edges) {
216
- if (adj.has(e.from)) adj.get(e.from).push(e.to);
217
- }
218
- const index = new Map();
219
- const low = new Map();
220
- const onStack = new Set();
221
- const stack = [];
222
- const result = [];
223
- let counter = 0;
224
-
225
- for (const start of nodes) {
226
- if (index.has(start)) continue;
227
- const work = [[start, 0]];
228
- while (work.length) {
229
- const [v, pi] = work[work.length - 1];
230
- if (pi === 0) {
231
- index.set(v, counter);
232
- low.set(v, counter);
233
- counter++;
234
- stack.push(v);
235
- onStack.add(v);
236
- }
237
- const children = adj.get(v) || [];
238
- if (pi < children.length) {
239
- work[work.length - 1][1] = pi + 1;
240
- const w = children[pi];
241
- if (!index.has(w)) {
242
- work.push([w, 0]);
243
- } else if (onStack.has(w)) {
244
- low.set(v, Math.min(low.get(v), index.get(w)));
245
- }
246
- } else {
247
- work.pop();
248
- if (work.length) {
249
- const parent = work[work.length - 1][0];
250
- low.set(parent, Math.min(low.get(parent), low.get(v)));
251
- }
252
- if (low.get(v) === index.get(v)) {
253
- const scc = [];
254
- let w;
255
- do {
256
- w = stack.pop();
257
- onStack.delete(w);
258
- scc.push(w);
259
- } while (w !== v);
260
- result.push(scc);
206
+ const adj = new Map(nodes.map((n) => [n, []]));
207
+ for (const e of edges) {
208
+ if (adj.has(e.from))
209
+ adj.get(e.from).push(e.to);
210
+ }
211
+ const index = new Map();
212
+ const low = new Map();
213
+ const onStack = new Set();
214
+ const stack = [];
215
+ const result = [];
216
+ let counter = 0;
217
+ for (const start of nodes) {
218
+ if (index.has(start))
219
+ continue;
220
+ const work = [[start, 0]];
221
+ while (work.length) {
222
+ const [v, pi] = work[work.length - 1];
223
+ if (pi === 0) {
224
+ index.set(v, counter);
225
+ low.set(v, counter);
226
+ counter++;
227
+ stack.push(v);
228
+ onStack.add(v);
229
+ }
230
+ const children = adj.get(v) || [];
231
+ if (pi < children.length) {
232
+ work[work.length - 1][1] = pi + 1;
233
+ const w = children[pi];
234
+ if (!index.has(w)) {
235
+ work.push([w, 0]);
236
+ }
237
+ else if (onStack.has(w)) {
238
+ low.set(v, Math.min(low.get(v), index.get(w)));
239
+ }
240
+ }
241
+ else {
242
+ work.pop();
243
+ if (work.length) {
244
+ const parent = work[work.length - 1][0];
245
+ low.set(parent, Math.min(low.get(parent), low.get(v)));
246
+ }
247
+ if (low.get(v) === index.get(v)) {
248
+ const scc = [];
249
+ let w;
250
+ do {
251
+ w = stack.pop();
252
+ onStack.delete(w);
253
+ scc.push(w);
254
+ } while (w !== v);
255
+ result.push(scc);
256
+ }
257
+ }
261
258
  }
262
- }
263
259
  }
264
- }
265
- return result;
260
+ return result;
266
261
  }
267
-
268
262
  // Lookup shapes for the render loops.
269
263
  //
270
264
  // `facts` is plain data on purpose — it is serialized to JSON and handed to the
@@ -278,38 +272,40 @@ function stronglyConnected(nodes, edges) {
278
272
  // It assumes nobody mutates `facts` after computing it. Nothing does — the
279
273
  // engine returns it and every consumer reads.
280
274
  const INDEXES = new WeakMap();
281
-
282
275
  export function factIndex(facts) {
283
- let index = INDEXES.get(facts);
284
- if (index) return index;
285
- index = {
286
- entries: new Set(facts.entries || []),
287
- inCycle: new Set(facts.inCycle || []),
288
- hubs: new Map((facts.hubs || []).map((h) => [h.path, h])),
289
- };
290
- INDEXES.set(facts, index);
291
- return index;
276
+ let index = INDEXES.get(facts);
277
+ if (index)
278
+ return index;
279
+ index = {
280
+ entries: new Set(facts.entries || []),
281
+ inCycle: new Set(facts.inCycle || []),
282
+ hubs: new Map((facts.hubs || []).map((h) => [h.path, h])),
283
+ };
284
+ INDEXES.set(facts, index);
285
+ return index;
292
286
  }
293
-
294
287
  export function roleOf(path, facts) {
295
- if (TEST_RE.test(path)) return 'test';
296
- const index = factIndex(facts);
297
- if (index.entries.has(path)) return 'entry';
298
- const hub = index.hubs.get(path);
299
- if (hub && hub.fanIn >= 5) return 'hub';
300
- const fin = facts.fanIn[path] || 0;
301
- const fout = facts.fanOut[path] || 0;
302
- if (fout === 0 && fin > 0) return 'leaf';
303
- if (/config|settings|\.json$|\.ya?ml$|\.toml$/.test(path)) return 'config';
304
- return 'module';
288
+ if (isTestPath(path))
289
+ return 'test';
290
+ const index = factIndex(facts);
291
+ if (index.entries.has(path))
292
+ return 'entry';
293
+ const hub = index.hubs.get(path);
294
+ if (hub && hub.fanIn >= 5)
295
+ return 'hub';
296
+ const fin = facts.fanIn[path] || 0;
297
+ const fout = facts.fanOut[path] || 0;
298
+ if (fout === 0 && fin > 0)
299
+ return 'leaf';
300
+ if (/config|settings|\.json$|\.ya?ml$|\.toml$/.test(path))
301
+ return 'config';
302
+ return 'module';
305
303
  }
306
-
307
304
  // Is this file part of an import cycle? Same answer as
308
305
  // `facts.inCycle.includes(path)`, without the scan.
309
306
  export function inCycle(path, facts) {
310
- return factIndex(facts).inCycle.has(path);
307
+ return factIndex(facts).inCycle.has(path);
311
308
  }
312
-
313
309
  // The same trick for the scan itself. `scan.files.find((f) => f.path === p)` and
314
310
  // `scan.files.filter((f) => f.dir === d)` were written a dozen times across the
315
311
  // engine and the UI, both inside per-file loops — the docs generator alone ran
@@ -319,91 +315,88 @@ export function inCycle(path, facts) {
319
315
  // Treat it as read-only: copy before sorting.
320
316
  const SCAN_INDEXES = new WeakMap();
321
317
  const NO_FILES = Object.freeze([]);
322
-
323
318
  export function scanIndex(scan) {
324
- let index = SCAN_INDEXES.get(scan);
325
- if (index) return index;
326
- const byPath = new Map();
327
- const byDir = new Map();
328
- for (const f of scan.files || []) {
329
- byPath.set(f.path, f);
330
- const bucket = byDir.get(f.dir);
331
- if (bucket) bucket.push(f);
332
- else byDir.set(f.dir, [f]);
333
- }
334
- index = {
335
- byPath,
336
- byDir,
337
- fileAt: (path) => byPath.get(path) || null,
338
- filesIn: (dir) => byDir.get(dir) || NO_FILES,
339
- };
340
- SCAN_INDEXES.set(scan, index);
341
- return index;
319
+ let index = SCAN_INDEXES.get(scan);
320
+ if (index)
321
+ return index;
322
+ const byPath = new Map();
323
+ const byDir = new Map();
324
+ for (const f of scan.files || []) {
325
+ byPath.set(f.path, f);
326
+ const bucket = byDir.get(f.dir);
327
+ if (bucket)
328
+ bucket.push(f);
329
+ else
330
+ byDir.set(f.dir, [f]);
331
+ }
332
+ index = {
333
+ byPath,
334
+ byDir,
335
+ fileAt: (path) => byPath.get(path) || null,
336
+ filesIn: (dir) => byDir.get(dir) || NO_FILES,
337
+ };
338
+ SCAN_INDEXES.set(scan, index);
339
+ return index;
342
340
  }
343
-
344
341
  function louvainCommunities(nodes, edges) {
345
- let communities = new Map(nodes.map(n => [n, n]));
346
- let tot = new Map(nodes.map(n => [n, 0]));
347
- let inC = new Map(nodes.map(n => [n, 0]));
348
- let k = new Map(nodes.map(n => [n, 0]));
349
- let m2 = 0;
350
-
351
- const adj = new Map(nodes.map(n => [n, []]));
352
- for (const e of edges) {
353
- if (!adj.has(e.from)) adj.set(e.from, []);
354
- adj.get(e.from).push(e.to);
355
- k.set(e.from, (k.get(e.from) || 0) + 1);
356
- k.set(e.to, (k.get(e.to) || 0) + 1);
357
- m2 += 2;
358
- }
359
- if (m2 === 0) return communities;
360
-
361
- for (const n of nodes) tot.set(n, k.get(n));
362
-
363
- // Eight passes is enough for any practical graph to settle. Three was
364
- // the early limit and worked for small repos, but on denser graphs the
365
- // modularity gain was still climbing at iteration three. The early-exit
366
- // (`improved === false`) keeps the cost bounded on graphs that converge
367
- // quickly, so this is not a free pass on every scan — it is a ceiling.
368
- let iters = 0;
369
- let improved = true;
370
- while (iters < 8 && improved) {
371
- improved = false;
372
- for (const u of nodes) {
373
- const c_u = communities.get(u);
374
- const k_u = k.get(u);
375
-
376
- const counts = new Map();
377
- for (const v of (adj.get(u) || [])) {
378
- const c_v = communities.get(v);
379
- counts.set(c_v, (counts.get(c_v) || 0) + 1);
380
- }
381
-
382
- let best_c = c_u;
383
- let max_gain = 0;
384
-
385
- for (const [c_v, weight] of counts.entries()) {
386
- if (c_v === c_u) continue;
387
- const tot_c = tot.get(c_v);
388
- const gain = weight - (k_u * tot_c) / m2;
389
- if (gain > max_gain) {
390
- max_gain = gain;
391
- best_c = c_v;
342
+ let communities = new Map(nodes.map(n => [n, n]));
343
+ let tot = new Map(nodes.map(n => [n, 0]));
344
+ let inC = new Map(nodes.map(n => [n, 0]));
345
+ let k = new Map(nodes.map(n => [n, 0]));
346
+ let m2 = 0;
347
+ const adj = new Map(nodes.map(n => [n, []]));
348
+ for (const e of edges) {
349
+ if (!adj.has(e.from))
350
+ adj.set(e.from, []);
351
+ adj.get(e.from).push(e.to);
352
+ k.set(e.from, (k.get(e.from) || 0) + 1);
353
+ k.set(e.to, (k.get(e.to) || 0) + 1);
354
+ m2 += 2;
355
+ }
356
+ if (m2 === 0)
357
+ return communities;
358
+ for (const n of nodes)
359
+ tot.set(n, k.get(n));
360
+ // Eight passes is enough for any practical graph to settle. Three was
361
+ // the early limit and worked for small repos, but on denser graphs the
362
+ // modularity gain was still climbing at iteration three. The early-exit
363
+ // (`improved === false`) keeps the cost bounded on graphs that converge
364
+ // quickly, so this is not a free pass on every scan — it is a ceiling.
365
+ let iters = 0;
366
+ let improved = true;
367
+ while (iters < 8 && improved) {
368
+ improved = false;
369
+ for (const u of nodes) {
370
+ const c_u = communities.get(u);
371
+ const k_u = k.get(u);
372
+ const counts = new Map();
373
+ for (const v of (adj.get(u) || [])) {
374
+ const c_v = communities.get(v);
375
+ counts.set(c_v, (counts.get(c_v) || 0) + 1);
376
+ }
377
+ let best_c = c_u;
378
+ let max_gain = 0;
379
+ for (const [c_v, weight] of counts.entries()) {
380
+ if (c_v === c_u)
381
+ continue;
382
+ const tot_c = tot.get(c_v);
383
+ const gain = weight - (k_u * tot_c) / m2;
384
+ if (gain > max_gain) {
385
+ max_gain = gain;
386
+ best_c = c_v;
387
+ }
388
+ }
389
+ if (best_c !== c_u) {
390
+ tot.set(c_u, tot.get(c_u) - k_u);
391
+ tot.set(best_c, tot.get(best_c) + k_u);
392
+ communities.set(u, best_c);
393
+ improved = true;
394
+ }
392
395
  }
393
- }
394
-
395
- if (best_c !== c_u) {
396
- tot.set(c_u, tot.get(c_u) - k_u);
397
- tot.set(best_c, tot.get(best_c) + k_u);
398
- communities.set(u, best_c);
399
- improved = true;
400
- }
396
+ iters++;
401
397
  }
402
- iters++;
403
- }
404
- return communities;
398
+ return communities;
405
399
  }
406
-
407
400
  // Brandes's algorithm. The old return was just a Map of zeros when the
408
401
  // graph had more than 1,000 nodes, which is honest about the cost (O(V·E)
409
402
  // in the unweighted case) but dishonest about what the consumer is looking
@@ -412,55 +405,55 @@ function louvainCommunities(nodes, edges) {
412
405
  // for repos over 1,000 files" the way the health panel shows
413
406
  // `blastExact: false` next to a fan-in fallback.
414
407
  function brandesBetweenness(nodes, edges) {
415
- const cb = new Map(nodes.map(n => [n, 0]));
416
- if (nodes.length > 1000) return { map: cb, exact: false };
417
-
418
- const adj = new Map(nodes.map(n => [n, []]));
419
- for (const e of edges) {
420
- if (adj.has(e.from)) adj.get(e.from).push(e.to);
421
- }
422
-
423
- for (const s of nodes) {
424
- const S = [];
425
- const P = new Map(nodes.map(n => [n, []]));
426
- const sigma = new Map(nodes.map(n => [n, 0]));
427
- sigma.set(s, 1);
428
- const d = new Map(nodes.map(n => [n, -1]));
429
- d.set(s, 0);
430
- const Q = [s];
431
-
432
- while (Q.length > 0) {
433
- const v = Q.shift();
434
- S.push(v);
435
- for (const w of (adj.get(v) || [])) {
436
- if (d.get(w) < 0) {
437
- d.set(w, d.get(v) + 1);
438
- Q.push(w);
408
+ const cb = new Map(nodes.map(n => [n, 0]));
409
+ if (nodes.length > 1000)
410
+ return { map: cb, exact: false };
411
+ const adj = new Map(nodes.map(n => [n, []]));
412
+ for (const e of edges) {
413
+ if (adj.has(e.from))
414
+ adj.get(e.from).push(e.to);
415
+ }
416
+ for (const s of nodes) {
417
+ const S = [];
418
+ const P = new Map(nodes.map(n => [n, []]));
419
+ const sigma = new Map(nodes.map(n => [n, 0]));
420
+ sigma.set(s, 1);
421
+ const d = new Map(nodes.map(n => [n, -1]));
422
+ d.set(s, 0);
423
+ const Q = [s];
424
+ while (Q.length > 0) {
425
+ const v = Q.shift();
426
+ S.push(v);
427
+ for (const w of (adj.get(v) || [])) {
428
+ if (d.get(w) < 0) {
429
+ d.set(w, d.get(v) + 1);
430
+ Q.push(w);
431
+ }
432
+ if (d.get(w) === d.get(v) + 1) {
433
+ sigma.set(w, sigma.get(w) + sigma.get(v));
434
+ P.get(w).push(v);
435
+ }
436
+ }
439
437
  }
440
- if (d.get(w) === d.get(v) + 1) {
441
- sigma.set(w, sigma.get(w) + sigma.get(v));
442
- P.get(w).push(v);
438
+ const delta = new Map(nodes.map(n => [n, 0]));
439
+ while (S.length > 0) {
440
+ const w = S.pop();
441
+ for (const v of P.get(w)) {
442
+ delta.set(v, delta.get(v) + (sigma.get(v) / sigma.get(w)) * (1 + delta.get(w)));
443
+ }
444
+ if (w !== s) {
445
+ cb.set(w, cb.get(w) + delta.get(w));
446
+ }
443
447
  }
444
- }
445
448
  }
446
-
447
- const delta = new Map(nodes.map(n => [n, 0]));
448
- while (S.length > 0) {
449
- const w = S.pop();
450
- for (const v of P.get(w)) {
451
- delta.set(v, delta.get(v) + (sigma.get(v) / sigma.get(w)) * (1 + delta.get(w)));
452
- }
453
- if (w !== s) {
454
- cb.set(w, cb.get(w) + delta.get(w));
455
- }
449
+ let max = 0;
450
+ for (const val of cb.values())
451
+ if (val > max)
452
+ max = val;
453
+ if (max > 0) {
454
+ for (const [k, v] of cb.entries())
455
+ cb.set(k, v / max);
456
456
  }
457
- }
458
-
459
- let max = 0;
460
- for (const val of cb.values()) if (val > max) max = val;
461
- if (max > 0) {
462
- for (const [k, v] of cb.entries()) cb.set(k, v / max);
463
- }
464
-
465
- return { map: cb, exact: true };
457
+ return { map: cb, exact: true };
466
458
  }
459
+ //# sourceMappingURL=graph.js.map