codebase-onboarder 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/README.md +196 -47
  2. package/bin/build-if-source.js +23 -0
  3. package/cli/commands.d.ts +26 -0
  4. package/cli/commands.js +836 -811
  5. package/cli/commands.js.map +1 -0
  6. package/cli/explorer/advanced.d.ts +14 -0
  7. package/cli/explorer/advanced.js +449 -0
  8. package/cli/explorer/advanced.js.map +1 -0
  9. package/cli/explorer/app.d.ts +1 -0
  10. package/cli/explorer/app.js +396 -229
  11. package/cli/explorer/app.js.map +1 -0
  12. package/cli/explorer/assistant.d.ts +9 -0
  13. package/cli/explorer/assistant.js +58 -0
  14. package/cli/explorer/assistant.js.map +1 -0
  15. package/cli/explorer/commands.d.ts +17 -0
  16. package/cli/explorer/commands.js +400 -162
  17. package/cli/explorer/commands.js.map +1 -0
  18. package/cli/explorer/featureViews.d.ts +124 -0
  19. package/cli/explorer/featureViews.js +179 -0
  20. package/cli/explorer/featureViews.js.map +1 -0
  21. package/cli/explorer/github.d.ts +21 -0
  22. package/cli/explorer/github.js +73 -0
  23. package/cli/explorer/github.js.map +1 -0
  24. package/cli/explorer/graphs.d.ts +7 -0
  25. package/cli/explorer/graphs.js +173 -0
  26. package/cli/explorer/graphs.js.map +1 -0
  27. package/cli/explorer/picker.d.ts +22 -0
  28. package/cli/explorer/picker.js +150 -0
  29. package/cli/explorer/picker.js.map +1 -0
  30. package/cli/explorer/report.d.ts +85 -0
  31. package/cli/explorer/report.js +60 -0
  32. package/cli/explorer/report.js.map +1 -0
  33. package/cli/explorer/session.d.ts +449 -0
  34. package/cli/explorer/session.js +184 -95
  35. package/cli/explorer/session.js.map +1 -0
  36. package/cli/explorer/views.d.ts +19 -0
  37. package/cli/explorer/views.js +496 -412
  38. package/cli/explorer/views.js.map +1 -0
  39. package/cli/explorer/wrap.d.ts +1 -0
  40. package/cli/explorer/wrap.js +33 -0
  41. package/cli/explorer/wrap.js.map +1 -0
  42. package/cli/main.d.ts +1 -0
  43. package/cli/main.js +235 -138
  44. package/cli/main.js.map +1 -0
  45. package/cli/prompt.d.ts +5 -0
  46. package/cli/prompt.js +84 -80
  47. package/cli/prompt.js.map +1 -0
  48. package/cli/scanOptions.d.ts +2 -0
  49. package/cli/scanOptions.js +11 -0
  50. package/cli/scanOptions.js.map +1 -0
  51. package/cli/ui.d.ts +33 -0
  52. package/cli/ui.js +55 -35
  53. package/cli/ui.js.map +1 -0
  54. package/cli/wizard.d.ts +187 -0
  55. package/cli/wizard.js +304 -284
  56. package/cli/wizard.js.map +1 -0
  57. package/package.json +15 -4
  58. package/public/app.d.ts +1 -0
  59. package/public/app.js +1057 -1009
  60. package/public/app.js.map +1 -0
  61. package/public/browser.d.ts +68 -0
  62. package/public/browser.js +2 -0
  63. package/public/browser.js.map +1 -0
  64. package/public/index.html +30 -13
  65. package/public/js/about.d.ts +6 -0
  66. package/public/js/about.js +165 -172
  67. package/public/js/about.js.map +1 -0
  68. package/public/js/aiDraft.d.ts +3 -0
  69. package/public/js/aiDraft.js +116 -124
  70. package/public/js/aiDraft.js.map +1 -0
  71. package/public/js/analysisPanel.d.ts +7 -0
  72. package/public/js/analysisPanel.js +166 -166
  73. package/public/js/analysisPanel.js.map +1 -0
  74. package/public/js/analysisReport.d.ts +38 -0
  75. package/public/js/analysisReport.js +105 -110
  76. package/public/js/analysisReport.js.map +1 -0
  77. package/public/js/api.d.ts +26 -0
  78. package/public/js/api.js +176 -167
  79. package/public/js/api.js.map +1 -0
  80. package/public/js/atlas.d.ts +6 -0
  81. package/public/js/atlas.js +50 -58
  82. package/public/js/atlas.js.map +1 -0
  83. package/public/js/blameView.d.ts +2 -0
  84. package/public/js/blameView.js +36 -37
  85. package/public/js/blameView.js.map +1 -0
  86. package/public/js/codeTab.d.ts +3 -0
  87. package/public/js/codeTab.js +175 -180
  88. package/public/js/codeTab.js.map +1 -0
  89. package/public/js/codeViewer.d.ts +5 -0
  90. package/public/js/codeViewer.js +162 -150
  91. package/public/js/codeViewer.js.map +1 -0
  92. package/public/js/components/FileChip.d.ts +9 -0
  93. package/public/js/components/FileChip.js +45 -49
  94. package/public/js/components/FileChip.js.map +1 -0
  95. package/public/js/components/MetricSparkline.d.ts +7 -0
  96. package/public/js/components/MetricSparkline.js +35 -44
  97. package/public/js/components/MetricSparkline.js.map +1 -0
  98. package/public/js/components/RiskBadge.d.ts +9 -0
  99. package/public/js/components/RiskBadge.js +55 -63
  100. package/public/js/components/RiskBadge.js.map +1 -0
  101. package/public/js/deepAnalysisView.d.ts +99 -0
  102. package/public/js/deepAnalysisView.js +282 -302
  103. package/public/js/deepAnalysisView.js.map +1 -0
  104. package/public/js/diagramPane.d.ts +8 -0
  105. package/public/js/diagramPane.js +133 -135
  106. package/public/js/diagramPane.js.map +1 -0
  107. package/public/js/diffView.d.ts +6 -0
  108. package/public/js/diffView.js +222 -209
  109. package/public/js/diffView.js.map +1 -0
  110. package/public/js/docsView.d.ts +2 -0
  111. package/public/js/docsView.js +441 -442
  112. package/public/js/docsView.js.map +1 -0
  113. package/public/js/dom.d.ts +189 -0
  114. package/public/js/dom.js +5 -0
  115. package/public/js/dom.js.map +1 -0
  116. package/public/js/fileSourceBrowser.d.ts +5 -0
  117. package/public/js/fileSourceBrowser.js +33 -41
  118. package/public/js/fileSourceBrowser.js.map +1 -0
  119. package/public/js/flameGraph.d.ts +5 -0
  120. package/public/js/flameGraph.js +62 -72
  121. package/public/js/flameGraph.js.map +1 -0
  122. package/public/js/forceGraph.d.ts +10 -0
  123. package/public/js/forceGraph.js +581 -556
  124. package/public/js/forceGraph.js.map +1 -0
  125. package/public/js/heatmap.d.ts +4 -0
  126. package/public/js/heatmap.js +142 -164
  127. package/public/js/heatmap.js.map +1 -0
  128. package/public/js/highlight.d.ts +2 -0
  129. package/public/js/highlight.js +116 -107
  130. package/public/js/highlight.js.map +1 -0
  131. package/public/js/html.d.ts +2 -0
  132. package/public/js/html.js +14 -44
  133. package/public/js/html.js.map +1 -0
  134. package/public/js/insightsView.d.ts +5 -0
  135. package/public/js/insightsView.js +93 -111
  136. package/public/js/insightsView.js.map +1 -0
  137. package/public/js/inspector.d.ts +37 -0
  138. package/public/js/inspector.js +416 -445
  139. package/public/js/inspector.js.map +1 -0
  140. package/public/js/llm.d.ts +113 -0
  141. package/public/js/llm.js +233 -272
  142. package/public/js/llm.js.map +1 -0
  143. package/public/js/mapView.d.ts +3 -0
  144. package/public/js/mapView.js +121 -120
  145. package/public/js/mapView.js.map +1 -0
  146. package/public/js/markdown.d.ts +3 -0
  147. package/public/js/markdown.js +84 -91
  148. package/public/js/markdown.js.map +1 -0
  149. package/public/js/mindmap.d.ts +32 -0
  150. package/public/js/mindmap.js +244 -259
  151. package/public/js/mindmap.js.map +1 -0
  152. package/public/js/mobilePanels.d.ts +5 -0
  153. package/public/js/mobilePanels.js +50 -0
  154. package/public/js/mobilePanels.js.map +1 -0
  155. package/public/js/repoFiles.d.ts +12 -0
  156. package/public/js/repoFiles.js +28 -27
  157. package/public/js/repoFiles.js.map +1 -0
  158. package/public/js/reviewView.d.ts +28 -0
  159. package/public/js/reviewView.js +256 -0
  160. package/public/js/reviewView.js.map +1 -0
  161. package/public/js/sbomView.d.ts +3 -0
  162. package/public/js/sbomView.js +59 -67
  163. package/public/js/sbomView.js.map +1 -0
  164. package/public/js/scanCache.d.ts +16 -0
  165. package/public/js/scanCache.js +67 -65
  166. package/public/js/scanCache.js.map +1 -0
  167. package/public/js/search.d.ts +7 -0
  168. package/public/js/search.js +868 -800
  169. package/public/js/search.js.map +1 -0
  170. package/public/js/searchLocal.d.ts +42 -0
  171. package/public/js/searchLocal.js +87 -0
  172. package/public/js/searchLocal.js.map +1 -0
  173. package/public/js/serverSettings.d.ts +5 -0
  174. package/public/js/serverSettings.js +153 -164
  175. package/public/js/serverSettings.js.map +1 -0
  176. package/public/js/state.d.ts +798 -0
  177. package/public/js/state.js +114 -122
  178. package/public/js/state.js.map +1 -0
  179. package/public/js/tour.d.ts +6 -0
  180. package/public/js/tour.js +5 -7
  181. package/public/js/tour.js.map +1 -0
  182. package/public/js/transitions.d.ts +2 -0
  183. package/public/js/transitions.js +9 -10
  184. package/public/js/transitions.js.map +1 -0
  185. package/public/js/tree.d.ts +12 -0
  186. package/public/js/tree.js +157 -154
  187. package/public/js/tree.js.map +1 -0
  188. package/public/js/workflowsView.d.ts +3 -0
  189. package/public/js/workflowsView.js +15 -22
  190. package/public/js/workflowsView.js.map +1 -0
  191. package/public/search.css +495 -0
  192. package/public/styles.css +163 -346
  193. package/public/workbench.css +166 -0
  194. package/server/apiAuth.d.ts +3 -0
  195. package/server/apiAuth.js +18 -20
  196. package/server/apiAuth.js.map +1 -0
  197. package/server/apiDiff.d.ts +2 -0
  198. package/server/apiDiff.js +20 -18
  199. package/server/apiDiff.js.map +1 -0
  200. package/server/apiDocs.d.ts +2 -0
  201. package/server/apiDocs.js +38 -40
  202. package/server/apiDocs.js.map +1 -0
  203. package/server/apiFile.d.ts +1 -0
  204. package/server/apiFile.js +14 -17
  205. package/server/apiFile.js.map +1 -0
  206. package/server/apiGitBlame.d.ts +2 -0
  207. package/server/apiGitBlame.js +50 -51
  208. package/server/apiGitBlame.js.map +1 -0
  209. package/server/apiMcp.d.ts +4 -0
  210. package/server/apiMcp.js +64 -66
  211. package/server/apiMcp.js.map +1 -0
  212. package/server/apiReview.d.ts +2 -0
  213. package/server/apiReview.js +45 -0
  214. package/server/apiReview.js.map +1 -0
  215. package/server/apiScan.d.ts +5 -0
  216. package/server/apiScan.js +90 -71
  217. package/server/apiScan.js.map +1 -0
  218. package/server/apiSearch.d.ts +33 -0
  219. package/server/apiSearch.js +184 -200
  220. package/server/apiSearch.js.map +1 -0
  221. package/server/apiSettings.d.ts +4 -0
  222. package/server/apiSettings.js +84 -85
  223. package/server/apiSettings.js.map +1 -0
  224. package/server/apiTools.d.ts +3 -0
  225. package/server/apiTools.js +55 -56
  226. package/server/apiTools.js.map +1 -0
  227. package/server/auth.d.ts +5 -0
  228. package/server/auth.js +54 -51
  229. package/server/auth.js.map +1 -0
  230. package/server/config.d.ts +42 -0
  231. package/server/config.js +189 -194
  232. package/server/config.js.map +1 -0
  233. package/server/daemon.d.ts +12 -0
  234. package/server/daemon.js +124 -114
  235. package/server/daemon.js.map +1 -0
  236. package/server/fileSourceNode.d.ts +2 -0
  237. package/server/fileSourceNode.js +34 -36
  238. package/server/fileSourceNode.js.map +1 -0
  239. package/server/gitClone.d.ts +9 -0
  240. package/server/gitClone.js +59 -61
  241. package/server/gitClone.js.map +1 -0
  242. package/server/gitDiff.d.ts +36 -0
  243. package/server/gitDiff.js +271 -169
  244. package/server/gitDiff.js.map +1 -0
  245. package/server/gitHistory.d.ts +12 -0
  246. package/server/gitHistory.js +80 -80
  247. package/server/gitHistory.js.map +1 -0
  248. package/server/gitRemote.d.ts +12 -0
  249. package/server/gitRemote.js +60 -0
  250. package/server/gitRemote.js.map +1 -0
  251. package/server/htmlText.d.ts +4 -0
  252. package/server/htmlText.js +16 -23
  253. package/server/htmlText.js.map +1 -0
  254. package/server/http.d.ts +5 -0
  255. package/server/http.js +27 -30
  256. package/server/http.js.map +1 -0
  257. package/server/httpGuards.d.ts +2 -0
  258. package/server/httpGuards.js +47 -43
  259. package/server/httpGuards.js.map +1 -0
  260. package/server/https.d.ts +34 -0
  261. package/server/https.js +121 -111
  262. package/server/https.js.map +1 -0
  263. package/server/index.d.ts +40 -0
  264. package/server/index.js +139 -147
  265. package/server/index.js.map +1 -0
  266. package/server/layout.d.ts +26 -0
  267. package/server/layout.js +59 -37
  268. package/server/layout.js.map +1 -0
  269. package/server/llmProxy.d.ts +3 -0
  270. package/server/llmProxy.js +137 -135
  271. package/server/llmProxy.js.map +1 -0
  272. package/server/logger.d.ts +38 -0
  273. package/server/logger.js +198 -211
  274. package/server/logger.js.map +1 -0
  275. package/server/mcp/analysis.d.ts +29 -0
  276. package/server/mcp/analysis.js +99 -120
  277. package/server/mcp/analysis.js.map +1 -0
  278. package/server/mcp/http.d.ts +9 -0
  279. package/server/mcp/http.js +128 -137
  280. package/server/mcp/http.js.map +1 -0
  281. package/server/mcp/runner.d.ts +68 -0
  282. package/server/mcp/runner.js +208 -218
  283. package/server/mcp/runner.js.map +1 -0
  284. package/server/mcp/server.d.ts +29 -0
  285. package/server/mcp/server.js +166 -179
  286. package/server/mcp/server.js.map +1 -0
  287. package/server/mcp/standalone.d.ts +1 -0
  288. package/server/mcp/standalone.js +8 -10
  289. package/server/mcp/standalone.js.map +1 -0
  290. package/server/mcp/tools.d.ts +2020 -0
  291. package/server/mcp/tools.js +523 -574
  292. package/server/mcp/tools.js.map +1 -0
  293. package/server/paths.d.ts +3 -0
  294. package/server/paths.js +17 -15
  295. package/server/paths.js.map +1 -0
  296. package/server/pidfile.d.ts +9 -0
  297. package/server/pidfile.js +43 -45
  298. package/server/pidfile.js.map +1 -0
  299. package/server/review.d.ts +5 -0
  300. package/server/review.js +35 -0
  301. package/server/review.js.map +1 -0
  302. package/server/router.d.ts +33 -0
  303. package/server/router.js +191 -197
  304. package/server/router.js.map +1 -0
  305. package/server/scanRequest.d.ts +3 -0
  306. package/server/scanRequest.js +36 -0
  307. package/server/scanRequest.js.map +1 -0
  308. package/server/searchIndex.d.ts +17 -0
  309. package/server/searchIndex.js +83 -80
  310. package/server/searchIndex.js.map +1 -0
  311. package/server/sessions.d.ts +14 -0
  312. package/server/sessions.js +62 -70
  313. package/server/sessions.js.map +1 -0
  314. package/server/startup.d.ts +118 -0
  315. package/server/startup.js +143 -148
  316. package/server/startup.js.map +1 -0
  317. package/server/static.d.ts +6 -0
  318. package/server/static.js +28 -31
  319. package/server/static.js.map +1 -0
  320. package/server/tools/install.d.ts +4 -0
  321. package/server/tools/install.js +176 -185
  322. package/server/tools/install.js.map +1 -0
  323. package/server/tools/parse.d.ts +8 -0
  324. package/server/tools/parse.js +112 -114
  325. package/server/tools/parse.js.map +1 -0
  326. package/server/tools/platform.d.ts +9 -0
  327. package/server/tools/platform.js +49 -47
  328. package/server/tools/platform.js.map +1 -0
  329. package/server/tools/registry.d.ts +137 -0
  330. package/server/tools/registry.js +173 -172
  331. package/server/tools/registry.js.map +1 -0
  332. package/server/tools/scan.d.ts +34 -0
  333. package/server/tools/scan.js +89 -98
  334. package/server/tools/scan.js.map +1 -0
  335. package/server/tools.d.ts +34 -0
  336. package/server/tools.js +94 -107
  337. package/server/tools.js.map +1 -0
  338. package/server/tunnel.d.ts +29 -0
  339. package/server/tunnel.js +61 -66
  340. package/server/tunnel.js.map +1 -0
  341. package/shared/analyzer/docs.d.ts +16 -0
  342. package/shared/analyzer/docs.js +99 -93
  343. package/shared/analyzer/docs.js.map +1 -0
  344. package/shared/analyzer/explainLocal.d.ts +4 -0
  345. package/shared/analyzer/explainLocal.js +122 -142
  346. package/shared/analyzer/explainLocal.js.map +1 -0
  347. package/shared/analyzer/github.d.ts +37 -0
  348. package/shared/analyzer/github.js +79 -0
  349. package/shared/analyzer/github.js.map +1 -0
  350. package/shared/analyzer/graph.d.ts +41 -0
  351. package/shared/analyzer/graph.js +393 -400
  352. package/shared/analyzer/graph.js.map +1 -0
  353. package/shared/analyzer/health.d.ts +33 -0
  354. package/shared/analyzer/health.js +197 -193
  355. package/shared/analyzer/health.js.map +1 -0
  356. package/shared/analyzer/history.d.ts +29 -0
  357. package/shared/analyzer/history.js +110 -111
  358. package/shared/analyzer/history.js.map +1 -0
  359. package/shared/analyzer/jsonConfig.d.ts +2 -0
  360. package/shared/analyzer/jsonConfig.js +61 -0
  361. package/shared/analyzer/jsonConfig.js.map +1 -0
  362. package/shared/analyzer/languages/csharp.d.ts +26 -0
  363. package/shared/analyzer/languages/csharp.js +83 -88
  364. package/shared/analyzer/languages/csharp.js.map +1 -0
  365. package/shared/analyzer/languages/generic.d.ts +23 -0
  366. package/shared/analyzer/languages/generic.js +94 -105
  367. package/shared/analyzer/languages/generic.js.map +1 -0
  368. package/shared/analyzer/languages/go.d.ts +24 -0
  369. package/shared/analyzer/languages/go.js +45 -54
  370. package/shared/analyzer/languages/go.js.map +1 -0
  371. package/shared/analyzer/languages/index.d.ts +6 -0
  372. package/shared/analyzer/languages/index.js +19 -20
  373. package/shared/analyzer/languages/index.js.map +1 -0
  374. package/shared/analyzer/languages/java.d.ts +20 -0
  375. package/shared/analyzer/languages/java.js +73 -78
  376. package/shared/analyzer/languages/java.js.map +1 -0
  377. package/shared/analyzer/languages/javascript.d.ts +12 -0
  378. package/shared/analyzer/languages/javascript.js +258 -209
  379. package/shared/analyzer/languages/javascript.js.map +1 -0
  380. package/shared/analyzer/languages/python.d.ts +23 -0
  381. package/shared/analyzer/languages/python.js +92 -100
  382. package/shared/analyzer/languages/python.js.map +1 -0
  383. package/shared/analyzer/languages/rust.d.ts +17 -0
  384. package/shared/analyzer/languages/rust.js +96 -98
  385. package/shared/analyzer/languages/rust.js.map +1 -0
  386. package/shared/analyzer/languages/typescript.d.ts +11 -0
  387. package/shared/analyzer/languages/typescript.js +117 -116
  388. package/shared/analyzer/languages/typescript.js.map +1 -0
  389. package/shared/analyzer/licenses.d.ts +18 -0
  390. package/shared/analyzer/licenses.js +130 -133
  391. package/shared/analyzer/licenses.js.map +1 -0
  392. package/shared/analyzer/metrics.d.ts +20 -0
  393. package/shared/analyzer/metrics.js +112 -104
  394. package/shared/analyzer/metrics.js.map +1 -0
  395. package/shared/analyzer/pathUtil.d.ts +10 -0
  396. package/shared/analyzer/pathUtil.js +29 -35
  397. package/shared/analyzer/pathUtil.js.map +1 -0
  398. package/shared/analyzer/patterns.d.ts +11 -0
  399. package/shared/analyzer/patterns.js +231 -253
  400. package/shared/analyzer/patterns.js.map +1 -0
  401. package/shared/analyzer/scan.d.ts +62 -0
  402. package/shared/analyzer/scan.js +451 -442
  403. package/shared/analyzer/scan.js.map +1 -0
  404. package/shared/analyzer/scanControl.d.ts +11 -0
  405. package/shared/analyzer/scanControl.js +62 -0
  406. package/shared/analyzer/scanControl.js.map +1 -0
  407. package/shared/analyzer/security.d.ts +18 -0
  408. package/shared/analyzer/security.js +159 -159
  409. package/shared/analyzer/security.js.map +1 -0
  410. package/shared/analyzer/services.d.ts +5 -0
  411. package/shared/analyzer/services.js +141 -138
  412. package/shared/analyzer/services.js.map +1 -0
  413. package/shared/analyzer/stack.d.ts +6 -0
  414. package/shared/analyzer/stack.js +134 -141
  415. package/shared/analyzer/stack.js.map +1 -0
  416. package/shared/analyzer/tour.d.ts +2 -0
  417. package/shared/analyzer/tour.js +45 -53
  418. package/shared/analyzer/tour.js.map +1 -0
  419. package/shared/analyzer/util.d.ts +8 -0
  420. package/shared/analyzer/util.js +130 -76
  421. package/shared/analyzer/util.js.map +1 -0
  422. package/shared/analyzer/workflows.d.ts +8 -0
  423. package/shared/analyzer/workflows.js +139 -134
  424. package/shared/analyzer/workflows.js.map +1 -0
  425. package/shared/contracts.d.ts +250 -0
  426. package/shared/contracts.js +2 -0
  427. package/shared/contracts.js.map +1 -0
  428. package/shared/diagram/aiFacts.d.ts +35 -0
  429. package/shared/diagram/aiFacts.js +102 -105
  430. package/shared/diagram/aiFacts.js.map +1 -0
  431. package/shared/diagram/aiMermaid.d.ts +5 -0
  432. package/shared/diagram/aiMermaid.js +46 -45
  433. package/shared/diagram/aiMermaid.js.map +1 -0
  434. package/shared/diagram/atlas.d.ts +16 -0
  435. package/shared/diagram/atlas.js +51 -60
  436. package/shared/diagram/atlas.js.map +1 -0
  437. package/shared/diagram/mermaid.d.ts +43 -0
  438. package/shared/diagram/mermaid.js +348 -370
  439. package/shared/diagram/mermaid.js.map +1 -0
  440. package/shared/review/contracts.d.ts +95 -0
  441. package/shared/review/contracts.js +2 -0
  442. package/shared/review/contracts.js.map +1 -0
  443. package/shared/review/review.d.ts +10 -0
  444. package/shared/review/review.js +184 -0
  445. package/shared/review/review.js.map +1 -0
  446. package/shared/search/query.d.ts +32 -0
  447. package/shared/search/query.js +395 -388
  448. package/shared/search/query.js.map +1 -0
package/server/startup.js CHANGED
@@ -19,27 +19,21 @@
19
19
  // Deliberately no `sudo`, no writing into launchd's system domain, and nothing
20
20
  // outside the user's own home. A login item is a convenience; it must never be
21
21
  // the thing that needs an administrator password.
22
-
23
22
  import { promises as fs } from 'node:fs';
24
23
  import os from 'node:os';
25
24
  import path from 'node:path';
26
25
  import { spawnSync } from 'node:child_process';
27
26
  import { fileURLToPath } from 'node:url';
28
-
29
27
  import { configPath } from './config.js';
30
-
31
28
  const HERE = path.dirname(fileURLToPath(import.meta.url));
32
-
33
29
  export const LABEL = 'com.onboarder.server';
34
30
  export const UNIT = 'onboarder.service';
35
-
36
31
  export function cliEntry() {
37
- // `bin/onboarder.js` next to `server/`, whether we were run from a checkout
38
- // or from a global install. The env override is what lets a test point the
39
- // generated unit at a fixture instead of the real machine.
40
- return process.env.ONBOARDER_CLI || path.resolve(HERE, '..', 'bin', 'onboarder.js');
32
+ // `bin/onboarder.js` next to `server/`, whether we were run from a checkout
33
+ // or from a global install. The env override is what lets a test point the
34
+ // generated unit at a fixture instead of the real machine.
35
+ return process.env.ONBOARDER_CLI || path.resolve(HERE, '..', 'bin', 'onboarder.js');
41
36
  }
42
-
43
37
  // The argv a login item runs.
44
38
  //
45
39
  // Note what is *not* here: `background`. launchd and systemd are already
@@ -49,24 +43,21 @@ export function cliEntry() {
49
43
  // busy port into a respawn loop. So the generated command is a plain foreground
50
44
  // `start`, and the OS owns the lifecycle from there.
51
45
  export function startupCommand(configFile = configPath(), { node = process.execPath, entry = cliEntry() } = {}) {
52
- return [node, entry, 'start', '--config', configFile];
46
+ return [node, entry, 'start', '--config', configFile];
53
47
  }
54
-
55
48
  function xmlEscape(value) {
56
- const map = { '<': '&lt;', '>': '&gt;', '&': '&amp;', "'": '&apos;', '"': '&quot;' };
57
- return String(value).replace(/[<>&'"]/g, (c) => map[c]);
49
+ const map = { '<': '&lt;', '>': '&gt;', '&': '&amp;', "'": '&apos;', '"': '&quot;' };
50
+ return String(value).replace(/[<>&'"]/g, (c) => map[c]);
58
51
  }
59
-
60
52
  function argList(args) {
61
- return args.map((a) => ` <string>${xmlEscape(a)}</string>`).join('\n');
53
+ return args.map((a) => ` <string>${xmlEscape(a)}</string>`).join('\n');
62
54
  }
63
-
64
55
  export function renderLaunchAgent({ configFile = configPath(), log = '', ...options } = {}) {
65
- const args = startupCommand(configFile, options);
66
- const streams = log
67
- ? ` <key>StandardOutPath</key>\n <string>${xmlEscape(log)}</string>\n <key>StandardErrorPath</key>\n <string>${xmlEscape(log)}</string>\n`
68
- : '';
69
- return `<?xml version="1.0" encoding="UTF-8"?>
56
+ const args = startupCommand(configFile, options);
57
+ const streams = log
58
+ ? ` <key>StandardOutPath</key>\n <string>${xmlEscape(log)}</string>\n <key>StandardErrorPath</key>\n <string>${xmlEscape(log)}</string>\n`
59
+ : '';
60
+ return `<?xml version="1.0" encoding="UTF-8"?>
70
61
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
71
62
  <plist version="1.0">
72
63
  <dict>
@@ -94,14 +85,13 @@ ${streams} <key>EnvironmentVariables</key>
94
85
  </plist>
95
86
  `;
96
87
  }
97
-
98
88
  export function renderSystemdUnit({ configFile = configPath(), log = '', ...options } = {}) {
99
- const args = startupCommand(configFile, options);
100
- // `Restart=always` would fight `onboarder stop`: a deliberate stop must stay
101
- // stopped, so only a *failed* exit is restarted. `on-failure` is the honest
102
- // setting here, and `SuccessfulExit=false` above is its launchd spelling.
103
- const exec = args.map((a) => (/[\s"]/.test(a) ? JSON.stringify(a) : a)).join(' ');
104
- return `[Unit]
89
+ const args = startupCommand(configFile, options);
90
+ // `Restart=always` would fight `onboarder stop`: a deliberate stop must stay
91
+ // stopped, so only a *failed* exit is restarted. `on-failure` is the honest
92
+ // setting here, and `SuccessfulExit=false` above is its launchd spelling.
93
+ const exec = args.map((a) => (/[\s"]/.test(a) ? JSON.stringify(a) : a)).join(' ');
94
+ return `[Unit]
105
95
  Description=Onboarder — codebase visualizer and onboarding map
106
96
  Documentation=https://github.com/Amitpandey88/onboarder
107
97
  After=network-online.target
@@ -119,143 +109,148 @@ Environment=ONBOARDER_LAUNCH=startup
119
109
  WantedBy=default.target
120
110
  `;
121
111
  }
122
-
123
112
  export function renderWindowsStartup({ configFile = configPath(), log = '', ...options } = {}) {
124
- const args = startupCommand(configFile, options);
125
- const line = args.map((a) => `"${a}"`).join(' ');
126
- return `@echo off\r\nrem Managed by "onboarder start startup". Edits are replaced.\r\nstart "" /b ${line}${log ? ` >> "${log}" 2>&1` : ''}\r\n`;
113
+ const args = startupCommand(configFile, options);
114
+ const line = args.map((a) => `"${a}"`).join(' ');
115
+ return `@echo off\r\nrem Managed by "onboarder start startup". Edits are replaced.\r\nstart "" /b ${line}${log ? ` >> "${log}" 2>&1` : ''}\r\n`;
127
116
  }
128
-
129
117
  // The target carries its own platform, so every message about it can name the
130
118
  // platform it was resolved for rather than the one this process happens to run
131
119
  // on. A test (or a future cross-platform installer) resolves a plan9 target on a
132
120
  // Mac; saying "darwin" in that error would be a lie.
133
121
  export function startupTarget({ platform = process.platform, home = os.homedir(), env = process.env } = {}) {
134
- // The per-user launchd domain. The system domain needs root, which this tool
135
- // never asks for.
136
- const domain = `gui/${process.getuid?.() ?? 501}`;
137
- if (platform === 'darwin') {
138
- return {
139
- kind: 'launchd',
140
- platform,
141
- label: LABEL,
142
- path: path.join(home, 'Library', 'LaunchAgents', LABEL + '.plist'),
143
- render: renderLaunchAgent,
144
- load: ['launchctl', 'bootstrap', domain, '{file}'],
145
- unload: ['launchctl', 'bootout', `${domain}/{label}`],
146
- status: ['launchctl', 'print', `${domain}/{label}`],
147
- hint: 'launchd agent in ~/Library/LaunchAgents',
148
- };
149
- }
150
- if (platform === 'linux') {
151
- const configHome = env.XDG_CONFIG_HOME || path.join(home, '.config');
152
- return {
153
- kind: 'systemd',
154
- platform,
155
- label: UNIT,
156
- path: path.join(configHome, 'systemd', 'user', UNIT),
157
- render: renderSystemdUnit,
158
- daemonReload: ['systemctl', '--user', 'daemon-reload'],
159
- load: ['systemctl', '--user', 'enable', '--now', UNIT],
160
- unload: ['systemctl', '--user', 'disable', '--now', UNIT],
161
- status: ['systemctl', '--user', 'is-active', UNIT],
162
- hint: 'systemd --user unit (no root; starts with your session)',
163
- };
164
- }
165
- if (platform === 'win32') {
166
- const appData = env.APPDATA || path.join(home, 'AppData', 'Roaming');
167
- // Native separators throughout: this string goes into a .cmd file and into
168
- // the Startup folder itself, and `path.join` would emit `\` mixed with `/`
169
- // — which Windows tolerates in a file path but no one should have to read.
170
- return {
171
- kind: 'startup-folder',
172
- platform,
173
- label: 'Onboarder.cmd',
174
- path: [
175
- appData, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup', 'Onboarder.cmd',
176
- ].join('\\'),
177
- render: renderWindowsStartup,
178
- load: null, // the file *is* the registration
179
- unload: null,
180
- status: null,
181
- hint: 'script in the Windows Startup folder',
182
- };
183
- }
184
- return { kind: 'unsupported', platform, label: '', path: '', render: null, load: null, unload: null, status: null, hint: '' };
122
+ // The per-user launchd domain. The system domain needs root, which this tool
123
+ // never asks for.
124
+ const domain = `gui/${process.getuid?.() ?? 501}`;
125
+ if (platform === 'darwin') {
126
+ return {
127
+ kind: 'launchd',
128
+ platform,
129
+ label: LABEL,
130
+ path: path.join(home, 'Library', 'LaunchAgents', LABEL + '.plist'),
131
+ render: renderLaunchAgent,
132
+ load: ['launchctl', 'bootstrap', domain, '{file}'],
133
+ unload: ['launchctl', 'bootout', `${domain}/{label}`],
134
+ status: ['launchctl', 'print', `${domain}/{label}`],
135
+ hint: 'launchd agent in ~/Library/LaunchAgents',
136
+ };
137
+ }
138
+ if (platform === 'linux') {
139
+ const configHome = env.XDG_CONFIG_HOME || path.join(home, '.config');
140
+ return {
141
+ kind: 'systemd',
142
+ platform,
143
+ label: UNIT,
144
+ path: path.join(configHome, 'systemd', 'user', UNIT),
145
+ render: renderSystemdUnit,
146
+ daemonReload: ['systemctl', '--user', 'daemon-reload'],
147
+ load: ['systemctl', '--user', 'enable', '--now', UNIT],
148
+ unload: ['systemctl', '--user', 'disable', '--now', UNIT],
149
+ status: ['systemctl', '--user', 'is-active', UNIT],
150
+ hint: 'systemd --user unit (no root; starts with your session)',
151
+ };
152
+ }
153
+ if (platform === 'win32') {
154
+ const appData = env.APPDATA || path.join(home, 'AppData', 'Roaming');
155
+ // Native separators throughout: this string goes into a .cmd file and into
156
+ // the Startup folder itself, and `path.join` would emit `\` mixed with `/`
157
+ // — which Windows tolerates in a file path but no one should have to read.
158
+ return {
159
+ kind: 'startup-folder',
160
+ platform,
161
+ label: 'Onboarder.cmd',
162
+ path: [
163
+ appData, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup', 'Onboarder.cmd',
164
+ ].join('\\'),
165
+ render: renderWindowsStartup,
166
+ load: null, // the file *is* the registration
167
+ unload: null,
168
+ status: null,
169
+ hint: 'script in the Windows Startup folder',
170
+ };
171
+ }
172
+ return { kind: 'unsupported', platform, label: '', path: '', render: null, load: null, unload: null, status: null, hint: '' };
185
173
  }
186
-
187
174
  // Substitute `{file}` / `{label}` and run without a shell — an argument is an
188
175
  // argument, never a command line somebody else gets to compose. `spawn` is
189
176
  // injected so a test can assert on the argv without touching launchd.
190
177
  function exec(argv, { spawn = spawnSync } = {}) {
191
- const result = spawn(argv[0], argv.slice(1), { encoding: 'utf8' });
192
- return {
193
- ok: !result.error && result.status === 0,
194
- status: result.status ?? null,
195
- output: String(result.stdout || result.stderr || '').trim(),
196
- error: result.error?.message || '',
197
- };
178
+ const result = spawn(argv[0], argv.slice(1), { encoding: 'utf8' });
179
+ return {
180
+ ok: !result.error && result.status === 0,
181
+ status: result.status ?? null,
182
+ output: String(result.stdout || result.stderr || '').trim(),
183
+ error: result.error?.message || '',
184
+ };
198
185
  }
199
-
200
186
  const fill = (argv, target) => argv
201
- .map((a) => a.replace('{file}', target.path).replace('{label}', target.label));
202
-
187
+ .map((a) => a.replace('{file}', target.path).replace('{label}', target.label));
203
188
  export async function startupInstalled(target = startupTarget()) {
204
- if (!target.path) return false;
205
- try { await fs.access(target.path); return true; } catch { return false; }
189
+ if (!target.path)
190
+ return false;
191
+ try {
192
+ await fs.access(target.path);
193
+ return true;
194
+ }
195
+ catch {
196
+ return false;
197
+ }
206
198
  }
207
-
208
199
  export async function startupStatus(target = startupTarget(), { run = spawnSync } = {}) {
209
- const installed = await startupInstalled(target);
210
- let active = null;
211
- if (installed && target.status) {
212
- const result = exec(fill(target.status, target), { spawn: run });
213
- // systemd answers `active`/`inactive` on stdout; `launchctl print` succeeds
214
- // only for a job that is actually loaded. Both answer "is it live now".
215
- const text = result.output.toLowerCase();
216
- active = target.kind === 'systemd'
217
- ? text.includes('active') && !text.includes('inactive')
218
- : result.ok;
219
- }
220
- return {
221
- kind: target.kind,
222
- supported: target.kind !== 'unsupported',
223
- label: target.label,
224
- path: target.path,
225
- installed,
226
- active,
227
- detail: target.kind === 'unsupported'
228
- ? `no automatic-startup mechanism for ${target.platform || process.platform}`
229
- : installed
230
- ? (active ? `running — ${target.hint}` : `installed, not running — ${target.hint}`)
231
- : 'not installed',
232
- hint: target.hint,
233
- };
200
+ const installed = await startupInstalled(target);
201
+ let active = null;
202
+ if (installed && target.status) {
203
+ const result = exec(fill(target.status, target), { spawn: run });
204
+ // systemd answers `active`/`inactive` on stdout; `launchctl print` succeeds
205
+ // only for a job that is actually loaded. Both answer "is it live now".
206
+ const text = result.output.toLowerCase();
207
+ active = target.kind === 'systemd'
208
+ ? text.includes('active') && !text.includes('inactive')
209
+ : result.ok;
210
+ }
211
+ return {
212
+ kind: target.kind,
213
+ supported: target.kind !== 'unsupported',
214
+ label: target.label,
215
+ path: target.path,
216
+ installed,
217
+ active,
218
+ detail: target.kind === 'unsupported'
219
+ ? `no automatic-startup mechanism for ${target.platform || process.platform}`
220
+ : installed
221
+ ? (active ? `running — ${target.hint}` : `installed, not running — ${target.hint}`)
222
+ : 'not installed',
223
+ hint: target.hint,
224
+ };
234
225
  }
235
-
236
226
  export async function installStartup({ configFile = configPath(), log = '', target = startupTarget(), run = spawnSync } = {}) {
237
- if (target.kind === 'unsupported') {
238
- return { ok: false, reason: `There is no automatic-startup mechanism Onboarder knows how to write on ${target.platform || process.platform}. Start it with \`onboarder start background\` from whatever your machine runs at boot.` };
239
- }
240
- await fs.mkdir(path.dirname(target.path), { recursive: true });
241
- await fs.writeFile(target.path, target.render({ configFile, log }), { encoding: 'utf8', mode: 0o600 });
242
- if (target.kind === 'systemd' && target.daemonReload) exec(fill(target.daemonReload, target), { spawn: run });
243
- if (!target.load) return { ok: true, path: target.path, loaded: true, output: '' };
244
- const result = exec(fill(target.load, target), { spawn: run });
245
- // A unit that is already loaded is a success, not a failure — installing twice
246
- // has to be idempotent, and `launchctl` says so in three different ways.
247
- const already = /already (been )?(loaded|active|exists|running)|115|unit .*already/i.test(result.output);
248
- if (!result.ok && !already) {
249
- return { ok: false, path: target.path, output: result.output || result.error, error: result.error };
250
- }
251
- return { ok: true, path: target.path, loaded: true, output: result.output };
227
+ if (target.kind === 'unsupported') {
228
+ return { ok: false, reason: `There is no automatic-startup mechanism Onboarder knows how to write on ${target.platform || process.platform}. Start it with \`onboarder start background\` from whatever your machine runs at boot.` };
229
+ }
230
+ await fs.mkdir(path.dirname(target.path), { recursive: true });
231
+ await fs.writeFile(target.path, target.render({ configFile, log }), { encoding: 'utf8', mode: 0o600 });
232
+ if (target.kind === 'systemd' && target.daemonReload)
233
+ exec(fill(target.daemonReload, target), { spawn: run });
234
+ if (!target.load)
235
+ return { ok: true, path: target.path, loaded: true, output: '' };
236
+ const result = exec(fill(target.load, target), { spawn: run });
237
+ // A unit that is already loaded is a success, not a failure — installing twice
238
+ // has to be idempotent, and `launchctl` says so in three different ways.
239
+ const already = /already (been )?(loaded|active|exists|running)|115|unit .*already/i.test(result.output);
240
+ if (!result.ok && !already) {
241
+ return { ok: false, path: target.path, output: result.output || result.error, error: result.error };
242
+ }
243
+ return { ok: true, path: target.path, loaded: true, output: result.output };
252
244
  }
253
-
254
245
  export async function removeStartup({ target = startupTarget(), run = spawnSync } = {}) {
255
- if (target.kind === 'unsupported') return { ok: false, reason: 'Nothing is installed for this platform.' };
256
- let output = '';
257
- if (target.unload) output = exec(fill(target.unload, target), { spawn: run }).output;
258
- await fs.rm(target.path, { force: true });
259
- if (target.kind === 'systemd' && target.daemonReload) exec(fill(target.daemonReload, target), { spawn: run });
260
- return { ok: true, path: target.path, output };
261
- }
246
+ if (target.kind === 'unsupported')
247
+ return { ok: false, reason: 'Nothing is installed for this platform.' };
248
+ let output = '';
249
+ if (target.unload)
250
+ output = exec(fill(target.unload, target), { spawn: run }).output;
251
+ await fs.rm(target.path, { force: true });
252
+ if (target.kind === 'systemd' && target.daemonReload)
253
+ exec(fill(target.daemonReload, target), { spawn: run });
254
+ return { ok: true, path: target.path, output };
255
+ }
256
+ //# sourceMappingURL=startup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"startup.js","sourceRoot":"","sources":["../src/server/startup.ts"],"names":[],"mappings":"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","sourcesContent":["// Start Onboarder when the machine boots, the way a person actually wants a\n// server they always want running to behave.\n//\n// \"Startup\" is three different mechanisms wearing one name, so this module\n// detects the platform and speaks its dialect — and, importantly, the *file\n// writing* is separated from the *service loading* so both are testable without\n// a Mac or a systemd:\n//\n// macOS ~/Library/LaunchAgents/<label>.plist → launchctl bootstrap\n// Linux ~/.config/systemd/user/<unit>.service → systemctl --user enable --now\n// Windows %APPDATA%\\...\\Startup\\Onboarder.cmd → being there is enough\n// other nothing; we say so rather than pretending\n//\n// Every artifact is generated from the *same* command line a person would type\n// (`<node> <cli> start background --config <file>`), so a login-started server\n// is indistinguishable from a hand-started one — same config, same pid file,\n// same `onboarder stop`.\n//\n// Deliberately no `sudo`, no writing into launchd's system domain, and nothing\n// outside the user's own home. A login item is a convenience; it must never be\n// the thing that needs an administrator password.\n\nimport { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\n\nimport { configPath } from './config.js';\n\nconst HERE = path.dirname(fileURLToPath(import.meta.url));\n\nexport const LABEL = 'com.onboarder.server';\nexport const UNIT = 'onboarder.service';\n\nexport function cliEntry() {\n // `bin/onboarder.js` next to `server/`, whether we were run from a checkout\n // or from a global install. The env override is what lets a test point the\n // generated unit at a fixture instead of the real machine.\n return process.env.ONBOARDER_CLI || path.resolve(HERE, '..', 'bin', 'onboarder.js');\n}\n\n// The argv a login item runs.\n//\n// Note what is *not* here: `background`. launchd and systemd are already\n// supervisors — they hold the process, restart it, and capture its output. A\n// login item that spawned a detached grandchild and exited immediately would\n// leave the supervisor watching a corpse, which defeats `KeepAlive` and turns a\n// busy port into a respawn loop. So the generated command is a plain foreground\n// `start`, and the OS owns the lifecycle from there.\nexport function startupCommand(configFile = configPath(), { node = process.execPath, entry = cliEntry() }: Record<string, any> = {}) {\n return [node, entry, 'start', '--config', configFile];\n}\n\nfunction xmlEscape(value) {\n const map = { '<': '&lt;', '>': '&gt;', '&': '&amp;', \"'\": '&apos;', '\"': '&quot;' };\n return String(value).replace(/[<>&'\"]/g, (c) => map[c]);\n}\n\nfunction argList(args) {\n return args.map((a) => ` <string>${xmlEscape(a)}</string>`).join('\\n');\n}\n\nexport function renderLaunchAgent({ configFile = configPath(), log = '', ...options }: Record<string, any> = {}) {\n const args = startupCommand(configFile, options);\n const streams = log\n ? ` <key>StandardOutPath</key>\\n <string>${xmlEscape(log)}</string>\\n <key>StandardErrorPath</key>\\n <string>${xmlEscape(log)}</string>\\n`\n : '';\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${xmlEscape(LABEL)}</string>\n <key>ProgramArguments</key>\n <array>\n${argList(args)}\n </array>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <dict>\n <key>SuccessfulExit</key>\n <false/>\n </dict>\n${streams} <key>EnvironmentVariables</key>\n <dict>\n <key>PATH</key>\n <string>${xmlEscape(process.env.PATH || '/usr/local/bin:/usr/bin:/bin')}</string>\n <key>ONBOARDER_LAUNCH</key>\n <string>startup</string>\n </dict>\n</dict>\n</plist>\n`;\n}\n\nexport function renderSystemdUnit({ configFile = configPath(), log = '', ...options }: Record<string, any> = {}) {\n const args = startupCommand(configFile, options);\n // `Restart=always` would fight `onboarder stop`: a deliberate stop must stay\n // stopped, so only a *failed* exit is restarted. `on-failure` is the honest\n // setting here, and `SuccessfulExit=false` above is its launchd spelling.\n const exec = args.map((a) => (/[\\s\"]/.test(a) ? JSON.stringify(a) : a)).join(' ');\n return `[Unit]\nDescription=Onboarder — codebase visualizer and onboarding map\nDocumentation=https://github.com/Amitpandey88/onboarder\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nExecStart=${exec}\nRestart=on-failure\nRestartSec=3\n${log ? `StandardOutput=append:${log}\\nStandardError=append:${log}\\n` : ''}Environment=NO_COLOR=1\nEnvironment=ONBOARDER_LAUNCH=startup\n\n[Install]\nWantedBy=default.target\n`;\n}\n\nexport function renderWindowsStartup({ configFile = configPath(), log = '', ...options }: Record<string, any> = {}) {\n const args = startupCommand(configFile, options);\n const line = args.map((a) => `\"${a}\"`).join(' ');\n return `@echo off\\r\\nrem Managed by \"onboarder start startup\". Edits are replaced.\\r\\nstart \"\" /b ${line}${log ? ` >> \"${log}\" 2>&1` : ''}\\r\\n`;\n}\n\n// The target carries its own platform, so every message about it can name the\n// platform it was resolved for rather than the one this process happens to run\n// on. A test (or a future cross-platform installer) resolves a plan9 target on a\n// Mac; saying \"darwin\" in that error would be a lie.\nexport function startupTarget({ platform = process.platform, home = os.homedir(), env = process.env }: Record<string, any> = {}) {\n // The per-user launchd domain. The system domain needs root, which this tool\n // never asks for.\n const domain = `gui/${process.getuid?.() ?? 501}`;\n if (platform === 'darwin') {\n return {\n kind: 'launchd',\n platform,\n label: LABEL,\n path: path.join(home, 'Library', 'LaunchAgents', LABEL + '.plist'),\n render: renderLaunchAgent,\n load: ['launchctl', 'bootstrap', domain, '{file}'],\n unload: ['launchctl', 'bootout', `${domain}/{label}`],\n status: ['launchctl', 'print', `${domain}/{label}`],\n hint: 'launchd agent in ~/Library/LaunchAgents',\n };\n }\n if (platform === 'linux') {\n const configHome = env.XDG_CONFIG_HOME || path.join(home, '.config');\n return {\n kind: 'systemd',\n platform,\n label: UNIT,\n path: path.join(configHome, 'systemd', 'user', UNIT),\n render: renderSystemdUnit,\n daemonReload: ['systemctl', '--user', 'daemon-reload'],\n load: ['systemctl', '--user', 'enable', '--now', UNIT],\n unload: ['systemctl', '--user', 'disable', '--now', UNIT],\n status: ['systemctl', '--user', 'is-active', UNIT],\n hint: 'systemd --user unit (no root; starts with your session)',\n };\n }\n if (platform === 'win32') {\n const appData = env.APPDATA || path.join(home, 'AppData', 'Roaming');\n // Native separators throughout: this string goes into a .cmd file and into\n // the Startup folder itself, and `path.join` would emit `\\` mixed with `/`\n // — which Windows tolerates in a file path but no one should have to read.\n return {\n kind: 'startup-folder',\n platform,\n label: 'Onboarder.cmd',\n path: [\n appData, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup', 'Onboarder.cmd',\n ].join('\\\\'),\n render: renderWindowsStartup,\n load: null, // the file *is* the registration\n unload: null,\n status: null,\n hint: 'script in the Windows Startup folder',\n };\n }\n return { kind: 'unsupported', platform, label: '', path: '', render: null, load: null, unload: null, status: null, hint: '' };\n}\n\n// Substitute `{file}` / `{label}` and run without a shell — an argument is an\n// argument, never a command line somebody else gets to compose. `spawn` is\n// injected so a test can assert on the argv without touching launchd.\nfunction exec(argv, { spawn = spawnSync }: Record<string, any> = {}) {\n const result = spawn(argv[0], argv.slice(1), { encoding: 'utf8' });\n return {\n ok: !result.error && result.status === 0,\n status: result.status ?? null,\n output: String(result.stdout || result.stderr || '').trim(),\n error: result.error?.message || '',\n };\n}\n\nconst fill = (argv, target) => argv\n .map((a) => a.replace('{file}', target.path).replace('{label}', target.label));\n\nexport async function startupInstalled(target = startupTarget()) {\n if (!target.path) return false;\n try { await fs.access(target.path); return true; } catch { return false; }\n}\n\nexport async function startupStatus(target = startupTarget(), { run = spawnSync }: Record<string, any> = {}) {\n const installed = await startupInstalled(target);\n let active = null;\n if (installed && target.status) {\n const result = exec(fill(target.status, target), { spawn: run });\n // systemd answers `active`/`inactive` on stdout; `launchctl print` succeeds\n // only for a job that is actually loaded. Both answer \"is it live now\".\n const text = result.output.toLowerCase();\n active = target.kind === 'systemd'\n ? text.includes('active') && !text.includes('inactive')\n : result.ok;\n }\n return {\n kind: target.kind,\n supported: target.kind !== 'unsupported',\n label: target.label,\n path: target.path,\n installed,\n active,\n detail: target.kind === 'unsupported'\n ? `no automatic-startup mechanism for ${target.platform || process.platform}`\n : installed\n ? (active ? `running — ${target.hint}` : `installed, not running — ${target.hint}`)\n : 'not installed',\n hint: target.hint,\n };\n}\n\nexport async function installStartup({ configFile = configPath(), log = '', target = startupTarget(), run = spawnSync }: Record<string, any> = {}) {\n if (target.kind === 'unsupported') {\n return { ok: false, reason: `There is no automatic-startup mechanism Onboarder knows how to write on ${target.platform || process.platform}. Start it with \\`onboarder start background\\` from whatever your machine runs at boot.` };\n }\n await fs.mkdir(path.dirname(target.path), { recursive: true });\n await fs.writeFile(target.path, target.render({ configFile, log }), { encoding: 'utf8', mode: 0o600 });\n if (target.kind === 'systemd' && target.daemonReload) exec(fill(target.daemonReload, target), { spawn: run });\n if (!target.load) return { ok: true, path: target.path, loaded: true, output: '' };\n const result = exec(fill(target.load, target), { spawn: run });\n // A unit that is already loaded is a success, not a failure — installing twice\n // has to be idempotent, and `launchctl` says so in three different ways.\n const already = /already (been )?(loaded|active|exists|running)|115|unit .*already/i.test(result.output);\n if (!result.ok && !already) {\n return { ok: false, path: target.path, output: result.output || result.error, error: result.error };\n }\n return { ok: true, path: target.path, loaded: true, output: result.output };\n}\n\nexport async function removeStartup({ target = startupTarget(), run = spawnSync }: Record<string, any> = {}) {\n if (target.kind === 'unsupported') return { ok: false, reason: 'Nothing is installed for this platform.' };\n let output = '';\n if (target.unload) output = exec(fill(target.unload, target), { spawn: run }).output;\n await fs.rm(target.path, { force: true });\n if (target.kind === 'systemd' && target.daemonReload) exec(fill(target.daemonReload, target), { spawn: run });\n return { ok: true, path: target.path, output };\n}"]}
@@ -0,0 +1,6 @@
1
+ export declare function resolveAsset(urlPath: any, { publicDir, sharedDir }: {
2
+ publicDir: any;
3
+ sharedDir: any;
4
+ }): string;
5
+ export declare function cacheControlFor(file: any): "no-cache" | "public, max-age=86400";
6
+ export declare function serveStatic(res: any, urlPath: any, dirs: any): Promise<void>;
package/server/static.js CHANGED
@@ -7,53 +7,50 @@
7
7
  // and work in both places, which is why browser modules reach for `/shared/...`
8
8
  // and pure logic that Node needs to test lives in `shared/` rather than beside
9
9
  // its caller.
10
-
11
10
  import { promises as fs } from 'node:fs';
12
11
  import path from 'node:path';
13
-
14
12
  import { sendError } from './http.js';
15
13
  import { resolveInside } from './paths.js';
16
-
17
14
  const MIME = {
18
- '.html': 'text/html; charset=utf-8',
19
- '.js': 'text/javascript; charset=utf-8',
20
- '.mjs': 'text/javascript; charset=utf-8',
21
- '.css': 'text/css; charset=utf-8',
22
- '.json': 'application/json; charset=utf-8',
23
- '.svg': 'image/svg+xml',
24
- '.png': 'image/png',
25
- '.ico': 'image/x-icon',
26
- '.map': 'application/json',
27
- '.woff2': 'font/woff2',
15
+ '.html': 'text/html; charset=utf-8',
16
+ '.js': 'text/javascript; charset=utf-8',
17
+ '.mjs': 'text/javascript; charset=utf-8',
18
+ '.css': 'text/css; charset=utf-8',
19
+ '.json': 'application/json; charset=utf-8',
20
+ '.svg': 'image/svg+xml',
21
+ '.png': 'image/png',
22
+ '.ico': 'image/x-icon',
23
+ '.map': 'application/json',
24
+ '.woff2': 'font/woff2',
28
25
  };
29
-
30
26
  // `null` for anything that resolves outside the directory it was mapped into —
31
27
  // `resolveInside` is the traversal guard, and a request for `/../../etc/passwd`
32
28
  // has to fail here rather than reach `readFile`.
33
29
  export function resolveAsset(urlPath, { publicDir, sharedDir }) {
34
- if (urlPath === '/' || urlPath === '/index.html') return path.join(publicDir, 'index.html');
35
- if (urlPath.startsWith('/shared/')) return resolveInside(sharedDir, urlPath.slice('/shared/'.length));
36
- return resolveInside(publicDir, urlPath);
30
+ if (urlPath === '/' || urlPath === '/index.html')
31
+ return path.join(publicDir, 'index.html');
32
+ if (urlPath.startsWith('/shared/'))
33
+ return resolveInside(sharedDir, urlPath.slice('/shared/'.length));
34
+ return resolveInside(publicDir, urlPath);
37
35
  }
38
-
39
36
  // Everything we author is served no-cache: the UI and the engine ship as loose
40
37
  // modules with no build step and no content hashes, so a stale app.js against a
41
38
  // fresh index.html breaks the whole page. Vendored builds are the exception —
42
39
  // they are versioned by the directory they sit in and never edited in place.
43
40
  export function cacheControlFor(file) {
44
- return file.includes(path.sep + 'vendor' + path.sep) ? 'public, max-age=86400' : 'no-cache';
41
+ return file.includes(path.sep + 'vendor' + path.sep) ? 'public, max-age=86400' : 'no-cache';
45
42
  }
46
-
47
43
  export async function serveStatic(res, urlPath, dirs) {
48
- const file = resolveAsset(urlPath, dirs);
49
- if (!file) return sendError(res, 403, 'Not from here.');
50
-
51
- const data = await fs.readFile(file).catch(() => null);
52
- if (data === null) return sendError(res, 404, 'Not found: ' + urlPath);
53
-
54
- res.writeHead(200, {
55
- 'content-type': MIME[path.extname(file).toLowerCase()] || 'application/octet-stream',
56
- 'cache-control': cacheControlFor(file),
57
- });
58
- res.end(data);
44
+ const file = resolveAsset(urlPath, dirs);
45
+ if (!file)
46
+ return sendError(res, 403, 'Not from here.');
47
+ const data = await fs.readFile(file).catch(() => null);
48
+ if (data === null)
49
+ return sendError(res, 404, 'Not found: ' + urlPath);
50
+ res.writeHead(200, {
51
+ 'content-type': MIME[path.extname(file).toLowerCase()] || 'application/octet-stream',
52
+ 'cache-control': cacheControlFor(file),
53
+ });
54
+ res.end(data);
59
55
  }
56
+ //# sourceMappingURL=static.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static.js","sourceRoot":"","sources":["../src/server/static.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,4EAA4E;AAC5E,8EAA8E;AAC9E,8EAA8E;AAC9E,EAAE;AACF,iFAAiF;AACjF,gFAAgF;AAChF,+EAA+E;AAC/E,cAAc;AAEd,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,IAAI,GAAG;IACX,OAAO,EAAE,0BAA0B;IACnC,KAAK,EAAE,gCAAgC;IACvC,MAAM,EAAE,gCAAgC;IACxC,MAAM,EAAE,yBAAyB;IACjC,OAAO,EAAE,iCAAiC;IAC1C,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,cAAc;IACtB,MAAM,EAAE,kBAAkB;IAC1B,QAAQ,EAAE,YAAY;CACvB,CAAC;AAEF,+EAA+E;AAC/E,gFAAgF;AAChF,iDAAiD;AACjD,MAAM,UAAU,YAAY,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE;IAC5D,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,aAAa;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IAC5F,IAAI,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IACtG,OAAO,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED,+EAA+E;AAC/E,gFAAgF;AAChF,8EAA8E;AAC9E,6EAA6E;AAC7E,MAAM,UAAU,eAAe,CAAC,IAAI;IAClC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAC;AAC9F,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI;IAClD,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACzC,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,gBAAgB,CAAC,CAAC;IAExD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACvD,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,CAAC;IAEvE,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;QACjB,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,0BAA0B;QACpF,eAAe,EAAE,eAAe,CAAC,IAAI,CAAC;KACvC,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC","sourcesContent":["// Serving the app itself: `public/` is the site root, and `/shared/` is mapped to\n// the repo's `shared/` directory so the analyzer the server imports and the\n// analyzer the browser imports are the same files. That mapping is the reason\n// nothing under `shared/` may touch `fs` or `window` — both runtimes load it.\n//\n// It also means no relative specifier can point from `public/js/` into `shared/`\n// and work in both places, which is why browser modules reach for `/shared/...`\n// and pure logic that Node needs to test lives in `shared/` rather than beside\n// its caller.\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\nimport { sendError } from './http.js';\nimport { resolveInside } from './paths.js';\n\nconst MIME = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'text/javascript; charset=utf-8',\n '.mjs': 'text/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.ico': 'image/x-icon',\n '.map': 'application/json',\n '.woff2': 'font/woff2',\n};\n\n// `null` for anything that resolves outside the directory it was mapped into —\n// `resolveInside` is the traversal guard, and a request for `/../../etc/passwd`\n// has to fail here rather than reach `readFile`.\nexport function resolveAsset(urlPath, { publicDir, sharedDir }) {\n if (urlPath === '/' || urlPath === '/index.html') return path.join(publicDir, 'index.html');\n if (urlPath.startsWith('/shared/')) return resolveInside(sharedDir, urlPath.slice('/shared/'.length));\n return resolveInside(publicDir, urlPath);\n}\n\n// Everything we author is served no-cache: the UI and the engine ship as loose\n// modules with no build step and no content hashes, so a stale app.js against a\n// fresh index.html breaks the whole page. Vendored builds are the exception —\n// they are versioned by the directory they sit in and never edited in place.\nexport function cacheControlFor(file) {\n return file.includes(path.sep + 'vendor' + path.sep) ? 'public, max-age=86400' : 'no-cache';\n}\n\nexport async function serveStatic(res, urlPath, dirs) {\n const file = resolveAsset(urlPath, dirs);\n if (!file) return sendError(res, 403, 'Not from here.');\n\n const data = await fs.readFile(file).catch(() => null);\n if (data === null) return sendError(res, 404, 'Not found: ' + urlPath);\n\n res.writeHead(200, {\n 'content-type': MIME[path.extname(file).toLowerCase()] || 'application/octet-stream',\n 'cache-control': cacheControlFor(file),\n });\n res.end(data);\n}\n"]}
@@ -0,0 +1,4 @@
1
+ export declare function plansFor(toolId: any, platform?: NodeJS.Platform): any;
2
+ export declare function planAvailability(toolId: any, options?: Record<string, any>): any;
3
+ export declare function isInstalling(toolId: any): boolean;
4
+ export declare function installTool(toolId: any, onEvent?: (event: Record<string, unknown>) => void): Promise<any>;