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
@@ -7,140 +7,139 @@
7
7
  // Everything is keyed on file path, which is already the join key the rest of
8
8
  // the engine speaks — complexity comes over from scan.files, structural edges
9
9
  // from scan.edges, and the two views of "these change together" sit side by side.
10
-
11
10
  import { baseName } from './pathUtil.js';
12
-
13
11
  // Commits touching more files than this are skipped for pair counting, not for
14
12
  // churn — a 900-file reformat or a mass rename would otherwise contribute
15
13
  // C(900,2) ≈ 400k pairs of noise to co-change while saying nothing about
16
14
  // coupling. Churn still counts them; every file in them was really touched.
17
15
  const MAX_COMMIT_FILES_FOR_PAIRS = 50;
18
-
19
16
  // Once this many distinct pairs are tracked, new pairs stop being recorded and
20
17
  // only existing ones keep counting. A hard bound on memory for repos with long
21
18
  // histories of small commits; the top of the list is decided well before this.
22
19
  const MAX_TRACKED_PAIRS = 5000;
23
-
24
20
  export function analyzeHistory(scan, commits, opts = {}) {
25
- const totalCommits = opts.totalCommits ?? commits.length;
26
- const truncated = totalCommits > commits.length;
27
-
28
- // ---- per-file rollup -----------------------------------------------------
29
- // One pass over every commit's file list. Authors are identified by email —
30
- // names collide and change; the email is what git itself keys identity on.
31
- const churn = new Map(); // path -> commit count
32
- const authorsOf = new Map(); // path -> Map(email -> display name)
33
- const firstSeen = new Map(); // path -> earliest commit date (ISO strings sort)
34
- const lastTouched = new Map();
35
- const authorCommits = new Map(); // email -> { name, commits }
36
- let pathsGone = 0;
37
-
38
- for (const c of commits) {
39
- const date = c.date || '';
40
- const known = authorCommits.get(c.author?.email);
41
- if (known) known.commits++;
42
- else if (c.author?.email) authorCommits.set(c.author.email, { name: c.author.name || c.author.email, commits: 1 });
43
-
44
- for (const p of c.files || []) {
45
- churn.set(p, (churn.get(p) || 0) + 1);
46
- if (!firstSeen.has(p) || date < firstSeen.get(p)) firstSeen.set(p, date);
47
- if (!lastTouched.has(p) || date > lastTouched.get(p)) lastTouched.set(p, date);
48
- let byEmail = authorsOf.get(p);
49
- if (!byEmail) { byEmail = new Map(); authorsOf.set(p, byEmail); }
50
- if (!byEmail.has(c.author?.email)) byEmail.set(c.author?.email, c.author?.name || c.author?.email || '?');
21
+ const totalCommits = opts.totalCommits ?? commits.length;
22
+ const truncated = totalCommits > commits.length;
23
+ // ---- per-file rollup -----------------------------------------------------
24
+ // One pass over every commit's file list. Authors are identified by email —
25
+ // names collide and change; the email is what git itself keys identity on.
26
+ const churn = new Map(); // path -> commit count
27
+ const authorsOf = new Map(); // path -> Map(email -> display name)
28
+ const firstSeen = new Map(); // path -> earliest commit date (ISO strings sort)
29
+ const lastTouched = new Map();
30
+ const authorCommits = new Map(); // email -> { name, commits }
31
+ let pathsGone = 0;
32
+ for (const c of commits) {
33
+ const date = c.date || '';
34
+ const known = authorCommits.get(c.author?.email);
35
+ if (known)
36
+ known.commits++;
37
+ else if (c.author?.email)
38
+ authorCommits.set(c.author.email, { name: c.author.name || c.author.email, commits: 1 });
39
+ for (const p of c.files || []) {
40
+ churn.set(p, (churn.get(p) || 0) + 1);
41
+ if (!firstSeen.has(p) || date < firstSeen.get(p))
42
+ firstSeen.set(p, date);
43
+ if (!lastTouched.has(p) || date > lastTouched.get(p))
44
+ lastTouched.set(p, date);
45
+ let byEmail = authorsOf.get(p);
46
+ if (!byEmail) {
47
+ byEmail = new Map();
48
+ authorsOf.set(p, byEmail);
49
+ }
50
+ if (!byEmail.has(c.author?.email))
51
+ byEmail.set(c.author?.email, c.author?.name || c.author?.email || '?');
52
+ }
51
53
  }
52
- }
53
-
54
- // ---- join with the scan ---------------------------------------------------
55
- // Complexity lives on scan.files; history paths that are not in the scan are
56
- // files deleted or renamed inside the window. They had churn once — counted,
57
- // then set aside rather than silently mixed into rankings of files that no
58
- // longer exist.
59
- const cxOf = new Map(scan.files.map((f) => [f.path, f.complexity || 1]));
60
- for (const p of churn.keys()) if (!cxOf.has(p)) pathsGone++;
61
-
62
- const live = [...churn.entries()].filter(([p]) => cxOf.has(p));
63
- const maxChurn = Math.max(1, ...live.map(([, n]) => n));
64
- const maxCx = Math.max(1, ...live.map(([p]) => cxOf.get(p)));
65
-
66
- const perFile = live.map(([p, n]) => {
67
- const authors = authorsOf.get(p).size;
54
+ // ---- join with the scan ---------------------------------------------------
55
+ // Complexity lives on scan.files; history paths that are not in the scan are
56
+ // files deleted or renamed inside the window. They had churn once — counted,
57
+ // then set aside rather than silently mixed into rankings of files that no
58
+ // longer exist.
59
+ const cxOf = new Map(scan.files.map((f) => [f.path, f.complexity || 1]));
60
+ for (const p of churn.keys())
61
+ if (!cxOf.has(p))
62
+ pathsGone++;
63
+ const live = [...churn.entries()].filter(([p]) => cxOf.has(p));
64
+ const maxChurn = Math.max(1, ...live.map(([, n]) => n));
65
+ const maxCx = Math.max(1, ...live.map(([p]) => cxOf.get(p)));
66
+ const perFile = live.map(([p, n]) => {
67
+ const authors = authorsOf.get(p).size;
68
+ return {
69
+ path: p,
70
+ name: baseName(p),
71
+ churn: n,
72
+ authors,
73
+ solo: authors === 1,
74
+ firstSeen: firstSeen.get(p),
75
+ lastTouched: lastTouched.get(p),
76
+ complexity: cxOf.get(p),
77
+ // The cross-tab: both axes normalized against the repo's own worst, so
78
+ // the score reads "how far up both columns at once" and a file maxing
79
+ // one axis but not the other cannot outrank one high on both.
80
+ hotspot: Math.round(100 * (n / maxChurn) * (cxOf.get(p) / maxCx)),
81
+ };
82
+ });
83
+ perFile.sort((a, b) => b.hotspot - a.hotspot || b.churn - a.churn || a.path.localeCompare(b.path));
84
+ const byPath = {};
85
+ for (const row of perFile)
86
+ byPath[row.path] = row;
87
+ const soloFiles = perFile.filter((r) => r.solo && r.churn >= 3).length;
88
+ const dates = commits.map((c) => c.date).filter(Boolean);
68
89
  return {
69
- path: p,
70
- name: baseName(p),
71
- churn: n,
72
- authors,
73
- solo: authors === 1,
74
- firstSeen: firstSeen.get(p),
75
- lastTouched: lastTouched.get(p),
76
- complexity: cxOf.get(p),
77
- // The cross-tab: both axes normalized against the repo's own worst, so
78
- // the score reads "how far up both columns at once" and a file maxing
79
- // one axis but not the other cannot outrank one high on both.
80
- hotspot: Math.round(100 * (n / maxChurn) * (cxOf.get(p) / maxCx)),
90
+ available: true,
91
+ commitCount: commits.length,
92
+ totalCommits,
93
+ truncated,
94
+ // The raw commit list, not just the rollups. The insights view draws a
95
+ // 52-week heatmap and a punch card from per-commit dates; without the
96
+ // original array, that view rendered an empty calendar even when history
97
+ // was fully available. The cost is the same parsed commits we already hold
98
+ // — `parseGitLog` capped at 2,000 — so duplication here is honest.
99
+ commits,
100
+ authors: [...authorCommits.values()].sort((a, b) => b.commits - a.commits),
101
+ firstCommitAt: dates.length ? dates.reduce((a, b) => (a < b ? a : b)) : null,
102
+ lastCommitAt: dates.length ? dates.reduce((a, b) => (a > b ? a : b)) : null,
103
+ perFile,
104
+ byPath,
105
+ soloFiles,
106
+ coChanged: coChangePairs(commits, new Set(scan.edges.map((e) => e.from + '->' + e.to))),
107
+ pathsGone,
81
108
  };
82
- });
83
- perFile.sort((a, b) => b.hotspot - a.hotspot || b.churn - a.churn || a.path.localeCompare(b.path));
84
-
85
- const byPath = {};
86
- for (const row of perFile) byPath[row.path] = row;
87
- const soloFiles = perFile.filter((r) => r.solo && r.churn >= 3).length;
88
-
89
- const dates = commits.map((c) => c.date).filter(Boolean);
90
-
91
- return {
92
- available: true,
93
- commitCount: commits.length,
94
- totalCommits,
95
- truncated,
96
- // The raw commit list, not just the rollups. The insights view draws a
97
- // 52-week heatmap and a punch card from per-commit dates; without the
98
- // original array, that view rendered an empty calendar even when history
99
- // was fully available. The cost is the same parsed commits we already hold
100
- // — `parseGitLog` capped at 2,000 — so duplication here is honest.
101
- commits,
102
- authors: [...authorCommits.values()].sort((a, b) => b.commits - a.commits),
103
- firstCommitAt: dates.length ? dates.reduce((a, b) => (a < b ? a : b)) : null,
104
- lastCommitAt: dates.length ? dates.reduce((a, b) => (a > b ? a : b)) : null,
105
- perFile,
106
- byPath,
107
- soloFiles,
108
- coChanged: coChangePairs(commits, new Set(scan.edges.map((e) => e.from + '->' + e.to))),
109
- pathsGone,
110
- };
111
109
  }
112
-
113
110
  // Files that keep turning up in the same commit without importing each other.
114
111
  // The structural coupling matrix already shows what imports what; this is the
115
112
  // contrast — changes that travel together for reasons the import graph does
116
113
  // not know about (shared schema, feature pairs, copy-paste siblings).
117
114
  function coChangePairs(commits, structuralEdges) {
118
- const pairs = new Map(); // 'a|b' (sorted) -> count
119
-
120
- for (const c of commits) {
121
- const files = c.files || [];
122
- if (files.length < 2 || files.length > MAX_COMMIT_FILES_FOR_PAIRS) continue;
123
- for (let i = 0; i < files.length; i++) {
124
- for (let j = i + 1; j < files.length; j++) {
125
- const a = files[i] < files[j] ? files[i] : files[j];
126
- const b = files[i] < files[j] ? files[j] : files[i];
127
- if (structuralEdges.has(a + '->' + b) || structuralEdges.has(b + '->' + a)) continue;
128
- const key = a + '|' + b;
129
- const seen = pairs.get(key);
130
- if (seen) seen.count++;
131
- else if (pairs.size < MAX_TRACKED_PAIRS) pairs.set(key, { a, b, count: 1 });
132
- }
115
+ const pairs = new Map(); // 'a|b' (sorted) -> count
116
+ for (const c of commits) {
117
+ const files = c.files || [];
118
+ if (files.length < 2 || files.length > MAX_COMMIT_FILES_FOR_PAIRS)
119
+ continue;
120
+ for (let i = 0; i < files.length; i++) {
121
+ for (let j = i + 1; j < files.length; j++) {
122
+ const a = files[i] < files[j] ? files[i] : files[j];
123
+ const b = files[i] < files[j] ? files[j] : files[i];
124
+ if (structuralEdges.has(a + '->' + b) || structuralEdges.has(b + '->' + a))
125
+ continue;
126
+ const key = a + '|' + b;
127
+ const seen = pairs.get(key);
128
+ if (seen)
129
+ seen.count++;
130
+ else if (pairs.size < MAX_TRACKED_PAIRS)
131
+ pairs.set(key, { a, b, count: 1 });
132
+ }
133
+ }
133
134
  }
134
- }
135
-
136
- return [...pairs.values()]
137
- .filter((p) => p.count >= 2) // once is coincidence; the plan is about habits
138
- .sort((x, y) => y.count - x.count || x.a.localeCompare(y.a))
139
- .slice(0, 20);
135
+ return [...pairs.values()]
136
+ .filter((p) => p.count >= 2) // once is coincidence; the plan is about habits
137
+ .sort((x, y) => y.count - x.count || x.a.localeCompare(y.a))
138
+ .slice(0, 20);
140
139
  }
141
-
142
140
  // The shape callers should hold when there is nothing to analyze — same fields,
143
141
  // honest reason. Views render this instead of inventing zeros.
144
142
  export function unavailableHistory(reason) {
145
- return { available: false, reason };
143
+ return { available: false, reason };
146
144
  }
145
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/shared/analyzer/history.ts"],"names":[],"mappings":"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","sourcesContent":["// Git history analysis: churn, authorship, the hotspot cross-tab, and\n// temporal co-change coupling. Pure — the commits arrive as plain data from an\n// injected provider (the server's `gitLog`), exactly as `scanRepo` takes files\n// through `FileSource`. Nothing here knows git exists.\n//\n// The unit of history is a commit: { hash, author: { name, email }, date, files }.\n// Everything is keyed on file path, which is already the join key the rest of\n// the engine speaks — complexity comes over from scan.files, structural edges\n// from scan.edges, and the two views of \"these change together\" sit side by side.\n\nimport { baseName } from './pathUtil.js';\n\n// Commits touching more files than this are skipped for pair counting, not for\n// churn — a 900-file reformat or a mass rename would otherwise contribute\n// C(900,2) ≈ 400k pairs of noise to co-change while saying nothing about\n// coupling. Churn still counts them; every file in them was really touched.\nconst MAX_COMMIT_FILES_FOR_PAIRS = 50;\n\n// Once this many distinct pairs are tracked, new pairs stop being recorded and\n// only existing ones keep counting. A hard bound on memory for repos with long\n// histories of small commits; the top of the list is decided well before this.\nconst MAX_TRACKED_PAIRS = 5000;\n\nexport function analyzeHistory(scan, commits, opts: Record<string, any> = {}) {\n const totalCommits = opts.totalCommits ?? commits.length;\n const truncated = totalCommits > commits.length;\n\n // ---- per-file rollup -----------------------------------------------------\n // One pass over every commit's file list. Authors are identified by email —\n // names collide and change; the email is what git itself keys identity on.\n const churn = new Map(); // path -> commit count\n const authorsOf = new Map(); // path -> Map(email -> display name)\n const firstSeen = new Map(); // path -> earliest commit date (ISO strings sort)\n const lastTouched = new Map();\n const authorCommits = new Map(); // email -> { name, commits }\n let pathsGone = 0;\n\n for (const c of commits) {\n const date = c.date || '';\n const known = authorCommits.get(c.author?.email);\n if (known) known.commits++;\n else if (c.author?.email) authorCommits.set(c.author.email, { name: c.author.name || c.author.email, commits: 1 });\n\n for (const p of c.files || []) {\n churn.set(p, (churn.get(p) || 0) + 1);\n if (!firstSeen.has(p) || date < firstSeen.get(p)) firstSeen.set(p, date);\n if (!lastTouched.has(p) || date > lastTouched.get(p)) lastTouched.set(p, date);\n let byEmail = authorsOf.get(p);\n if (!byEmail) { byEmail = new Map(); authorsOf.set(p, byEmail); }\n if (!byEmail.has(c.author?.email)) byEmail.set(c.author?.email, c.author?.name || c.author?.email || '?');\n }\n }\n\n // ---- join with the scan ---------------------------------------------------\n // Complexity lives on scan.files; history paths that are not in the scan are\n // files deleted or renamed inside the window. They had churn once — counted,\n // then set aside rather than silently mixed into rankings of files that no\n // longer exist.\n const cxOf = new Map<string, number>(scan.files.map((f) => [f.path, f.complexity || 1]));\n for (const p of churn.keys()) if (!cxOf.has(p)) pathsGone++;\n\n const live = [...churn.entries()].filter(([p]) => cxOf.has(p));\n const maxChurn = Math.max(1, ...live.map(([, n]) => n));\n const maxCx = Math.max(1, ...live.map(([p]) => cxOf.get(p)));\n\n const perFile = live.map(([p, n]) => {\n const authors = authorsOf.get(p).size;\n return {\n path: p,\n name: baseName(p),\n churn: n,\n authors,\n solo: authors === 1,\n firstSeen: firstSeen.get(p),\n lastTouched: lastTouched.get(p),\n complexity: cxOf.get(p),\n // The cross-tab: both axes normalized against the repo's own worst, so\n // the score reads \"how far up both columns at once\" and a file maxing\n // one axis but not the other cannot outrank one high on both.\n hotspot: Math.round(100 * (n / maxChurn) * (cxOf.get(p) / maxCx)),\n };\n });\n perFile.sort((a, b) => b.hotspot - a.hotspot || b.churn - a.churn || a.path.localeCompare(b.path));\n\n const byPath: Record<string, any> = {};\n for (const row of perFile) byPath[row.path] = row;\n const soloFiles = perFile.filter((r) => r.solo && r.churn >= 3).length;\n\n const dates = commits.map((c) => c.date).filter(Boolean);\n\n return {\n available: true,\n commitCount: commits.length,\n totalCommits,\n truncated,\n // The raw commit list, not just the rollups. The insights view draws a\n // 52-week heatmap and a punch card from per-commit dates; without the\n // original array, that view rendered an empty calendar even when history\n // was fully available. The cost is the same parsed commits we already hold\n // — `parseGitLog` capped at 2,000 — so duplication here is honest.\n commits,\n authors: [...authorCommits.values()].sort((a, b) => b.commits - a.commits),\n firstCommitAt: dates.length ? dates.reduce((a, b) => (a < b ? a : b)) : null,\n lastCommitAt: dates.length ? dates.reduce((a, b) => (a > b ? a : b)) : null,\n perFile,\n byPath,\n soloFiles,\n coChanged: coChangePairs(commits, new Set(scan.edges.map((e) => e.from + '->' + e.to))),\n pathsGone,\n };\n}\n\n// Files that keep turning up in the same commit without importing each other.\n// The structural coupling matrix already shows what imports what; this is the\n// contrast — changes that travel together for reasons the import graph does\n// not know about (shared schema, feature pairs, copy-paste siblings).\nfunction coChangePairs(commits, structuralEdges) {\n const pairs = new Map(); // 'a|b' (sorted) -> count\n\n for (const c of commits) {\n const files = c.files || [];\n if (files.length < 2 || files.length > MAX_COMMIT_FILES_FOR_PAIRS) continue;\n for (let i = 0; i < files.length; i++) {\n for (let j = i + 1; j < files.length; j++) {\n const a = files[i] < files[j] ? files[i] : files[j];\n const b = files[i] < files[j] ? files[j] : files[i];\n if (structuralEdges.has(a + '->' + b) || structuralEdges.has(b + '->' + a)) continue;\n const key = a + '|' + b;\n const seen = pairs.get(key);\n if (seen) seen.count++;\n else if (pairs.size < MAX_TRACKED_PAIRS) pairs.set(key, { a, b, count: 1 });\n }\n }\n }\n\n return [...pairs.values()]\n .filter((p) => p.count >= 2) // once is coincidence; the plan is about habits\n .sort((x, y) => y.count - x.count || x.a.localeCompare(y.a))\n .slice(0, 20);\n}\n\n// The shape callers should hold when there is nothing to analyze — same fields,\n// honest reason. Views render this instead of inventing zeros.\nexport function unavailableHistory(reason) {\n return { available: false, reason };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ /** Parse TypeScript's JSON-with-comments configs without altering quoted paths. */
2
+ export declare function parseJsonConfig(text: string): unknown;
@@ -0,0 +1,61 @@
1
+ /** Parse TypeScript's JSON-with-comments configs without altering quoted paths. */
2
+ export function parseJsonConfig(text) {
3
+ const characters = text.split('');
4
+ let quoted = false;
5
+ for (let i = 0; i < text.length; i++) {
6
+ const character = text[i];
7
+ if (quoted) {
8
+ if (character === '\\')
9
+ i++;
10
+ else if (character === '"')
11
+ quoted = false;
12
+ continue;
13
+ }
14
+ if (character === '"') {
15
+ quoted = true;
16
+ continue;
17
+ }
18
+ if (character === '/' && text[i + 1] === '/') {
19
+ while (i < text.length && text[i] !== '\n')
20
+ characters[i++] = ' ';
21
+ }
22
+ else if (character === '/' && text[i + 1] === '*') {
23
+ characters[i++] = ' ';
24
+ characters[i++] = ' ';
25
+ while (i < text.length && !(text[i] === '*' && text[i + 1] === '/')) {
26
+ if (text[i] !== '\n' && text[i] !== '\r')
27
+ characters[i] = ' ';
28
+ i++;
29
+ }
30
+ if (i >= text.length)
31
+ throw new SyntaxError('Unterminated config comment.');
32
+ characters[i++] = ' ';
33
+ characters[i] = ' ';
34
+ }
35
+ }
36
+ // JSONC also accepts trailing commas. Handle them only outside strings.
37
+ quoted = false;
38
+ for (let i = 0; i < characters.length; i++) {
39
+ const character = characters[i];
40
+ if (quoted) {
41
+ if (character === '\\')
42
+ i++;
43
+ else if (character === '"')
44
+ quoted = false;
45
+ continue;
46
+ }
47
+ if (character === '"') {
48
+ quoted = true;
49
+ continue;
50
+ }
51
+ if (character !== ',')
52
+ continue;
53
+ let next = i + 1;
54
+ while (next < characters.length && /\s/.test(characters[next]))
55
+ next++;
56
+ if (characters[next] === '}' || characters[next] === ']')
57
+ characters[i] = ' ';
58
+ }
59
+ return JSON.parse(characters.join(''));
60
+ }
61
+ //# sourceMappingURL=jsonConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonConfig.js","sourceRoot":"","sources":["../../src/shared/analyzer/jsonConfig.ts"],"names":[],"mappings":"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","sourcesContent":["/** Parse TypeScript's JSON-with-comments configs without altering quoted paths. */\nexport function parseJsonConfig(text: string): unknown {\n const characters = text.split('');\n let quoted = false;\n for (let i = 0; i < text.length; i++) {\n const character = text[i];\n if (quoted) {\n if (character === '\\\\') i++;\n else if (character === '\"') quoted = false;\n continue;\n }\n if (character === '\"') { quoted = true; continue; }\n if (character === '/' && text[i + 1] === '/') {\n while (i < text.length && text[i] !== '\\n') characters[i++] = ' ';\n } else if (character === '/' && text[i + 1] === '*') {\n characters[i++] = ' ';\n characters[i++] = ' ';\n while (i < text.length && !(text[i] === '*' && text[i + 1] === '/')) {\n if (text[i] !== '\\n' && text[i] !== '\\r') characters[i] = ' ';\n i++;\n }\n if (i >= text.length) throw new SyntaxError('Unterminated config comment.');\n characters[i++] = ' ';\n characters[i] = ' ';\n }\n }\n // JSONC also accepts trailing commas. Handle them only outside strings.\n quoted = false;\n for (let i = 0; i < characters.length; i++) {\n const character = characters[i];\n if (quoted) {\n if (character === '\\\\') i++;\n else if (character === '\"') quoted = false;\n continue;\n }\n if (character === '\"') { quoted = true; continue; }\n if (character !== ',') continue;\n let next = i + 1;\n while (next < characters.length && /\\s/.test(characters[next])) next++;\n if (characters[next] === '}' || characters[next] === ']') characters[i] = ' ';\n }\n return JSON.parse(characters.join('')) as unknown;\n}\n"]}
@@ -0,0 +1,26 @@
1
+ export declare const extensions: string[];
2
+ export declare function analyze(source: any, path: any): {
3
+ imports: any[];
4
+ exports: {
5
+ name: any;
6
+ kind: string;
7
+ }[];
8
+ functions: any[];
9
+ classes: any[];
10
+ hasMain: boolean;
11
+ namespace: any;
12
+ };
13
+ export declare function sourceRootFor(fromPath: any, namespace: any): string;
14
+ export declare function resolveImport(spec: any, fromPath: any, has: any, context?: Record<string, any>, meta?: Record<string, any>): {
15
+ path?: undefined;
16
+ unresolved: any;
17
+ packageDir?: undefined;
18
+ } | {
19
+ unresolved?: undefined;
20
+ path: string;
21
+ packageDir?: undefined;
22
+ } | {
23
+ path?: undefined;
24
+ unresolved?: undefined;
25
+ packageDir: any;
26
+ };
@@ -8,54 +8,45 @@
8
8
  // directory and the scanner links to every file in it — the same shape Go uses
9
9
  // for packages.
10
10
  import { blankComments, lineCounter } from '../util.js';
11
-
12
11
  export const extensions = ['.cs'];
13
-
14
12
  const NAMESPACE_RE = /^\s*namespace\s+([A-Za-z0-9_.]+)\s*[;{]/m;
15
-
16
13
  export function analyze(source, path) {
17
- const clean = blankComments(source);
18
- const lineAt = lineCounter(clean);
19
-
20
- // The file's own namespace. Captured first because every import is resolved
21
- // relative to it — this declaration is the only place the root is written down.
22
- // Block-scoped namespaces (`namespace A.B { }`) are the norm, and the regex
23
- // accepts both the `;` and `{` forms.
24
- const namespace = (clean.match(NAMESPACE_RE) || [])[1] || '';
25
-
26
- const imports = [];
27
- // `using static A.B.C;` names a type (and optionally a member of it); plain
28
- // `using A.B;` names a namespace. The distinction decides whether we look for
29
- // a file or a directory.
30
- for (const m of clean.matchAll(/\busing\s+(static\s+)?([A-Za-z0-9_.]+)\s*;/g)) {
31
- imports.push({ spec: m[2], static: !!m[1], namespace, line: lineAt(m.index) });
32
- }
33
- // `using X = Y;` aliases and global usings are out of scope; a spec that fails
34
- // to resolve is reported as unresolved rather than guessed at.
35
-
36
- const classes = [];
37
- for (const m of clean.matchAll(/(\[[^\]]+\]\s*)*\b(?:public\s+|private\s+|protected\s+|internal\s+)*(?:abstract\s+|sealed\s+|static\s+|partial\s+)*(?:class|interface|struct|record|enum)\s+([a-zA-Z0-9_]+)/g)) {
38
- const attributes = [];
39
- if (m[1]) {
40
- for (const am of m[1].matchAll(/\[([A-Za-z0-9_]+)/g)) {
41
- attributes.push(am[1]);
42
- }
14
+ const clean = blankComments(source);
15
+ const lineAt = lineCounter(clean);
16
+ // The file's own namespace. Captured first because every import is resolved
17
+ // relative to it — this declaration is the only place the root is written down.
18
+ // Block-scoped namespaces (`namespace A.B { }`) are the norm, and the regex
19
+ // accepts both the `;` and `{` forms.
20
+ const namespace = (clean.match(NAMESPACE_RE) || [])[1] || '';
21
+ const imports = [];
22
+ // `using static A.B.C;` names a type (and optionally a member of it); plain
23
+ // `using A.B;` names a namespace. The distinction decides whether we look for
24
+ // a file or a directory.
25
+ for (const m of clean.matchAll(/\busing\s+(static\s+)?([A-Za-z0-9_.]+)\s*;/g)) {
26
+ imports.push({ spec: m[2], static: !!m[1], namespace, line: lineAt(m.index) });
43
27
  }
44
- classes.push({ name: m[2], attributes, line: lineAt(m.index) });
45
- }
46
-
47
- const hasMain = /static\s+(?:async\s+Task|void|int|async\s+Task<int>)\s+Main\s*\(/.test(clean);
48
-
49
- return {
50
- imports,
51
- exports: classes.map(c => ({ name: c.name, kind: 'class' })),
52
- functions: [],
53
- classes,
54
- hasMain,
55
- namespace,
56
- };
28
+ // `using X = Y;` aliases and global usings are out of scope; a spec that fails
29
+ // to resolve is reported as unresolved rather than guessed at.
30
+ const classes = [];
31
+ for (const m of clean.matchAll(/(\[[^\]]+\]\s*)*\b(?:public\s+|private\s+|protected\s+|internal\s+)*(?:abstract\s+|sealed\s+|static\s+|partial\s+)*(?:class|interface|struct|record|enum)\s+([a-zA-Z0-9_]+)/g)) {
32
+ const attributes = [];
33
+ if (m[1]) {
34
+ for (const am of m[1].matchAll(/\[([A-Za-z0-9_]+)/g)) {
35
+ attributes.push(am[1]);
36
+ }
37
+ }
38
+ classes.push({ name: m[2], attributes, line: lineAt(m.index) });
39
+ }
40
+ const hasMain = /static\s+(?:async\s+Task|void|int|async\s+Task<int>)\s+Main\s*\(/.test(clean);
41
+ return {
42
+ imports,
43
+ exports: classes.map(c => ({ name: c.name, kind: 'class' })),
44
+ functions: [],
45
+ classes,
46
+ hasMain,
47
+ namespace,
48
+ };
57
49
  }
58
-
59
50
  // A C# `using` is resolved by *path suffix*, not by a root prefix. See
60
51
  // `resolveImport` below for why that distinction matters — it is the whole
61
52
  // difference between C# and Java, and getting it backwards drops every import.
@@ -64,51 +55,55 @@ export function analyze(source, path) {
64
55
  // where a project *does* mirror the full namespace (`Acme/Services/User.cs`).
65
56
  // It is a fallback, not the main path.
66
57
  export function sourceRootFor(fromPath, namespace) {
67
- if (!namespace) return null;
68
- const suffix = namespace.replace(/\./g, '/');
69
- const normalized = String(fromPath).replace(/\\/g, '/');
70
- const nested = normalized.lastIndexOf('/' + suffix + '/');
71
- if (nested >= 0) return normalized.slice(0, nested + 1);
72
- if (normalized === suffix || normalized.startsWith(suffix + '/')) return '';
73
- return null;
58
+ if (!namespace)
59
+ return null;
60
+ const suffix = namespace.replace(/\./g, '/');
61
+ const normalized = String(fromPath).replace(/\\/g, '/');
62
+ const nested = normalized.lastIndexOf('/' + suffix + '/');
63
+ if (nested >= 0)
64
+ return normalized.slice(0, nested + 1);
65
+ if (normalized === suffix || normalized.startsWith(suffix + '/'))
66
+ return '';
67
+ return null;
74
68
  }
75
-
76
69
  export function resolveImport(spec, fromPath, has, context = {}, meta = {}) {
77
- const parts = spec.split('.').filter(Boolean);
78
- const findDir = (segments) => (segments.length ? context.findDirEndingWith?.(segments.join('/')) : null);
79
- if (!parts.length) return { unresolved: spec };
80
-
81
- // A C# `using` is ambiguous from the string alone: in `using Acme.Models;`,
82
- // `Models` might be a namespace (link its directory) or a type (link the
83
- // file). Both readings are tried, most specific first.
84
- //
85
- // The other half of the puzzle is that C# resolves by *path suffix*, not by a
86
- // root prefix the way Java does. `namespace Acme.Services` conventionally
87
- // lives in `src/Services/`: the folders mirror the namespace, but the leading
88
- // `Acme` — the project or company root — is not a directory. So the namespace
89
- // segments are matched against the *tail* of a real directory path, which is
90
- // what `findDirEndingWith` answers. Stripping the whole namespace instead, the
91
- // Java approach, matches nothing here and silently drops every import.
92
-
93
- // Reading 1: the last segment is a type. Find the directory holding its
94
- // namespace, then the file named after it.
95
- const namespaceParts = parts.slice(0, -1);
96
- for (let take = namespaceParts.length; take > 0; take -= 1) {
97
- const dir = findDir(namespaceParts.slice(namespaceParts.length - take));
98
- if (!dir) continue;
99
- const exact = dir + '/' + parts[parts.length - 1] + '.cs';
100
- if (has(exact)) return { path: exact };
101
- if (meta.static) return { unresolved: spec }; // `using static A.B.C;` is always a type
102
- }
103
-
104
- // Reading 2: the whole spec is a namespace, so link its directory.
105
- for (let take = parts.length; take > 0; take -= 1) {
106
- const dir = findDir(parts.slice(parts.length - take));
107
- if (dir) return { packageDir: dir };
108
- }
109
-
110
- // The BCL (`System`, `System.Collections.Generic`) and every NuGet package land
111
- // here. Staying unresolved is the honest answer: a file we invent would be a
112
- // node in the graph that does not exist.
113
- return { unresolved: spec };
70
+ const parts = spec.split('.').filter(Boolean);
71
+ const findDir = (segments) => (segments.length ? context.findDirEndingWith?.(segments.join('/')) : null);
72
+ if (!parts.length)
73
+ return { unresolved: spec };
74
+ // A C# `using` is ambiguous from the string alone: in `using Acme.Models;`,
75
+ // `Models` might be a namespace (link its directory) or a type (link the
76
+ // file). Both readings are tried, most specific first.
77
+ //
78
+ // The other half of the puzzle is that C# resolves by *path suffix*, not by a
79
+ // root prefix the way Java does. `namespace Acme.Services` conventionally
80
+ // lives in `src/Services/`: the folders mirror the namespace, but the leading
81
+ // `Acme` — the project or company root — is not a directory. So the namespace
82
+ // segments are matched against the *tail* of a real directory path, which is
83
+ // what `findDirEndingWith` answers. Stripping the whole namespace instead, the
84
+ // Java approach, matches nothing here and silently drops every import.
85
+ // Reading 1: the last segment is a type. Find the directory holding its
86
+ // namespace, then the file named after it.
87
+ const namespaceParts = parts.slice(0, -1);
88
+ for (let take = namespaceParts.length; take > 0; take -= 1) {
89
+ const dir = findDir(namespaceParts.slice(namespaceParts.length - take));
90
+ if (!dir)
91
+ continue;
92
+ const exact = dir + '/' + parts[parts.length - 1] + '.cs';
93
+ if (has(exact))
94
+ return { path: exact };
95
+ if (meta.static)
96
+ return { unresolved: spec }; // `using static A.B.C;` is always a type
97
+ }
98
+ // Reading 2: the whole spec is a namespace, so link its directory.
99
+ for (let take = parts.length; take > 0; take -= 1) {
100
+ const dir = findDir(parts.slice(parts.length - take));
101
+ if (dir)
102
+ return { packageDir: dir };
103
+ }
104
+ // The BCL (`System`, `System.Collections.Generic`) and every NuGet package land
105
+ // here. Staying unresolved is the honest answer: a file we invent would be a
106
+ // node in the graph that does not exist.
107
+ return { unresolved: spec };
114
108
  }
109
+ //# sourceMappingURL=csharp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csharp.js","sourceRoot":"","sources":["../../../src/shared/analyzer/languages/csharp.ts"],"names":[],"mappings":"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","sourcesContent":["// C# analyzer\n//\n// C# is namespace-rooted exactly as Java is package-rooted: a file's path is its\n// namespace spelled with slashes, under a project root. The difference that\n// matters is the import. Java's `import a.b.C;` names a *class*, so one path\n// answers it; C#'s `using A.B;` names a *namespace*, and the classes inside it\n// are not knowable from the import string. So a namespace import resolves to a\n// directory and the scanner links to every file in it — the same shape Go uses\n// for packages.\nimport { blankComments, lineCounter } from '../util.js';\n\nexport const extensions = ['.cs'];\n\nconst NAMESPACE_RE = /^\\s*namespace\\s+([A-Za-z0-9_.]+)\\s*[;{]/m;\n\nexport function analyze(source, path) {\n const clean = blankComments(source);\n const lineAt = lineCounter(clean);\n\n // The file's own namespace. Captured first because every import is resolved\n // relative to it — this declaration is the only place the root is written down.\n // Block-scoped namespaces (`namespace A.B { }`) are the norm, and the regex\n // accepts both the `;` and `{` forms.\n const namespace = (clean.match(NAMESPACE_RE) || [])[1] || '';\n\n const imports = [];\n // `using static A.B.C;` names a type (and optionally a member of it); plain\n // `using A.B;` names a namespace. The distinction decides whether we look for\n // a file or a directory.\n for (const m of clean.matchAll(/\\busing\\s+(static\\s+)?([A-Za-z0-9_.]+)\\s*;/g)) {\n imports.push({ spec: m[2], static: !!m[1], namespace, line: lineAt(m.index) });\n }\n // `using X = Y;` aliases and global usings are out of scope; a spec that fails\n // to resolve is reported as unresolved rather than guessed at.\n\n const classes = [];\n for (const m of clean.matchAll(/(\\[[^\\]]+\\]\\s*)*\\b(?:public\\s+|private\\s+|protected\\s+|internal\\s+)*(?:abstract\\s+|sealed\\s+|static\\s+|partial\\s+)*(?:class|interface|struct|record|enum)\\s+([a-zA-Z0-9_]+)/g)) {\n const attributes = [];\n if (m[1]) {\n for (const am of m[1].matchAll(/\\[([A-Za-z0-9_]+)/g)) {\n attributes.push(am[1]);\n }\n }\n classes.push({ name: m[2], attributes, line: lineAt(m.index) });\n }\n\n const hasMain = /static\\s+(?:async\\s+Task|void|int|async\\s+Task<int>)\\s+Main\\s*\\(/.test(clean);\n\n return {\n imports,\n exports: classes.map(c => ({ name: c.name, kind: 'class' })),\n functions: [],\n classes,\n hasMain,\n namespace,\n };\n}\n\n// A C# `using` is resolved by *path suffix*, not by a root prefix. See\n// `resolveImport` below for why that distinction matters — it is the whole\n// difference between C# and Java, and getting it backwards drops every import.\n//\n// `sourceRootFor` is kept and exported because it is the answer for the layouts\n// where a project *does* mirror the full namespace (`Acme/Services/User.cs`).\n// It is a fallback, not the main path.\nexport function sourceRootFor(fromPath, namespace) {\n if (!namespace) return null;\n const suffix = namespace.replace(/\\./g, '/');\n const normalized = String(fromPath).replace(/\\\\/g, '/');\n const nested = normalized.lastIndexOf('/' + suffix + '/');\n if (nested >= 0) return normalized.slice(0, nested + 1);\n if (normalized === suffix || normalized.startsWith(suffix + '/')) return '';\n return null;\n}\n\nexport function resolveImport(spec, fromPath, has, context: Record<string, any> = {}, meta: Record<string, any> = {}) {\n const parts = spec.split('.').filter(Boolean);\n const findDir = (segments) => (segments.length ? context.findDirEndingWith?.(segments.join('/')) : null);\n if (!parts.length) return { unresolved: spec };\n\n // A C# `using` is ambiguous from the string alone: in `using Acme.Models;`,\n // `Models` might be a namespace (link its directory) or a type (link the\n // file). Both readings are tried, most specific first.\n //\n // The other half of the puzzle is that C# resolves by *path suffix*, not by a\n // root prefix the way Java does. `namespace Acme.Services` conventionally\n // lives in `src/Services/`: the folders mirror the namespace, but the leading\n // `Acme` — the project or company root — is not a directory. So the namespace\n // segments are matched against the *tail* of a real directory path, which is\n // what `findDirEndingWith` answers. Stripping the whole namespace instead, the\n // Java approach, matches nothing here and silently drops every import.\n\n // Reading 1: the last segment is a type. Find the directory holding its\n // namespace, then the file named after it.\n const namespaceParts = parts.slice(0, -1);\n for (let take = namespaceParts.length; take > 0; take -= 1) {\n const dir = findDir(namespaceParts.slice(namespaceParts.length - take));\n if (!dir) continue;\n const exact = dir + '/' + parts[parts.length - 1] + '.cs';\n if (has(exact)) return { path: exact };\n if (meta.static) return { unresolved: spec }; // `using static A.B.C;` is always a type\n }\n\n // Reading 2: the whole spec is a namespace, so link its directory.\n for (let take = parts.length; take > 0; take -= 1) {\n const dir = findDir(parts.slice(parts.length - take));\n if (dir) return { packageDir: dir };\n }\n\n // The BCL (`System`, `System.Collections.Generic`) and every NuGet package land\n // here. Staying unresolved is the honest answer: a file we invent would be a\n // node in the graph that does not exist.\n return { unresolved: spec };\n}\n"]}