codebase-onboarder 0.6.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (526) hide show
  1. package/README.md +284 -53
  2. package/bin/build-if-source.js +23 -0
  3. package/bin/onboarder.js +0 -0
  4. package/cli/agent/command.d.ts +71 -0
  5. package/cli/agent/command.js +177 -0
  6. package/cli/agent/command.js.map +1 -0
  7. package/cli/agent/config.d.ts +31 -0
  8. package/cli/agent/config.js +98 -0
  9. package/cli/agent/config.js.map +1 -0
  10. package/cli/agent/contracts.d.ts +77 -0
  11. package/cli/agent/contracts.js +2 -0
  12. package/cli/agent/contracts.js.map +1 -0
  13. package/cli/agent/files.d.ts +19 -0
  14. package/cli/agent/files.js +109 -0
  15. package/cli/agent/files.js.map +1 -0
  16. package/cli/agent/gitSource.d.ts +18 -0
  17. package/cli/agent/gitSource.js +69 -0
  18. package/cli/agent/gitSource.js.map +1 -0
  19. package/cli/agent/github.d.ts +21 -0
  20. package/cli/agent/github.js +94 -0
  21. package/cli/agent/github.js.map +1 -0
  22. package/cli/agent/mcp.d.ts +15 -0
  23. package/cli/agent/mcp.js +78 -0
  24. package/cli/agent/mcp.js.map +1 -0
  25. package/cli/agent/process.d.ts +18 -0
  26. package/cli/agent/process.js +118 -0
  27. package/cli/agent/process.js.map +1 -0
  28. package/cli/agent/protocol.d.ts +3 -0
  29. package/cli/agent/protocol.js +26 -0
  30. package/cli/agent/protocol.js.map +1 -0
  31. package/cli/agent/runner.d.ts +34 -0
  32. package/cli/agent/runner.js +152 -0
  33. package/cli/agent/runner.js.map +1 -0
  34. package/cli/agent/stdio.d.ts +1 -0
  35. package/cli/agent/stdio.js +62 -0
  36. package/cli/agent/stdio.js.map +1 -0
  37. package/cli/agent/tools.d.ts +7 -0
  38. package/cli/agent/tools.js +201 -0
  39. package/cli/agent/tools.js.map +1 -0
  40. package/cli/chat/app.d.ts +16 -0
  41. package/cli/chat/app.js +345 -0
  42. package/cli/chat/app.js.map +1 -0
  43. package/cli/chat/commands.d.ts +11 -0
  44. package/cli/chat/commands.js +120 -0
  45. package/cli/chat/commands.js.map +1 -0
  46. package/cli/chat/composer.d.ts +75 -0
  47. package/cli/chat/composer.js +467 -0
  48. package/cli/chat/composer.js.map +1 -0
  49. package/cli/chat/controller.d.ts +60 -0
  50. package/cli/chat/controller.js +393 -0
  51. package/cli/chat/controller.js.map +1 -0
  52. package/cli/chat/logo.d.ts +3 -0
  53. package/cli/chat/logo.js +14 -0
  54. package/cli/chat/logo.js.map +1 -0
  55. package/cli/chat/models.d.ts +18 -0
  56. package/cli/chat/models.js +88 -0
  57. package/cli/chat/models.js.map +1 -0
  58. package/cli/chat/profile.d.ts +5 -0
  59. package/cli/chat/profile.js +98 -0
  60. package/cli/chat/profile.js.map +1 -0
  61. package/cli/chat/render.d.ts +40 -0
  62. package/cli/chat/render.js +259 -0
  63. package/cli/chat/render.js.map +1 -0
  64. package/cli/chat/screen.d.ts +26 -0
  65. package/cli/chat/screen.js +117 -0
  66. package/cli/chat/screen.js.map +1 -0
  67. package/cli/chat/source.d.ts +29 -0
  68. package/cli/chat/source.js +116 -0
  69. package/cli/chat/source.js.map +1 -0
  70. package/cli/chat/store.d.ts +43 -0
  71. package/cli/chat/store.js +94 -0
  72. package/cli/chat/store.js.map +1 -0
  73. package/cli/chat/text.d.ts +4 -0
  74. package/cli/chat/text.js +27 -0
  75. package/cli/chat/text.js.map +1 -0
  76. package/cli/commands.d.ts +26 -0
  77. package/cli/commands.js +836 -811
  78. package/cli/commands.js.map +1 -0
  79. package/cli/explorer/advanced.d.ts +14 -0
  80. package/cli/explorer/advanced.js +321 -329
  81. package/cli/explorer/advanced.js.map +1 -0
  82. package/cli/explorer/app.d.ts +2 -0
  83. package/cli/explorer/app.js +404 -314
  84. package/cli/explorer/app.js.map +1 -0
  85. package/cli/explorer/assistant.d.ts +9 -0
  86. package/cli/explorer/assistant.js +58 -0
  87. package/cli/explorer/assistant.js.map +1 -0
  88. package/cli/explorer/commands.d.ts +17 -0
  89. package/cli/explorer/commands.js +373 -302
  90. package/cli/explorer/commands.js.map +1 -0
  91. package/cli/explorer/featureViews.d.ts +124 -0
  92. package/cli/explorer/featureViews.js +179 -0
  93. package/cli/explorer/featureViews.js.map +1 -0
  94. package/cli/explorer/github.d.ts +21 -0
  95. package/cli/explorer/github.js +42 -44
  96. package/cli/explorer/github.js.map +1 -0
  97. package/cli/explorer/graphs.d.ts +7 -0
  98. package/cli/explorer/graphs.js +90 -95
  99. package/cli/explorer/graphs.js.map +1 -0
  100. package/cli/explorer/picker.d.ts +22 -0
  101. package/cli/explorer/picker.js +150 -0
  102. package/cli/explorer/picker.js.map +1 -0
  103. package/cli/explorer/report.d.ts +85 -0
  104. package/cli/explorer/report.js +60 -0
  105. package/cli/explorer/report.js.map +1 -0
  106. package/cli/explorer/session.d.ts +449 -0
  107. package/cli/explorer/session.js +143 -144
  108. package/cli/explorer/session.js.map +1 -0
  109. package/cli/explorer/views.d.ts +19 -0
  110. package/cli/explorer/views.js +465 -482
  111. package/cli/explorer/views.js.map +1 -0
  112. package/cli/explorer/wrap.d.ts +1 -0
  113. package/cli/explorer/wrap.js +28 -44
  114. package/cli/explorer/wrap.js.map +1 -0
  115. package/cli/main.d.ts +1 -0
  116. package/cli/main.js +251 -164
  117. package/cli/main.js.map +1 -0
  118. package/cli/prompt.d.ts +5 -0
  119. package/cli/prompt.js +84 -80
  120. package/cli/prompt.js.map +1 -0
  121. package/cli/scanOptions.d.ts +2 -0
  122. package/cli/scanOptions.js +11 -0
  123. package/cli/scanOptions.js.map +1 -0
  124. package/cli/ui.d.ts +33 -0
  125. package/cli/ui.js +35 -44
  126. package/cli/ui.js.map +1 -0
  127. package/cli/wizard.d.ts +187 -0
  128. package/cli/wizard.js +304 -284
  129. package/cli/wizard.js.map +1 -0
  130. package/docs/HERMES_RESEARCH.md +51 -0
  131. package/package.json +16 -4
  132. package/public/app.d.ts +1 -0
  133. package/public/app.js +1133 -1011
  134. package/public/app.js.map +1 -0
  135. package/public/assets/onboarder-mark.svg +11 -0
  136. package/public/browser.d.ts +71 -0
  137. package/public/browser.js +2 -0
  138. package/public/browser.js.map +1 -0
  139. package/public/index.html +54 -20
  140. package/public/js/about.d.ts +6 -0
  141. package/public/js/about.js +152 -172
  142. package/public/js/about.js.map +1 -0
  143. package/public/js/aiDraft.d.ts +4 -0
  144. package/public/js/aiDraft.js +166 -125
  145. package/public/js/aiDraft.js.map +1 -0
  146. package/public/js/analysisPanel.d.ts +7 -0
  147. package/public/js/analysisPanel.js +166 -166
  148. package/public/js/analysisPanel.js.map +1 -0
  149. package/public/js/analysisReport.d.ts +38 -0
  150. package/public/js/analysisReport.js +105 -110
  151. package/public/js/analysisReport.js.map +1 -0
  152. package/public/js/api.d.ts +29 -0
  153. package/public/js/api.js +198 -166
  154. package/public/js/api.js.map +1 -0
  155. package/public/js/atlas.d.ts +6 -0
  156. package/public/js/atlas.js +50 -58
  157. package/public/js/atlas.js.map +1 -0
  158. package/public/js/blameView.d.ts +2 -0
  159. package/public/js/blameView.js +36 -37
  160. package/public/js/blameView.js.map +1 -0
  161. package/public/js/codeTab.d.ts +3 -0
  162. package/public/js/codeTab.js +175 -180
  163. package/public/js/codeTab.js.map +1 -0
  164. package/public/js/codeViewer.d.ts +5 -0
  165. package/public/js/codeViewer.js +162 -150
  166. package/public/js/codeViewer.js.map +1 -0
  167. package/public/js/components/FileChip.d.ts +9 -0
  168. package/public/js/components/FileChip.js +45 -49
  169. package/public/js/components/FileChip.js.map +1 -0
  170. package/public/js/components/MetricSparkline.d.ts +7 -0
  171. package/public/js/components/MetricSparkline.js +35 -44
  172. package/public/js/components/MetricSparkline.js.map +1 -0
  173. package/public/js/components/RiskBadge.d.ts +9 -0
  174. package/public/js/components/RiskBadge.js +55 -63
  175. package/public/js/components/RiskBadge.js.map +1 -0
  176. package/public/js/deepAnalysisView.d.ts +99 -0
  177. package/public/js/deepAnalysisView.js +282 -302
  178. package/public/js/deepAnalysisView.js.map +1 -0
  179. package/public/js/diagramPane.d.ts +9 -0
  180. package/public/js/diagramPane.js +138 -135
  181. package/public/js/diagramPane.js.map +1 -0
  182. package/public/js/diffView.d.ts +6 -0
  183. package/public/js/diffView.js +222 -209
  184. package/public/js/diffView.js.map +1 -0
  185. package/public/js/docsView.d.ts +2 -0
  186. package/public/js/docsView.js +441 -442
  187. package/public/js/docsView.js.map +1 -0
  188. package/public/js/dom.d.ts +197 -0
  189. package/public/js/dom.js +5 -0
  190. package/public/js/dom.js.map +1 -0
  191. package/public/js/fileSourceBrowser.d.ts +5 -0
  192. package/public/js/fileSourceBrowser.js +33 -41
  193. package/public/js/fileSourceBrowser.js.map +1 -0
  194. package/public/js/flameGraph.d.ts +5 -0
  195. package/public/js/flameGraph.js +62 -72
  196. package/public/js/flameGraph.js.map +1 -0
  197. package/public/js/forceGraph.d.ts +10 -0
  198. package/public/js/forceGraph.js +581 -556
  199. package/public/js/forceGraph.js.map +1 -0
  200. package/public/js/heatmap.d.ts +4 -0
  201. package/public/js/heatmap.js +142 -164
  202. package/public/js/heatmap.js.map +1 -0
  203. package/public/js/highlight.d.ts +2 -0
  204. package/public/js/highlight.js +116 -107
  205. package/public/js/highlight.js.map +1 -0
  206. package/public/js/html.d.ts +2 -0
  207. package/public/js/html.js +14 -44
  208. package/public/js/html.js.map +1 -0
  209. package/public/js/insightsView.d.ts +5 -0
  210. package/public/js/insightsView.js +93 -111
  211. package/public/js/insightsView.js.map +1 -0
  212. package/public/js/inspector.d.ts +37 -0
  213. package/public/js/inspector.js +416 -445
  214. package/public/js/inspector.js.map +1 -0
  215. package/public/js/llm.d.ts +115 -0
  216. package/public/js/llm.js +246 -278
  217. package/public/js/llm.js.map +1 -0
  218. package/public/js/mapView.d.ts +3 -0
  219. package/public/js/mapView.js +121 -120
  220. package/public/js/mapView.js.map +1 -0
  221. package/public/js/markdown.d.ts +3 -0
  222. package/public/js/markdown.js +84 -91
  223. package/public/js/markdown.js.map +1 -0
  224. package/public/js/mindmap.d.ts +32 -0
  225. package/public/js/mindmap.js +244 -259
  226. package/public/js/mindmap.js.map +1 -0
  227. package/public/js/mobilePanels.d.ts +5 -0
  228. package/public/js/mobilePanels.js +50 -0
  229. package/public/js/mobilePanels.js.map +1 -0
  230. package/public/js/repoFiles.d.ts +12 -0
  231. package/public/js/repoFiles.js +29 -28
  232. package/public/js/repoFiles.js.map +1 -0
  233. package/public/js/reviewView.d.ts +28 -0
  234. package/public/js/reviewView.js +256 -0
  235. package/public/js/reviewView.js.map +1 -0
  236. package/public/js/sbomView.d.ts +3 -0
  237. package/public/js/sbomView.js +59 -67
  238. package/public/js/sbomView.js.map +1 -0
  239. package/public/js/scanCache.d.ts +16 -0
  240. package/public/js/scanCache.js +67 -65
  241. package/public/js/scanCache.js.map +1 -0
  242. package/public/js/search.d.ts +7 -0
  243. package/public/js/search.js +868 -800
  244. package/public/js/search.js.map +1 -0
  245. package/public/js/searchLocal.d.ts +42 -0
  246. package/public/js/searchLocal.js +87 -0
  247. package/public/js/searchLocal.js.map +1 -0
  248. package/public/js/serverSettings.d.ts +5 -0
  249. package/public/js/serverSettings.js +153 -164
  250. package/public/js/serverSettings.js.map +1 -0
  251. package/public/js/state.d.ts +798 -0
  252. package/public/js/state.js +114 -122
  253. package/public/js/state.js.map +1 -0
  254. package/public/js/tour.d.ts +6 -0
  255. package/public/js/tour.js +5 -7
  256. package/public/js/tour.js.map +1 -0
  257. package/public/js/transitions.d.ts +2 -0
  258. package/public/js/transitions.js +9 -10
  259. package/public/js/transitions.js.map +1 -0
  260. package/public/js/tree.d.ts +12 -0
  261. package/public/js/tree.js +157 -154
  262. package/public/js/tree.js.map +1 -0
  263. package/public/js/workflowsView.d.ts +3 -0
  264. package/public/js/workflowsView.js +15 -22
  265. package/public/js/workflowsView.js.map +1 -0
  266. package/public/search.css +495 -0
  267. package/public/styles.css +188 -346
  268. package/public/workbench.css +166 -0
  269. package/server/apiAuth.d.ts +3 -0
  270. package/server/apiAuth.js +18 -20
  271. package/server/apiAuth.js.map +1 -0
  272. package/server/apiDiff.d.ts +2 -0
  273. package/server/apiDiff.js +20 -18
  274. package/server/apiDiff.js.map +1 -0
  275. package/server/apiDocs.d.ts +2 -0
  276. package/server/apiDocs.js +38 -40
  277. package/server/apiDocs.js.map +1 -0
  278. package/server/apiFile.d.ts +1 -0
  279. package/server/apiFile.js +14 -17
  280. package/server/apiFile.js.map +1 -0
  281. package/server/apiGitBlame.d.ts +2 -0
  282. package/server/apiGitBlame.js +50 -51
  283. package/server/apiGitBlame.js.map +1 -0
  284. package/server/apiMcp.d.ts +4 -0
  285. package/server/apiMcp.js +64 -66
  286. package/server/apiMcp.js.map +1 -0
  287. package/server/apiReview.d.ts +2 -0
  288. package/server/apiReview.js +45 -0
  289. package/server/apiReview.js.map +1 -0
  290. package/server/apiScan.d.ts +5 -0
  291. package/server/apiScan.js +90 -71
  292. package/server/apiScan.js.map +1 -0
  293. package/server/apiSearch.d.ts +33 -0
  294. package/server/apiSearch.js +184 -200
  295. package/server/apiSearch.js.map +1 -0
  296. package/server/apiSettings.d.ts +4 -0
  297. package/server/apiSettings.js +84 -85
  298. package/server/apiSettings.js.map +1 -0
  299. package/server/apiTools.d.ts +3 -0
  300. package/server/apiTools.js +55 -56
  301. package/server/apiTools.js.map +1 -0
  302. package/server/auth.d.ts +5 -0
  303. package/server/auth.js +54 -51
  304. package/server/auth.js.map +1 -0
  305. package/server/config.d.ts +42 -0
  306. package/server/config.js +189 -194
  307. package/server/config.js.map +1 -0
  308. package/server/daemon.d.ts +12 -0
  309. package/server/daemon.js +124 -114
  310. package/server/daemon.js.map +1 -0
  311. package/server/fileSourceNode.d.ts +2 -0
  312. package/server/fileSourceNode.js +34 -36
  313. package/server/fileSourceNode.js.map +1 -0
  314. package/server/gitClone.d.ts +9 -0
  315. package/server/gitClone.js +59 -61
  316. package/server/gitClone.js.map +1 -0
  317. package/server/gitDiff.d.ts +36 -0
  318. package/server/gitDiff.js +271 -169
  319. package/server/gitDiff.js.map +1 -0
  320. package/server/gitHistory.d.ts +12 -0
  321. package/server/gitHistory.js +80 -80
  322. package/server/gitHistory.js.map +1 -0
  323. package/server/gitRemote.d.ts +12 -0
  324. package/server/gitRemote.js +37 -38
  325. package/server/gitRemote.js.map +1 -0
  326. package/server/hermesChat.d.ts +13 -0
  327. package/server/hermesChat.js +145 -0
  328. package/server/hermesChat.js.map +1 -0
  329. package/server/htmlText.d.ts +4 -0
  330. package/server/htmlText.js +16 -23
  331. package/server/htmlText.js.map +1 -0
  332. package/server/http.d.ts +6 -0
  333. package/server/http.js +27 -34
  334. package/server/http.js.map +1 -0
  335. package/server/httpGuards.d.ts +2 -0
  336. package/server/httpGuards.js +47 -43
  337. package/server/httpGuards.js.map +1 -0
  338. package/server/https.d.ts +34 -0
  339. package/server/https.js +121 -111
  340. package/server/https.js.map +1 -0
  341. package/server/index.d.ts +40 -0
  342. package/server/index.js +139 -147
  343. package/server/index.js.map +1 -0
  344. package/server/layout.d.ts +26 -0
  345. package/server/layout.js +59 -64
  346. package/server/layout.js.map +1 -0
  347. package/server/llmProxy.d.ts +3 -0
  348. package/server/llmProxy.js +137 -135
  349. package/server/llmProxy.js.map +1 -0
  350. package/server/logger.d.ts +38 -0
  351. package/server/logger.js +198 -211
  352. package/server/logger.js.map +1 -0
  353. package/server/mcp/analysis.d.ts +29 -0
  354. package/server/mcp/analysis.js +99 -120
  355. package/server/mcp/analysis.js.map +1 -0
  356. package/server/mcp/http.d.ts +9 -0
  357. package/server/mcp/http.js +128 -137
  358. package/server/mcp/http.js.map +1 -0
  359. package/server/mcp/runner.d.ts +68 -0
  360. package/server/mcp/runner.js +208 -218
  361. package/server/mcp/runner.js.map +1 -0
  362. package/server/mcp/server.d.ts +29 -0
  363. package/server/mcp/server.js +167 -180
  364. package/server/mcp/server.js.map +1 -0
  365. package/server/mcp/standalone.d.ts +1 -0
  366. package/server/mcp/standalone.js +8 -10
  367. package/server/mcp/standalone.js.map +1 -0
  368. package/server/mcp/tools.d.ts +2020 -0
  369. package/server/mcp/tools.js +523 -574
  370. package/server/mcp/tools.js.map +1 -0
  371. package/server/paths.d.ts +3 -0
  372. package/server/paths.js +17 -15
  373. package/server/paths.js.map +1 -0
  374. package/server/pidfile.d.ts +9 -0
  375. package/server/pidfile.js +43 -45
  376. package/server/pidfile.js.map +1 -0
  377. package/server/review.d.ts +5 -0
  378. package/server/review.js +35 -0
  379. package/server/review.js.map +1 -0
  380. package/server/router.d.ts +33 -0
  381. package/server/router.js +195 -197
  382. package/server/router.js.map +1 -0
  383. package/server/scanRequest.d.ts +3 -0
  384. package/server/scanRequest.js +36 -0
  385. package/server/scanRequest.js.map +1 -0
  386. package/server/searchIndex.d.ts +17 -0
  387. package/server/searchIndex.js +83 -80
  388. package/server/searchIndex.js.map +1 -0
  389. package/server/sessions.d.ts +14 -0
  390. package/server/sessions.js +62 -70
  391. package/server/sessions.js.map +1 -0
  392. package/server/startup.d.ts +118 -0
  393. package/server/startup.js +143 -148
  394. package/server/startup.js.map +1 -0
  395. package/server/static.d.ts +6 -0
  396. package/server/static.js +28 -31
  397. package/server/static.js.map +1 -0
  398. package/server/tools/install.d.ts +4 -0
  399. package/server/tools/install.js +176 -185
  400. package/server/tools/install.js.map +1 -0
  401. package/server/tools/parse.d.ts +8 -0
  402. package/server/tools/parse.js +112 -114
  403. package/server/tools/parse.js.map +1 -0
  404. package/server/tools/platform.d.ts +9 -0
  405. package/server/tools/platform.js +49 -47
  406. package/server/tools/platform.js.map +1 -0
  407. package/server/tools/registry.d.ts +137 -0
  408. package/server/tools/registry.js +173 -172
  409. package/server/tools/registry.js.map +1 -0
  410. package/server/tools/scan.d.ts +34 -0
  411. package/server/tools/scan.js +89 -98
  412. package/server/tools/scan.js.map +1 -0
  413. package/server/tools.d.ts +34 -0
  414. package/server/tools.js +94 -107
  415. package/server/tools.js.map +1 -0
  416. package/server/tunnel.d.ts +29 -0
  417. package/server/tunnel.js +61 -66
  418. package/server/tunnel.js.map +1 -0
  419. package/shared/analyzer/docs.d.ts +16 -0
  420. package/shared/analyzer/docs.js +99 -93
  421. package/shared/analyzer/docs.js.map +1 -0
  422. package/shared/analyzer/explainLocal.d.ts +4 -0
  423. package/shared/analyzer/explainLocal.js +122 -142
  424. package/shared/analyzer/explainLocal.js.map +1 -0
  425. package/shared/analyzer/github.d.ts +37 -0
  426. package/shared/analyzer/github.js +41 -43
  427. package/shared/analyzer/github.js.map +1 -0
  428. package/shared/analyzer/graph.d.ts +41 -0
  429. package/shared/analyzer/graph.js +393 -400
  430. package/shared/analyzer/graph.js.map +1 -0
  431. package/shared/analyzer/health.d.ts +33 -0
  432. package/shared/analyzer/health.js +197 -193
  433. package/shared/analyzer/health.js.map +1 -0
  434. package/shared/analyzer/history.d.ts +29 -0
  435. package/shared/analyzer/history.js +110 -111
  436. package/shared/analyzer/history.js.map +1 -0
  437. package/shared/analyzer/jsonConfig.d.ts +2 -0
  438. package/shared/analyzer/jsonConfig.js +61 -0
  439. package/shared/analyzer/jsonConfig.js.map +1 -0
  440. package/shared/analyzer/languages/csharp.d.ts +26 -0
  441. package/shared/analyzer/languages/csharp.js +83 -88
  442. package/shared/analyzer/languages/csharp.js.map +1 -0
  443. package/shared/analyzer/languages/generic.d.ts +23 -0
  444. package/shared/analyzer/languages/generic.js +94 -105
  445. package/shared/analyzer/languages/generic.js.map +1 -0
  446. package/shared/analyzer/languages/go.d.ts +24 -0
  447. package/shared/analyzer/languages/go.js +45 -54
  448. package/shared/analyzer/languages/go.js.map +1 -0
  449. package/shared/analyzer/languages/index.d.ts +6 -0
  450. package/shared/analyzer/languages/index.js +19 -20
  451. package/shared/analyzer/languages/index.js.map +1 -0
  452. package/shared/analyzer/languages/java.d.ts +20 -0
  453. package/shared/analyzer/languages/java.js +73 -78
  454. package/shared/analyzer/languages/java.js.map +1 -0
  455. package/shared/analyzer/languages/javascript.d.ts +12 -0
  456. package/shared/analyzer/languages/javascript.js +258 -209
  457. package/shared/analyzer/languages/javascript.js.map +1 -0
  458. package/shared/analyzer/languages/python.d.ts +23 -0
  459. package/shared/analyzer/languages/python.js +92 -100
  460. package/shared/analyzer/languages/python.js.map +1 -0
  461. package/shared/analyzer/languages/rust.d.ts +17 -0
  462. package/shared/analyzer/languages/rust.js +96 -98
  463. package/shared/analyzer/languages/rust.js.map +1 -0
  464. package/shared/analyzer/languages/typescript.d.ts +11 -0
  465. package/shared/analyzer/languages/typescript.js +117 -116
  466. package/shared/analyzer/languages/typescript.js.map +1 -0
  467. package/shared/analyzer/licenses.d.ts +18 -0
  468. package/shared/analyzer/licenses.js +130 -133
  469. package/shared/analyzer/licenses.js.map +1 -0
  470. package/shared/analyzer/metrics.d.ts +20 -0
  471. package/shared/analyzer/metrics.js +112 -104
  472. package/shared/analyzer/metrics.js.map +1 -0
  473. package/shared/analyzer/pathUtil.d.ts +10 -0
  474. package/shared/analyzer/pathUtil.js +29 -35
  475. package/shared/analyzer/pathUtil.js.map +1 -0
  476. package/shared/analyzer/patterns.d.ts +11 -0
  477. package/shared/analyzer/patterns.js +231 -253
  478. package/shared/analyzer/patterns.js.map +1 -0
  479. package/shared/analyzer/scan.d.ts +62 -0
  480. package/shared/analyzer/scan.js +451 -442
  481. package/shared/analyzer/scan.js.map +1 -0
  482. package/shared/analyzer/scanControl.d.ts +11 -0
  483. package/shared/analyzer/scanControl.js +62 -0
  484. package/shared/analyzer/scanControl.js.map +1 -0
  485. package/shared/analyzer/security.d.ts +18 -0
  486. package/shared/analyzer/security.js +159 -159
  487. package/shared/analyzer/security.js.map +1 -0
  488. package/shared/analyzer/services.d.ts +5 -0
  489. package/shared/analyzer/services.js +141 -138
  490. package/shared/analyzer/services.js.map +1 -0
  491. package/shared/analyzer/stack.d.ts +6 -0
  492. package/shared/analyzer/stack.js +134 -141
  493. package/shared/analyzer/stack.js.map +1 -0
  494. package/shared/analyzer/tour.d.ts +2 -0
  495. package/shared/analyzer/tour.js +45 -53
  496. package/shared/analyzer/tour.js.map +1 -0
  497. package/shared/analyzer/util.d.ts +8 -0
  498. package/shared/analyzer/util.js +130 -76
  499. package/shared/analyzer/util.js.map +1 -0
  500. package/shared/analyzer/workflows.d.ts +8 -0
  501. package/shared/analyzer/workflows.js +139 -134
  502. package/shared/analyzer/workflows.js.map +1 -0
  503. package/shared/contracts.d.ts +250 -0
  504. package/shared/contracts.js +2 -0
  505. package/shared/contracts.js.map +1 -0
  506. package/shared/diagram/aiFacts.d.ts +35 -0
  507. package/shared/diagram/aiFacts.js +102 -105
  508. package/shared/diagram/aiFacts.js.map +1 -0
  509. package/shared/diagram/aiMermaid.d.ts +5 -0
  510. package/shared/diagram/aiMermaid.js +50 -46
  511. package/shared/diagram/aiMermaid.js.map +1 -0
  512. package/shared/diagram/atlas.d.ts +16 -0
  513. package/shared/diagram/atlas.js +51 -60
  514. package/shared/diagram/atlas.js.map +1 -0
  515. package/shared/diagram/mermaid.d.ts +43 -0
  516. package/shared/diagram/mermaid.js +348 -370
  517. package/shared/diagram/mermaid.js.map +1 -0
  518. package/shared/review/contracts.d.ts +95 -0
  519. package/shared/review/contracts.js +2 -0
  520. package/shared/review/contracts.js.map +1 -0
  521. package/shared/review/review.d.ts +10 -0
  522. package/shared/review/review.js +184 -0
  523. package/shared/review/review.js.map +1 -0
  524. package/shared/search/query.d.ts +32 -0
  525. package/shared/search/query.js +395 -388
  526. package/shared/search/query.js.map +1 -0
package/server/router.js CHANGED
@@ -9,156 +9,159 @@
9
9
  // `Sec-Fetch-Site` to stop another page and DNS rebinding from driving it.
10
10
  // Self-hosted mode adds real access-key authentication: local browser requests
11
11
  // stay open, remote browsers get a signed session, and API clients use Bearer.
12
-
13
12
  import { handleDocs } from './apiDocs.js';
14
13
  import { handleFile } from './apiFile.js';
15
14
  import { handleCleanup, handleScan } from './apiScan.js';
16
15
  import { sendError, sendJSON, readBody } from './http.js';
17
16
  import { crossOriginReason, rebindingReason } from './httpGuards.js';
18
17
  import { proxyChat } from './llmProxy.js';
18
+ import { hermesWeb } from './hermesChat.js';
19
19
  import { serveStatic } from './static.js';
20
20
  import { handleSearch } from './apiSearch.js';
21
21
  import { handleBlame } from './apiGitBlame.js';
22
22
  import { handleDiff, handleDiffRefs } from './apiDiff.js';
23
+ import { handleReview } from './apiReview.js';
23
24
  import { handleToolsInstall, handleToolsRun, handleToolsStatus } from './apiTools.js';
24
25
  import { handleMcpStart, handleMcpStatus, handleMcpStop, handleMcpCommand } from './apiMcp.js';
25
26
  import { handleGetSettings, handleRotateAccessKey, handleUpdateSettings } from './apiSettings.js';
26
27
  import { handleAuthStatus, handleLogin, handleLogout } from './apiAuth.js';
27
28
  import { accessKeysMatch, allowedHosts, authReason, bearerToken, DEFAULT_SETTINGS } from './config.js';
28
29
  import { hasValidSession } from './auth.js';
29
-
30
30
  const ROUTES = [
31
- {
32
- method: 'GET', path: '/api/diff/refs', sameOrigin: true,
33
- run: ({ res, url }) => handleDiffRefs(res, url.searchParams.get('scan')),
34
- },
35
- {
36
- method: 'GET', path: '/api/diff', sameOrigin: true,
37
- run: ({ res, url }) => handleDiff(res, url.searchParams.get('scan'), url.searchParams),
38
- },
39
- {
40
- method: 'POST', path: '/api/search', body: true,
41
- run: ({ res, body }) => handleSearch(res, body),
42
- },
43
- {
44
- method: 'GET', path: '/api/blame', sameOrigin: true,
45
- run: ({ res, url }) => handleBlame(res, url.searchParams.get('scan'), url.searchParams.get('path')),
46
- },
47
- {
48
- method: 'POST', path: '/api/scan', body: true,
49
- run: ({ res, body, config }) => handleScan(res, body, config),
50
- },
51
- {
52
- method: 'DELETE', prefix: '/api/scan/',
53
- run: ({ res, rest }) => handleCleanup(res, decodeURIComponent(rest)),
54
- },
55
- {
56
- method: 'GET', path: '/api/file', sameOrigin: true,
57
- run: ({ res, url }) => handleFile(res, url.searchParams.get('scan'), url.searchParams.get('path')),
58
- },
59
- {
60
- // The proxy is the handler; there is no wrapper to write. It forwards the
61
- // browser's key to the endpoint the browser chose and never keeps either.
62
- method: 'POST', path: '/api/explain', body: true,
63
- run: ({ res, body }) => proxyChat(res, body),
64
- },
65
- {
66
- method: 'POST', path: '/api/doc', body: true,
67
- run: ({ res, body }) => handleDocs(res, body),
68
- },
69
- {
70
- // Reports which analyzers are installed — environment information a foreign
71
- // page has no business reading, so it is guarded like /api/file.
72
- method: 'GET', path: '/api/tools', sameOrigin: true,
73
- run: ({ res }) => handleToolsStatus(res),
74
- },
75
- {
76
- // Runs real analyzers over a scanned root. `body: true` applies the size
77
- // limit; the session check in the handler is the capability gate.
78
- method: 'POST', path: '/api/tools/run', body: true,
79
- run: ({ res, body }) => handleToolsRun(res, body),
80
- },
81
- {
82
- // Installs a missing analyzer from the GUI. Same-origin like every POST;
83
- // the tool name is validated against the registry and the install plans
84
- // are fixed data, so the request body never reaches a command line.
85
- method: 'POST', path: '/api/tools/install', body: true,
86
- run: ({ res, body }) => handleToolsInstall(res, body),
87
- },
88
- {
89
- // The MCP button's state, and the command an agent harness is configured with.
90
- // The config is not secret, but it is a path into this machine and a foreign
91
- // page has no business reading either one.
92
- method: 'GET', path: '/api/mcp', sameOrigin: true,
93
- run: ({ req, res, config }) => handleMcpStatus(req, res, config),
94
- },
95
- {
96
- method: 'GET', path: '/api/mcp/command', sameOrigin: true,
97
- run: ({ req, res, config }) => handleMcpCommand(req, res, config),
98
- },
99
- {
100
- // Starting and stopping a process is a side effect on the person's machine, so
101
- // these take a body like every other POST and are checked like every other POST.
102
- method: 'POST', path: '/api/mcp/start', body: true,
103
- run: ({ req, res, config }) => handleMcpStart(req, res, config),
104
- },
105
- {
106
- method: 'POST', path: '/api/mcp/stop', body: true,
107
- run: ({ req, res, config }) => handleMcpStop(req, res, config),
108
- },
109
- {
110
- method: 'GET', path: '/api/health',
111
- run: ({ res }) => sendJSON(res, 200, { ok: true }),
112
- },
113
- {
114
- method: 'GET', path: '/api/auth/status', sameOrigin: true,
115
- run: ({ req, res, settings }) => handleAuthStatus(req, res, settings),
116
- },
117
- {
118
- method: 'POST', path: '/api/auth/login', body: true, sameOrigin: true,
119
- run: ({ req, res, body, settings }) => handleLogin(req, res, body, settings),
120
- },
121
- {
122
- method: 'POST', path: '/api/auth/logout', body: true, sameOrigin: true,
123
- run: ({ req, res }) => handleLogout(req, res),
124
- },
125
- {
126
- // The settings drawer and the CLI read the same public shape: everything
127
- // about the configuration except the access key itself.
128
- method: 'GET', path: '/api/settings', sameOrigin: true,
129
- run: ({ req, res, config }) => handleGetSettings(req, res, config),
130
- },
131
- {
132
- // PATCH semantics over a small allow-listed key set; the validation that
133
- // rejects a bad port or a lawless mode lives in `server/config.js` and is
134
- // shared with the CLI wizard, so both surfaces enforce one schema.
135
- method: 'PUT', path: '/api/settings', body: true,
136
- run: ({ res, body, config }) => handleUpdateSettings(res, body, config),
137
- },
138
- {
139
- // The only way the key changes: generated on the server, shown once in
140
- // this response, never readable again. In self-hosted mode this endpoint
141
- // is itself behind the current key, so rotation requires possession.
142
- method: 'POST', path: '/api/settings/access-key', body: true,
143
- run: ({ req, res, config }) => handleRotateAccessKey(req, res, config),
144
- },
31
+ { method: 'POST', path: '/api/review', body: true, run: ({ res, body }) => handleReview(res, body) },
32
+ {
33
+ method: 'GET', path: '/api/diff/refs', sameOrigin: true,
34
+ run: ({ res, url }) => handleDiffRefs(res, url.searchParams.get('scan')),
35
+ },
36
+ {
37
+ method: 'GET', path: '/api/diff', sameOrigin: true,
38
+ run: ({ res, url }) => handleDiff(res, url.searchParams.get('scan'), url.searchParams),
39
+ },
40
+ {
41
+ method: 'POST', path: '/api/search', body: true,
42
+ run: ({ res, body }) => handleSearch(res, body),
43
+ },
44
+ {
45
+ method: 'GET', path: '/api/blame', sameOrigin: true,
46
+ run: ({ res, url }) => handleBlame(res, url.searchParams.get('scan'), url.searchParams.get('path')),
47
+ },
48
+ {
49
+ method: 'POST', path: '/api/scan', body: true,
50
+ run: ({ res, body, config }) => handleScan(res, body, config),
51
+ },
52
+ {
53
+ method: 'DELETE', prefix: '/api/scan/',
54
+ run: ({ res, rest }) => handleCleanup(res, decodeURIComponent(rest)),
55
+ },
56
+ {
57
+ method: 'GET', path: '/api/file', sameOrigin: true,
58
+ run: ({ res, url }) => handleFile(res, url.searchParams.get('scan'), url.searchParams.get('path')),
59
+ },
60
+ {
61
+ // Hermes owns its server-side login. API mode forwards the browser's key
62
+ // to its chosen endpoint. Both share the same streaming response contract.
63
+ method: 'POST', path: '/api/explain', body: true,
64
+ run: ({ res, body, config }) => body?.connection === 'hermes'
65
+ ? (config.hermes || hermesWeb).chat(res, body) : proxyChat(res, body),
66
+ },
67
+ { method: 'GET', path: '/api/hermes', sameOrigin: true,
68
+ run: ({ res, config }) => (config.hermes || hermesWeb).status(res) },
69
+ {
70
+ method: 'POST', path: '/api/doc', body: true,
71
+ run: ({ res, body }) => handleDocs(res, body),
72
+ },
73
+ {
74
+ // Reports which analyzers are installed — environment information a foreign
75
+ // page has no business reading, so it is guarded like /api/file.
76
+ method: 'GET', path: '/api/tools', sameOrigin: true,
77
+ run: ({ res }) => handleToolsStatus(res),
78
+ },
79
+ {
80
+ // Runs real analyzers over a scanned root. `body: true` applies the size
81
+ // limit; the session check in the handler is the capability gate.
82
+ method: 'POST', path: '/api/tools/run', body: true,
83
+ run: ({ res, body }) => handleToolsRun(res, body),
84
+ },
85
+ {
86
+ // Installs a missing analyzer from the GUI. Same-origin like every POST;
87
+ // the tool name is validated against the registry and the install plans
88
+ // are fixed data, so the request body never reaches a command line.
89
+ method: 'POST', path: '/api/tools/install', body: true,
90
+ run: ({ res, body }) => handleToolsInstall(res, body),
91
+ },
92
+ {
93
+ // The MCP button's state, and the command an agent harness is configured with.
94
+ // The config is not secret, but it is a path into this machine and a foreign
95
+ // page has no business reading either one.
96
+ method: 'GET', path: '/api/mcp', sameOrigin: true,
97
+ run: ({ req, res, config }) => handleMcpStatus(req, res, config),
98
+ },
99
+ {
100
+ method: 'GET', path: '/api/mcp/command', sameOrigin: true,
101
+ run: ({ req, res, config }) => handleMcpCommand(req, res, config),
102
+ },
103
+ {
104
+ // Starting and stopping a process is a side effect on the person's machine, so
105
+ // these take a body like every other POST and are checked like every other POST.
106
+ method: 'POST', path: '/api/mcp/start', body: true,
107
+ run: ({ req, res, config }) => handleMcpStart(req, res, config),
108
+ },
109
+ {
110
+ method: 'POST', path: '/api/mcp/stop', body: true,
111
+ run: ({ req, res, config }) => handleMcpStop(req, res, config),
112
+ },
113
+ {
114
+ method: 'GET', path: '/api/health',
115
+ run: ({ res }) => sendJSON(res, 200, { ok: true }),
116
+ },
117
+ {
118
+ method: 'GET', path: '/api/auth/status', sameOrigin: true,
119
+ run: ({ req, res, settings }) => handleAuthStatus(req, res, settings),
120
+ },
121
+ {
122
+ method: 'POST', path: '/api/auth/login', body: true, sameOrigin: true,
123
+ run: ({ req, res, body, settings }) => handleLogin(req, res, body, settings),
124
+ },
125
+ {
126
+ method: 'POST', path: '/api/auth/logout', body: true, sameOrigin: true,
127
+ run: ({ req, res }) => handleLogout(req, res),
128
+ },
129
+ {
130
+ // The settings drawer and the CLI read the same public shape: everything
131
+ // about the configuration except the access key itself.
132
+ method: 'GET', path: '/api/settings', sameOrigin: true,
133
+ run: ({ req, res, config }) => handleGetSettings(req, res, config),
134
+ },
135
+ {
136
+ // PATCH semantics over a small allow-listed key set; the validation that
137
+ // rejects a bad port or a lawless mode lives in `server/config.js` and is
138
+ // shared with the CLI wizard, so both surfaces enforce one schema.
139
+ method: 'PUT', path: '/api/settings', body: true,
140
+ run: ({ res, body, config }) => handleUpdateSettings(res, body, config),
141
+ },
142
+ {
143
+ // The only way the key changes: generated on the server, shown once in
144
+ // this response, never readable again. In self-hosted mode this endpoint
145
+ // is itself behind the current key, so rotation requires possession.
146
+ method: 'POST', path: '/api/settings/access-key', body: true,
147
+ run: ({ req, res, config }) => handleRotateAccessKey(req, res, config),
148
+ },
145
149
  ];
146
-
147
150
  // The table itself, for the test that walks it. Exported read-only: the routes
148
151
  // are decided here, not assembled by whoever imports this.
149
152
  export const routes = Object.freeze(ROUTES.map((r) => Object.freeze({ ...r })));
150
-
151
153
  export function matchRoute(method, pathname) {
152
- for (const route of ROUTES) {
153
- if (route.method !== method) continue;
154
- if (route.path === pathname) return { route, rest: '' };
155
- if (route.prefix && pathname.startsWith(route.prefix)) {
156
- return { route, rest: pathname.slice(route.prefix.length) };
154
+ for (const route of ROUTES) {
155
+ if (route.method !== method)
156
+ continue;
157
+ if (route.path === pathname)
158
+ return { route, rest: '' };
159
+ if (route.prefix && pathname.startsWith(route.prefix)) {
160
+ return { route, rest: pathname.slice(route.prefix.length) };
161
+ }
157
162
  }
158
- }
159
- return null;
163
+ return null;
160
164
  }
161
-
162
165
  // `config` carries the directories the handlers need — the project root to scan
163
166
  // for the demo, and the two roots static serving maps into. Passed in rather
164
167
  // than resolved here so a test can point the server somewhere else, and so this
@@ -169,79 +172,74 @@ export function matchRoute(method, pathname) {
169
172
  // request without a restart. A bare `createServer()` (the tests) has no getter
170
173
  // and sees the local-mode defaults — never somebody's home directory.
171
174
  async function liveSettings(config) {
172
- if (typeof config?.getSettings !== 'function') return DEFAULT_SETTINGS;
173
- try {
174
- return await config.getSettings();
175
- } catch {
176
- return null; // unreadable config: fail closed, every /api call gets a 500
177
- }
175
+ if (typeof config?.getSettings !== 'function')
176
+ return DEFAULT_SETTINGS;
177
+ try {
178
+ return await config.getSettings();
179
+ }
180
+ catch {
181
+ return null; // unreadable config: fail closed, every /api call gets a 500
182
+ }
178
183
  }
179
-
180
184
  export function createRouter(config) {
181
- return async function handleRequest(req, res) {
182
- try {
183
- const url = new URL(req.url, 'http://127.0.0.1');
184
-
185
- const settings = await liveSettings(config);
186
- if (!settings) {
187
- return sendError(res, 500, 'The settings file could not be read — run `onboarder doctor` to find out why.');
188
- }
189
-
190
- const wrongHost = rebindingReason(req, allowedHosts(settings));
191
- if (wrongHost) {
192
- const scope = settings.mode === 'self-hosted'
193
- ? 'Onboarder only answers to its configured host and domain. '
194
- : 'Onboarder only answers to localhost. ';
195
- return sendError(res, 403, scope + wrongHost);
196
- }
197
-
198
- const found = matchRoute(req.method, url.pathname);
199
- const publicAuthRoute = ['/api/health', '/api/auth/status', '/api/auth/login', '/api/auth/logout'].includes(url.pathname);
200
- if (req.method !== 'GET' || found?.route.sameOrigin) {
201
- const foreign = crossOriginReason(req);
202
- if (foreign) {
203
- return sendError(res, 403, 'That request did not come from Onboarder’s own page. ' + foreign);
185
+ return async function handleRequest(req, res) {
186
+ try {
187
+ const url = new URL(req.url, 'http://127.0.0.1');
188
+ const settings = await liveSettings(config);
189
+ if (!settings) {
190
+ return sendError(res, 500, 'The settings file could not be read — run `onboarder doctor` to find out why.');
191
+ }
192
+ const wrongHost = rebindingReason(req, allowedHosts(settings));
193
+ if (wrongHost) {
194
+ const scope = settings.mode === 'self-hosted'
195
+ ? 'Onboarder only answers to its configured host and domain. '
196
+ : 'Onboarder only answers to localhost. ';
197
+ return sendError(res, 403, scope + wrongHost);
198
+ }
199
+ const found = matchRoute(req.method, url.pathname);
200
+ const publicAuthRoute = ['/api/health', '/api/auth/status', '/api/auth/login', '/api/auth/logout'].includes(url.pathname);
201
+ if (req.method !== 'GET' || found?.route.sameOrigin) {
202
+ const foreign = crossOriginReason(req);
203
+ if (foreign) {
204
+ return sendError(res, 403, 'That request did not come from Onboarder’s own page. ' + foreign);
205
+ }
206
+ }
207
+ // Bearer clients keep their existing API contract. A browser gets a signed,
208
+ // HttpOnly session from the login form instead of storing the raw key.
209
+ const bearerClient = accessKeysMatch(settings.accessKey, bearerToken(req));
210
+ const browserAuthenticated = hasValidSession(req, settings);
211
+ const authDenied = authReason(req, settings);
212
+ const locallyExempt = !authDenied;
213
+ const authenticated = bearerClient || browserAuthenticated || locallyExempt;
214
+ const remoteSelfHosted = settings.mode === 'self-hosted' && Boolean(authDenied);
215
+ if (remoteSelfHosted && !authenticated && !publicAuthRoute) {
216
+ // API callers keep a machine-readable 401. A browser navigation gets the
217
+ // themed sign-in document so the user never has to paste JSON into a tab.
218
+ const accepts = String(req.headers?.accept || '');
219
+ if (req.method === 'GET' && (url.pathname === '/' || accepts.includes('text/html'))) {
220
+ res.statusCode = 200;
221
+ return await serveStatic(res, '/login.html', config);
222
+ }
223
+ return sendError(res, 401, authDenied || 'Sign in with the Onboarder access key first.');
224
+ }
225
+ if (url.pathname === '/api/auth/logout') {
226
+ // Always clear the browser cookie, even if it had already expired.
227
+ return handleLogout(req, res);
228
+ }
229
+ if (found) {
230
+ const body = found.route.body ? await readBody(req) : null;
231
+ return await found.route.run({ req, res, url, body, rest: found.rest, config, settings });
232
+ }
233
+ if (req.method === 'GET')
234
+ return await serveStatic(res, url.pathname, config);
235
+ sendError(res, 404, 'Nothing lives at ' + url.pathname + '.');
204
236
  }
205
- }
206
-
207
- // Bearer clients keep their existing API contract. A browser gets a signed,
208
- // HttpOnly session from the login form instead of storing the raw key.
209
- const bearerClient = accessKeysMatch(settings.accessKey, bearerToken(req));
210
- const browserAuthenticated = hasValidSession(req, settings);
211
- const authDenied = authReason(req, settings);
212
- const locallyExempt = !authDenied;
213
- const authenticated = bearerClient || browserAuthenticated || locallyExempt;
214
- const remoteSelfHosted = settings.mode === 'self-hosted' && Boolean(authDenied);
215
-
216
- if (remoteSelfHosted && !authenticated && !publicAuthRoute) {
217
- // API callers keep a machine-readable 401. A browser navigation gets the
218
- // themed sign-in document so the user never has to paste JSON into a tab.
219
- const accepts = String(req.headers?.accept || '');
220
- if (req.method === 'GET' && (url.pathname === '/' || accepts.includes('text/html'))) {
221
- res.statusCode = 200;
222
- return await serveStatic(res, '/login.html', config);
237
+ catch (err) {
238
+ // The last resort. Handlers turn their own expected failures into a status
239
+ // that says something useful; anything reaching here is a bug or a broken
240
+ // request body, and the message is more use to the person than "500".
241
+ sendError(res, 500, err.message || 'Something went sideways.');
223
242
  }
224
- return sendError(res, 401, authDenied || 'Sign in with the Onboarder access key first.');
225
- }
226
-
227
- if (url.pathname === '/api/auth/logout') {
228
- // Always clear the browser cookie, even if it had already expired.
229
- return handleLogout(req, res);
230
- }
231
-
232
- if (found) {
233
- const body = found.route.body ? await readBody(req) : null;
234
- return await found.route.run({ req, res, url, body, rest: found.rest, config, settings });
235
- }
236
-
237
- if (req.method === 'GET') return await serveStatic(res, url.pathname, config);
238
-
239
- sendError(res, 404, 'Nothing lives at ' + url.pathname + '.');
240
- } catch (err) {
241
- // The last resort. Handlers turn their own expected failures into a status
242
- // that says something useful; anything reaching here is a bug or a broken
243
- // request body, and the message is more use to the person than "500".
244
- sendError(res, 500, err.message || 'Something went sideways.');
245
- }
246
- };
243
+ };
247
244
  }
245
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/server/router.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { Settings } from '../shared/contracts.js';\n\ninterface RouteContext { req: IncomingMessage; res: ServerResponse; url: URL; body: any; rest: string; config: any; settings: Settings }\ninterface Route { method: string; path?: string; prefix?: string; body?: boolean; sameOrigin?: boolean; run(context: RouteContext): unknown }\n// The route table and the gates in front of it.\n//\n// Everything arrives here: one function decides whether a request is allowed to\n// be answered at all, then which handler answers it. The routes are a list rather\n// than a ladder of `if` statements so that the whole surface of the server is\n// visible in one screen, and everything else is a static file.\n//\n// There are three concerns. Local mode relies on `Host`, `Origin`, and\n// `Sec-Fetch-Site` to stop another page and DNS rebinding from driving it.\n// Self-hosted mode adds real access-key authentication: local browser requests\n// stay open, remote browsers get a signed session, and API clients use Bearer.\n\nimport { handleDocs } from './apiDocs.js';\nimport { handleFile } from './apiFile.js';\nimport { handleCleanup, handleScan } from './apiScan.js';\nimport { sendError, sendJSON, readBody } from './http.js';\nimport { crossOriginReason, rebindingReason } from './httpGuards.js';\nimport { proxyChat } from './llmProxy.js';\nimport { hermesWeb } from './hermesChat.js';\nimport { serveStatic } from './static.js';\nimport { handleSearch } from './apiSearch.js';\nimport { handleBlame } from './apiGitBlame.js';\nimport { handleDiff, handleDiffRefs } from './apiDiff.js';\nimport { handleReview } from './apiReview.js';\nimport { handleToolsInstall, handleToolsRun, handleToolsStatus } from './apiTools.js';\nimport { handleMcpStart, handleMcpStatus, handleMcpStop, handleMcpCommand } from './apiMcp.js';\nimport { handleGetSettings, handleRotateAccessKey, handleUpdateSettings } from './apiSettings.js';\nimport { handleAuthStatus, handleLogin, handleLogout } from './apiAuth.js';\nimport { accessKeysMatch, allowedHosts, authReason, bearerToken, DEFAULT_SETTINGS } from './config.js';\nimport { hasValidSession } from './auth.js';\n\nconst ROUTES: Route[] = [\n { method: 'POST', path: '/api/review', body: true, run: ({ res, body }) => handleReview(res, body) },\n {\n method: 'GET', path: '/api/diff/refs', sameOrigin: true,\n run: ({ res, url }) => handleDiffRefs(res, url.searchParams.get('scan')),\n },\n {\n method: 'GET', path: '/api/diff', sameOrigin: true,\n run: ({ res, url }) => handleDiff(res, url.searchParams.get('scan'), url.searchParams),\n },\n {\n method: 'POST', path: '/api/search', body: true,\n run: ({ res, body }) => handleSearch(res, body),\n },\n {\n method: 'GET', path: '/api/blame', sameOrigin: true,\n run: ({ res, url }) => handleBlame(res, url.searchParams.get('scan'), url.searchParams.get('path')),\n },\n {\n method: 'POST', path: '/api/scan', body: true,\n run: ({ res, body, config }) => handleScan(res, body, config),\n },\n {\n method: 'DELETE', prefix: '/api/scan/',\n run: ({ res, rest }) => handleCleanup(res, decodeURIComponent(rest)),\n },\n {\n method: 'GET', path: '/api/file', sameOrigin: true,\n run: ({ res, url }) => handleFile(res, url.searchParams.get('scan'), url.searchParams.get('path')),\n },\n {\n // Hermes owns its server-side login. API mode forwards the browser's key\n // to its chosen endpoint. Both share the same streaming response contract.\n method: 'POST', path: '/api/explain', body: true,\n run: ({ res, body, config }) => body?.connection === 'hermes'\n ? (config.hermes || hermesWeb).chat(res, body) : proxyChat(res, body),\n },\n { method: 'GET', path: '/api/hermes', sameOrigin: true,\n run: ({ res, config }) => (config.hermes || hermesWeb).status(res) },\n {\n method: 'POST', path: '/api/doc', body: true,\n run: ({ res, body }) => handleDocs(res, body),\n },\n {\n // Reports which analyzers are installed — environment information a foreign\n // page has no business reading, so it is guarded like /api/file.\n method: 'GET', path: '/api/tools', sameOrigin: true,\n run: ({ res }) => handleToolsStatus(res),\n },\n {\n // Runs real analyzers over a scanned root. `body: true` applies the size\n // limit; the session check in the handler is the capability gate.\n method: 'POST', path: '/api/tools/run', body: true,\n run: ({ res, body }) => handleToolsRun(res, body),\n },\n {\n // Installs a missing analyzer from the GUI. Same-origin like every POST;\n // the tool name is validated against the registry and the install plans\n // are fixed data, so the request body never reaches a command line.\n method: 'POST', path: '/api/tools/install', body: true,\n run: ({ res, body }) => handleToolsInstall(res, body),\n },\n {\n // The MCP button's state, and the command an agent harness is configured with.\n // The config is not secret, but it is a path into this machine and a foreign\n // page has no business reading either one.\n method: 'GET', path: '/api/mcp', sameOrigin: true,\n run: ({ req, res, config }) => handleMcpStatus(req, res, config),\n },\n {\n method: 'GET', path: '/api/mcp/command', sameOrigin: true,\n run: ({ req, res, config }) => handleMcpCommand(req, res, config),\n },\n {\n // Starting and stopping a process is a side effect on the person's machine, so\n // these take a body like every other POST and are checked like every other POST.\n method: 'POST', path: '/api/mcp/start', body: true,\n run: ({ req, res, config }) => handleMcpStart(req, res, config),\n },\n {\n method: 'POST', path: '/api/mcp/stop', body: true,\n run: ({ req, res, config }) => handleMcpStop(req, res, config),\n },\n {\n method: 'GET', path: '/api/health',\n run: ({ res }) => sendJSON(res, 200, { ok: true }),\n },\n {\n method: 'GET', path: '/api/auth/status', sameOrigin: true,\n run: ({ req, res, settings }) => handleAuthStatus(req, res, settings),\n },\n {\n method: 'POST', path: '/api/auth/login', body: true, sameOrigin: true,\n run: ({ req, res, body, settings }) => handleLogin(req, res, body, settings),\n },\n {\n method: 'POST', path: '/api/auth/logout', body: true, sameOrigin: true,\n run: ({ req, res }) => handleLogout(req, res),\n },\n {\n // The settings drawer and the CLI read the same public shape: everything\n // about the configuration except the access key itself.\n method: 'GET', path: '/api/settings', sameOrigin: true,\n run: ({ req, res, config }) => handleGetSettings(req, res, config),\n },\n {\n // PATCH semantics over a small allow-listed key set; the validation that\n // rejects a bad port or a lawless mode lives in `server/config.js` and is\n // shared with the CLI wizard, so both surfaces enforce one schema.\n method: 'PUT', path: '/api/settings', body: true,\n run: ({ res, body, config }) => handleUpdateSettings(res, body, config),\n },\n {\n // The only way the key changes: generated on the server, shown once in\n // this response, never readable again. In self-hosted mode this endpoint\n // is itself behind the current key, so rotation requires possession.\n method: 'POST', path: '/api/settings/access-key', body: true,\n run: ({ req, res, config }) => handleRotateAccessKey(req, res, config),\n },\n];\n\n// The table itself, for the test that walks it. Exported read-only: the routes\n// are decided here, not assembled by whoever imports this.\nexport const routes = Object.freeze(ROUTES.map((r) => Object.freeze({ ...r })));\n\nexport function matchRoute(method, pathname) {\n for (const route of ROUTES) {\n if (route.method !== method) continue;\n if (route.path === pathname) return { route, rest: '' };\n if (route.prefix && pathname.startsWith(route.prefix)) {\n return { route, rest: pathname.slice(route.prefix.length) };\n }\n }\n return null;\n}\n\n// `config` carries the directories the handlers need — the project root to scan\n// for the demo, and the two roots static serving maps into. Passed in rather\n// than resolved here so a test can point the server somewhere else, and so this\n// module has nothing to say about where it was installed.\n//\n// Settings arrive the same way: `config.getSettings` is read on every request,\n// so a key rotated or a domain changed through the API takes effect on the next\n// request without a restart. A bare `createServer()` (the tests) has no getter\n// and sees the local-mode defaults — never somebody's home directory.\nasync function liveSettings(config) {\n if (typeof config?.getSettings !== 'function') return DEFAULT_SETTINGS;\n try {\n return await config.getSettings();\n } catch {\n return null; // unreadable config: fail closed, every /api call gets a 500\n }\n}\n\nexport function createRouter(config) {\n return async function handleRequest(req, res) {\n try {\n const url = new URL(req.url, 'http://127.0.0.1');\n\n const settings = await liveSettings(config);\n if (!settings) {\n return sendError(res, 500, 'The settings file could not be read — run `onboarder doctor` to find out why.');\n }\n\n const wrongHost = rebindingReason(req, allowedHosts(settings));\n if (wrongHost) {\n const scope = settings.mode === 'self-hosted'\n ? 'Onboarder only answers to its configured host and domain. '\n : 'Onboarder only answers to localhost. ';\n return sendError(res, 403, scope + wrongHost);\n }\n\n const found = matchRoute(req.method, url.pathname);\n const publicAuthRoute = ['/api/health', '/api/auth/status', '/api/auth/login', '/api/auth/logout'].includes(url.pathname);\n if (req.method !== 'GET' || found?.route.sameOrigin) {\n const foreign = crossOriginReason(req);\n if (foreign) {\n return sendError(res, 403, 'That request did not come from Onboarder’s own page. ' + foreign);\n }\n }\n\n // Bearer clients keep their existing API contract. A browser gets a signed,\n // HttpOnly session from the login form instead of storing the raw key.\n const bearerClient = accessKeysMatch(settings.accessKey, bearerToken(req));\n const browserAuthenticated = hasValidSession(req, settings);\n const authDenied = authReason(req, settings);\n const locallyExempt = !authDenied;\n const authenticated = bearerClient || browserAuthenticated || locallyExempt;\n const remoteSelfHosted = settings.mode === 'self-hosted' && Boolean(authDenied);\n\n if (remoteSelfHosted && !authenticated && !publicAuthRoute) {\n // API callers keep a machine-readable 401. A browser navigation gets the\n // themed sign-in document so the user never has to paste JSON into a tab.\n const accepts = String(req.headers?.accept || '');\n if (req.method === 'GET' && (url.pathname === '/' || accepts.includes('text/html'))) {\n res.statusCode = 200;\n return await serveStatic(res, '/login.html', config);\n }\n return sendError(res, 401, authDenied || 'Sign in with the Onboarder access key first.');\n }\n\n if (url.pathname === '/api/auth/logout') {\n // Always clear the browser cookie, even if it had already expired.\n return handleLogout(req, res);\n }\n\n if (found) {\n const body = found.route.body ? await readBody(req) : null;\n return await found.route.run({ req, res, url, body, rest: found.rest, config, settings });\n }\n\n if (req.method === 'GET') return await serveStatic(res, url.pathname, config);\n\n sendError(res, 404, 'Nothing lives at ' + url.pathname + '.');\n } catch (err) {\n // The last resort. Handlers turn their own expected failures into a status\n // that says something useful; anything reaching here is a bug or a broken\n // request body, and the message is more use to the person than \"500\".\n sendError(res, 500, err.message || 'Something went sideways.');\n }\n };\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { ScanRequest } from '../shared/contracts.js';
2
+ /** Validate untrusted JSON before touching the filesystem or cloning anything. */
3
+ export declare function parseScanRequest(value: unknown): ScanRequest;
@@ -0,0 +1,36 @@
1
+ import { normalizeScanOptions } from '../shared/analyzer/scanControl.js';
2
+ /** Validate untrusted JSON before touching the filesystem or cloning anything. */
3
+ export function parseScanRequest(value) {
4
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
5
+ throw new TypeError('Send a path, a gitUrl, or { demo: true }.');
6
+ }
7
+ const body = value;
8
+ const sources = [body.path !== undefined, body.gitUrl !== undefined, body.demo === true].filter(Boolean).length;
9
+ if (sources === 0)
10
+ throw new TypeError('Send a path, a gitUrl, or { demo: true }.');
11
+ if (sources !== 1)
12
+ throw new TypeError('Send exactly one path, gitUrl, or { demo: true }.');
13
+ const options = {};
14
+ if (body.options !== undefined) {
15
+ if (!body.options || typeof body.options !== 'object' || Array.isArray(body.options)) {
16
+ throw new TypeError('Scan options must be an object.');
17
+ }
18
+ const input = body.options;
19
+ for (const key of ['maxFiles', 'maxFileSize', 'readConcurrency']) {
20
+ if (input[key] === undefined)
21
+ continue;
22
+ if (typeof input[key] !== 'number')
23
+ throw new TypeError(`${key} must be a number.`);
24
+ options[key] = input[key];
25
+ }
26
+ normalizeScanOptions(options);
27
+ }
28
+ if (body.demo === true)
29
+ return { demo: true, options };
30
+ if (typeof body.path === 'string' && body.path.trim())
31
+ return { path: body.path.trim(), options };
32
+ if (typeof body.gitUrl === 'string' && body.gitUrl.trim())
33
+ return { gitUrl: body.gitUrl.trim(), options };
34
+ throw new TypeError('The path or gitUrl must be a non-empty string.');
35
+ }
36
+ //# sourceMappingURL=scanRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanRequest.js","sourceRoot":"","sources":["../src/server/scanRequest.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAEzE,kFAAkF;AAClF,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,SAAS,CAAC,2CAA2C,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,IAAI,GAAG,KAAgC,CAAC;IAC9C,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IAChH,IAAI,OAAO,KAAK,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,2CAA2C,CAAC,CAAC;IACpF,IAAI,OAAO,KAAK,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,mDAAmD,CAAC,CAAC;IAC5F,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACrF,MAAM,IAAI,SAAS,CAAC,iCAAiC,CAAC,CAAC;QACzD,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAkC,CAAC;QACtD,KAAK,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,EAAE,iBAAiB,CAAU,EAAE,CAAC;YAC1E,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS;gBAAE,SAAS;YACvC,IAAI,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,QAAQ;gBAAE,MAAM,IAAI,SAAS,CAAC,GAAG,GAAG,oBAAoB,CAAC,CAAC;YACpF,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;QACD,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACvD,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC;IAClG,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC;IAC1G,MAAM,IAAI,SAAS,CAAC,gDAAgD,CAAC,CAAC;AACxE,CAAC","sourcesContent":["import type { ScanRequest, ScanRequestOptions } from '../shared/contracts.js';\nimport { normalizeScanOptions } from '../shared/analyzer/scanControl.js';\n\n/** Validate untrusted JSON before touching the filesystem or cloning anything. */\nexport function parseScanRequest(value: unknown): ScanRequest {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new TypeError('Send a path, a gitUrl, or { demo: true }.');\n }\n const body = value as Record<string, unknown>;\n const sources = [body.path !== undefined, body.gitUrl !== undefined, body.demo === true].filter(Boolean).length;\n if (sources === 0) throw new TypeError('Send a path, a gitUrl, or { demo: true }.');\n if (sources !== 1) throw new TypeError('Send exactly one path, gitUrl, or { demo: true }.');\n const options: ScanRequestOptions = {};\n if (body.options !== undefined) {\n if (!body.options || typeof body.options !== 'object' || Array.isArray(body.options)) {\n throw new TypeError('Scan options must be an object.');\n }\n const input = body.options as Record<string, unknown>;\n for (const key of ['maxFiles', 'maxFileSize', 'readConcurrency'] as const) {\n if (input[key] === undefined) continue;\n if (typeof input[key] !== 'number') throw new TypeError(`${key} must be a number.`);\n options[key] = input[key];\n }\n normalizeScanOptions(options);\n }\n if (body.demo === true) return { demo: true, options };\n if (typeof body.path === 'string' && body.path.trim()) return { path: body.path.trim(), options };\n if (typeof body.gitUrl === 'string' && body.gitUrl.trim()) return { gitUrl: body.gitUrl.trim(), options };\n throw new TypeError('The path or gitUrl must be a non-empty string.');\n}\n"]}
@@ -0,0 +1,17 @@
1
+ export declare function buildSearchIndex(source: any, codeFiles: any, options?: Record<string, any>): Promise<{
2
+ index: Map<any, any>;
3
+ docCounts: Map<any, any>;
4
+ totalDocs: number;
5
+ totalBytes: number;
6
+ skipped: {
7
+ tooLarge: number;
8
+ overCap: number;
9
+ readFailed: number;
10
+ binary: number;
11
+ noTokens: number;
12
+ };
13
+ cap: {
14
+ maxFileBytes: number;
15
+ maxTotalBytes: number;
16
+ };
17
+ }>;