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
@@ -1,3 +1,4 @@
1
+ import { scanOptionsFromFlags } from '../scanOptions.js';
1
2
  // The interactive session.
2
3
  //
3
4
  // This is a prompt, not a full-screen TUI, and that is a deliberate choice.
@@ -14,12 +15,12 @@
14
15
  // hanging forever waiting for input nobody is there to type.
15
16
  // * Flags → env → config precedence. `NO_COLOR` and `COLUMNS` are honored
16
17
  // before anything is drawn, so a redirect gets plain, fitted text.
17
-
18
18
  import readline from 'node:readline';
19
+ import { explorerAgent } from '../agent/command.js';
20
+ import readlinePromises from 'node:readline/promises';
19
21
  import fs from 'node:fs';
20
22
  import path from 'node:path';
21
-
22
- import { openRepo, openRepoOrClone, isGitUrl, remoteUrlFor, closeRemote } from './session.js';
23
+ import { openRepo, openRepoOrClone, isGitUrl, remoteUrlFor, closeRemote, searchRepo, explainRepoOverview } from './session.js';
23
24
  import { fetchRepoFacts } from './github.js';
24
25
  import { CLEAR, EXIT, commandNames, completer, helpText, lookup, shellEscape, tokenize } from './commands.js';
25
26
  import { overview, github as githubView } from './views.js';
@@ -27,365 +28,454 @@ import { bold, cyan, dim, ok, bad, paint } from '../ui.js';
27
28
  import { configPath, readSettings, serverUrls } from '../../server/config.js';
28
29
  import { readPidFile, pidIsAlive } from '../../server/pidfile.js';
29
30
  import { expandHome } from '../../server/paths.js';
30
-
31
- const VERSION = JSON.parse(
32
- fs.readFileSync(new URL('../../package.json', import.meta.url), 'utf8')
33
- ).version;
34
-
31
+ import { SourcePicker } from './picker.js';
32
+ import { getGitDiff } from '../../server/gitDiff.js';
33
+ import { runExternalAnalysis, toolsStatus } from '../../server/tools/scan.js';
34
+ import { formatDiff, formatDeepAnalysis, formatEngines } from './featureViews.js';
35
+ import { askConfig, askModel, askSetupMessage } from './assistant.js';
36
+ import { wrapText } from './wrap.js';
37
+ const VERSION = JSON.parse(fs.readFileSync(new URL('../../package.json', import.meta.url), 'utf8')).version;
35
38
  // The one-time note. `onboarder` used to start a web server; now it opens this.
36
39
  // Someone who upgrades and has muscle memory for the old thing deserves to be
37
40
  // told once where the server went, and then never again.
38
41
  const HINT_MARKER = 'explorer-hint-v1';
39
-
40
- export async function runExplore({ target = '.', flags = {}, out = console.log, err = console.error, version = VERSION } = {}) {
41
- // The guard. `stdin` matters as much as `stdout`: a session with no input
42
- // source is a hang, and a hang in CI is worse than any error.
43
- if (!process.stdin.isTTY || !process.stdout.isTTY) {
44
- out('');
45
- out(' The terminal explorer needs an interactive terminal.');
46
- out(dim(' In a script or a pipe, use these instead:'));
47
- out(dim(' onboarder start start the web UI'));
48
- out(dim(' onboarder start background start it detached'));
49
- out(dim(' onboarder status | stop manage a running one'));
50
- out(dim(' onboarder --help everything else'));
42
+ export async function runExplore({ target = null, flags = {}, out = console.log, err = console.error, version = VERSION } = {}) {
43
+ // The guard. `stdin` matters as much as `stdout`: a session with no input
44
+ // source is a hang, and a hang in CI is worse than any error.
45
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
46
+ out('');
47
+ out(' The terminal explorer needs an interactive terminal.');
48
+ out(dim(' In a script or a pipe, use these instead:'));
49
+ out(dim(' onboarder start start the web UI'));
50
+ out(dim(' onboarder start background start it detached'));
51
+ out(dim(' onboarder status | stop manage a running one'));
52
+ out(dim(' onboarder --help everything else'));
53
+ out('');
54
+ return 0;
55
+ }
56
+ if (!target) {
57
+ target = await chooseInitialSource(out);
58
+ if (!target)
59
+ return 0;
60
+ }
61
+ let repo;
62
+ try {
63
+ // The launch argument accepts a URL for the same reason `cd` does: someone
64
+ // who has never seen this repo should be able to name it and read it. A
65
+ // silent ten-second clone looks like a hang, so the URL case says what it
66
+ // is doing before it starts.
67
+ if (isGitUrl(target))
68
+ out(dim(` cloning ${target}…`));
69
+ repo = await openRepoOrClone(target, { ...scanOptionsFromFlags(flags), onProgress: progressReporter(out) });
70
+ }
71
+ catch (e) {
72
+ err(' ' + bad((e.message || String(e))));
73
+ err(dim(' Point it at a folder: onboarder explore /path/to/repo'));
74
+ err(dim(' …or a git URL: onboarder explore https://github.com/org/repo'));
75
+ return 1;
76
+ }
51
77
  out('');
52
- return 0;
53
- }
54
-
55
- let repo;
56
- try {
57
- // The launch argument accepts a URL for the same reason `cd` does: someone
58
- // who has never seen this repo should be able to name it and read it. A
59
- // silent ten-second clone looks like a hang, so the URL case says what it
60
- // is doing before it starts.
61
- if (isGitUrl(target)) out(dim(` cloning ${target}…`));
62
- repo = await openRepoOrClone(target, { onProgress: progressReporter(out) });
63
- } catch (e) {
64
- err(' ' + bad((e.message || String(e))));
65
- err(dim(' Point it at a folder: onboarder explore /path/to/repo'));
66
- err(dim(' …or a git URL: onboarder explore https://github.com/org/repo'));
67
- return 1;
68
- }
69
-
70
- out('');
71
- out(overview(repo));
72
- out('');
73
- if (await shouldShowHint(flags)) {
74
- out(dim(' Note: `onboarder` used to start the web server. That is now `onboarder start`'));
75
- out(dim(' (or the `web` command here) — this session reads the repo directly,'));
76
- out(dim(' so it needs no server and works offline.'));
78
+ out(overview(repo));
77
79
  out('');
78
- }
79
- return session({ repo, flags, out, err, version });
80
+ if (await shouldShowHint(flags)) {
81
+ out(dim(' Note: `onboarder` used to start the web server. That is now `onboarder start`'));
82
+ out(dim(' (or the `web` command here) — this session reads the repo directly,'));
83
+ out(dim(' so it needs no server and works offline.'));
84
+ out('');
85
+ }
86
+ return session({ repo, flags, out, err, version });
87
+ }
88
+ async function chooseInitialSource(out) {
89
+ const picker = new SourcePicker();
90
+ const rl = readlinePromises.createInterface({ input: process.stdin, output: process.stdout });
91
+ try {
92
+ out(await picker.view());
93
+ for (;;) {
94
+ const result = await picker.choose(await rl.question(picker.prompt));
95
+ if (result.message)
96
+ out(result.message);
97
+ if (result.done)
98
+ return result.target;
99
+ }
100
+ }
101
+ catch {
102
+ return null;
103
+ }
104
+ finally {
105
+ rl.close();
106
+ }
80
107
  }
81
-
82
108
  // Scanning a large monorepo is the one genuinely slow thing this does, so it
83
109
  // says so. A silent eight seconds is indistinguishable from a hang.
84
110
  function progressReporter(out) {
85
- let last = 0;
86
- return ({ phase, done }) => {
87
- if (!process.stdout.isTTY) return;
88
- const now = Date.now();
89
- if (phase === 'parse' && done && now - last > 400) {
90
- last = now;
91
- out(dim(`\r scanning… ${done} files`));
92
- }
93
- };
111
+ let last = 0;
112
+ return (progress) => {
113
+ if (!process.stdout.isTTY)
114
+ return;
115
+ const now = Date.now();
116
+ if (progress.phase === 'parse' && progress.done && now - last > 400) {
117
+ last = now;
118
+ out(dim(`\r scanning… ${progress.done} files`));
119
+ }
120
+ };
94
121
  }
95
-
96
122
  async function shouldShowHint(flags) {
97
- if (process.env.ONBOARDER_NO_HINT) return false;
98
- try {
99
- const marker = path.join(path.dirname(flags.config || configPath()), HINT_MARKER);
100
- const seen = await fs.promises.stat(marker).then(() => true).catch(() => false);
101
- if (seen) return false;
102
- await fs.promises.mkdir(path.dirname(marker), { recursive: true });
103
- await fs.promises.writeFile(marker, 'shown\n');
104
- return true;
105
- } catch {
106
- // A read-only config home is not a reason to nag on every launch.
107
- return false;
108
- }
123
+ if (process.env.ONBOARDER_NO_HINT)
124
+ return false;
125
+ try {
126
+ const marker = path.join(path.dirname(flags.config || configPath()), HINT_MARKER);
127
+ const seen = await fs.promises.stat(marker).then(() => true).catch(() => false);
128
+ if (seen)
129
+ return false;
130
+ await fs.promises.mkdir(path.dirname(marker), { recursive: true });
131
+ await fs.promises.writeFile(marker, 'shown\n');
132
+ return true;
133
+ }
134
+ catch {
135
+ // A read-only config home is not a reason to nag on every launch.
136
+ return false;
137
+ }
109
138
  }
110
-
111
139
  // The read loop. Commands are queued rather than awaited inline, because
112
140
  // readline emits the next line while a slow command is still running and two
113
141
  // interleaved `cd`s would leave the session pointing at a repo nobody asked
114
142
  // for.
115
143
  function session({ repo, flags, out, err, version }) {
116
- const ctx = {
117
- repo,
118
- version,
119
- flags,
120
- help: (topic) => helpText(ctx, topic),
121
- rescan: () => reload(ctx, ctx.repo.root),
122
- loadRepo: (where) => reload(ctx, where),
123
- github: () => askGithub(ctx),
124
- web: () => startWeb(ctx),
125
- };
126
-
127
- const rl = readline.createInterface({
128
- input: process.stdin,
129
- output: process.stdout,
130
- prompt: promptFor(repo),
131
- terminal: true,
132
- historySize: 200,
133
- // The completer closes over the *current* repo rather than the one captured
134
- // here, so after a `cd` it completes paths in the new repository. Reading
135
- // `ctx.repo` at completion time is the whole trick.
136
- completer: (line) => completer(ctx.repo)(line),
137
- });
138
-
139
- let queue = Promise.resolve();
140
- let closed = false;
141
- let interrupts = 0;
142
- let onResize = null;
143
-
144
- // One poisoned promise must not end the session. `handleLine` catches its own
145
- // errors, but anything thrown outside it — a prompt write to a closed stream,
146
- // an error in a command's argument handling — would otherwise reject this
147
- // chain and silently swallow every command typed afterwards. The session would
148
- // look alive and do nothing, which is the worst failure mode a REPL has.
149
- rl.on('line', (line) => {
150
- queue = queue
151
- .then(() => handleLine(ctx, line, rl, out, err))
152
- .catch((e) => {
153
- err(' ' + bad((e?.message || String(e))));
154
- if (!closed) {
155
- try {
144
+ let agentAbort = null;
145
+ const ctx = {
146
+ picker: null,
147
+ repo,
148
+ version,
149
+ flags,
150
+ help: (topic) => helpText(ctx, topic),
151
+ rescan: () => reload(ctx, ctx.repo.root),
152
+ loadRepo: (where) => reload(ctx, where),
153
+ selectSource: async () => {
154
+ ctx.picker = new SourcePicker(ctx.repo.cloneDir ? process.cwd() : ctx.repo.root);
155
+ return ctx.picker.view();
156
+ },
157
+ github: () => askGithub(ctx),
158
+ agent: async (args) => {
159
+ if (ctx.repo.cloneDir && ['implement', 'pr'].includes(args[0]))
160
+ throw new Error('Open a persistent local checkout before implementing changes or creating a PR. This explorer clone is removed when the session ends.');
161
+ agentAbort = new AbortController();
162
+ try {
163
+ return await explorerAgent(args, ctx.repo.root, agentAbort.signal, out, err);
164
+ }
165
+ finally {
166
+ agentAbort = null;
167
+ }
168
+ },
169
+ web: () => startWeb(ctx),
170
+ diff: async (base = 'HEAD', head = '', file = '') => formatDiff(await getGitDiff(ctx.repo.root, { base, head, file }), ctx.repo.facts.importers || {}, ctx.repo.scan.files.length, file),
171
+ engines: () => formatEngines(toolsStatus()),
172
+ deep: async (tool) => {
173
+ const known = toolsStatus();
174
+ if (tool !== 'all' && !Object.hasOwn(known, tool)) {
175
+ return ' Unknown engine: ' + tool + '. Run `engines` to see the available names.';
176
+ }
177
+ return formatDeepAnalysis(await runExternalAnalysis(ctx.repo.root, tool === 'all' ? {} : { tools: [tool] }));
178
+ },
179
+ ask: async (question) => {
180
+ if (!question.trim())
181
+ return ' Ask a question, for example: ask Where should I start?';
182
+ const config = askConfig();
183
+ if (!config)
184
+ return askSetupMessage();
185
+ const hits = searchRepo(ctx.repo, question, { limit: 8 });
186
+ const lines = [
187
+ explainRepoOverview(ctx.repo),
188
+ `Health: ${ctx.repo.health.grade} (${ctx.repo.health.score}/100).`,
189
+ `Entries: ${ctx.repo.facts.entries.slice(0, 10).join(', ') || 'none detected'}.`,
190
+ `Hubs: ${ctx.repo.facts.hubs.slice(0, 10).map((hub) => hub.path).join(', ') || 'none detected'}.`,
191
+ 'Search matches:',
192
+ ...(hits.results || []).map((hit) => `${hit.path}${hit.line ? ':' + hit.line : ''} ${hit.snippet || ''}`),
193
+ ];
194
+ return '\n AI answer\n' + wrapText(await askModel(question, lines.join('\n'), config), ' ');
195
+ },
196
+ };
197
+ const rl = readline.createInterface({
198
+ input: process.stdin,
199
+ output: process.stdout,
200
+ prompt: promptFor(repo),
201
+ terminal: true,
202
+ historySize: 200,
203
+ // The completer closes over the *current* repo rather than the one captured
204
+ // here, so after a `cd` it completes paths in the new repository. Reading
205
+ // `ctx.repo` at completion time is the whole trick.
206
+ completer: (line) => completer(ctx.repo)(line),
207
+ });
208
+ let queue = Promise.resolve();
209
+ let closed = false;
210
+ let interrupts = 0;
211
+ let onResize = null;
212
+ // One poisoned promise must not end the session. `handleLine` catches its own
213
+ // errors, but anything thrown outside it — a prompt write to a closed stream,
214
+ // an error in a command's argument handling — would otherwise reject this
215
+ // chain and silently swallow every command typed afterwards. The session would
216
+ // look alive and do nothing, which is the worst failure mode a REPL has.
217
+ rl.on('line', (line) => {
218
+ queue = queue
219
+ .then(() => handleLine(ctx, line, rl, out, err))
220
+ .catch((e) => {
221
+ err(' ' + bad((e?.message || String(e))));
222
+ if (!closed) {
223
+ try {
224
+ rl.setPrompt(promptFor(ctx.repo));
225
+ rl.prompt();
226
+ }
227
+ catch {
228
+ // The stream is gone; the close handler finishes the session.
229
+ }
230
+ }
231
+ });
232
+ });
233
+ // Ctrl-D on an empty line is the universal "I'm done". On a line with text,
234
+ // readline handles it itself; this only sees the empty-line case.
235
+ //
236
+ // Closing does NOT end the session. A piped or fast-typed sequence of commands
237
+ // can already be queued when the last line arrives, and resolving here would
238
+ // throw those away mid-flight — which is exactly what happens to `tour` when
239
+ // its input is followed immediately by `exit`. The exit waits on the queue.
240
+ rl.on('close', () => {
241
+ closed = true;
242
+ agentAbort?.abort();
243
+ // The listener is removed on every exit path, including the interval one
244
+ // below, so a session that ends by any route leaves stdout as it found it.
245
+ if (onResize)
246
+ process.stdout.off('resize', onResize);
247
+ });
248
+ // Ctrl-C twice leaves. Once clears the line, which is what readline already
249
+ // does, and matches every other REPL people use.
250
+ rl.on('SIGINT', () => {
251
+ if (closed)
252
+ return;
253
+ if (agentAbort) {
254
+ agentAbort.abort();
255
+ out(dim('\n Cancelling agent…'));
256
+ return;
257
+ }
258
+ if (ctx.picker) {
259
+ ctx.picker = null;
260
+ out(dim('\n Selection cancelled.'));
156
261
  rl.setPrompt(promptFor(ctx.repo));
157
262
  rl.prompt();
158
- } catch {
159
- // The stream is gone; the close handler finishes the session.
160
- }
263
+ return;
161
264
  }
162
- });
163
- });
164
-
165
- // Ctrl-D on an empty line is the universal "I'm done". On a line with text,
166
- // readline handles it itself; this only sees the empty-line case.
167
- //
168
- // Closing does NOT end the session. A piped or fast-typed sequence of commands
169
- // can already be queued when the last line arrives, and resolving here would
170
- // throw those away mid-flight — which is exactly what happens to `tour` when
171
- // its input is followed immediately by `exit`. The exit waits on the queue.
172
- rl.on('close', () => {
173
- closed = true;
174
- // The listener is removed on every exit path, including the interval one
175
- // below, so a session that ends by any route leaves stdout as it found it.
176
- if (onResize) process.stdout.off('resize', onResize);
177
- });
178
-
179
- // Ctrl-C twice leaves. Once clears the line, which is what readline already
180
- // does, and matches every other REPL people use.
181
- rl.on('SIGINT', () => {
182
- if (closed) return;
183
- interrupts++;
184
- if (interrupts >= 2) {
185
- rl.close();
186
- return;
187
- }
188
- out(dim('\n Ctrl-C again to leave.'));
189
- rl.setPrompt(promptFor(ctx.repo));
190
- rl.prompt();
191
- });
192
-
193
- // A resize redraws rather than leaving the prompt stranded mid-wrap.
194
- onResize = () => {
195
- if (!closed) rl.write(null, { ctrl: true, name: 'l' });
196
- };
197
- process.stdout.on('resize', onResize);
198
-
199
- queue = queue.then(() => rl.prompt());
200
-
201
- return new Promise((resolve) => {
202
- const poll = setInterval(() => {
203
- if (!closed) return;
204
- clearInterval(poll);
205
- // Drain whatever is still running, then say goodbye. A command that throws
206
- // has already been caught in `handleLine`, so this cannot reject.
207
- queue.then(() => {
208
- out('');
209
- out(dim(' bye.'));
210
- // A clone this session made is a temp directory, and the session is the
211
- // only thing that knows about it. Removing it last — after the last
212
- // command has finished reading files out of it — is the only ordering
213
- // that cannot pull the ground out from under a command still running.
214
- closeRemote(ctx.repo).catch(() => {});
215
- resolve(0);
216
- });
217
- }, 20);
218
- });
265
+ interrupts++;
266
+ if (interrupts >= 2) {
267
+ rl.close();
268
+ return;
269
+ }
270
+ out(dim('\n Ctrl-C again to leave.'));
271
+ rl.setPrompt(promptFor(ctx.repo));
272
+ rl.prompt();
273
+ });
274
+ // A resize redraws rather than leaving the prompt stranded mid-wrap.
275
+ onResize = () => {
276
+ if (!closed)
277
+ rl.write(null, { ctrl: true, name: 'l' });
278
+ };
279
+ process.stdout.on('resize', onResize);
280
+ queue = queue.then(() => rl.prompt());
281
+ return new Promise((resolve) => {
282
+ const poll = setInterval(() => {
283
+ if (!closed)
284
+ return;
285
+ clearInterval(poll);
286
+ // Drain whatever is still running, then say goodbye. A command that throws
287
+ // has already been caught in `handleLine`, so this cannot reject.
288
+ queue.then(() => {
289
+ out('');
290
+ out(dim(' bye.'));
291
+ // A clone this session made is a temp directory, and the session is the
292
+ // only thing that knows about it. Removing it last — after the last
293
+ // command has finished reading files out of it — is the only ordering
294
+ // that cannot pull the ground out from under a command still running.
295
+ closeRemote(ctx.repo).catch((..._args) => { });
296
+ resolve(0);
297
+ });
298
+ }, 20);
299
+ });
219
300
  }
220
-
221
301
  function promptFor(repo) {
222
- return paint(' ', 'cyan') + bold(repo.name.slice(0, 24)) + paint(' > ', 'gray');
302
+ return paint(' ', 'cyan') + bold(repo.name.slice(0, 24)) + paint(' > ', 'gray');
223
303
  }
224
-
225
304
  async function handleLine(ctx, line, rl, out, err) {
226
- const words = tokenize(line);
227
- if (!words.length) {
228
- rl.prompt();
229
- return;
230
- }
231
- const [name, ...args] = words;
232
-
233
- // `!cmd` runs a shell command from inside the session and prints its output.
234
- // It is the only way out to a shell, which is the point: the set of things
235
- // that can happen here stays small enough to remember.
236
- if (name.startsWith('!') && name.length > 1) {
237
- const result = await shellEscape(line.replace(/^!\s*/, ''), ctx.repo.root);
238
- if (result) out(result);
239
- rl.setPrompt(promptFor(ctx.repo));
240
- rl.prompt();
241
- return;
242
- }
243
-
244
- const cmd = lookup(name);
245
-
246
- if (!cmd) {
247
- // The nearest command by edit distance is almost always what was meant, and
248
- // a one-line "did you mean" beats a paragraph about `help`.
249
- const near = nearest(name);
250
- err(' ' + bad('Unknown command: ' + name) + (near ? dim(' did you mean `' + near + '`?') : dim(' try `help`')));
251
- rl.prompt();
252
- return;
253
- }
254
-
255
- try {
256
- const result = await cmd.run(ctx, args);
257
- if (result === EXIT) {
258
- rl.close();
259
- return;
305
+ if (ctx.picker) {
306
+ const result = await ctx.picker.choose(line);
307
+ if (result.done) {
308
+ ctx.picker = null;
309
+ if (result.target) {
310
+ try {
311
+ out(await reload(ctx, result.target));
312
+ }
313
+ catch (e) {
314
+ err(' ' + bad(e.message || String(e)));
315
+ }
316
+ }
317
+ else if (result.message)
318
+ out(dim(result.message));
319
+ }
320
+ else if (result.message)
321
+ out(result.message);
322
+ rl.setPrompt(ctx.picker ? ctx.picker.prompt : promptFor(ctx.repo));
323
+ rl.prompt();
324
+ return;
325
+ }
326
+ const words = tokenize(line);
327
+ if (!words.length) {
328
+ rl.prompt();
329
+ return;
330
+ }
331
+ const [name, ...args] = words;
332
+ // `!cmd` runs a shell command from inside the session and prints its output.
333
+ // It is the only way out to a shell, which is the point: the set of things
334
+ // that can happen here stays small enough to remember.
335
+ if (name.startsWith('!') && name.length > 1) {
336
+ const result = await shellEscape(line.replace(/^!\s*/, ''), ctx.repo.root);
337
+ if (result)
338
+ out(result);
339
+ rl.setPrompt(promptFor(ctx.repo));
340
+ rl.prompt();
341
+ return;
342
+ }
343
+ const cmd = lookup(name);
344
+ if (!cmd) {
345
+ // The nearest command by edit distance is almost always what was meant, and
346
+ // a one-line "did you mean" beats a paragraph about `help`.
347
+ const near = nearest(name);
348
+ err(' ' + bad('Unknown command: ' + name) + (near ? dim(' did you mean `' + near + '`?') : dim(' try `help`')));
349
+ rl.prompt();
350
+ return;
351
+ }
352
+ try {
353
+ const result = await cmd.run(ctx, args);
354
+ if (result === EXIT) {
355
+ rl.close();
356
+ return;
357
+ }
358
+ if (result === CLEAR) {
359
+ out('\x1b[2J\x1b[3J\x1b[H');
360
+ }
361
+ else if (result) {
362
+ out(result);
363
+ }
260
364
  }
261
- if (result === CLEAR) {
262
- out('\x1b[2J\x1b[3J\x1b[H');
263
- } else if (result) {
264
- out(result);
365
+ catch (e) {
366
+ err(' ' + bad((e.message || String(e))));
265
367
  }
266
- } catch (e) {
267
- err(' ' + bad((e.message || String(e))));
268
- }
269
- // The prompt carries the repo name, and `cd` can change which repo that is.
270
- // Re-reading it after every command is cheaper than tracking which commands
271
- // swap the repo, and it cannot go stale.
272
- rl.setPrompt(promptFor(ctx.repo));
273
- rl.prompt();
368
+ // The prompt carries the repo name, and `cd` can change which repo that is.
369
+ // Re-reading it after every command is cheaper than tracking which commands
370
+ // swap the repo, and it cannot go stale.
371
+ rl.setPrompt(ctx.picker ? ctx.picker.prompt : promptFor(ctx.repo));
372
+ rl.prompt();
274
373
  }
275
-
276
374
  // Swap the loaded repo. Used by `cd` and `rescan`; the scan is the slow part,
277
375
  // so the new name reaches the prompt only after it succeeds.
278
376
  async function reload(ctx, where) {
279
- const target = String(where || '').trim();
280
- if (!target) {
281
- return ' cd needs a folder or a URL — `cd ../other-repo`, `cd https://github.com/org/repo`.';
282
- }
283
-
284
- // `rescan` re-reads the folder the session is already in. Re-cloning the URL
285
- // to get the same bytes back would be slow and would change the temp
286
- // directory out from under the session, so a target that resolves to the
287
- // current root takes the local path even when the repo remembers a URL.
288
- const reloadingCurrent = !isGitUrl(target) && path.resolve(expandHome(target)) === path.resolve(ctx.repo.root);
289
- const previous = ctx.repo;
290
- const next = reloadingCurrent
291
- ? await openRepo(previous.root)
292
- : await openRepoOrClone(target, { onProgress: () => {} });
293
-
294
- // A reload of the current folder produces a repo that has never heard of the
295
- // URL it was cloned from: `openRepo` reads a directory, and a directory does
296
- // not know where it came from. Carrying the three fields across is what keeps
297
- // `rescan` from silently demoting a clone to a nameless temp folder — the
298
- // prompt, `about` and `github` all read them.
299
- if (reloadingCurrent) {
300
- next.gitUrl = previous.gitUrl;
301
- next.cloneDir = previous.cloneDir;
302
- next.tempId = previous.tempId;
303
- if (previous.name !== next.name && !previous.cloneDir) next.name = previous.name;
304
- }
305
-
306
- // The old clone is only dropped once the new one has loaded. Doing it the
307
- // other way round means a typo in a URL leaves you with nothing loaded *and*
308
- // the repo you were reading deleted from under you.
309
- if (!reloadingCurrent) await closeRemote(previous);
310
- ctx.repo = next;
311
- return '\n' + overview(next);
377
+ const target = String(where || '').trim();
378
+ if (!target) {
379
+ return ' cd needs a folder or a URL — `cd ../other-repo`, `cd https://github.com/org/repo`.';
380
+ }
381
+ // `rescan` re-reads the folder the session is already in. Re-cloning the URL
382
+ // to get the same bytes back would be slow and would change the temp
383
+ // directory out from under the session, so a target that resolves to the
384
+ // current root takes the local path even when the repo remembers a URL.
385
+ const reloadingCurrent = !isGitUrl(target) && path.resolve(expandHome(target)) === path.resolve(ctx.repo.root);
386
+ const previous = ctx.repo;
387
+ const options = scanOptionsFromFlags(ctx.flags || {});
388
+ const next = reloadingCurrent
389
+ ? await openRepo(previous.root, options)
390
+ : await openRepoOrClone(target, options);
391
+ // A reload of the current folder produces a repo that has never heard of the
392
+ // URL it was cloned from: `openRepo` reads a directory, and a directory does
393
+ // not know where it came from. Carrying the three fields across is what keeps
394
+ // `rescan` from silently demoting a clone to a nameless temp folder — the
395
+ // prompt, `about` and `github` all read them.
396
+ if (reloadingCurrent) {
397
+ next.gitUrl = previous.gitUrl;
398
+ next.cloneDir = previous.cloneDir;
399
+ next.tempId = previous.tempId;
400
+ if (previous.name !== next.name && !previous.cloneDir)
401
+ next.name = previous.name;
402
+ }
403
+ // The old clone is only dropped once the new one has loaded. Doing it the
404
+ // other way round means a typo in a URL leaves you with nothing loaded *and*
405
+ // the repo you were reading deleted from under you.
406
+ if (!reloadingCurrent)
407
+ await closeRemote(previous);
408
+ ctx.repo = next;
409
+ return '\n' + overview(next);
312
410
  }
313
-
314
411
  // Ask GitHub about the loaded repo and print the answer. Network failures are
315
412
  // the expected case, not the exception — this is a command someone types on a
316
413
  // plane — so every one of them comes back as a line of text.
317
414
  async function askGithub(ctx) {
318
- const url = await remoteUrlFor(ctx.repo);
319
- if (!url) {
320
- return githubView(ctx.repo, { ok: false, reason: 'This folder has no GitHub remote — there is nothing to ask about.' });
321
- }
322
- return githubView(ctx.repo, await fetchRepoFacts(url));
415
+ const url = await remoteUrlFor(ctx.repo);
416
+ if (!url) {
417
+ return githubView(ctx.repo, { ok: false, reason: 'This folder has no GitHub remote — there is nothing to ask about.' });
418
+ }
419
+ return githubView(ctx.repo, await fetchRepoFacts(url));
323
420
  }
324
-
325
421
  // The bridge between the two surfaces. If the server is already up this just
326
422
  // prints where it is; if not, it starts it detached, so the person keeps their
327
423
  // session. The URL is the same one `onboarder start` would print, because it
328
424
  // comes from the same `serverUrls` the CLI and the banner use.
329
- async function startWeb(ctx) {
330
- const file = ctx.flags.config || configPath();
331
- const settings = await readSettings(file).catch(() => null);
332
- const urls = serverUrls(settings || undefined);
333
- const recorded = readPidFile(file);
334
-
335
- if (recorded && pidIsAlive(recorded)) {
336
- return [' ' + ok('Already running.') + dim(` PID ${recorded}`), ' ' + cyan(urls.local)].join('\n');
337
- }
338
-
339
- const { runStartBackground } = await import('../commands.js');
340
- const code = await runStartBackground({
341
- // `nonInteractive` is not optional here. With no config on disk,
342
- // `runStartBackground` hands off to `runSetup`, which opens its own readline
343
- // on the same stdin this session is already reading — the wizard and the
344
- // explorer would then compete for keystrokes, and the explorer could process
345
- // a wizard answer as a command. Inside a session the server either starts
346
- // from the config that exists or reports that there is none; the person can
347
- // run `onboarder setup` deliberately if they want the wizard.
348
- flags: { ...ctx.flags, json: true, nonInteractive: true },
349
- out: () => {},
350
- err: () => {},
351
- });
352
- if (code !== 0) return ' ' + bad('Could not start the web UI.') + dim(' Try `onboarder doctor`.');
353
- return [
354
- ' ' + ok('Web UI started in the background.'),
355
- ' ' + cyan(urls.local),
356
- dim(' onboarder logs -f to watch it · onboarder stop to shut it down'),
357
- ].join('\n');
425
+ export async function startWeb(ctx) {
426
+ const file = ctx.flags.config || configPath();
427
+ const settings = await readSettings(file).catch(() => null);
428
+ const urls = serverUrls(settings || undefined);
429
+ const recorded = readPidFile(file);
430
+ if (recorded && pidIsAlive(recorded)) {
431
+ return [' ' + ok('Already running.') + dim(` PID ${recorded}`), ' ' + cyan(urls.local)].join('\n');
432
+ }
433
+ const { runStartBackground } = await import('../commands.js');
434
+ const code = await runStartBackground({
435
+ // `nonInteractive` is not optional here. With no config on disk,
436
+ // `runStartBackground` hands off to `runSetup`, which opens its own readline
437
+ // on the same stdin this session is already reading — the wizard and the
438
+ // explorer would then compete for keystrokes, and the explorer could process
439
+ // a wizard answer as a command. Inside a session the server either starts
440
+ // from the config that exists or reports that there is none; the person can
441
+ // run `onboarder setup` deliberately if they want the wizard.
442
+ flags: { ...ctx.flags, json: true, nonInteractive: true },
443
+ out: (..._args) => { },
444
+ err: (..._args) => { },
445
+ });
446
+ if (code !== 0)
447
+ return ' ' + bad('Could not start the web UI.') + dim(' Try `onboarder doctor`.');
448
+ return [
449
+ ' ' + ok('Web UI started in the background.'),
450
+ ' ' + cyan(urls.local),
451
+ dim(' onboarder logs -f to watch it · onboarder stop to shut it down'),
452
+ ].join('\n');
358
453
  }
359
-
360
454
  // Cheap "did you mean": plain Levenshtein over the command names, with a
361
455
  // distance cap of 2 so a wildly misspelled word gets "try `help`" instead of a
362
456
  // confident wrong suggestion. A wrong suggestion is worse than none.
363
457
  function nearest(word) {
364
- const w = String(word).toLowerCase();
365
- let best = null;
366
- let bestScore = Infinity;
367
- for (const name of commandNames()) {
368
- const d = distance(w, name);
369
- if (d < bestScore) {
370
- bestScore = d;
371
- best = name;
458
+ const w = String(word).toLowerCase();
459
+ let best = null;
460
+ let bestScore = Infinity;
461
+ for (const name of commandNames()) {
462
+ const d = distance(w, name);
463
+ if (d < bestScore) {
464
+ bestScore = d;
465
+ best = name;
466
+ }
372
467
  }
373
- }
374
- return bestScore <= 2 ? best : null;
468
+ return bestScore <= 2 ? best : null;
375
469
  }
376
-
377
470
  function distance(a, b) {
378
- let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
379
- for (let i = 1; i <= a.length; i++) {
380
- const cur = [i];
381
- for (let j = 1; j <= b.length; j++) {
382
- cur[j] = Math.min(
383
- prev[j] + 1,
384
- cur[j - 1] + 1,
385
- prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1),
386
- );
471
+ let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
472
+ for (let i = 1; i <= a.length; i++) {
473
+ const cur = [i];
474
+ for (let j = 1; j <= b.length; j++) {
475
+ cur[j] = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
476
+ }
477
+ prev = cur;
387
478
  }
388
- prev = cur;
389
- }
390
- return prev[b.length];
479
+ return prev[b.length];
391
480
  }
481
+ //# sourceMappingURL=app.js.map