pull-request-split-advisor 3.1.2

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 (375) hide show
  1. package/LICENSE +52 -0
  2. package/README.md +168 -0
  3. package/dist/ai/config-wizard.js +282 -0
  4. package/dist/ai/enricher.js +290 -0
  5. package/dist/ai/prompts.js +231 -0
  6. package/dist/ai/provider.js +265 -0
  7. package/dist/cli.js +442 -0
  8. package/dist/config/config.js +315 -0
  9. package/dist/config/default-config.js +223 -0
  10. package/dist/core/blocks.js +145 -0
  11. package/dist/core/commit-planner.js +273 -0
  12. package/dist/core/dependency.js +284 -0
  13. package/dist/core/file-stats.js +341 -0
  14. package/dist/core/history.js +72 -0
  15. package/dist/core/planner.js +25 -0
  16. package/dist/core/scoring.js +166 -0
  17. package/dist/core/strategy.js +486 -0
  18. package/dist/git/branch-naming.js +120 -0
  19. package/dist/git/executor.js +378 -0
  20. package/dist/git/git.js +239 -0
  21. package/dist/output/report-styles.generated.js +10 -0
  22. package/dist/output/report.js +726 -0
  23. package/dist/output/ui.js +417 -0
  24. package/dist/shared/constants.js +59 -0
  25. package/dist/shared/types.js +7 -0
  26. package/dist/shared/utils.js +73 -0
  27. package/node_modules/@colors/colors/LICENSE +26 -0
  28. package/node_modules/@colors/colors/README.md +219 -0
  29. package/node_modules/@colors/colors/examples/normal-usage.js +83 -0
  30. package/node_modules/@colors/colors/examples/safe-string.js +80 -0
  31. package/node_modules/@colors/colors/index.d.ts +136 -0
  32. package/node_modules/@colors/colors/lib/colors.js +211 -0
  33. package/node_modules/@colors/colors/lib/custom/trap.js +46 -0
  34. package/node_modules/@colors/colors/lib/custom/zalgo.js +110 -0
  35. package/node_modules/@colors/colors/lib/extendStringPrototype.js +110 -0
  36. package/node_modules/@colors/colors/lib/index.js +13 -0
  37. package/node_modules/@colors/colors/lib/maps/america.js +10 -0
  38. package/node_modules/@colors/colors/lib/maps/rainbow.js +12 -0
  39. package/node_modules/@colors/colors/lib/maps/random.js +11 -0
  40. package/node_modules/@colors/colors/lib/maps/zebra.js +5 -0
  41. package/node_modules/@colors/colors/lib/styles.js +95 -0
  42. package/node_modules/@colors/colors/lib/system/has-flag.js +35 -0
  43. package/node_modules/@colors/colors/lib/system/supports-colors.js +151 -0
  44. package/node_modules/@colors/colors/package.json +45 -0
  45. package/node_modules/@colors/colors/safe.d.ts +48 -0
  46. package/node_modules/@colors/colors/safe.js +10 -0
  47. package/node_modules/@colors/colors/themes/generic-logging.js +12 -0
  48. package/node_modules/ansi-align/LICENSE +13 -0
  49. package/node_modules/ansi-align/README.md +80 -0
  50. package/node_modules/ansi-align/index.js +61 -0
  51. package/node_modules/ansi-align/node_modules/ansi-regex/index.d.ts +37 -0
  52. package/node_modules/ansi-align/node_modules/ansi-regex/index.js +10 -0
  53. package/node_modules/ansi-align/node_modules/ansi-regex/license +9 -0
  54. package/node_modules/ansi-align/node_modules/ansi-regex/package.json +55 -0
  55. package/node_modules/ansi-align/node_modules/ansi-regex/readme.md +78 -0
  56. package/node_modules/ansi-align/node_modules/emoji-regex/LICENSE-MIT.txt +20 -0
  57. package/node_modules/ansi-align/node_modules/emoji-regex/README.md +73 -0
  58. package/node_modules/ansi-align/node_modules/emoji-regex/es2015/index.js +6 -0
  59. package/node_modules/ansi-align/node_modules/emoji-regex/es2015/text.js +6 -0
  60. package/node_modules/ansi-align/node_modules/emoji-regex/index.d.ts +23 -0
  61. package/node_modules/ansi-align/node_modules/emoji-regex/index.js +6 -0
  62. package/node_modules/ansi-align/node_modules/emoji-regex/package.json +50 -0
  63. package/node_modules/ansi-align/node_modules/emoji-regex/text.js +6 -0
  64. package/node_modules/ansi-align/node_modules/string-width/index.d.ts +29 -0
  65. package/node_modules/ansi-align/node_modules/string-width/index.js +47 -0
  66. package/node_modules/ansi-align/node_modules/string-width/license +9 -0
  67. package/node_modules/ansi-align/node_modules/string-width/package.json +56 -0
  68. package/node_modules/ansi-align/node_modules/string-width/readme.md +50 -0
  69. package/node_modules/ansi-align/node_modules/strip-ansi/index.d.ts +17 -0
  70. package/node_modules/ansi-align/node_modules/strip-ansi/index.js +4 -0
  71. package/node_modules/ansi-align/node_modules/strip-ansi/license +9 -0
  72. package/node_modules/ansi-align/node_modules/strip-ansi/package.json +54 -0
  73. package/node_modules/ansi-align/node_modules/strip-ansi/readme.md +46 -0
  74. package/node_modules/ansi-align/package.json +43 -0
  75. package/node_modules/ansi-regex/index.d.ts +33 -0
  76. package/node_modules/ansi-regex/index.js +14 -0
  77. package/node_modules/ansi-regex/license +9 -0
  78. package/node_modules/ansi-regex/package.json +61 -0
  79. package/node_modules/ansi-regex/readme.md +66 -0
  80. package/node_modules/ansi-styles/index.d.ts +236 -0
  81. package/node_modules/ansi-styles/index.js +223 -0
  82. package/node_modules/ansi-styles/license +9 -0
  83. package/node_modules/ansi-styles/package.json +54 -0
  84. package/node_modules/ansi-styles/readme.md +173 -0
  85. package/node_modules/boxen/index.d.ts +267 -0
  86. package/node_modules/boxen/index.js +376 -0
  87. package/node_modules/boxen/license +9 -0
  88. package/node_modules/boxen/package.json +69 -0
  89. package/node_modules/boxen/readme.md +300 -0
  90. package/node_modules/camelcase/index.d.ts +102 -0
  91. package/node_modules/camelcase/index.js +110 -0
  92. package/node_modules/camelcase/license +9 -0
  93. package/node_modules/camelcase/package.json +47 -0
  94. package/node_modules/camelcase/readme.md +135 -0
  95. package/node_modules/chalk/license +9 -0
  96. package/node_modules/chalk/package.json +83 -0
  97. package/node_modules/chalk/readme.md +297 -0
  98. package/node_modules/chalk/source/index.d.ts +325 -0
  99. package/node_modules/chalk/source/index.js +225 -0
  100. package/node_modules/chalk/source/utilities.js +33 -0
  101. package/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
  102. package/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
  103. package/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
  104. package/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
  105. package/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
  106. package/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
  107. package/node_modules/cli-boxes/boxes.json +82 -0
  108. package/node_modules/cli-boxes/index.d.ts +127 -0
  109. package/node_modules/cli-boxes/index.js +6 -0
  110. package/node_modules/cli-boxes/license +9 -0
  111. package/node_modules/cli-boxes/package.json +42 -0
  112. package/node_modules/cli-boxes/readme.md +115 -0
  113. package/node_modules/cli-table3/LICENSE +21 -0
  114. package/node_modules/cli-table3/README.md +236 -0
  115. package/node_modules/cli-table3/index.d.ts +96 -0
  116. package/node_modules/cli-table3/index.js +1 -0
  117. package/node_modules/cli-table3/node_modules/ansi-regex/index.d.ts +37 -0
  118. package/node_modules/cli-table3/node_modules/ansi-regex/index.js +10 -0
  119. package/node_modules/cli-table3/node_modules/ansi-regex/license +9 -0
  120. package/node_modules/cli-table3/node_modules/ansi-regex/package.json +55 -0
  121. package/node_modules/cli-table3/node_modules/ansi-regex/readme.md +78 -0
  122. package/node_modules/cli-table3/node_modules/emoji-regex/LICENSE-MIT.txt +20 -0
  123. package/node_modules/cli-table3/node_modules/emoji-regex/README.md +73 -0
  124. package/node_modules/cli-table3/node_modules/emoji-regex/es2015/index.js +6 -0
  125. package/node_modules/cli-table3/node_modules/emoji-regex/es2015/text.js +6 -0
  126. package/node_modules/cli-table3/node_modules/emoji-regex/index.d.ts +23 -0
  127. package/node_modules/cli-table3/node_modules/emoji-regex/index.js +6 -0
  128. package/node_modules/cli-table3/node_modules/emoji-regex/package.json +50 -0
  129. package/node_modules/cli-table3/node_modules/emoji-regex/text.js +6 -0
  130. package/node_modules/cli-table3/node_modules/string-width/index.d.ts +29 -0
  131. package/node_modules/cli-table3/node_modules/string-width/index.js +47 -0
  132. package/node_modules/cli-table3/node_modules/string-width/license +9 -0
  133. package/node_modules/cli-table3/node_modules/string-width/package.json +56 -0
  134. package/node_modules/cli-table3/node_modules/string-width/readme.md +50 -0
  135. package/node_modules/cli-table3/node_modules/strip-ansi/index.d.ts +17 -0
  136. package/node_modules/cli-table3/node_modules/strip-ansi/index.js +4 -0
  137. package/node_modules/cli-table3/node_modules/strip-ansi/license +9 -0
  138. package/node_modules/cli-table3/node_modules/strip-ansi/package.json +54 -0
  139. package/node_modules/cli-table3/node_modules/strip-ansi/readme.md +46 -0
  140. package/node_modules/cli-table3/package.json +100 -0
  141. package/node_modules/cli-table3/src/cell.js +409 -0
  142. package/node_modules/cli-table3/src/debug.js +28 -0
  143. package/node_modules/cli-table3/src/layout-manager.js +254 -0
  144. package/node_modules/cli-table3/src/table.js +106 -0
  145. package/node_modules/cli-table3/src/utils.js +344 -0
  146. package/node_modules/commander/LICENSE +22 -0
  147. package/node_modules/commander/Readme.md +1157 -0
  148. package/node_modules/commander/esm.mjs +16 -0
  149. package/node_modules/commander/index.js +24 -0
  150. package/node_modules/commander/lib/argument.js +149 -0
  151. package/node_modules/commander/lib/command.js +2509 -0
  152. package/node_modules/commander/lib/error.js +39 -0
  153. package/node_modules/commander/lib/help.js +520 -0
  154. package/node_modules/commander/lib/option.js +330 -0
  155. package/node_modules/commander/lib/suggestSimilar.js +101 -0
  156. package/node_modules/commander/package-support.json +16 -0
  157. package/node_modules/commander/package.json +84 -0
  158. package/node_modules/commander/typings/esm.d.mts +3 -0
  159. package/node_modules/commander/typings/index.d.ts +969 -0
  160. package/node_modules/emoji-regex/LICENSE-MIT.txt +20 -0
  161. package/node_modules/emoji-regex/README.md +107 -0
  162. package/node_modules/emoji-regex/index.d.ts +3 -0
  163. package/node_modules/emoji-regex/index.js +4 -0
  164. package/node_modules/emoji-regex/index.mjs +4 -0
  165. package/node_modules/emoji-regex/package.json +45 -0
  166. package/node_modules/get-east-asian-width/index.d.ts +60 -0
  167. package/node_modules/get-east-asian-width/index.js +30 -0
  168. package/node_modules/get-east-asian-width/license +9 -0
  169. package/node_modules/get-east-asian-width/lookup-data.js +18 -0
  170. package/node_modules/get-east-asian-width/lookup.js +135 -0
  171. package/node_modules/get-east-asian-width/package.json +71 -0
  172. package/node_modules/get-east-asian-width/readme.md +65 -0
  173. package/node_modules/get-east-asian-width/utilities.js +24 -0
  174. package/node_modules/is-fullwidth-code-point/index.d.ts +17 -0
  175. package/node_modules/is-fullwidth-code-point/index.js +50 -0
  176. package/node_modules/is-fullwidth-code-point/license +9 -0
  177. package/node_modules/is-fullwidth-code-point/package.json +42 -0
  178. package/node_modules/is-fullwidth-code-point/readme.md +39 -0
  179. package/node_modules/isbinaryfile/LICENSE.txt +22 -0
  180. package/node_modules/isbinaryfile/README.md +70 -0
  181. package/node_modules/isbinaryfile/lib/index.d.ts +3 -0
  182. package/node_modules/isbinaryfile/lib/index.js +256 -0
  183. package/node_modules/isbinaryfile/package.json +64 -0
  184. package/node_modules/string-width/index.d.ts +39 -0
  185. package/node_modules/string-width/index.js +82 -0
  186. package/node_modules/string-width/license +9 -0
  187. package/node_modules/string-width/package.json +64 -0
  188. package/node_modules/string-width/readme.md +66 -0
  189. package/node_modules/strip-ansi/index.d.ts +15 -0
  190. package/node_modules/strip-ansi/index.js +19 -0
  191. package/node_modules/strip-ansi/license +9 -0
  192. package/node_modules/strip-ansi/package.json +59 -0
  193. package/node_modules/strip-ansi/readme.md +37 -0
  194. package/node_modules/type-fest/index.d.ts +178 -0
  195. package/node_modules/type-fest/license-cc0 +121 -0
  196. package/node_modules/type-fest/license-mit +9 -0
  197. package/node_modules/type-fest/package.json +91 -0
  198. package/node_modules/type-fest/readme.md +1060 -0
  199. package/node_modules/type-fest/source/all-union-fields.d.ts +88 -0
  200. package/node_modules/type-fest/source/and.d.ts +25 -0
  201. package/node_modules/type-fest/source/array-indices.d.ts +23 -0
  202. package/node_modules/type-fest/source/array-slice.d.ts +109 -0
  203. package/node_modules/type-fest/source/array-splice.d.ts +99 -0
  204. package/node_modules/type-fest/source/array-tail.d.ts +76 -0
  205. package/node_modules/type-fest/source/array-values.d.ts +22 -0
  206. package/node_modules/type-fest/source/arrayable.d.ts +29 -0
  207. package/node_modules/type-fest/source/async-return-type.d.ts +23 -0
  208. package/node_modules/type-fest/source/asyncify.d.ts +32 -0
  209. package/node_modules/type-fest/source/basic.d.ts +68 -0
  210. package/node_modules/type-fest/source/camel-case.d.ts +89 -0
  211. package/node_modules/type-fest/source/camel-cased-properties-deep.d.ts +97 -0
  212. package/node_modules/type-fest/source/camel-cased-properties.d.ts +43 -0
  213. package/node_modules/type-fest/source/conditional-except.d.ts +45 -0
  214. package/node_modules/type-fest/source/conditional-keys.d.ts +47 -0
  215. package/node_modules/type-fest/source/conditional-pick-deep.d.ts +118 -0
  216. package/node_modules/type-fest/source/conditional-pick.d.ts +44 -0
  217. package/node_modules/type-fest/source/conditional-simplify.d.ts +32 -0
  218. package/node_modules/type-fest/source/delimiter-case.d.ts +78 -0
  219. package/node_modules/type-fest/source/delimiter-cased-properties-deep.d.ts +106 -0
  220. package/node_modules/type-fest/source/delimiter-cased-properties.d.ts +46 -0
  221. package/node_modules/type-fest/source/distributed-omit.d.ts +89 -0
  222. package/node_modules/type-fest/source/distributed-pick.d.ts +85 -0
  223. package/node_modules/type-fest/source/empty-object.d.ts +46 -0
  224. package/node_modules/type-fest/source/enforce-optional.d.ts +47 -0
  225. package/node_modules/type-fest/source/entries.d.ts +62 -0
  226. package/node_modules/type-fest/source/entry.d.ts +65 -0
  227. package/node_modules/type-fest/source/exact.d.ts +68 -0
  228. package/node_modules/type-fest/source/except.d.ts +108 -0
  229. package/node_modules/type-fest/source/find-global-type.d.ts +64 -0
  230. package/node_modules/type-fest/source/fixed-length-array.d.ts +43 -0
  231. package/node_modules/type-fest/source/get.d.ts +219 -0
  232. package/node_modules/type-fest/source/global-this.d.ts +21 -0
  233. package/node_modules/type-fest/source/greater-than-or-equal.d.ts +22 -0
  234. package/node_modules/type-fest/source/greater-than.d.ts +56 -0
  235. package/node_modules/type-fest/source/has-optional-keys.d.ts +21 -0
  236. package/node_modules/type-fest/source/has-readonly-keys.d.ts +21 -0
  237. package/node_modules/type-fest/source/has-required-keys.d.ts +59 -0
  238. package/node_modules/type-fest/source/has-writable-keys.d.ts +21 -0
  239. package/node_modules/type-fest/source/if-any.d.ts +24 -0
  240. package/node_modules/type-fest/source/if-empty-object.d.ts +26 -0
  241. package/node_modules/type-fest/source/if-never.d.ts +24 -0
  242. package/node_modules/type-fest/source/if-null.d.ts +24 -0
  243. package/node_modules/type-fest/source/if-unknown.d.ts +24 -0
  244. package/node_modules/type-fest/source/includes.d.ts +22 -0
  245. package/node_modules/type-fest/source/int-closed-range.d.ts +35 -0
  246. package/node_modules/type-fest/source/int-range.d.ts +55 -0
  247. package/node_modules/type-fest/source/internal/array.d.ts +126 -0
  248. package/node_modules/type-fest/source/internal/characters.d.ts +67 -0
  249. package/node_modules/type-fest/source/internal/index.d.ts +8 -0
  250. package/node_modules/type-fest/source/internal/keys.d.ts +97 -0
  251. package/node_modules/type-fest/source/internal/numeric.d.ts +118 -0
  252. package/node_modules/type-fest/source/internal/object.d.ts +236 -0
  253. package/node_modules/type-fest/source/internal/string.d.ts +210 -0
  254. package/node_modules/type-fest/source/internal/tuple.d.ts +90 -0
  255. package/node_modules/type-fest/source/internal/type.d.ts +139 -0
  256. package/node_modules/type-fest/source/invariant-of.d.ts +76 -0
  257. package/node_modules/type-fest/source/is-any.d.ts +33 -0
  258. package/node_modules/type-fest/source/is-equal.d.ts +31 -0
  259. package/node_modules/type-fest/source/is-float.d.ts +41 -0
  260. package/node_modules/type-fest/source/is-integer.d.ts +58 -0
  261. package/node_modules/type-fest/source/is-literal.d.ts +296 -0
  262. package/node_modules/type-fest/source/is-never.d.ts +42 -0
  263. package/node_modules/type-fest/source/is-null.d.ts +20 -0
  264. package/node_modules/type-fest/source/is-tuple.d.ts +89 -0
  265. package/node_modules/type-fest/source/is-unknown.d.ts +52 -0
  266. package/node_modules/type-fest/source/iterable-element.d.ts +64 -0
  267. package/node_modules/type-fest/source/join.d.ts +68 -0
  268. package/node_modules/type-fest/source/jsonifiable.d.ts +37 -0
  269. package/node_modules/type-fest/source/jsonify.d.ts +122 -0
  270. package/node_modules/type-fest/source/kebab-case.d.ts +44 -0
  271. package/node_modules/type-fest/source/kebab-cased-properties-deep.d.ts +63 -0
  272. package/node_modules/type-fest/source/kebab-cased-properties.d.ts +40 -0
  273. package/node_modules/type-fest/source/keys-of-union.d.ts +42 -0
  274. package/node_modules/type-fest/source/last-array-element.d.ts +38 -0
  275. package/node_modules/type-fest/source/less-than-or-equal.d.ts +22 -0
  276. package/node_modules/type-fest/source/less-than.d.ts +26 -0
  277. package/node_modules/type-fest/source/literal-to-primitive-deep.d.ts +36 -0
  278. package/node_modules/type-fest/source/literal-to-primitive.d.ts +36 -0
  279. package/node_modules/type-fest/source/literal-union.d.ts +37 -0
  280. package/node_modules/type-fest/source/merge-deep.d.ts +486 -0
  281. package/node_modules/type-fest/source/merge-exclusive.d.ts +41 -0
  282. package/node_modules/type-fest/source/merge.d.ts +48 -0
  283. package/node_modules/type-fest/source/multidimensional-array.d.ts +44 -0
  284. package/node_modules/type-fest/source/multidimensional-readonly-array.d.ts +48 -0
  285. package/node_modules/type-fest/source/non-empty-object.d.ts +35 -0
  286. package/node_modules/type-fest/source/non-empty-string.d.ts +28 -0
  287. package/node_modules/type-fest/source/non-empty-tuple.d.ts +21 -0
  288. package/node_modules/type-fest/source/numeric.d.ts +222 -0
  289. package/node_modules/type-fest/source/observable-like.d.ts +63 -0
  290. package/node_modules/type-fest/source/omit-deep.d.ts +167 -0
  291. package/node_modules/type-fest/source/omit-index-signature.d.ts +95 -0
  292. package/node_modules/type-fest/source/opaque.d.ts +1 -0
  293. package/node_modules/type-fest/source/optional-keys-of.d.ts +39 -0
  294. package/node_modules/type-fest/source/or.d.ts +25 -0
  295. package/node_modules/type-fest/source/override-properties.d.ts +36 -0
  296. package/node_modules/type-fest/source/package-json.d.ts +676 -0
  297. package/node_modules/type-fest/source/partial-deep.d.ts +151 -0
  298. package/node_modules/type-fest/source/partial-on-undefined-deep.d.ts +78 -0
  299. package/node_modules/type-fest/source/pascal-case.d.ts +42 -0
  300. package/node_modules/type-fest/source/pascal-cased-properties-deep.d.ts +62 -0
  301. package/node_modules/type-fest/source/pascal-cased-properties.d.ts +36 -0
  302. package/node_modules/type-fest/source/paths.d.ts +262 -0
  303. package/node_modules/type-fest/source/pick-deep.d.ts +149 -0
  304. package/node_modules/type-fest/source/pick-index-signature.d.ts +50 -0
  305. package/node_modules/type-fest/source/primitive.d.ts +13 -0
  306. package/node_modules/type-fest/source/promisable.d.ts +25 -0
  307. package/node_modules/type-fest/source/readonly-deep.d.ts +81 -0
  308. package/node_modules/type-fest/source/readonly-keys-of.d.ts +30 -0
  309. package/node_modules/type-fest/source/readonly-tuple.d.ts +41 -0
  310. package/node_modules/type-fest/source/replace.d.ts +85 -0
  311. package/node_modules/type-fest/source/require-all-or-none.d.ts +51 -0
  312. package/node_modules/type-fest/source/require-at-least-one.d.ts +47 -0
  313. package/node_modules/type-fest/source/require-exactly-one.d.ts +45 -0
  314. package/node_modules/type-fest/source/require-one-or-none.d.ts +46 -0
  315. package/node_modules/type-fest/source/required-deep.d.ts +78 -0
  316. package/node_modules/type-fest/source/required-keys-of.d.ts +30 -0
  317. package/node_modules/type-fest/source/schema.d.ts +114 -0
  318. package/node_modules/type-fest/source/screaming-snake-case.d.ts +28 -0
  319. package/node_modules/type-fest/source/set-field-type.d.ts +65 -0
  320. package/node_modules/type-fest/source/set-non-nullable-deep.d.ts +83 -0
  321. package/node_modules/type-fest/source/set-non-nullable.d.ts +39 -0
  322. package/node_modules/type-fest/source/set-optional.d.ts +38 -0
  323. package/node_modules/type-fest/source/set-parameter-type.d.ts +117 -0
  324. package/node_modules/type-fest/source/set-readonly.d.ts +39 -0
  325. package/node_modules/type-fest/source/set-required-deep.d.ts +68 -0
  326. package/node_modules/type-fest/source/set-required.d.ts +70 -0
  327. package/node_modules/type-fest/source/set-return-type.d.ts +29 -0
  328. package/node_modules/type-fest/source/shared-union-fields-deep.d.ts +178 -0
  329. package/node_modules/type-fest/source/shared-union-fields.d.ts +76 -0
  330. package/node_modules/type-fest/source/simplify-deep.d.ts +115 -0
  331. package/node_modules/type-fest/source/simplify.d.ts +58 -0
  332. package/node_modules/type-fest/source/single-key-object.d.ts +29 -0
  333. package/node_modules/type-fest/source/snake-case.d.ts +45 -0
  334. package/node_modules/type-fest/source/snake-cased-properties-deep.d.ts +63 -0
  335. package/node_modules/type-fest/source/snake-cased-properties.d.ts +40 -0
  336. package/node_modules/type-fest/source/split.d.ts +88 -0
  337. package/node_modules/type-fest/source/spread.d.ts +84 -0
  338. package/node_modules/type-fest/source/string-key-of.d.ts +25 -0
  339. package/node_modules/type-fest/source/string-repeat.d.ts +47 -0
  340. package/node_modules/type-fest/source/string-slice.d.ts +37 -0
  341. package/node_modules/type-fest/source/stringified.d.ts +23 -0
  342. package/node_modules/type-fest/source/structured-cloneable.d.ts +92 -0
  343. package/node_modules/type-fest/source/subtract.d.ts +83 -0
  344. package/node_modules/type-fest/source/sum.d.ts +78 -0
  345. package/node_modules/type-fest/source/tagged-union.d.ts +51 -0
  346. package/node_modules/type-fest/source/tagged.d.ts +256 -0
  347. package/node_modules/type-fest/source/trim.d.ts +27 -0
  348. package/node_modules/type-fest/source/tsconfig-json.d.ts +1294 -0
  349. package/node_modules/type-fest/source/tuple-to-object.d.ts +42 -0
  350. package/node_modules/type-fest/source/tuple-to-union.d.ts +51 -0
  351. package/node_modules/type-fest/source/typed-array.d.ts +17 -0
  352. package/node_modules/type-fest/source/undefined-on-partial-deep.d.ts +80 -0
  353. package/node_modules/type-fest/source/union-to-intersection.d.ts +61 -0
  354. package/node_modules/type-fest/source/union-to-tuple.d.ts +56 -0
  355. package/node_modules/type-fest/source/unknown-array.d.ts +25 -0
  356. package/node_modules/type-fest/source/unknown-map.d.ts +24 -0
  357. package/node_modules/type-fest/source/unknown-record.d.ts +31 -0
  358. package/node_modules/type-fest/source/unknown-set.d.ts +24 -0
  359. package/node_modules/type-fest/source/value-of.d.ts +42 -0
  360. package/node_modules/type-fest/source/words.d.ts +118 -0
  361. package/node_modules/type-fest/source/writable-deep.d.ts +83 -0
  362. package/node_modules/type-fest/source/writable-keys-of.d.ts +33 -0
  363. package/node_modules/type-fest/source/writable.d.ts +68 -0
  364. package/node_modules/widest-line/index.d.ts +12 -0
  365. package/node_modules/widest-line/index.js +11 -0
  366. package/node_modules/widest-line/license +9 -0
  367. package/node_modules/widest-line/package.json +60 -0
  368. package/node_modules/widest-line/readme.md +26 -0
  369. package/node_modules/wrap-ansi/index.d.ts +41 -0
  370. package/node_modules/wrap-ansi/index.js +222 -0
  371. package/node_modules/wrap-ansi/license +9 -0
  372. package/node_modules/wrap-ansi/package.json +69 -0
  373. package/node_modules/wrap-ansi/readme.md +75 -0
  374. package/package.json +78 -0
  375. package/scripts/postinstall.cjs +122 -0
@@ -0,0 +1,273 @@
1
+ /**
2
+ * commit-planner.ts — Generación del plan de commits para una rama.
3
+ *
4
+ * A partir de los bloques asignados a una rama produce una secuencia ordenada
5
+ * de {@link CommitPlan}: cada elemento representa un commit con sus archivos,
6
+ * mensaje sugerido y metadatos (type, scope, subject).
7
+ *
8
+ * ### Algoritmo de agrupación
9
+ * 1. Los bloques se ordenan: prioridad asc → depScore desc → indivisibles primero → más líneas primero.
10
+ * 2. Bloques **indivisibles** o **medianos** (`lines > mediumFileThreshold`) van
11
+ * siempre en su propio commit (`mustIsolate = true`).
12
+ * 3. Los demás bloques se acumulan en el commit actual hasta superar
13
+ * `maxLinesPerCommitIdeal` o `maxFilesPerCommit`; entonces se flush y se empieza uno nuevo.
14
+ * 4. Al terminar el bucle, el grupo pendiente se flushea.
15
+ *
16
+ * ### Inferencia del mensaje de commit
17
+ * El tipo, scope y subject se infieren heurísticamente a partir de los nombres y
18
+ * rutas de los archivos del commit. Si `enrichCommitTickets` se ejecuta después,
19
+ * el ticket se incrusta en `suggestedMessage`.
20
+ *
21
+ * @module
22
+ */
23
+ import { basename, dirname } from "node:path";
24
+ import { normalizePathValue } from "../shared/utils.js";
25
+ // ---------------------------------------------------------------------------
26
+ // Commit type / scope / subject detection
27
+ // ---------------------------------------------------------------------------
28
+ // ---------------------------------------------------------------------------
29
+ // Inferencia de tipo, scope y subject del commit
30
+ // ---------------------------------------------------------------------------
31
+ /**
32
+ * Infiere el tipo Conventional Commits a partir de los patrones de ruta y nombre de los archivos.
33
+ *
34
+ * Tipos soportados (en orden de prioridad):
35
+ * 1. `ci` — archivos de CI/CD o DevSecOps
36
+ * 2. `docs` — todos los archivos son documentación
37
+ * 3. `test` — todos los archivos son pruebas
38
+ * 4. `style` — todos son archivos de formato/linters (CSS, .eslintrc, .prettierrc…)
39
+ * 5. `perf` — archivos con patrones de rendimiento/optimización
40
+ * 6. `refactor` — tipos, interfaces, schemas, DTOs, modelos
41
+ * 7. `fix` — archivos con patrones de corrección de errores (bugfix/hotfix)
42
+ * 8. `chore` — configuraciones, dependencias, YAML/TOML no-CI
43
+ * 9. `feat` — fallback para todo lo demás
44
+ *
45
+ * @param files - Rutas de los archivos del commit.
46
+ */
47
+ function detectCommitType(files) {
48
+ const lower = files.map((f) => f.toLowerCase());
49
+ // ci: integración continua / entrega continua / DevSecOps
50
+ if (lower.some((f) => /(?:^|\/)\.github\/workflows\//.test(f) ||
51
+ /(?:^|\/)\.gitlab-ci\.ya?ml$/.test(f) ||
52
+ /(?:^|\/)[jJ]enkinsfile(\.[^/]*)?$/.test(f) ||
53
+ /(?:^|\/)\.circleci\//.test(f) ||
54
+ /(?:^|\/)\.travis\.ya?ml$/.test(f) ||
55
+ /(?:^|\/)azure-pipelines\.ya?ml$/.test(f) ||
56
+ /(?:^|\/)bitbucket-pipelines\.ya?ml$/.test(f) ||
57
+ /(?:^|\/)[dD]ockerfile(\.[^/]*)?$/.test(f) ||
58
+ /(?:^|\/)docker-compose[^/]*\.ya?ml$/.test(f))) {
59
+ return "ci";
60
+ }
61
+ // docs: todos los archivos son documentación
62
+ if (lower.every((f) => /(^|\/)(docs|doc)(\/|$)|(^|\/)readme(\.[^/]*)?$|(^|\/)changelog(\.[^/]*)?$|\.md$|\.adoc$|\.rst$/.test(f))) {
63
+ return "docs";
64
+ }
65
+ // test: todos los archivos son pruebas unitarias
66
+ if (lower.every((f) => /(^|\/)(__tests__|tests|test)(\/|$)|(\.spec\.|\.test\.)/.test(f))) {
67
+ return "test";
68
+ }
69
+ // style: todos son archivos de formato o herramientas de estilo (linters, formateadores, CSS)
70
+ if (lower.every((f) => /\.(css|scss|sass|less)$/.test(f) ||
71
+ /(?:^|\/)\.eslintrc[^/]*$/.test(f) ||
72
+ /(?:^|\/)\.prettierrc[^/]*$/.test(f) ||
73
+ /(?:^|\/)\.editorconfig$/.test(f) ||
74
+ /(?:^|\/)\.stylelintrc[^/]*$/.test(f))) {
75
+ return "style";
76
+ }
77
+ // perf: mejoras de rendimiento sin cambios funcionales
78
+ if (lower.some((f) => /\b(perf|performance|optim|optimize|cache|memo|memoize)\b/.test(f))) {
79
+ return "perf";
80
+ }
81
+ // refactor: reestructuración de código sin nuevas funcionalidades ni correcciones
82
+ if (lower.some((f) => /\b(type|types|interface|interfaces|schema|schemas|dto|dtos|model|models)\b/.test(f))) {
83
+ return "refactor";
84
+ }
85
+ // fix: corrección de errores (aplica también a ramas bugfix y hotfix)
86
+ if (lower.some((f) => /\b(fix|bug|hotfix|patch)\b/.test(f))) {
87
+ return "fix";
88
+ }
89
+ // chore: configuraciones, dependencias externas, empaquetadores, migraciones
90
+ // .json solo es chore cuando es un archivo de configuración conocido; los .json en src/ pueden ser feat.
91
+ if (lower.some((f) => /(^|\/)(config|configs|settings)(\/|$)|\.ya?ml$|\.toml$/.test(f) ||
92
+ /(?:^|\/)(?:package|tsconfig[^/]*|\.babelrc|[a-z.]+\.config)\.json$/.test(f))) {
93
+ return "chore";
94
+ }
95
+ return "feat";
96
+ }
97
+ /**
98
+ * Infiere el scope del commit a partir del directorio más frecuente entre los archivos.
99
+ *
100
+ * Ignora directorios genéricos (`src`, `lib`, `app`, `dist`) que no aportan
101
+ * contexto útil. Si todos los archivos están en directorios genéricos, usa el
102
+ * nombre base del primer archivo como fallback.
103
+ *
104
+ * @param files - Rutas de los archivos del commit.
105
+ */
106
+ function detectCommitScope(files) {
107
+ const normalized = files.map((f) => normalizePathValue(f).toLowerCase());
108
+ // Derivar scope del directorio padre más frecuente (genérico para cualquier proyecto)
109
+ const dirs = normalized
110
+ .map((f) => dirname(f))
111
+ .filter((d) => d && d !== "." && d !== "/")
112
+ .map((d) => d.split("/").pop() ?? d);
113
+ if (dirs.length) {
114
+ const counts = new Map();
115
+ for (const dir of dirs)
116
+ counts.set(dir, (counts.get(dir) ?? 0) + 1);
117
+ const top = [...counts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0];
118
+ // Excluir carpetas genéricas que no aportan contexto
119
+ const generic = new Set(["src", "lib", "app", "dist"]);
120
+ if (top && !generic.has(top))
121
+ return top;
122
+ }
123
+ // Fallback: nombre base del primer archivo
124
+ const baseNames = normalized
125
+ .map((f) => basename(f).replace(/\.[^.]+$/, ""))
126
+ .filter(Boolean);
127
+ if (baseNames.length)
128
+ return baseNames[0];
129
+ return "core";
130
+ }
131
+ /**
132
+ * Genera un subject breve y legible para el commit a partir del tipo y los archivos.
133
+ *
134
+ * Las descripciones están en español para coincidir con la UI del proyecto.
135
+ * Para commits de tipo `feat` con un solo archivo, incluye el nombre del archivo
136
+ * para dar más contexto. El parámetro `_scope` está reservado para futura
137
+ * personalización por scope.
138
+ *
139
+ * @param files - Rutas de los archivos del commit.
140
+ * @param type - Tipo Conventional Commits ya inferido.
141
+ * @param _scope - Scope ya inferido (no usado actualmente, reservado).
142
+ */
143
+ function detectCommitSubject(files, type, _scope) {
144
+ const lower = files.map((f) => f.toLowerCase());
145
+ // Sujetos basados en el tipo (siempre aplicables, independientes del proyecto)
146
+ if (type === "ci")
147
+ return "actualizar configuracion de CI/CD";
148
+ if (type === "docs")
149
+ return "actualizar documentacion relacionada";
150
+ if (type === "test")
151
+ return "agregar o corregir pruebas unitarias";
152
+ if (type === "style")
153
+ return "aplicar formato y estilo de codigo";
154
+ if (type === "perf")
155
+ return "mejorar rendimiento de la aplicacion";
156
+ if (type === "fix")
157
+ return "corregir comportamiento incorrecto";
158
+ if (type === "revert")
159
+ return "revertir cambios anteriores";
160
+ if (type === "refactor")
161
+ return "refactorizar sin cambios de negocio";
162
+ if (type === "chore") {
163
+ if (lower.some((f) => /\.(ya?ml|toml)$/.test(f)))
164
+ return "actualizar archivos de configuracion";
165
+ return "actualizar dependencias o configuracion";
166
+ }
167
+ // Sujeto basado en extensión / tipo de archivo
168
+ if (lower.some((f) => f.endsWith(".html") || f.endsWith(".css"))) {
169
+ return "actualizar vistas y estilos";
170
+ }
171
+ // Fallback genérico
172
+ return files.length === 1
173
+ ? `actualizar ${basename(files[0]).toLowerCase()}`
174
+ : "actualizar archivos relacionados";
175
+ }
176
+ /**
177
+ * Combina las tres funciones de detección en un solo objeto de partes del título.
178
+ * Mantiene el orden de llamadas estándar para evitar repetirlo en cada sitio de uso.
179
+ */
180
+ export function buildCommitTitleParts(files) {
181
+ const suggestedType = detectCommitType(files);
182
+ const suggestedScope = detectCommitScope(files);
183
+ const suggestedSubject = detectCommitSubject(files, suggestedType, suggestedScope);
184
+ return { suggestedType, suggestedScope, suggestedSubject };
185
+ }
186
+ /**
187
+ * Construye el mensaje de commit en formato Conventional Commits:
188
+ * `type(scope): [ticket] subject`.
189
+ *
190
+ * @param suggestedType - Tipo inferido (feat, fix, chore, etc.).
191
+ * @param suggestedScope - Scope inferido del directorio/nombre de archivo.
192
+ * @param suggestedSubject - Descripción breve de los cambios.
193
+ * @param ticketCode - Prefijo de ticket opcional (p.ej. "ABC-123").
194
+ */
195
+ export function buildSuggestedMessage(suggestedType, suggestedScope, suggestedSubject, ticketCode) {
196
+ const ticketPart = ticketCode ? `${ticketCode} ` : "";
197
+ return `${suggestedType}(${suggestedScope}): ${ticketPart}${suggestedSubject}`;
198
+ }
199
+ // ---------------------------------------------------------------------------
200
+ // Public
201
+ // ---------------------------------------------------------------------------
202
+ /**
203
+ * Genera el plan de commits para un conjunto de bloques.
204
+ *
205
+ * Ordena los bloques por prioridad (asc), luego por depScore (desc), luego por
206
+ * divisibilidad y por tamaño, y los agrupa respetando `config.maxFilesPerCommit`
207
+ * y `config.maxLinesPerCommitIdeal`. Para cada grupo infiere type, scope y
208
+ * subject a partir de los nombres y rutas de los archivos.
209
+ *
210
+ * @param blocks - Bloques a incluir en el plan.
211
+ * @param config - Configuración activa del proyecto.
212
+ * @returns Array de {@link CommitPlan} en el orden de commit sugerido.
213
+ */
214
+ export function buildCommitPlan(blocks, config) {
215
+ // Si la rama tiene contexto de nomenclatura, usamos su ticket como prefijo automático.
216
+ const autoTicket = config.branchNamingContext
217
+ ? `${config.branchNamingContext.teamCode}-${config.branchNamingContext.storyNumber}`
218
+ : undefined;
219
+ const ordered = [...blocks].sort((a, b) => {
220
+ if (a.priority !== b.priority)
221
+ return a.priority - b.priority;
222
+ if (a.depScore !== b.depScore)
223
+ return b.depScore - a.depScore;
224
+ if (a.divisible !== b.divisible)
225
+ return a.divisible ? 1 : -1;
226
+ return b.lines - a.lines;
227
+ });
228
+ const commits = [];
229
+ let currentFiles = [];
230
+ let currentLines = 0;
231
+ let index = 1;
232
+ const pushCurrent = () => {
233
+ if (!currentFiles.length)
234
+ return;
235
+ const titleParts = buildCommitTitleParts(currentFiles);
236
+ commits.push({
237
+ index,
238
+ files: [...currentFiles],
239
+ totalLines: currentLines,
240
+ ...titleParts,
241
+ suggestedMessage: buildSuggestedMessage(titleParts.suggestedType, titleParts.suggestedScope, titleParts.suggestedSubject, autoTicket)
242
+ });
243
+ index += 1;
244
+ currentFiles = [];
245
+ currentLines = 0;
246
+ };
247
+ for (const block of ordered) {
248
+ const mustIsolate = !block.divisible || block.lines > config.mediumFileThreshold;
249
+ if (mustIsolate) {
250
+ pushCurrent();
251
+ const titleParts = buildCommitTitleParts(block.files);
252
+ commits.push({
253
+ index,
254
+ files: [...block.files],
255
+ totalLines: block.lines,
256
+ ...titleParts,
257
+ suggestedMessage: buildSuggestedMessage(titleParts.suggestedType, titleParts.suggestedScope, titleParts.suggestedSubject, autoTicket)
258
+ });
259
+ index += 1;
260
+ continue;
261
+ }
262
+ const projectedLines = currentLines + block.lines;
263
+ const projectedFiles = currentFiles.length + block.files.length;
264
+ if (projectedLines > config.maxLinesPerCommitIdeal ||
265
+ projectedFiles > config.maxFilesPerCommit) {
266
+ pushCurrent();
267
+ }
268
+ currentFiles.push(...block.files);
269
+ currentLines += block.lines;
270
+ }
271
+ pushCurrent();
272
+ return commits;
273
+ }
@@ -0,0 +1,284 @@
1
+ /**
2
+ * dependency.ts — Detección heurística de dependencias entre archivos cambiados.
3
+ *
4
+ * Analiza las sentencias de importación de los archivos modificados para
5
+ * construir un grafo de aristas `{ from, to }` donde ambos nodos pertenecen
6
+ * al conjunto de archivos cambiados. Las importaciones hacia código no tocado
7
+ * se ignoran (no aportan información útil para la división del PR).
8
+ *
9
+ * ### Lenguajes soportados
10
+ * - **TypeScript / JavaScript** (`.ts`, `.tsx`, `.js`, `.jsx`, `.mjs`, `.cjs`):
11
+ * detecta `import … from`, `require()` e `import()` dinámico.
12
+ * Resuelve rutas relativas probando las extensiones más comunes y los
13
+ * patrones de módulo índice (`index.ts`, `index.js`, etc.).
14
+ * - **Python** (`.py`): detecta `import …` y `from … import`.
15
+ * Soporta imports relativos (`from . import …`) y absolutos.
16
+ * - **Java** (`.java`): detecta `import com.package.ClassName;`.
17
+ * Construye el conjunto de archivos `.java` del repositorio una sola vez
18
+ * (con `git ls-files -- '*.java'`) para resolver en O(1) sin `find` por clase.
19
+ *
20
+ * ### Cachés de rendimiento
21
+ * - `_fileContentCache`: evita releer o ejecutar `git show HEAD:<archivo>` más de
22
+ * una vez por archivo en un mismo análisis. Se limpia al inicio de cada llamada
23
+ * a `buildDependencyEdges` para garantizar datos frescos.
24
+ */
25
+ import { readFileSync } from "node:fs";
26
+ import { dirname, extname } from "node:path";
27
+ import { q, shSafe } from "../git/git.js";
28
+ import { normalizePathValue, fileExistsInRepoOrFs } from "../shared/utils.js";
29
+ // ---------------------------------------------------------------------------
30
+ // Detección de lenguaje
31
+ // ---------------------------------------------------------------------------
32
+ /**
33
+ * Clasifica un archivo por su lenguaje de programación basándose en la extensión.
34
+ * Los lenguajes no reconocidos devuelven `"other"` y no se analiza su contenido.
35
+ */
36
+ function detectLanguage(file) {
37
+ const ext = extname(file).toLowerCase();
38
+ if ([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"].includes(ext))
39
+ return "js";
40
+ if (ext === ".py")
41
+ return "py";
42
+ if (ext === ".java")
43
+ return "java";
44
+ return "other";
45
+ }
46
+ // ---------------------------------------------------------------------------
47
+ // Lectura de archivos con caché en memoria
48
+ // ---------------------------------------------------------------------------
49
+ /** Caché de contenido por ruta para evitar releer o ejecutar `git show` múltiples veces. */
50
+ const _fileContentCache = new Map();
51
+ /**
52
+ * Limpia la caché de contenido de archivos.
53
+ * Útil para garantizar datos frescos entre análisis sucesivos en el mismo proceso (tests, llamadas encadenadas).
54
+ */
55
+ export function clearDependencyCache() {
56
+ _fileContentCache.clear();
57
+ }
58
+ /**
59
+ * Lee el contenido de un archivo para parsear sus imports.
60
+ *
61
+ * Estrategia:
62
+ * 1. Si el archivo existe en disco (working tree), lo lee directamente.
63
+ * 2. Si fue eliminado o no está en disco, intenta obtenerlo desde `git show HEAD:<ruta>`.
64
+ * Esto permite detectar dependencias de archivos que han sido borrados pero
65
+ * aún están en el último commit.
66
+ * 3. El resultado se cachéa para evitar releer el mismo archivo en el mismo análisis.
67
+ *
68
+ * @param file - Ruta relativa del archivo a leer.
69
+ * @returns Contenido del archivo como texto, o `""` si no se puede obtener.
70
+ */
71
+ function readFileForParsing(file) {
72
+ const cached = _fileContentCache.get(file);
73
+ if (cached !== undefined)
74
+ return cached;
75
+ let content;
76
+ try {
77
+ content = readFileSync(file, "utf8");
78
+ }
79
+ catch {
80
+ content = shSafe(`git show HEAD:${q(file)}`);
81
+ }
82
+ _fileContentCache.set(file, content);
83
+ return content;
84
+ }
85
+ // ---------------------------------------------------------------------------
86
+ // Resolvedores de rutas de import por lenguaje
87
+ // ---------------------------------------------------------------------------
88
+ /**
89
+ * Resuelve un import relativo JS/TS a una ruta de archivo concreta.
90
+ *
91
+ * Solo procesa imports relativos (que comienzan por `"."`). Los imports de
92
+ * módulos de node_modules o paths absolutos se ignoran porque no pertenecerán
93
+ * al conjunto de archivos cambiados.
94
+ *
95
+ * Prueba en orden: la ruta tal cual, + las extensiones `.ts`, `.tsx`, `.js`, `.jsx`,
96
+ * y los variantes `/index.<ext>`. Devuelve la primera que exista en disco o en git.
97
+ *
98
+ * @param importer - Ruta del archivo que contiene el import.
99
+ * @param imp - Valor del import (ej. `"./utils"`, `"../core/service"`).
100
+ * @returns Ruta resuelta o `null` si no se encuentra.
101
+ */
102
+ function resolveJsImport(importer, imp) {
103
+ if (!imp.startsWith("."))
104
+ return null;
105
+ const importerDir = dirname(importer);
106
+ const candidate = normalizePathValue(`${importerDir}/${imp}`);
107
+ const variants = [
108
+ candidate,
109
+ `${candidate}.ts`,
110
+ `${candidate}.tsx`,
111
+ `${candidate}.js`,
112
+ `${candidate}.jsx`,
113
+ `${candidate}.mjs`,
114
+ `${candidate}.cjs`,
115
+ `${candidate}/index.ts`,
116
+ `${candidate}/index.tsx`,
117
+ `${candidate}/index.js`,
118
+ `${candidate}/index.jsx`,
119
+ `${candidate}/index.mjs`,
120
+ `${candidate}/index.cjs`
121
+ ];
122
+ for (const v of variants) {
123
+ if (fileExistsInRepoOrFs(v))
124
+ return v;
125
+ }
126
+ return null;
127
+ }
128
+ /**
129
+ * Resuelve un import Python (relativo o absoluto) a una ruta de archivo.
130
+ *
131
+ * - Imports relativos (`from . import`, `from .utils import`): usa el directorio
132
+ * del importador como base y construye la ruta.
133
+ * - Imports absolutos (`import os.path`): convierte los puntos del paquete a `/`.
134
+ * - Prueba tanto `<ruta>.py` como `<ruta>/__init__.py` para soportar paquetes.
135
+ *
136
+ * @param importer - Ruta del archivo Python que contiene el import.
137
+ * @param imp - Módulo o paquete importado (ej. `"utils"`, `".helpers"`, `"core.service"`).
138
+ * @returns Ruta resuelta o `null` si no se encuentra.
139
+ */
140
+ function resolvePyImport(importer, imp) {
141
+ if (imp.startsWith(".")) {
142
+ const dots = imp.match(/^\.+/)[0].length;
143
+ let base = dirname(importer);
144
+ for (let i = 1; i < dots; i++)
145
+ base = dirname(base);
146
+ const trimmed = imp.replace(/^\.+/, "");
147
+ const target = trimmed
148
+ ? `${base}/${trimmed.replace(/\./g, "/")}`
149
+ : base;
150
+ for (const v of [`${target}.py`, `${target}/__init__.py`]) {
151
+ const normalized = normalizePathValue(v);
152
+ if (fileExistsInRepoOrFs(normalized))
153
+ return normalized;
154
+ }
155
+ return null;
156
+ }
157
+ const base = imp.replace(/\./g, "/");
158
+ for (const v of [`${base}.py`, `${base}/__init__.py`]) {
159
+ const normalized = normalizePathValue(v);
160
+ if (fileExistsInRepoOrFs(normalized))
161
+ return normalized;
162
+ }
163
+ return null;
164
+ }
165
+ /**
166
+ * Resuelve un import Java buscando en el conjunto pre-cargado de archivos .java.
167
+ * Evita lanzar un proceso `find` por cada sentencia import (O(n) por archivo → O(1) por import).
168
+ *
169
+ * @param imp - Nombre de clase o paquete Java a resolver.
170
+ * @param javaFiles - Conjunto de rutas .java del repositorio (construido una vez por análisis).
171
+ */
172
+ function resolveJavaImport(imp, javaFiles) {
173
+ if (!/^[a-zA-Z0-9_.]+$/.test(imp))
174
+ return null;
175
+ const rel = imp.replace(/\./g, "/") + ".java";
176
+ for (const f of javaFiles) {
177
+ if (f === rel || f.endsWith(`/${rel}`))
178
+ return f;
179
+ }
180
+ return null;
181
+ }
182
+ // ---------------------------------------------------------------------------
183
+ // Deduplicación de aristas
184
+ // ---------------------------------------------------------------------------
185
+ /**
186
+ * Elimina aristas duplicadas del grafo de dependencias.
187
+ *
188
+ * Una arista duplicada puede ocurrir cuando el mismo par `from → to` aparece
189
+ * en múltiples sentencias de import dentro del mismo archivo (poco frecuente,
190
+ * pero posible con barrel imports o re-exports).
191
+ *
192
+ * Usa un `Set<string>` de claves `"from=>to"` para detección O(n).
193
+ */
194
+ function dedupeEdges(edges) {
195
+ const seen = new Set();
196
+ const out = [];
197
+ for (const e of edges) {
198
+ const key = `${e.from}=>${e.to}`;
199
+ if (!seen.has(key)) {
200
+ seen.add(key);
201
+ out.push(e);
202
+ }
203
+ }
204
+ return out;
205
+ }
206
+ // ---------------------------------------------------------------------------
207
+ // Public
208
+ // ---------------------------------------------------------------------------
209
+ /**
210
+ * Detecta aristas de dependencia entre los archivos cambiados analizando sus
211
+ * sentencias de importación (TypeScript/JS, Python, Java).
212
+ *
213
+ * Solo se incluyen dependencias cuyo destino también esté en el conjunto de
214
+ * archivos cambiados; las importaciones hacia código no modificado se ignoran.
215
+ *
216
+ * Los contenidos de archivos se cachean en memoria para evitar múltiples
217
+ * llamadas a `readFileSync` o `git show` por el mismo archivo.
218
+ *
219
+ * @param files - Rutas relativas de los archivos cambiados en el working tree.
220
+ * @returns Array de aristas `{ from, to }` sin duplicados.
221
+ */
222
+ export function buildDependencyEdges(files) {
223
+ // Limpiar caché de contenido al iniciar cada análisis para evitar datos obsoletos.
224
+ // No se limpia _trackedFilesCache: ya es fresca desde getFileStats (llamado antes
225
+ // en el flujo CLI) y relanzar git ls-files sería redundante.
226
+ clearDependencyCache();
227
+ // Construir el conjunto de archivos .java del repositorio una sola vez.
228
+ // Evita lanzar un subproceso `find` por cada sentencia import Java.
229
+ const javaFiles = new Set(shSafe("git ls-files -- '*.java'")
230
+ .split("\n")
231
+ .map((s) => s.trim())
232
+ .filter(Boolean));
233
+ const changedSet = new Set(files);
234
+ const edges = [];
235
+ for (const file of files) {
236
+ const lang = detectLanguage(file);
237
+ const content = readFileForParsing(file);
238
+ if (lang === "js") {
239
+ const matches = [
240
+ ...content.matchAll(/from\s+['"]([^'"]+)['"]/g),
241
+ ...content.matchAll(/require\(['"]([^'"]+)['"]\)/g),
242
+ ...content.matchAll(/import\(['"]([^'"]+)['"]\)/g)
243
+ ];
244
+ for (const m of matches) {
245
+ const resolved = resolveJsImport(file, m[1]);
246
+ if (resolved && changedSet.has(resolved)) {
247
+ edges.push({ from: file, to: resolved });
248
+ }
249
+ }
250
+ }
251
+ if (lang === "py") {
252
+ const lines = content.split("\n");
253
+ for (const line of lines) {
254
+ let m = line.match(/^import\s+([a-zA-Z0-9_.]+)/);
255
+ if (m) {
256
+ const resolved = resolvePyImport(file, m[1]);
257
+ if (resolved && changedSet.has(resolved)) {
258
+ edges.push({ from: file, to: resolved });
259
+ }
260
+ }
261
+ m = line.match(/^from\s+([.a-zA-Z0-9_]+)\s+import/);
262
+ if (m) {
263
+ const resolved = resolvePyImport(file, m[1]);
264
+ if (resolved && changedSet.has(resolved)) {
265
+ edges.push({ from: file, to: resolved });
266
+ }
267
+ }
268
+ }
269
+ }
270
+ if (lang === "java") {
271
+ const lines = content.split("\n");
272
+ for (const line of lines) {
273
+ const m = line.match(/^import\s+([a-zA-Z0-9_.]+);/);
274
+ if (m) {
275
+ const resolved = resolveJavaImport(m[1], javaFiles);
276
+ if (resolved && changedSet.has(resolved)) {
277
+ edges.push({ from: file, to: resolved });
278
+ }
279
+ }
280
+ }
281
+ }
282
+ }
283
+ return dedupeEdges(edges);
284
+ }