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
@@ -12,159 +12,157 @@
12
12
  // `severity` is one of the built-in five. `source` is 'builtin' or 'external'
13
13
  // and `tool` names which engine answered, so the UI can say "found by Semgrep"
14
14
  // rather than letting a finding appear from nowhere.
15
-
16
15
  export const SEVERITY_ORDER = ['info', 'low', 'medium', 'high', 'critical'];
17
-
18
16
  export function normalizeSeverity(raw) {
19
- const s = String(raw || '').toLowerCase();
20
- if (s === 'critical' || s === 'error') return s === 'error' ? 'high' : 'critical';
21
- if (s === 'high') return 'high';
22
- if (s === 'medium' || s === 'warning' || s === 'warn' || s === 'moderate') return 'medium';
23
- if (s === 'low' || s === 'note') return 'low';
24
- return 'info';
17
+ const s = String(raw || '').toLowerCase();
18
+ if (s === 'critical' || s === 'error')
19
+ return s === 'error' ? 'high' : 'critical';
20
+ if (s === 'high')
21
+ return 'high';
22
+ if (s === 'medium' || s === 'warning' || s === 'warn' || s === 'moderate')
23
+ return 'medium';
24
+ if (s === 'low' || s === 'note')
25
+ return 'low';
26
+ return 'info';
25
27
  }
26
-
27
28
  function clipExcerpt(text) {
28
- return String(text ?? '').replace(/\s+/g, ' ').trim().slice(0, 90);
29
+ return String(text ?? '').replace(/\s+/g, ' ').trim().slice(0, 90);
29
30
  }
30
-
31
31
  // ---- Semgrep / Opengrep ----------------------------------------------------
32
32
  // `semgrep --json` → { results: [ { check_id, path, start:{line}, extra:
33
33
  // { severity, message, lines, metadata:{category} } } ] }. Opengrep is the same
34
34
  // JSON. `rel` strips the scan root so paths match the repo-relative form the
35
35
  // rest of the app uses.
36
36
  export function parseSemgrep(json, rel) {
37
- const results = Array.isArray(json && json.results) ? json.results : [];
38
- const findings = [];
39
- for (const r of results) {
40
- const extra = r.extra || {};
41
- findings.push({
42
- rule: String(r.check_id || 'semgrep-rule'),
43
- severity: normalizeSeverity(extra.severity),
44
- category: (extra.metadata && extra.metadata.category) || 'security',
45
- message: clipExcerpt(extra.message || r.check_id),
46
- path: rel(r.path),
47
- line: r.start && r.start.line ? r.start.line : 1,
48
- excerpt: clipExcerpt(extra.lines),
49
- source: 'external',
50
- tool: 'semgrep',
51
- });
52
- }
53
- return findings;
37
+ const results = Array.isArray(json && json.results) ? json.results : [];
38
+ const findings = [];
39
+ for (const r of results) {
40
+ const extra = r.extra || {};
41
+ findings.push({
42
+ rule: String(r.check_id || 'semgrep-rule'),
43
+ severity: normalizeSeverity(extra.severity),
44
+ category: (extra.metadata && extra.metadata.category) || 'security',
45
+ message: clipExcerpt(extra.message || r.check_id),
46
+ path: rel(r.path),
47
+ line: r.start && r.start.line ? r.start.line : 1,
48
+ excerpt: clipExcerpt(extra.lines),
49
+ source: 'external',
50
+ tool: 'semgrep',
51
+ });
52
+ }
53
+ return findings;
54
54
  }
55
-
56
55
  // ---- Gitleaks ---------------------------------------------------------------
57
56
  // `gitleaks --report-format json` → an array of secrets: [ { RuleID,
58
57
  // Description, File, StartLine, Match, Secret } ]. The finding reports *that* a
59
58
  // secret exists, never the secret — `Secret` is read for nothing.
60
59
  export function parseGitleaks(json, rel) {
61
- const list = Array.isArray(json) ? json : [];
62
- const findings = [];
63
- for (const r of list) {
64
- findings.push({
65
- rule: 'secret:' + (r.RuleID || 'unknown'),
66
- severity: 'critical',
67
- category: 'secret',
68
- message: clipExcerpt(r.Description || 'A secret is committed to the source.'),
69
- path: rel(r.File),
70
- line: r.StartLine || 1,
71
- excerpt: 'committed credential (value redacted)',
72
- source: 'external',
73
- tool: 'gitleaks',
74
- });
75
- }
76
- return findings;
60
+ const list = Array.isArray(json) ? json : [];
61
+ const findings = [];
62
+ for (const r of list) {
63
+ findings.push({
64
+ rule: 'secret:' + (r.RuleID || 'unknown'),
65
+ severity: 'critical',
66
+ category: 'secret',
67
+ message: clipExcerpt(r.Description || 'A secret is committed to the source.'),
68
+ path: rel(r.File),
69
+ line: r.StartLine || 1,
70
+ excerpt: 'committed credential (value redacted)',
71
+ source: 'external',
72
+ tool: 'gitleaks',
73
+ });
74
+ }
75
+ return findings;
77
76
  }
78
-
79
77
  // ---- Knip -------------------------------------------------------------------
80
78
  // `knip --reporter json` groups dead code by kind: { files:[], dependencies:[],
81
79
  // unused:[{name,file,line}], ... }. Each becomes a finding so the dead-code
82
80
  // pass can be read in one list; the kind is the rule.
83
81
  export function parseKnip(json, rel) {
84
- const findings = [];
85
- const push = (rule, category, severity, path, line, message) => {
86
- findings.push({ rule, category, severity, message, path: rel(path), line: line || 1, excerpt: '', source: 'external', tool: 'knip' });
87
- };
88
-
89
- for (const file of (json && json.files) || []) {
90
- push('knip:unused-file', 'dead-file', 'medium', file, 1, 'This file is never imported anywhere.');
91
- }
92
- for (const dep of (json && json.dependencies) || []) {
93
- push('knip:unused-dependency', 'dead-dependency', 'low', dep, 1, `Dependency "${dep}" is declared but never imported.`);
94
- }
95
- for (const u of (json && json.unused) || []) {
96
- push('knip:unused-export', 'dead-export', 'low', u.file, u.line, `Export "${u.name}" is never used.`);
97
- }
98
- for (const u of (json && json.unresolved) || []) {
99
- push('knip:unresolved', 'dead-import', 'medium', u.file, u.line, `Import "${u.name}" does not resolve to anything.`);
100
- }
101
- return findings;
82
+ const findings = [];
83
+ const push = (rule, category, severity, path, line, message) => {
84
+ findings.push({ rule, category, severity, message, path: rel(path), line: line || 1, excerpt: '', source: 'external', tool: 'knip' });
85
+ };
86
+ for (const file of (json && json.files) || []) {
87
+ push('knip:unused-file', 'dead-file', 'medium', file, 1, 'This file is never imported anywhere.');
88
+ }
89
+ for (const dep of (json && json.dependencies) || []) {
90
+ push('knip:unused-dependency', 'dead-dependency', 'low', dep, 1, `Dependency "${dep}" is declared but never imported.`);
91
+ }
92
+ for (const u of (json && json.unused) || []) {
93
+ push('knip:unused-export', 'dead-export', 'low', u.file, u.line, `Export "${u.name}" is never used.`);
94
+ }
95
+ for (const u of (json && json.unresolved) || []) {
96
+ push('knip:unresolved', 'dead-import', 'medium', u.file, u.line, `Import "${u.name}" does not resolve to anything.`);
97
+ }
98
+ return findings;
102
99
  }
103
-
104
100
  // ---- Vulture ----------------------------------------------------------------
105
101
  // `vulture` prints lines like `src/util.py:42: unused function 'helper' (60%
106
102
  // confidence)`. There is no stable JSON, so we parse the text — which is why the
107
103
  // parser is a pure function over a string, and why the line shape is pinned by
108
104
  // a test rather than by reading the binary's source.
109
105
  const VULTURE_RE = /^(.+?):(\d+):\s+(.+?)\s+\((\d+)% confidence\)/;
110
-
111
106
  export function parseVulture(text, rel) {
112
- const findings = [];
113
- for (const line of String(text || '').split('\n')) {
114
- const m = line.match(VULTURE_RE);
115
- if (!m) continue;
116
- const confidence = Number(m[4]);
117
- if (confidence < 60) continue; // below vulture's own floor, it is guessing
118
- findings.push({
119
- rule: 'vulture:' + (m[3].split(' ')[0] || 'unused'),
120
- severity: confidence >= 90 ? 'medium' : 'low',
121
- category: 'dead-code',
122
- message: clipExcerpt(m[3]) + ` (${confidence}% confident)`,
123
- path: rel(m[1]),
124
- line: Number(m[2]) || 1,
125
- excerpt: '',
126
- source: 'external',
127
- tool: 'vulture',
128
- });
129
- }
130
- return findings;
107
+ const findings = [];
108
+ for (const line of String(text || '').split('\n')) {
109
+ const m = line.match(VULTURE_RE);
110
+ if (!m)
111
+ continue;
112
+ const confidence = Number(m[4]);
113
+ if (confidence < 60)
114
+ continue; // below vulture's own floor, it is guessing
115
+ findings.push({
116
+ rule: 'vulture:' + (m[3].split(' ')[0] || 'unused'),
117
+ severity: confidence >= 90 ? 'medium' : 'low',
118
+ category: 'dead-code',
119
+ message: clipExcerpt(m[3]) + ` (${confidence}% confident)`,
120
+ path: rel(m[1]),
121
+ line: Number(m[2]) || 1,
122
+ excerpt: '',
123
+ source: 'external',
124
+ tool: 'vulture',
125
+ });
126
+ }
127
+ return findings;
131
128
  }
132
-
133
129
  // ---- Depcheck ---------------------------------------------------------------
134
130
  // `depcheck --json` → { dependencies:[], devDependencies:[], missing:{} }.
135
131
  export function parseDepcheck(json) {
136
- const findings = [];
137
- const push = (name, dev) => findings.push({
138
- rule: 'depcheck:unused',
139
- severity: 'low',
140
- category: 'dead-dependency',
141
- message: `Package "${name}" is declared in package.json but never imported.`,
142
- path: 'package.json',
143
- line: 1,
144
- excerpt: '',
145
- source: 'external',
146
- tool: 'depcheck',
147
- dev,
148
- });
149
- for (const name of (json && json.dependencies) || []) push(name, false);
150
- for (const name of (json && json.devDependencies) || []) push(name, true);
151
- return findings;
132
+ const findings = [];
133
+ const push = (name, dev) => findings.push({
134
+ rule: 'depcheck:unused',
135
+ severity: 'low',
136
+ category: 'dead-dependency',
137
+ message: `Package "${name}" is declared in package.json but never imported.`,
138
+ path: 'package.json',
139
+ line: 1,
140
+ excerpt: '',
141
+ source: 'external',
142
+ tool: 'depcheck',
143
+ dev,
144
+ });
145
+ for (const name of (json && json.dependencies) || [])
146
+ push(name, false);
147
+ for (const name of (json && json.devDependencies) || [])
148
+ push(name, true);
149
+ return findings;
152
150
  }
153
-
154
151
  // Merge the external passes into one list, keeping the built-in scan's findings
155
152
  // untouched. Dedup on (path, line, rule): two engines that flag the same line
156
153
  // for the same reason are one problem, not two.
157
154
  export function mergeFindings(...lists) {
158
- const seen = new Set();
159
- const out = [];
160
- for (const list of lists) {
161
- for (const f of list || []) {
162
- const key = `${f.path}:${f.line}:${f.rule}`;
163
- if (seen.has(key)) continue;
164
- seen.add(key);
165
- out.push(f);
155
+ const seen = new Set();
156
+ const out = [];
157
+ for (const list of lists) {
158
+ for (const f of list || []) {
159
+ const key = `${f.path}:${f.line}:${f.rule}`;
160
+ if (seen.has(key))
161
+ continue;
162
+ seen.add(key);
163
+ out.push(f);
164
+ }
166
165
  }
167
- }
168
- return out;
166
+ return out;
169
167
  }
170
-
168
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/server/tools/parse.ts"],"names":[],"mappings":"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","sourcesContent":["// Parsing the dialects. Every analyzer speaks its own JSON (or SARIF); the UI\n// speaks one. This file is the translation layer, and it is pure — it takes a\n// string a tool printed and returns findings, so it can be tested in Node with\n// fixtures and needs no process, no filesystem, no PATH.\n//\n// The single target shape is the one the built-in scanner already emits\n// (`shared/analyzer/security.js`), so the existing security view needs no new\n// kind of row:\n//\n// { rule, severity, category, message, line, excerpt, source, tool }\n//\n// `severity` is one of the built-in five. `source` is 'builtin' or 'external'\n// and `tool` names which engine answered, so the UI can say \"found by Semgrep\"\n// rather than letting a finding appear from nowhere.\n\nexport const SEVERITY_ORDER = ['info', 'low', 'medium', 'high', 'critical'];\n\nexport function normalizeSeverity(raw) {\n const s = String(raw || '').toLowerCase();\n if (s === 'critical' || s === 'error') return s === 'error' ? 'high' : 'critical';\n if (s === 'high') return 'high';\n if (s === 'medium' || s === 'warning' || s === 'warn' || s === 'moderate') return 'medium';\n if (s === 'low' || s === 'note') return 'low';\n return 'info';\n}\n\nfunction clipExcerpt(text) {\n return String(text ?? '').replace(/\\s+/g, ' ').trim().slice(0, 90);\n}\n\n// ---- Semgrep / Opengrep ----------------------------------------------------\n// `semgrep --json` → { results: [ { check_id, path, start:{line}, extra:\n// { severity, message, lines, metadata:{category} } } ] }. Opengrep is the same\n// JSON. `rel` strips the scan root so paths match the repo-relative form the\n// rest of the app uses.\nexport function parseSemgrep(json, rel) {\n const results = Array.isArray(json && json.results) ? json.results : [];\n const findings = [];\n for (const r of results) {\n const extra = r.extra || {};\n findings.push({\n rule: String(r.check_id || 'semgrep-rule'),\n severity: normalizeSeverity(extra.severity),\n category: (extra.metadata && extra.metadata.category) || 'security',\n message: clipExcerpt(extra.message || r.check_id),\n path: rel(r.path),\n line: r.start && r.start.line ? r.start.line : 1,\n excerpt: clipExcerpt(extra.lines),\n source: 'external',\n tool: 'semgrep',\n });\n }\n return findings;\n}\n\n// ---- Gitleaks ---------------------------------------------------------------\n// `gitleaks --report-format json` → an array of secrets: [ { RuleID,\n// Description, File, StartLine, Match, Secret } ]. The finding reports *that* a\n// secret exists, never the secret — `Secret` is read for nothing.\nexport function parseGitleaks(json, rel) {\n const list = Array.isArray(json) ? json : [];\n const findings = [];\n for (const r of list) {\n findings.push({\n rule: 'secret:' + (r.RuleID || 'unknown'),\n severity: 'critical',\n category: 'secret',\n message: clipExcerpt(r.Description || 'A secret is committed to the source.'),\n path: rel(r.File),\n line: r.StartLine || 1,\n excerpt: 'committed credential (value redacted)',\n source: 'external',\n tool: 'gitleaks',\n });\n }\n return findings;\n}\n\n// ---- Knip -------------------------------------------------------------------\n// `knip --reporter json` groups dead code by kind: { files:[], dependencies:[],\n// unused:[{name,file,line}], ... }. Each becomes a finding so the dead-code\n// pass can be read in one list; the kind is the rule.\nexport function parseKnip(json, rel) {\n const findings = [];\n const push = (rule, category, severity, path, line, message) => {\n findings.push({ rule, category, severity, message, path: rel(path), line: line || 1, excerpt: '', source: 'external', tool: 'knip' });\n };\n\n for (const file of (json && json.files) || []) {\n push('knip:unused-file', 'dead-file', 'medium', file, 1, 'This file is never imported anywhere.');\n }\n for (const dep of (json && json.dependencies) || []) {\n push('knip:unused-dependency', 'dead-dependency', 'low', dep, 1, `Dependency \"${dep}\" is declared but never imported.`);\n }\n for (const u of (json && json.unused) || []) {\n push('knip:unused-export', 'dead-export', 'low', u.file, u.line, `Export \"${u.name}\" is never used.`);\n }\n for (const u of (json && json.unresolved) || []) {\n push('knip:unresolved', 'dead-import', 'medium', u.file, u.line, `Import \"${u.name}\" does not resolve to anything.`);\n }\n return findings;\n}\n\n// ---- Vulture ----------------------------------------------------------------\n// `vulture` prints lines like `src/util.py:42: unused function 'helper' (60%\n// confidence)`. There is no stable JSON, so we parse the text — which is why the\n// parser is a pure function over a string, and why the line shape is pinned by\n// a test rather than by reading the binary's source.\nconst VULTURE_RE = /^(.+?):(\\d+):\\s+(.+?)\\s+\\((\\d+)% confidence\\)/;\n\nexport function parseVulture(text, rel) {\n const findings = [];\n for (const line of String(text || '').split('\\n')) {\n const m = line.match(VULTURE_RE);\n if (!m) continue;\n const confidence = Number(m[4]);\n if (confidence < 60) continue; // below vulture's own floor, it is guessing\n findings.push({\n rule: 'vulture:' + (m[3].split(' ')[0] || 'unused'),\n severity: confidence >= 90 ? 'medium' : 'low',\n category: 'dead-code',\n message: clipExcerpt(m[3]) + ` (${confidence}% confident)`,\n path: rel(m[1]),\n line: Number(m[2]) || 1,\n excerpt: '',\n source: 'external',\n tool: 'vulture',\n });\n }\n return findings;\n}\n\n// ---- Depcheck ---------------------------------------------------------------\n// `depcheck --json` → { dependencies:[], devDependencies:[], missing:{} }.\nexport function parseDepcheck(json) {\n const findings = [];\n const push = (name, dev) => findings.push({\n rule: 'depcheck:unused',\n severity: 'low',\n category: 'dead-dependency',\n message: `Package \"${name}\" is declared in package.json but never imported.`,\n path: 'package.json',\n line: 1,\n excerpt: '',\n source: 'external',\n tool: 'depcheck',\n dev,\n });\n for (const name of (json && json.dependencies) || []) push(name, false);\n for (const name of (json && json.devDependencies) || []) push(name, true);\n return findings;\n}\n\n// Merge the external passes into one list, keeping the built-in scan's findings\n// untouched. Dedup on (path, line, rule): two engines that flag the same line\n// for the same reason are one problem, not two.\nexport function mergeFindings(...lists) {\n const seen = new Set();\n const out = [];\n for (const list of lists) {\n for (const f of list || []) {\n const key = `${f.path}:${f.line}:${f.rule}`;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push(f);\n }\n }\n return out;\n}\n\n"]}
@@ -0,0 +1,9 @@
1
+ export declare function onboarderBinDir(home?: string): string;
2
+ export declare function candidateNames(cmd: any, platform?: NodeJS.Platform, pathext?: string): any[];
3
+ export declare function extraSearchDirs(platform?: NodeJS.Platform, home?: string): string[];
4
+ export declare function splitPath(pathValue: any, platform?: NodeJS.Platform): string[];
5
+ export declare function findOnPath(cmd: any, options?: Record<string, any>): string;
6
+ export declare function spawnArgv(argv: any, platform?: NodeJS.Platform): {
7
+ command: any;
8
+ args: any;
9
+ };
@@ -12,80 +12,82 @@
12
12
  // Silicon is the classic case — and the folder Onboarder's own installer
13
13
  // drops downloaded binaries into, so a tool installed from the GUI is found
14
14
  // on the next status check without a server restart.
15
-
16
15
  import fs from 'node:fs';
17
16
  import os from 'node:os';
18
17
  import path from 'node:path';
19
-
20
18
  // Where `install.js` puts binaries it downloads itself (gitleaks on Linux and
21
19
  // Windows). One fixed place, under the user's home, never the scanned repo.
22
20
  export function onboarderBinDir(home = os.homedir()) {
23
- return path.join(home, '.onboarder', 'bin');
21
+ return path.join(home, '.onboarder', 'bin');
24
22
  }
25
-
26
23
  // The names a command can go by on disk. Windows resolves `npm` to the first
27
24
  // of `npm.exe`, `npm.cmd`, … on PATHEXT; POSIX looks for the name as-is.
28
25
  export function candidateNames(cmd, platform = process.platform, pathext = '') {
29
- if (platform !== 'win32') return [cmd];
30
- const exts = (pathext || process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM')
31
- .split(';').map((e) => e.trim()).filter(Boolean);
32
- const lower = cmd.toLowerCase();
33
- if (exts.some((e) => lower.endsWith(e.toLowerCase()))) return [cmd];
34
- return [cmd, ...exts.map((e) => cmd + e.toLowerCase())];
26
+ if (platform !== 'win32')
27
+ return [cmd];
28
+ const exts = (pathext || process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM')
29
+ .split(';').map((e) => e.trim()).filter(Boolean);
30
+ const lower = cmd.toLowerCase();
31
+ if (exts.some((e) => lower.endsWith(e.toLowerCase())))
32
+ return [cmd];
33
+ return [cmd, ...exts.map((e) => cmd + e.toLowerCase())];
35
34
  }
36
-
37
35
  // Directories worth checking beyond PATH itself. The Homebrew pair matters on
38
36
  // a Mac launched from Spotlight rather than a shell; the Onboarder bin dir is
39
37
  // where the GUI installer puts self-downloaded tools.
40
38
  export function extraSearchDirs(platform = process.platform, home = os.homedir()) {
41
- const dirs = [onboarderBinDir(home)];
42
- if (platform === 'darwin') dirs.push('/opt/homebrew/bin', '/usr/local/bin');
43
- if (platform === 'linux') dirs.push('/usr/local/bin', path.join(home, '.local', 'bin'));
44
- if (platform === 'win32') {
45
- const local = process.env.LOCALAPPDATA;
46
- if (local) dirs.push(path.join(local, 'Programs', 'Gitleaks'));
47
- }
48
- return dirs;
39
+ const dirs = [onboarderBinDir(home)];
40
+ if (platform === 'darwin')
41
+ dirs.push('/opt/homebrew/bin', '/usr/local/bin');
42
+ if (platform === 'linux')
43
+ dirs.push('/usr/local/bin', path.join(home, '.local', 'bin'));
44
+ if (platform === 'win32') {
45
+ const local = process.env.LOCALAPPDATA;
46
+ if (local)
47
+ dirs.push(path.join(local, 'Programs', 'Gitleaks'));
48
+ }
49
+ return dirs;
49
50
  }
50
-
51
51
  // Split a PATH string the way the platform does. Exported for tests.
52
52
  export function splitPath(pathValue, platform = process.platform) {
53
- return String(pathValue || '')
54
- .split(platform === 'win32' ? ';' : ':')
55
- .map((d) => d.trim())
56
- .filter(Boolean);
53
+ return String(pathValue || '')
54
+ .split(platform === 'win32' ? ';' : ':')
55
+ .map((d) => d.trim())
56
+ .filter(Boolean);
57
57
  }
58
-
59
58
  // Find `cmd` on PATH (plus the extra dirs). Returns the absolute path, or
60
59
  // null. Pure apart from the `exists` probe, which defaults to the disk and is
61
60
  // injectable so the tests never touch a real filesystem layout.
62
61
  export function findOnPath(cmd, options = {}) {
63
- const platform = options.platform || process.platform;
64
- const envPath = options.envPath !== undefined ? options.envPath : process.env.PATH;
65
- const pathext = options.pathext !== undefined ? options.pathext : process.env.PATHEXT;
66
- const exists = options.exists || ((p) => fs.existsSync(p));
67
- const home = options.home || os.homedir();
68
-
69
- const dirs = [...splitPath(envPath, platform), ...extraSearchDirs(platform, home)];
70
- for (const dir of dirs) {
71
- for (const name of candidateNames(cmd, platform, pathext)) {
72
- const full = path.join(dir, name);
73
- try {
74
- if (exists(full)) return full;
75
- } catch {
76
- /* an unreadable dir is just not where the tool lives */
77
- }
62
+ const platform = options.platform || process.platform;
63
+ const envPath = options.envPath !== undefined ? options.envPath : process.env.PATH;
64
+ const pathext = options.pathext !== undefined ? options.pathext : process.env.PATHEXT;
65
+ const exists = options.exists || ((p) => fs.existsSync(p));
66
+ const home = options.home || os.homedir();
67
+ const dirs = [...splitPath(envPath, platform), ...extraSearchDirs(platform, home)];
68
+ for (const dir of dirs) {
69
+ for (const name of candidateNames(cmd, platform, pathext)) {
70
+ const full = path.join(dir, name);
71
+ try {
72
+ if (exists(full))
73
+ return full;
74
+ }
75
+ catch {
76
+ /* an unreadable dir is just not where the tool lives */
77
+ }
78
+ }
78
79
  }
79
- }
80
- return null;
80
+ return null;
81
81
  }
82
-
83
82
  // A `.cmd`/`.bat` shim cannot be spawned directly on Windows (Node refuses
84
83
  // with EINVAL): it needs cmd.exe. `spawnArgv` rewrites the argv for that case
85
84
  // and leaves everything else untouched, so callers keep passing plain arrays.
86
85
  export function spawnArgv(argv, platform = process.platform) {
87
- if (platform !== 'win32') return { command: argv[0], args: argv.slice(1) };
88
- if (!/\.(cmd|bat)$/i.test(argv[0] || '')) return { command: argv[0], args: argv.slice(1) };
89
- const quoted = argv.map((a) => `"${String(a).replace(/"/g, '\\"')}"`).join(' ');
90
- return { command: 'cmd.exe', args: ['/d', '/s', '/c', quoted] };
86
+ if (platform !== 'win32')
87
+ return { command: argv[0], args: argv.slice(1) };
88
+ if (!/\.(cmd|bat)$/i.test(argv[0] || ''))
89
+ return { command: argv[0], args: argv.slice(1) };
90
+ const quoted = argv.map((a) => `"${String(a).replace(/"/g, '\\"')}"`).join(' ');
91
+ return { command: 'cmd.exe', args: ['/d', '/s', '/c', quoted] };
91
92
  }
93
+ //# sourceMappingURL=platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/server/tools/platform.ts"],"names":[],"mappings":"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","sourcesContent":["// Cross-platform binary lookup.\n//\n// The engine used to ask the Unix `which` command where a tool lives. That is\n// the right answer on macOS and Linux and *no* answer on Windows, where the\n// command is `where` and an npm-installed tool is a `npm.cmd` shim, not an\n// ELF file. Doing the lookup by hand — split PATH, try the PATHEXT suffixes\n// on Windows — keeps one code path for all three platforms, keeps it testable\n// (`exists` is injectable), and removes a spawned process from detection.\n//\n// `findOnPath` also checks a couple of well-known directories that are on a\n// user's interactive PATH but often not on the server's — Homebrew on Apple\n// Silicon is the classic case — and the folder Onboarder's own installer\n// drops downloaded binaries into, so a tool installed from the GUI is found\n// on the next status check without a server restart.\n\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\n// Where `install.js` puts binaries it downloads itself (gitleaks on Linux and\n// Windows). One fixed place, under the user's home, never the scanned repo.\nexport function onboarderBinDir(home = os.homedir()) {\n return path.join(home, '.onboarder', 'bin');\n}\n\n// The names a command can go by on disk. Windows resolves `npm` to the first\n// of `npm.exe`, `npm.cmd`, … on PATHEXT; POSIX looks for the name as-is.\nexport function candidateNames(cmd, platform = process.platform, pathext = '') {\n if (platform !== 'win32') return [cmd];\n const exts = (pathext || process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM')\n .split(';').map((e) => e.trim()).filter(Boolean);\n const lower = cmd.toLowerCase();\n if (exts.some((e) => lower.endsWith(e.toLowerCase()))) return [cmd];\n return [cmd, ...exts.map((e) => cmd + e.toLowerCase())];\n}\n\n// Directories worth checking beyond PATH itself. The Homebrew pair matters on\n// a Mac launched from Spotlight rather than a shell; the Onboarder bin dir is\n// where the GUI installer puts self-downloaded tools.\nexport function extraSearchDirs(platform = process.platform, home = os.homedir()) {\n const dirs = [onboarderBinDir(home)];\n if (platform === 'darwin') dirs.push('/opt/homebrew/bin', '/usr/local/bin');\n if (platform === 'linux') dirs.push('/usr/local/bin', path.join(home, '.local', 'bin'));\n if (platform === 'win32') {\n const local = process.env.LOCALAPPDATA;\n if (local) dirs.push(path.join(local, 'Programs', 'Gitleaks'));\n }\n return dirs;\n}\n\n// Split a PATH string the way the platform does. Exported for tests.\nexport function splitPath(pathValue, platform = process.platform) {\n return String(pathValue || '')\n .split(platform === 'win32' ? ';' : ':')\n .map((d) => d.trim())\n .filter(Boolean);\n}\n\n// Find `cmd` on PATH (plus the extra dirs). Returns the absolute path, or\n// null. Pure apart from the `exists` probe, which defaults to the disk and is\n// injectable so the tests never touch a real filesystem layout.\nexport function findOnPath(cmd, options: Record<string, any> = {}) {\n const platform = options.platform || process.platform;\n const envPath = options.envPath !== undefined ? options.envPath : process.env.PATH;\n const pathext = options.pathext !== undefined ? options.pathext : process.env.PATHEXT;\n const exists = options.exists || ((p) => fs.existsSync(p));\n const home = options.home || os.homedir();\n\n const dirs = [...splitPath(envPath, platform), ...extraSearchDirs(platform, home)];\n for (const dir of dirs) {\n for (const name of candidateNames(cmd, platform, pathext)) {\n const full = path.join(dir, name);\n try {\n if (exists(full)) return full;\n } catch {\n /* an unreadable dir is just not where the tool lives */\n }\n }\n }\n return null;\n}\n\n// A `.cmd`/`.bat` shim cannot be spawned directly on Windows (Node refuses\n// with EINVAL): it needs cmd.exe. `spawnArgv` rewrites the argv for that case\n// and leaves everything else untouched, so callers keep passing plain arrays.\nexport function spawnArgv(argv, platform = process.platform) {\n if (platform !== 'win32') return { command: argv[0], args: argv.slice(1) };\n if (!/\\.(cmd|bat)$/i.test(argv[0] || '')) return { command: argv[0], args: argv.slice(1) };\n const quoted = argv.map((a) => `\"${String(a).replace(/\"/g, '\\\\\"')}\"`).join(' ');\n return { command: 'cmd.exe', args: ['/d', '/s', '/c', quoted] };\n}\n"]}
@@ -0,0 +1,137 @@
1
+ export declare const TOOL_DEFS: ({
2
+ id: string;
3
+ label: string;
4
+ kind: string;
5
+ purpose: string;
6
+ commands: ({
7
+ kind: string;
8
+ bin: string;
9
+ pkg?: undefined;
10
+ } | {
11
+ kind: string;
12
+ pkg: string;
13
+ bin: string;
14
+ })[];
15
+ install: string[];
16
+ options: {
17
+ key: string;
18
+ label: string;
19
+ type: string;
20
+ values: string[];
21
+ default: string;
22
+ hint: string;
23
+ }[];
24
+ argv: (root: any, options?: Record<string, any>) => any[];
25
+ parse: (text: any, root: any) => any[];
26
+ usesReportFile?: undefined;
27
+ textOutput?: undefined;
28
+ cwd?: undefined;
29
+ } | {
30
+ id: string;
31
+ label: string;
32
+ kind: string;
33
+ purpose: string;
34
+ commands: {
35
+ kind: string;
36
+ bin: string;
37
+ }[];
38
+ install: string[];
39
+ options: {
40
+ key: string;
41
+ label: string;
42
+ type: string;
43
+ default: boolean;
44
+ hint: string;
45
+ }[];
46
+ usesReportFile: boolean;
47
+ argv: (root: any, options?: Record<string, any>, ctx?: Record<string, any>) => any[];
48
+ parse: (text: any, root: any) => any[];
49
+ textOutput?: undefined;
50
+ cwd?: undefined;
51
+ } | {
52
+ usesReportFile?: undefined;
53
+ id: string;
54
+ label: string;
55
+ kind: string;
56
+ purpose: string;
57
+ commands: ({
58
+ pkg?: undefined;
59
+ kind: string;
60
+ bin: string;
61
+ } | {
62
+ bin?: undefined;
63
+ kind: string;
64
+ pkg: string;
65
+ })[];
66
+ install: string[];
67
+ options: {
68
+ key: string;
69
+ label: string;
70
+ type: string;
71
+ values: string[];
72
+ default: any[];
73
+ hint: string;
74
+ }[];
75
+ argv: (root: any, options?: Record<string, any>) => any[];
76
+ parse: (text: any, root: any) => any[];
77
+ textOutput?: undefined;
78
+ cwd?: undefined;
79
+ } | {
80
+ usesReportFile?: undefined;
81
+ id: string;
82
+ label: string;
83
+ kind: string;
84
+ purpose: string;
85
+ commands: ({
86
+ pkg?: undefined;
87
+ kind: string;
88
+ bin: string;
89
+ } | {
90
+ kind: string;
91
+ pkg: string;
92
+ bin: string;
93
+ })[];
94
+ install: string[];
95
+ options: {
96
+ key: string;
97
+ label: string;
98
+ type: string;
99
+ min: number;
100
+ max: number;
101
+ default: number;
102
+ hint: string;
103
+ }[];
104
+ argv: (root: any, options?: Record<string, any>) => any[];
105
+ parse: (text: any, root: any) => any[];
106
+ textOutput: boolean;
107
+ cwd?: undefined;
108
+ } | {
109
+ usesReportFile?: undefined;
110
+ textOutput?: undefined;
111
+ id: string;
112
+ label: string;
113
+ kind: string;
114
+ purpose: string;
115
+ commands: ({
116
+ pkg?: undefined;
117
+ kind: string;
118
+ bin: string;
119
+ } | {
120
+ bin?: undefined;
121
+ kind: string;
122
+ pkg: string;
123
+ })[];
124
+ install: string[];
125
+ options: {
126
+ key: string;
127
+ label: string;
128
+ type: string;
129
+ default: boolean;
130
+ hint: string;
131
+ }[];
132
+ argv: (root: any, options?: Record<string, any>) => string[];
133
+ cwd: boolean;
134
+ parse: (text: any) => any[];
135
+ })[];
136
+ export declare function sanitizeOptions(def: any, raw: any): Record<string, any>;
137
+ export declare function defaultOptions(def: any): Record<string, any>;