codebase-onboarder 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/README.md +196 -47
  2. package/bin/build-if-source.js +23 -0
  3. package/cli/commands.d.ts +26 -0
  4. package/cli/commands.js +836 -811
  5. package/cli/commands.js.map +1 -0
  6. package/cli/explorer/advanced.d.ts +14 -0
  7. package/cli/explorer/advanced.js +449 -0
  8. package/cli/explorer/advanced.js.map +1 -0
  9. package/cli/explorer/app.d.ts +1 -0
  10. package/cli/explorer/app.js +396 -229
  11. package/cli/explorer/app.js.map +1 -0
  12. package/cli/explorer/assistant.d.ts +9 -0
  13. package/cli/explorer/assistant.js +58 -0
  14. package/cli/explorer/assistant.js.map +1 -0
  15. package/cli/explorer/commands.d.ts +17 -0
  16. package/cli/explorer/commands.js +400 -162
  17. package/cli/explorer/commands.js.map +1 -0
  18. package/cli/explorer/featureViews.d.ts +124 -0
  19. package/cli/explorer/featureViews.js +179 -0
  20. package/cli/explorer/featureViews.js.map +1 -0
  21. package/cli/explorer/github.d.ts +21 -0
  22. package/cli/explorer/github.js +73 -0
  23. package/cli/explorer/github.js.map +1 -0
  24. package/cli/explorer/graphs.d.ts +7 -0
  25. package/cli/explorer/graphs.js +173 -0
  26. package/cli/explorer/graphs.js.map +1 -0
  27. package/cli/explorer/picker.d.ts +22 -0
  28. package/cli/explorer/picker.js +150 -0
  29. package/cli/explorer/picker.js.map +1 -0
  30. package/cli/explorer/report.d.ts +85 -0
  31. package/cli/explorer/report.js +60 -0
  32. package/cli/explorer/report.js.map +1 -0
  33. package/cli/explorer/session.d.ts +449 -0
  34. package/cli/explorer/session.js +184 -95
  35. package/cli/explorer/session.js.map +1 -0
  36. package/cli/explorer/views.d.ts +19 -0
  37. package/cli/explorer/views.js +496 -412
  38. package/cli/explorer/views.js.map +1 -0
  39. package/cli/explorer/wrap.d.ts +1 -0
  40. package/cli/explorer/wrap.js +33 -0
  41. package/cli/explorer/wrap.js.map +1 -0
  42. package/cli/main.d.ts +1 -0
  43. package/cli/main.js +235 -138
  44. package/cli/main.js.map +1 -0
  45. package/cli/prompt.d.ts +5 -0
  46. package/cli/prompt.js +84 -80
  47. package/cli/prompt.js.map +1 -0
  48. package/cli/scanOptions.d.ts +2 -0
  49. package/cli/scanOptions.js +11 -0
  50. package/cli/scanOptions.js.map +1 -0
  51. package/cli/ui.d.ts +33 -0
  52. package/cli/ui.js +55 -35
  53. package/cli/ui.js.map +1 -0
  54. package/cli/wizard.d.ts +187 -0
  55. package/cli/wizard.js +304 -284
  56. package/cli/wizard.js.map +1 -0
  57. package/package.json +15 -4
  58. package/public/app.d.ts +1 -0
  59. package/public/app.js +1057 -1009
  60. package/public/app.js.map +1 -0
  61. package/public/browser.d.ts +68 -0
  62. package/public/browser.js +2 -0
  63. package/public/browser.js.map +1 -0
  64. package/public/index.html +30 -13
  65. package/public/js/about.d.ts +6 -0
  66. package/public/js/about.js +165 -172
  67. package/public/js/about.js.map +1 -0
  68. package/public/js/aiDraft.d.ts +3 -0
  69. package/public/js/aiDraft.js +116 -124
  70. package/public/js/aiDraft.js.map +1 -0
  71. package/public/js/analysisPanel.d.ts +7 -0
  72. package/public/js/analysisPanel.js +166 -166
  73. package/public/js/analysisPanel.js.map +1 -0
  74. package/public/js/analysisReport.d.ts +38 -0
  75. package/public/js/analysisReport.js +105 -110
  76. package/public/js/analysisReport.js.map +1 -0
  77. package/public/js/api.d.ts +26 -0
  78. package/public/js/api.js +176 -167
  79. package/public/js/api.js.map +1 -0
  80. package/public/js/atlas.d.ts +6 -0
  81. package/public/js/atlas.js +50 -58
  82. package/public/js/atlas.js.map +1 -0
  83. package/public/js/blameView.d.ts +2 -0
  84. package/public/js/blameView.js +36 -37
  85. package/public/js/blameView.js.map +1 -0
  86. package/public/js/codeTab.d.ts +3 -0
  87. package/public/js/codeTab.js +175 -180
  88. package/public/js/codeTab.js.map +1 -0
  89. package/public/js/codeViewer.d.ts +5 -0
  90. package/public/js/codeViewer.js +162 -150
  91. package/public/js/codeViewer.js.map +1 -0
  92. package/public/js/components/FileChip.d.ts +9 -0
  93. package/public/js/components/FileChip.js +45 -49
  94. package/public/js/components/FileChip.js.map +1 -0
  95. package/public/js/components/MetricSparkline.d.ts +7 -0
  96. package/public/js/components/MetricSparkline.js +35 -44
  97. package/public/js/components/MetricSparkline.js.map +1 -0
  98. package/public/js/components/RiskBadge.d.ts +9 -0
  99. package/public/js/components/RiskBadge.js +55 -63
  100. package/public/js/components/RiskBadge.js.map +1 -0
  101. package/public/js/deepAnalysisView.d.ts +99 -0
  102. package/public/js/deepAnalysisView.js +282 -302
  103. package/public/js/deepAnalysisView.js.map +1 -0
  104. package/public/js/diagramPane.d.ts +8 -0
  105. package/public/js/diagramPane.js +133 -135
  106. package/public/js/diagramPane.js.map +1 -0
  107. package/public/js/diffView.d.ts +6 -0
  108. package/public/js/diffView.js +222 -209
  109. package/public/js/diffView.js.map +1 -0
  110. package/public/js/docsView.d.ts +2 -0
  111. package/public/js/docsView.js +441 -442
  112. package/public/js/docsView.js.map +1 -0
  113. package/public/js/dom.d.ts +189 -0
  114. package/public/js/dom.js +5 -0
  115. package/public/js/dom.js.map +1 -0
  116. package/public/js/fileSourceBrowser.d.ts +5 -0
  117. package/public/js/fileSourceBrowser.js +33 -41
  118. package/public/js/fileSourceBrowser.js.map +1 -0
  119. package/public/js/flameGraph.d.ts +5 -0
  120. package/public/js/flameGraph.js +62 -72
  121. package/public/js/flameGraph.js.map +1 -0
  122. package/public/js/forceGraph.d.ts +10 -0
  123. package/public/js/forceGraph.js +581 -556
  124. package/public/js/forceGraph.js.map +1 -0
  125. package/public/js/heatmap.d.ts +4 -0
  126. package/public/js/heatmap.js +142 -164
  127. package/public/js/heatmap.js.map +1 -0
  128. package/public/js/highlight.d.ts +2 -0
  129. package/public/js/highlight.js +116 -107
  130. package/public/js/highlight.js.map +1 -0
  131. package/public/js/html.d.ts +2 -0
  132. package/public/js/html.js +14 -44
  133. package/public/js/html.js.map +1 -0
  134. package/public/js/insightsView.d.ts +5 -0
  135. package/public/js/insightsView.js +93 -111
  136. package/public/js/insightsView.js.map +1 -0
  137. package/public/js/inspector.d.ts +37 -0
  138. package/public/js/inspector.js +416 -445
  139. package/public/js/inspector.js.map +1 -0
  140. package/public/js/llm.d.ts +113 -0
  141. package/public/js/llm.js +233 -272
  142. package/public/js/llm.js.map +1 -0
  143. package/public/js/mapView.d.ts +3 -0
  144. package/public/js/mapView.js +121 -120
  145. package/public/js/mapView.js.map +1 -0
  146. package/public/js/markdown.d.ts +3 -0
  147. package/public/js/markdown.js +84 -91
  148. package/public/js/markdown.js.map +1 -0
  149. package/public/js/mindmap.d.ts +32 -0
  150. package/public/js/mindmap.js +244 -259
  151. package/public/js/mindmap.js.map +1 -0
  152. package/public/js/mobilePanels.d.ts +5 -0
  153. package/public/js/mobilePanels.js +50 -0
  154. package/public/js/mobilePanels.js.map +1 -0
  155. package/public/js/repoFiles.d.ts +12 -0
  156. package/public/js/repoFiles.js +28 -27
  157. package/public/js/repoFiles.js.map +1 -0
  158. package/public/js/reviewView.d.ts +28 -0
  159. package/public/js/reviewView.js +256 -0
  160. package/public/js/reviewView.js.map +1 -0
  161. package/public/js/sbomView.d.ts +3 -0
  162. package/public/js/sbomView.js +59 -67
  163. package/public/js/sbomView.js.map +1 -0
  164. package/public/js/scanCache.d.ts +16 -0
  165. package/public/js/scanCache.js +67 -65
  166. package/public/js/scanCache.js.map +1 -0
  167. package/public/js/search.d.ts +7 -0
  168. package/public/js/search.js +868 -800
  169. package/public/js/search.js.map +1 -0
  170. package/public/js/searchLocal.d.ts +42 -0
  171. package/public/js/searchLocal.js +87 -0
  172. package/public/js/searchLocal.js.map +1 -0
  173. package/public/js/serverSettings.d.ts +5 -0
  174. package/public/js/serverSettings.js +153 -164
  175. package/public/js/serverSettings.js.map +1 -0
  176. package/public/js/state.d.ts +798 -0
  177. package/public/js/state.js +114 -122
  178. package/public/js/state.js.map +1 -0
  179. package/public/js/tour.d.ts +6 -0
  180. package/public/js/tour.js +5 -7
  181. package/public/js/tour.js.map +1 -0
  182. package/public/js/transitions.d.ts +2 -0
  183. package/public/js/transitions.js +9 -10
  184. package/public/js/transitions.js.map +1 -0
  185. package/public/js/tree.d.ts +12 -0
  186. package/public/js/tree.js +157 -154
  187. package/public/js/tree.js.map +1 -0
  188. package/public/js/workflowsView.d.ts +3 -0
  189. package/public/js/workflowsView.js +15 -22
  190. package/public/js/workflowsView.js.map +1 -0
  191. package/public/search.css +495 -0
  192. package/public/styles.css +163 -346
  193. package/public/workbench.css +166 -0
  194. package/server/apiAuth.d.ts +3 -0
  195. package/server/apiAuth.js +18 -20
  196. package/server/apiAuth.js.map +1 -0
  197. package/server/apiDiff.d.ts +2 -0
  198. package/server/apiDiff.js +20 -18
  199. package/server/apiDiff.js.map +1 -0
  200. package/server/apiDocs.d.ts +2 -0
  201. package/server/apiDocs.js +38 -40
  202. package/server/apiDocs.js.map +1 -0
  203. package/server/apiFile.d.ts +1 -0
  204. package/server/apiFile.js +14 -17
  205. package/server/apiFile.js.map +1 -0
  206. package/server/apiGitBlame.d.ts +2 -0
  207. package/server/apiGitBlame.js +50 -51
  208. package/server/apiGitBlame.js.map +1 -0
  209. package/server/apiMcp.d.ts +4 -0
  210. package/server/apiMcp.js +64 -66
  211. package/server/apiMcp.js.map +1 -0
  212. package/server/apiReview.d.ts +2 -0
  213. package/server/apiReview.js +45 -0
  214. package/server/apiReview.js.map +1 -0
  215. package/server/apiScan.d.ts +5 -0
  216. package/server/apiScan.js +90 -71
  217. package/server/apiScan.js.map +1 -0
  218. package/server/apiSearch.d.ts +33 -0
  219. package/server/apiSearch.js +184 -200
  220. package/server/apiSearch.js.map +1 -0
  221. package/server/apiSettings.d.ts +4 -0
  222. package/server/apiSettings.js +84 -85
  223. package/server/apiSettings.js.map +1 -0
  224. package/server/apiTools.d.ts +3 -0
  225. package/server/apiTools.js +55 -56
  226. package/server/apiTools.js.map +1 -0
  227. package/server/auth.d.ts +5 -0
  228. package/server/auth.js +54 -51
  229. package/server/auth.js.map +1 -0
  230. package/server/config.d.ts +42 -0
  231. package/server/config.js +189 -194
  232. package/server/config.js.map +1 -0
  233. package/server/daemon.d.ts +12 -0
  234. package/server/daemon.js +124 -114
  235. package/server/daemon.js.map +1 -0
  236. package/server/fileSourceNode.d.ts +2 -0
  237. package/server/fileSourceNode.js +34 -36
  238. package/server/fileSourceNode.js.map +1 -0
  239. package/server/gitClone.d.ts +9 -0
  240. package/server/gitClone.js +59 -61
  241. package/server/gitClone.js.map +1 -0
  242. package/server/gitDiff.d.ts +36 -0
  243. package/server/gitDiff.js +271 -169
  244. package/server/gitDiff.js.map +1 -0
  245. package/server/gitHistory.d.ts +12 -0
  246. package/server/gitHistory.js +80 -80
  247. package/server/gitHistory.js.map +1 -0
  248. package/server/gitRemote.d.ts +12 -0
  249. package/server/gitRemote.js +60 -0
  250. package/server/gitRemote.js.map +1 -0
  251. package/server/htmlText.d.ts +4 -0
  252. package/server/htmlText.js +16 -23
  253. package/server/htmlText.js.map +1 -0
  254. package/server/http.d.ts +5 -0
  255. package/server/http.js +27 -30
  256. package/server/http.js.map +1 -0
  257. package/server/httpGuards.d.ts +2 -0
  258. package/server/httpGuards.js +47 -43
  259. package/server/httpGuards.js.map +1 -0
  260. package/server/https.d.ts +34 -0
  261. package/server/https.js +121 -111
  262. package/server/https.js.map +1 -0
  263. package/server/index.d.ts +40 -0
  264. package/server/index.js +139 -147
  265. package/server/index.js.map +1 -0
  266. package/server/layout.d.ts +26 -0
  267. package/server/layout.js +59 -37
  268. package/server/layout.js.map +1 -0
  269. package/server/llmProxy.d.ts +3 -0
  270. package/server/llmProxy.js +137 -135
  271. package/server/llmProxy.js.map +1 -0
  272. package/server/logger.d.ts +38 -0
  273. package/server/logger.js +198 -211
  274. package/server/logger.js.map +1 -0
  275. package/server/mcp/analysis.d.ts +29 -0
  276. package/server/mcp/analysis.js +99 -120
  277. package/server/mcp/analysis.js.map +1 -0
  278. package/server/mcp/http.d.ts +9 -0
  279. package/server/mcp/http.js +128 -137
  280. package/server/mcp/http.js.map +1 -0
  281. package/server/mcp/runner.d.ts +68 -0
  282. package/server/mcp/runner.js +208 -218
  283. package/server/mcp/runner.js.map +1 -0
  284. package/server/mcp/server.d.ts +29 -0
  285. package/server/mcp/server.js +166 -179
  286. package/server/mcp/server.js.map +1 -0
  287. package/server/mcp/standalone.d.ts +1 -0
  288. package/server/mcp/standalone.js +8 -10
  289. package/server/mcp/standalone.js.map +1 -0
  290. package/server/mcp/tools.d.ts +2020 -0
  291. package/server/mcp/tools.js +523 -574
  292. package/server/mcp/tools.js.map +1 -0
  293. package/server/paths.d.ts +3 -0
  294. package/server/paths.js +17 -15
  295. package/server/paths.js.map +1 -0
  296. package/server/pidfile.d.ts +9 -0
  297. package/server/pidfile.js +43 -45
  298. package/server/pidfile.js.map +1 -0
  299. package/server/review.d.ts +5 -0
  300. package/server/review.js +35 -0
  301. package/server/review.js.map +1 -0
  302. package/server/router.d.ts +33 -0
  303. package/server/router.js +191 -197
  304. package/server/router.js.map +1 -0
  305. package/server/scanRequest.d.ts +3 -0
  306. package/server/scanRequest.js +36 -0
  307. package/server/scanRequest.js.map +1 -0
  308. package/server/searchIndex.d.ts +17 -0
  309. package/server/searchIndex.js +83 -80
  310. package/server/searchIndex.js.map +1 -0
  311. package/server/sessions.d.ts +14 -0
  312. package/server/sessions.js +62 -70
  313. package/server/sessions.js.map +1 -0
  314. package/server/startup.d.ts +118 -0
  315. package/server/startup.js +143 -148
  316. package/server/startup.js.map +1 -0
  317. package/server/static.d.ts +6 -0
  318. package/server/static.js +28 -31
  319. package/server/static.js.map +1 -0
  320. package/server/tools/install.d.ts +4 -0
  321. package/server/tools/install.js +176 -185
  322. package/server/tools/install.js.map +1 -0
  323. package/server/tools/parse.d.ts +8 -0
  324. package/server/tools/parse.js +112 -114
  325. package/server/tools/parse.js.map +1 -0
  326. package/server/tools/platform.d.ts +9 -0
  327. package/server/tools/platform.js +49 -47
  328. package/server/tools/platform.js.map +1 -0
  329. package/server/tools/registry.d.ts +137 -0
  330. package/server/tools/registry.js +173 -172
  331. package/server/tools/registry.js.map +1 -0
  332. package/server/tools/scan.d.ts +34 -0
  333. package/server/tools/scan.js +89 -98
  334. package/server/tools/scan.js.map +1 -0
  335. package/server/tools.d.ts +34 -0
  336. package/server/tools.js +94 -107
  337. package/server/tools.js.map +1 -0
  338. package/server/tunnel.d.ts +29 -0
  339. package/server/tunnel.js +61 -66
  340. package/server/tunnel.js.map +1 -0
  341. package/shared/analyzer/docs.d.ts +16 -0
  342. package/shared/analyzer/docs.js +99 -93
  343. package/shared/analyzer/docs.js.map +1 -0
  344. package/shared/analyzer/explainLocal.d.ts +4 -0
  345. package/shared/analyzer/explainLocal.js +122 -142
  346. package/shared/analyzer/explainLocal.js.map +1 -0
  347. package/shared/analyzer/github.d.ts +37 -0
  348. package/shared/analyzer/github.js +79 -0
  349. package/shared/analyzer/github.js.map +1 -0
  350. package/shared/analyzer/graph.d.ts +41 -0
  351. package/shared/analyzer/graph.js +393 -400
  352. package/shared/analyzer/graph.js.map +1 -0
  353. package/shared/analyzer/health.d.ts +33 -0
  354. package/shared/analyzer/health.js +197 -193
  355. package/shared/analyzer/health.js.map +1 -0
  356. package/shared/analyzer/history.d.ts +29 -0
  357. package/shared/analyzer/history.js +110 -111
  358. package/shared/analyzer/history.js.map +1 -0
  359. package/shared/analyzer/jsonConfig.d.ts +2 -0
  360. package/shared/analyzer/jsonConfig.js +61 -0
  361. package/shared/analyzer/jsonConfig.js.map +1 -0
  362. package/shared/analyzer/languages/csharp.d.ts +26 -0
  363. package/shared/analyzer/languages/csharp.js +83 -88
  364. package/shared/analyzer/languages/csharp.js.map +1 -0
  365. package/shared/analyzer/languages/generic.d.ts +23 -0
  366. package/shared/analyzer/languages/generic.js +94 -105
  367. package/shared/analyzer/languages/generic.js.map +1 -0
  368. package/shared/analyzer/languages/go.d.ts +24 -0
  369. package/shared/analyzer/languages/go.js +45 -54
  370. package/shared/analyzer/languages/go.js.map +1 -0
  371. package/shared/analyzer/languages/index.d.ts +6 -0
  372. package/shared/analyzer/languages/index.js +19 -20
  373. package/shared/analyzer/languages/index.js.map +1 -0
  374. package/shared/analyzer/languages/java.d.ts +20 -0
  375. package/shared/analyzer/languages/java.js +73 -78
  376. package/shared/analyzer/languages/java.js.map +1 -0
  377. package/shared/analyzer/languages/javascript.d.ts +12 -0
  378. package/shared/analyzer/languages/javascript.js +258 -209
  379. package/shared/analyzer/languages/javascript.js.map +1 -0
  380. package/shared/analyzer/languages/python.d.ts +23 -0
  381. package/shared/analyzer/languages/python.js +92 -100
  382. package/shared/analyzer/languages/python.js.map +1 -0
  383. package/shared/analyzer/languages/rust.d.ts +17 -0
  384. package/shared/analyzer/languages/rust.js +96 -98
  385. package/shared/analyzer/languages/rust.js.map +1 -0
  386. package/shared/analyzer/languages/typescript.d.ts +11 -0
  387. package/shared/analyzer/languages/typescript.js +117 -116
  388. package/shared/analyzer/languages/typescript.js.map +1 -0
  389. package/shared/analyzer/licenses.d.ts +18 -0
  390. package/shared/analyzer/licenses.js +130 -133
  391. package/shared/analyzer/licenses.js.map +1 -0
  392. package/shared/analyzer/metrics.d.ts +20 -0
  393. package/shared/analyzer/metrics.js +112 -104
  394. package/shared/analyzer/metrics.js.map +1 -0
  395. package/shared/analyzer/pathUtil.d.ts +10 -0
  396. package/shared/analyzer/pathUtil.js +29 -35
  397. package/shared/analyzer/pathUtil.js.map +1 -0
  398. package/shared/analyzer/patterns.d.ts +11 -0
  399. package/shared/analyzer/patterns.js +231 -253
  400. package/shared/analyzer/patterns.js.map +1 -0
  401. package/shared/analyzer/scan.d.ts +62 -0
  402. package/shared/analyzer/scan.js +451 -442
  403. package/shared/analyzer/scan.js.map +1 -0
  404. package/shared/analyzer/scanControl.d.ts +11 -0
  405. package/shared/analyzer/scanControl.js +62 -0
  406. package/shared/analyzer/scanControl.js.map +1 -0
  407. package/shared/analyzer/security.d.ts +18 -0
  408. package/shared/analyzer/security.js +159 -159
  409. package/shared/analyzer/security.js.map +1 -0
  410. package/shared/analyzer/services.d.ts +5 -0
  411. package/shared/analyzer/services.js +141 -138
  412. package/shared/analyzer/services.js.map +1 -0
  413. package/shared/analyzer/stack.d.ts +6 -0
  414. package/shared/analyzer/stack.js +134 -141
  415. package/shared/analyzer/stack.js.map +1 -0
  416. package/shared/analyzer/tour.d.ts +2 -0
  417. package/shared/analyzer/tour.js +45 -53
  418. package/shared/analyzer/tour.js.map +1 -0
  419. package/shared/analyzer/util.d.ts +8 -0
  420. package/shared/analyzer/util.js +130 -76
  421. package/shared/analyzer/util.js.map +1 -0
  422. package/shared/analyzer/workflows.d.ts +8 -0
  423. package/shared/analyzer/workflows.js +139 -134
  424. package/shared/analyzer/workflows.js.map +1 -0
  425. package/shared/contracts.d.ts +250 -0
  426. package/shared/contracts.js +2 -0
  427. package/shared/contracts.js.map +1 -0
  428. package/shared/diagram/aiFacts.d.ts +35 -0
  429. package/shared/diagram/aiFacts.js +102 -105
  430. package/shared/diagram/aiFacts.js.map +1 -0
  431. package/shared/diagram/aiMermaid.d.ts +5 -0
  432. package/shared/diagram/aiMermaid.js +46 -45
  433. package/shared/diagram/aiMermaid.js.map +1 -0
  434. package/shared/diagram/atlas.d.ts +16 -0
  435. package/shared/diagram/atlas.js +51 -60
  436. package/shared/diagram/atlas.js.map +1 -0
  437. package/shared/diagram/mermaid.d.ts +43 -0
  438. package/shared/diagram/mermaid.js +348 -370
  439. package/shared/diagram/mermaid.js.map +1 -0
  440. package/shared/review/contracts.d.ts +95 -0
  441. package/shared/review/contracts.js +2 -0
  442. package/shared/review/contracts.js.map +1 -0
  443. package/shared/review/review.d.ts +10 -0
  444. package/shared/review/review.js +184 -0
  445. package/shared/review/review.js.map +1 -0
  446. package/shared/search/query.d.ts +32 -0
  447. package/shared/search/query.js +395 -388
  448. package/shared/search/query.js.map +1 -0
@@ -0,0 +1,36 @@
1
+ import type { GitDiff, ReviewMode } from '../shared/review/contracts.js';
2
+ export interface DiffOptions {
3
+ base?: string;
4
+ head?: string;
5
+ file?: string;
6
+ mode?: ReviewMode;
7
+ includeUntracked?: boolean;
8
+ signal?: AbortSignal;
9
+ }
10
+ export declare class GitDiffError extends Error {
11
+ status: number;
12
+ constructor(message: string, status?: number);
13
+ }
14
+ export declare function getGitRefs(root: string): Promise<{
15
+ reason?: undefined;
16
+ available: boolean;
17
+ branches: string[];
18
+ tags: string[];
19
+ current: string;
20
+ commits: {
21
+ hash: string;
22
+ short: string;
23
+ message: string;
24
+ author: string;
25
+ date: string;
26
+ }[];
27
+ } | {
28
+ branches?: undefined;
29
+ tags?: undefined;
30
+ current?: undefined;
31
+ commits?: undefined;
32
+ available: boolean;
33
+ reason: string;
34
+ }>;
35
+ export declare function getGitDiff(root: string, options?: DiffOptions): Promise<GitDiff>;
36
+ export declare function parseUnifiedDiff(diffText: string): GitDiff;
package/server/gitDiff.js CHANGED
@@ -1,184 +1,286 @@
1
- // Git diff & refs provider.
2
- // Executes git subcommands safely via child_process and parses patch hunks.
3
-
1
+ // Bounded, shell-free Git comparisons. A failed range must never become another diff.
4
2
  import { execFile } from 'node:child_process';
5
3
  import { promisify } from 'node:util';
6
-
4
+ import { lstat, readFile, realpath } from 'node:fs/promises';
5
+ import { isInside, resolveInside } from './paths.js';
7
6
  const execFileAsync = promisify(execFile);
8
- const MAX_DIFF_BYTES = 5 * 1024 * 1024; // 5 MB cap
9
-
10
- export async function getGitRefs(root) {
11
- try {
12
- const [branchRes, tagRes, headRes, logRes] = await Promise.all([
13
- execFileAsync('git', ['branch', '-a', '--format=%(refname:short)'], { cwd: root }).catch(() => ({ stdout: '' })),
14
- execFileAsync('git', ['tag', '--sort=-creatordate'], { cwd: root }).catch(() => ({ stdout: '' })),
15
- execFileAsync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: root }).catch(() => ({ stdout: 'main\n' })),
16
- execFileAsync('git', ['log', '-n', '40', '--format=%H|%h|%s|%an|%aI'], { cwd: root }).catch(() => ({ stdout: '' })),
17
- ]);
18
-
19
- const branches = branchRes.stdout.split('\n').map((b) => b.trim()).filter(Boolean);
20
- const tags = tagRes.stdout.split('\n').map((t) => t.trim()).filter(Boolean);
21
- const current = headRes.stdout.trim() || 'HEAD';
22
-
23
- const commits = logRes.stdout.split('\n').filter(Boolean).map((line) => {
24
- const [hash, short, message, author, date] = line.split('|');
25
- return { hash, short, message, author, date };
26
- });
27
-
28
- return {
29
- available: true,
30
- branches: [...new Set(branches)],
31
- tags,
32
- current,
33
- commits,
34
- };
35
- } catch (err) {
36
- return { available: false, reason: err.message };
37
- }
7
+ const MAX_DIFF_BYTES = 5 * 1024 * 1024;
8
+ const EMPTY_TREE = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
9
+ export class GitDiffError extends Error {
10
+ status;
11
+ constructor(message, status = 422) {
12
+ super(message);
13
+ this.status = status;
14
+ this.name = 'GitDiffError';
15
+ }
38
16
  }
39
-
40
- export async function getGitDiff(root, options = {}) {
41
- const { base, head, file } = options;
42
- const args = ['diff', '--no-color', '-U3'];
43
-
44
- if (base && head) {
45
- args.push(`${base}...${head}`);
46
- } else if (base) {
47
- args.push(base);
48
- } else {
49
- args.push('HEAD');
50
- }
51
-
52
- if (file) {
53
- args.push('--', file);
54
- }
55
-
56
- try {
57
- const { stdout } = await execFileAsync('git', args, {
58
- cwd: root,
59
- maxBuffer: MAX_DIFF_BYTES,
60
- });
61
- return parseUnifiedDiff(stdout);
62
- } catch (err) {
63
- // If git diff exited with empty or specific error, fallback to HEAD~1..HEAD or working tree
17
+ async function git(root, args, signal) {
64
18
  try {
65
- const fallback = await execFileAsync('git', ['diff', '--no-color', '-U3'], {
66
- cwd: root,
67
- maxBuffer: MAX_DIFF_BYTES,
68
- });
69
- return parseUnifiedDiff(fallback.stdout);
70
- } catch (e) {
71
- return { files: [], stats: { filesChanged: 0, additions: 0, deletions: 0 }, raw: '' };
19
+ const { stdout } = await execFileAsync('git', ['--literal-pathspecs', '-c', 'core.quotePath=false', ...args], {
20
+ cwd: root, maxBuffer: MAX_DIFF_BYTES, timeout: 15000, killSignal: 'SIGKILL', signal,
21
+ env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' },
22
+ });
23
+ return stdout;
24
+ }
25
+ catch (error) {
26
+ if (signal?.aborted)
27
+ throw error;
28
+ const e = error;
29
+ if (e.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER')
30
+ throw new GitDiffError('This diff exceeds the 5 MB review limit. Choose a smaller range.', 413);
31
+ if (e.killed)
32
+ throw new GitDiffError('Git took too long. Choose a smaller comparison and try again.', 408);
33
+ throw new GitDiffError('Git could not read this comparison. Check the repository and its available history.');
72
34
  }
73
- }
74
35
  }
75
-
76
- export function parseUnifiedDiff(diffText) {
77
- if (!diffText || typeof diffText !== 'string') {
78
- return { files: [], stats: { filesChanged: 0, additions: 0, deletions: 0 }, raw: '' };
79
- }
80
-
81
- const files = [];
82
- const lines = diffText.split('\n');
83
- let currentFile = null;
84
- let currentHunk = null;
85
- let totalAdditions = 0;
86
- let totalDeletions = 0;
87
-
88
- for (let i = 0; i < lines.length; i++) {
89
- const line = lines[i];
90
-
91
- // File header: diff --git a/path b/path
92
- if (line.startsWith('diff --git ')) {
93
- const m = line.match(/^diff --git a\/(.+?) b\/(.+)$/);
94
- const oldPath = m ? m[1] : '';
95
- const newPath = m ? m[2] : '';
96
- currentFile = {
97
- oldPath,
98
- newPath,
99
- status: 'modified',
100
- additions: 0,
101
- deletions: 0,
102
- hunks: [],
103
- };
104
- files.push(currentFile);
105
- currentHunk = null;
106
- continue;
36
+ async function resolveRef(root, ref, signal) {
37
+ if (!ref || ref.length > 200 || ref.startsWith('-') || !/^[a-zA-Z0-9_./~^@{}-]+$/.test(ref))
38
+ throw new GitDiffError('Use a valid branch, tag, or commit reference.', 400);
39
+ try {
40
+ return (await git(root, ['rev-parse', '--verify', '--end-of-options', ref + '^{commit}'], signal)).trim();
41
+ }
42
+ catch (e) {
43
+ if (signal?.aborted || (e instanceof GitDiffError && e.status !== 422))
44
+ throw e;
45
+ throw new GitDiffError(`Reference "${ref}" is unavailable. Shallow clones may not contain older commits.`);
46
+ }
47
+ }
48
+ export async function getGitRefs(root) {
49
+ try {
50
+ await git(root, ['rev-parse', '--is-inside-work-tree']);
51
+ const [branches, tags, current, log] = await Promise.all([
52
+ git(root, ['branch', '-a', '--format=%(refname:short)']),
53
+ git(root, ['tag', '--sort=-creatordate']),
54
+ git(root, ['symbolic-ref', '--short', 'HEAD']).catch(() => 'HEAD'),
55
+ git(root, ['log', '-n', '40', '--format=%H%x00%h%x00%s%x00%an%x00%aI']).catch(() => ''),
56
+ ]);
57
+ return { available: true, branches: branches.trim().split('\n').filter(Boolean), tags: tags.trim().split('\n').filter(Boolean), current: current.trim(),
58
+ commits: log.trim().split('\n').filter(Boolean).map(line => { const [hash, short, message, author, date] = line.split('\0'); return { hash, short, message, author, date }; }) };
107
59
  }
108
-
109
- if (!currentFile) continue;
110
-
111
- if (line.startsWith('new file mode ')) {
112
- currentFile.status = 'added';
113
- continue;
60
+ catch (err) {
61
+ return { available: false, reason: err instanceof Error ? err.message : 'Git unavailable.' };
114
62
  }
115
- if (line.startsWith('deleted file mode ')) {
116
- currentFile.status = 'deleted';
117
- continue;
63
+ }
64
+ export async function getGitDiff(root, options = {}) {
65
+ const { base = 'HEAD', head = '', file = '', includeUntracked = false, signal } = options;
66
+ const mode = options.mode || (head ? 'range' : 'working');
67
+ if (!['working', 'staged', 'range'].includes(mode))
68
+ throw new GitDiffError('Choose working, staged, or range review.', 400);
69
+ if (mode === 'range' && !head)
70
+ throw new GitDiffError('A branch comparison needs a head reference.', 400);
71
+ await git(root, ['rev-parse', '--is-inside-work-tree'], signal);
72
+ const repoRoot = (await git(root, ['rev-parse', '--show-toplevel'], signal)).trim();
73
+ if (await realpath(root) !== await realpath(repoRoot))
74
+ throw new GitDiffError('Open the Git repository root to review changes. A subfolder scan cannot read changes outside its scan root.', 400);
75
+ let baseHash;
76
+ try {
77
+ baseHash = await resolveRef(root, base || 'HEAD', signal);
118
78
  }
119
- if (line.startsWith('rename from ')) {
120
- currentFile.status = 'renamed';
121
- currentFile.oldPath = line.slice(12).trim();
122
- continue;
79
+ catch (error) {
80
+ // An unborn repository has no HEAD. Only that explicit default is allowed.
81
+ if ((base || 'HEAD') !== 'HEAD' || mode === 'range' || signal?.aborted)
82
+ throw error;
83
+ const count = (await git(root, ['rev-list', '--all', '--count'], signal)).trim();
84
+ if (count !== '0')
85
+ throw error;
86
+ baseHash = EMPTY_TREE;
123
87
  }
124
- if (line.startsWith('rename to ')) {
125
- currentFile.newPath = line.slice(10).trim();
126
- continue;
88
+ const headHash = mode === 'range' ? await resolveRef(root, head, signal) : '';
89
+ const args = ['diff', '--no-color', '--no-ext-diff', '--no-textconv', '-U3'];
90
+ if (mode === 'staged')
91
+ args.push('--cached');
92
+ args.push(headHash ? `${baseHash}...${headHash}` : baseHash, '--');
93
+ if (file)
94
+ args.push(file);
95
+ let raw = await git(root, args, signal);
96
+ let untracked = 0;
97
+ if (includeUntracked && mode === 'working' && !file) {
98
+ const names = (await git(root, ['ls-files', '--others', '--exclude-standard', '-z'], signal)).split('\0').filter(Boolean);
99
+ if (names.length > 200)
100
+ throw new GitDiffError('More than 200 untracked files. Stage selected files or narrow the repository before reviewing.', 413);
101
+ const canonicalRoot = await realpath(root);
102
+ for (const name of names) {
103
+ signal?.throwIfAborted();
104
+ const abs = resolveInside(root, name);
105
+ if (!abs)
106
+ throw new GitDiffError('An untracked path is outside this repository.');
107
+ const st = await lstat(abs);
108
+ if (st.isSymbolicLink()) {
109
+ raw += `diff --git ${JSON.stringify('a/' + name)} ${JSON.stringify('b/' + name)}\nnew file mode 120000\nonboarder skipped symlink\n`;
110
+ untracked++;
111
+ continue;
112
+ }
113
+ if (!st.isFile())
114
+ continue;
115
+ if (!isInside(canonicalRoot, await realpath(abs)))
116
+ throw new GitDiffError('An untracked path resolves outside this repository.');
117
+ if (st.size > 1024 * 1024)
118
+ throw new GitDiffError(`Untracked file "${name}" exceeds the 1 MB limit. Stage it to review its Git diff.`, 413);
119
+ const buffer = await readFile(abs);
120
+ if (buffer.byteLength > 1024 * 1024)
121
+ throw new GitDiffError('An untracked file grew beyond the review limit.', 413);
122
+ const header = `diff --git ${JSON.stringify('a/' + name)} ${JSON.stringify('b/' + name)}\nnew file mode 100644\n`;
123
+ if (buffer.includes(0))
124
+ raw += header + `Binary files /dev/null and ${name} differ\n`;
125
+ else {
126
+ const source = buffer.toString('utf8');
127
+ const lines = source === '' ? [] : source.replace(/\n$/, '').split('\n');
128
+ raw += header + `--- /dev/null\n+++ ${JSON.stringify('b/' + name)}\n@@ -0,0 +1,${lines.length} @@\n` + lines.map(l => '+' + l + '\n').join('');
129
+ }
130
+ untracked++;
131
+ if (Buffer.byteLength(raw) > MAX_DIFF_BYTES)
132
+ throw new GitDiffError('This diff exceeds the 5 MB review limit.', 413);
133
+ }
127
134
  }
128
-
129
- // Hunk header: @@ -1,5 +1,6 @@ optional context
130
- if (line.startsWith('@@ ')) {
131
- const match = line.match(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/);
132
- if (match) {
133
- const oldStart = parseInt(match[1], 10);
134
- const oldLines = match[2] !== undefined ? parseInt(match[2], 10) : 1;
135
- const newStart = parseInt(match[3], 10);
136
- const newLines = match[4] !== undefined ? parseInt(match[4], 10) : 1;
137
- currentHunk = {
138
- header: line,
139
- oldStart,
140
- oldLines,
141
- newStart,
142
- newLines,
143
- heading: match[5]?.trim() || '',
144
- lines: [],
145
- };
146
- currentFile.hunks.push(currentHunk);
147
- }
148
- continue;
135
+ return { ...parseUnifiedDiff(raw), base: baseHash, head: headHash, mode, untracked };
136
+ }
137
+ function decodeGitPath(value) {
138
+ if (!value.startsWith('"'))
139
+ return value;
140
+ // Git quotes control characters and sometimes octal UTF-8 bytes.
141
+ const bytes = [];
142
+ for (let i = 1; i < value.length - 1; i++) {
143
+ if (value[i] === '\\') {
144
+ const octal = value.slice(i + 1).match(/^[0-7]{1,3}/)?.[0];
145
+ if (octal) {
146
+ bytes.push(parseInt(octal, 8));
147
+ i += octal.length;
148
+ continue;
149
+ }
150
+ const escaped = { n: '\n', t: '\t', r: '\r', b: '\b', f: '\f', v: '\v', a: '\x07' };
151
+ bytes.push(...Buffer.from(escaped[value[++i]] ?? value[i]));
152
+ }
153
+ else {
154
+ const cp = value.codePointAt(i);
155
+ bytes.push(...Buffer.from(String.fromCodePoint(cp)));
156
+ if (cp > 0xffff)
157
+ i++;
158
+ }
149
159
  }
150
-
151
- if (!currentHunk) continue;
152
-
153
- if (line.startsWith('+') && !line.startsWith('+++')) {
154
- currentFile.additions++;
155
- totalAdditions++;
156
- currentHunk.lines.push({
157
- type: 'add',
158
- text: line.slice(1),
159
- });
160
- } else if (line.startsWith('-') && !line.startsWith('---')) {
161
- currentFile.deletions++;
162
- totalDeletions++;
163
- currentHunk.lines.push({
164
- type: 'del',
165
- text: line.slice(1),
166
- });
167
- } else if (line.startsWith(' ')) {
168
- currentHunk.lines.push({
169
- type: 'context',
170
- text: line.slice(1),
171
- });
160
+ return Buffer.from(bytes).toString('utf8');
161
+ }
162
+ export function parseUnifiedDiff(diffText) {
163
+ if (!diffText || typeof diffText !== 'string') {
164
+ return { files: [], stats: { filesChanged: 0, additions: 0, deletions: 0 }, raw: '' };
165
+ }
166
+ const files = [];
167
+ const lines = diffText.split('\n');
168
+ let currentFile = null;
169
+ let currentHunk = null;
170
+ let totalAdditions = 0;
171
+ let totalDeletions = 0;
172
+ for (let i = 0; i < lines.length; i++) {
173
+ const line = lines[i];
174
+ // File header: diff --git a/path b/path
175
+ if (line.startsWith('diff --git ')) {
176
+ const m = line.match(/^diff --git (\"(?:[^\"\\]|\\.)*\"|a\/.*?) (\"(?:[^\"\\]|\\.)*\"|b\/.*)$/);
177
+ const oldPath = m ? decodeGitPath(m[1]).slice(2) : '';
178
+ const newPath = m ? decodeGitPath(m[2]).slice(2) : '';
179
+ currentFile = {
180
+ oldPath,
181
+ newPath,
182
+ status: 'modified',
183
+ additions: 0,
184
+ deletions: 0,
185
+ hunks: [],
186
+ };
187
+ files.push(currentFile);
188
+ currentHunk = null;
189
+ continue;
190
+ }
191
+ if (!currentFile)
192
+ continue;
193
+ // File markers disambiguate unquoted paths containing " b/" in the header.
194
+ if (!currentHunk && (line.startsWith('--- ') || line.startsWith('+++ '))) {
195
+ const value = line.slice(4);
196
+ const markerPath = decodeGitPath(value.startsWith('"') ? value : value.split('\t')[0]);
197
+ if (markerPath !== '/dev/null') {
198
+ if (line.startsWith('--- '))
199
+ currentFile.oldPath = markerPath.slice(2);
200
+ else
201
+ currentFile.newPath = markerPath.slice(2);
202
+ }
203
+ continue;
204
+ }
205
+ if (line === 'onboarder skipped symlink') {
206
+ currentFile.skipReason = 'Untracked symlink: target not read';
207
+ continue;
208
+ }
209
+ if (line.startsWith('Binary files ') || line === 'GIT binary patch') {
210
+ currentFile.binary = true;
211
+ continue;
212
+ }
213
+ if (line.startsWith('new file mode ')) {
214
+ currentFile.status = 'added';
215
+ continue;
216
+ }
217
+ if (line.startsWith('deleted file mode ')) {
218
+ currentFile.status = 'deleted';
219
+ continue;
220
+ }
221
+ if (line.startsWith('rename from ')) {
222
+ currentFile.status = 'renamed';
223
+ currentFile.oldPath = decodeGitPath(line.slice(12));
224
+ continue;
225
+ }
226
+ if (line.startsWith('rename to ')) {
227
+ currentFile.newPath = decodeGitPath(line.slice(10));
228
+ continue;
229
+ }
230
+ // Hunk header: @@ -1,5 +1,6 @@ optional context
231
+ if (line.startsWith('@@ ')) {
232
+ const match = line.match(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/);
233
+ if (match) {
234
+ const oldStart = parseInt(match[1], 10);
235
+ const oldLines = match[2] !== undefined ? parseInt(match[2], 10) : 1;
236
+ const newStart = parseInt(match[3], 10);
237
+ const newLines = match[4] !== undefined ? parseInt(match[4], 10) : 1;
238
+ currentHunk = {
239
+ header: line,
240
+ oldStart,
241
+ oldLines,
242
+ newStart,
243
+ newLines,
244
+ heading: match[5]?.trim() || '',
245
+ lines: [],
246
+ };
247
+ currentFile.hunks.push(currentHunk);
248
+ }
249
+ continue;
250
+ }
251
+ if (!currentHunk)
252
+ continue;
253
+ if (line.startsWith('+')) {
254
+ currentFile.additions++;
255
+ totalAdditions++;
256
+ currentHunk.lines.push({
257
+ type: 'add',
258
+ text: line.slice(1),
259
+ });
260
+ }
261
+ else if (line.startsWith('-')) {
262
+ currentFile.deletions++;
263
+ totalDeletions++;
264
+ currentHunk.lines.push({
265
+ type: 'del',
266
+ text: line.slice(1),
267
+ });
268
+ }
269
+ else if (line.startsWith(' ')) {
270
+ currentHunk.lines.push({
271
+ type: 'context',
272
+ text: line.slice(1),
273
+ });
274
+ }
172
275
  }
173
- }
174
-
175
- return {
176
- files,
177
- stats: {
178
- filesChanged: files.length,
179
- additions: totalAdditions,
180
- deletions: totalDeletions,
181
- },
182
- raw: diffText,
183
- };
276
+ return {
277
+ files,
278
+ stats: {
279
+ filesChanged: files.length,
280
+ additions: totalAdditions,
281
+ deletions: totalDeletions,
282
+ },
283
+ raw: diffText,
284
+ };
184
285
  }
286
+ //# sourceMappingURL=gitDiff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitDiff.js","sourceRoot":"","sources":["../src/server/gitDiff.ts"],"names":[],"mappings":"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","sourcesContent":["// Bounded, shell-free Git comparisons. A failed range must never become another diff.\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { lstat, readFile, realpath } from 'node:fs/promises';\nimport { isInside, resolveInside } from './paths.js';\nimport type { GitDiff, PatchFile, PatchHunk, ReviewMode } from '../shared/review/contracts.js';\nconst execFileAsync = promisify(execFile);\nconst MAX_DIFF_BYTES = 5 * 1024 * 1024;\nconst EMPTY_TREE = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';\nexport interface DiffOptions { base?: string; head?: string; file?: string; mode?: ReviewMode; includeUntracked?: boolean; signal?: AbortSignal }\n\nexport class GitDiffError extends Error {\n constructor(message: string, public status = 422) { super(message); this.name = 'GitDiffError'; }\n}\nasync function git(root: string, args: string[], signal?: AbortSignal): Promise<string> {\n try {\n const { stdout } = await execFileAsync('git', ['--literal-pathspecs', '-c', 'core.quotePath=false', ...args], {\n cwd: root, maxBuffer: MAX_DIFF_BYTES, timeout: 15000, killSignal: 'SIGKILL', signal,\n env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' },\n });\n return stdout;\n } catch (error) {\n if (signal?.aborted) throw error;\n const e = error as { code?: string; killed?: boolean };\n if (e.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER') throw new GitDiffError('This diff exceeds the 5 MB review limit. Choose a smaller range.', 413);\n if (e.killed) throw new GitDiffError('Git took too long. Choose a smaller comparison and try again.', 408);\n throw new GitDiffError('Git could not read this comparison. Check the repository and its available history.');\n }\n}\nasync function resolveRef(root: string, ref: string, signal?: AbortSignal): Promise<string> {\n if (!ref || ref.length > 200 || ref.startsWith('-') || !/^[a-zA-Z0-9_./~^@{}-]+$/.test(ref)) throw new GitDiffError('Use a valid branch, tag, or commit reference.', 400);\n try { return (await git(root, ['rev-parse', '--verify', '--end-of-options', ref + '^{commit}'], signal)).trim(); }\n catch (e) { if (signal?.aborted || (e instanceof GitDiffError && e.status !== 422)) throw e; throw new GitDiffError(`Reference \"${ref}\" is unavailable. Shallow clones may not contain older commits.`); }\n}\nexport async function getGitRefs(root: string) {\n try {\n await git(root, ['rev-parse', '--is-inside-work-tree']);\n const [branches, tags, current, log] = await Promise.all([\n git(root, ['branch', '-a', '--format=%(refname:short)']),\n git(root, ['tag', '--sort=-creatordate']),\n git(root, ['symbolic-ref', '--short', 'HEAD']).catch(() => 'HEAD'),\n git(root, ['log', '-n', '40', '--format=%H%x00%h%x00%s%x00%an%x00%aI']).catch(() => ''),\n ]);\n return { available: true, branches: branches.trim().split('\\n').filter(Boolean), tags: tags.trim().split('\\n').filter(Boolean), current: current.trim(),\n commits: log.trim().split('\\n').filter(Boolean).map(line => { const [hash, short, message, author, date] = line.split('\\0'); return { hash, short, message, author, date }; }) };\n } catch (err) { return { available: false, reason: err instanceof Error ? err.message : 'Git unavailable.' }; }\n}\nexport async function getGitDiff(root: string, options: DiffOptions = {}): Promise<GitDiff> {\n const { base = 'HEAD', head = '', file = '', includeUntracked = false, signal } = options;\n const mode = options.mode || (head ? 'range' : 'working');\n if (!['working', 'staged', 'range'].includes(mode)) throw new GitDiffError('Choose working, staged, or range review.', 400);\n if (mode === 'range' && !head) throw new GitDiffError('A branch comparison needs a head reference.', 400);\n await git(root, ['rev-parse', '--is-inside-work-tree'], signal);\n const repoRoot = (await git(root, ['rev-parse', '--show-toplevel'], signal)).trim();\n if (await realpath(root) !== await realpath(repoRoot)) throw new GitDiffError('Open the Git repository root to review changes. A subfolder scan cannot read changes outside its scan root.', 400);\n let baseHash: string;\n try { baseHash = await resolveRef(root, base || 'HEAD', signal); }\n catch (error) {\n // An unborn repository has no HEAD. Only that explicit default is allowed.\n if ((base || 'HEAD') !== 'HEAD' || mode === 'range' || signal?.aborted) throw error;\n const count = (await git(root, ['rev-list', '--all', '--count'], signal)).trim();\n if (count !== '0') throw error;\n baseHash = EMPTY_TREE;\n }\n const headHash = mode === 'range' ? await resolveRef(root, head, signal) : '';\n const args = ['diff', '--no-color', '--no-ext-diff', '--no-textconv', '-U3'];\n if (mode === 'staged') args.push('--cached');\n args.push(headHash ? `${baseHash}...${headHash}` : baseHash, '--');\n if (file) args.push(file);\n let raw = await git(root, args, signal);\n let untracked = 0;\n if (includeUntracked && mode === 'working' && !file) {\n const names = (await git(root, ['ls-files', '--others', '--exclude-standard', '-z'], signal)).split('\\0').filter(Boolean);\n if (names.length > 200) throw new GitDiffError('More than 200 untracked files. Stage selected files or narrow the repository before reviewing.', 413);\n const canonicalRoot = await realpath(root);\n for (const name of names) {\n signal?.throwIfAborted();\n const abs = resolveInside(root, name);\n if (!abs) throw new GitDiffError('An untracked path is outside this repository.');\n const st = await lstat(abs);\n if (st.isSymbolicLink()) {\n raw += `diff --git ${JSON.stringify('a/' + name)} ${JSON.stringify('b/' + name)}\\nnew file mode 120000\\nonboarder skipped symlink\\n`; untracked++; continue;\n }\n if (!st.isFile()) continue;\n if (!isInside(canonicalRoot, await realpath(abs))) throw new GitDiffError('An untracked path resolves outside this repository.');\n if (st.size > 1024 * 1024) throw new GitDiffError(`Untracked file \"${name}\" exceeds the 1 MB limit. Stage it to review its Git diff.`, 413);\n const buffer = await readFile(abs);\n if (buffer.byteLength > 1024 * 1024) throw new GitDiffError('An untracked file grew beyond the review limit.', 413);\n const header = `diff --git ${JSON.stringify('a/' + name)} ${JSON.stringify('b/' + name)}\\nnew file mode 100644\\n`;\n if (buffer.includes(0)) raw += header + `Binary files /dev/null and ${name} differ\\n`;\n else {\n const source = buffer.toString('utf8');\n const lines = source === '' ? [] : source.replace(/\\n$/, '').split('\\n');\n raw += header + `--- /dev/null\\n+++ ${JSON.stringify('b/' + name)}\\n@@ -0,0 +1,${lines.length} @@\\n` + lines.map(l => '+' + l + '\\n').join('');\n }\n untracked++;\n if (Buffer.byteLength(raw) > MAX_DIFF_BYTES) throw new GitDiffError('This diff exceeds the 5 MB review limit.', 413);\n }\n }\n return { ...parseUnifiedDiff(raw), base: baseHash, head: headHash, mode, untracked };\n}\nfunction decodeGitPath(value: string): string {\n if (!value.startsWith('\"')) return value;\n // Git quotes control characters and sometimes octal UTF-8 bytes.\n const bytes: number[] = [];\n for (let i = 1; i < value.length - 1; i++) {\n if (value[i] === '\\\\') {\n const octal = value.slice(i + 1).match(/^[0-7]{1,3}/)?.[0];\n if (octal) { bytes.push(parseInt(octal, 8)); i += octal.length; continue; }\n const escaped: Record<string, string> = { n: '\\n', t: '\\t', r: '\\r', b: '\\b', f: '\\f', v: '\\v', a: '\\x07' };\n bytes.push(...Buffer.from(escaped[value[++i]] ?? value[i]));\n } else { const cp = value.codePointAt(i)!; bytes.push(...Buffer.from(String.fromCodePoint(cp))); if (cp > 0xffff) i++; }\n }\n return Buffer.from(bytes).toString('utf8');\n}\n\nexport function parseUnifiedDiff(diffText: string): GitDiff {\n if (!diffText || typeof diffText !== 'string') {\n return { files: [], stats: { filesChanged: 0, additions: 0, deletions: 0 }, raw: '' };\n }\n\n const files: PatchFile[] = [];\n const lines = diffText.split('\\n');\n let currentFile: PatchFile | null = null;\n let currentHunk: PatchHunk | null = null;\n let totalAdditions = 0;\n let totalDeletions = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // File header: diff --git a/path b/path\n if (line.startsWith('diff --git ')) {\n const m = line.match(/^diff --git (\\\"(?:[^\\\"\\\\]|\\\\.)*\\\"|a\\/.*?) (\\\"(?:[^\\\"\\\\]|\\\\.)*\\\"|b\\/.*)$/);\n const oldPath = m ? decodeGitPath(m[1]).slice(2) : '';\n const newPath = m ? decodeGitPath(m[2]).slice(2) : '';\n currentFile = {\n oldPath,\n newPath,\n status: 'modified',\n additions: 0,\n deletions: 0,\n hunks: [],\n };\n files.push(currentFile);\n currentHunk = null;\n continue;\n }\n\n if (!currentFile) continue;\n // File markers disambiguate unquoted paths containing \" b/\" in the header.\n if (!currentHunk && (line.startsWith('--- ') || line.startsWith('+++ '))) {\n const value = line.slice(4);\n const markerPath = decodeGitPath(value.startsWith('\"') ? value : value.split('\\t')[0]);\n if (markerPath !== '/dev/null') {\n if (line.startsWith('--- ')) currentFile.oldPath = markerPath.slice(2);\n else currentFile.newPath = markerPath.slice(2);\n }\n continue;\n }\n if (line === 'onboarder skipped symlink') { currentFile.skipReason = 'Untracked symlink: target not read'; continue; }\n if (line.startsWith('Binary files ') || line === 'GIT binary patch') { currentFile.binary = true; continue; }\n\n if (line.startsWith('new file mode ')) {\n currentFile.status = 'added';\n continue;\n }\n if (line.startsWith('deleted file mode ')) {\n currentFile.status = 'deleted';\n continue;\n }\n if (line.startsWith('rename from ')) {\n currentFile.status = 'renamed';\n currentFile.oldPath = decodeGitPath(line.slice(12));\n continue;\n }\n if (line.startsWith('rename to ')) {\n currentFile.newPath = decodeGitPath(line.slice(10));\n continue;\n }\n\n // Hunk header: @@ -1,5 +1,6 @@ optional context\n if (line.startsWith('@@ ')) {\n const match = line.match(/^@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@(.*)$/);\n if (match) {\n const oldStart = parseInt(match[1], 10);\n const oldLines = match[2] !== undefined ? parseInt(match[2], 10) : 1;\n const newStart = parseInt(match[3], 10);\n const newLines = match[4] !== undefined ? parseInt(match[4], 10) : 1;\n currentHunk = {\n header: line,\n oldStart,\n oldLines,\n newStart,\n newLines,\n heading: match[5]?.trim() || '',\n lines: [],\n };\n currentFile.hunks.push(currentHunk);\n }\n continue;\n }\n\n if (!currentHunk) continue;\n\n if (line.startsWith('+')) {\n currentFile.additions++;\n totalAdditions++;\n currentHunk.lines.push({\n type: 'add',\n text: line.slice(1),\n });\n } else if (line.startsWith('-')) {\n currentFile.deletions++;\n totalDeletions++;\n currentHunk.lines.push({\n type: 'del',\n text: line.slice(1),\n });\n } else if (line.startsWith(' ')) {\n currentHunk.lines.push({\n type: 'context',\n text: line.slice(1),\n });\n }\n }\n\n return {\n files,\n stats: {\n filesChanged: files.length,\n additions: totalAdditions,\n deletions: totalDeletions,\n },\n raw: diffText,\n };\n}\n"]}
@@ -0,0 +1,12 @@
1
+ export declare function gitLog(root: any): Promise<{
2
+ ok: boolean;
3
+ reason: string;
4
+ text?: undefined;
5
+ totalCommits?: undefined;
6
+ } | {
7
+ reason?: undefined;
8
+ ok: boolean;
9
+ text: any;
10
+ totalCommits: number;
11
+ }>;
12
+ export declare function parseGitLog(text: any): any[];