codebase-onboarder 0.6.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 +174 -46
  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 +321 -329
  8. package/cli/explorer/advanced.js.map +1 -0
  9. package/cli/explorer/app.d.ts +1 -0
  10. package/cli/explorer/app.js +384 -313
  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 +368 -302
  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 +42 -44
  23. package/cli/explorer/github.js.map +1 -0
  24. package/cli/explorer/graphs.d.ts +7 -0
  25. package/cli/explorer/graphs.js +90 -95
  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 +143 -144
  35. package/cli/explorer/session.js.map +1 -0
  36. package/cli/explorer/views.d.ts +19 -0
  37. package/cli/explorer/views.js +465 -482
  38. package/cli/explorer/views.js.map +1 -0
  39. package/cli/explorer/wrap.d.ts +1 -0
  40. package/cli/explorer/wrap.js +28 -44
  41. package/cli/explorer/wrap.js.map +1 -0
  42. package/cli/main.d.ts +1 -0
  43. package/cli/main.js +214 -161
  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 +35 -44
  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 +152 -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 +37 -38
  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 -64
  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 +41 -43
  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
@@ -9,297 +9,358 @@
9
9
  // `run(ctx, args)` returns a string to print, or a marker the app layer acts on
10
10
  // (`EXIT`, `CLEAR`). `args` is an array of already-parsed words, so quoting is
11
11
  // handled once, in the tokenizer, and every command sees the same shape.
12
-
13
12
  import * as V from './views.js';
14
13
  import * as A from './advanced.js';
15
- import { lineNumber } from './session.js';
14
+ import { lineNumber, resolveTarget, fileFacts } from './session.js';
16
15
  import { bold, cyan, dim, ok, fit, termWidth } from '../ui.js';
17
16
  import { wrapText } from './wrap.js';
17
+ import { formatSbom, formatWorkflows, formatAtlas, formatInspector } from './featureViews.js';
18
18
  import { execFile } from 'node:child_process';
19
19
  import { promisify } from 'node:util';
20
-
21
20
  const run = promisify(execFile);
22
-
23
21
  export const EXIT = Symbol('exit');
24
22
  export const CLEAR = Symbol('clear');
25
-
26
23
  export const COMMANDS = [
27
- {
28
- name: 'help', aliases: ['?'], group: 'basics',
29
- usage: 'help [command]', summary: 'This list, or everything about one command.',
30
- // The topic is forwarded. `help find` used to ignore its argument and print
31
- // the whole list, which reads as the command not working.
32
- run: (ctx, args) => ctx.help(args.join(' ')),
33
- },
34
- {
35
- name: 'map', aliases: ['overview', 'home'], group: 'basics',
36
- usage: 'map', summary: 'What this repo is, and where to start.',
37
- run: (ctx) => V.overview(ctx.repo),
38
- },
39
- {
40
- name: 'tour', aliases: ['start', 'onboarding'], group: 'basics',
41
- usage: 'tour', summary: 'The reading order a new teammate should follow.',
42
- run: (ctx) => V.tour(ctx.repo),
43
- },
44
- {
45
- name: 'explain', aliases: ['why', 'what'], group: 'basics',
46
- usage: 'explain [file|folder]', summary: 'This repo, or one file/folder, in prose. No AI key needed.',
47
- run: (ctx, args) => V.explain(ctx.repo, { target: args.join(' ') }),
48
- },
49
- {
50
- name: 'tree', aliases: ['ls', 'files'], group: 'navigate',
51
- usage: 'tree [folder] [depth]', summary: 'The file tree, with entries and hubs marked.',
52
- run: (ctx, args) => {
53
- // A lone number is the depth, not a folder called "2". `tree 3` is what
54
- // everyone types when they want to see more; making them spell
55
- // `tree . 3` would be pedantry in a tool built to be forgiving. `.` is the
56
- // root, so it must not be taken as a folder name either.
57
- const onlyDepth = args.length === 1 && /^\d+$/.test(args[0]);
58
- const sub = onlyDepth ? '' : (args[0] || '');
59
- return V.tree(ctx.repo, {
60
- sub: sub === '.' ? '' : sub,
61
- depth: onlyDepth ? Number(args[0]) : (Number(args[1]) || 2),
62
- });
63
- },
64
- },
65
- {
66
- name: 'find', aliases: ['search', 'grep'], group: 'navigate',
67
- usage: 'find <query>', summary: 'Search. Supports ext:js, -exclude, "phrases", /regex/.',
68
- run: (ctx, args) => V.find(ctx.repo, { query: args.join(' ') }),
69
- },
70
- {
71
- name: 'show', aliases: ['open', 'cat', 'read'], group: 'navigate',
72
- usage: 'show <file> [from] [count]', summary: 'Read a file. Name it loosely: `show logger.js` works.',
73
- run: (ctx, args) => V.show(ctx.repo, {
74
- target: args[0] || '',
75
- from: lineNumber(args[1], 0),
76
- count: lineNumber(args[2], 0),
77
- }),
78
- },
79
- {
80
- name: 'deps', aliases: ['connections'], group: 'navigate',
81
- usage: 'deps <file>', summary: 'What a file imports, and what imports it.',
82
- run: (ctx, args) => V.deps(ctx.repo, { target: args.join(' ') }),
83
- },
84
- {
85
- name: 'health', aliases: ['grade'], group: 'analyze',
86
- usage: 'health', summary: 'Health grade, riskiest files, debt.',
87
- run: (ctx) => V.health(ctx.repo),
88
- },
89
- {
90
- name: 'hubs', aliases: ['core'], group: 'analyze',
91
- usage: 'hubs', summary: 'The most depended-on files.',
92
- run: (ctx) => V.hubs(ctx.repo),
93
- },
94
- {
95
- name: 'layers', aliases: ['depth'], group: 'analyze',
96
- usage: 'layers', summary: 'Import depth, shallowest first.',
97
- run: (ctx) => V.layers(ctx.repo),
98
- },
99
- {
100
- name: 'patterns', aliases: ['architecture'], group: 'analyze',
101
- usage: 'patterns', summary: 'What the architecture looks like, in prose.',
102
- run: (ctx) => V.patterns(ctx.repo),
103
- },
104
- {
105
- name: 'stats', aliases: ['numbers'], group: 'analyze',
106
- usage: 'stats', summary: 'Languages, biggest folders and files, complexity.',
107
- run: (ctx) => V.stats(ctx.repo),
108
- },
109
- {
110
- name: 'security', aliases: ['audit'], group: 'analyze',
111
- usage: 'security', summary: 'Heuristic findings from the built-in rules.',
112
- run: (ctx) => V.security(ctx.repo),
113
- },
114
- {
115
- name: 'stack', aliases: ['packages'], group: 'analyze',
116
- usage: 'stack', summary: 'Declared dependencies and frameworks.',
117
- run: (ctx) => V.stack(ctx.repo),
118
- },
119
- {
120
- name: 'entry', aliases: ['entries'], group: 'analyze',
121
- usage: 'entry', summary: 'Recognized entry points and how far they reach.',
122
- run: (ctx) => V.entry(ctx.repo),
123
- },
124
- {
125
- name: 'externals', aliases: ['drift'], group: 'analyze',
126
- usage: 'externals', summary: 'External packages, plus dependency drift.',
127
- run: (ctx) => V.externals(ctx.repo),
128
- },
129
- {
130
- name: 'graph', aliases: ['tree-graph'], group: 'navigate',
131
- usage: 'graph <file> [depth]', summary: 'The dependency tree around a file, as arrows.',
132
- run: (ctx, args) => A.graph(ctx.repo, { target: args[0] || '', depth: Number(args[1]) || 2 }),
133
- },
134
- {
135
- name: 'blast', aliases: ['impact', 'radius'], group: 'navigate',
136
- usage: 'blast <file>', summary: 'What breaks if this file breaks, transitively.',
137
- run: (ctx, args) => A.blast(ctx.repo, { target: args.join(' ') }),
138
- },
139
- {
140
- name: 'symbols', aliases: ['outline', 'functions'], group: 'navigate',
141
- usage: 'symbols <file>', summary: 'Functions, classes and exports in a file.',
142
- run: (ctx, args) => A.symbols(ctx.repo, { target: args.join(' ') }),
143
- },
144
- {
145
- name: 'docs', aliases: ['document'], group: 'analyze',
146
- usage: 'docs [file|folder] | docs --write', summary: 'Prose docs for a file, or write ONBOARDER.md.',
147
- run: async (ctx, args) => {
148
- // `--write` is the one command here that touches the filesystem. It is
149
- // opt-in, explicit, and prints where it wrote — a map tool should never
150
- // leave a file behind just because someone asked what the docs say.
151
- if (args[0] === '--write') {
152
- const abs = await A.writeDocs(ctx.repo, args[1] || 'ONBOARDER.md');
153
- return ' ' + ok('Wrote ') + cyan(abs);
154
- }
155
- return A.docs(ctx.repo, { target: args.filter((a) => a !== '--write').join(' ') });
156
- },
157
- },
158
- {
159
- name: 'log', aliases: ['history', 'commits'], group: 'git',
160
- usage: 'log [count]', summary: 'Recent commits, and who wrote them.',
161
- run: (ctx, args) => A.log(ctx.repo, { limit: Number(args[0]) || 15 }),
162
- },
163
- {
164
- name: 'hotspots', aliases: ['churn'], group: 'git',
165
- usage: 'hotspots [count]', summary: 'Files that are both complex and frequently changed.',
166
- run: (ctx, args) => A.hotspots(ctx.repo, { limit: Number(args[0]) || 12 }),
167
- },
168
- {
169
- name: 'blame', aliases: ['authors'], group: 'git',
170
- usage: 'blame <file>', summary: 'Who wrote each line of a file.',
171
- run: (ctx, args) => A.blame(ctx.repo, { target: args.join(' ') }),
172
- },
173
- {
174
- name: 'coupling', aliases: ['matrix', 'heatmap'], group: 'analyze',
175
- usage: 'coupling', summary: 'Folder-to-folder import traffic, as a heat grid.',
176
- run: (ctx) => A.coupling(ctx.repo),
177
- },
178
- {
179
- name: 'clusters', aliases: ['communities', 'modules'], group: 'analyze',
180
- usage: 'clusters', summary: 'Groups of files that import each other more than the rest.',
181
- run: (ctx) => A.clusters(ctx.repo),
182
- },
183
- {
184
- name: 'diagram', aliases: ['mermaid'], group: 'analyze',
185
- usage: 'diagram [file]', summary: 'Mermaid source for the repo, or one file.',
186
- run: (ctx, args) => A.diagram(ctx.repo, { target: args.join(' ') }),
187
- },
188
- {
189
- name: 'layers-diagram', aliases: [], group: 'analyze',
190
- usage: 'layers-diagram', summary: 'Mermaid source for the layer stack.',
191
- run: (ctx) => A.layerDiagram(ctx.repo),
192
- },
193
- {
194
- name: 'risks', aliases: ['problems', 'smells'], group: 'analyze',
195
- usage: 'risks', summary: 'Cycles, orphans, dead exports, drift — in one list.',
196
- run: (ctx) => A.risks(ctx.repo),
197
- },
198
- {
199
- name: 'about', aliases: ['version'], group: 'session',
200
- usage: 'about', summary: 'Version, repo path, and what is indexed.',
201
- run: (ctx) => V.about(ctx.repo, ctx.version),
202
- },
203
- {
204
- name: 'rescan', aliases: ['reload'], group: 'session',
205
- usage: 'rescan', summary: 'Re-read the repo from disk.',
206
- run: (ctx) => ctx.rescan(),
207
- },
208
- {
209
- name: 'github', aliases: ['remote', 'repo'], group: 'session',
210
- usage: 'github', summary: "What GitHub says about this repo — stars, issues, license.",
211
- run: (ctx) => ctx.github(),
212
- },
213
- {
214
- name: 'cd', aliases: ['open-repo', 'use'], group: 'session',
215
- usage: 'cd <folder|url>', summary: 'Load another repository, or clone one by URL.',
216
- run: (ctx, args) => ctx.loadRepo(args.join(' ')),
217
- },
218
- {
219
- name: 'web', aliases: ['site', 'serve'], group: 'session',
220
- usage: 'web', summary: 'Start the web UI and print its URL.',
221
- run: (ctx) => ctx.web(),
222
- },
223
- {
224
- name: 'clear', aliases: ['cls'], group: 'session',
225
- usage: 'clear', summary: 'Clear the screen.',
226
- run: () => CLEAR,
227
- },
228
- {
229
- name: 'exit', aliases: ['quit', 'q'], group: 'session',
230
- usage: 'exit', summary: 'Leave. Ctrl-D does the same.',
231
- run: () => EXIT,
232
- },
24
+ {
25
+ name: 'help', aliases: ['?'], group: 'basics',
26
+ usage: 'help [command]', summary: 'This list, or everything about one command.',
27
+ // The topic is forwarded. `help find` used to ignore its argument and print
28
+ // the whole list, which reads as the command not working.
29
+ run: (ctx, args) => ctx.help(args.join(' ')),
30
+ },
31
+ {
32
+ name: 'map', aliases: ['overview', 'home'], group: 'basics',
33
+ usage: 'map', summary: 'What this repo is, and where to start.',
34
+ run: (ctx) => V.overview(ctx.repo),
35
+ },
36
+ {
37
+ name: 'tour', aliases: ['start', 'onboarding'], group: 'basics',
38
+ usage: 'tour', summary: 'The reading order a new teammate should follow.',
39
+ run: (ctx) => V.tour(ctx.repo),
40
+ },
41
+ {
42
+ name: 'explain', aliases: ['why', 'what'], group: 'basics',
43
+ usage: 'explain [file|folder]', summary: 'This repo, or one file/folder, in prose. No AI key needed.',
44
+ run: (ctx, args) => V.explain(ctx.repo, { target: args.join(' ') }),
45
+ },
46
+ {
47
+ name: 'tree', aliases: ['ls', 'files'], group: 'navigate',
48
+ usage: 'tree [folder] [depth]', summary: 'The file tree, with entries and hubs marked.',
49
+ run: (ctx, args) => {
50
+ // A lone number is the depth, not a folder called "2". `tree 3` is what
51
+ // everyone types when they want to see more; making them spell
52
+ // `tree . 3` would be pedantry in a tool built to be forgiving. `.` is the
53
+ // root, so it must not be taken as a folder name either.
54
+ const onlyDepth = args.length === 1 && /^\d+$/.test(args[0]);
55
+ const sub = onlyDepth ? '' : (args[0] || '');
56
+ return V.tree(ctx.repo, {
57
+ sub: sub === '.' ? '' : sub,
58
+ depth: onlyDepth ? Number(args[0]) : (Number(args[1]) || 2),
59
+ });
60
+ },
61
+ },
62
+ {
63
+ name: 'find', aliases: ['search', 'grep'], group: 'navigate',
64
+ usage: 'find <query>', summary: 'Search. Supports ext:js, -exclude, "phrases", /regex/.',
65
+ run: (ctx, args) => V.find(ctx.repo, { query: args.join(' ') }),
66
+ },
67
+ {
68
+ name: 'show', aliases: ['open', 'cat', 'read', 'code'], group: 'navigate',
69
+ usage: 'show <file> [from] [count]', summary: 'Read a file. Name it loosely: `show logger.js` works.',
70
+ run: (ctx, args) => V.show(ctx.repo, {
71
+ target: args[0] || '',
72
+ from: lineNumber(args[1], 0),
73
+ count: lineNumber(args[2], 0),
74
+ }),
75
+ },
76
+ {
77
+ name: 'deps', aliases: ['connections'], group: 'navigate',
78
+ usage: 'deps <file>', summary: 'What a file imports, and what imports it.',
79
+ run: (ctx, args) => V.deps(ctx.repo, { target: args.join(' ') }),
80
+ },
81
+ {
82
+ name: 'inspect', aliases: ['detail'], group: 'navigate',
83
+ usage: 'inspect <file>', summary: 'One file’s role, links, exports, and findings.',
84
+ run: (ctx, args) => {
85
+ const target = args.join(' ');
86
+ if (!target)
87
+ return ' Name a file: inspect path/to/file.js';
88
+ const found = resolveTarget(ctx.repo, target);
89
+ if (found.error)
90
+ return V.explain(ctx.repo, { target });
91
+ if (found.folder)
92
+ return V.explain(ctx.repo, { target });
93
+ const file = found.file;
94
+ return formatInspector({
95
+ path: file.path,
96
+ role: fileFacts(ctx.repo, file).role,
97
+ loc: file.loc || 0,
98
+ complexity: file.complexity || 0,
99
+ risk: ctx.repo.health.perFile.find((item) => item.path === file.path)?.risk || 0,
100
+ imports: ctx.repo.facts.importsOf[file.path] || [],
101
+ importers: ctx.repo.facts.importers[file.path] || [],
102
+ exports: file.exports || [],
103
+ findings: file.findings || [],
104
+ });
105
+ },
106
+ },
107
+ {
108
+ name: 'health', aliases: ['grade'], group: 'analyze',
109
+ usage: 'health', summary: 'Health grade, riskiest files, debt.',
110
+ run: (ctx) => V.health(ctx.repo),
111
+ },
112
+ {
113
+ name: 'hubs', aliases: ['core'], group: 'analyze',
114
+ usage: 'hubs', summary: 'The most depended-on files.',
115
+ run: (ctx) => V.hubs(ctx.repo),
116
+ },
117
+ {
118
+ name: 'layers', aliases: ['depth'], group: 'analyze',
119
+ usage: 'layers', summary: 'Import depth, shallowest first.',
120
+ run: (ctx) => V.layers(ctx.repo),
121
+ },
122
+ {
123
+ name: 'patterns', aliases: ['architecture'], group: 'analyze',
124
+ usage: 'patterns', summary: 'What the architecture looks like, in prose.',
125
+ run: (ctx) => V.patterns(ctx.repo),
126
+ },
127
+ {
128
+ name: 'stats', aliases: ['numbers'], group: 'analyze',
129
+ usage: 'stats', summary: 'Languages, biggest folders and files, complexity.',
130
+ run: (ctx) => V.stats(ctx.repo),
131
+ },
132
+ {
133
+ name: 'security', aliases: ['audit'], group: 'analyze',
134
+ usage: 'security', summary: 'Heuristic findings from the built-in rules.',
135
+ run: (ctx) => V.security(ctx.repo),
136
+ },
137
+ {
138
+ name: 'stack', aliases: ['packages', 'services'], group: 'analyze',
139
+ usage: 'stack', summary: 'Declared dependencies and frameworks.',
140
+ run: (ctx) => V.stack(ctx.repo),
141
+ },
142
+ {
143
+ name: 'entry', aliases: ['entries'], group: 'analyze',
144
+ usage: 'entry', summary: 'Recognized entry points and how far they reach.',
145
+ run: (ctx) => V.entry(ctx.repo),
146
+ },
147
+ {
148
+ name: 'externals', aliases: ['drift'], group: 'analyze',
149
+ usage: 'externals', summary: 'External packages, plus dependency drift.',
150
+ run: (ctx) => V.externals(ctx.repo),
151
+ },
152
+ {
153
+ name: 'graph', aliases: ['tree-graph'], group: 'navigate',
154
+ usage: 'graph <file> [depth]', summary: 'The dependency tree around a file, as arrows.',
155
+ run: (ctx, args) => A.graph(ctx.repo, { target: args[0] || '', depth: Number(args[1]) || 2 }),
156
+ },
157
+ {
158
+ name: 'blast', aliases: ['impact', 'radius'], group: 'navigate',
159
+ usage: 'blast <file>', summary: 'What breaks if this file breaks, transitively.',
160
+ run: (ctx, args) => A.blast(ctx.repo, { target: args.join(' ') }),
161
+ },
162
+ {
163
+ name: 'symbols', aliases: ['outline', 'functions'], group: 'navigate',
164
+ usage: 'symbols <file>', summary: 'Functions, classes and exports in a file.',
165
+ run: (ctx, args) => A.symbols(ctx.repo, { target: args.join(' ') }),
166
+ },
167
+ {
168
+ name: 'docs', aliases: ['document'], group: 'analyze',
169
+ usage: 'docs [file|folder] | docs --write', summary: 'Prose docs for a file, or write ONBOARDER.md.',
170
+ run: async (ctx, args) => {
171
+ // `--write` is the one command here that touches the filesystem. It is
172
+ // opt-in, explicit, and prints where it wrote — a map tool should never
173
+ // leave a file behind just because someone asked what the docs say.
174
+ if (args[0] === '--write') {
175
+ const abs = await A.writeDocs(ctx.repo, args[1] || 'ONBOARDER.md');
176
+ return ' ' + ok('Wrote ') + cyan(abs);
177
+ }
178
+ return A.docs(ctx.repo, { target: args.filter((a) => a !== '--write').join(' ') });
179
+ },
180
+ },
181
+ {
182
+ name: 'log', aliases: ['history', 'commits'], group: 'git',
183
+ usage: 'log [count]', summary: 'Recent commits, and who wrote them.',
184
+ run: (ctx, args) => A.log(ctx.repo, { limit: Number(args[0]) || 15 }),
185
+ },
186
+ {
187
+ name: 'hotspots', aliases: ['churn'], group: 'git',
188
+ usage: 'hotspots [count]', summary: 'Files that are both complex and frequently changed.',
189
+ run: (ctx, args) => A.hotspots(ctx.repo, { limit: Number(args[0]) || 12 }),
190
+ },
191
+ {
192
+ name: 'blame', aliases: ['authors'], group: 'git',
193
+ usage: 'blame <file>', summary: 'Who wrote each line of a file.',
194
+ run: (ctx, args) => A.blame(ctx.repo, { target: args.join(' ') }),
195
+ },
196
+ {
197
+ name: 'coupling', aliases: ['matrix', 'heatmap'], group: 'analyze',
198
+ usage: 'coupling', summary: 'Folder-to-folder import traffic, as a heat grid.',
199
+ run: (ctx) => A.coupling(ctx.repo),
200
+ },
201
+ {
202
+ name: 'clusters', aliases: ['communities', 'modules'], group: 'analyze',
203
+ usage: 'clusters', summary: 'Groups of files that import each other more than the rest.',
204
+ run: (ctx) => A.clusters(ctx.repo),
205
+ },
206
+ {
207
+ name: 'diagram', aliases: ['mermaid'], group: 'analyze',
208
+ usage: 'diagram [file]', summary: 'Mermaid source for the repo, or one file.',
209
+ run: (ctx, args) => A.diagram(ctx.repo, { target: args.join(' ') }),
210
+ },
211
+ {
212
+ name: 'layers-diagram', aliases: [], group: 'analyze',
213
+ usage: 'layers-diagram', summary: 'Mermaid source for the layer stack.',
214
+ run: (ctx) => A.layerDiagram(ctx.repo),
215
+ },
216
+ {
217
+ name: 'risks', aliases: ['problems', 'smells', 'insights'], group: 'analyze',
218
+ usage: 'risks', summary: 'Cycles, orphans, dead exports, drift — in one list.',
219
+ run: (ctx) => A.risks(ctx.repo),
220
+ },
221
+ {
222
+ name: 'workflows', aliases: ['ci', 'pipelines'], group: 'analyze',
223
+ usage: 'workflows', summary: 'GitHub Actions triggers, jobs, and steps.',
224
+ run: (ctx) => formatWorkflows(ctx.repo.scan.workflows || []),
225
+ },
226
+ {
227
+ name: 'atlas', aliases: ['diagrams'], group: 'analyze',
228
+ usage: 'atlas', summary: 'An index of useful repository and file diagrams.',
229
+ run: (ctx) => formatAtlas(ctx.repo.facts.entries, ctx.repo.facts.hubs, ctx.repo.scan.folders),
230
+ },
231
+ {
232
+ name: 'sbom', aliases: ['licenses', 'inventory'], group: 'analyze',
233
+ usage: 'sbom [filter]', summary: 'Declared dependencies and inferred license inventory.',
234
+ run: (ctx, args) => formatSbom(ctx.repo.scan.licenseReport, args.join(' ')),
235
+ },
236
+ {
237
+ name: 'diff', aliases: ['changes'], group: 'git',
238
+ usage: 'diff [base] [head] [file]', summary: 'Git changes, patch, and dependent-file impact.',
239
+ run: (ctx, args) => ctx.diff(args[0] || 'HEAD', args[1] || '', args[2] || ''),
240
+ },
241
+ {
242
+ name: 'engines', aliases: ['analyzers'], group: 'analyze',
243
+ usage: 'engines', summary: 'Show available external analyzers and how to install them.',
244
+ run: (ctx) => ctx.engines(),
245
+ },
246
+ {
247
+ name: 'deep', aliases: ['deep-analysis'], group: 'analyze',
248
+ usage: 'deep <engine|all>', summary: 'Run an optional analyzer and show its findings.',
249
+ run: (ctx, args) => args[0] ? ctx.deep(args[0]) : ctx.engines(),
250
+ },
251
+ {
252
+ name: 'ask', aliases: ['ai'], group: 'basics',
253
+ usage: 'ask <question>', summary: 'Ask an optional OpenAI-compatible model about this repo.',
254
+ run: (ctx, args) => ctx.ask(args.join(' ')),
255
+ },
256
+ {
257
+ name: 'about', aliases: ['version'], group: 'session',
258
+ usage: 'about', summary: 'Version, repo path, and what is indexed.',
259
+ run: (ctx) => V.about(ctx.repo, ctx.version),
260
+ },
261
+ {
262
+ name: 'rescan', aliases: ['reload'], group: 'session',
263
+ usage: 'rescan', summary: 'Re-read the repo from disk.',
264
+ run: (ctx) => ctx.rescan(),
265
+ },
266
+ {
267
+ name: 'github', aliases: ['remote', 'repo'], group: 'session',
268
+ usage: 'github', summary: "What GitHub says about this repo — stars, issues, license.",
269
+ run: (ctx) => ctx.github(),
270
+ },
271
+ {
272
+ name: 'cd', aliases: ['open-repo', 'use'], group: 'session',
273
+ usage: 'cd [folder|url]', summary: 'Choose a folder, or load one by path or Git URL.',
274
+ run: (ctx, args) => args.length ? ctx.loadRepo(args.join(' ')) : ctx.selectSource(),
275
+ },
276
+ {
277
+ name: 'pick', aliases: ['browse'], group: 'session',
278
+ usage: 'pick', summary: 'Browse device folders or paste a Git URL.',
279
+ run: (ctx) => ctx.selectSource(),
280
+ },
281
+ {
282
+ name: 'web', aliases: ['site', 'serve'], group: 'session',
283
+ usage: 'web', summary: 'Start the web UI and print its URL.',
284
+ run: (ctx) => ctx.web(),
285
+ },
286
+ {
287
+ name: 'clear', aliases: ['cls'], group: 'session',
288
+ usage: 'clear', summary: 'Clear the screen.',
289
+ run: () => CLEAR,
290
+ },
291
+ {
292
+ name: 'exit', aliases: ['quit', 'q'], group: 'session',
293
+ usage: 'exit', summary: 'Leave. Ctrl-D does the same.',
294
+ run: () => EXIT,
295
+ },
233
296
  ];
234
-
235
297
  // One lookup for every spelling a person might type, built once at import.
236
298
  const BY_NAME = new Map();
237
299
  for (const cmd of COMMANDS) {
238
- BY_NAME.set(cmd.name, cmd);
239
- for (const a of cmd.aliases) BY_NAME.set(a, cmd);
300
+ BY_NAME.set(cmd.name, cmd);
301
+ for (const a of cmd.aliases)
302
+ BY_NAME.set(a, cmd);
240
303
  }
241
-
242
304
  export function lookup(word) {
243
- return BY_NAME.get(String(word || '').toLowerCase());
305
+ return BY_NAME.get(String(word || '').toLowerCase());
244
306
  }
245
-
246
307
  // Every canonical name, for "did you mean" matching. Aliases are deliberately
247
308
  // excluded: suggesting `open` when someone typed `sho` is less useful than
248
309
  // suggesting `show`, which is the word they were reaching for.
249
310
  export function commandNames() {
250
- return COMMANDS.map((c) => c.name);
311
+ return COMMANDS.map((c) => c.name);
251
312
  }
252
-
253
313
  // `help <command>` answers about one command; bare `help` lists them, grouped so
254
314
  // the shape of the tool is visible rather than alphabetical. Every row is
255
315
  // fitted, because a long summary on a narrow terminal used to wrap into the
256
316
  // next row and make the list unreadable.
257
317
  export function helpText(ctx, topic = '') {
258
- const w = termWidth();
259
- if (topic) {
260
- const cmd = lookup(topic);
261
- if (!cmd) return fit(` No command called "${topic}". Try \`help\`.`, Math.max(10, w - 2));
262
- const also = cmd.aliases.length ? ` (also: ${cmd.aliases.join(', ')})` : '';
263
- return [
264
- fit(' ' + cmd.usage + also, Math.max(10, w - 2)),
265
- wrapText(cmd.summary, ' '),
266
- ].join('\n');
267
- }
268
- const groups = new Map();
269
- for (const cmd of COMMANDS) {
270
- if (!groups.has(cmd.group)) groups.set(cmd.group, []);
271
- groups.get(cmd.group).push(cmd);
272
- }
273
- // Two cells of indent, two of gap, and the summary gets whatever is left. The
274
- // usage column shrinks with the terminal rather than pushing the text off it.
275
- const longest = Math.max(...COMMANDS.map((c) => c.usage.length));
276
- const usageRoom = Math.max(8, Math.min(longest, Math.floor(w * 0.4)));
277
- const out = [];
278
- for (const [group, list] of groups) {
279
- out.push(fit(' ' + group.toUpperCase(), Math.max(10, w - 2)));
280
- for (const c of list) {
281
- const left = ' ' + fit(c.usage, usageRoom);
282
- const room = w - left.length - 2;
283
- out.push(room > 8 ? left + ' ' + fit(c.summary, room, { tail: false }) : left);
318
+ const w = termWidth();
319
+ if (topic) {
320
+ const cmd = lookup(topic);
321
+ if (!cmd)
322
+ return fit(` No command called "${topic}". Try \`help\`.`, Math.max(10, w - 2));
323
+ const also = cmd.aliases.length ? ` (also: ${cmd.aliases.join(', ')})` : '';
324
+ return [
325
+ fit(' ' + cmd.usage + also, Math.max(10, w - 2)),
326
+ wrapText(cmd.summary, ' '),
327
+ ].join('\n');
284
328
  }
285
- }
286
- out.push('');
287
- out.push(fit(' ' + (ctx?.repo ? ctx.repo.name : 'onboarder')
288
- + ' · Ctrl-D or `exit` to leave · Ctrl-C twice to quit', Math.max(10, w - 2)));
289
- return out.join('\n');
329
+ const groups = new Map();
330
+ for (const cmd of COMMANDS) {
331
+ if (!groups.has(cmd.group))
332
+ groups.set(cmd.group, []);
333
+ groups.get(cmd.group).push(cmd);
334
+ }
335
+ // Two cells of indent, two of gap, and the summary gets whatever is left. The
336
+ // usage column shrinks with the terminal rather than pushing the text off it.
337
+ const longest = Math.max(...COMMANDS.map((c) => c.usage.length));
338
+ const usageRoom = Math.max(8, Math.min(longest, Math.floor(w * 0.4)));
339
+ const out = [];
340
+ for (const [group, list] of groups) {
341
+ out.push(fit(' ' + group.toUpperCase(), Math.max(10, w - 2)));
342
+ for (const c of list) {
343
+ const left = ' ' + fit(c.usage, usageRoom);
344
+ const room = w - left.length - 2;
345
+ out.push(room > 8 ? left + ' ' + fit(c.summary, room, { tail: false }) : left);
346
+ }
347
+ }
348
+ out.push('');
349
+ out.push(fit(' ' + (ctx?.repo ? ctx.repo.name : 'onboarder')
350
+ + ' · Ctrl-D or `exit` to leave · Ctrl-C twice to quit', Math.max(10, w - 2)));
351
+ return out.join('\n');
290
352
  }
291
-
292
353
  // Split a typed line into words, honoring quotes so `find "exact phrase"` and
293
354
  // `show "my file.js"` arrive as one argument each. Done once, here, so no
294
355
  // command has to re-implement it.
295
356
  export function tokenize(line) {
296
- const out = [];
297
- const re = /"([^"]*)"|'([^']*)'|(\S+)/g;
298
- let m;
299
- while ((m = re.exec(String(line || '')))) out.push(m[1] ?? m[2] ?? m[3]);
300
- return out;
357
+ const out = [];
358
+ const re = /"([^"]*)"|'([^']*)'|(\S+)/g;
359
+ let m;
360
+ while ((m = re.exec(String(line || ''))))
361
+ out.push(m[1] ?? m[2] ?? m[3]);
362
+ return out;
301
363
  }
302
-
303
364
  // Tab completion, because a REPL where you retype `shared/analyzer/graph.js` one
304
365
  // letter at a time is not a REPL, it is a punishment.
305
366
  //
@@ -314,56 +375,61 @@ export function tokenize(line) {
314
375
  // one thing. It is deliberately the *only* way out to a shell, so the set of
315
376
  // things that can happen in a session stays legible.
316
377
  function completer(repo) {
317
- return function complete(line) {
318
- const trailingSpace = /\s$/.test(line);
319
- const parts = line.split(/\s+/);
320
- // Completing a command (no space yet, or trailing space after one word).
321
- if (parts.length <= 1 || (parts.length === 2 && trailingSpace)) {
322
- const hits = [...BY_NAME.keys()].filter((n) => n.startsWith(parts[0] || '')).sort();
323
- return [hits.length ? hits : parts, parts[0] || ''];
324
- }
325
- // Completing a path argument against the loaded repo. Matches at any depth,
326
- // not just from the root: `show rend` should find `src/render.js`, which is
327
- // the case the resolver's forgiving path lookup already handles — the
328
- // completer has to agree with it or Tab contradicts what the command does.
329
- const frag = parts[parts.length - 1] || '';
330
- const slash = frag.lastIndexOf('/');
331
- const dir = slash === -1 ? '' : frag.slice(0, slash + 1);
332
- const base = slash === -1 ? frag : frag.slice(slash + 1);
333
- const seen = new Set();
334
- const hits = [];
335
- for (const f of repo.scan.allFiles || repo.scan.files) {
336
- if (dir && !f.startsWith(dir)) continue;
337
- // With no directory typed, match the *last* segment so `rend` finds
338
- // `src/render.js`; with one typed, match the segment being completed.
339
- const name = dir ? f.slice(dir.length) : f.slice(f.lastIndexOf('/') + 1);
340
- if (!name.startsWith(base)) continue;
341
- if (seen.has(name)) continue;
342
- seen.add(name);
343
- hits.push(name);
344
- if (hits.length >= 200) break;
345
- }
346
- return [hits.length ? hits : [frag], frag];
347
- };
378
+ return function complete(line) {
379
+ const trailingSpace = /\s$/.test(line);
380
+ const parts = line.split(/\s+/);
381
+ // Completing a command (no space yet, or trailing space after one word).
382
+ if (parts.length <= 1 || (parts.length === 2 && trailingSpace)) {
383
+ const hits = [...BY_NAME.keys()].filter((n) => n.startsWith(parts[0] || '')).sort();
384
+ return [hits.length ? hits : parts, parts[0] || ''];
385
+ }
386
+ // Completing a path argument against the loaded repo. Matches at any depth,
387
+ // not just from the root: `show rend` should find `src/render.js`, which is
388
+ // the case the resolver's forgiving path lookup already handles — the
389
+ // completer has to agree with it or Tab contradicts what the command does.
390
+ const frag = parts[parts.length - 1] || '';
391
+ const slash = frag.lastIndexOf('/');
392
+ const dir = slash === -1 ? '' : frag.slice(0, slash + 1);
393
+ const base = slash === -1 ? frag : frag.slice(slash + 1);
394
+ const seen = new Set();
395
+ const hits = [];
396
+ for (const f of repo.scan.allFiles || repo.scan.files) {
397
+ if (dir && !f.startsWith(dir))
398
+ continue;
399
+ // With no directory typed, match the *last* segment so `rend` finds
400
+ // `src/render.js`; with one typed, match the segment being completed.
401
+ const name = dir ? f.slice(dir.length) : f.slice(f.lastIndexOf('/') + 1);
402
+ if (!name.startsWith(base))
403
+ continue;
404
+ if (seen.has(name))
405
+ continue;
406
+ seen.add(name);
407
+ hits.push(name);
408
+ if (hits.length >= 200)
409
+ break;
410
+ }
411
+ return [hits.length ? hits : [frag], frag];
412
+ };
348
413
  }
349
-
350
414
  // Run a shell command and capture its output. A non-zero exit is not a crash —
351
415
  // `grep` that finds nothing is a normal answer — so the code is reported, not
352
416
  // thrown. There is no `shell: true`: the whole line is the argument vector, so
353
417
  // nothing in a filename can be interpreted as a second command.
354
418
  async function shellEscape(line, cwd) {
355
- const parts = tokenize(line);
356
- if (!parts.length) return null;
357
- try {
358
- const { stdout, stderr } = await run(parts[0], parts.slice(1), { cwd, maxBuffer: 8 * 1024 * 1024 });
359
- const out = String(stdout || '').trimEnd();
360
- const err = String(stderr || '').trimEnd();
361
- return [out, err].filter(Boolean).join('\n') || dim(' (no output)');
362
- } catch (e) {
363
- const code = e.code ?? e.status;
364
- const err = String(e.stderr || '').trimEnd() || String(e.message || '').trimEnd();
365
- return dim(' exit ' + (code ?? '?') + (err ? '\n ' + err : ''));
366
- }
419
+ const parts = tokenize(line);
420
+ if (!parts.length)
421
+ return null;
422
+ try {
423
+ const { stdout, stderr } = await run(parts[0], parts.slice(1), { cwd, maxBuffer: 8 * 1024 * 1024 });
424
+ const out = String(stdout || '').trimEnd();
425
+ const err = String(stderr || '').trimEnd();
426
+ return [out, err].filter(Boolean).join('\n') || dim(' (no output)');
427
+ }
428
+ catch (e) {
429
+ const code = e.code ?? e.status;
430
+ const err = String(e.stderr || '').trimEnd() || String(e.message || '').trimEnd();
431
+ return dim(' exit ' + (code ?? '?') + (err ? '\n ' + err : ''));
432
+ }
367
433
  }
368
-
369
434
  export { completer, shellEscape };
435
+ //# sourceMappingURL=commands.js.map