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
package/server/tunnel.js CHANGED
@@ -6,92 +6,87 @@
6
6
  // is installed, the exact command that would expose the current settings, and
7
7
  // the install hint for when it isn't. The CLI (`onboarder tunnel`) is what
8
8
  // actually spawns anything; the HTTP layer only ever reads this status.
9
-
10
9
  import { spawnSync } from 'node:child_process';
11
-
12
10
  import { isLoopbackHost, normalizeSettings } from './config.js';
13
-
14
11
  // `spawnSync` on a missing binary resolves with an ENOENT error rather than
15
12
  // throwing, which is exactly the signal we need. `--version` is a flag every
16
13
  // CLI here answers; anything that doesn't is treated as absent.
17
14
  export function findOnPath(name) {
18
- try {
19
- const res = spawnSync(name, ['--version'], { encoding: 'utf8', timeout: 5000 });
20
- if (res.error) return { installed: false };
21
- const first = String(res.stdout || res.stderr || '').trim().split('\n')[0] || '';
22
- return { installed: true, version: first.slice(0, 120) };
23
- } catch {
24
- return { installed: false };
25
- }
15
+ try {
16
+ const res = spawnSync(name, ['--version'], { encoding: 'utf8', timeout: 5000 });
17
+ if (res.error)
18
+ return { installed: false };
19
+ const first = String(res.stdout || res.stderr || '').trim().split('\n')[0] || '';
20
+ return { installed: true, version: first.slice(0, 120) };
21
+ }
22
+ catch {
23
+ return { installed: false };
24
+ }
26
25
  }
27
-
28
26
  // The one address a tunnel should forward to. Tunnels always dial loopback —
29
27
  // that is what makes "loopback behind a tunnel" a safe self-hosted layout, so
30
28
  // even a 0.0.0.0 bind is proxied from 127.0.0.1.
31
29
  export function tunnelTarget(settings) {
32
- const s = normalizeSettings(settings);
33
- return `http://127.0.0.1:${s.port}`;
30
+ const s = normalizeSettings(settings);
31
+ return `http://127.0.0.1:${s.port}`;
34
32
  }
35
-
36
33
  export function cloudflareCommand(settings) {
37
- // A "quick tunnel": no account, no DNS edit, a random trycloudflare.com name
38
- // that lives as long as the process. The named-tunnel route (a fixed domain
39
- // on the person's own Cloudflare account) is a `cloudflared tunnel` setup of
40
- // its own; the wizard says so rather than pretending one command covers both.
41
- return `cloudflared tunnel --url ${tunnelTarget(settings)}`;
34
+ // A "quick tunnel": no account, no DNS edit, a random trycloudflare.com name
35
+ // that lives as long as the process. The named-tunnel route (a fixed domain
36
+ // on the person's own Cloudflare account) is a `cloudflared tunnel` setup of
37
+ // its own; the wizard says so rather than pretending one command covers both.
38
+ return `cloudflared tunnel --url ${tunnelTarget(settings)}`;
42
39
  }
43
-
44
40
  export function tailscaleCommand(settings) {
45
- const s = normalizeSettings(settings);
46
- // serve puts the machine's tailnet name (https://host.tailnet.ts.net) in
47
- // front of the port, visible only to the tailnet. funnel would go further
48
- // and publish it to the internet — mentioned, never run for you.
49
- return `tailscale serve --bg --https=443 ${tunnelTarget(s)}`;
41
+ const s = normalizeSettings(settings);
42
+ // serve puts the machine's tailnet name (https://host.tailnet.ts.net) in
43
+ // front of the port, visible only to the tailnet. funnel would go further
44
+ // and publish it to the internet — mentioned, never run for you.
45
+ return `tailscale serve --bg --https=443 ${tunnelTarget(s)}`;
50
46
  }
51
-
52
47
  export function installHint(name) {
53
- if (name === 'caddy') {
48
+ if (name === 'caddy') {
49
+ return process.platform === 'darwin'
50
+ ? 'brew install caddy'
51
+ : 'Install Caddy with: sudo apt install caddy';
52
+ }
53
+ if (name === 'cloudflared') {
54
+ return process.platform === 'darwin'
55
+ ? 'brew install cloudflared (or see https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/)'
56
+ : 'See https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/';
57
+ }
54
58
  return process.platform === 'darwin'
55
- ? 'brew install caddy'
56
- : 'Install Caddy with: sudo apt install caddy';
57
- }
58
- if (name === 'cloudflared') {
59
- return process.platform === 'darwin'
60
- ? 'brew install cloudflared (or see https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/)'
61
- : 'See https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/';
62
- }
63
- return process.platform === 'darwin'
64
- ? 'brew install --cask tailscale (or see https://tailscale.com/download)'
65
- : 'See https://tailscale.com/download';
59
+ ? 'brew install --cask tailscale (or see https://tailscale.com/download)'
60
+ : 'See https://tailscale.com/download';
66
61
  }
67
-
68
62
  // The settings drawer's tunnel section and `onboarder doctor` both render this:
69
63
  // what is enabled, what is installed, and what to run. Never spawns anything.
70
64
  export function tunnelStatus(settings) {
71
- const s = normalizeSettings(settings);
72
- const cf = findOnPath('cloudflared');
73
- const ts = findOnPath('tailscale');
74
- return {
75
- target: tunnelTarget(s),
76
- cloudflare: {
77
- enabled: s.tunnel.cloudflare,
78
- installed: cf.installed,
79
- version: cf.version || '',
80
- command: cloudflareCommand(s),
81
- install: cf.installed ? '' : installHint('cloudflared'),
82
- },
83
- tailscale: {
84
- enabled: s.tunnel.tailscale,
85
- installed: ts.installed,
86
- version: ts.version || '',
87
- command: tailscaleCommand(s),
88
- install: ts.installed ? '' : installHint('tailscale'),
89
- },
90
- // A tunnel answering a bind the server refused is the classic misread of
91
- // "self-hosted": the tunnel terminates TLS and dials loopback, so the bind
92
- // stays 127.0.0.1. Worth one explicit line everywhere the status is shown.
93
- note: isLoopbackHost(s.host)
94
- ? 'Loopback bind — a tunnel is the right way to reach this server remotely.'
95
- : 'Network bind — a tunnel is optional; the access key is not.',
96
- };
65
+ const s = normalizeSettings(settings);
66
+ const cf = findOnPath('cloudflared');
67
+ const ts = findOnPath('tailscale');
68
+ return {
69
+ target: tunnelTarget(s),
70
+ cloudflare: {
71
+ enabled: s.tunnel.cloudflare,
72
+ installed: cf.installed,
73
+ version: cf.version || '',
74
+ command: cloudflareCommand(s),
75
+ install: cf.installed ? '' : installHint('cloudflared'),
76
+ },
77
+ tailscale: {
78
+ enabled: s.tunnel.tailscale,
79
+ installed: ts.installed,
80
+ version: ts.version || '',
81
+ command: tailscaleCommand(s),
82
+ install: ts.installed ? '' : installHint('tailscale'),
83
+ },
84
+ // A tunnel answering a bind the server refused is the classic misread of
85
+ // "self-hosted": the tunnel terminates TLS and dials loopback, so the bind
86
+ // stays 127.0.0.1. Worth one explicit line everywhere the status is shown.
87
+ note: isLoopbackHost(s.host)
88
+ ? 'Loopback bind — a tunnel is the right way to reach this server remotely.'
89
+ : 'Network bind — a tunnel is optional; the access key is not.',
90
+ };
97
91
  }
92
+ //# sourceMappingURL=tunnel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel.js","sourceRoot":"","sources":["../src/server/tunnel.ts"],"names":[],"mappings":"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","sourcesContent":["// The two tunnels this server knows how to sit behind, and nothing else.\n//\n// A tunnel here is not a feature of the server — it is another program the\n// person runs that forwards a public name to our port. What this module owns\n// is everything we can honestly say about that arrangement: whether the tool\n// is installed, the exact command that would expose the current settings, and\n// the install hint for when it isn't. The CLI (`onboarder tunnel`) is what\n// actually spawns anything; the HTTP layer only ever reads this status.\n\nimport { spawnSync } from 'node:child_process';\n\nimport { isLoopbackHost, normalizeSettings } from './config.js';\n\n// `spawnSync` on a missing binary resolves with an ENOENT error rather than\n// throwing, which is exactly the signal we need. `--version` is a flag every\n// CLI here answers; anything that doesn't is treated as absent.\nexport function findOnPath(name) {\n try {\n const res = spawnSync(name, ['--version'], { encoding: 'utf8', timeout: 5000 });\n if (res.error) return { installed: false };\n const first = String(res.stdout || res.stderr || '').trim().split('\\n')[0] || '';\n return { installed: true, version: first.slice(0, 120) };\n } catch {\n return { installed: false };\n }\n}\n\n// The one address a tunnel should forward to. Tunnels always dial loopback —\n// that is what makes \"loopback behind a tunnel\" a safe self-hosted layout, so\n// even a 0.0.0.0 bind is proxied from 127.0.0.1.\nexport function tunnelTarget(settings) {\n const s = normalizeSettings(settings);\n return `http://127.0.0.1:${s.port}`;\n}\n\nexport function cloudflareCommand(settings) {\n // A \"quick tunnel\": no account, no DNS edit, a random trycloudflare.com name\n // that lives as long as the process. The named-tunnel route (a fixed domain\n // on the person's own Cloudflare account) is a `cloudflared tunnel` setup of\n // its own; the wizard says so rather than pretending one command covers both.\n return `cloudflared tunnel --url ${tunnelTarget(settings)}`;\n}\n\nexport function tailscaleCommand(settings) {\n const s = normalizeSettings(settings);\n // serve puts the machine's tailnet name (https://host.tailnet.ts.net) in\n // front of the port, visible only to the tailnet. funnel would go further\n // and publish it to the internet — mentioned, never run for you.\n return `tailscale serve --bg --https=443 ${tunnelTarget(s)}`;\n}\n\nexport function installHint(name) {\n if (name === 'caddy') {\n return process.platform === 'darwin'\n ? 'brew install caddy'\n : 'Install Caddy with: sudo apt install caddy';\n }\n if (name === 'cloudflared') {\n return process.platform === 'darwin'\n ? 'brew install cloudflared (or see https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/)'\n : 'See https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/';\n }\n return process.platform === 'darwin'\n ? 'brew install --cask tailscale (or see https://tailscale.com/download)'\n : 'See https://tailscale.com/download';\n}\n\n// The settings drawer's tunnel section and `onboarder doctor` both render this:\n// what is enabled, what is installed, and what to run. Never spawns anything.\nexport function tunnelStatus(settings) {\n const s = normalizeSettings(settings);\n const cf = findOnPath('cloudflared');\n const ts = findOnPath('tailscale');\n return {\n target: tunnelTarget(s),\n cloudflare: {\n enabled: s.tunnel.cloudflare,\n installed: cf.installed,\n version: cf.version || '',\n command: cloudflareCommand(s),\n install: cf.installed ? '' : installHint('cloudflared'),\n },\n tailscale: {\n enabled: s.tunnel.tailscale,\n installed: ts.installed,\n version: ts.version || '',\n command: tailscaleCommand(s),\n install: ts.installed ? '' : installHint('tailscale'),\n },\n // A tunnel answering a bind the server refused is the classic misread of\n // \"self-hosted\": the tunnel terminates TLS and dials loopback, so the bind\n // stays 127.0.0.1. Worth one explicit line everywhere the status is shown.\n note: isLoopbackHost(s.host)\n ? 'Loopback bind — a tunnel is the right way to reach this server remotely.'\n : 'Network bind — a tunnel is optional; the access key is not.',\n };\n}\n"]}
@@ -0,0 +1,16 @@
1
+ export declare function parseFolderDoc(text: any): {
2
+ folderBrief: string;
3
+ files: Map<any, any>;
4
+ };
5
+ export declare function fileFactsLine(path: any, scan: any, facts: any): string;
6
+ export declare function fileStaticDoc(path: any, scan: any, facts: any): any;
7
+ export declare function folderStaticDoc(folder: any, scan: any, facts: any, subfolderCount?: number): string;
8
+ export declare function docFileRow(path: any, scan: any, facts: any): {
9
+ path: any;
10
+ name: any;
11
+ parsed: boolean;
12
+ fanIn: any;
13
+ fanOut: any;
14
+ role: string;
15
+ functions: any;
16
+ };
@@ -6,9 +6,7 @@
6
6
  // docs page shows before anyone presses "Generate", and what it keeps showing if
7
7
  // no endpoint is ever configured. It used to sit in app.js, where it could not
8
8
  // be tested; it is pure text-from-facts, so it belongs next to `explainLocal`.
9
-
10
9
  import { factIndex, scanIndex } from './graph.js';
11
-
12
10
  // Parses the model's folder-brief answer, which we ask to be shaped like:
13
11
  //
14
12
  // FOLDER: two plain sentences about what lives here and why.
@@ -18,118 +16,126 @@ import { factIndex, scanIndex } from './graph.js';
18
16
  // Deliberately forgiving: missing markers fall back to taking the first
19
17
  // couple of non-empty lines as the folder brief.
20
18
  export function parseFolderDoc(text) {
21
- const out = { folderBrief: '', files: new Map() };
22
- if (!text) return out;
23
-
24
- const fallback = [];
25
- for (const raw of text.split('\n')) {
26
- const line = raw.trim();
27
- if (!line) continue;
28
-
29
- const folderMatch = line.match(/^FOLDER:\s*(.+)$/i);
30
- if (folderMatch) {
31
- out.folderBrief = (out.folderBrief ? out.folderBrief + ' ' : '') + folderMatch[1].trim();
32
- continue;
19
+ const out = { folderBrief: '', files: new Map() };
20
+ if (!text)
21
+ return out;
22
+ const fallback = [];
23
+ for (const raw of text.split('\n')) {
24
+ const line = raw.trim();
25
+ if (!line)
26
+ continue;
27
+ const folderMatch = line.match(/^FOLDER:\s*(.+)$/i);
28
+ if (folderMatch) {
29
+ out.folderBrief = (out.folderBrief ? out.folderBrief + ' ' : '') + folderMatch[1].trim();
30
+ continue;
31
+ }
32
+ const fileMatch = line.match(/^FILE:\s*([^:]+?):\s+(.+)$/i);
33
+ if (fileMatch) {
34
+ out.files.set(fileMatch[1].trim(), fileMatch[2].trim());
35
+ continue;
36
+ }
37
+ fallback.push(line);
33
38
  }
34
- const fileMatch = line.match(/^FILE:\s*([^:]+?):\s+(.+)$/i);
35
- if (fileMatch) {
36
- out.files.set(fileMatch[1].trim(), fileMatch[2].trim());
37
- continue;
39
+ if (!out.folderBrief && fallback.length) {
40
+ out.folderBrief = fallback.slice(0, 2).join(' ');
38
41
  }
39
- fallback.push(line);
40
- }
41
-
42
- if (!out.folderBrief && fallback.length) {
43
- out.folderBrief = fallback.slice(0, 2).join(' ');
44
- }
45
- return out;
42
+ return out;
46
43
  }
47
-
48
44
  // ---- documentation from the graph, no model involved -----------------------
49
-
50
45
  // The one-line facts strip under a file's name in the generated docs.
51
46
  export function fileFactsLine(path, scan, facts) {
52
- const f = scanIndex(scan).fileAt(path);
53
- if (!f) return 'not parsed';
54
- const fx = factIndex(facts);
55
- const fin = facts.fanIn[path] || 0;
56
- const fout = facts.fanOut[path] || 0;
57
- const bits = [];
58
- if (fx.entries.has(path)) bits.push('entry');
59
- if (fin >= 5) bits.push('hub');
60
- if (fx.inCycle.has(path)) bits.push('in a cycle');
61
- bits.push(`${fin} dependents · pulls in ${fout}`);
62
- if (f.functions.length) bits.push(`${f.functions.length} functions`);
63
- return bits.join(' · ');
47
+ const f = scanIndex(scan).fileAt(path);
48
+ if (!f)
49
+ return 'not parsed';
50
+ const fx = factIndex(facts);
51
+ const fin = facts.fanIn[path] || 0;
52
+ const fout = facts.fanOut[path] || 0;
53
+ const bits = [];
54
+ if (fx.entries.has(path))
55
+ bits.push('entry');
56
+ if (fin >= 5)
57
+ bits.push('hub');
58
+ if (fx.inCycle.has(path))
59
+ bits.push('in a cycle');
60
+ bits.push(`${fin} dependents · pulls in ${fout}`);
61
+ if (f.functions.length)
62
+ bits.push(`${f.functions.length} functions`);
63
+ return bits.join(' · ');
64
64
  }
65
-
66
65
  // A paragraph about one file. The branches are ordered by how much they tell
67
66
  // you: being an entry point is the most useful thing to say about a file, being
68
67
  // load-bearing is next, and "pulls in N, answers to M" is the fallback that
69
68
  // always holds.
70
69
  export function fileStaticDoc(path, scan, facts) {
71
- const f = scanIndex(scan).fileAt(path);
72
- if (!f) return 'Not parsed — kept as an asset or data file.';
73
- const fin = facts.fanIn[path] || 0;
74
- const fout = facts.fanOut[path] || 0;
75
- const importers = (facts.importers[path] || []).map((p) => p.split('/').pop());
76
- let s;
77
- if (factIndex(facts).entries.has(path)) {
78
- s = `${f.name} is one of the ways into the codebase — it pulls in ${fout} other ${fout === 1 ? 'file' : 'files'} and answers to nothing above it.`;
79
- } else if (fin >= 5) {
80
- s = `${f.name} is load-bearing: ${fin} files import it directly${importers.length ? `, ${importers.slice(0, 2).join(', ')} among them` : ''}.`;
81
- } else if (!fin && !fout) {
82
- s = `${f.name} stands alone — nothing imports it and it imports nothing we can see.`;
83
- } else if (!fout) {
84
- s = `${f.name} sits at the end of a chain — it imports nothing and is leaned on by ${fin} ${fin === 1 ? 'file' : 'files'}.`;
85
- } else if (!fin) {
86
- s = `${f.name} pulls in ${fout} ${fout === 1 ? 'file' : 'files'} but nothing imports it — a door we didn't recognize, or dead code.`;
87
- } else {
88
- s = `${f.name} pulls in ${fout} and answers to ${fin}.`;
89
- }
90
- if (f.functions.length) {
91
- s += ` It defines ${f.functions.length} function${f.functions.length === 1 ? '' : 's'} — ${f.functions.slice(0, 4).map((fn) => fn.name).join(', ')}${f.functions.length > 4 ? `, and ${f.functions.length - 4} more` : ''}.`;
92
- }
93
- if (f.exports.length) {
94
- s += ` Exports: ${f.exports.slice(0, 4).map((e) => e.name).join(', ')}${f.exports.length > 4 ? ', …' : ''}.`;
95
- }
96
- return s;
70
+ const f = scanIndex(scan).fileAt(path);
71
+ if (!f)
72
+ return 'Not parsed — kept as an asset or data file.';
73
+ const fin = facts.fanIn[path] || 0;
74
+ const fout = facts.fanOut[path] || 0;
75
+ const importers = (facts.importers[path] || []).map((p) => p.split('/').pop());
76
+ let s;
77
+ if (factIndex(facts).entries.has(path)) {
78
+ s = `${f.name} is one of the ways into the codebase — it pulls in ${fout} other ${fout === 1 ? 'file' : 'files'} and answers to nothing above it.`;
79
+ }
80
+ else if (fin >= 5) {
81
+ s = `${f.name} is load-bearing: ${fin} files import it directly${importers.length ? `, ${importers.slice(0, 2).join(', ')} among them` : ''}.`;
82
+ }
83
+ else if (!fin && !fout) {
84
+ s = `${f.name} stands alone — nothing imports it and it imports nothing we can see.`;
85
+ }
86
+ else if (!fout) {
87
+ s = `${f.name} sits at the end of a chain — it imports nothing and is leaned on by ${fin} ${fin === 1 ? 'file' : 'files'}.`;
88
+ }
89
+ else if (!fin) {
90
+ s = `${f.name} pulls in ${fout} ${fout === 1 ? 'file' : 'files'} but nothing imports it — a door we didn't recognize, or dead code.`;
91
+ }
92
+ else {
93
+ s = `${f.name} pulls in ${fout} and answers to ${fin}.`;
94
+ }
95
+ if (f.functions.length) {
96
+ s += ` It defines ${f.functions.length} function${f.functions.length === 1 ? '' : 's'} — ${f.functions.slice(0, 4).map((fn) => fn.name).join(', ')}${f.functions.length > 4 ? `, and ${f.functions.length - 4} more` : ''}.`;
97
+ }
98
+ if (f.exports.length) {
99
+ s += ` Exports: ${f.exports.slice(0, 4).map((e) => e.name).join(', ')}${f.exports.length > 4 ? ', …' : ''}.`;
100
+ }
101
+ return s;
97
102
  }
98
-
99
103
  // A paragraph about one folder. `subfolderCount` is passed rather than read off
100
104
  // a tree node, so nothing in the shared layer needs to know the view's tree
101
105
  // shape.
102
106
  export function folderStaticDoc(folder, scan, facts, subfolderCount = 0) {
103
- const here = scanIndex(scan).filesIn(folder);
104
- let s = `${here.length} parsed ${here.length === 1 ? 'file lives' : 'files live'} here`;
105
- if (subfolderCount) s += `, with ${subfolderCount} subfolder${subfolderCount === 1 ? '' : 's'} inside`;
106
- s += '.';
107
- const heaviest = here
108
- .map((f) => ({ name: f.name, fanIn: facts.fanIn[f.path] || 0 }))
109
- .sort((a, b) => b.fanIn - a.fanIn)[0];
110
- if (heaviest && heaviest.fanIn >= 3) {
111
- s += ` The one everything leans on is ${heaviest.name}, with ${heaviest.fanIn} dependents.`;
112
- }
113
- const entries = factIndex(facts).entries;
114
- const entriesHere = here.filter((f) => entries.has(f.path));
115
- if (entriesHere.length) s += ` The way in: ${entriesHere.map((f) => f.name).join(', ')}.`;
116
- return s;
107
+ const here = scanIndex(scan).filesIn(folder);
108
+ let s = `${here.length} parsed ${here.length === 1 ? 'file lives' : 'files live'} here`;
109
+ if (subfolderCount)
110
+ s += `, with ${subfolderCount} subfolder${subfolderCount === 1 ? '' : 's'} inside`;
111
+ s += '.';
112
+ const heaviest = here
113
+ .map((f) => ({ name: f.name, fanIn: facts.fanIn[f.path] || 0 }))
114
+ .sort((a, b) => b.fanIn - a.fanIn)[0];
115
+ if (heaviest && heaviest.fanIn >= 3) {
116
+ s += ` The one everything leans on is ${heaviest.name}, with ${heaviest.fanIn} dependents.`;
117
+ }
118
+ const entries = factIndex(facts).entries;
119
+ const entriesHere = here.filter((f) => entries.has(f.path));
120
+ if (entriesHere.length)
121
+ s += ` The way in: ${entriesHere.map((f) => f.name).join(', ')}.`;
122
+ return s;
117
123
  }
118
-
119
124
  // The facts about one file as the prompts want them. Two identical copies of
120
125
  // this used to sit in app.js — one for a single doc tab, one for the
121
126
  // folder-by-folder pass — and they had to agree for the two pages to describe
122
127
  // the same file the same way.
123
128
  export function docFileRow(path, scan, facts) {
124
- const f = scanIndex(scan).fileAt(path);
125
- const fanIn = facts.fanIn[path] || 0;
126
- return {
127
- path,
128
- name: path.split('/').pop(),
129
- parsed: Boolean(f),
130
- fanIn,
131
- fanOut: facts.fanOut[path] || 0,
132
- role: factIndex(facts).entries.has(path) ? 'entry' : fanIn >= 5 ? 'hub' : 'module',
133
- functions: f ? f.functions.map((fn) => fn.name) : [],
134
- };
129
+ const f = scanIndex(scan).fileAt(path);
130
+ const fanIn = facts.fanIn[path] || 0;
131
+ return {
132
+ path,
133
+ name: path.split('/').pop(),
134
+ parsed: Boolean(f),
135
+ fanIn,
136
+ fanOut: facts.fanOut[path] || 0,
137
+ role: factIndex(facts).entries.has(path) ? 'entry' : fanIn >= 5 ? 'hub' : 'module',
138
+ functions: f ? f.functions.map((fn) => fn.name) : [],
139
+ };
135
140
  }
141
+ //# sourceMappingURL=docs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.js","sourceRoot":"","sources":["../../src/shared/analyzer/docs.ts"],"names":[],"mappings":"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","sourcesContent":["// Documentation written from the import graph alone.\n//\n// Two halves live here. The first parses the model's answer back into rows. The\n// second writes the documentation *without* a model — plain sentences about what\n// a file is and what leans on it. That half is the offline floor: it is what the\n// docs page shows before anyone presses \"Generate\", and what it keeps showing if\n// no endpoint is ever configured. It used to sit in app.js, where it could not\n// be tested; it is pure text-from-facts, so it belongs next to `explainLocal`.\n\nimport { factIndex, scanIndex } from './graph.js';\n\n// Parses the model's folder-brief answer, which we ask to be shaped like:\n//\n// FOLDER: two plain sentences about what lives here and why.\n// FILE: scan.js: one sentence about this file.\n// FILE: graph.js: one sentence about this file.\n//\n// Deliberately forgiving: missing markers fall back to taking the first\n// couple of non-empty lines as the folder brief.\nexport function parseFolderDoc(text) {\n const out = { folderBrief: '', files: new Map() };\n if (!text) return out;\n\n const fallback = [];\n for (const raw of text.split('\\n')) {\n const line = raw.trim();\n if (!line) continue;\n\n const folderMatch = line.match(/^FOLDER:\\s*(.+)$/i);\n if (folderMatch) {\n out.folderBrief = (out.folderBrief ? out.folderBrief + ' ' : '') + folderMatch[1].trim();\n continue;\n }\n const fileMatch = line.match(/^FILE:\\s*([^:]+?):\\s+(.+)$/i);\n if (fileMatch) {\n out.files.set(fileMatch[1].trim(), fileMatch[2].trim());\n continue;\n }\n fallback.push(line);\n }\n\n if (!out.folderBrief && fallback.length) {\n out.folderBrief = fallback.slice(0, 2).join(' ');\n }\n return out;\n}\n\n// ---- documentation from the graph, no model involved -----------------------\n\n// The one-line facts strip under a file's name in the generated docs.\nexport function fileFactsLine(path, scan, facts) {\n const f = scanIndex(scan).fileAt(path);\n if (!f) return 'not parsed';\n const fx = factIndex(facts);\n const fin = facts.fanIn[path] || 0;\n const fout = facts.fanOut[path] || 0;\n const bits = [];\n if (fx.entries.has(path)) bits.push('entry');\n if (fin >= 5) bits.push('hub');\n if (fx.inCycle.has(path)) bits.push('in a cycle');\n bits.push(`${fin} dependents · pulls in ${fout}`);\n if (f.functions.length) bits.push(`${f.functions.length} functions`);\n return bits.join(' · ');\n}\n\n// A paragraph about one file. The branches are ordered by how much they tell\n// you: being an entry point is the most useful thing to say about a file, being\n// load-bearing is next, and \"pulls in N, answers to M\" is the fallback that\n// always holds.\nexport function fileStaticDoc(path, scan, facts) {\n const f = scanIndex(scan).fileAt(path);\n if (!f) return 'Not parsed — kept as an asset or data file.';\n const fin = facts.fanIn[path] || 0;\n const fout = facts.fanOut[path] || 0;\n const importers = (facts.importers[path] || []).map((p) => p.split('/').pop());\n let s;\n if (factIndex(facts).entries.has(path)) {\n s = `${f.name} is one of the ways into the codebase — it pulls in ${fout} other ${fout === 1 ? 'file' : 'files'} and answers to nothing above it.`;\n } else if (fin >= 5) {\n s = `${f.name} is load-bearing: ${fin} files import it directly${importers.length ? `, ${importers.slice(0, 2).join(', ')} among them` : ''}.`;\n } else if (!fin && !fout) {\n s = `${f.name} stands alone — nothing imports it and it imports nothing we can see.`;\n } else if (!fout) {\n s = `${f.name} sits at the end of a chain — it imports nothing and is leaned on by ${fin} ${fin === 1 ? 'file' : 'files'}.`;\n } else if (!fin) {\n s = `${f.name} pulls in ${fout} ${fout === 1 ? 'file' : 'files'} but nothing imports it — a door we didn't recognize, or dead code.`;\n } else {\n s = `${f.name} pulls in ${fout} and answers to ${fin}.`;\n }\n if (f.functions.length) {\n s += ` It defines ${f.functions.length} function${f.functions.length === 1 ? '' : 's'} — ${f.functions.slice(0, 4).map((fn) => fn.name).join(', ')}${f.functions.length > 4 ? `, and ${f.functions.length - 4} more` : ''}.`;\n }\n if (f.exports.length) {\n s += ` Exports: ${f.exports.slice(0, 4).map((e) => e.name).join(', ')}${f.exports.length > 4 ? ', …' : ''}.`;\n }\n return s;\n}\n\n// A paragraph about one folder. `subfolderCount` is passed rather than read off\n// a tree node, so nothing in the shared layer needs to know the view's tree\n// shape.\nexport function folderStaticDoc(folder, scan, facts, subfolderCount = 0) {\n const here = scanIndex(scan).filesIn(folder);\n let s = `${here.length} parsed ${here.length === 1 ? 'file lives' : 'files live'} here`;\n if (subfolderCount) s += `, with ${subfolderCount} subfolder${subfolderCount === 1 ? '' : 's'} inside`;\n s += '.';\n const heaviest = here\n .map((f) => ({ name: f.name, fanIn: facts.fanIn[f.path] || 0 }))\n .sort((a, b) => b.fanIn - a.fanIn)[0];\n if (heaviest && heaviest.fanIn >= 3) {\n s += ` The one everything leans on is ${heaviest.name}, with ${heaviest.fanIn} dependents.`;\n }\n const entries = factIndex(facts).entries;\n const entriesHere = here.filter((f) => entries.has(f.path));\n if (entriesHere.length) s += ` The way in: ${entriesHere.map((f) => f.name).join(', ')}.`;\n return s;\n}\n\n// The facts about one file as the prompts want them. Two identical copies of\n// this used to sit in app.js — one for a single doc tab, one for the\n// folder-by-folder pass — and they had to agree for the two pages to describe\n// the same file the same way.\nexport function docFileRow(path, scan, facts) {\n const f = scanIndex(scan).fileAt(path);\n const fanIn = facts.fanIn[path] || 0;\n return {\n path,\n name: path.split('/').pop(),\n parsed: Boolean(f),\n fanIn,\n fanOut: facts.fanOut[path] || 0,\n role: factIndex(facts).entries.has(path) ? 'entry' : fanIn >= 5 ? 'hub' : 'module',\n functions: f ? f.functions.map((fn) => fn.name) : [],\n };\n}\n"]}
@@ -0,0 +1,4 @@
1
+ export declare function explainFile(path: any, file: any, facts: any): string;
2
+ export declare function explainFolder(path: any, scan: any, facts: any): string;
3
+ export declare function explainOverview(scan: any, facts: any, manifest: any): string;
4
+ export declare function scanCaveats(scan: any): any[];