codebase-onboarder 0.5.0 → 0.7.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 (448) hide show
  1. package/README.md +196 -47
  2. package/bin/build-if-source.js +23 -0
  3. package/cli/commands.d.ts +26 -0
  4. package/cli/commands.js +836 -811
  5. package/cli/commands.js.map +1 -0
  6. package/cli/explorer/advanced.d.ts +14 -0
  7. package/cli/explorer/advanced.js +449 -0
  8. package/cli/explorer/advanced.js.map +1 -0
  9. package/cli/explorer/app.d.ts +1 -0
  10. package/cli/explorer/app.js +396 -229
  11. package/cli/explorer/app.js.map +1 -0
  12. package/cli/explorer/assistant.d.ts +9 -0
  13. package/cli/explorer/assistant.js +58 -0
  14. package/cli/explorer/assistant.js.map +1 -0
  15. package/cli/explorer/commands.d.ts +17 -0
  16. package/cli/explorer/commands.js +400 -162
  17. package/cli/explorer/commands.js.map +1 -0
  18. package/cli/explorer/featureViews.d.ts +124 -0
  19. package/cli/explorer/featureViews.js +179 -0
  20. package/cli/explorer/featureViews.js.map +1 -0
  21. package/cli/explorer/github.d.ts +21 -0
  22. package/cli/explorer/github.js +73 -0
  23. package/cli/explorer/github.js.map +1 -0
  24. package/cli/explorer/graphs.d.ts +7 -0
  25. package/cli/explorer/graphs.js +173 -0
  26. package/cli/explorer/graphs.js.map +1 -0
  27. package/cli/explorer/picker.d.ts +22 -0
  28. package/cli/explorer/picker.js +150 -0
  29. package/cli/explorer/picker.js.map +1 -0
  30. package/cli/explorer/report.d.ts +85 -0
  31. package/cli/explorer/report.js +60 -0
  32. package/cli/explorer/report.js.map +1 -0
  33. package/cli/explorer/session.d.ts +449 -0
  34. package/cli/explorer/session.js +184 -95
  35. package/cli/explorer/session.js.map +1 -0
  36. package/cli/explorer/views.d.ts +19 -0
  37. package/cli/explorer/views.js +496 -412
  38. package/cli/explorer/views.js.map +1 -0
  39. package/cli/explorer/wrap.d.ts +1 -0
  40. package/cli/explorer/wrap.js +33 -0
  41. package/cli/explorer/wrap.js.map +1 -0
  42. package/cli/main.d.ts +1 -0
  43. package/cli/main.js +235 -138
  44. package/cli/main.js.map +1 -0
  45. package/cli/prompt.d.ts +5 -0
  46. package/cli/prompt.js +84 -80
  47. package/cli/prompt.js.map +1 -0
  48. package/cli/scanOptions.d.ts +2 -0
  49. package/cli/scanOptions.js +11 -0
  50. package/cli/scanOptions.js.map +1 -0
  51. package/cli/ui.d.ts +33 -0
  52. package/cli/ui.js +55 -35
  53. package/cli/ui.js.map +1 -0
  54. package/cli/wizard.d.ts +187 -0
  55. package/cli/wizard.js +304 -284
  56. package/cli/wizard.js.map +1 -0
  57. package/package.json +15 -4
  58. package/public/app.d.ts +1 -0
  59. package/public/app.js +1057 -1009
  60. package/public/app.js.map +1 -0
  61. package/public/browser.d.ts +68 -0
  62. package/public/browser.js +2 -0
  63. package/public/browser.js.map +1 -0
  64. package/public/index.html +30 -13
  65. package/public/js/about.d.ts +6 -0
  66. package/public/js/about.js +165 -172
  67. package/public/js/about.js.map +1 -0
  68. package/public/js/aiDraft.d.ts +3 -0
  69. package/public/js/aiDraft.js +116 -124
  70. package/public/js/aiDraft.js.map +1 -0
  71. package/public/js/analysisPanel.d.ts +7 -0
  72. package/public/js/analysisPanel.js +166 -166
  73. package/public/js/analysisPanel.js.map +1 -0
  74. package/public/js/analysisReport.d.ts +38 -0
  75. package/public/js/analysisReport.js +105 -110
  76. package/public/js/analysisReport.js.map +1 -0
  77. package/public/js/api.d.ts +26 -0
  78. package/public/js/api.js +176 -167
  79. package/public/js/api.js.map +1 -0
  80. package/public/js/atlas.d.ts +6 -0
  81. package/public/js/atlas.js +50 -58
  82. package/public/js/atlas.js.map +1 -0
  83. package/public/js/blameView.d.ts +2 -0
  84. package/public/js/blameView.js +36 -37
  85. package/public/js/blameView.js.map +1 -0
  86. package/public/js/codeTab.d.ts +3 -0
  87. package/public/js/codeTab.js +175 -180
  88. package/public/js/codeTab.js.map +1 -0
  89. package/public/js/codeViewer.d.ts +5 -0
  90. package/public/js/codeViewer.js +162 -150
  91. package/public/js/codeViewer.js.map +1 -0
  92. package/public/js/components/FileChip.d.ts +9 -0
  93. package/public/js/components/FileChip.js +45 -49
  94. package/public/js/components/FileChip.js.map +1 -0
  95. package/public/js/components/MetricSparkline.d.ts +7 -0
  96. package/public/js/components/MetricSparkline.js +35 -44
  97. package/public/js/components/MetricSparkline.js.map +1 -0
  98. package/public/js/components/RiskBadge.d.ts +9 -0
  99. package/public/js/components/RiskBadge.js +55 -63
  100. package/public/js/components/RiskBadge.js.map +1 -0
  101. package/public/js/deepAnalysisView.d.ts +99 -0
  102. package/public/js/deepAnalysisView.js +282 -302
  103. package/public/js/deepAnalysisView.js.map +1 -0
  104. package/public/js/diagramPane.d.ts +8 -0
  105. package/public/js/diagramPane.js +133 -135
  106. package/public/js/diagramPane.js.map +1 -0
  107. package/public/js/diffView.d.ts +6 -0
  108. package/public/js/diffView.js +222 -209
  109. package/public/js/diffView.js.map +1 -0
  110. package/public/js/docsView.d.ts +2 -0
  111. package/public/js/docsView.js +441 -442
  112. package/public/js/docsView.js.map +1 -0
  113. package/public/js/dom.d.ts +189 -0
  114. package/public/js/dom.js +5 -0
  115. package/public/js/dom.js.map +1 -0
  116. package/public/js/fileSourceBrowser.d.ts +5 -0
  117. package/public/js/fileSourceBrowser.js +33 -41
  118. package/public/js/fileSourceBrowser.js.map +1 -0
  119. package/public/js/flameGraph.d.ts +5 -0
  120. package/public/js/flameGraph.js +62 -72
  121. package/public/js/flameGraph.js.map +1 -0
  122. package/public/js/forceGraph.d.ts +10 -0
  123. package/public/js/forceGraph.js +581 -556
  124. package/public/js/forceGraph.js.map +1 -0
  125. package/public/js/heatmap.d.ts +4 -0
  126. package/public/js/heatmap.js +142 -164
  127. package/public/js/heatmap.js.map +1 -0
  128. package/public/js/highlight.d.ts +2 -0
  129. package/public/js/highlight.js +116 -107
  130. package/public/js/highlight.js.map +1 -0
  131. package/public/js/html.d.ts +2 -0
  132. package/public/js/html.js +14 -44
  133. package/public/js/html.js.map +1 -0
  134. package/public/js/insightsView.d.ts +5 -0
  135. package/public/js/insightsView.js +93 -111
  136. package/public/js/insightsView.js.map +1 -0
  137. package/public/js/inspector.d.ts +37 -0
  138. package/public/js/inspector.js +416 -445
  139. package/public/js/inspector.js.map +1 -0
  140. package/public/js/llm.d.ts +113 -0
  141. package/public/js/llm.js +233 -272
  142. package/public/js/llm.js.map +1 -0
  143. package/public/js/mapView.d.ts +3 -0
  144. package/public/js/mapView.js +121 -120
  145. package/public/js/mapView.js.map +1 -0
  146. package/public/js/markdown.d.ts +3 -0
  147. package/public/js/markdown.js +84 -91
  148. package/public/js/markdown.js.map +1 -0
  149. package/public/js/mindmap.d.ts +32 -0
  150. package/public/js/mindmap.js +244 -259
  151. package/public/js/mindmap.js.map +1 -0
  152. package/public/js/mobilePanels.d.ts +5 -0
  153. package/public/js/mobilePanels.js +50 -0
  154. package/public/js/mobilePanels.js.map +1 -0
  155. package/public/js/repoFiles.d.ts +12 -0
  156. package/public/js/repoFiles.js +28 -27
  157. package/public/js/repoFiles.js.map +1 -0
  158. package/public/js/reviewView.d.ts +28 -0
  159. package/public/js/reviewView.js +256 -0
  160. package/public/js/reviewView.js.map +1 -0
  161. package/public/js/sbomView.d.ts +3 -0
  162. package/public/js/sbomView.js +59 -67
  163. package/public/js/sbomView.js.map +1 -0
  164. package/public/js/scanCache.d.ts +16 -0
  165. package/public/js/scanCache.js +67 -65
  166. package/public/js/scanCache.js.map +1 -0
  167. package/public/js/search.d.ts +7 -0
  168. package/public/js/search.js +868 -800
  169. package/public/js/search.js.map +1 -0
  170. package/public/js/searchLocal.d.ts +42 -0
  171. package/public/js/searchLocal.js +87 -0
  172. package/public/js/searchLocal.js.map +1 -0
  173. package/public/js/serverSettings.d.ts +5 -0
  174. package/public/js/serverSettings.js +153 -164
  175. package/public/js/serverSettings.js.map +1 -0
  176. package/public/js/state.d.ts +798 -0
  177. package/public/js/state.js +114 -122
  178. package/public/js/state.js.map +1 -0
  179. package/public/js/tour.d.ts +6 -0
  180. package/public/js/tour.js +5 -7
  181. package/public/js/tour.js.map +1 -0
  182. package/public/js/transitions.d.ts +2 -0
  183. package/public/js/transitions.js +9 -10
  184. package/public/js/transitions.js.map +1 -0
  185. package/public/js/tree.d.ts +12 -0
  186. package/public/js/tree.js +157 -154
  187. package/public/js/tree.js.map +1 -0
  188. package/public/js/workflowsView.d.ts +3 -0
  189. package/public/js/workflowsView.js +15 -22
  190. package/public/js/workflowsView.js.map +1 -0
  191. package/public/search.css +495 -0
  192. package/public/styles.css +163 -346
  193. package/public/workbench.css +166 -0
  194. package/server/apiAuth.d.ts +3 -0
  195. package/server/apiAuth.js +18 -20
  196. package/server/apiAuth.js.map +1 -0
  197. package/server/apiDiff.d.ts +2 -0
  198. package/server/apiDiff.js +20 -18
  199. package/server/apiDiff.js.map +1 -0
  200. package/server/apiDocs.d.ts +2 -0
  201. package/server/apiDocs.js +38 -40
  202. package/server/apiDocs.js.map +1 -0
  203. package/server/apiFile.d.ts +1 -0
  204. package/server/apiFile.js +14 -17
  205. package/server/apiFile.js.map +1 -0
  206. package/server/apiGitBlame.d.ts +2 -0
  207. package/server/apiGitBlame.js +50 -51
  208. package/server/apiGitBlame.js.map +1 -0
  209. package/server/apiMcp.d.ts +4 -0
  210. package/server/apiMcp.js +64 -66
  211. package/server/apiMcp.js.map +1 -0
  212. package/server/apiReview.d.ts +2 -0
  213. package/server/apiReview.js +45 -0
  214. package/server/apiReview.js.map +1 -0
  215. package/server/apiScan.d.ts +5 -0
  216. package/server/apiScan.js +90 -71
  217. package/server/apiScan.js.map +1 -0
  218. package/server/apiSearch.d.ts +33 -0
  219. package/server/apiSearch.js +184 -200
  220. package/server/apiSearch.js.map +1 -0
  221. package/server/apiSettings.d.ts +4 -0
  222. package/server/apiSettings.js +84 -85
  223. package/server/apiSettings.js.map +1 -0
  224. package/server/apiTools.d.ts +3 -0
  225. package/server/apiTools.js +55 -56
  226. package/server/apiTools.js.map +1 -0
  227. package/server/auth.d.ts +5 -0
  228. package/server/auth.js +54 -51
  229. package/server/auth.js.map +1 -0
  230. package/server/config.d.ts +42 -0
  231. package/server/config.js +189 -194
  232. package/server/config.js.map +1 -0
  233. package/server/daemon.d.ts +12 -0
  234. package/server/daemon.js +124 -114
  235. package/server/daemon.js.map +1 -0
  236. package/server/fileSourceNode.d.ts +2 -0
  237. package/server/fileSourceNode.js +34 -36
  238. package/server/fileSourceNode.js.map +1 -0
  239. package/server/gitClone.d.ts +9 -0
  240. package/server/gitClone.js +59 -61
  241. package/server/gitClone.js.map +1 -0
  242. package/server/gitDiff.d.ts +36 -0
  243. package/server/gitDiff.js +271 -169
  244. package/server/gitDiff.js.map +1 -0
  245. package/server/gitHistory.d.ts +12 -0
  246. package/server/gitHistory.js +80 -80
  247. package/server/gitHistory.js.map +1 -0
  248. package/server/gitRemote.d.ts +12 -0
  249. package/server/gitRemote.js +60 -0
  250. package/server/gitRemote.js.map +1 -0
  251. package/server/htmlText.d.ts +4 -0
  252. package/server/htmlText.js +16 -23
  253. package/server/htmlText.js.map +1 -0
  254. package/server/http.d.ts +5 -0
  255. package/server/http.js +27 -30
  256. package/server/http.js.map +1 -0
  257. package/server/httpGuards.d.ts +2 -0
  258. package/server/httpGuards.js +47 -43
  259. package/server/httpGuards.js.map +1 -0
  260. package/server/https.d.ts +34 -0
  261. package/server/https.js +121 -111
  262. package/server/https.js.map +1 -0
  263. package/server/index.d.ts +40 -0
  264. package/server/index.js +139 -147
  265. package/server/index.js.map +1 -0
  266. package/server/layout.d.ts +26 -0
  267. package/server/layout.js +59 -37
  268. package/server/layout.js.map +1 -0
  269. package/server/llmProxy.d.ts +3 -0
  270. package/server/llmProxy.js +137 -135
  271. package/server/llmProxy.js.map +1 -0
  272. package/server/logger.d.ts +38 -0
  273. package/server/logger.js +198 -211
  274. package/server/logger.js.map +1 -0
  275. package/server/mcp/analysis.d.ts +29 -0
  276. package/server/mcp/analysis.js +99 -120
  277. package/server/mcp/analysis.js.map +1 -0
  278. package/server/mcp/http.d.ts +9 -0
  279. package/server/mcp/http.js +128 -137
  280. package/server/mcp/http.js.map +1 -0
  281. package/server/mcp/runner.d.ts +68 -0
  282. package/server/mcp/runner.js +208 -218
  283. package/server/mcp/runner.js.map +1 -0
  284. package/server/mcp/server.d.ts +29 -0
  285. package/server/mcp/server.js +166 -179
  286. package/server/mcp/server.js.map +1 -0
  287. package/server/mcp/standalone.d.ts +1 -0
  288. package/server/mcp/standalone.js +8 -10
  289. package/server/mcp/standalone.js.map +1 -0
  290. package/server/mcp/tools.d.ts +2020 -0
  291. package/server/mcp/tools.js +523 -574
  292. package/server/mcp/tools.js.map +1 -0
  293. package/server/paths.d.ts +3 -0
  294. package/server/paths.js +17 -15
  295. package/server/paths.js.map +1 -0
  296. package/server/pidfile.d.ts +9 -0
  297. package/server/pidfile.js +43 -45
  298. package/server/pidfile.js.map +1 -0
  299. package/server/review.d.ts +5 -0
  300. package/server/review.js +35 -0
  301. package/server/review.js.map +1 -0
  302. package/server/router.d.ts +33 -0
  303. package/server/router.js +191 -197
  304. package/server/router.js.map +1 -0
  305. package/server/scanRequest.d.ts +3 -0
  306. package/server/scanRequest.js +36 -0
  307. package/server/scanRequest.js.map +1 -0
  308. package/server/searchIndex.d.ts +17 -0
  309. package/server/searchIndex.js +83 -80
  310. package/server/searchIndex.js.map +1 -0
  311. package/server/sessions.d.ts +14 -0
  312. package/server/sessions.js +62 -70
  313. package/server/sessions.js.map +1 -0
  314. package/server/startup.d.ts +118 -0
  315. package/server/startup.js +143 -148
  316. package/server/startup.js.map +1 -0
  317. package/server/static.d.ts +6 -0
  318. package/server/static.js +28 -31
  319. package/server/static.js.map +1 -0
  320. package/server/tools/install.d.ts +4 -0
  321. package/server/tools/install.js +176 -185
  322. package/server/tools/install.js.map +1 -0
  323. package/server/tools/parse.d.ts +8 -0
  324. package/server/tools/parse.js +112 -114
  325. package/server/tools/parse.js.map +1 -0
  326. package/server/tools/platform.d.ts +9 -0
  327. package/server/tools/platform.js +49 -47
  328. package/server/tools/platform.js.map +1 -0
  329. package/server/tools/registry.d.ts +137 -0
  330. package/server/tools/registry.js +173 -172
  331. package/server/tools/registry.js.map +1 -0
  332. package/server/tools/scan.d.ts +34 -0
  333. package/server/tools/scan.js +89 -98
  334. package/server/tools/scan.js.map +1 -0
  335. package/server/tools.d.ts +34 -0
  336. package/server/tools.js +94 -107
  337. package/server/tools.js.map +1 -0
  338. package/server/tunnel.d.ts +29 -0
  339. package/server/tunnel.js +61 -66
  340. package/server/tunnel.js.map +1 -0
  341. package/shared/analyzer/docs.d.ts +16 -0
  342. package/shared/analyzer/docs.js +99 -93
  343. package/shared/analyzer/docs.js.map +1 -0
  344. package/shared/analyzer/explainLocal.d.ts +4 -0
  345. package/shared/analyzer/explainLocal.js +122 -142
  346. package/shared/analyzer/explainLocal.js.map +1 -0
  347. package/shared/analyzer/github.d.ts +37 -0
  348. package/shared/analyzer/github.js +79 -0
  349. package/shared/analyzer/github.js.map +1 -0
  350. package/shared/analyzer/graph.d.ts +41 -0
  351. package/shared/analyzer/graph.js +393 -400
  352. package/shared/analyzer/graph.js.map +1 -0
  353. package/shared/analyzer/health.d.ts +33 -0
  354. package/shared/analyzer/health.js +197 -193
  355. package/shared/analyzer/health.js.map +1 -0
  356. package/shared/analyzer/history.d.ts +29 -0
  357. package/shared/analyzer/history.js +110 -111
  358. package/shared/analyzer/history.js.map +1 -0
  359. package/shared/analyzer/jsonConfig.d.ts +2 -0
  360. package/shared/analyzer/jsonConfig.js +61 -0
  361. package/shared/analyzer/jsonConfig.js.map +1 -0
  362. package/shared/analyzer/languages/csharp.d.ts +26 -0
  363. package/shared/analyzer/languages/csharp.js +83 -88
  364. package/shared/analyzer/languages/csharp.js.map +1 -0
  365. package/shared/analyzer/languages/generic.d.ts +23 -0
  366. package/shared/analyzer/languages/generic.js +94 -105
  367. package/shared/analyzer/languages/generic.js.map +1 -0
  368. package/shared/analyzer/languages/go.d.ts +24 -0
  369. package/shared/analyzer/languages/go.js +45 -54
  370. package/shared/analyzer/languages/go.js.map +1 -0
  371. package/shared/analyzer/languages/index.d.ts +6 -0
  372. package/shared/analyzer/languages/index.js +19 -20
  373. package/shared/analyzer/languages/index.js.map +1 -0
  374. package/shared/analyzer/languages/java.d.ts +20 -0
  375. package/shared/analyzer/languages/java.js +73 -78
  376. package/shared/analyzer/languages/java.js.map +1 -0
  377. package/shared/analyzer/languages/javascript.d.ts +12 -0
  378. package/shared/analyzer/languages/javascript.js +258 -209
  379. package/shared/analyzer/languages/javascript.js.map +1 -0
  380. package/shared/analyzer/languages/python.d.ts +23 -0
  381. package/shared/analyzer/languages/python.js +92 -100
  382. package/shared/analyzer/languages/python.js.map +1 -0
  383. package/shared/analyzer/languages/rust.d.ts +17 -0
  384. package/shared/analyzer/languages/rust.js +96 -98
  385. package/shared/analyzer/languages/rust.js.map +1 -0
  386. package/shared/analyzer/languages/typescript.d.ts +11 -0
  387. package/shared/analyzer/languages/typescript.js +117 -116
  388. package/shared/analyzer/languages/typescript.js.map +1 -0
  389. package/shared/analyzer/licenses.d.ts +18 -0
  390. package/shared/analyzer/licenses.js +130 -133
  391. package/shared/analyzer/licenses.js.map +1 -0
  392. package/shared/analyzer/metrics.d.ts +20 -0
  393. package/shared/analyzer/metrics.js +112 -104
  394. package/shared/analyzer/metrics.js.map +1 -0
  395. package/shared/analyzer/pathUtil.d.ts +10 -0
  396. package/shared/analyzer/pathUtil.js +29 -35
  397. package/shared/analyzer/pathUtil.js.map +1 -0
  398. package/shared/analyzer/patterns.d.ts +11 -0
  399. package/shared/analyzer/patterns.js +231 -253
  400. package/shared/analyzer/patterns.js.map +1 -0
  401. package/shared/analyzer/scan.d.ts +62 -0
  402. package/shared/analyzer/scan.js +451 -442
  403. package/shared/analyzer/scan.js.map +1 -0
  404. package/shared/analyzer/scanControl.d.ts +11 -0
  405. package/shared/analyzer/scanControl.js +62 -0
  406. package/shared/analyzer/scanControl.js.map +1 -0
  407. package/shared/analyzer/security.d.ts +18 -0
  408. package/shared/analyzer/security.js +159 -159
  409. package/shared/analyzer/security.js.map +1 -0
  410. package/shared/analyzer/services.d.ts +5 -0
  411. package/shared/analyzer/services.js +141 -138
  412. package/shared/analyzer/services.js.map +1 -0
  413. package/shared/analyzer/stack.d.ts +6 -0
  414. package/shared/analyzer/stack.js +134 -141
  415. package/shared/analyzer/stack.js.map +1 -0
  416. package/shared/analyzer/tour.d.ts +2 -0
  417. package/shared/analyzer/tour.js +45 -53
  418. package/shared/analyzer/tour.js.map +1 -0
  419. package/shared/analyzer/util.d.ts +8 -0
  420. package/shared/analyzer/util.js +130 -76
  421. package/shared/analyzer/util.js.map +1 -0
  422. package/shared/analyzer/workflows.d.ts +8 -0
  423. package/shared/analyzer/workflows.js +139 -134
  424. package/shared/analyzer/workflows.js.map +1 -0
  425. package/shared/contracts.d.ts +250 -0
  426. package/shared/contracts.js +2 -0
  427. package/shared/contracts.js.map +1 -0
  428. package/shared/diagram/aiFacts.d.ts +35 -0
  429. package/shared/diagram/aiFacts.js +102 -105
  430. package/shared/diagram/aiFacts.js.map +1 -0
  431. package/shared/diagram/aiMermaid.d.ts +5 -0
  432. package/shared/diagram/aiMermaid.js +46 -45
  433. package/shared/diagram/aiMermaid.js.map +1 -0
  434. package/shared/diagram/atlas.d.ts +16 -0
  435. package/shared/diagram/atlas.js +51 -60
  436. package/shared/diagram/atlas.js.map +1 -0
  437. package/shared/diagram/mermaid.d.ts +43 -0
  438. package/shared/diagram/mermaid.js +348 -370
  439. package/shared/diagram/mermaid.js.map +1 -0
  440. package/shared/review/contracts.d.ts +95 -0
  441. package/shared/review/contracts.js +2 -0
  442. package/shared/review/contracts.js.map +1 -0
  443. package/shared/review/review.d.ts +10 -0
  444. package/shared/review/review.js +184 -0
  445. package/shared/review/review.js.map +1 -0
  446. package/shared/search/query.d.ts +32 -0
  447. package/shared/search/query.js +395 -388
  448. package/shared/search/query.js.map +1 -0
@@ -17,52 +17,44 @@
17
17
  // directory, re-reading every file, parsing its tokens — is gone. The
18
18
  // per-request cost is one Map lookup plus the scoring pass over matching
19
19
  // documents, which is bounded by the index size, not the repo size.
20
-
21
20
  const DEFAULTS = {
22
- // Aggregate content size. Files beyond this are not indexed, only counted.
23
- // 200 MB is enough to index the source of a large monorepo comfortably;
24
- // past that the search would be matching against vendor copies and
25
- // generated code more often than against code people wrote.
26
- maxTotalBytes: 200 * 1024 * 1024,
27
- // Per-file ceiling. Files larger than this are skipped (the scanner has
28
- // its own ceiling for the same reason).
29
- maxFileBytes: 1024 * 1024,
30
- // Reads in flight at once. Same shape as `scan.js`'s read-ahead — a file
31
- // is held in memory whole before the next one starts.
32
- width: 8,
21
+ // Aggregate content size. Files beyond this are not indexed, only counted.
22
+ // 200 MB is enough to index the source of a large monorepo comfortably;
23
+ // past that the search would be matching against vendor copies and
24
+ // generated code more often than against code people wrote.
25
+ maxTotalBytes: 200 * 1024 * 1024,
26
+ // Per-file ceiling. Files larger than this are skipped (the scanner has
27
+ // its own ceiling for the same reason).
28
+ maxFileBytes: 1024 * 1024,
29
+ // Reads in flight at once. Same shape as `scan.js`'s read-ahead — a file
30
+ // is held in memory whole before the next one starts.
31
+ width: 8,
33
32
  };
34
-
35
33
  const BINARY_HEAD_BYTES = 1000;
36
-
37
34
  function looksBinary(content) {
38
- // NUL in the first KB is a reliable, cheap heuristic for "this is not
39
- // text the search would help with". The first KB also covers the BOM and
40
- // the shebang without missing the start of the file.
41
- return content.slice(0, BINARY_HEAD_BYTES).includes('\0');
35
+ // NUL in the first KB is a reliable, cheap heuristic for "this is not
36
+ // text the search would help with". The first KB also covers the BOM and
37
+ // the shebang without missing the start of the file.
38
+ return content.slice(0, BINARY_HEAD_BYTES).includes('\0');
42
39
  }
43
-
44
40
  // Read each path's text up to width at a time. Failures are skipped, the
45
41
  // same way `scan.js:readAhead` handles them: one unreadable file should not
46
42
  // end an index build, and the caller counts it in `skipped.readFailed`.
47
43
  async function* readAhead(source, paths, width) {
48
- const inFlight = [];
49
- let next = 0;
50
- const read = (p) =>
51
- Promise.resolve()
52
- .then(() => source.read(p))
53
- .then(
54
- (text) => ({ path: p, text, failed: false }),
55
- () => ({ path: p, text: '', failed: true }),
56
- );
57
-
58
- while (next < paths.length && inFlight.length < width) inFlight.push(read(paths[next++]));
59
- while (inFlight.length) {
60
- const settled = inFlight.shift();
61
- if (next < paths.length) inFlight.push(read(paths[next++]));
62
- yield await settled;
63
- }
44
+ const inFlight = [];
45
+ let next = 0;
46
+ const read = (p) => Promise.resolve()
47
+ .then(() => source.read(p))
48
+ .then((text) => ({ path: p, text, failed: false }), () => ({ path: p, text: '', failed: true }));
49
+ while (next < paths.length && inFlight.length < width)
50
+ inFlight.push(read(paths[next++]));
51
+ while (inFlight.length) {
52
+ const settled = inFlight.shift();
53
+ if (next < paths.length)
54
+ inFlight.push(read(paths[next++]));
55
+ yield await settled;
56
+ }
64
57
  }
65
-
66
58
  // Build the search index from the file list the scanner already produced.
67
59
  // The scanner has read these files once for parsing; indexing reads them a
68
60
  // second time for tokenizing, which is the cheapest place to do it — a
@@ -71,48 +63,59 @@ async function* readAhead(source, paths, width) {
71
63
  // smallest change that closes the audit's three real concerns (first-search
72
64
  // latency, no aggregate cap, no concurrency).
73
65
  export async function buildSearchIndex(source, codeFiles, options = {}) {
74
- const opts = { ...DEFAULTS, ...options };
75
- const index = new Map();
76
- const docCounts = new Map();
77
- let totalDocs = 0;
78
- let totalBytes = 0;
79
-
80
- // Files the indexer cannot or will not index, broken down by reason. The
81
- // shape matches `scan.js:skips` so a future UI surface can render one
82
- // unified "what was left out" panel without translation.
83
- const skipped = {
84
- tooLarge: 0, // one file over maxFileBytes
85
- overCap: 0, // a later file pushed the aggregate over maxTotalBytes
86
- readFailed: 0, // the file would not read
87
- binary: 0, // NUL in the first KB
88
- noTokens: 0, // the file read, but tokenizing produced nothing useful
89
- };
90
-
91
- for await (const { path, text, failed } of readAhead(source, codeFiles, opts.width)) {
92
- if (failed) { skipped.readFailed++; continue; }
93
-
94
- if (text.length > opts.maxFileBytes) { skipped.tooLarge++; continue; }
95
- if (totalBytes + text.length > opts.maxTotalBytes) { skipped.overCap++; continue; }
96
- if (looksBinary(text)) { skipped.binary++; continue; }
97
-
98
- const tokens = text.toLowerCase().split(/\W+/).filter((t) => t.length > 1);
99
- if (!tokens.length) { skipped.noTokens++; continue; }
100
-
101
- const tf = new Map();
102
- for (const t of tokens) tf.set(t, (tf.get(t) || 0) + 1);
103
- for (const t of tf.keys()) docCounts.set(t, (docCounts.get(t) || 0) + 1);
104
-
105
- index.set(path, { tf, content: text, tokenCount: tokens.length });
106
- totalDocs++;
107
- totalBytes += text.length;
108
- }
109
-
110
- return {
111
- index,
112
- docCounts,
113
- totalDocs,
114
- totalBytes,
115
- skipped,
116
- cap: { maxFileBytes: opts.maxFileBytes, maxTotalBytes: opts.maxTotalBytes },
117
- };
66
+ const opts = { ...DEFAULTS, ...options };
67
+ const index = new Map();
68
+ const docCounts = new Map();
69
+ let totalDocs = 0;
70
+ let totalBytes = 0;
71
+ // Files the indexer cannot or will not index, broken down by reason. The
72
+ // shape matches `scan.js:skips` so a future UI surface can render one
73
+ // unified "what was left out" panel without translation.
74
+ const skipped = {
75
+ tooLarge: 0, // one file over maxFileBytes
76
+ overCap: 0, // a later file pushed the aggregate over maxTotalBytes
77
+ readFailed: 0, // the file would not read
78
+ binary: 0, // NUL in the first KB
79
+ noTokens: 0, // the file read, but tokenizing produced nothing useful
80
+ };
81
+ for await (const { path, text, failed } of readAhead(source, codeFiles, opts.width)) {
82
+ if (failed) {
83
+ skipped.readFailed++;
84
+ continue;
85
+ }
86
+ if (text.length > opts.maxFileBytes) {
87
+ skipped.tooLarge++;
88
+ continue;
89
+ }
90
+ if (totalBytes + text.length > opts.maxTotalBytes) {
91
+ skipped.overCap++;
92
+ continue;
93
+ }
94
+ if (looksBinary(text)) {
95
+ skipped.binary++;
96
+ continue;
97
+ }
98
+ const tokens = text.toLowerCase().split(/\W+/).filter((t) => t.length > 1);
99
+ if (!tokens.length) {
100
+ skipped.noTokens++;
101
+ continue;
102
+ }
103
+ const tf = new Map();
104
+ for (const t of tokens)
105
+ tf.set(t, (tf.get(t) || 0) + 1);
106
+ for (const t of tf.keys())
107
+ docCounts.set(t, (docCounts.get(t) || 0) + 1);
108
+ index.set(path, { tf, content: text, tokenCount: tokens.length });
109
+ totalDocs++;
110
+ totalBytes += text.length;
111
+ }
112
+ return {
113
+ index,
114
+ docCounts,
115
+ totalDocs,
116
+ totalBytes,
117
+ skipped,
118
+ cap: { maxFileBytes: opts.maxFileBytes, maxTotalBytes: opts.maxTotalBytes },
119
+ };
118
120
  }
121
+ //# sourceMappingURL=searchIndex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchIndex.js","sourceRoot":"","sources":["../src/server/searchIndex.ts"],"names":[],"mappings":"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","sourcesContent":["// The search index lives with the scan, not behind a request. Building it\n// here means:\n//\n// * The first /api/search call is fast. The user is searching — make it feel\n// that way; the work that would have been a request-blocking second walk\n// is already done.\n// * The index reads exactly the files the scanner did. The caller hands us\n// `scan.files`, the list of paths the scanner accepted; we never walk\n// the tree ourselves, so the index can never disagree with the scan\n// about which files exist.\n// * The index has a hard cap. A repo with a single 200 MB SQL dump used to\n// hold its full content in the process for the lifetime of the session;\n// now it stops indexing at the cap and records what it skipped, so a\n// future \"why doesn't my file show up?\" question has a real answer.\n//\n// The on-disk cost of the work the old /api/search did — re-listing every\n// directory, re-reading every file, parsing its tokens — is gone. The\n// per-request cost is one Map lookup plus the scoring pass over matching\n// documents, which is bounded by the index size, not the repo size.\n\nconst DEFAULTS = {\n // Aggregate content size. Files beyond this are not indexed, only counted.\n // 200 MB is enough to index the source of a large monorepo comfortably;\n // past that the search would be matching against vendor copies and\n // generated code more often than against code people wrote.\n maxTotalBytes: 200 * 1024 * 1024,\n // Per-file ceiling. Files larger than this are skipped (the scanner has\n // its own ceiling for the same reason).\n maxFileBytes: 1024 * 1024,\n // Reads in flight at once. Same shape as `scan.js`'s read-ahead — a file\n // is held in memory whole before the next one starts.\n width: 8,\n};\n\nconst BINARY_HEAD_BYTES = 1000;\n\nfunction looksBinary(content) {\n // NUL in the first KB is a reliable, cheap heuristic for \"this is not\n // text the search would help with\". The first KB also covers the BOM and\n // the shebang without missing the start of the file.\n return content.slice(0, BINARY_HEAD_BYTES).includes('\\0');\n}\n\n// Read each path's text up to width at a time. Failures are skipped, the\n// same way `scan.js:readAhead` handles them: one unreadable file should not\n// end an index build, and the caller counts it in `skipped.readFailed`.\nasync function* readAhead(source, paths, width) {\n const inFlight = [];\n let next = 0;\n const read = (p) =>\n Promise.resolve()\n .then(() => source.read(p))\n .then(\n (text) => ({ path: p, text, failed: false }),\n () => ({ path: p, text: '', failed: true }),\n );\n\n while (next < paths.length && inFlight.length < width) inFlight.push(read(paths[next++]));\n while (inFlight.length) {\n const settled = inFlight.shift();\n if (next < paths.length) inFlight.push(read(paths[next++]));\n yield await settled;\n }\n}\n\n// Build the search index from the file list the scanner already produced.\n// The scanner has read these files once for parsing; indexing reads them a\n// second time for tokenizing, which is the cheapest place to do it — a\n// refactor that streamed text from the scanner into both consumers would\n// save one disk pass at the cost of a much larger refactor. This is the\n// smallest change that closes the audit's three real concerns (first-search\n// latency, no aggregate cap, no concurrency).\nexport async function buildSearchIndex(source, codeFiles, options: Record<string, any> = {}) {\n const opts = { ...DEFAULTS, ...options };\n const index = new Map();\n const docCounts = new Map();\n let totalDocs = 0;\n let totalBytes = 0;\n\n // Files the indexer cannot or will not index, broken down by reason. The\n // shape matches `scan.js:skips` so a future UI surface can render one\n // unified \"what was left out\" panel without translation.\n const skipped = {\n tooLarge: 0, // one file over maxFileBytes\n overCap: 0, // a later file pushed the aggregate over maxTotalBytes\n readFailed: 0, // the file would not read\n binary: 0, // NUL in the first KB\n noTokens: 0, // the file read, but tokenizing produced nothing useful\n };\n\n for await (const { path, text, failed } of readAhead(source, codeFiles, opts.width)) {\n if (failed) { skipped.readFailed++; continue; }\n\n if (text.length > opts.maxFileBytes) { skipped.tooLarge++; continue; }\n if (totalBytes + text.length > opts.maxTotalBytes) { skipped.overCap++; continue; }\n if (looksBinary(text)) { skipped.binary++; continue; }\n\n const tokens = text.toLowerCase().split(/\\W+/).filter((t) => t.length > 1);\n if (!tokens.length) { skipped.noTokens++; continue; }\n\n const tf = new Map();\n for (const t of tokens) tf.set(t, (tf.get(t) || 0) + 1);\n for (const t of tf.keys()) docCounts.set(t, (docCounts.get(t) || 0) + 1);\n\n index.set(path, { tf, content: text, tokenCount: tokens.length });\n totalDocs++;\n totalBytes += text.length;\n }\n\n return {\n index,\n docCounts,\n totalDocs,\n totalBytes,\n skipped,\n cap: { maxFileBytes: opts.maxFileBytes, maxTotalBytes: opts.maxTotalBytes },\n };\n}\n"]}
@@ -0,0 +1,14 @@
1
+ export declare const MAX_SESSIONS = 12;
2
+ export declare function openSession({ root, cloneDir, searchIndex }: {
3
+ cloneDir?: any;
4
+ root: any;
5
+ searchIndex?: any;
6
+ }): string;
7
+ export declare function getSession(scanId: any): any;
8
+ export declare function isCloneId(id: any): boolean;
9
+ export declare function closeClone(cloneId: any): Promise<boolean>;
10
+ export declare function removalsSettled(): Promise<void>;
11
+ export declare function sweepClonesSync(): void;
12
+ export declare function installExitCleanup(proc?: NodeJS.Process): void;
13
+ export declare function _resetSessions(): void;
14
+ export declare function _sessionCount(): number;
@@ -17,18 +17,14 @@
17
17
  // * It leaked clones on exit. A clone lives in the OS temp dir until someone
18
18
  // removes it, and only an explicit `DELETE /api/scan/:id` did. Ctrl-C left
19
19
  // every clone of the session behind — hundreds of megabytes, silently.
20
-
21
20
  import crypto from 'node:crypto';
22
21
  import path from 'node:path';
23
22
  import { realpathSync } from 'node:fs';
24
-
25
23
  import { isCloneDir, removeClone, removeCloneSync } from './gitClone.js';
26
-
27
24
  // Twelve repos is far more than anyone holds open at once, and each entry is a
28
25
  // couple of strings — the cap is about not serving from a root the person has
29
26
  // forgotten scanning, not about memory.
30
27
  export const MAX_SESSIONS = 12;
31
-
32
28
  // scanId -> { root, cloneDir, at, searchIndex? }. Insertion-ordered, which is
33
29
  // what makes "oldest first" a `keys().next()` rather than a sort.
34
30
  //
@@ -39,14 +35,12 @@ export const MAX_SESSIONS = 12;
39
35
  // the same repo would rebuild it; the cost of one scan's worth of work is
40
36
  // far below the cost of re-fetching the repo.
41
37
  const sessions = new Map();
42
-
43
38
  export function openSession({ root, cloneDir = null, searchIndex = null }) {
44
- const scanId = crypto.randomBytes(8).toString('hex');
45
- sessions.set(scanId, { root: canonicalRoot(root), cloneDir, at: Date.now(), searchIndex });
46
- evictBeyondCap();
47
- return scanId;
39
+ const scanId = crypto.randomBytes(8).toString('hex');
40
+ sessions.set(scanId, { root: canonicalRoot(root), cloneDir, at: Date.now(), searchIndex });
41
+ evictBeyondCap();
42
+ return scanId;
48
43
  }
49
-
50
44
  // Resolve symlinks once, so the root every consumer sees is the real one. On
51
45
  // macOS `/tmp` is a symlink to `/private/tmp`, and an analyzer run against the
52
46
  // alias reports paths rooted at the target — without this, `/api/tools/run`
@@ -54,110 +48,108 @@ export function openSession({ root, cloneDir = null, searchIndex = null }) {
54
48
  // scanned through a symlinked path. Failing to resolve (a path that is gone)
55
49
  // is not fatal: the original is used and the scan's own error path reports it.
56
50
  function canonicalRoot(root) {
57
- if (typeof root !== 'string' || !root) return root;
58
- try {
59
- return realpathSync(root);
60
- } catch {
61
- return root;
62
- }
51
+ if (typeof root !== 'string' || !root)
52
+ return root;
53
+ try {
54
+ return realpathSync(root);
55
+ }
56
+ catch {
57
+ return root;
58
+ }
63
59
  }
64
-
65
60
  // Reading from a scan keeps it alive. Without the touch, opening files in the
66
61
  // first repo you scanned is what evicts it — you would lose the one you are
67
62
  // actually using and keep eleven you are not.
68
63
  export function getSession(scanId) {
69
- if (!scanId) return null;
70
- const session = sessions.get(scanId);
71
- if (!session) return null;
72
- session.at = Date.now();
73
- sessions.delete(scanId);
74
- sessions.set(scanId, session);
75
- return session;
64
+ if (!scanId)
65
+ return null;
66
+ const session = sessions.get(scanId);
67
+ if (!session)
68
+ return null;
69
+ session.at = Date.now();
70
+ sessions.delete(scanId);
71
+ sessions.set(scanId, session);
72
+ return session;
76
73
  }
77
-
78
74
  // Clone ids are the 12 hex characters `gitClone` puts after `onboarder-`. The
79
75
  // match is on the exact directory name: `endsWith(cloneId)` treated an empty id
80
76
  // as a match against every clone, so `DELETE /api/scan/` used to delete
81
77
  // whichever clone the map happened to yield first.
82
78
  export function isCloneId(id) {
83
- return /^[0-9a-f]{12}$/.test(id || '');
79
+ return /^[0-9a-f]{12}$/.test(id || '');
84
80
  }
85
-
86
81
  // Removes the clone with this id and forgets every scan pointing at it. Returns
87
82
  // whether anything was there — a repeat DELETE is not an error; the page sends
88
83
  // one on unload and may well be the second to arrive.
89
84
  export async function closeClone(cloneId) {
90
- const dirName = 'onboarder-' + cloneId;
91
- let found = null;
92
- for (const [scanId, session] of sessions) {
93
- if (session.cloneDir && path.basename(session.cloneDir) === dirName) {
94
- found = session.cloneDir;
95
- sessions.delete(scanId);
85
+ const dirName = 'onboarder-' + cloneId;
86
+ let found = null;
87
+ for (const [scanId, session] of sessions) {
88
+ if (session.cloneDir && path.basename(session.cloneDir) === dirName) {
89
+ found = session.cloneDir;
90
+ sessions.delete(scanId);
91
+ }
96
92
  }
97
- }
98
- if (found) await removeClone(found);
99
- return Boolean(found);
93
+ if (found)
94
+ await removeClone(found);
95
+ return Boolean(found);
100
96
  }
101
-
102
97
  function evictBeyondCap() {
103
- while (sessions.size > MAX_SESSIONS) {
104
- const [scanId, session] = sessions.entries().next().value;
105
- sessions.delete(scanId);
106
- if (session.cloneDir && !stillReferenced(session.cloneDir)) sweep(session.cloneDir);
107
- }
98
+ while (sessions.size > MAX_SESSIONS) {
99
+ const [scanId, session] = sessions.entries().next().value;
100
+ sessions.delete(scanId);
101
+ if (session.cloneDir && !stillReferenced(session.cloneDir))
102
+ sweep(session.cloneDir);
103
+ }
108
104
  }
109
-
110
105
  // Eviction happens inside a scan request, and the person is waiting on the scan,
111
106
  // not on a directory being swept — so the removal is started and not awaited. The
112
107
  // promises are chained rather than dropped so that a caller who does need to know
113
108
  // when the disk is quiet can wait for it; the only one that does is a test.
114
109
  let removals = Promise.resolve();
115
-
116
110
  function sweep(dir) {
117
- removals = removals.then(() => removeClone(dir));
111
+ removals = removals.then(() => removeClone(dir));
118
112
  }
119
-
120
113
  export function removalsSettled() {
121
- return removals;
114
+ return removals;
122
115
  }
123
-
124
116
  // Two sessions can name the same clone — scan a git URL, then scan the temp path
125
117
  // it landed in. Do not delete a directory another live session still reads from.
126
118
  function stillReferenced(dir) {
127
- for (const session of sessions.values()) if (session.cloneDir === dir) return true;
128
- return false;
119
+ for (const session of sessions.values())
120
+ if (session.cloneDir === dir)
121
+ return true;
122
+ return false;
129
123
  }
130
-
131
124
  // Synchronous on purpose: this is what an exit handler can finish.
132
125
  export function sweepClonesSync() {
133
- for (const [scanId, session] of sessions) {
134
- sessions.delete(scanId);
135
- if (isCloneDir(session.cloneDir)) removeCloneSync(session.cloneDir);
136
- }
126
+ for (const [scanId, session] of sessions) {
127
+ sessions.delete(scanId);
128
+ if (isCloneDir(session.cloneDir))
129
+ removeCloneSync(session.cloneDir);
130
+ }
137
131
  }
138
-
139
132
  // Called from the `node server/index.js` path only, never on import. The tests
140
133
  // drive the real router in-process, and a module that added signal handlers just
141
134
  // by being imported would take Ctrl-C away from the test runner.
142
135
  export function installExitCleanup(proc = process) {
143
- proc.on('exit', sweepClonesSync);
144
- // A signal does not run `exit` handlers on its own — the process dies where it
145
- // stands. Sweeping in the signal handler and then exiting is what gets the
146
- // clones removed.
147
- for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
148
- proc.on(signal, () => {
149
- sweepClonesSync();
150
- proc.exit(0);
151
- });
152
- }
136
+ proc.on('exit', sweepClonesSync);
137
+ // A signal does not run `exit` handlers on its own — the process dies where it
138
+ // stands. Sweeping in the signal handler and then exiting is what gets the
139
+ // clones removed.
140
+ for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
141
+ proc.on(signal, () => {
142
+ sweepClonesSync();
143
+ proc.exit(0);
144
+ });
145
+ }
153
146
  }
154
-
155
147
  // Tests only. The store is module state, so a test that opens sessions would
156
148
  // otherwise leak them into the next one.
157
149
  export function _resetSessions() {
158
- sessions.clear();
150
+ sessions.clear();
159
151
  }
160
-
161
152
  export function _sessionCount() {
162
- return sessions.size;
153
+ return sessions.size;
163
154
  }
155
+ //# sourceMappingURL=sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../src/server/sessions.ts"],"names":[],"mappings":"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","sourcesContent":["// What the server remembers between requests: which directory each scan came\n// from. `/api/file` needs it — the browser asks for `server/paths.js` and the\n// server has to know which root that is relative to — and the git-URL flow needs\n// it to find a clone again when the page says it is done with one.\n//\n// A scan id is the capability. Handing the browser a path and trusting it back\n// would make `/api/file` a \"read any file on this machine\" endpoint; handing it\n// an opaque id means the only readable roots are ones the person chose to scan\n// during this run.\n//\n// Two things the inline Map this replaces got wrong:\n//\n// * It never forgot. Every scan added an entry and nothing removed one, so an\n// afternoon of scanning left a growing list of roots still being served\n// from. A cap with oldest-out eviction bounds it, and evicting a cloned repo\n// deletes the clone with it.\n// * It leaked clones on exit. A clone lives in the OS temp dir until someone\n// removes it, and only an explicit `DELETE /api/scan/:id` did. Ctrl-C left\n// every clone of the session behind — hundreds of megabytes, silently.\n\nimport crypto from 'node:crypto';\nimport path from 'node:path';\nimport { realpathSync } from 'node:fs';\n\nimport { isCloneDir, removeClone, removeCloneSync } from './gitClone.js';\n\n// Twelve repos is far more than anyone holds open at once, and each entry is a\n// couple of strings — the cap is about not serving from a root the person has\n// forgotten scanning, not about memory.\nexport const MAX_SESSIONS = 12;\n\n// scanId -> { root, cloneDir, at, searchIndex? }. Insertion-ordered, which is\n// what makes \"oldest first\" a `keys().next()` rather than a sort.\n//\n// `searchIndex`, when present, is the TF-IDF index built at scan time\n// (`searchIndex.js`). It is held on the session for the same reason `root`\n// is — `/api/search` is a request that has to be answered against this\n// particular scan — and is dropped when the session is evicted. Reopening\n// the same repo would rebuild it; the cost of one scan's worth of work is\n// far below the cost of re-fetching the repo.\nconst sessions = new Map();\n\nexport function openSession({ root, cloneDir = null, searchIndex = null }) {\n const scanId = crypto.randomBytes(8).toString('hex');\n sessions.set(scanId, { root: canonicalRoot(root), cloneDir, at: Date.now(), searchIndex });\n evictBeyondCap();\n return scanId;\n}\n\n// Resolve symlinks once, so the root every consumer sees is the real one. On\n// macOS `/tmp` is a symlink to `/private/tmp`, and an analyzer run against the\n// alias reports paths rooted at the target — without this, `/api/tools/run`\n// findings and `/api/file` lookups would silently miss every file in a repo\n// scanned through a symlinked path. Failing to resolve (a path that is gone)\n// is not fatal: the original is used and the scan's own error path reports it.\nfunction canonicalRoot(root) {\n if (typeof root !== 'string' || !root) return root;\n try {\n return realpathSync(root);\n } catch {\n return root;\n }\n}\n\n// Reading from a scan keeps it alive. Without the touch, opening files in the\n// first repo you scanned is what evicts it — you would lose the one you are\n// actually using and keep eleven you are not.\nexport function getSession(scanId) {\n if (!scanId) return null;\n const session = sessions.get(scanId);\n if (!session) return null;\n session.at = Date.now();\n sessions.delete(scanId);\n sessions.set(scanId, session);\n return session;\n}\n\n// Clone ids are the 12 hex characters `gitClone` puts after `onboarder-`. The\n// match is on the exact directory name: `endsWith(cloneId)` treated an empty id\n// as a match against every clone, so `DELETE /api/scan/` used to delete\n// whichever clone the map happened to yield first.\nexport function isCloneId(id) {\n return /^[0-9a-f]{12}$/.test(id || '');\n}\n\n// Removes the clone with this id and forgets every scan pointing at it. Returns\n// whether anything was there — a repeat DELETE is not an error; the page sends\n// one on unload and may well be the second to arrive.\nexport async function closeClone(cloneId) {\n const dirName = 'onboarder-' + cloneId;\n let found = null;\n for (const [scanId, session] of sessions) {\n if (session.cloneDir && path.basename(session.cloneDir) === dirName) {\n found = session.cloneDir;\n sessions.delete(scanId);\n }\n }\n if (found) await removeClone(found);\n return Boolean(found);\n}\n\nfunction evictBeyondCap() {\n while (sessions.size > MAX_SESSIONS) {\n const [scanId, session] = sessions.entries().next().value;\n sessions.delete(scanId);\n if (session.cloneDir && !stillReferenced(session.cloneDir)) sweep(session.cloneDir);\n }\n}\n\n// Eviction happens inside a scan request, and the person is waiting on the scan,\n// not on a directory being swept — so the removal is started and not awaited. The\n// promises are chained rather than dropped so that a caller who does need to know\n// when the disk is quiet can wait for it; the only one that does is a test.\nlet removals = Promise.resolve();\n\nfunction sweep(dir) {\n removals = removals.then(() => removeClone(dir));\n}\n\nexport function removalsSettled() {\n return removals;\n}\n\n// Two sessions can name the same clone — scan a git URL, then scan the temp path\n// it landed in. Do not delete a directory another live session still reads from.\nfunction stillReferenced(dir) {\n for (const session of sessions.values()) if (session.cloneDir === dir) return true;\n return false;\n}\n\n// Synchronous on purpose: this is what an exit handler can finish.\nexport function sweepClonesSync() {\n for (const [scanId, session] of sessions) {\n sessions.delete(scanId);\n if (isCloneDir(session.cloneDir)) removeCloneSync(session.cloneDir);\n }\n}\n\n// Called from the `node server/index.js` path only, never on import. The tests\n// drive the real router in-process, and a module that added signal handlers just\n// by being imported would take Ctrl-C away from the test runner.\nexport function installExitCleanup(proc = process) {\n proc.on('exit', sweepClonesSync);\n // A signal does not run `exit` handlers on its own — the process dies where it\n // stands. Sweeping in the signal handler and then exiting is what gets the\n // clones removed.\n for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) {\n proc.on(signal, () => {\n sweepClonesSync();\n proc.exit(0);\n });\n }\n}\n\n// Tests only. The store is module state, so a test that opens sessions would\n// otherwise leak them into the next one.\nexport function _resetSessions() {\n sessions.clear();\n}\n\nexport function _sessionCount() {\n return sessions.size;\n}\n"]}
@@ -0,0 +1,118 @@
1
+ export declare const LABEL = "com.onboarder.server";
2
+ export declare const UNIT = "onboarder.service";
3
+ export declare function cliEntry(): string;
4
+ export declare function startupCommand(configFile?: string, { node, entry }?: Record<string, any>): any[];
5
+ export declare function renderLaunchAgent({ configFile, log, ...options }?: Record<string, any>): string;
6
+ export declare function renderSystemdUnit({ configFile, log, ...options }?: Record<string, any>): string;
7
+ export declare function renderWindowsStartup({ configFile, log, ...options }?: Record<string, any>): string;
8
+ export declare function startupTarget({ platform, home, env }?: Record<string, any>): {
9
+ kind: string;
10
+ platform: any;
11
+ label: string;
12
+ path: string;
13
+ render: typeof renderLaunchAgent;
14
+ load: string[];
15
+ unload: string[];
16
+ status: string[];
17
+ hint: string;
18
+ daemonReload?: undefined;
19
+ } | {
20
+ kind: string;
21
+ platform: any;
22
+ label: string;
23
+ path: string;
24
+ render: typeof renderSystemdUnit;
25
+ daemonReload: string[];
26
+ load: string[];
27
+ unload: string[];
28
+ status: string[];
29
+ hint: string;
30
+ };
31
+ export declare function startupInstalled(target?: {
32
+ kind: string;
33
+ platform: any;
34
+ label: string;
35
+ path: string;
36
+ render: typeof renderLaunchAgent;
37
+ load: string[];
38
+ unload: string[];
39
+ status: string[];
40
+ hint: string;
41
+ daemonReload?: undefined;
42
+ } | {
43
+ kind: string;
44
+ platform: any;
45
+ label: string;
46
+ path: string;
47
+ render: typeof renderSystemdUnit;
48
+ daemonReload: string[];
49
+ load: string[];
50
+ unload: string[];
51
+ status: string[];
52
+ hint: string;
53
+ }): Promise<boolean>;
54
+ export declare function startupStatus(target?: {
55
+ kind: string;
56
+ platform: any;
57
+ label: string;
58
+ path: string;
59
+ render: typeof renderLaunchAgent;
60
+ load: string[];
61
+ unload: string[];
62
+ status: string[];
63
+ hint: string;
64
+ daemonReload?: undefined;
65
+ } | {
66
+ kind: string;
67
+ platform: any;
68
+ label: string;
69
+ path: string;
70
+ render: typeof renderSystemdUnit;
71
+ daemonReload: string[];
72
+ load: string[];
73
+ unload: string[];
74
+ status: string[];
75
+ hint: string;
76
+ }, { run }?: Record<string, any>): Promise<{
77
+ kind: string;
78
+ supported: boolean;
79
+ label: string;
80
+ path: string;
81
+ installed: boolean;
82
+ active: any;
83
+ detail: string;
84
+ hint: string;
85
+ }>;
86
+ export declare function installStartup({ configFile, log, target, run }?: Record<string, any>): Promise<{
87
+ path?: undefined;
88
+ ok: boolean;
89
+ reason: string;
90
+ loaded?: undefined;
91
+ output?: undefined;
92
+ error?: undefined;
93
+ } | {
94
+ reason?: undefined;
95
+ ok: boolean;
96
+ path: any;
97
+ loaded: boolean;
98
+ output: string;
99
+ error?: undefined;
100
+ } | {
101
+ reason?: undefined;
102
+ loaded?: undefined;
103
+ ok: boolean;
104
+ path: any;
105
+ output: any;
106
+ error: any;
107
+ }>;
108
+ export declare function removeStartup({ target, run }?: Record<string, any>): Promise<{
109
+ path?: undefined;
110
+ output?: undefined;
111
+ ok: boolean;
112
+ reason: string;
113
+ } | {
114
+ reason?: undefined;
115
+ ok: boolean;
116
+ path: any;
117
+ output: string;
118
+ }>;