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/config.js CHANGED
@@ -1,161 +1,151 @@
1
1
  // Durable, user-scoped settings for the CLI/server. This file deliberately does
2
2
  // not know about HTTP: the CLI and the settings API use the same validation and
3
3
  // write path so a browser can change a setting without inventing a second schema.
4
-
5
4
  import { promises as fs } from 'node:fs';
6
5
  import { randomBytes, timingSafeEqual } from 'node:crypto';
7
6
  import os from 'node:os';
8
7
  import path from 'node:path';
9
-
10
8
  export const CONFIG_VERSION = 2;
11
9
  export const LOOPBACK_HOSTS = new Set(['127.0.0.1', 'localhost', '::1', '[::1]']);
12
10
  export const DEFAULT_SETTINGS = Object.freeze({
13
- version: CONFIG_VERSION,
14
- mode: 'local',
15
- host: '127.0.0.1',
16
- port: 4310,
17
- domain: '',
18
- // When a domain is configured, ask Caddy to obtain and renew a trusted TLS
19
- // certificate and reverse-proxy this app. The certificate itself belongs to
20
- // Caddy; the server still speaks plain HTTP to its local upstream.
21
- https: false,
22
- accessKey: '',
23
- // Whether `onboarder start` opens the app in a browser once it is listening.
24
- // Off in the schema so `npm start` from a checkout stays quiet; the setup
25
- // wizard offers to turn it on, which is where the people who want it are.
26
- autoOpen: false,
27
- account: Object.freeze({ name: '', email: '', provider: 'openai-compatible', baseUrl: '', model: '' }),
28
- tunnel: Object.freeze({ cloudflare: false, tailscale: false }),
11
+ version: CONFIG_VERSION,
12
+ mode: 'local',
13
+ host: '127.0.0.1',
14
+ port: 4310,
15
+ domain: '',
16
+ // When a domain is configured, ask Caddy to obtain and renew a trusted TLS
17
+ // certificate and reverse-proxy this app. The certificate itself belongs to
18
+ // Caddy; the server still speaks plain HTTP to its local upstream.
19
+ https: false,
20
+ accessKey: '',
21
+ // Whether `onboarder start` opens the app in a browser once it is listening.
22
+ // Off in the schema so `npm start` from a checkout stays quiet; the setup
23
+ // wizard offers to turn it on, which is where the people who want it are.
24
+ autoOpen: false,
25
+ account: Object.freeze({ name: '', email: '', provider: 'openai-compatible', baseUrl: '', model: '' }),
26
+ tunnel: Object.freeze({ cloudflare: false, tailscale: false }),
29
27
  });
30
-
31
28
  export function configHome(env = process.env) {
32
- if (env.XDG_CONFIG_HOME) return path.resolve(env.XDG_CONFIG_HOME, 'onboarder');
33
- return path.join(os.homedir(), '.config', 'onboarder');
29
+ if (env.XDG_CONFIG_HOME)
30
+ return path.resolve(env.XDG_CONFIG_HOME, 'onboarder');
31
+ return path.join(os.homedir(), '.config', 'onboarder');
34
32
  }
35
-
36
33
  export function configPath(env = process.env) {
37
- // An explicit override first: the CLI's --config flag and the test suite both
38
- // need a config file that is not the one in the person's home directory.
39
- if (env.ONBOARDER_CONFIG) return path.resolve(env.ONBOARDER_CONFIG);
40
- return path.join(configHome(env), 'config.json');
34
+ // An explicit override first: the CLI's --config flag and the test suite both
35
+ // need a config file that is not the one in the person's home directory.
36
+ if (env.ONBOARDER_CONFIG)
37
+ return path.resolve(env.ONBOARDER_CONFIG);
38
+ return path.join(configHome(env), 'config.json');
41
39
  }
42
-
43
40
  export function isLoopbackHost(host) {
44
- return LOOPBACK_HOSTS.has(String(host || '').trim().toLowerCase());
41
+ return LOOPBACK_HOSTS.has(String(host || '').trim().toLowerCase());
45
42
  }
46
-
47
43
  function cleanString(value, max = 240) {
48
- return String(value ?? '').trim().slice(0, max);
44
+ return String(value ?? '').trim().slice(0, max);
49
45
  }
50
-
51
46
  function normalizePort(value) {
52
- const port = Number(value);
53
- if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error('Port must be a whole number from 1 to 65535.');
54
- return port;
47
+ const port = Number(value);
48
+ if (!Number.isInteger(port) || port < 1 || port > 65535)
49
+ throw new Error('Port must be a whole number from 1 to 65535.');
50
+ return port;
55
51
  }
56
-
57
52
  function normalizeDomain(value) {
58
- const domain = cleanString(value).toLowerCase();
59
- if (!domain) return '';
60
- if (domain.length > 253 || domain.includes('/') || domain.includes('\\') || domain.includes(' ') || domain.includes('@') || domain.startsWith('.')) {
61
- throw new Error('Domain must be a hostname such as map.example.com.');
62
- }
63
- return domain;
53
+ const domain = cleanString(value).toLowerCase();
54
+ if (!domain)
55
+ return '';
56
+ if (domain.length > 253 || domain.includes('/') || domain.includes('\\') || domain.includes(' ') || domain.includes('@') || domain.startsWith('.')) {
57
+ throw new Error('Domain must be a hostname such as map.example.com.');
58
+ }
59
+ return domain;
64
60
  }
65
-
66
61
  function normalizeAccount(value = {}) {
67
- return {
68
- name: cleanString(value.name, 80),
69
- email: cleanString(value.email, 160),
70
- provider: cleanString(value.provider || 'openai-compatible', 80),
71
- baseUrl: cleanString(value.baseUrl, 500),
72
- model: cleanString(value.model, 160),
73
- };
62
+ return {
63
+ name: cleanString(value.name, 80),
64
+ email: cleanString(value.email, 160),
65
+ provider: cleanString(value.provider || 'openai-compatible', 80),
66
+ baseUrl: cleanString(value.baseUrl, 500),
67
+ model: cleanString(value.model, 160),
68
+ };
74
69
  }
75
-
76
70
  function normalizeTunnel(value = {}) {
77
- return { cloudflare: Boolean(value.cloudflare), tailscale: Boolean(value.tailscale) };
71
+ return { cloudflare: Boolean(value.cloudflare), tailscale: Boolean(value.tailscale) };
78
72
  }
79
-
80
73
  export function normalizeSettings(value = {}) {
81
- const mode = value.mode === 'self-hosted' ? 'self-hosted' : 'local';
82
- const host = cleanString(value.host || DEFAULT_SETTINGS.host, 120);
83
- const settings = {
84
- version: CONFIG_VERSION,
85
- mode,
86
- host,
87
- port: normalizePort(value.port ?? DEFAULT_SETTINGS.port),
88
- domain: normalizeDomain(value.domain),
89
- https: Boolean(value.https),
90
- accessKey: cleanString(value.accessKey, 256),
91
- autoOpen: value.autoOpen === undefined ? DEFAULT_SETTINGS.autoOpen : Boolean(value.autoOpen),
92
- account: normalizeAccount(value.account),
93
- tunnel: normalizeTunnel(value.tunnel),
94
- };
95
- if (!host) throw new Error('Host cannot be empty.');
96
- if (settings.mode === 'local' && !isLoopbackHost(settings.host)) {
97
- throw new Error('Local mode only binds to 127.0.0.1, localhost, or ::1. Choose self-hosted mode for a network bind.');
98
- }
99
- if (settings.https && !settings.domain) {
100
- throw new Error('HTTPS needs a domain such as map.example.com. A public IP alone cannot be used for a normal trusted certificate.');
101
- }
102
- // Self-hosted needs no domain: a bare-IP bind (a VPS with no DNS name) is a
103
- // legitimate layout. Every API call needs the access key either way.
104
- return settings;
74
+ const mode = value.mode === 'self-hosted' ? 'self-hosted' : 'local';
75
+ const host = cleanString(value.host || DEFAULT_SETTINGS.host, 120);
76
+ const settings = {
77
+ version: CONFIG_VERSION,
78
+ mode,
79
+ host,
80
+ port: normalizePort(value.port ?? DEFAULT_SETTINGS.port),
81
+ domain: normalizeDomain(value.domain),
82
+ https: Boolean(value.https),
83
+ accessKey: cleanString(value.accessKey, 256),
84
+ autoOpen: value.autoOpen === undefined ? DEFAULT_SETTINGS.autoOpen : Boolean(value.autoOpen),
85
+ account: normalizeAccount(value.account),
86
+ tunnel: normalizeTunnel(value.tunnel),
87
+ };
88
+ if (!host)
89
+ throw new Error('Host cannot be empty.');
90
+ if (settings.mode === 'local' && !isLoopbackHost(settings.host)) {
91
+ throw new Error('Local mode only binds to 127.0.0.1, localhost, or ::1. Choose self-hosted mode for a network bind.');
92
+ }
93
+ if (settings.https && !settings.domain) {
94
+ throw new Error('HTTPS needs a domain such as map.example.com. A public IP alone cannot be used for a normal trusted certificate.');
95
+ }
96
+ // Self-hosted needs no domain: a bare-IP bind (a VPS with no DNS name) is a
97
+ // legitimate layout. Every API call needs the access key either way.
98
+ return settings;
105
99
  }
106
-
107
100
  export function generateAccessKey() {
108
- return `ob_${randomBytes(32).toString('base64url')}`;
101
+ return `ob_${randomBytes(32).toString('base64url')}`;
109
102
  }
110
-
111
103
  // Every URL a person might reach this server through, derived from the settings
112
104
  // so the CLI banner, the settings drawer, and `onboarder config` never disagree
113
105
  // about what to print.
114
106
  export function serverUrls(value = DEFAULT_SETTINGS) {
115
- const settings = normalizeSettings(value);
116
- const urls = { local: `http://localhost:${settings.port}` };
117
- if (!isLoopbackHost(settings.host)) {
118
- urls.network = settings.host === '0.0.0.0' || settings.host === '::'
119
- ? `http://<this-machine>:${settings.port} (every interface)`
120
- : `http://${settings.host}:${settings.port}`;
121
- }
122
- if (settings.domain) urls.domain = settings.https ? `https://${settings.domain}` : `http://${settings.domain}:${settings.port}`;
123
- return urls;
107
+ const settings = normalizeSettings(value);
108
+ const urls = { local: `http://localhost:${settings.port}` };
109
+ if (!isLoopbackHost(settings.host)) {
110
+ urls.network = settings.host === '0.0.0.0' || settings.host === '::'
111
+ ? `http://<this-machine>:${settings.port} (every interface)`
112
+ : `http://${settings.host}:${settings.port}`;
113
+ }
114
+ if (settings.domain)
115
+ urls.domain = settings.https ? `https://${settings.domain}` : `http://${settings.domain}:${settings.port}`;
116
+ return urls;
124
117
  }
125
-
126
118
  // The key, safe to print in a list: enough to recognize it, not enough to use it.
127
119
  export function maskAccessKey(key) {
128
- const value = String(key || '');
129
- if (value.length <= 8) return value ? '…' : '';
130
- return `${value.slice(0, 6)}…${value.slice(-4)}`;
120
+ const value = String(key || '');
121
+ if (value.length <= 8)
122
+ return value ? '…' : '';
123
+ return `${value.slice(0, 6)}…${value.slice(-4)}`;
131
124
  }
132
-
133
125
  export function browserUrl(settings) {
134
- return new URL(serverUrls(settings).local).toString();
126
+ return new URL(serverUrls(settings).local).toString();
135
127
  }
136
-
137
128
  export function publicSettings(value = DEFAULT_SETTINGS) {
138
- const settings = normalizeSettings(value);
139
- return {
140
- version: settings.version,
141
- mode: settings.mode,
142
- host: settings.host,
143
- port: settings.port,
144
- domain: settings.domain,
145
- https: settings.https,
146
- autoOpen: settings.autoOpen,
147
- hasAccessKey: Boolean(settings.accessKey),
148
- accessKeyMasked: maskAccessKey(settings.accessKey),
149
- account: settings.account,
150
- tunnel: settings.tunnel,
151
- urls: serverUrls(settings),
152
- security: {
153
- remoteAuth: settings.mode === 'self-hosted',
154
- loopback: isLoopbackHost(settings.host),
155
- },
156
- };
129
+ const settings = normalizeSettings(value);
130
+ return {
131
+ version: settings.version,
132
+ mode: settings.mode,
133
+ host: settings.host,
134
+ port: settings.port,
135
+ domain: settings.domain,
136
+ https: settings.https,
137
+ autoOpen: settings.autoOpen,
138
+ hasAccessKey: Boolean(settings.accessKey),
139
+ accessKeyMasked: maskAccessKey(settings.accessKey),
140
+ account: settings.account,
141
+ tunnel: settings.tunnel,
142
+ urls: serverUrls(settings),
143
+ security: {
144
+ remoteAuth: settings.mode === 'self-hosted',
145
+ loopback: isLoopbackHost(settings.host),
146
+ },
147
+ };
157
148
  }
158
-
159
149
  // Hostnames the rebinding guard should accept beyond loopback: the configured
160
150
  // domain, and a non-loopback bind address itself. A loopback-only local server
161
151
  // gets an empty list, which is exactly the old behavior.
@@ -172,104 +162,109 @@ export function publicSettings(value = DEFAULT_SETTINGS) {
172
162
  // call time (the router asks per request), so a DHCP lease change does not
173
163
  // strand the guard on a stale address.
174
164
  function ownInterfaceHosts() {
175
- const hosts = [];
176
- for (const list of Object.values(os.networkInterfaces())) {
177
- for (const addr of list || []) {
178
- if (addr.internal) continue; // loopback is always allowed anyway
179
- hosts.push(addr.address);
165
+ const hosts = [];
166
+ for (const list of Object.values(os.networkInterfaces())) {
167
+ for (const addr of list || []) {
168
+ if (addr.internal)
169
+ continue; // loopback is always allowed anyway
170
+ hosts.push(addr.address);
171
+ }
180
172
  }
181
- }
182
- return hosts;
173
+ return hosts;
183
174
  }
184
-
185
175
  export function allowedHosts(value = DEFAULT_SETTINGS) {
186
- const settings = normalizeSettings(value);
187
- const hosts = new Set();
188
- if (settings.domain) hosts.add(settings.domain);
189
- if (!isLoopbackHost(settings.host)) {
190
- // A wildcard bind is useful as a literal Host value to diagnostics, even
191
- // though browsers normally address the machine by one of its real IPs.
192
- hosts.add(settings.host.toLowerCase());
193
- // Any network bind can sit behind NAT: a VPS may be configured as a private
194
- // interface address while browsers address its public/NAT IP. Accept every IP
195
- // literal, never arbitrary DNS names; the access key protects remote data.
196
- hosts.add('ip:*');
197
- for (const ip of ownInterfaceHosts()) if (!isLoopbackHost(ip)) hosts.add(ip);
198
- }
199
- if (settings.tunnel.cloudflare) hosts.add('*.trycloudflare.com');
200
- if (settings.tunnel.tailscale) hosts.add('*.ts.net');
201
- return [...hosts];
176
+ const settings = normalizeSettings(value);
177
+ const hosts = new Set();
178
+ if (settings.domain)
179
+ hosts.add(settings.domain);
180
+ if (!isLoopbackHost(settings.host)) {
181
+ // A wildcard bind is useful as a literal Host value to diagnostics, even
182
+ // though browsers normally address the machine by one of its real IPs.
183
+ hosts.add(settings.host.toLowerCase());
184
+ // Any network bind can sit behind NAT: a VPS may be configured as a private
185
+ // interface address while browsers address its public/NAT IP. Accept every IP
186
+ // literal, never arbitrary DNS names; the access key protects remote data.
187
+ hosts.add('ip:*');
188
+ for (const ip of ownInterfaceHosts())
189
+ if (!isLoopbackHost(ip))
190
+ hosts.add(ip);
191
+ }
192
+ if (settings.tunnel.cloudflare)
193
+ hosts.add('*.trycloudflare.com');
194
+ if (settings.tunnel.tailscale)
195
+ hosts.add('*.ts.net');
196
+ return [...hosts];
202
197
  }
203
-
204
198
  export function accessKeysMatch(expected, actual) {
205
- const a = Buffer.from(String(expected || ''));
206
- const b = Buffer.from(String(actual || ''));
207
- return a.length > 0 && a.length === b.length && timingSafeEqual(a, b);
199
+ const a = Buffer.from(String(expected || ''));
200
+ const b = Buffer.from(String(actual || ''));
201
+ return a.length > 0 && a.length === b.length && timingSafeEqual(a, b);
208
202
  }
209
-
210
203
  export function bearerToken(req) {
211
- const value = String(req.headers?.authorization || '');
212
- const match = value.match(/^Bearer\s+(.+)$/i);
213
- return match ? match[1].trim() : '';
204
+ const value = String(req.headers?.authorization || '');
205
+ const match = value.match(/^Bearer\s+(.+)$/i);
206
+ return match ? match[1].trim() : '';
214
207
  }
215
-
216
208
  export function requestIsLoopback(req) {
217
- const remote = String(req.socket?.remoteAddress || '').replace(/^::ffff:/, '');
218
- return remote === '127.0.0.1' || remote === '::1';
209
+ const remote = String(req.socket?.remoteAddress || '').replace(/^::ffff:/, '');
210
+ return remote === '127.0.0.1' || remote === '::1';
219
211
  }
220
-
221
212
  export function authReason(req, settings = DEFAULT_SETTINGS) {
222
- const normalized = normalizeSettings(settings);
223
- if (normalized.mode !== 'self-hosted') return null;
224
- // A self-hosted server can still be opened on the same machine. Caddy and
225
- // tunnels arrive from loopback but keep the public Host, so both signals must
226
- // agree before a login page is skipped.
227
- const host = String(req.headers?.host || '').toLowerCase();
228
- const hostIsLoopback = isLoopbackHost(host.replace(/:\d+$/, '')) || /^localhost:\d+$/.test(host);
229
- if (requestIsLoopback(req) && hostIsLoopback) return null;
230
- if (!normalized.accessKey) return 'Self-hosted mode has no access key configured.';
231
- const token = bearerToken(req);
232
- if (!accessKeysMatch(normalized.accessKey, token)) return 'A valid access key is required.';
233
- return null;
213
+ const normalized = normalizeSettings(settings);
214
+ if (normalized.mode !== 'self-hosted')
215
+ return null;
216
+ // A self-hosted server can still be opened on the same machine. Caddy and
217
+ // tunnels arrive from loopback but keep the public Host, so both signals must
218
+ // agree before a login page is skipped.
219
+ const host = String(req.headers?.host || '').toLowerCase();
220
+ const hostIsLoopback = isLoopbackHost(host.replace(/:\d+$/, '')) || /^localhost:\d+$/.test(host);
221
+ if (requestIsLoopback(req) && hostIsLoopback)
222
+ return null;
223
+ if (!normalized.accessKey)
224
+ return 'Self-hosted mode has no access key configured.';
225
+ const token = bearerToken(req);
226
+ if (!accessKeysMatch(normalized.accessKey, token))
227
+ return 'A valid access key is required.';
228
+ return null;
234
229
  }
235
-
236
230
  // Has a config ever been written? The wizard asks this to decide between
237
231
  // "start from the defaults" and "start from what you already have".
238
232
  export async function configExists(file = configPath()) {
239
- try {
240
- await fs.access(file);
241
- return true;
242
- } catch {
243
- return false;
244
- }
233
+ try {
234
+ await fs.access(file);
235
+ return true;
236
+ }
237
+ catch {
238
+ return false;
239
+ }
245
240
  }
246
-
247
-
248
241
  export async function readSettings(file = configPath()) {
249
- try {
250
- const raw = await fs.readFile(file, 'utf8');
251
- return normalizeSettings(JSON.parse(raw));
252
- } catch (err) {
253
- if (err.code === 'ENOENT') return { ...DEFAULT_SETTINGS, account: { ...DEFAULT_SETTINGS.account }, tunnel: { ...DEFAULT_SETTINGS.tunnel } };
254
- if (err instanceof SyntaxError) throw new Error(`Config is not valid JSON: ${file}`);
255
- throw err;
256
- }
242
+ try {
243
+ const raw = await fs.readFile(file, 'utf8');
244
+ return normalizeSettings(JSON.parse(raw));
245
+ }
246
+ catch (err) {
247
+ if (err.code === 'ENOENT')
248
+ return { ...DEFAULT_SETTINGS, account: { ...DEFAULT_SETTINGS.account }, tunnel: { ...DEFAULT_SETTINGS.tunnel } };
249
+ if (err instanceof SyntaxError)
250
+ throw new Error(`Config is not valid JSON: ${file}`);
251
+ throw err;
252
+ }
257
253
  }
258
-
259
254
  export async function writeSettings(value, file = configPath()) {
260
- const settings = normalizeSettings(value);
261
- const dir = path.dirname(file);
262
- await fs.mkdir(dir, { recursive: true, mode: 0o700 });
263
- const temp = `${file}.${process.pid}.${Date.now()}.tmp`;
264
- const body = JSON.stringify(settings, null, 2) + '\n';
265
- await fs.writeFile(temp, body, { encoding: 'utf8', mode: 0o600 });
266
- await fs.rename(temp, file);
267
- await fs.chmod(file, 0o600);
268
- return settings;
255
+ const settings = normalizeSettings(value);
256
+ const dir = path.dirname(file);
257
+ await fs.mkdir(dir, { recursive: true, mode: 0o700 });
258
+ const temp = `${file}.${process.pid}.${Date.now()}.tmp`;
259
+ const body = JSON.stringify(settings, null, 2) + '\n';
260
+ await fs.writeFile(temp, body, { encoding: 'utf8', mode: 0o600 });
261
+ await fs.rename(temp, file);
262
+ await fs.chmod(file, 0o600);
263
+ return settings;
269
264
  }
270
-
271
265
  export async function updateSettings(patch = {}, file = configPath()) {
272
- const current = await readSettings(file);
273
- const next = normalizeSettings({ ...current, ...patch, account: { ...current.account, ...(patch.account || {}) }, tunnel: { ...current.tunnel, ...(patch.tunnel || {}) } });
274
- return writeSettings(next, file);
266
+ const current = await readSettings(file);
267
+ const next = normalizeSettings({ ...current, ...patch, account: { ...current.account, ...(patch.account || {}) }, tunnel: { ...current.tunnel, ...(patch.tunnel || {}) } });
268
+ return writeSettings(next, file);
275
269
  }
270
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/server/config.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Settings, SettingsInput, ServerUrls } from '../shared/contracts.js';\n// Durable, user-scoped settings for the CLI/server. This file deliberately does\n// not know about HTTP: the CLI and the settings API use the same validation and\n// write path so a browser can change a setting without inventing a second schema.\n\nimport { promises as fs } from 'node:fs';\nimport { randomBytes, timingSafeEqual } from 'node:crypto';\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport const CONFIG_VERSION = 2;\nexport const LOOPBACK_HOSTS = new Set(['127.0.0.1', 'localhost', '::1', '[::1]']);\nexport const DEFAULT_SETTINGS: Readonly<Settings> = Object.freeze({\n version: CONFIG_VERSION,\n mode: 'local',\n host: '127.0.0.1',\n port: 4310,\n domain: '',\n // When a domain is configured, ask Caddy to obtain and renew a trusted TLS\n // certificate and reverse-proxy this app. The certificate itself belongs to\n // Caddy; the server still speaks plain HTTP to its local upstream.\n https: false,\n accessKey: '',\n // Whether `onboarder start` opens the app in a browser once it is listening.\n // Off in the schema so `npm start` from a checkout stays quiet; the setup\n // wizard offers to turn it on, which is where the people who want it are.\n autoOpen: false,\n account: Object.freeze({ name: '', email: '', provider: 'openai-compatible', baseUrl: '', model: '' }),\n tunnel: Object.freeze({ cloudflare: false, tailscale: false }),\n});\n\nexport function configHome(env = process.env) {\n if (env.XDG_CONFIG_HOME) return path.resolve(env.XDG_CONFIG_HOME, 'onboarder');\n return path.join(os.homedir(), '.config', 'onboarder');\n}\n\nexport function configPath(env = process.env) {\n // An explicit override first: the CLI's --config flag and the test suite both\n // need a config file that is not the one in the person's home directory.\n if (env.ONBOARDER_CONFIG) return path.resolve(env.ONBOARDER_CONFIG);\n return path.join(configHome(env), 'config.json');\n}\n\nexport function isLoopbackHost(host) {\n return LOOPBACK_HOSTS.has(String(host || '').trim().toLowerCase());\n}\n\nfunction cleanString(value, max = 240) {\n return String(value ?? '').trim().slice(0, max);\n}\n\nfunction normalizePort(value) {\n const port = Number(value);\n if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error('Port must be a whole number from 1 to 65535.');\n return port;\n}\n\nfunction normalizeDomain(value) {\n const domain = cleanString(value).toLowerCase();\n if (!domain) return '';\n if (domain.length > 253 || domain.includes('/') || domain.includes('\\\\') || domain.includes(' ') || domain.includes('@') || domain.startsWith('.')) {\n throw new Error('Domain must be a hostname such as map.example.com.');\n }\n return domain;\n}\n\nfunction normalizeAccount(value: SettingsInput['account'] = {}) {\n return {\n name: cleanString(value.name, 80),\n email: cleanString(value.email, 160),\n provider: cleanString(value.provider || 'openai-compatible', 80),\n baseUrl: cleanString(value.baseUrl, 500),\n model: cleanString(value.model, 160),\n };\n}\n\nfunction normalizeTunnel(value: SettingsInput['tunnel'] = {}) {\n return { cloudflare: Boolean(value.cloudflare), tailscale: Boolean(value.tailscale) };\n}\n\nexport function normalizeSettings(value: SettingsInput = {}): Settings {\n const mode = value.mode === 'self-hosted' ? 'self-hosted' : 'local';\n const host = cleanString(value.host || DEFAULT_SETTINGS.host, 120);\n const settings: Settings = {\n version: CONFIG_VERSION,\n mode,\n host,\n port: normalizePort(value.port ?? DEFAULT_SETTINGS.port),\n domain: normalizeDomain(value.domain),\n https: Boolean(value.https),\n accessKey: cleanString(value.accessKey, 256),\n autoOpen: value.autoOpen === undefined ? DEFAULT_SETTINGS.autoOpen : Boolean(value.autoOpen),\n account: normalizeAccount(value.account),\n tunnel: normalizeTunnel(value.tunnel),\n };\n if (!host) throw new Error('Host cannot be empty.');\n if (settings.mode === 'local' && !isLoopbackHost(settings.host)) {\n throw new Error('Local mode only binds to 127.0.0.1, localhost, or ::1. Choose self-hosted mode for a network bind.');\n }\n if (settings.https && !settings.domain) {\n throw new Error('HTTPS needs a domain such as map.example.com. A public IP alone cannot be used for a normal trusted certificate.');\n }\n // Self-hosted needs no domain: a bare-IP bind (a VPS with no DNS name) is a\n // legitimate layout. Every API call needs the access key either way.\n return settings;\n}\n\nexport function generateAccessKey() {\n return `ob_${randomBytes(32).toString('base64url')}`;\n}\n\n// Every URL a person might reach this server through, derived from the settings\n// so the CLI banner, the settings drawer, and `onboarder config` never disagree\n// about what to print.\nexport function serverUrls(value: SettingsInput = DEFAULT_SETTINGS) {\n const settings = normalizeSettings(value);\n const urls: ServerUrls = { local: `http://localhost:${settings.port}` };\n if (!isLoopbackHost(settings.host)) {\n urls.network = settings.host === '0.0.0.0' || settings.host === '::'\n ? `http://<this-machine>:${settings.port} (every interface)`\n : `http://${settings.host}:${settings.port}`;\n }\n if (settings.domain) urls.domain = settings.https ? `https://${settings.domain}` : `http://${settings.domain}:${settings.port}`;\n return urls;\n}\n\n// The key, safe to print in a list: enough to recognize it, not enough to use it.\nexport function maskAccessKey(key) {\n const value = String(key || '');\n if (value.length <= 8) return value ? '…' : '';\n return `${value.slice(0, 6)}…${value.slice(-4)}`;\n}\n\nexport function browserUrl(settings) {\n return new URL(serverUrls(settings).local).toString();\n}\n\nexport function publicSettings(value: SettingsInput = DEFAULT_SETTINGS) {\n const settings = normalizeSettings(value);\n return {\n version: settings.version,\n mode: settings.mode,\n host: settings.host,\n port: settings.port,\n domain: settings.domain,\n https: settings.https,\n autoOpen: settings.autoOpen,\n hasAccessKey: Boolean(settings.accessKey),\n accessKeyMasked: maskAccessKey(settings.accessKey),\n account: settings.account,\n tunnel: settings.tunnel,\n urls: serverUrls(settings),\n security: {\n remoteAuth: settings.mode === 'self-hosted',\n loopback: isLoopbackHost(settings.host),\n },\n };\n}\n\n// Hostnames the rebinding guard should accept beyond loopback: the configured\n// domain, and a non-loopback bind address itself. A loopback-only local server\n// gets an empty list, which is exactly the old behavior.\n//\n// Enabled tunnels add wildcard suffixes: a Cloudflare quick tunnel's name is\n// random (https://<something>.trycloudflare.com) and a Tailscale machine name\n// belongs to the tailnet, so neither can be configured ahead of time. This is\n// safe because it can only widen Host acceptance in self-hosted mode, where\n// every API call already needs the access key — the guard's job there is\n// keeping drive-by traffic off the static files, not authentication.\n// A wildcard bind (0.0.0.0 / ::) has no name of its own, so the names it\n// honestly answers to are this machine's own interface addresses — a request\n// addressed to 10.0.0.2 or a public VPS IP really did arrive here. Read at\n// call time (the router asks per request), so a DHCP lease change does not\n// strand the guard on a stale address.\nfunction ownInterfaceHosts() {\n const hosts = [];\n for (const list of Object.values(os.networkInterfaces())) {\n for (const addr of list || []) {\n if (addr.internal) continue; // loopback is always allowed anyway\n hosts.push(addr.address);\n }\n }\n return hosts;\n}\n\nexport function allowedHosts(value: SettingsInput = DEFAULT_SETTINGS) {\n const settings = normalizeSettings(value);\n const hosts = new Set();\n if (settings.domain) hosts.add(settings.domain);\n if (!isLoopbackHost(settings.host)) {\n // A wildcard bind is useful as a literal Host value to diagnostics, even\n // though browsers normally address the machine by one of its real IPs.\n hosts.add(settings.host.toLowerCase());\n // Any network bind can sit behind NAT: a VPS may be configured as a private\n // interface address while browsers address its public/NAT IP. Accept every IP\n // literal, never arbitrary DNS names; the access key protects remote data.\n hosts.add('ip:*');\n for (const ip of ownInterfaceHosts()) if (!isLoopbackHost(ip)) hosts.add(ip);\n }\n if (settings.tunnel.cloudflare) hosts.add('*.trycloudflare.com');\n if (settings.tunnel.tailscale) hosts.add('*.ts.net');\n return [...hosts];\n}\n\nexport function accessKeysMatch(expected, actual) {\n const a = Buffer.from(String(expected || ''));\n const b = Buffer.from(String(actual || ''));\n return a.length > 0 && a.length === b.length && timingSafeEqual(a, b);\n}\n\nexport function bearerToken(req) {\n const value = String(req.headers?.authorization || '');\n const match = value.match(/^Bearer\\s+(.+)$/i);\n return match ? match[1].trim() : '';\n}\n\nexport function requestIsLoopback(req) {\n const remote = String(req.socket?.remoteAddress || '').replace(/^::ffff:/, '');\n return remote === '127.0.0.1' || remote === '::1';\n}\n\nexport function authReason(req, settings: SettingsInput = DEFAULT_SETTINGS) {\n const normalized = normalizeSettings(settings);\n if (normalized.mode !== 'self-hosted') return null;\n // A self-hosted server can still be opened on the same machine. Caddy and\n // tunnels arrive from loopback but keep the public Host, so both signals must\n // agree before a login page is skipped.\n const host = String(req.headers?.host || '').toLowerCase();\n const hostIsLoopback = isLoopbackHost(host.replace(/:\\d+$/, '')) || /^localhost:\\d+$/.test(host);\n if (requestIsLoopback(req) && hostIsLoopback) return null;\n if (!normalized.accessKey) return 'Self-hosted mode has no access key configured.';\n const token = bearerToken(req);\n if (!accessKeysMatch(normalized.accessKey, token)) return 'A valid access key is required.';\n return null;\n}\n\n// Has a config ever been written? The wizard asks this to decide between\n// \"start from the defaults\" and \"start from what you already have\".\nexport async function configExists(file = configPath()) {\n try {\n await fs.access(file);\n return true;\n } catch {\n return false;\n }\n}\n\n\nexport async function readSettings(file = configPath()) {\n try {\n const raw = await fs.readFile(file, 'utf8');\n return normalizeSettings(JSON.parse(raw));\n } catch (err) {\n if (err.code === 'ENOENT') return { ...DEFAULT_SETTINGS, account: { ...DEFAULT_SETTINGS.account }, tunnel: { ...DEFAULT_SETTINGS.tunnel } };\n if (err instanceof SyntaxError) throw new Error(`Config is not valid JSON: ${file}`);\n throw err;\n }\n}\n\nexport async function writeSettings(value, file = configPath()) {\n const settings = normalizeSettings(value);\n const dir = path.dirname(file);\n await fs.mkdir(dir, { recursive: true, mode: 0o700 });\n const temp = `${file}.${process.pid}.${Date.now()}.tmp`;\n const body = JSON.stringify(settings, null, 2) + '\\n';\n await fs.writeFile(temp, body, { encoding: 'utf8', mode: 0o600 });\n await fs.rename(temp, file);\n await fs.chmod(file, 0o600);\n return settings;\n}\n\nexport async function updateSettings(patch: SettingsInput = {}, file = configPath()) {\n const current = await readSettings(file);\n const next = normalizeSettings({ ...current, ...patch, account: { ...current.account, ...(patch.account || {}) }, tunnel: { ...current.tunnel, ...(patch.tunnel || {}) } });\n return writeSettings(next, file);\n}\n"]}
@@ -0,0 +1,12 @@
1
+ export declare const CLI_ENTRY: string;
2
+ export declare function logPath(configFile?: string): string;
3
+ export declare const MAX_LOG_BYTES: number;
4
+ export declare function rotateLogIfNeeded(file?: string, maxBytes?: number): Promise<boolean>;
5
+ export declare function readLog(file?: string, bytes?: number): Promise<string>;
6
+ export declare function tailLog(file?: string, count?: number): Promise<string[]>;
7
+ export declare function logExists(file?: string): Promise<boolean>;
8
+ export declare function probe(url: any, timeoutMs?: number): Promise<unknown>;
9
+ export declare function waitForReady(url: any, { timeoutMs, intervalMs, check }?: Record<string, any>): Promise<boolean>;
10
+ export declare function spawnDetached({ configFile, entry, env, log }?: Record<string, any>): number;
11
+ export declare function waitForPidFile(configFile: any, { timeoutMs, intervalMs, readPid, isAlive }?: Record<string, any>): Promise<any>;
12
+ export declare function followLog(file: any, onLine: any, { intervalMs, from }?: Record<string, any>): () => void;