codebase-onboarder 0.6.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (526) hide show
  1. package/README.md +284 -53
  2. package/bin/build-if-source.js +23 -0
  3. package/bin/onboarder.js +0 -0
  4. package/cli/agent/command.d.ts +71 -0
  5. package/cli/agent/command.js +177 -0
  6. package/cli/agent/command.js.map +1 -0
  7. package/cli/agent/config.d.ts +31 -0
  8. package/cli/agent/config.js +98 -0
  9. package/cli/agent/config.js.map +1 -0
  10. package/cli/agent/contracts.d.ts +77 -0
  11. package/cli/agent/contracts.js +2 -0
  12. package/cli/agent/contracts.js.map +1 -0
  13. package/cli/agent/files.d.ts +19 -0
  14. package/cli/agent/files.js +109 -0
  15. package/cli/agent/files.js.map +1 -0
  16. package/cli/agent/gitSource.d.ts +18 -0
  17. package/cli/agent/gitSource.js +69 -0
  18. package/cli/agent/gitSource.js.map +1 -0
  19. package/cli/agent/github.d.ts +21 -0
  20. package/cli/agent/github.js +94 -0
  21. package/cli/agent/github.js.map +1 -0
  22. package/cli/agent/mcp.d.ts +15 -0
  23. package/cli/agent/mcp.js +78 -0
  24. package/cli/agent/mcp.js.map +1 -0
  25. package/cli/agent/process.d.ts +18 -0
  26. package/cli/agent/process.js +118 -0
  27. package/cli/agent/process.js.map +1 -0
  28. package/cli/agent/protocol.d.ts +3 -0
  29. package/cli/agent/protocol.js +26 -0
  30. package/cli/agent/protocol.js.map +1 -0
  31. package/cli/agent/runner.d.ts +34 -0
  32. package/cli/agent/runner.js +152 -0
  33. package/cli/agent/runner.js.map +1 -0
  34. package/cli/agent/stdio.d.ts +1 -0
  35. package/cli/agent/stdio.js +62 -0
  36. package/cli/agent/stdio.js.map +1 -0
  37. package/cli/agent/tools.d.ts +7 -0
  38. package/cli/agent/tools.js +201 -0
  39. package/cli/agent/tools.js.map +1 -0
  40. package/cli/chat/app.d.ts +16 -0
  41. package/cli/chat/app.js +345 -0
  42. package/cli/chat/app.js.map +1 -0
  43. package/cli/chat/commands.d.ts +11 -0
  44. package/cli/chat/commands.js +120 -0
  45. package/cli/chat/commands.js.map +1 -0
  46. package/cli/chat/composer.d.ts +75 -0
  47. package/cli/chat/composer.js +467 -0
  48. package/cli/chat/composer.js.map +1 -0
  49. package/cli/chat/controller.d.ts +60 -0
  50. package/cli/chat/controller.js +393 -0
  51. package/cli/chat/controller.js.map +1 -0
  52. package/cli/chat/logo.d.ts +3 -0
  53. package/cli/chat/logo.js +14 -0
  54. package/cli/chat/logo.js.map +1 -0
  55. package/cli/chat/models.d.ts +18 -0
  56. package/cli/chat/models.js +88 -0
  57. package/cli/chat/models.js.map +1 -0
  58. package/cli/chat/profile.d.ts +5 -0
  59. package/cli/chat/profile.js +98 -0
  60. package/cli/chat/profile.js.map +1 -0
  61. package/cli/chat/render.d.ts +40 -0
  62. package/cli/chat/render.js +259 -0
  63. package/cli/chat/render.js.map +1 -0
  64. package/cli/chat/screen.d.ts +26 -0
  65. package/cli/chat/screen.js +117 -0
  66. package/cli/chat/screen.js.map +1 -0
  67. package/cli/chat/source.d.ts +29 -0
  68. package/cli/chat/source.js +116 -0
  69. package/cli/chat/source.js.map +1 -0
  70. package/cli/chat/store.d.ts +43 -0
  71. package/cli/chat/store.js +94 -0
  72. package/cli/chat/store.js.map +1 -0
  73. package/cli/chat/text.d.ts +4 -0
  74. package/cli/chat/text.js +27 -0
  75. package/cli/chat/text.js.map +1 -0
  76. package/cli/commands.d.ts +26 -0
  77. package/cli/commands.js +836 -811
  78. package/cli/commands.js.map +1 -0
  79. package/cli/explorer/advanced.d.ts +14 -0
  80. package/cli/explorer/advanced.js +321 -329
  81. package/cli/explorer/advanced.js.map +1 -0
  82. package/cli/explorer/app.d.ts +2 -0
  83. package/cli/explorer/app.js +404 -314
  84. package/cli/explorer/app.js.map +1 -0
  85. package/cli/explorer/assistant.d.ts +9 -0
  86. package/cli/explorer/assistant.js +58 -0
  87. package/cli/explorer/assistant.js.map +1 -0
  88. package/cli/explorer/commands.d.ts +17 -0
  89. package/cli/explorer/commands.js +373 -302
  90. package/cli/explorer/commands.js.map +1 -0
  91. package/cli/explorer/featureViews.d.ts +124 -0
  92. package/cli/explorer/featureViews.js +179 -0
  93. package/cli/explorer/featureViews.js.map +1 -0
  94. package/cli/explorer/github.d.ts +21 -0
  95. package/cli/explorer/github.js +42 -44
  96. package/cli/explorer/github.js.map +1 -0
  97. package/cli/explorer/graphs.d.ts +7 -0
  98. package/cli/explorer/graphs.js +90 -95
  99. package/cli/explorer/graphs.js.map +1 -0
  100. package/cli/explorer/picker.d.ts +22 -0
  101. package/cli/explorer/picker.js +150 -0
  102. package/cli/explorer/picker.js.map +1 -0
  103. package/cli/explorer/report.d.ts +85 -0
  104. package/cli/explorer/report.js +60 -0
  105. package/cli/explorer/report.js.map +1 -0
  106. package/cli/explorer/session.d.ts +449 -0
  107. package/cli/explorer/session.js +143 -144
  108. package/cli/explorer/session.js.map +1 -0
  109. package/cli/explorer/views.d.ts +19 -0
  110. package/cli/explorer/views.js +465 -482
  111. package/cli/explorer/views.js.map +1 -0
  112. package/cli/explorer/wrap.d.ts +1 -0
  113. package/cli/explorer/wrap.js +28 -44
  114. package/cli/explorer/wrap.js.map +1 -0
  115. package/cli/main.d.ts +1 -0
  116. package/cli/main.js +251 -164
  117. package/cli/main.js.map +1 -0
  118. package/cli/prompt.d.ts +5 -0
  119. package/cli/prompt.js +84 -80
  120. package/cli/prompt.js.map +1 -0
  121. package/cli/scanOptions.d.ts +2 -0
  122. package/cli/scanOptions.js +11 -0
  123. package/cli/scanOptions.js.map +1 -0
  124. package/cli/ui.d.ts +33 -0
  125. package/cli/ui.js +35 -44
  126. package/cli/ui.js.map +1 -0
  127. package/cli/wizard.d.ts +187 -0
  128. package/cli/wizard.js +304 -284
  129. package/cli/wizard.js.map +1 -0
  130. package/docs/HERMES_RESEARCH.md +51 -0
  131. package/package.json +16 -4
  132. package/public/app.d.ts +1 -0
  133. package/public/app.js +1133 -1011
  134. package/public/app.js.map +1 -0
  135. package/public/assets/onboarder-mark.svg +11 -0
  136. package/public/browser.d.ts +71 -0
  137. package/public/browser.js +2 -0
  138. package/public/browser.js.map +1 -0
  139. package/public/index.html +54 -20
  140. package/public/js/about.d.ts +6 -0
  141. package/public/js/about.js +152 -172
  142. package/public/js/about.js.map +1 -0
  143. package/public/js/aiDraft.d.ts +4 -0
  144. package/public/js/aiDraft.js +166 -125
  145. package/public/js/aiDraft.js.map +1 -0
  146. package/public/js/analysisPanel.d.ts +7 -0
  147. package/public/js/analysisPanel.js +166 -166
  148. package/public/js/analysisPanel.js.map +1 -0
  149. package/public/js/analysisReport.d.ts +38 -0
  150. package/public/js/analysisReport.js +105 -110
  151. package/public/js/analysisReport.js.map +1 -0
  152. package/public/js/api.d.ts +29 -0
  153. package/public/js/api.js +198 -166
  154. package/public/js/api.js.map +1 -0
  155. package/public/js/atlas.d.ts +6 -0
  156. package/public/js/atlas.js +50 -58
  157. package/public/js/atlas.js.map +1 -0
  158. package/public/js/blameView.d.ts +2 -0
  159. package/public/js/blameView.js +36 -37
  160. package/public/js/blameView.js.map +1 -0
  161. package/public/js/codeTab.d.ts +3 -0
  162. package/public/js/codeTab.js +175 -180
  163. package/public/js/codeTab.js.map +1 -0
  164. package/public/js/codeViewer.d.ts +5 -0
  165. package/public/js/codeViewer.js +162 -150
  166. package/public/js/codeViewer.js.map +1 -0
  167. package/public/js/components/FileChip.d.ts +9 -0
  168. package/public/js/components/FileChip.js +45 -49
  169. package/public/js/components/FileChip.js.map +1 -0
  170. package/public/js/components/MetricSparkline.d.ts +7 -0
  171. package/public/js/components/MetricSparkline.js +35 -44
  172. package/public/js/components/MetricSparkline.js.map +1 -0
  173. package/public/js/components/RiskBadge.d.ts +9 -0
  174. package/public/js/components/RiskBadge.js +55 -63
  175. package/public/js/components/RiskBadge.js.map +1 -0
  176. package/public/js/deepAnalysisView.d.ts +99 -0
  177. package/public/js/deepAnalysisView.js +282 -302
  178. package/public/js/deepAnalysisView.js.map +1 -0
  179. package/public/js/diagramPane.d.ts +9 -0
  180. package/public/js/diagramPane.js +138 -135
  181. package/public/js/diagramPane.js.map +1 -0
  182. package/public/js/diffView.d.ts +6 -0
  183. package/public/js/diffView.js +222 -209
  184. package/public/js/diffView.js.map +1 -0
  185. package/public/js/docsView.d.ts +2 -0
  186. package/public/js/docsView.js +441 -442
  187. package/public/js/docsView.js.map +1 -0
  188. package/public/js/dom.d.ts +197 -0
  189. package/public/js/dom.js +5 -0
  190. package/public/js/dom.js.map +1 -0
  191. package/public/js/fileSourceBrowser.d.ts +5 -0
  192. package/public/js/fileSourceBrowser.js +33 -41
  193. package/public/js/fileSourceBrowser.js.map +1 -0
  194. package/public/js/flameGraph.d.ts +5 -0
  195. package/public/js/flameGraph.js +62 -72
  196. package/public/js/flameGraph.js.map +1 -0
  197. package/public/js/forceGraph.d.ts +10 -0
  198. package/public/js/forceGraph.js +581 -556
  199. package/public/js/forceGraph.js.map +1 -0
  200. package/public/js/heatmap.d.ts +4 -0
  201. package/public/js/heatmap.js +142 -164
  202. package/public/js/heatmap.js.map +1 -0
  203. package/public/js/highlight.d.ts +2 -0
  204. package/public/js/highlight.js +116 -107
  205. package/public/js/highlight.js.map +1 -0
  206. package/public/js/html.d.ts +2 -0
  207. package/public/js/html.js +14 -44
  208. package/public/js/html.js.map +1 -0
  209. package/public/js/insightsView.d.ts +5 -0
  210. package/public/js/insightsView.js +93 -111
  211. package/public/js/insightsView.js.map +1 -0
  212. package/public/js/inspector.d.ts +37 -0
  213. package/public/js/inspector.js +416 -445
  214. package/public/js/inspector.js.map +1 -0
  215. package/public/js/llm.d.ts +115 -0
  216. package/public/js/llm.js +246 -278
  217. package/public/js/llm.js.map +1 -0
  218. package/public/js/mapView.d.ts +3 -0
  219. package/public/js/mapView.js +121 -120
  220. package/public/js/mapView.js.map +1 -0
  221. package/public/js/markdown.d.ts +3 -0
  222. package/public/js/markdown.js +84 -91
  223. package/public/js/markdown.js.map +1 -0
  224. package/public/js/mindmap.d.ts +32 -0
  225. package/public/js/mindmap.js +244 -259
  226. package/public/js/mindmap.js.map +1 -0
  227. package/public/js/mobilePanels.d.ts +5 -0
  228. package/public/js/mobilePanels.js +50 -0
  229. package/public/js/mobilePanels.js.map +1 -0
  230. package/public/js/repoFiles.d.ts +12 -0
  231. package/public/js/repoFiles.js +29 -28
  232. package/public/js/repoFiles.js.map +1 -0
  233. package/public/js/reviewView.d.ts +28 -0
  234. package/public/js/reviewView.js +256 -0
  235. package/public/js/reviewView.js.map +1 -0
  236. package/public/js/sbomView.d.ts +3 -0
  237. package/public/js/sbomView.js +59 -67
  238. package/public/js/sbomView.js.map +1 -0
  239. package/public/js/scanCache.d.ts +16 -0
  240. package/public/js/scanCache.js +67 -65
  241. package/public/js/scanCache.js.map +1 -0
  242. package/public/js/search.d.ts +7 -0
  243. package/public/js/search.js +868 -800
  244. package/public/js/search.js.map +1 -0
  245. package/public/js/searchLocal.d.ts +42 -0
  246. package/public/js/searchLocal.js +87 -0
  247. package/public/js/searchLocal.js.map +1 -0
  248. package/public/js/serverSettings.d.ts +5 -0
  249. package/public/js/serverSettings.js +153 -164
  250. package/public/js/serverSettings.js.map +1 -0
  251. package/public/js/state.d.ts +798 -0
  252. package/public/js/state.js +114 -122
  253. package/public/js/state.js.map +1 -0
  254. package/public/js/tour.d.ts +6 -0
  255. package/public/js/tour.js +5 -7
  256. package/public/js/tour.js.map +1 -0
  257. package/public/js/transitions.d.ts +2 -0
  258. package/public/js/transitions.js +9 -10
  259. package/public/js/transitions.js.map +1 -0
  260. package/public/js/tree.d.ts +12 -0
  261. package/public/js/tree.js +157 -154
  262. package/public/js/tree.js.map +1 -0
  263. package/public/js/workflowsView.d.ts +3 -0
  264. package/public/js/workflowsView.js +15 -22
  265. package/public/js/workflowsView.js.map +1 -0
  266. package/public/search.css +495 -0
  267. package/public/styles.css +188 -346
  268. package/public/workbench.css +166 -0
  269. package/server/apiAuth.d.ts +3 -0
  270. package/server/apiAuth.js +18 -20
  271. package/server/apiAuth.js.map +1 -0
  272. package/server/apiDiff.d.ts +2 -0
  273. package/server/apiDiff.js +20 -18
  274. package/server/apiDiff.js.map +1 -0
  275. package/server/apiDocs.d.ts +2 -0
  276. package/server/apiDocs.js +38 -40
  277. package/server/apiDocs.js.map +1 -0
  278. package/server/apiFile.d.ts +1 -0
  279. package/server/apiFile.js +14 -17
  280. package/server/apiFile.js.map +1 -0
  281. package/server/apiGitBlame.d.ts +2 -0
  282. package/server/apiGitBlame.js +50 -51
  283. package/server/apiGitBlame.js.map +1 -0
  284. package/server/apiMcp.d.ts +4 -0
  285. package/server/apiMcp.js +64 -66
  286. package/server/apiMcp.js.map +1 -0
  287. package/server/apiReview.d.ts +2 -0
  288. package/server/apiReview.js +45 -0
  289. package/server/apiReview.js.map +1 -0
  290. package/server/apiScan.d.ts +5 -0
  291. package/server/apiScan.js +90 -71
  292. package/server/apiScan.js.map +1 -0
  293. package/server/apiSearch.d.ts +33 -0
  294. package/server/apiSearch.js +184 -200
  295. package/server/apiSearch.js.map +1 -0
  296. package/server/apiSettings.d.ts +4 -0
  297. package/server/apiSettings.js +84 -85
  298. package/server/apiSettings.js.map +1 -0
  299. package/server/apiTools.d.ts +3 -0
  300. package/server/apiTools.js +55 -56
  301. package/server/apiTools.js.map +1 -0
  302. package/server/auth.d.ts +5 -0
  303. package/server/auth.js +54 -51
  304. package/server/auth.js.map +1 -0
  305. package/server/config.d.ts +42 -0
  306. package/server/config.js +189 -194
  307. package/server/config.js.map +1 -0
  308. package/server/daemon.d.ts +12 -0
  309. package/server/daemon.js +124 -114
  310. package/server/daemon.js.map +1 -0
  311. package/server/fileSourceNode.d.ts +2 -0
  312. package/server/fileSourceNode.js +34 -36
  313. package/server/fileSourceNode.js.map +1 -0
  314. package/server/gitClone.d.ts +9 -0
  315. package/server/gitClone.js +59 -61
  316. package/server/gitClone.js.map +1 -0
  317. package/server/gitDiff.d.ts +36 -0
  318. package/server/gitDiff.js +271 -169
  319. package/server/gitDiff.js.map +1 -0
  320. package/server/gitHistory.d.ts +12 -0
  321. package/server/gitHistory.js +80 -80
  322. package/server/gitHistory.js.map +1 -0
  323. package/server/gitRemote.d.ts +12 -0
  324. package/server/gitRemote.js +37 -38
  325. package/server/gitRemote.js.map +1 -0
  326. package/server/hermesChat.d.ts +13 -0
  327. package/server/hermesChat.js +145 -0
  328. package/server/hermesChat.js.map +1 -0
  329. package/server/htmlText.d.ts +4 -0
  330. package/server/htmlText.js +16 -23
  331. package/server/htmlText.js.map +1 -0
  332. package/server/http.d.ts +6 -0
  333. package/server/http.js +27 -34
  334. package/server/http.js.map +1 -0
  335. package/server/httpGuards.d.ts +2 -0
  336. package/server/httpGuards.js +47 -43
  337. package/server/httpGuards.js.map +1 -0
  338. package/server/https.d.ts +34 -0
  339. package/server/https.js +121 -111
  340. package/server/https.js.map +1 -0
  341. package/server/index.d.ts +40 -0
  342. package/server/index.js +139 -147
  343. package/server/index.js.map +1 -0
  344. package/server/layout.d.ts +26 -0
  345. package/server/layout.js +59 -64
  346. package/server/layout.js.map +1 -0
  347. package/server/llmProxy.d.ts +3 -0
  348. package/server/llmProxy.js +137 -135
  349. package/server/llmProxy.js.map +1 -0
  350. package/server/logger.d.ts +38 -0
  351. package/server/logger.js +198 -211
  352. package/server/logger.js.map +1 -0
  353. package/server/mcp/analysis.d.ts +29 -0
  354. package/server/mcp/analysis.js +99 -120
  355. package/server/mcp/analysis.js.map +1 -0
  356. package/server/mcp/http.d.ts +9 -0
  357. package/server/mcp/http.js +128 -137
  358. package/server/mcp/http.js.map +1 -0
  359. package/server/mcp/runner.d.ts +68 -0
  360. package/server/mcp/runner.js +208 -218
  361. package/server/mcp/runner.js.map +1 -0
  362. package/server/mcp/server.d.ts +29 -0
  363. package/server/mcp/server.js +167 -180
  364. package/server/mcp/server.js.map +1 -0
  365. package/server/mcp/standalone.d.ts +1 -0
  366. package/server/mcp/standalone.js +8 -10
  367. package/server/mcp/standalone.js.map +1 -0
  368. package/server/mcp/tools.d.ts +2020 -0
  369. package/server/mcp/tools.js +523 -574
  370. package/server/mcp/tools.js.map +1 -0
  371. package/server/paths.d.ts +3 -0
  372. package/server/paths.js +17 -15
  373. package/server/paths.js.map +1 -0
  374. package/server/pidfile.d.ts +9 -0
  375. package/server/pidfile.js +43 -45
  376. package/server/pidfile.js.map +1 -0
  377. package/server/review.d.ts +5 -0
  378. package/server/review.js +35 -0
  379. package/server/review.js.map +1 -0
  380. package/server/router.d.ts +33 -0
  381. package/server/router.js +195 -197
  382. package/server/router.js.map +1 -0
  383. package/server/scanRequest.d.ts +3 -0
  384. package/server/scanRequest.js +36 -0
  385. package/server/scanRequest.js.map +1 -0
  386. package/server/searchIndex.d.ts +17 -0
  387. package/server/searchIndex.js +83 -80
  388. package/server/searchIndex.js.map +1 -0
  389. package/server/sessions.d.ts +14 -0
  390. package/server/sessions.js +62 -70
  391. package/server/sessions.js.map +1 -0
  392. package/server/startup.d.ts +118 -0
  393. package/server/startup.js +143 -148
  394. package/server/startup.js.map +1 -0
  395. package/server/static.d.ts +6 -0
  396. package/server/static.js +28 -31
  397. package/server/static.js.map +1 -0
  398. package/server/tools/install.d.ts +4 -0
  399. package/server/tools/install.js +176 -185
  400. package/server/tools/install.js.map +1 -0
  401. package/server/tools/parse.d.ts +8 -0
  402. package/server/tools/parse.js +112 -114
  403. package/server/tools/parse.js.map +1 -0
  404. package/server/tools/platform.d.ts +9 -0
  405. package/server/tools/platform.js +49 -47
  406. package/server/tools/platform.js.map +1 -0
  407. package/server/tools/registry.d.ts +137 -0
  408. package/server/tools/registry.js +173 -172
  409. package/server/tools/registry.js.map +1 -0
  410. package/server/tools/scan.d.ts +34 -0
  411. package/server/tools/scan.js +89 -98
  412. package/server/tools/scan.js.map +1 -0
  413. package/server/tools.d.ts +34 -0
  414. package/server/tools.js +94 -107
  415. package/server/tools.js.map +1 -0
  416. package/server/tunnel.d.ts +29 -0
  417. package/server/tunnel.js +61 -66
  418. package/server/tunnel.js.map +1 -0
  419. package/shared/analyzer/docs.d.ts +16 -0
  420. package/shared/analyzer/docs.js +99 -93
  421. package/shared/analyzer/docs.js.map +1 -0
  422. package/shared/analyzer/explainLocal.d.ts +4 -0
  423. package/shared/analyzer/explainLocal.js +122 -142
  424. package/shared/analyzer/explainLocal.js.map +1 -0
  425. package/shared/analyzer/github.d.ts +37 -0
  426. package/shared/analyzer/github.js +41 -43
  427. package/shared/analyzer/github.js.map +1 -0
  428. package/shared/analyzer/graph.d.ts +41 -0
  429. package/shared/analyzer/graph.js +393 -400
  430. package/shared/analyzer/graph.js.map +1 -0
  431. package/shared/analyzer/health.d.ts +33 -0
  432. package/shared/analyzer/health.js +197 -193
  433. package/shared/analyzer/health.js.map +1 -0
  434. package/shared/analyzer/history.d.ts +29 -0
  435. package/shared/analyzer/history.js +110 -111
  436. package/shared/analyzer/history.js.map +1 -0
  437. package/shared/analyzer/jsonConfig.d.ts +2 -0
  438. package/shared/analyzer/jsonConfig.js +61 -0
  439. package/shared/analyzer/jsonConfig.js.map +1 -0
  440. package/shared/analyzer/languages/csharp.d.ts +26 -0
  441. package/shared/analyzer/languages/csharp.js +83 -88
  442. package/shared/analyzer/languages/csharp.js.map +1 -0
  443. package/shared/analyzer/languages/generic.d.ts +23 -0
  444. package/shared/analyzer/languages/generic.js +94 -105
  445. package/shared/analyzer/languages/generic.js.map +1 -0
  446. package/shared/analyzer/languages/go.d.ts +24 -0
  447. package/shared/analyzer/languages/go.js +45 -54
  448. package/shared/analyzer/languages/go.js.map +1 -0
  449. package/shared/analyzer/languages/index.d.ts +6 -0
  450. package/shared/analyzer/languages/index.js +19 -20
  451. package/shared/analyzer/languages/index.js.map +1 -0
  452. package/shared/analyzer/languages/java.d.ts +20 -0
  453. package/shared/analyzer/languages/java.js +73 -78
  454. package/shared/analyzer/languages/java.js.map +1 -0
  455. package/shared/analyzer/languages/javascript.d.ts +12 -0
  456. package/shared/analyzer/languages/javascript.js +258 -209
  457. package/shared/analyzer/languages/javascript.js.map +1 -0
  458. package/shared/analyzer/languages/python.d.ts +23 -0
  459. package/shared/analyzer/languages/python.js +92 -100
  460. package/shared/analyzer/languages/python.js.map +1 -0
  461. package/shared/analyzer/languages/rust.d.ts +17 -0
  462. package/shared/analyzer/languages/rust.js +96 -98
  463. package/shared/analyzer/languages/rust.js.map +1 -0
  464. package/shared/analyzer/languages/typescript.d.ts +11 -0
  465. package/shared/analyzer/languages/typescript.js +117 -116
  466. package/shared/analyzer/languages/typescript.js.map +1 -0
  467. package/shared/analyzer/licenses.d.ts +18 -0
  468. package/shared/analyzer/licenses.js +130 -133
  469. package/shared/analyzer/licenses.js.map +1 -0
  470. package/shared/analyzer/metrics.d.ts +20 -0
  471. package/shared/analyzer/metrics.js +112 -104
  472. package/shared/analyzer/metrics.js.map +1 -0
  473. package/shared/analyzer/pathUtil.d.ts +10 -0
  474. package/shared/analyzer/pathUtil.js +29 -35
  475. package/shared/analyzer/pathUtil.js.map +1 -0
  476. package/shared/analyzer/patterns.d.ts +11 -0
  477. package/shared/analyzer/patterns.js +231 -253
  478. package/shared/analyzer/patterns.js.map +1 -0
  479. package/shared/analyzer/scan.d.ts +62 -0
  480. package/shared/analyzer/scan.js +451 -442
  481. package/shared/analyzer/scan.js.map +1 -0
  482. package/shared/analyzer/scanControl.d.ts +11 -0
  483. package/shared/analyzer/scanControl.js +62 -0
  484. package/shared/analyzer/scanControl.js.map +1 -0
  485. package/shared/analyzer/security.d.ts +18 -0
  486. package/shared/analyzer/security.js +159 -159
  487. package/shared/analyzer/security.js.map +1 -0
  488. package/shared/analyzer/services.d.ts +5 -0
  489. package/shared/analyzer/services.js +141 -138
  490. package/shared/analyzer/services.js.map +1 -0
  491. package/shared/analyzer/stack.d.ts +6 -0
  492. package/shared/analyzer/stack.js +134 -141
  493. package/shared/analyzer/stack.js.map +1 -0
  494. package/shared/analyzer/tour.d.ts +2 -0
  495. package/shared/analyzer/tour.js +45 -53
  496. package/shared/analyzer/tour.js.map +1 -0
  497. package/shared/analyzer/util.d.ts +8 -0
  498. package/shared/analyzer/util.js +130 -76
  499. package/shared/analyzer/util.js.map +1 -0
  500. package/shared/analyzer/workflows.d.ts +8 -0
  501. package/shared/analyzer/workflows.js +139 -134
  502. package/shared/analyzer/workflows.js.map +1 -0
  503. package/shared/contracts.d.ts +250 -0
  504. package/shared/contracts.js +2 -0
  505. package/shared/contracts.js.map +1 -0
  506. package/shared/diagram/aiFacts.d.ts +35 -0
  507. package/shared/diagram/aiFacts.js +102 -105
  508. package/shared/diagram/aiFacts.js.map +1 -0
  509. package/shared/diagram/aiMermaid.d.ts +5 -0
  510. package/shared/diagram/aiMermaid.js +50 -46
  511. package/shared/diagram/aiMermaid.js.map +1 -0
  512. package/shared/diagram/atlas.d.ts +16 -0
  513. package/shared/diagram/atlas.js +51 -60
  514. package/shared/diagram/atlas.js.map +1 -0
  515. package/shared/diagram/mermaid.d.ts +43 -0
  516. package/shared/diagram/mermaid.js +348 -370
  517. package/shared/diagram/mermaid.js.map +1 -0
  518. package/shared/review/contracts.d.ts +95 -0
  519. package/shared/review/contracts.js +2 -0
  520. package/shared/review/contracts.js.map +1 -0
  521. package/shared/review/review.d.ts +10 -0
  522. package/shared/review/review.js +184 -0
  523. package/shared/review/review.js.map +1 -0
  524. package/shared/search/query.d.ts +32 -0
  525. package/shared/search/query.js +395 -388
  526. package/shared/search/query.js.map +1 -0
@@ -1,3 +1,4 @@
1
+ import { eventElement } from '/js/dom.js';
1
2
  // The Docs tab: a written account of the repo.
2
3
  //
3
4
  // Three layers, in order of how much they cost. The overview page and the
@@ -9,7 +10,6 @@
9
10
  //
10
11
  // The static sentences live in `/shared/analyzer/docs.js` — pure, and tested.
11
12
  // What is here is the DOM: tabs, streaming, and the wiring between them.
12
-
13
13
  import { parseFolderDoc, fileFactsLine, fileStaticDoc, folderStaticDoc, docFileRow } from '/shared/analyzer/docs.js';
14
14
  import { explainOverview } from '/shared/analyzer/explainLocal.js';
15
15
  import { scanIndex } from '/shared/analyzer/graph.js';
@@ -20,100 +20,89 @@ import { streamExplain } from './api.js';
20
20
  import { findNode, countFiles } from './tree.js';
21
21
  import { readRepoFile, gatherFileContext } from './repoFiles.js';
22
22
  import * as llm from './llm.js';
23
-
24
23
  let host = null;
25
24
  let hooks = {
26
- onToast: () => {},
27
- onOpenSettings: () => {},
28
- onOpenFile: () => {},
29
- repoOverview: () => '',
25
+ onToast: (..._args) => { },
26
+ onOpenSettings: (..._args) => { },
27
+ onOpenFile: (..._args) => { },
28
+ repoOverview: () => '',
30
29
  };
31
-
32
30
  export function initDocs(options) {
33
- host = options.host;
34
- hooks = { ...hooks, ...options };
31
+ host = options.host;
32
+ hooks = { ...hooks, ...options };
35
33
  }
36
-
37
34
  // Facts about one file or folder, bound to the loaded repo. Every prompt and
38
35
  // every static sentence on this page goes through these two, so the doc tab and
39
36
  // the folder pass can never describe the same file differently.
40
37
  const factsLine = (path) => fileFactsLine(path, state.scan, state.facts);
41
38
  const staticDoc = (path) => fileStaticDoc(path, state.scan, state.facts);
42
39
  const fileRow = (path) => docFileRow(path, state.scan, state.facts);
43
-
44
40
  // ---- the page ---------------------------------------------------------------
45
-
46
41
  // One-time document build per scan; AI briefs update rows in place afterwards.
47
42
  export function renderDocs() {
48
- if (state.docs.rendered) return;
49
- state.docs.rendered = true;
50
-
51
- const tabsEl = document.createElement('div');
52
- tabsEl.className = 'doc-tabs';
53
- const wrapEl = document.createElement('div');
54
- const scrollEl = document.createElement('div');
55
- scrollEl.className = 'doc-scroll';
56
- scrollEl.append(tabsEl, wrapEl);
57
-
58
- // Answers stream into this rail, above the bar, only once there's something
59
- // to show.
60
- const railEl = document.createElement('div');
61
- railEl.className = 'doc-qa-rail';
62
- railEl.hidden = true;
63
-
64
- // The sticky bottom bar: questions about whatever doc is on screen, with
65
- // clear/close once a conversation is underway.
66
- const barEl = document.createElement('form');
67
- barEl.className = 'doc-askbar';
68
- barEl.innerHTML = `
43
+ if (state.docs.rendered)
44
+ return;
45
+ state.docs.rendered = true;
46
+ const tabsEl = document.createElement('div');
47
+ tabsEl.className = 'doc-tabs';
48
+ const wrapEl = document.createElement('div');
49
+ const scrollEl = document.createElement('div');
50
+ scrollEl.className = 'doc-scroll';
51
+ scrollEl.append(tabsEl, wrapEl);
52
+ // Answers stream into this rail, above the bar, only once there's something
53
+ // to show.
54
+ const railEl = document.createElement('div');
55
+ railEl.className = 'doc-qa-rail';
56
+ railEl.hidden = true;
57
+ // The sticky bottom bar: questions about whatever doc is on screen, with
58
+ // clear/close once a conversation is underway.
59
+ const barEl = document.createElement('form');
60
+ barEl.className = 'doc-askbar';
61
+ barEl.innerHTML = `
69
62
  <input type="text" id="docAskInput" class="text-input" placeholder="Ask me anything about this doc…" spellcheck="false" autocomplete="off">
70
63
  <button type="submit" class="btn btn-ink">Ask</button>`;
71
- const clearBtn = document.createElement('button');
72
- clearBtn.type = 'button';
73
- clearBtn.className = 'btn btn-sm btn-ghost doc-clear';
74
- clearBtn.textContent = 'clear';
75
- clearBtn.title = 'Clear the conversation';
76
- clearBtn.hidden = true;
77
- const closeBtn = document.createElement('button');
78
- closeBtn.type = 'button';
79
- closeBtn.className = 'btn btn-sm btn-ghost doc-close';
80
- closeBtn.textContent = 'close';
81
- closeBtn.title = 'Close the conversation';
82
- closeBtn.hidden = true;
83
- clearBtn.addEventListener('click', () => { railEl.innerHTML = ''; });
84
- closeBtn.addEventListener('click', () => {
85
- railEl.hidden = true;
64
+ const clearBtn = document.createElement('button');
65
+ clearBtn.type = 'button';
66
+ clearBtn.className = 'btn btn-sm btn-ghost doc-clear';
67
+ clearBtn.textContent = 'clear';
68
+ clearBtn.title = 'Clear the conversation';
86
69
  clearBtn.hidden = true;
70
+ const closeBtn = document.createElement('button');
71
+ closeBtn.type = 'button';
72
+ closeBtn.className = 'btn btn-sm btn-ghost doc-close';
73
+ closeBtn.textContent = 'close';
74
+ closeBtn.title = 'Close the conversation';
87
75
  closeBtn.hidden = true;
88
- });
89
- barEl.append(clearBtn, closeBtn);
90
- barEl.addEventListener('submit', (event) => {
91
- event.preventDefault();
92
- askAboutRepo();
93
- });
94
-
95
- host.innerHTML = '';
96
- host.append(scrollEl, railEl, barEl);
97
- state.docs.tabsEl = tabsEl;
98
- state.docs.wrapEl = wrapEl;
99
- state.docs.railEl = railEl;
100
- state.docs.bar = barEl;
101
- state.docs.pageEl = buildOverviewPage();
102
-
103
- renderDocStrip();
104
- showActiveDoc();
105
- loadReadme();
76
+ clearBtn.addEventListener('click', () => { railEl.innerHTML = ''; });
77
+ closeBtn.addEventListener('click', () => {
78
+ railEl.hidden = true;
79
+ clearBtn.hidden = true;
80
+ closeBtn.hidden = true;
81
+ });
82
+ barEl.append(clearBtn, closeBtn);
83
+ barEl.addEventListener('submit', (event) => {
84
+ event.preventDefault();
85
+ askAboutRepo();
86
+ });
87
+ host.innerHTML = '';
88
+ host.append(scrollEl, railEl, barEl);
89
+ state.docs.tabsEl = tabsEl;
90
+ state.docs.wrapEl = wrapEl;
91
+ state.docs.railEl = railEl;
92
+ state.docs.bar = barEl;
93
+ state.docs.pageEl = buildOverviewPage();
94
+ renderDocStrip();
95
+ showActiveDoc();
96
+ loadReadme();
106
97
  }
107
-
108
98
  // The landing tab: repo header, topic index, README, the documentation zone
109
99
  // (filled on demand by the AI), and the question box at the bottom.
110
100
  function buildOverviewPage() {
111
- const { scan, facts, manifest } = state;
112
- const root = state.treeData;
113
-
114
- const page = document.createElement('div');
115
- page.className = 'doc-page';
116
- page.innerHTML = `
101
+ const { scan, facts, manifest } = state;
102
+ const root = state.treeData;
103
+ const page = document.createElement('div');
104
+ page.className = 'doc-page';
105
+ page.innerHTML = `
117
106
  <div id="doc-top">
118
107
  <h1 class="doc-title">${escapeHtml(scan.name)}</h1>
119
108
  <p class="doc-sub">${escapeHtml(scan.root)}</p>
@@ -130,219 +119,217 @@ function buildOverviewPage() {
130
119
  <button class="btn btn-ink" id="docGenBtn">Generate documentation</button>
131
120
  </div>
132
121
  `;
133
-
134
- buildToc(page, root);
135
-
136
- page.addEventListener('click', (event) => {
137
- const b = event.target.closest('[data-doc-open]');
138
- if (!b) return;
139
- const raw = b.dataset.docOpen;
140
- const i = raw.indexOf(':');
141
- openDocTab(raw.slice(0, i), raw.slice(i + 1));
142
- });
143
- page.querySelector('#docGenBtn').addEventListener('click', writeDocsWithAI);
144
-
145
- return page;
122
+ buildToc(page, root);
123
+ page.addEventListener('click', (event) => {
124
+ const b = eventElement(event)?.closest('[data-doc-open]');
125
+ if (!b)
126
+ return;
127
+ const raw = b.dataset.docOpen;
128
+ const i = raw.indexOf(':');
129
+ openDocTab(raw.slice(0, i), raw.slice(i + 1));
130
+ });
131
+ page.querySelector('#docGenBtn').addEventListener('click', writeDocsWithAI);
132
+ return page;
146
133
  }
147
-
148
134
  // The contents index: page anchors up top, then every folder and file as a
149
135
  // topic — clicking any of them opens its detailed AI tab.
150
136
  function buildToc(page, root) {
151
- const toc = page.querySelector('#docToc');
152
- const bits = [
153
- `<span class="doc-toc-h">Get documentation about a topic</span>`,
154
- `<a href="#doc-top">Overview</a>`,
155
- `<a href="#doc-readme-h">In its own words</a>`,
156
- `<span class="doc-toc-group">Folders and files — click for the AI document</span>`,
157
- ];
158
- let folderCount = 0;
159
- const parsedSet = new Set(state.scan.files.map((f) => f.path));
160
- const walk = (node, depth) => {
161
- if (folderCount >= 30) return;
162
- folderCount++;
163
- const indent = Math.min(depth, 3);
164
- bits.push(`<button class="doc-toc-link doc-toc-folder doc-indent-${indent}" data-doc-open="folder:${escapeHtml(node.path)}">${escapeHtml(node.path ? node.name + '/' : '(repo root)')}</button>`);
165
- const files = node.files.filter((f) => parsedSet.has(f)).slice(0, 10);
166
- if (files.length) {
167
- const links = files
168
- .map((f) => `<button class="doc-toc-link" data-doc-open="file:${escapeHtml(f)}">${escapeHtml(f.split('/').pop())}</button>`)
169
- .join('<span class="doc-toc-sep"> · </span>');
170
- bits.push(`<span class="doc-toc-files doc-indent-${indent}">${links}${node.files.length > files.length ? ' …' : ''}</span>`);
171
- }
172
- for (const child of [...node.dirs.values()].sort((a, b) => a.name.localeCompare(b.name))) {
173
- walk(child, depth + 1);
137
+ const toc = page.querySelector('#docToc');
138
+ const bits = [
139
+ `<span class="doc-toc-h">Get documentation about a topic</span>`,
140
+ `<a href="#doc-top">Overview</a>`,
141
+ `<a href="#doc-readme-h">In its own words</a>`,
142
+ `<span class="doc-toc-group">Folders and files — click for the AI document</span>`,
143
+ ];
144
+ let folderCount = 0;
145
+ const parsedSet = new Set(state.scan.files.map((f) => f.path));
146
+ const walk = (node, depth) => {
147
+ if (folderCount >= 30)
148
+ return;
149
+ folderCount++;
150
+ const indent = Math.min(depth, 3);
151
+ bits.push(`<button class="doc-toc-link doc-toc-folder doc-indent-${indent}" data-doc-open="folder:${escapeHtml(node.path)}">${escapeHtml(node.path ? node.name + '/' : '(repo root)')}</button>`);
152
+ const files = node.files.filter((f) => parsedSet.has(f)).slice(0, 10);
153
+ if (files.length) {
154
+ const links = files
155
+ .map((f) => `<button class="doc-toc-link" data-doc-open="file:${escapeHtml(f)}">${escapeHtml(f.split('/').pop())}</button>`)
156
+ .join('<span class="doc-toc-sep"> · </span>');
157
+ bits.push(`<span class="doc-toc-files doc-indent-${indent}">${links}${node.files.length > files.length ? ' …' : ''}</span>`);
158
+ }
159
+ for (const child of [...node.dirs.values()].sort((a, b) => a.name.localeCompare(b.name))) {
160
+ walk(child, depth + 1);
161
+ }
162
+ };
163
+ if (root.files.length)
164
+ walk({ ...root, dirs: new Map() }, 0);
165
+ for (const child of [...root.dirs.values()].sort((a, b) => a.name.localeCompare(b.name))) {
166
+ walk(child, 0);
174
167
  }
175
- };
176
- if (root.files.length) walk({ ...root, dirs: new Map() }, 0);
177
- for (const child of [...root.dirs.values()].sort((a, b) => a.name.localeCompare(b.name))) {
178
- walk(child, 0);
179
- }
180
- toc.innerHTML = bits.join('');
168
+ toc.innerHTML = bits.join('');
181
169
  }
182
-
183
170
  async function loadReadme() {
184
- const box = host.querySelector('#docReadme');
185
- if (!box) return;
186
- for (const name of ['README.md', 'readme.md', 'Readme.md', 'README', 'README.txt']) {
187
- try {
188
- const text = await readRepoFile(name);
189
- if (text) {
190
- box.innerHTML = mdRender(text);
171
+ const box = host.querySelector('#docReadme');
172
+ if (!box)
191
173
  return;
192
- }
193
- } catch {
194
- /* try the next spelling */
174
+ for (const name of ['README.md', 'readme.md', 'Readme.md', 'README', 'README.txt']) {
175
+ try {
176
+ const text = await readRepoFile(name);
177
+ if (text) {
178
+ box.innerHTML = mdRender(text);
179
+ return;
180
+ }
181
+ }
182
+ catch {
183
+ /* try the next spelling */
184
+ }
195
185
  }
196
- }
197
- box.innerHTML = '<span class="doc-readme-none">This repo ships no README — the map and the patterns are all you get.</span>';
186
+ box.innerHTML = '<span class="doc-readme-none">This repo ships no README — the map and the patterns are all you get.</span>';
198
187
  }
199
-
200
188
  // ---- the sticky ask bar: questions scoped to the doc on screen -------------
201
-
202
189
  async function askAboutRepo() {
203
- const input = host.querySelector('#docAskInput');
204
- const question = input?.value.trim();
205
- if (!question) return hooks.onToast('Type a question first.');
206
- if (!llm.isConfigured()) {
207
- hooks.onOpenSettings();
208
- hooks.onToast('Add an endpoint and model first.');
209
- return;
210
- }
211
- input.value = '';
212
- const rail = state.docs.railEl;
213
- rail.hidden = false;
214
- // reveal the clear/close controls now that a conversation exists
215
- const bar = state.docs.bar;
216
- if (bar) {
217
- const c = bar.querySelector('.doc-clear');
218
- const x = bar.querySelector('.doc-close');
219
- if (c) c.hidden = false;
220
- if (x) x.hidden = false;
221
- }
222
- const settings = llm.getSettings();
223
-
224
- const card = document.createElement('div');
225
- card.className = 'doc-qa-card';
226
- card.innerHTML = `<p class="doc-qa-q">“${escapeHtml(question)}”</p><div class="doc-qa-a"><span class="caret"></span></div>`;
227
- rail.appendChild(card);
228
- card.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
229
-
230
- // Scope the answer to whatever is on screen: an open file/folder doc tab
231
- // gets its facts (and source, for files) sent along; the overview answers
232
- // from the repo-wide picture.
233
- const active = state.docs.active || 'overview';
234
- let file = null;
235
- let scope = 'the repo overview';
236
- let overview = hooks.repoOverview() + ' Top-level folders: ' + [...state.treeData.dirs.keys()].join(', ') + '.';
237
- if (active.startsWith('file:')) {
238
- const path = active.slice(5);
239
- file = await gatherFileContext(path);
240
- scope = path;
241
- } else if (active.startsWith('folder:')) {
242
- scope = active.slice(7) + '/';
243
- overview += ` The user is currently reading the documentation for the folder "${active.slice(7)}".`;
244
- }
245
-
246
- const messages = llm.questionMessages({ repoName: state.scan.name, overview, question, file });
247
- let text = '';
248
- try {
249
- for await (const delta of streamExplain({ ...settings, messages, maxTokens: 1200 })) {
250
- text += delta;
251
- card.querySelector('.doc-qa-a').innerHTML = mdLite(text) + '<span class="caret"></span>';
190
+ const input = host.querySelector('#docAskInput');
191
+ const question = input?.value.trim();
192
+ if (!question)
193
+ return hooks.onToast('Type a question first.');
194
+ if (!llm.isConfigured()) {
195
+ hooks.onOpenSettings();
196
+ hooks.onToast('Choose Hermes or an endpoint in AI connection first.');
197
+ return;
198
+ }
199
+ input.value = '';
200
+ const rail = state.docs.railEl;
201
+ rail.hidden = false;
202
+ // reveal the clear/close controls now that a conversation exists
203
+ const bar = state.docs.bar;
204
+ if (bar) {
205
+ const c = bar.querySelector('.doc-clear');
206
+ const x = bar.querySelector('.doc-close');
207
+ if (c)
208
+ c.hidden = false;
209
+ if (x)
210
+ x.hidden = false;
211
+ }
212
+ const settings = llm.getSettings();
213
+ const card = document.createElement('div');
214
+ card.className = 'doc-qa-card';
215
+ card.innerHTML = `<p class="doc-qa-q">“${escapeHtml(question)}”</p><div class="doc-qa-a"><span class="caret"></span></div>`;
216
+ rail.appendChild(card);
217
+ card.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
218
+ // Scope the answer to whatever is on screen: an open file/folder doc tab
219
+ // gets its facts (and source, for files) sent along; the overview answers
220
+ // from the repo-wide picture.
221
+ const active = state.docs.active || 'overview';
222
+ let file = null;
223
+ let scope = 'the repo overview';
224
+ let overview = hooks.repoOverview() + ' Top-level folders: ' + [...state.treeData.dirs.keys()].join(', ') + '.';
225
+ if (active.startsWith('file:')) {
226
+ const path = active.slice(5);
227
+ file = await gatherFileContext(path);
228
+ scope = path;
229
+ }
230
+ else if (active.startsWith('folder:')) {
231
+ scope = active.slice(7) + '/';
232
+ overview += ` The user is currently reading the documentation for the folder "${active.slice(7)}".`;
233
+ }
234
+ const messages = llm.questionMessages({ repoName: state.scan.name, overview, question, file });
235
+ let text = '';
236
+ try {
237
+ for await (const delta of streamExplain({ ...settings, messages, maxTokens: 1200 })) {
238
+ text += delta;
239
+ card.querySelector('.doc-qa-a').innerHTML = mdLite(text) + '<span class="caret"></span>';
240
+ }
241
+ card.querySelector('.doc-qa-a').innerHTML =
242
+ mdLite(text) + `<p class="explain-src">Answered by ${escapeHtml(settings.model)}, looking at ${escapeHtml(scope)}.</p>`;
243
+ }
244
+ catch (err) {
245
+ card.querySelector('.doc-qa-a').innerHTML =
246
+ `<p style="color:var(--warn)">${escapeHtml(err.message)} — check the AI connection drawer, top right.</p>`;
252
247
  }
253
- card.querySelector('.doc-qa-a').innerHTML =
254
- mdLite(text) + `<p class="explain-src">Answered by ${settings.model}, looking at ${escapeHtml(scope)}.</p>`;
255
- } catch (err) {
256
- card.querySelector('.doc-qa-a').innerHTML =
257
- `<p style="color:var(--warn)">${escapeHtml(err.message)} — check the API key drawer, top right.</p>`;
258
- }
259
248
  }
260
-
261
249
  // ---- doc tabs: detailed AI documents per file/folder -----------------------
262
-
263
250
  function renderDocStrip() {
264
- const strip = state.docs.tabsEl;
265
- if (!strip) return;
266
- strip.innerHTML = '';
267
-
268
- const mk = (key, label, closable) => {
269
- const b = document.createElement('button');
270
- b.className = 'doc-tab' + (state.docs.active === key ? ' is-active' : '');
271
- const entry = state.docs.tabs.get(key);
272
- b.innerHTML = `<span>${escapeHtml(label)}</span>${entry?.status === 'writing' ? '<span class="doc-tab-spin">…</span>' : ''}`;
273
- b.addEventListener('click', () => {
274
- state.docs.active = key;
275
- renderDocStrip();
276
- showActiveDoc();
277
- });
278
- if (closable) {
279
- const x = document.createElement('span');
280
- x.className = 'doc-tab-x';
281
- x.textContent = '×';
282
- x.title = 'Close this tab';
283
- x.addEventListener('click', (event) => {
284
- event.stopPropagation();
285
- closeDocTab(key);
286
- });
287
- b.appendChild(x);
251
+ const strip = state.docs.tabsEl;
252
+ if (!strip)
253
+ return;
254
+ strip.innerHTML = '';
255
+ const mk = (key, label, closable) => {
256
+ const b = document.createElement('button');
257
+ b.className = 'doc-tab' + (state.docs.active === key ? ' is-active' : '');
258
+ const entry = state.docs.tabs.get(key);
259
+ b.innerHTML = `<span>${escapeHtml(label)}</span>${entry?.status === 'writing' ? '<span class="doc-tab-spin">…</span>' : ''}`;
260
+ b.addEventListener('click', () => {
261
+ state.docs.active = key;
262
+ renderDocStrip();
263
+ showActiveDoc();
264
+ });
265
+ if (closable) {
266
+ const x = document.createElement('span');
267
+ x.className = 'doc-tab-x';
268
+ x.textContent = '×';
269
+ x.title = 'Close this tab';
270
+ x.addEventListener('click', (event) => {
271
+ event.stopPropagation();
272
+ closeDocTab(key);
273
+ });
274
+ b.appendChild(x);
275
+ }
276
+ return b;
277
+ };
278
+ strip.appendChild(mk('overview', 'Overview', false));
279
+ for (const [key, entry] of state.docs.tabs) {
280
+ strip.appendChild(mk(key, entry.title, true));
288
281
  }
289
- return b;
290
- };
291
-
292
- strip.appendChild(mk('overview', 'Overview', false));
293
- for (const [key, entry] of state.docs.tabs) {
294
- strip.appendChild(mk(key, entry.title, true));
295
- }
296
282
  }
297
-
298
283
  function openDocTab(kind, path) {
299
- const key = kind + ':' + path;
300
- if (!state.docs.tabs.has(key)) {
301
- const title = (path ? path.split('/').pop() : '(root)') + (kind === 'folder' ? '/' : '');
302
- state.docs.tabs.set(key, { key, kind, path, title, status: 'idle', text: '', error: '' });
303
- }
304
- state.docs.active = key;
305
- renderDocStrip();
306
- showActiveDoc();
307
- const entry = state.docs.tabs.get(key);
308
- if (entry.status === 'idle') generateDocTab(entry);
284
+ const key = kind + ':' + path;
285
+ if (!state.docs.tabs.has(key)) {
286
+ const title = (path ? path.split('/').pop() : '(root)') + (kind === 'folder' ? '/' : '');
287
+ state.docs.tabs.set(key, { key, kind, path, title, status: 'idle', text: '', error: '' });
288
+ }
289
+ state.docs.active = key;
290
+ renderDocStrip();
291
+ showActiveDoc();
292
+ const entry = state.docs.tabs.get(key);
293
+ if (entry.status === 'idle')
294
+ generateDocTab(entry);
309
295
  }
310
-
311
296
  function closeDocTab(key) {
312
- state.docs.tabs.delete(key);
313
- if (state.docs.active === key) state.docs.active = 'overview';
314
- renderDocStrip();
315
- showActiveDoc();
297
+ state.docs.tabs.delete(key);
298
+ if (state.docs.active === key)
299
+ state.docs.active = 'overview';
300
+ renderDocStrip();
301
+ showActiveDoc();
316
302
  }
317
-
318
303
  function showActiveDoc() {
319
- const wrap = state.docs.wrapEl;
320
- if (!wrap) return;
321
- if (state.docs.active === 'overview') {
322
- wrap.replaceChildren(state.docs.pageEl);
323
- return;
324
- }
325
- const entry = state.docs.tabs.get(state.docs.active);
326
- if (entry) wrap.replaceChildren(buildPaneEl(entry));
304
+ const wrap = state.docs.wrapEl;
305
+ if (!wrap)
306
+ return;
307
+ if (state.docs.active === 'overview') {
308
+ wrap.replaceChildren(state.docs.pageEl);
309
+ return;
310
+ }
311
+ const entry = state.docs.tabs.get(state.docs.active);
312
+ if (entry)
313
+ wrap.replaceChildren(buildPaneEl(entry));
327
314
  }
328
-
329
315
  function buildPaneEl(entry) {
330
- const pane = document.createElement('div');
331
- pane.className = 'doc-page doc-detail';
332
-
333
- const chips = [];
334
- if (entry.kind === 'file') {
335
- const f = scanIndex(state.scan).fileAt(entry.path);
336
- const fin = state.facts.fanIn[entry.path] || 0;
337
- const fout = state.facts.fanOut[entry.path] || 0;
338
- chips.push(`<b>${fin}</b> dependents`, `<b>${fout}</b> imports`);
339
- if (f) chips.push(`<b>${f.functions.length}</b> functions`, `<b>${(f.size / 1024).toFixed(1)}</b> kb`);
340
- } else {
341
- const node = findNode(state.treeData, entry.path);
342
- if (node) chips.push(`<b>${node.files.length}</b> files`, `<b>${node.dirs.size}</b> subfolders`);
343
- }
344
-
345
- pane.innerHTML = `
316
+ const pane = document.createElement('div');
317
+ pane.className = 'doc-page doc-detail';
318
+ const chips = [];
319
+ if (entry.kind === 'file') {
320
+ const f = scanIndex(state.scan).fileAt(entry.path);
321
+ const fin = state.facts.fanIn[entry.path] || 0;
322
+ const fout = state.facts.fanOut[entry.path] || 0;
323
+ chips.push(`<b>${fin}</b> dependents`, `<b>${fout}</b> imports`);
324
+ if (f)
325
+ chips.push(`<b>${f.functions.length}</b> functions`, `<b>${(f.size / 1024).toFixed(1)}</b> kb`);
326
+ }
327
+ else {
328
+ const node = findNode(state.treeData, entry.path);
329
+ if (node)
330
+ chips.push(`<b>${node.files.length}</b> files`, `<b>${node.dirs.size}</b> subfolders`);
331
+ }
332
+ pane.innerHTML = `
346
333
  <h1 class="doc-title">${escapeHtml(entry.title)}</h1>
347
334
  <p class="doc-sub">${escapeHtml(entry.path || '(repo root)')}</p>
348
335
  <p class="doc-sub doc-detail-meta">${chips.join(' &nbsp;·&nbsp; ')}</p>
@@ -352,168 +339,172 @@ function buildPaneEl(entry) {
352
339
  </div>
353
340
  <div class="doc-detail-body"></div>
354
341
  `;
355
-
356
- const body = pane.querySelector('.doc-detail-body');
357
- if (entry.status === 'error') {
358
- body.innerHTML = `<p style="color:var(--warn)">${escapeHtml(entry.error)} — hit Regenerate to try again.</p>`;
359
- } else if (entry.status === 'idle' || (entry.status === 'writing' && !entry.text)) {
360
- // The static write-up is the floor: something true is on screen before the
361
- // model answers, and stays there if it never does.
362
- const fallback = entry.kind === 'file'
363
- ? staticDoc(entry.path)
364
- : folderStaticDoc(entry.path, state.scan, state.facts, findNode(state.treeData, entry.path)?.dirs.size || 0);
365
- body.innerHTML = `<p>${escapeHtml(fallback)}</p>`
366
- + '<p class="doc-readme-none">Gathering facts and writing<span class="caret"></span></p>';
367
- } else {
368
- body.innerHTML = mdRender(entry.text) + (entry.status === 'writing' ? '<span class="caret"></span>' : '');
369
- }
370
-
371
- pane.addEventListener('click', (event) => {
372
- if (event.target.closest('[data-doc-dd]')) hooks.onOpenFile(entry.path);
373
- if (event.target.closest('[data-doc-regen]')) {
374
- entry.status = 'idle';
375
- entry.text = '';
376
- generateDocTab(entry);
377
- showActiveDoc();
342
+ const body = pane.querySelector('.doc-detail-body');
343
+ if (entry.status === 'error') {
344
+ body.innerHTML = `<p style="color:var(--warn)">${escapeHtml(entry.error)} — hit Regenerate to try again.</p>`;
378
345
  }
379
- });
380
- return pane;
346
+ else if (entry.status === 'idle' || (entry.status === 'writing' && !entry.text)) {
347
+ // The static write-up is the floor: something true is on screen before the
348
+ // model answers, and stays there if it never does.
349
+ const fallback = entry.kind === 'file'
350
+ ? staticDoc(entry.path)
351
+ : folderStaticDoc(entry.path, state.scan, state.facts, findNode(state.treeData, entry.path)?.dirs.size || 0);
352
+ body.innerHTML = `<p>${escapeHtml(fallback)}</p>`
353
+ + '<p class="doc-readme-none">Gathering facts and writing<span class="caret"></span></p>';
354
+ }
355
+ else {
356
+ body.innerHTML = mdRender(entry.text) + (entry.status === 'writing' ? '<span class="caret"></span>' : '');
357
+ }
358
+ pane.addEventListener('click', (event) => {
359
+ if (eventElement(event)?.closest('[data-doc-dd]'))
360
+ hooks.onOpenFile(entry.path);
361
+ if (eventElement(event)?.closest('[data-doc-regen]')) {
362
+ entry.status = 'idle';
363
+ entry.text = '';
364
+ generateDocTab(entry);
365
+ showActiveDoc();
366
+ }
367
+ });
368
+ return pane;
381
369
  }
382
-
383
370
  let docRefreshTimer = null;
384
371
  function scheduleDocPaneRefresh(entry) {
385
- if (state.docs.active !== entry.key || docRefreshTimer) return;
386
- docRefreshTimer = setTimeout(() => {
387
- docRefreshTimer = null;
388
- if (state.docs.active === entry.key) showActiveDoc();
389
- }, 160);
372
+ if (state.docs.active !== entry.key || docRefreshTimer)
373
+ return;
374
+ docRefreshTimer = setTimeout(() => {
375
+ docRefreshTimer = null;
376
+ if (state.docs.active === entry.key)
377
+ showActiveDoc();
378
+ }, 160);
390
379
  }
391
-
392
380
  async function generateDocTab(entry) {
393
- if (!llm.isConfigured()) {
394
- entry.status = 'error';
395
- entry.error = 'No endpoint configured — open the API key drawer, top right.';
396
- showActiveDoc();
381
+ if (!llm.isConfigured()) {
382
+ entry.status = 'error';
383
+ entry.error = 'No AI connection configured — open the AI connection drawer, top right.';
384
+ showActiveDoc();
385
+ renderDocStrip();
386
+ hooks.onOpenSettings();
387
+ return;
388
+ }
389
+ const settings = llm.getSettings();
390
+ entry.status = 'writing';
391
+ entry.text = '';
392
+ entry.error = '';
397
393
  renderDocStrip();
398
- hooks.onOpenSettings();
399
- return;
400
- }
401
- const settings = llm.getSettings();
402
- entry.status = 'writing';
403
- entry.text = '';
404
- entry.error = '';
405
- renderDocStrip();
406
- try {
407
- let messages;
408
- if (entry.kind === 'file') {
409
- const ctx = await gatherFileContext(entry.path);
410
- messages = llm.fileDocMessages({ repoName: state.scan.name, overview: hooks.repoOverview(), file: ctx });
411
- } else {
412
- const node = findNode(state.treeData, entry.path);
413
- messages = llm.folderDocDetailedMessages({
414
- repoName: state.scan.name,
415
- folder: entry.path,
416
- subfolders: node ? [...node.dirs.keys()].map((n) => n + '/') : [],
417
- files: (node?.files || []).slice(0, 18).map(fileRow),
418
- });
394
+ try {
395
+ let messages;
396
+ if (entry.kind === 'file') {
397
+ const ctx = await gatherFileContext(entry.path);
398
+ messages = llm.fileDocMessages({ repoName: state.scan.name, overview: hooks.repoOverview(), file: ctx });
399
+ }
400
+ else {
401
+ const node = findNode(state.treeData, entry.path);
402
+ messages = llm.folderDocDetailedMessages({
403
+ repoName: state.scan.name,
404
+ folder: entry.path,
405
+ subfolders: node ? [...node.dirs.keys()].map((n) => n + '/') : [],
406
+ files: (node?.files || []).slice(0, 18).map(fileRow),
407
+ });
408
+ }
409
+ for await (const delta of streamExplain({ ...settings, messages, maxTokens: 1800 })) {
410
+ entry.text += delta;
411
+ scheduleDocPaneRefresh(entry);
412
+ }
413
+ entry.status = 'done';
419
414
  }
420
- for await (const delta of streamExplain({ ...settings, messages, maxTokens: 1800 })) {
421
- entry.text += delta;
422
- scheduleDocPaneRefresh(entry);
415
+ catch (err) {
416
+ entry.status = 'error';
417
+ entry.error = err.message;
423
418
  }
424
- entry.status = 'done';
425
- } catch (err) {
426
- entry.status = 'error';
427
- entry.error = err.message;
428
- }
429
- renderDocStrip();
430
- if (state.docs.active === entry.key) showActiveDoc();
419
+ renderDocStrip();
420
+ if (state.docs.active === entry.key)
421
+ showActiveDoc();
431
422
  }
432
-
433
423
  // ---- the folder-by-folder pass --------------------------------------------
434
-
435
424
  // Which folders get an AI brief, and with what file facts. Top-level folders
436
425
  // by size, capped — one call briefs a folder and everything directly in it.
437
426
  function docTargets() {
438
- const root = state.treeData;
439
- const targets = [];
440
- if (root.files.length) {
441
- targets.push({
442
- path: '',
443
- label: '(repo root)',
444
- subfolders: [...root.dirs.keys()].map((n) => n + '/'),
445
- files: root.files.slice(0, 18).map(fileRow),
446
- });
447
- }
448
- const topDirs = [...root.dirs.values()]
449
- .map((node) => ({ node, count: countFiles(node) }))
450
- .sort((a, b) => b.count - a.count)
451
- .slice(0, 8);
452
- for (const { node } of topDirs) {
453
- targets.push({
454
- path: node.path,
455
- label: node.path + '/',
456
- subfolders: [...node.dirs.keys()].map((n) => n + '/'),
457
- files: node.files.slice(0, 18).map(fileRow),
458
- });
459
- }
460
- return targets;
427
+ const root = state.treeData;
428
+ const targets = [];
429
+ if (root.files.length) {
430
+ targets.push({
431
+ path: '',
432
+ label: '(repo root)',
433
+ subfolders: [...root.dirs.keys()].map((n) => n + '/'),
434
+ files: root.files.slice(0, 18).map(fileRow),
435
+ });
436
+ }
437
+ const topDirs = [...root.dirs.values()]
438
+ .map((node) => ({ node, count: countFiles(node) }))
439
+ .sort((a, b) => b.count - a.count)
440
+ .slice(0, 8);
441
+ for (const { node } of topDirs) {
442
+ targets.push({
443
+ path: node.path,
444
+ label: node.path + '/',
445
+ subfolders: [...node.dirs.keys()].map((n) => n + '/'),
446
+ files: node.files.slice(0, 18).map(fileRow),
447
+ });
448
+ }
449
+ return targets;
461
450
  }
462
-
463
451
  async function writeDocsWithAI() {
464
- if (state.docs.writing) return;
465
- if (!llm.isConfigured()) {
466
- hooks.onOpenSettings();
467
- hooks.onToast('Add an endpoint and model first.');
468
- return;
469
- }
470
- const settings = llm.getSettings();
471
- const page = state.docs.pageEl;
472
- const zone = page?.querySelector('#docGenZone');
473
- const btn = page?.querySelector('#docGenBtn');
474
- const note = page?.querySelector('#docAiNote');
475
- const overviewEl = page?.querySelector('#docOverview');
476
- if (!zone) return;
477
-
478
- state.docs.writing = true;
479
- if (btn) {
480
- btn.disabled = true;
481
- btn.textContent = 'writing…';
482
- }
483
- zone.querySelectorAll('.doc-generated').forEach((el) => el.remove()); // regenerate = fresh page
484
- const empty = zone.querySelector('.doc-gen-empty');
485
- if (empty) empty.hidden = true;
486
-
487
- try {
488
- // 1. The repo-level overview, streamed in place.
489
- if (note) note.textContent = 'Writing the overview…';
490
- const readmeText = host.querySelector('#docReadme')?.innerText?.slice(0, 1500) || '';
491
- let out = '';
492
- if (overviewEl) overviewEl.innerHTML = '<span class="caret"></span>';
493
- const overviewMsgs = llm.repoDocMessages({
494
- repoName: state.scan.name,
495
- overview: hooks.repoOverview(),
496
- readmeExcerpt: readmeText,
497
- entries: state.facts.entries,
498
- hubs: state.facts.hubs,
499
- });
500
- for await (const delta of streamExplain({ ...settings, messages: overviewMsgs, maxTokens: 900 })) {
501
- out += delta;
502
- if (overviewEl) overviewEl.textContent = out;
452
+ if (state.docs.writing)
453
+ return;
454
+ if (!llm.isConfigured()) {
455
+ hooks.onOpenSettings();
456
+ hooks.onToast('Choose Hermes or an endpoint in AI connection first.');
457
+ return;
503
458
  }
504
-
505
- // 2. Folder by folder: each section appears with static sentences first,
506
- // then the AI's documentation overwrites it as the answer lands.
507
- const targets = docTargets();
508
- let done = 0;
509
- for (const t of targets) {
510
- done++;
511
- if (note) note.textContent = `Writing documentation… ${done} of ${targets.length} — ${t.label}`;
512
-
513
- const node = findNode(state.treeData, t.path);
514
- const section = document.createElement('section');
515
- section.className = 'doc-folder doc-generated';
516
- section.innerHTML = `
459
+ const settings = llm.getSettings();
460
+ const page = state.docs.pageEl;
461
+ const zone = page?.querySelector('#docGenZone');
462
+ const btn = page?.querySelector('#docGenBtn');
463
+ const note = page?.querySelector('#docAiNote');
464
+ const overviewEl = page?.querySelector('#docOverview');
465
+ if (!zone)
466
+ return;
467
+ state.docs.writing = true;
468
+ if (btn) {
469
+ btn.disabled = true;
470
+ btn.textContent = 'writing…';
471
+ }
472
+ zone.querySelectorAll('.doc-generated').forEach((el) => el.remove()); // regenerate = fresh page
473
+ const empty = zone.querySelector('.doc-gen-empty');
474
+ if (empty)
475
+ empty.hidden = true;
476
+ try {
477
+ // 1. The repo-level overview, streamed in place.
478
+ if (note)
479
+ note.textContent = 'Writing the overview…';
480
+ const readmeText = host.querySelector('#docReadme')?.innerText?.slice(0, 1500) || '';
481
+ let out = '';
482
+ if (overviewEl)
483
+ overviewEl.innerHTML = '<span class="caret"></span>';
484
+ const overviewMsgs = llm.repoDocMessages({
485
+ repoName: state.scan.name,
486
+ overview: hooks.repoOverview(),
487
+ readmeExcerpt: readmeText,
488
+ entries: state.facts.entries,
489
+ hubs: state.facts.hubs,
490
+ });
491
+ for await (const delta of streamExplain({ ...settings, messages: overviewMsgs, maxTokens: 900 })) {
492
+ out += delta;
493
+ if (overviewEl)
494
+ overviewEl.textContent = out;
495
+ }
496
+ // 2. Folder by folder: each section appears with static sentences first,
497
+ // then the AI's documentation overwrites it as the answer lands.
498
+ const targets = docTargets();
499
+ let done = 0;
500
+ for (const t of targets) {
501
+ done++;
502
+ if (note)
503
+ note.textContent = `Writing documentation… ${done} of ${targets.length} — ${t.label}`;
504
+ const node = findNode(state.treeData, t.path);
505
+ const section = document.createElement('section');
506
+ section.className = 'doc-folder doc-generated';
507
+ section.innerHTML = `
517
508
  <h3 class="doc-folder-h"><button data-doc-open="folder:${escapeHtml(t.path)}">${escapeHtml(t.label)}</button></h3>
518
509
  <p class="doc-folder-brief"><span class="caret"></span></p>
519
510
  ${t.files.map((f) => `
@@ -525,42 +516,50 @@ async function writeDocsWithAI() {
525
516
  <p class="doc-entry-text" data-doc-file="${escapeHtml(f.path)}">${escapeHtml(staticDoc(f.path))}</p>
526
517
  </div>`).join('')}
527
518
  `;
528
- zone.appendChild(section);
529
- section.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
530
-
531
- let text = '';
532
- const msgs = llm.folderDocMessages({
533
- repoName: state.scan.name,
534
- folder: t.path,
535
- subfolders: t.subfolders,
536
- files: t.files,
537
- });
538
- for await (const delta of streamExplain({ ...settings, messages: msgs, maxTokens: 1600 })) {
539
- text += delta;
540
- }
541
- const parsed = parseFolderDoc(text);
542
- const folderP = section.querySelector('.doc-folder-brief');
543
- if (folderP) {
544
- folderP.textContent = parsed.folderBrief
545
- || folderStaticDoc(t.path, state.scan, state.facts, node?.dirs.size || 0);
546
- }
547
- for (const [name, brief] of parsed.files) {
548
- const row = t.files.find((f) => f.name === name);
549
- if (!row) continue;
550
- const el = section.querySelector(`[data-doc-file="${CSS.escape(row.path)}"]`);
551
- if (el) el.textContent = brief;
552
- }
519
+ zone.appendChild(section);
520
+ section.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
521
+ let text = '';
522
+ const msgs = llm.folderDocMessages({
523
+ repoName: state.scan.name,
524
+ folder: t.path,
525
+ subfolders: t.subfolders,
526
+ files: t.files,
527
+ });
528
+ for await (const delta of streamExplain({ ...settings, messages: msgs, maxTokens: 1600 })) {
529
+ text += delta;
530
+ }
531
+ const parsed = parseFolderDoc(text);
532
+ const folderP = section.querySelector('.doc-folder-brief');
533
+ if (folderP) {
534
+ folderP.textContent = parsed.folderBrief
535
+ || folderStaticDoc(t.path, state.scan, state.facts, node?.dirs.size || 0);
536
+ }
537
+ for (const [name, brief] of parsed.files) {
538
+ const row = t.files.find((f) => f.name === name);
539
+ if (!row)
540
+ continue;
541
+ const el = section.querySelector(`[data-doc-file="${CSS.escape(row.path)}"]`);
542
+ if (el)
543
+ el.textContent = brief;
544
+ }
545
+ }
546
+ if (note)
547
+ note.textContent = `Written by ${escapeHtml(settings.model)} from the real import graph. Press “Regenerate documentation” for a fresh take.`;
548
+ if (btn)
549
+ btn.textContent = 'Regenerate documentation';
553
550
  }
554
- if (note) note.textContent = `Written by ${settings.model} from the real import graph. Press “Regenerate documentation” for a fresh take.`;
555
- if (btn) btn.textContent = 'Regenerate documentation';
556
- } catch (err) {
557
- if (note) note.textContent = 'AI writing stopped: ' + err.message;
558
- hooks.onToast(err.message);
559
- } finally {
560
- state.docs.writing = false;
561
- if (btn) {
562
- btn.disabled = false;
563
- if (btn.textContent === 'writing…') btn.textContent = 'Generate documentation';
551
+ catch (err) {
552
+ if (note)
553
+ note.textContent = 'AI writing stopped: ' + err.message;
554
+ hooks.onToast(err.message);
555
+ }
556
+ finally {
557
+ state.docs.writing = false;
558
+ if (btn) {
559
+ btn.disabled = false;
560
+ if (btn.textContent === 'writing…')
561
+ btn.textContent = 'Generate documentation';
562
+ }
564
563
  }
565
- }
566
564
  }
565
+ //# sourceMappingURL=docsView.js.map