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,290 @@
1
+ /**
2
+ * enricher.ts — Enriquecimiento post-heurístico de planes con IA.
3
+ *
4
+ * Recibe los planes generados por el motor heurístico (`findBestPlan`) y los
5
+ * mejora in-place usando el proveedor de IA configurado (Groq, GitHub Models o GitHub Copilot).
6
+ *
7
+ * ### Puntos de enriquecimiento
8
+ * 1. **Mensajes de commit** (`features.commitMessages`):
9
+ * Un request por rama con todos sus commits. El LLM devuelve subjects mejorados.
10
+ *
11
+ * 2. **Descripción de ramas** (`features.branchDescriptions`):
12
+ * Un request por rama derivada (no la rama base existente).
13
+ * El LLM devuelve un slug kebab-case mejorado para el nombre de rama.
14
+ *
15
+ * 3. **Rebalanceo del plan** (`features.planRebalance`):
16
+ * Un único request con el plan completo (todas las ramas y commits).
17
+ * El LLM propone mover archivos entre commits y ramas por cohesión semántica.
18
+ * La respuesta pasa validación estricta: diff de archivos, commits vacíos y
19
+ * reconstrucción completa del `commitPlan` con mensajes nuevos.
20
+ *
21
+ * ### Fallback silencioso
22
+ * Cualquier error individual (timeout, JSON inválido, error HTTP) es capturado.
23
+ * Se imprime un aviso y el elemento del plan conserva su valor heurístico original.
24
+ * El plan NUNCA queda en estado inconsistente por un fallo de la IA.
25
+ *
26
+ * ### Arquitectura
27
+ * ```
28
+ * findBestPlan() [heurístico, síncrono]
29
+ * ↓
30
+ * aiEnrichPlans() [IA, asíncrono, opcional — si isAiEnabled()]
31
+ * ↓
32
+ * printPlans() / exportJson / writeHtmlReport
33
+ * ```
34
+ */
35
+ import { isAiEnabled, callAI } from "./provider.js";
36
+ import { buildCommitMessagesPrompt, buildBranchDescriptionPrompt, buildPlanRebalancePrompt, } from "./prompts.js";
37
+ import { buildSuggestedMessage, buildCommitTitleParts } from "../core/commit-planner.js";
38
+ import { buildDerivedBranchName } from "../git/branch-naming.js";
39
+ import { ui } from "../output/ui.js";
40
+ // ---------------------------------------------------------------------------
41
+ // Helpers de parseo y validación
42
+ // ---------------------------------------------------------------------------
43
+ /** Normaliza un slug a kebab-case válido (a-z0-9-), máx. 50 chars. */
44
+ function sanitizeSlug(raw) {
45
+ const slug = raw
46
+ .toLowerCase()
47
+ .replace(/[^a-z0-9-]+/g, "-")
48
+ .replace(/^-+|-+$/g, "")
49
+ .replace(/--+/g, "-")
50
+ .slice(0, 50)
51
+ .replace(/-+$/, "");
52
+ return slug.length >= 2 ? slug : null;
53
+ }
54
+ // ---------------------------------------------------------------------------
55
+ // Enriquecimiento de mensajes de commit
56
+ // ---------------------------------------------------------------------------
57
+ async function enrichCommitMessages(plan, config) {
58
+ const messages = buildCommitMessagesPrompt(plan);
59
+ const response = await callAI(messages, config);
60
+ let parsed;
61
+ try {
62
+ parsed = JSON.parse(response.content);
63
+ }
64
+ catch {
65
+ return 0; // JSON inválido → conservar heurístico
66
+ }
67
+ if (!Array.isArray(parsed.commits))
68
+ return 0;
69
+ for (const aiCommit of parsed.commits) {
70
+ const commit = plan.commitPlan.find((c) => c.index === aiCommit.index);
71
+ if (!commit)
72
+ continue;
73
+ const type = typeof aiCommit.type === "string" && aiCommit.type.trim()
74
+ ? aiCommit.type.trim()
75
+ : commit.suggestedType;
76
+ const scope = typeof aiCommit.scope === "string" && aiCommit.scope.trim()
77
+ ? aiCommit.scope.trim()
78
+ : commit.suggestedScope;
79
+ const subject = typeof aiCommit.subject === "string" && aiCommit.subject.trim()
80
+ ? aiCommit.subject.trim().slice(0, 72)
81
+ : commit.suggestedSubject;
82
+ commit.suggestedType = type;
83
+ commit.suggestedScope = scope;
84
+ commit.suggestedSubject = subject;
85
+ commit.suggestedMessage = buildSuggestedMessage(type, scope, subject, commit.ticketCode);
86
+ }
87
+ return response.tokensUsed;
88
+ }
89
+ // ---------------------------------------------------------------------------
90
+ // Enriquecimiento de descripción de rama
91
+ // ---------------------------------------------------------------------------
92
+ async function enrichBranchDescription(plan, config, currentBranch) {
93
+ // Extraer el slug actual del nombre de rama: type/TEAM-123-<slug>
94
+ const match = plan.name.match(/^[^/]+\/[A-Za-z]+-\d+-(.+)$/);
95
+ const currentSlug = match ? match[1] : "";
96
+ if (!currentSlug)
97
+ return 0;
98
+ const messages = buildBranchDescriptionPrompt(plan, currentSlug);
99
+ const response = await callAI(messages, config);
100
+ let parsed;
101
+ try {
102
+ parsed = JSON.parse(response.content);
103
+ }
104
+ catch {
105
+ return response.tokensUsed;
106
+ }
107
+ const rawSlug = typeof parsed.description === "string" ? parsed.description : "";
108
+ const slug = sanitizeSlug(rawSlug);
109
+ if (!slug || slug === currentSlug)
110
+ return response.tokensUsed;
111
+ const ctx = config.branchNamingContext;
112
+ if (!ctx)
113
+ return response.tokensUsed;
114
+ try {
115
+ const newName = buildDerivedBranchName(ctx, slug);
116
+ // No renombrar la rama activa (sería la rama base existente)
117
+ if (newName && newName !== currentBranch) {
118
+ plan.name = newName;
119
+ }
120
+ }
121
+ catch {
122
+ // buildDerivedBranchName puede rechazar slugs inválidos → conservar original
123
+ }
124
+ return response.tokensUsed;
125
+ }
126
+ // ---------------------------------------------------------------------------
127
+ // Rebalanceo del plan
128
+ // ---------------------------------------------------------------------------
129
+ async function aiRebalancePlan(plans, config) {
130
+ const messages = buildPlanRebalancePrompt(plans);
131
+ const response = await callAI(messages, config);
132
+ let parsed;
133
+ try {
134
+ parsed = JSON.parse(response.content);
135
+ }
136
+ catch {
137
+ return response.tokensUsed;
138
+ }
139
+ if (!Array.isArray(parsed.branches))
140
+ return response.tokensUsed;
141
+ // Mapa global de archivo → líneas (calculado antes de mutar)
142
+ const fileLines = new Map();
143
+ for (const plan of plans) {
144
+ for (const commit of plan.commitPlan) {
145
+ const linesEach = commit.files.length > 0
146
+ ? Math.round(commit.totalLines / commit.files.length)
147
+ : 0;
148
+ for (const f of commit.files) {
149
+ if (!fileLines.has(f))
150
+ fileLines.set(f, linesEach);
151
+ }
152
+ }
153
+ }
154
+ // ── Validación estricta ────────────────────────────────────────────────
155
+ const inputFiles = new Set(plans.flatMap((p) => p.commitPlan.flatMap((c) => c.files)));
156
+ if (parsed.branches.length !== plans.length)
157
+ return response.tokensUsed;
158
+ const seen = new Set();
159
+ for (const aiBranch of parsed.branches) {
160
+ if (aiBranch.branchIndex < 0 ||
161
+ aiBranch.branchIndex >= plans.length)
162
+ return response.tokensUsed;
163
+ for (const commit of aiBranch.commits ?? []) {
164
+ if (!Array.isArray(commit.files) || commit.files.length === 0)
165
+ return response.tokensUsed;
166
+ for (const f of commit.files) {
167
+ if (seen.has(f) || !inputFiles.has(f))
168
+ return response.tokensUsed;
169
+ seen.add(f);
170
+ }
171
+ }
172
+ }
173
+ if (seen.size !== inputFiles.size)
174
+ return response.tokensUsed;
175
+ // ── Aplicar rebalanceo ─────────────────────────────────────────────────
176
+ const autoTicket = config.branchNamingContext
177
+ ? `${config.branchNamingContext.teamCode}-${config.branchNamingContext.storyNumber}`
178
+ : undefined;
179
+ for (const aiBranch of parsed.branches) {
180
+ const plan = plans[aiBranch.branchIndex];
181
+ if (!plan)
182
+ continue;
183
+ const newCommits = aiBranch.commits.map((ac, idx) => {
184
+ const parts = buildCommitTitleParts(ac.files);
185
+ const totalLines = ac.files.reduce((sum, f) => sum + (fileLines.get(f) ?? 0), 0);
186
+ return {
187
+ index: idx + 1,
188
+ files: ac.files,
189
+ totalLines,
190
+ suggestedType: parts.suggestedType,
191
+ suggestedScope: parts.suggestedScope,
192
+ suggestedSubject: parts.suggestedSubject,
193
+ ticketCode: autoTicket,
194
+ suggestedMessage: buildSuggestedMessage(parts.suggestedType, parts.suggestedScope, parts.suggestedSubject, autoTicket),
195
+ };
196
+ });
197
+ plan.commitPlan = newCommits;
198
+ plan.commits = newCommits.length;
199
+ plan.files = newCommits.reduce((s, c) => s + c.files.length, 0);
200
+ plan.lines = newCommits.reduce((s, c) => s + c.totalLines, 0);
201
+ plan.filesPerCommit = Number((plan.files / Math.max(plan.commits, 1)).toFixed(2));
202
+ plan.linesPerCommit = Number((plan.lines / Math.max(plan.commits, 1)).toFixed(2));
203
+ }
204
+ return response.tokensUsed;
205
+ }
206
+ // ---------------------------------------------------------------------------
207
+ // Punto de entrada público
208
+ // ---------------------------------------------------------------------------
209
+ /**
210
+ * Enriquece los planes del análisis heurístico usando el proveedor de IA configurado.
211
+ *
212
+ * Los planes se mutan **in-place**. Si la IA no está configurada o falla,
213
+ * los planes quedan intactos (modo heurístico puro).
214
+ *
215
+ * @param plans Planes generados por `findBestPlan()`.
216
+ * @param config Configuración completa (incluye `config.ai`).
217
+ * @param currentBranch Nombre de la rama activa (no se renombra).
218
+ */
219
+ export async function aiEnrichPlans(plans, config, currentBranch) {
220
+ if (!isAiEnabled(config))
221
+ return;
222
+ const features = config.ai.features;
223
+ const errors = [];
224
+ let totalTokens = 0;
225
+ ui.spinner.start("Enriqueciendo plan con IA...");
226
+ // ── Rebalanceo de archivos entre commits y ramas ───────────────────────
227
+ if (features.planRebalance) {
228
+ try {
229
+ totalTokens += await aiRebalancePlan(plans, config);
230
+ ui.spinner.stop();
231
+ ui.ok("IA rebalanceó la distribución de archivos entre commits y ramas.");
232
+ ui.spinner.start("Enriqueciendo plan con IA...");
233
+ }
234
+ catch (err) {
235
+ const msg = `plan-rebalance: ${err.message}`;
236
+ errors.push(msg);
237
+ ui.spinner.stop();
238
+ ui.warn(`IA falló en rebalanceo — se usará distribución heurística.\n • ${msg}`);
239
+ ui.spinner.start("Enriqueciendo plan con IA...");
240
+ }
241
+ }
242
+ for (const plan of plans) {
243
+ // ── Mensajes de commit ─────────────────────────────────────────────────
244
+ if (features.commitMessages && plan.commitPlan.length > 0) {
245
+ try {
246
+ totalTokens += await enrichCommitMessages(plan, config);
247
+ }
248
+ catch (err) {
249
+ const msg = `commit-messages [${plan.name}]: ${err.message}`;
250
+ errors.push(msg);
251
+ ui.spinner.stop();
252
+ ui.warn(`IA falló — se usará resultado heurístico.\n • ${msg}`);
253
+ ui.spinner.start("Enriqueciendo plan con IA...");
254
+ }
255
+ }
256
+ // ── Descripción de rama (solo ramas derivadas, no la base existente) ───
257
+ if (features.branchDescriptions && !plan.isExistingBaseBranch) {
258
+ try {
259
+ totalTokens += await enrichBranchDescription(plan, config, currentBranch);
260
+ }
261
+ catch (err) {
262
+ const msg = `branch-desc [${plan.name}]: ${err.message}`;
263
+ errors.push(msg);
264
+ ui.spinner.stop();
265
+ ui.warn(`IA falló — se usará resultado heurístico.\n • ${msg}`);
266
+ ui.spinner.start("Enriqueciendo plan con IA...");
267
+ }
268
+ }
269
+ }
270
+ ui.spinner.stop("Enriquecimiento con IA completado.");
271
+ // Post-deduplicación: la IA puede asignar el mismo slug a varias ramas
272
+ // del mismo módulo, deshaciendo la deduplicación previa de strategy.ts.
273
+ // Aplicamos el mismo algoritmo: sufijo numérico -1, -2... para los duplicados.
274
+ const derivedAfterEnrich = plans.filter((p) => !p.isExistingBaseBranch);
275
+ const nameCount = new Map();
276
+ for (const p of derivedAfterEnrich) {
277
+ nameCount.set(p.name, (nameCount.get(p.name) ?? 0) + 1);
278
+ }
279
+ const nameIdx = new Map();
280
+ for (const plan of derivedAfterEnrich) {
281
+ if ((nameCount.get(plan.name) ?? 0) <= 1)
282
+ continue;
283
+ const n = nameIdx.get(plan.name) ?? 1;
284
+ nameIdx.set(plan.name, n + 1);
285
+ plan.name = `${plan.name}-${n}`;
286
+ }
287
+ if (config.verbose && totalTokens > 0) {
288
+ ui.muted(`[verbose] Tokens IA usados: ${totalTokens}`);
289
+ }
290
+ }
@@ -0,0 +1,231 @@
1
+ /**
2
+ * prompts.ts — Constructores de mensajes para las llamadas a la API de IA.
3
+ *
4
+ * Cada función devuelve un array de `AIMessage` listo para pasar a `callAI`.
5
+ * Los prompts exigen que el modelo responda estrictamente en JSON.
6
+ *
7
+ * ### Contratos de respuesta esperada
8
+ * | Función | JSON esperado |
9
+ * |-------------------------------|------------------------------------------------------------------|
10
+ * | buildCommitMessagesPrompt | `{ "commits": [{ "index": 1, "type": "feat", "scope": "auth", "subject": "..." }] }` |
11
+ * | buildBranchDescriptionPrompt | `{ "description": "kebab-case-slug" }` |
12
+ * | buildPlanRebalancePrompt | `{ "branches": [{ "branchIndex": 0, "commits": [{ "commitIndex": 0, "files": ["..."] }] }] }` |
13
+ */
14
+ // ---------------------------------------------------------------------------
15
+ // Commit messages
16
+ // ---------------------------------------------------------------------------
17
+ /**
18
+ * Construye el prompt para mejorar los mensajes de commit de una rama.
19
+ *
20
+ * Envía todos los commits de la rama en un único request para minimizar
21
+ * el número de llamadas a la API.
22
+ */
23
+ export function buildCommitMessagesPrompt(plan) {
24
+ const commitDescriptions = plan.commitPlan
25
+ .map((c) => {
26
+ const maxFiles = 30;
27
+ const shown = c.files.slice(0, maxFiles).join("\n - ");
28
+ const overflow = c.files.length > maxFiles ? `\n - (+${c.files.length - maxFiles} more files)` : "";
29
+ return [
30
+ `Commit ${c.index}:`,
31
+ ` Heuristic suggestion: ${c.suggestedType}(${c.suggestedScope}): ${c.suggestedSubject}`,
32
+ ` Changed files (${c.files.length}):`,
33
+ ` - ${shown}${overflow}`,
34
+ ` Lines changed: ~${c.totalLines} lines`,
35
+ ].join("\n");
36
+ })
37
+ .join("\n\n");
38
+ // Extraer módulos únicos del plan para dar contexto
39
+ const modules = [...new Set(plan.commitPlan.flatMap((c) => c.files.map((f) => f.split("/").slice(0, 2).join("/"))))].slice(0, 10).join(", ");
40
+ return [
41
+ {
42
+ role: "system",
43
+ content: [
44
+ "You are a senior software engineer expert at writing git conventional commit messages.",
45
+ "Analyze the changed files carefully — the file paths reveal the domain, layer, and intent.",
46
+ "Your job: rewrite the heuristic subject lines to be precise, developer-friendly, and actionable.",
47
+ "",
48
+ "STRICT RULES:",
49
+ "- Imperative mood ONLY: 'add', 'fix', 'update', 'implement', 'refactor', 'remove', 'expose', 'wire'...",
50
+ " BAD: 'added login', 'fixes bug', 'updating config'",
51
+ " GOOD: 'add login endpoint', 'fix null pointer in auth', 'update config schema'",
52
+ "- Maximum 72 characters per subject",
53
+ "- Use the heuristic type/scope as starting point; only change if clearly wrong",
54
+ "- Be SPECIFIC: mention the module, entity, or feature affected — not generic verbs alone",
55
+ " BAD: 'update files', 'add code', 'fix stuff'",
56
+ " GOOD: 'add user profile picture upload endpoint', 'fix token expiry in refresh flow'",
57
+ "- No trailing period",
58
+ "- Do NOT include the ticket code in the subject (it will be prepended automatically)",
59
+ "- Infer intent from file names: e.g. 'auth/jwt.ts' → JWT/auth changes, 'payments/stripe.ts' → Stripe integration",
60
+ "",
61
+ "FEW-SHOT EXAMPLES:",
62
+ "Files: src/auth/login.ts, src/auth/token.ts → feat(auth): implement JWT-based login and token refresh",
63
+ "Files: src/payments/stripe.ts, src/payments/webhook.ts → feat(payments): integrate Stripe payment and webhook handling",
64
+ "Files: src/users/profile.ts, src/users/avatar.ts → feat(users): add profile management and avatar upload",
65
+ "Files: tests/auth.spec.ts, tests/token.spec.ts → test(auth): add unit tests for login and token refresh",
66
+ "Files: docker-compose.yml, .env.example → chore(infra): update Docker compose and env template",
67
+ "",
68
+ "Return ONLY a valid JSON object — no markdown, no explanation, no extra text:",
69
+ '{"commits": [{"index": 1, "type": "feat", "scope": "auth", "subject": "implement JWT-based login and token refresh"}, ...]}',
70
+ ].join("\n"),
71
+ },
72
+ {
73
+ role: "user",
74
+ content: [
75
+ `Branch: ${plan.name}`,
76
+ `Main modules involved: ${modules || "(unknown)"}`,
77
+ `Total commits in this branch: ${plan.commitPlan.length}`,
78
+ "",
79
+ "Commits to improve:",
80
+ "",
81
+ commitDescriptions,
82
+ "",
83
+ "Remember: be specific about what each commit does based on its file paths. Avoid generic subjects.",
84
+ ].join("\n"),
85
+ },
86
+ ];
87
+ }
88
+ // ---------------------------------------------------------------------------
89
+ // Branch description slug
90
+ // ---------------------------------------------------------------------------
91
+ /**
92
+ * Construye el prompt para mejorar el slug de descripción de una rama derivada.
93
+ */
94
+ export function buildBranchDescriptionPrompt(plan, currentSlug) {
95
+ const allFiles = plan.commitPlan.flatMap((c) => c.files);
96
+ const shown = allFiles.slice(0, 40).map((f) => ` - ${f}`).join("\n");
97
+ const overflow = allFiles.length > 40 ? `\n - (+${allFiles.length - 40} more files)` : "";
98
+ // Extraer módulos únicos dominantes para dar más contexto al LLM
99
+ const moduleFreq = new Map();
100
+ for (const f of allFiles) {
101
+ const mod = f.split("/").slice(0, 2).join("/");
102
+ moduleFreq.set(mod, (moduleFreq.get(mod) ?? 0) + 1);
103
+ }
104
+ const topModules = [...moduleFreq.entries()]
105
+ .sort((a, b) => b[1] - a[1])
106
+ .slice(0, 5)
107
+ .map(([mod, count]) => `${mod} (${count} files)`)
108
+ .join(", ");
109
+ // Recopilar los mensajes de commits enriquecidos para dar más contexto
110
+ const commitSummary = plan.commitPlan
111
+ .map((c) => ` - ${c.suggestedMessage || c.suggestedSubject}`)
112
+ .join("\n");
113
+ return [
114
+ {
115
+ role: "system",
116
+ content: [
117
+ "You are a senior software engineer expert at naming git branches.",
118
+ "Your goal: generate a slug that PRECISELY describes WHAT this branch does, not WHERE the files are.",
119
+ "",
120
+ "STRICT RULES:",
121
+ "- kebab-case ONLY: lowercase letters (a-z), digits (0-9), and hyphens (-)",
122
+ "- Maximum 50 characters",
123
+ "- No leading or trailing hyphens, no consecutive hyphens",
124
+ "- Do NOT include the branch type (feature, fix, chore) or ticket number — they are added automatically",
125
+ "- Start with a verb or a clear domain noun: 'add-', 'implement-', 'refactor-', 'fix-', 'migrate-'",
126
+ "- Be SPECIFIC and MEANINGFUL: describe the business feature or technical change",
127
+ " BAD: 'update-files', 'changes', 'update-code', 'update-experimental3', 'update-src'",
128
+ " GOOD: 'add-stripe-payment-integration', 'refactor-auth-token-refresh', 'implement-user-profile-api'",
129
+ "- Prefer domain language over technical/folder names",
130
+ " BAD: 'update-src-auth', 'update-payments-folder'",
131
+ " GOOD: 'add-jwt-authentication', 'integrate-stripe-webhooks'",
132
+ "",
133
+ "FEW-SHOT EXAMPLES:",
134
+ "Modules: src/auth (8 files), Commits: add JWT login, add token refresh → add-jwt-auth-and-token-refresh",
135
+ "Modules: src/payments (5 files), Commits: integrate Stripe, add webhook → integrate-stripe-payments",
136
+ "Modules: src/users (4 files), Commits: add user profile, add avatar → add-user-profile-management",
137
+ "Modules: src/notifications (3 files), Commits: add email notifications → add-email-notifications",
138
+ "Modules: config (2 files), Commits: update Docker config, update env → update-infra-config",
139
+ "",
140
+ "Return ONLY a valid JSON object — no markdown, no explanation, no extra text:",
141
+ '{"description": "precise-feature-name-here"}',
142
+ ].join("\n"),
143
+ },
144
+ {
145
+ role: "user",
146
+ content: [
147
+ `Top modules by file count: ${topModules || "(unknown)"}`,
148
+ `Total files in this branch: ${allFiles.length}`,
149
+ "",
150
+ "Changed files:",
151
+ shown + overflow,
152
+ "",
153
+ "Commit messages in this branch:",
154
+ commitSummary,
155
+ "",
156
+ `Current heuristic slug (improve upon this): ${currentSlug}`,
157
+ "",
158
+ "Generate a slug that describes the BUSINESS PURPOSE or TECHNICAL CHANGE — not just the folder name.",
159
+ ].join("\n"),
160
+ },
161
+ ];
162
+ }
163
+ // ---------------------------------------------------------------------------
164
+ // Plan rebalance
165
+ // ---------------------------------------------------------------------------
166
+ /**
167
+ * Construye el prompt para que la IA proponga un rebalanceo semántico del plan:
168
+ * movimientos de archivos entre commits y ramas basados en cohesión de dominio.
169
+ *
170
+ * El modelo recibe el plan heurístico completo (ramas → commits → archivos) y
171
+ * devuelve la distribución ideal. La respuesta incluye TODOS los archivos de
172
+ * TODAS las ramas, lo que permite reconciliar y detectar omisiones o duplicados.
173
+ *
174
+ * @param plans - Planes heurísticos ya generados por `findBestPlan`.
175
+ */
176
+ export function buildPlanRebalancePrompt(plans) {
177
+ const planDescription = plans.map((plan, bi) => {
178
+ const commits = plan.commitPlan.map((c) => {
179
+ const files = c.files.map((f) => ` - ${f}`).join("\n");
180
+ return [` Commit ${c.index} [${c.suggestedType}]:`, files].join("\n");
181
+ }).join("\n");
182
+ return [
183
+ `Branch ${bi} (${plan.isExistingBaseBranch ? "base existente" : "derivada"}): ${plan.name}`,
184
+ ` ${plan.files} archivos · ${plan.lines} líneas · ${plan.commits} commits`,
185
+ commits
186
+ ].join("\n");
187
+ }).join("\n\n");
188
+ const allFiles = plans.flatMap((p) => p.commitPlan.flatMap((c) => c.files));
189
+ const totalFiles = allFiles.length;
190
+ return [
191
+ {
192
+ role: "system",
193
+ content: [
194
+ "You are a senior software architect expert at organizing code changes into logical git commits and branches.",
195
+ "You will receive a heuristic plan of file distribution across branches and commits.",
196
+ "Your job: propose a SEMANTICALLY IMPROVED redistribution based on domain cohesion.",
197
+ "",
198
+ "CORE PRINCIPLES:",
199
+ "- Files that belong to the same feature/domain should go in the same commit",
200
+ "- Files that depend on each other (e.g. service + its DTO + its controller) should be in the same commit or at least the same branch",
201
+ "- Infrastructure/config changes (chore) should be isolated from feature changes",
202
+ "- Test files should ALWAYS stay with their source file (same commit)",
203
+ "- Migration files should go in their own commit, before the entity that uses them",
204
+ "- Do NOT create new branches — only redistribute files within the existing branch structure",
205
+ "- Every single file in the input MUST appear exactly once in the output",
206
+ "",
207
+ "CONSTRAINTS:",
208
+ "- Keep the same number of branches and same branch order (branchIndex 0, 1, 2...)",
209
+ "- You may merge or split commits within a branch — but keep commits reasonable in size",
210
+ "- An empty commit (no files) is NOT allowed — every commit must have at least 1 file",
211
+ "- Do not explode into too many single-file commits",
212
+ "",
213
+ "RESPONSE FORMAT — return ONLY valid JSON, no markdown, no explanation:",
214
+ '{"branches":[{"branchIndex":0,"commits":[{"commitIndex":1,"files":["src/example/file.ts"]}]}]}',
215
+ "",
216
+ `CRITICAL: your output must contain exactly ${totalFiles} files total — same as the input.`,
217
+ ].join("\n"),
218
+ },
219
+ {
220
+ role: "user",
221
+ content: [
222
+ `Current heuristic plan (${plans.length} branches, ${totalFiles} total files):`,
223
+ "",
224
+ planDescription,
225
+ "",
226
+ "Analyze domain relationships and propose an improved distribution.",
227
+ "Remember: same total files, same branch count, no empty commits.",
228
+ ].join("\n"),
229
+ },
230
+ ];
231
+ }