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
package/dist/cli.js ADDED
@@ -0,0 +1,442 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * cli.ts — Punto de entrada del CLI `pr-split-advisor`.
4
+ *
5
+ * ### Pipeline de análisis
6
+ * ```
7
+ * 1. Parsear argumentos CLI (Commander).
8
+ * 2. Cargar y validar configuración (loadConfig).
9
+ * 3. Verificar repositorio git limpio (requireGitRepo, requireCleanIndex).
10
+ * 4. Detectar rama actual; validar nomenclatura (obligatorio).
11
+ * 5. Validar rama base en el remoto (fetch + remoteTrackingExists + localBehindCount).
12
+ * 6. Recopilar archivos cambiados (gatherChangedFiles).
13
+ * 7. Calcular stats, dependencias, bloques y plan óptimo.
14
+ * 8. Imprimir resumen, archivos, dependencias, bloques y plan.
15
+ * 9. Exportar JSON si exportJson es true en el config.
16
+ * 10. Exportar reporte HTML.
17
+ * 11. Guardar historial de scores.
18
+ * ```
19
+ *
20
+ * ### Modos de ejecución
21
+ * | Flag | Comportamiento |
22
+ * |-----------|--------------------------------------------------------|
23
+ * | (ninguno) | Muestra el plan completo de división de PRs |
24
+ * | `--stats` | Muestra historial de scores y sale |
25
+ */
26
+ import { Command } from "commander";
27
+ import { parseAndValidateWorkingBranch } from "./git/branch-naming.js";
28
+ import { loadConfig } from "./config/config.js";
29
+ import { APP_BIN, APP_NAME, APP_VERSION } from "./shared/constants.js";
30
+ import { applyPlan } from "./git/executor.js";
31
+ import { detectRemote, fetchQuiet, getCurrentBranch, localAheadCount, localBehindCount, remoteTrackingExists, requireCleanIndex, requireGitRepo } from "./git/git.js";
32
+ import { buildBlocks, buildDependencyEdges, findBestPlan, gatherChangedFiles, getFileStats } from "./core/planner.js";
33
+ import { exportJson, writeHtmlReport } from "./output/report.js";
34
+ import { appendHistory, readHistory } from "./core/history.js";
35
+ import { buildSuggestedMessage } from "./core/commit-planner.js";
36
+ import { ui, closeReadlineInterface } from "./output/ui.js";
37
+ import { changeTypeLabel } from "./shared/utils.js";
38
+ import { aiEnrichPlans } from "./ai/enricher.js";
39
+ import { isAiEnabled, PROVIDER_REGISTRY } from "./ai/provider.js";
40
+ import { runConfigWizard, runConfigWithKey } from "./ai/config-wizard.js";
41
+ function normalizeStoryNumber(value) {
42
+ return value.trim().replace(/[^0-9]/g, "");
43
+ }
44
+ /**
45
+ * Pide al usuario el número de subtarea para cada commit del plan y rellena
46
+ * `commit.ticketCode` y `commit.suggestedMessage` con el resultado.
47
+ *
48
+ * Si no hay contexto de nomenclatura (teamCode/storyNumber) la función retorna
49
+ * sin modificar los planes (el mensaje sugerido original se mantiene).
50
+ */
51
+ async function enrichCommitTickets(plans, config) {
52
+ const teamCode = config.branchNamingContext?.teamCode;
53
+ const baseStoryNumber = config.branchNamingContext?.storyNumber;
54
+ if (!teamCode || !baseStoryNumber)
55
+ return;
56
+ const defaultTicket = `${teamCode}-${baseStoryNumber}`;
57
+ ui.section("CAPTURA DE NUMEROS PARA COMMITS", "#");
58
+ ui.info("Ingresa solo el numero de subtarea para cada commit. Si presionas Enter, se usara el numero de la historia base.");
59
+ ui.kv("Codigo de equipo", teamCode);
60
+ ui.kv("Numero por defecto", baseStoryNumber);
61
+ ui.kv("Ticket por defecto", defaultTicket);
62
+ for (const plan of plans) {
63
+ ui.subsection(plan.isExistingBaseBranch
64
+ ? `Rama base existente: ${plan.name}`
65
+ : `Rama derivada: ${plan.name}`);
66
+ for (const commit of plan.commitPlan) {
67
+ const preview = `${commit.suggestedType}(${commit.suggestedScope}): ${commit.suggestedSubject}`;
68
+ ui.muted(`Commit ${commit.index}`);
69
+ ui.muted(`Titulo base: ${preview}`);
70
+ const enteredNumber = await ui.prompt(`Numero de subtarea para commit ${commit.index}`, baseStoryNumber);
71
+ const normalizedNumber = normalizeStoryNumber(enteredNumber) || baseStoryNumber;
72
+ const finalTicket = `${teamCode}-${normalizedNumber}`;
73
+ commit.ticketCode = finalTicket;
74
+ commit.suggestedMessage = buildSuggestedMessage(commit.suggestedType, commit.suggestedScope, commit.suggestedSubject, finalTicket);
75
+ ui.ok(`Commit ${commit.index}: ${commit.suggestedMessage}`);
76
+ }
77
+ }
78
+ }
79
+ /**
80
+ * Calcula el porcentaje de archivos de test/spec dentro del conjunto cambiado.
81
+ * Considera test si la ruta contiene `test`, `spec`, `__tests__` o `__mocks__`.
82
+ */
83
+ function computeTestCoveragePercent(fileStats) {
84
+ if (fileStats.length === 0)
85
+ return 0;
86
+ const testFiles = fileStats.filter((f) => /\.(test|spec)\.[a-z]+$/.test(f.path) ||
87
+ f.path.includes("__tests__") ||
88
+ f.path.includes("__mocks__") ||
89
+ /\/tests?\//.test(f.path)).length;
90
+ return Math.round((testFiles / fileStats.length) * 100);
91
+ }
92
+ function printSummary(fileStats, config, currentBranch, baseBranch) {
93
+ const totalFiles = fileStats.length;
94
+ const totalLines = fileStats.reduce((sum, f) => sum + f.lines, 0);
95
+ const totalAdditions = fileStats.reduce((sum, f) => sum + f.additions, 0);
96
+ const totalDeletions = fileStats.reduce((sum, f) => sum + f.deletions, 0);
97
+ const createdFiles = fileStats.filter((f) => f.changeType === "A" || f.changeType === "U").length;
98
+ const updatedFiles = fileStats.filter((f) => f.changeType === "M").length;
99
+ const deletedFiles = fileStats.filter((f) => f.changeType === "D").length;
100
+ const renamedFiles = fileStats.filter((f) => f.changeType === "R").length;
101
+ const largeFiles = fileStats.filter((f) => f.lines > config.largeFileThreshold).length;
102
+ const testCoveragePercent = config.testCoveragePercent;
103
+ ui.header(APP_NAME.toUpperCase(), "Asesor de División de PRs", [
104
+ ["Rama actual", currentBranch],
105
+ ["Rama base del PR", baseBranch],
106
+ ["Score objetivo", config.targetScore],
107
+ ["Estrategia", "Puntuación máxima / división segura"],
108
+ ["Tipo de rama", config.branchNamingContext?.branchType ?? "N/A"],
109
+ ["Código de equipo", config.branchNamingContext?.teamCode ?? "N/A"],
110
+ ["Número de historia", config.branchNamingContext?.storyNumber ?? "N/A"]
111
+ ]);
112
+ ui.section("RESUMEN DE CAMBIOS", "#");
113
+ ui.dashboard([
114
+ ["Total de archivos", totalFiles, "blue"],
115
+ ["Lineas agregadas", totalAdditions, "green"],
116
+ ["Lineas borradas", totalDeletions, "red"],
117
+ ["Archivos creados", createdFiles, createdFiles > 0 ? "green" : "cyan"],
118
+ ["Archivos actualizados", updatedFiles, "blue"],
119
+ ["Archivos eliminados", deletedFiles, deletedFiles > 0 ? "yellow" : "cyan"],
120
+ ["Archivos renombrados", renamedFiles, renamedFiles > 0 ? "yellow" : "cyan"],
121
+ [`Archivos > ${config.largeFileThreshold} lineas`, largeFiles, largeFiles > 0 ? "yellow" : "green"],
122
+ ["Cobertura de tests", `${testCoveragePercent}%`, testCoveragePercent >= 20 ? "green" : testCoveragePercent > 0 ? "yellow" : "red"],
123
+ ["Max archivos por commit", config.maxFilesPerCommit, "cyan"],
124
+ ["Max lineas por commit ideal", config.maxLinesPerCommitIdeal, "cyan"],
125
+ ["Ideal lineas por PR", config.idealLinesPerPR, "cyan"],
126
+ ["Total de lineas tocadas", totalLines, "blue"]
127
+ ]);
128
+ }
129
+ function printFileStats(fileStats) {
130
+ ui.section("DETALLE DE ARCHIVOS", "#");
131
+ ui.table(["Marca", "Archivo", "Lineas", "+", "-", "Prioridad"], fileStats.map((f) => [
132
+ changeTypeLabel(f.changeType),
133
+ ui.truncateMiddle(f.path, 55),
134
+ f.lines,
135
+ f.additions,
136
+ f.deletions,
137
+ f.priority
138
+ ]), true);
139
+ }
140
+ function printDependencies(edges) {
141
+ ui.section("DEPENDENCIAS HEURISTICAS", "#");
142
+ if (!edges.length) {
143
+ ui.info("No se detectaron dependencias heuristicas.");
144
+ return;
145
+ }
146
+ ui.table(["Archivo origen", "Archivo dependencia"], edges.map((e) => [
147
+ ui.truncateMiddle(e.from, 45),
148
+ ui.truncateMiddle(e.to, 45)
149
+ ]), true);
150
+ }
151
+ function printBlocks(blocks) {
152
+ ui.section("BLOQUES DETECTADOS", "#");
153
+ ui.table(["Bloque", "Prioridad", "Divisible", "Lineas", "Archivos", "Dependencias"], blocks.map((b) => [
154
+ ui.blockLabel(b.id),
155
+ b.priority,
156
+ b.divisible ? "Si" : "No",
157
+ b.lines,
158
+ b.files.length,
159
+ b.depScore
160
+ ]), true);
161
+ }
162
+ function printPlans(plans, baseBranch, currentBranch, config) {
163
+ ui.section("PLAN RECOMENDADO", "#");
164
+ ui.kv("Rama actual", currentBranch);
165
+ ui.kv("Rama base del PR", baseBranch);
166
+ ui.kv("Total de PRs sugeridos", plans.length);
167
+ ui.kv("Ramas nuevas a crear", Math.max(plans.length - 1, 0));
168
+ for (const plan of plans) {
169
+ const scoreColor = ui.scoreColor(plan.score, config.targetScore);
170
+ const warnThreshold = config.targetScore > 4 ? 4 : Math.max(0, config.targetScore - 1);
171
+ const statusBadge = plan.score >= config.targetScore
172
+ ? ui.badge("ÓPTIMO", "green")
173
+ : plan.score >= warnThreshold
174
+ ? ui.badge("ACEPTABLE", "yellow")
175
+ : ui.badge("RIESGO", "red");
176
+ const riskBadge = plan.reason === "OK"
177
+ ? ui.badge("SIN ALERTAS", "green")
178
+ : ui.badge("CON ALERTAS", "yellow");
179
+ const title = plan.isExistingBaseBranch
180
+ ? `Rama existente base: ${plan.name}`
181
+ : `Rama sugerida a crear: ${plan.name}`;
182
+ ui.card(title, [
183
+ `${statusBadge} ${riskBadge} ${plan.isExistingBaseBranch ? ui.badge("BASE EXISTENTE", "cyan") : ui.badge("NUEVA RAMA", "blue")}`,
184
+ "",
185
+ `Archivos: ${plan.files}`,
186
+ `Lineas: ${plan.lines}`,
187
+ `Commits sugeridos: ${plan.commits}`,
188
+ `Promedio de archivos por commit: ${plan.filesPerCommit} (${plan.files} archivos / ${plan.commits} commits)`,
189
+ `Promedio de lineas por commit: ${plan.linesPerCommit} (${plan.lines} lineas / ${plan.commits} commits)`,
190
+ ...(plan.excludedCommitTypes?.length
191
+ ? [`⚠ M1.4 y M1.5 excluyen commits tipo: ${plan.excludedCommitTypes.join(", ")} (M1.3 y M3.2 usan todos los commits)`]
192
+ : []),
193
+ `Score estimado: ${ui.score(plan.score, config.targetScore)}`,
194
+ `Observacion: ${plan.reason}`,
195
+ `Metricas: ${Object.entries(plan.metrics).map(([k, v]) => `${k}=${v}`).join(", ")}`,
196
+ `Recomendacion: ${plan.recommendation ?? "N/A"}`
197
+ ], scoreColor, plan.isExistingBaseBranch
198
+ ? "Esta rama ya existe y debe usarse como el primer PR."
199
+ : "Esta rama debe crearse como PR derivado de la rama base existente.");
200
+ ui.subsection("Bloques de esta rama");
201
+ ui.table(["Bloque", "Prioridad", "Divisible", "Lineas", "Archivos", "Dependencias"], plan.blocks.map((block) => [
202
+ ui.blockLabel(block.id),
203
+ block.priority,
204
+ block.divisible ? "Si" : "No",
205
+ block.lines,
206
+ block.files.length,
207
+ block.depScore
208
+ ]), true);
209
+ ui.subsection("Plan de commits");
210
+ ui.table(["Commit", "Archivos", "Lineas", "Mensaje sugerido"], plan.commitPlan.map((commit) => [
211
+ commit.index,
212
+ commit.files.length,
213
+ commit.totalLines,
214
+ commit.suggestedMessage
215
+ ]), true);
216
+ for (const commit of plan.commitPlan) {
217
+ ui.muted(` Commit ${commit.index}`);
218
+ ui.muted(` Mensaje sugerido: ${commit.suggestedMessage}`);
219
+ ui.fileList(commit.files, 95);
220
+ }
221
+ ui.divider();
222
+ }
223
+ const avgScore = plans.length > 0
224
+ ? plans.reduce((sum, p) => sum + p.score, 0) / plans.length
225
+ : 0;
226
+ ui.summaryCard("Resumen final del plan", [
227
+ ["Cantidad total de PRs", plans.length, "blue"],
228
+ ["Ramas nuevas a crear", Math.max(plans.length - 1, 0), "cyan"],
229
+ ["Score promedio", avgScore.toFixed(2), ui.scoreColor(avgScore, config.targetScore)],
230
+ [
231
+ "Ramas por debajo del objetivo",
232
+ plans.filter((p) => p.score < config.targetScore).length,
233
+ plans.some((p) => p.score < config.targetScore) ? "yellow" : "green"
234
+ ],
235
+ [
236
+ "Ramas grandes indivisibles",
237
+ plans.filter((p) => p.reason.includes("indivisible")).length,
238
+ plans.some((p) => p.reason.includes("indivisible")) ? "yellow" : "green"
239
+ ]
240
+ ]);
241
+ }
242
+ async function main() {
243
+ const program = new Command();
244
+ program
245
+ .name(APP_BIN)
246
+ .description("Analiza cambios y opcionalmente crea ramas y commits")
247
+ .version(APP_VERSION, "-v, --version", "muestra la version actual")
248
+ .option("-b, --base <branch>", "rama base para analizar cambios del PR")
249
+ .option("--apply", "aplica el plan: crea ramas y commits (Enter acepta el valor sugerido)")
250
+ .option("--stats", "muestra el historial de scores y sale");
251
+ // ─── Acción principal (análisis de PRs) ─────────────────────────────────
252
+ // Se registra como .action() del programa raíz para que Commander la ejecute
253
+ // cuando no se pasa ningún subcomando. Sin esto, Commander muestra el help.
254
+ program.action(async (options) => {
255
+ const config = loadConfig();
256
+ // ─── --stats: mostrar historial y salir ─────────────────────────────────
257
+ if (options.stats) {
258
+ const history = readHistory(config);
259
+ if (history.length === 0) {
260
+ ui.info(`No hay historial de scores. El archivo se crea en la primera ejecución.`);
261
+ ui.muted(`Archivo: ${config.historyFile}`);
262
+ closeReadlineInterface();
263
+ return;
264
+ }
265
+ ui.section("HISTORIAL DE SCORES", "#");
266
+ ui.table(["Fecha", "Rama", "Base", "Score Prom.", "Ramas", "Archivos", "Líneas"], history.slice(-20).reverse().map((e) => [
267
+ new Date(e.timestamp).toLocaleString("es-PE"),
268
+ ui.truncateMiddle(e.branch, 35),
269
+ e.baseBranch,
270
+ e.avgScore.toFixed(2),
271
+ e.totalBranches,
272
+ e.totalFiles,
273
+ e.totalLines
274
+ ]), true);
275
+ closeReadlineInterface();
276
+ return;
277
+ }
278
+ config.runtimeExcludedFiles = [
279
+ config.jsonOutputFile,
280
+ "pr-split-advisor.config.json",
281
+ "pr-split-report.html",
282
+ config.historyFile
283
+ ].filter(Boolean);
284
+ if (config.verbose) {
285
+ ui.muted(`[verbose] targetScore: ${config.targetScore}`);
286
+ }
287
+ try {
288
+ requireGitRepo();
289
+ requireCleanIndex();
290
+ }
291
+ catch (error) {
292
+ ui.error(error.message);
293
+ closeReadlineInterface();
294
+ process.exit(1);
295
+ }
296
+ const baseBranch = options.base || config.baseBranch || "main";
297
+ const currentBranch = getCurrentBranch();
298
+ try {
299
+ config.branchNamingContext = parseAndValidateWorkingBranch(currentBranch);
300
+ }
301
+ catch (error) {
302
+ ui.error(error.message);
303
+ closeReadlineInterface();
304
+ process.exit(1);
305
+ }
306
+ // ─── Aviso de responsabilidad ────────────────────────────────────────────
307
+ ui.card("⚠️ AVISO DE RESPONSABILIDAD", [
308
+ "Esta herramienta genera un plan de distribución de cambios.",
309
+ "No ejecuta compilaciones ni suites de pruebas.",
310
+ "",
311
+ "Antes de implementar el plan, confirme que:",
312
+ " • El proyecto compile sin errores (ej: npm run build)",
313
+ " • Todas las pruebas finalicen correctamente (ej: npm test)",
314
+ "",
315
+ "La verificación de la integridad del código es responsabilidad del equipo de desarrollo.",
316
+ ], "yellow");
317
+ // ─── Validar rama base en el remoto ─────────────────────────────────────
318
+ const remote = detectRemote(currentBranch);
319
+ try {
320
+ fetchQuiet(remote, baseBranch);
321
+ }
322
+ catch {
323
+ ui.warn(`git fetch ${remote} ${baseBranch} falló. Se usará la info local del remoto.`);
324
+ }
325
+ if (!remoteTrackingExists(baseBranch, remote)) {
326
+ ui.error(`La rama base '${baseBranch}' no existe en el remoto '${remote}'.\n` +
327
+ `Publícala primero antes de continuar:\n` +
328
+ ` git push ${remote} ${baseBranch}`);
329
+ closeReadlineInterface();
330
+ process.exit(1);
331
+ }
332
+ const behind = localBehindCount(baseBranch, remote);
333
+ if (behind > 0) {
334
+ ui.error(`La rama '${baseBranch}' tiene ${behind} commit(s) pendiente(s) de '${remote}/${baseBranch}'.\n` +
335
+ `Actualizála antes de continuar:\n` +
336
+ ` git pull --rebase ${remote} ${baseBranch}`);
337
+ closeReadlineInterface();
338
+ process.exit(1);
339
+ }
340
+ ui.ok(`Rama base '${baseBranch}' verificada en '${remote}' (última versión).`);
341
+ const aheadCount = localAheadCount(baseBranch);
342
+ if (aheadCount > 0) {
343
+ ui.warn(`La rama '${currentBranch}' ya tiene ${aheadCount} commit(s) adelantados respecto a '${baseBranch}'.\n` +
344
+ `Los archivos ya commiteados aparecerán en el análisis pero no podrán re-commitearse al aplicar el plan.`);
345
+ }
346
+ // ─── Pipeline de análisis ────────────────────────────────────────────────
347
+ ui.spinner.start("Analizando cambios del working tree...");
348
+ const changedFiles = gatherChangedFiles(config, baseBranch);
349
+ if (!changedFiles.length) {
350
+ ui.spinner.stop();
351
+ ui.warn("No hay cambios sin commit en el working tree.");
352
+ closeReadlineInterface();
353
+ return;
354
+ }
355
+ const fileStats = getFileStats(changedFiles, baseBranch);
356
+ const deps = buildDependencyEdges(changedFiles);
357
+ const blocks = buildBlocks(fileStats, config, deps);
358
+ if (config.verbose) {
359
+ ui.muted(`[verbose] Archivos detectados: ${fileStats.length}`);
360
+ ui.muted(`[verbose] Dependencias heurísticas: ${deps.length}`);
361
+ ui.muted(`[verbose] Bloques formados: ${blocks.length}`);
362
+ }
363
+ const plans = findBestPlan(blocks, currentBranch, config, deps);
364
+ config.testCoveragePercent = computeTestCoveragePercent(fileStats);
365
+ ui.spinner.stop("Analisis completado.");
366
+ // ─── Enriquecimiento con IA (opcional) ───────────────────────────────────
367
+ // Si la IA no está habilitada o configurada, `aiEnrichPlans` retorna
368
+ // de inmediato sin modificar los planes (modo heurístico puro).
369
+ if (isAiEnabled(config)) {
370
+ const providerId = config.ai?.provider ?? "groq";
371
+ const providerLabel = PROVIDER_REGISTRY.get(providerId)?.label ?? providerId;
372
+ ui.info(`Modo IA activo: ${providerLabel} / ${config.ai?.model ?? "llama-3.3-70b-versatile"}`);
373
+ }
374
+ await aiEnrichPlans(plans, config, currentBranch);
375
+ printSummary(fileStats, config, currentBranch, baseBranch);
376
+ printFileStats(fileStats);
377
+ printDependencies(deps);
378
+ printBlocks(blocks);
379
+ printPlans(plans, baseBranch, currentBranch, config);
380
+ // ─── Exportar reporte HTML ───────────────────────────────────────────────
381
+ const reportInput = { currentBranch, baseBranch, config, fileStats, deps, blocks, plans };
382
+ const htmlFile = "pr-split-report.html";
383
+ writeHtmlReport(htmlFile, reportInput);
384
+ ui.ok(`Reporte HTML generado: ${htmlFile}`);
385
+ if (config.exportJson) {
386
+ exportJson(plans, currentBranch, baseBranch, config);
387
+ ui.ok(`Plan exportado a JSON: ${config.jsonOutputFile}`);
388
+ }
389
+ // ─── Guardar historial de scores ──────────────────────────────────────────
390
+ // Se guarda ANTES del apply: el análisis ya está completo en este punto.
391
+ // Si apply falla y llama process.exit(1), el historial ya fue persistido.
392
+ try {
393
+ appendHistory(plans, currentBranch, baseBranch, fileStats, config);
394
+ if (config.verbose)
395
+ ui.muted(`[verbose] Historial actualizado en: ${config.historyFile}`);
396
+ }
397
+ catch {
398
+ // El historial es best-effort; no debe interrumpir el flujo
399
+ }
400
+ // ─── Decidir si aplicar el plan ───────────────────────────────────────────
401
+ // --apply omite la pregunta y ejecuta directamente (modo no interactivo/CI).
402
+ // Sin el flag, siempre se pregunta al usuario tras ver el reporte y el HTML.
403
+ const shouldApply = !!options.apply || await ui.confirm("¿Deseas aplicar el plan ahora?");
404
+ if (shouldApply) {
405
+ await enrichCommitTickets(plans, config);
406
+ try {
407
+ await applyPlan(plans, config);
408
+ }
409
+ catch {
410
+ // El error ya fue impreso y el rollback ejecutado dentro de applyPlan.
411
+ closeReadlineInterface();
412
+ process.exit(1);
413
+ }
414
+ }
415
+ else {
416
+ ui.info("Sin cambios en git.");
417
+ }
418
+ closeReadlineInterface();
419
+ });
420
+ // ─── Subcomando: config ──────────────────────────────────────────────────
421
+ program
422
+ .command("config")
423
+ .description("Configura las opciones de la herramienta interactivamente (IA, etc.)")
424
+ .option("--api-key <key>", "API key del proveedor (omite el wizard interactivo)")
425
+ .option("--provider <id>", "Proveedor de IA: groq, copilot (predeterminado: groq)")
426
+ .action(async (opts) => {
427
+ if (opts.apiKey) {
428
+ await runConfigWithKey(opts.apiKey, opts.provider ?? "groq");
429
+ }
430
+ else {
431
+ await runConfigWizard();
432
+ }
433
+ closeReadlineInterface();
434
+ process.exit(0);
435
+ });
436
+ await program.parseAsync(process.argv);
437
+ }
438
+ main().catch((error) => {
439
+ ui.error(error.message);
440
+ closeReadlineInterface();
441
+ process.exit(1);
442
+ });