git-release-manager 0.0.13 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (381) hide show
  1. package/README.md +0 -0
  2. package/dist/commands/branch/command.js +84 -14
  3. package/dist/commands/branch/command.js.map +1 -1
  4. package/dist/commands/branch/types/BranchCliArgs.js +0 -0
  5. package/dist/commands/branch/types/BranchCliArgs.js.map +0 -0
  6. package/dist/commands/branch/types/BranchCreateCliArgs.js +0 -0
  7. package/dist/commands/branch/types/BranchCreateCliArgs.js.map +0 -0
  8. package/dist/commands/branch/types/BranchDeleteCliArgs.js +0 -0
  9. package/dist/commands/branch/types/BranchDeleteCliArgs.js.map +0 -0
  10. package/dist/{cli/types/BranchDeleteCliArgs.js → commands/branch/types/BranchFinishCliArgs.js} +1 -1
  11. package/dist/commands/branch/types/BranchFinishCliArgs.js.map +1 -0
  12. package/dist/commands/branch/types/BranchListCliArgs.js +0 -0
  13. package/dist/commands/branch/types/BranchListCliArgs.js.map +0 -0
  14. package/dist/commands/branch/types/BranchMergeCliArgs.js +0 -0
  15. package/dist/commands/branch/types/BranchMergeCliArgs.js.map +0 -0
  16. package/dist/commands/branch/types/BranchProtectCliArgs.js +0 -0
  17. package/dist/commands/branch/types/BranchProtectCliArgs.js.map +0 -0
  18. package/dist/commands/branch/types/BranchRebaseCliArgs.js +0 -0
  19. package/dist/commands/branch/types/BranchRebaseCliArgs.js.map +0 -0
  20. package/dist/commands/branch/types/BranchSwitchCliArgs.js +0 -0
  21. package/dist/commands/branch/types/BranchSwitchCliArgs.js.map +0 -0
  22. package/dist/{cli/types/ChangelogCliArgs.js → commands/branch/types/BranchSyncCliArgs.js} +1 -1
  23. package/dist/commands/branch/types/BranchSyncCliArgs.js.map +1 -0
  24. package/dist/commands/branch/types/BranchUnProtectCliArgs.js +0 -0
  25. package/dist/commands/branch/types/BranchUnProtectCliArgs.js.map +0 -0
  26. package/dist/commands/changelog/command.js +28 -3
  27. package/dist/commands/changelog/command.js.map +1 -1
  28. package/dist/commands/changelog/types/ChangelogCliArgs.js +0 -0
  29. package/dist/commands/changelog/types/ChangelogCliArgs.js.map +0 -0
  30. package/dist/commands/changelog/types/ChangelogGenerateCliArgs.js +0 -0
  31. package/dist/commands/changelog/types/ChangelogGenerateCliArgs.js.map +0 -0
  32. package/dist/commands/commit/command.js +8 -3
  33. package/dist/commands/commit/command.js.map +1 -1
  34. package/dist/commands/commit/types/CommitAmendCliArgs.js +0 -0
  35. package/dist/commands/commit/types/CommitAmendCliArgs.js.map +0 -0
  36. package/dist/commands/commit/types/CommitCliArgs.js +0 -0
  37. package/dist/commands/commit/types/CommitCliArgs.js.map +0 -0
  38. package/dist/commands/commit/types/CommitCreateCliArgs.js +0 -0
  39. package/dist/commands/commit/types/CommitCreateCliArgs.js.map +0 -0
  40. package/dist/commands/commit/types/CommitListCliArgs.js +0 -0
  41. package/dist/commands/commit/types/CommitListCliArgs.js.map +0 -0
  42. package/dist/commands/flow/command.js +196 -6
  43. package/dist/commands/flow/command.js.map +1 -1
  44. package/dist/commands/track/command.js +136 -0
  45. package/dist/commands/track/command.js.map +1 -0
  46. package/dist/commands/types/CliArgs.js +0 -0
  47. package/dist/commands/types/CliArgs.js.map +0 -0
  48. package/dist/commands/version/command.js +115 -23
  49. package/dist/commands/version/command.js.map +1 -1
  50. package/dist/commands/version/types/VersionCliArgs.js +0 -0
  51. package/dist/commands/version/types/VersionCliArgs.js.map +0 -0
  52. package/dist/commands/version/types/VersionCompareCliArgs.js +0 -0
  53. package/dist/commands/version/types/VersionCompareCliArgs.js.map +0 -0
  54. package/dist/commands/version/types/VersionIncrementCliArgs.js +0 -0
  55. package/dist/commands/version/types/VersionIncrementCliArgs.js.map +0 -0
  56. package/dist/commands/version/types/VersionInitCliArgs.js +0 -0
  57. package/dist/commands/version/types/VersionInitCliArgs.js.map +0 -0
  58. package/dist/commands/version/types/VersionListCliArgs.js +0 -0
  59. package/dist/commands/version/types/VersionListCliArgs.js.map +0 -0
  60. package/dist/commands/version/types/VersionProjectCliArgs.js +0 -0
  61. package/dist/commands/version/types/VersionProjectCliArgs.js.map +0 -0
  62. package/dist/commands/version/types/VersionRemoteCliArgs.js +0 -0
  63. package/dist/commands/version/types/VersionRemoteCliArgs.js.map +0 -0
  64. package/dist/commands/version/types/VersionResetCliArgs.js +0 -0
  65. package/dist/commands/version/types/VersionResetCliArgs.js.map +0 -0
  66. package/dist/commands/version/types/VersionRevertCliArgs.js +0 -0
  67. package/dist/commands/version/types/VersionRevertCliArgs.js.map +0 -0
  68. package/dist/commands/version/types/VersionSetCliArgs.js +0 -0
  69. package/dist/commands/version/types/VersionSetCliArgs.js.map +0 -0
  70. package/dist/commands/version/types/VersionValidateCliArgs.js +0 -0
  71. package/dist/commands/version/types/VersionValidateCliArgs.js.map +0 -0
  72. package/dist/config/configLoader.js +0 -0
  73. package/dist/config/configLoader.js.map +0 -0
  74. package/dist/config/configManager.js +0 -0
  75. package/dist/config/configManager.js.map +0 -0
  76. package/dist/config/constants.js +0 -0
  77. package/dist/config/constants.js.map +0 -0
  78. package/dist/config/defaults/config.json +375 -250
  79. package/dist/config/types/BranchConfig.js +0 -0
  80. package/dist/config/types/BranchConfig.js.map +0 -0
  81. package/dist/config/types/ChannelType.js +0 -0
  82. package/dist/config/types/ChannelType.js.map +0 -0
  83. package/dist/config/types/CommitType.js +0 -0
  84. package/dist/config/types/CommitType.js.map +0 -0
  85. package/dist/config/types/Config.js +0 -0
  86. package/dist/config/types/Config.js.map +0 -0
  87. package/dist/config/types/FileGroups.js +0 -0
  88. package/dist/config/types/FileGroups.js.map +0 -0
  89. package/dist/config/types/Flow.js +34 -0
  90. package/dist/config/types/Flow.js.map +1 -0
  91. package/dist/config/types/LinkType.js +0 -0
  92. package/dist/config/types/LinkType.js.map +0 -0
  93. package/dist/config/types/MentionType.js +0 -0
  94. package/dist/config/types/MentionType.js.map +0 -0
  95. package/dist/config/types/NoteType.js +0 -0
  96. package/dist/config/types/NoteType.js.map +0 -0
  97. package/dist/config/types/Options.js +0 -0
  98. package/dist/config/types/Options.js.map +0 -0
  99. package/dist/config/types/Repository.js +0 -0
  100. package/dist/config/types/Repository.js.map +0 -0
  101. package/dist/{cli/types/CliArgs.js → config/types/Track.js} +1 -1
  102. package/dist/config/types/Track.js.map +1 -0
  103. package/dist/{cli/types/BranchCliArgs.js → config/types/Versioning.js} +1 -1
  104. package/dist/config/types/Versioning.js.map +1 -0
  105. package/dist/index.js +25 -6
  106. package/dist/index.js.map +1 -1
  107. package/dist/modules/FlowManager.js +47 -4
  108. package/dist/modules/FlowManager.js.map +1 -1
  109. package/dist/modules/branch/BranchController.js +33 -2
  110. package/dist/modules/branch/BranchController.js.map +1 -1
  111. package/dist/modules/branch/BranchManager.js +0 -0
  112. package/dist/modules/branch/BranchManager.js.map +0 -0
  113. package/dist/modules/changelog/ChangelogController.js +0 -0
  114. package/dist/modules/changelog/ChangelogController.js.map +1 -1
  115. package/dist/modules/changelog/ChangelogValidator.js +0 -0
  116. package/dist/modules/changelog/ChangelogValidator.js.map +0 -0
  117. package/dist/modules/changelog/templateOperations.js +0 -0
  118. package/dist/modules/changelog/templateOperations.js.map +1 -1
  119. package/dist/modules/changes/types/ChangeInformation.js +0 -0
  120. package/dist/modules/changes/types/ChangeInformation.js.map +0 -0
  121. package/dist/modules/changes/types/Context.js +0 -0
  122. package/dist/modules/changes/types/Context.js.map +0 -0
  123. package/dist/modules/changes/types/RangeInfo.js +0 -0
  124. package/dist/modules/changes/types/RangeInfo.js.map +0 -0
  125. package/dist/modules/changes/types/RangeSummary.js +0 -0
  126. package/dist/modules/changes/types/RangeSummary.js.map +0 -0
  127. package/dist/modules/changes/types/ReferenceTypesEnum.js +0 -0
  128. package/dist/modules/changes/types/ReferenceTypesEnum.js.map +0 -0
  129. package/dist/modules/commit/CommitController.js +0 -0
  130. package/dist/modules/commit/CommitController.js.map +0 -0
  131. package/dist/modules/commit/CommitManager.js +0 -0
  132. package/dist/modules/commit/CommitManager.js.map +0 -0
  133. package/dist/modules/flow/FlowController.js +764 -0
  134. package/dist/modules/flow/FlowController.js.map +1 -0
  135. package/dist/modules/git/commits/commitProcessor.js +21 -3
  136. package/dist/modules/git/commits/commitProcessor.js.map +1 -1
  137. package/dist/modules/git/commits/gitLogFetcher.js +0 -0
  138. package/dist/modules/git/commits/gitLogFetcher.js.map +0 -0
  139. package/dist/modules/git/commits/index.js +9 -1
  140. package/dist/modules/git/commits/index.js.map +1 -1
  141. package/dist/modules/git/commits/profileHandler.js +0 -0
  142. package/dist/modules/git/commits/profileHandler.js.map +0 -0
  143. package/dist/modules/git/commits/regexHandlers.js +0 -0
  144. package/dist/modules/git/commits/regexHandlers.js.map +0 -0
  145. package/dist/modules/git/context/branchHandler.js +0 -0
  146. package/dist/modules/git/context/branchHandler.js.map +0 -0
  147. package/dist/modules/git/context/commitHandler.js +0 -0
  148. package/dist/modules/git/context/commitHandler.js.map +0 -0
  149. package/dist/modules/git/context/index.js +0 -0
  150. package/dist/modules/git/context/index.js.map +0 -0
  151. package/dist/modules/git/context/remoteHandler.js +1 -1
  152. package/dist/modules/git/context/remoteHandler.js.map +1 -1
  153. package/dist/modules/git/context/statusHandler.js +0 -0
  154. package/dist/modules/git/context/statusHandler.js.map +0 -0
  155. package/dist/modules/git/context/tagHandler.js +0 -0
  156. package/dist/modules/git/context/tagHandler.js.map +0 -0
  157. package/dist/modules/git/gitOperations.js +0 -0
  158. package/dist/modules/git/gitOperations.js.map +1 -1
  159. package/dist/modules/git/lineTags.js +58 -0
  160. package/dist/modules/git/lineTags.js.map +1 -0
  161. package/dist/modules/git/types/Author.js +0 -0
  162. package/dist/modules/git/types/Author.js.map +0 -0
  163. package/dist/modules/git/types/Branch.js +0 -0
  164. package/dist/modules/git/types/Branch.js.map +0 -0
  165. package/dist/modules/git/types/BranchInfo.js +0 -0
  166. package/dist/modules/git/types/BranchInfo.js.map +0 -0
  167. package/dist/modules/git/types/CommitContent.js +0 -0
  168. package/dist/modules/git/types/CommitContent.js.map +0 -0
  169. package/dist/modules/git/types/CommitInfo.js +0 -0
  170. package/dist/modules/git/types/CommitInfo.js.map +0 -0
  171. package/dist/modules/git/types/CommitType.js +0 -0
  172. package/dist/modules/git/types/CommitType.js.map +0 -0
  173. package/dist/modules/git/types/GitCommit.js +0 -0
  174. package/dist/modules/git/types/GitCommit.js.map +0 -0
  175. package/dist/modules/git/types/GitReference.js +0 -0
  176. package/dist/modules/git/types/GitReference.js.map +0 -0
  177. package/dist/modules/git/types/Link.js +0 -0
  178. package/dist/modules/git/types/Link.js.map +0 -0
  179. package/dist/modules/git/types/Mention.js +0 -0
  180. package/dist/modules/git/types/Mention.js.map +0 -0
  181. package/dist/modules/git/types/Note.js +0 -0
  182. package/dist/modules/git/types/Note.js.map +0 -0
  183. package/dist/modules/git/types/RemoteInfo.js +0 -0
  184. package/dist/modules/git/types/RemoteInfo.js.map +0 -0
  185. package/dist/modules/git/types/Repository.js +0 -0
  186. package/dist/modules/git/types/Repository.js.map +0 -0
  187. package/dist/modules/git/types/StatusInfo.js +0 -0
  188. package/dist/modules/git/types/StatusInfo.js.map +0 -0
  189. package/dist/modules/git/types/Tag.js +0 -0
  190. package/dist/modules/git/types/Tag.js.map +0 -0
  191. package/dist/modules/git/types/TagInfo.js +0 -0
  192. package/dist/modules/git/types/TagInfo.js.map +0 -0
  193. package/dist/modules/git/utils/branchUtils.js +0 -0
  194. package/dist/modules/git/utils/branchUtils.js.map +0 -0
  195. package/dist/modules/git/utils/commitUtils.js +0 -0
  196. package/dist/modules/git/utils/commitUtils.js.map +0 -0
  197. package/dist/modules/git/utils/logUtils.js +0 -0
  198. package/dist/modules/git/utils/logUtils.js.map +0 -0
  199. package/dist/modules/git/utils/rangeOperations.js +0 -0
  200. package/dist/modules/git/utils/rangeOperations.js.map +0 -0
  201. package/dist/modules/git/utils/refUtils.js +0 -0
  202. package/dist/modules/git/utils/refUtils.js.map +0 -0
  203. package/dist/modules/git/utils/referenceUtils.js +0 -0
  204. package/dist/modules/git/utils/referenceUtils.js.map +0 -0
  205. package/dist/modules/git/utils/tagUtils.js +0 -0
  206. package/dist/modules/git/utils/tagUtils.js.map +0 -0
  207. package/dist/modules/output/writer.js +0 -0
  208. package/dist/modules/output/writer.js.map +0 -0
  209. package/dist/modules/sections/contributors.js +0 -0
  210. package/dist/modules/sections/contributors.js.map +0 -0
  211. package/dist/modules/sections/grouping.js +0 -0
  212. package/dist/modules/sections/grouping.js.map +0 -0
  213. package/dist/modules/sections/index.js +0 -0
  214. package/dist/modules/sections/index.js.map +0 -0
  215. package/dist/modules/sections/summarizing.js +0 -0
  216. package/dist/modules/sections/summarizing.js.map +0 -0
  217. package/dist/modules/sections/types/Contributor.js +0 -0
  218. package/dist/modules/sections/types/Contributor.js.map +0 -0
  219. package/dist/modules/sections/types/Group.js +0 -0
  220. package/dist/modules/sections/types/Group.js.map +0 -0
  221. package/dist/modules/sections/types/SectionSummary.js +0 -0
  222. package/dist/modules/sections/types/SectionSummary.js.map +0 -0
  223. package/dist/modules/sections/types/Sections.js +0 -0
  224. package/dist/modules/sections/types/Sections.js.map +0 -0
  225. package/dist/modules/track/TrackController.js +320 -0
  226. package/dist/modules/track/TrackController.js.map +1 -0
  227. package/dist/modules/version/BumpDeriver.js +119 -0
  228. package/dist/modules/version/BumpDeriver.js.map +1 -0
  229. package/dist/modules/version/GitVersionManager.js +42 -14
  230. package/dist/modules/version/GitVersionManager.js.map +1 -1
  231. package/dist/modules/version/ProjectVersion.js +84 -3
  232. package/dist/modules/version/ProjectVersion.js.map +1 -1
  233. package/dist/modules/version/ReleaseManager.js +0 -0
  234. package/dist/modules/version/ReleaseManager.js.map +0 -0
  235. package/dist/modules/version/VersionController.js +238 -3
  236. package/dist/modules/version/VersionController.js.map +1 -1
  237. package/dist/modules/version/VersionStamper.js +139 -0
  238. package/dist/modules/version/VersionStamper.js.map +1 -0
  239. package/dist/modules/version/VersionValidator.js +0 -0
  240. package/dist/modules/version/VersionValidator.js.map +0 -0
  241. package/dist/modules/version/branchChannel.js +94 -0
  242. package/dist/modules/version/branchChannel.js.map +1 -0
  243. package/dist/modules/version/resolveVersionRef.js +78 -0
  244. package/dist/modules/version/resolveVersionRef.js.map +1 -0
  245. package/dist/modules/version/types/const.js +0 -0
  246. package/dist/modules/version/types/const.js.map +0 -0
  247. package/dist/modules/version/versionFormatter.js +19 -1
  248. package/dist/modules/version/versionFormatter.js.map +1 -1
  249. package/dist/modules/version/versionHelper.js +0 -0
  250. package/dist/modules/version/versionHelper.js.map +0 -0
  251. package/dist/templates/constants.js +0 -0
  252. package/dist/templates/constants.js.map +0 -0
  253. package/dist/templates/defaults/changelog.detailed.ejs +0 -0
  254. package/dist/templates/defaults/changelog.ejs +0 -0
  255. package/dist/templates/templateRenderer.js +0 -0
  256. package/dist/templates/templateRenderer.js.map +0 -0
  257. package/dist/templates/templateResolver.js +0 -0
  258. package/dist/templates/templateResolver.js.map +0 -0
  259. package/dist/types/PackageJson.js +0 -0
  260. package/dist/types/PackageJson.js.map +0 -0
  261. package/dist/utils/cmd.js +15 -2
  262. package/dist/utils/cmd.js.map +1 -1
  263. package/dist/utils/date.js +0 -0
  264. package/dist/utils/date.js.map +0 -0
  265. package/package.json +5 -2
  266. package/dist/cli/types/BranchCliArgs.js.map +0 -1
  267. package/dist/cli/types/BranchCreateCliArgs.js +0 -3
  268. package/dist/cli/types/BranchCreateCliArgs.js.map +0 -1
  269. package/dist/cli/types/BranchDeleteCliArgs.js.map +0 -1
  270. package/dist/cli/types/BranchListCliArgs.js +0 -3
  271. package/dist/cli/types/BranchListCliArgs.js.map +0 -1
  272. package/dist/cli/types/BranchMergeCliArgs.js +0 -3
  273. package/dist/cli/types/BranchMergeCliArgs.js.map +0 -1
  274. package/dist/cli/types/BranchProtectCliArgs.js +0 -3
  275. package/dist/cli/types/BranchProtectCliArgs.js.map +0 -1
  276. package/dist/cli/types/BranchRebaseCliArgs.js +0 -3
  277. package/dist/cli/types/BranchRebaseCliArgs.js.map +0 -1
  278. package/dist/cli/types/BranchSwitchCliArgs.js +0 -3
  279. package/dist/cli/types/BranchSwitchCliArgs.js.map +0 -1
  280. package/dist/cli/types/BranchUnProtectCliArgs.js +0 -3
  281. package/dist/cli/types/BranchUnProtectCliArgs.js.map +0 -1
  282. package/dist/cli/types/ChangelogCliArgs.js.map +0 -1
  283. package/dist/cli/types/ChangelogGenerateCliArgs.js +0 -3
  284. package/dist/cli/types/ChangelogGenerateCliArgs.js.map +0 -1
  285. package/dist/cli/types/CliArgs.js.map +0 -1
  286. package/dist/cli/types/CommitAmendCliArgs.js +0 -3
  287. package/dist/cli/types/CommitAmendCliArgs.js.map +0 -1
  288. package/dist/cli/types/CommitCliArgs.js +0 -3
  289. package/dist/cli/types/CommitCliArgs.js.map +0 -1
  290. package/dist/cli/types/CommitCreateCliArgs.js +0 -3
  291. package/dist/cli/types/CommitCreateCliArgs.js.map +0 -1
  292. package/dist/cli/types/CommitListCliArgs.js +0 -3
  293. package/dist/cli/types/CommitListCliArgs.js.map +0 -1
  294. package/dist/cli/types/VersionCliArgs.js +0 -3
  295. package/dist/cli/types/VersionCliArgs.js.map +0 -1
  296. package/dist/cli/types/VersionCompareCliArgs.js +0 -3
  297. package/dist/cli/types/VersionCompareCliArgs.js.map +0 -1
  298. package/dist/cli/types/VersionIncrementCliArgs.js +0 -3
  299. package/dist/cli/types/VersionIncrementCliArgs.js.map +0 -1
  300. package/dist/cli/types/VersionInitCliArgs.js +0 -3
  301. package/dist/cli/types/VersionInitCliArgs.js.map +0 -1
  302. package/dist/cli/types/VersionListCliArgs.js +0 -3
  303. package/dist/cli/types/VersionListCliArgs.js.map +0 -1
  304. package/dist/cli/types/VersionProjectCliArgs.js +0 -3
  305. package/dist/cli/types/VersionProjectCliArgs.js.map +0 -1
  306. package/dist/cli/types/VersionRemoteCliArgs.js +0 -3
  307. package/dist/cli/types/VersionRemoteCliArgs.js.map +0 -1
  308. package/dist/cli/types/VersionResetCliArgs.js +0 -3
  309. package/dist/cli/types/VersionResetCliArgs.js.map +0 -1
  310. package/dist/cli/types/VersionRevertCliArgs.js +0 -3
  311. package/dist/cli/types/VersionRevertCliArgs.js.map +0 -1
  312. package/dist/cli/types/VersionSetCliArgs.js +0 -3
  313. package/dist/cli/types/VersionSetCliArgs.js.map +0 -1
  314. package/dist/cli/types/VersionValidateCliArgs.js +0 -3
  315. package/dist/cli/types/VersionValidateCliArgs.js.map +0 -1
  316. package/dist/commands/branchCommand.js +0 -150
  317. package/dist/commands/branchCommand.js.map +0 -1
  318. package/dist/commands/changelogCommand.js +0 -32
  319. package/dist/commands/changelogCommand.js.map +0 -1
  320. package/dist/commands/commitCommand.js +0 -58
  321. package/dist/commands/commitCommand.js.map +0 -1
  322. package/dist/commands/types/BranchCliArgs.js +0 -3
  323. package/dist/commands/types/BranchCliArgs.js.map +0 -1
  324. package/dist/commands/types/BranchCreateCliArgs.js +0 -3
  325. package/dist/commands/types/BranchCreateCliArgs.js.map +0 -1
  326. package/dist/commands/types/BranchDeleteCliArgs.js +0 -3
  327. package/dist/commands/types/BranchDeleteCliArgs.js.map +0 -1
  328. package/dist/commands/types/BranchListCliArgs.js +0 -3
  329. package/dist/commands/types/BranchListCliArgs.js.map +0 -1
  330. package/dist/commands/types/BranchMergeCliArgs.js +0 -3
  331. package/dist/commands/types/BranchMergeCliArgs.js.map +0 -1
  332. package/dist/commands/types/BranchProtectCliArgs.js +0 -3
  333. package/dist/commands/types/BranchProtectCliArgs.js.map +0 -1
  334. package/dist/commands/types/BranchRebaseCliArgs.js +0 -3
  335. package/dist/commands/types/BranchRebaseCliArgs.js.map +0 -1
  336. package/dist/commands/types/BranchSwitchCliArgs.js +0 -3
  337. package/dist/commands/types/BranchSwitchCliArgs.js.map +0 -1
  338. package/dist/commands/types/BranchUnProtectCliArgs.js +0 -3
  339. package/dist/commands/types/BranchUnProtectCliArgs.js.map +0 -1
  340. package/dist/commands/types/ChangelogCliArgs.js +0 -3
  341. package/dist/commands/types/ChangelogCliArgs.js.map +0 -1
  342. package/dist/commands/types/ChangelogGenerateCliArgs.js +0 -3
  343. package/dist/commands/types/ChangelogGenerateCliArgs.js.map +0 -1
  344. package/dist/commands/types/CommitAmendCliArgs.js +0 -3
  345. package/dist/commands/types/CommitAmendCliArgs.js.map +0 -1
  346. package/dist/commands/types/CommitCliArgs.js +0 -3
  347. package/dist/commands/types/CommitCliArgs.js.map +0 -1
  348. package/dist/commands/types/CommitCreateCliArgs.js +0 -3
  349. package/dist/commands/types/CommitCreateCliArgs.js.map +0 -1
  350. package/dist/commands/types/CommitListCliArgs.js +0 -3
  351. package/dist/commands/types/CommitListCliArgs.js.map +0 -1
  352. package/dist/commands/types/VersionCliArgs.js +0 -3
  353. package/dist/commands/types/VersionCliArgs.js.map +0 -1
  354. package/dist/commands/types/VersionCompareCliArgs.js +0 -3
  355. package/dist/commands/types/VersionCompareCliArgs.js.map +0 -1
  356. package/dist/commands/types/VersionIncrementCliArgs.js +0 -3
  357. package/dist/commands/types/VersionIncrementCliArgs.js.map +0 -1
  358. package/dist/commands/types/VersionInitCliArgs.js +0 -3
  359. package/dist/commands/types/VersionInitCliArgs.js.map +0 -1
  360. package/dist/commands/types/VersionListCliArgs.js +0 -3
  361. package/dist/commands/types/VersionListCliArgs.js.map +0 -1
  362. package/dist/commands/types/VersionProjectCliArgs.js +0 -3
  363. package/dist/commands/types/VersionProjectCliArgs.js.map +0 -1
  364. package/dist/commands/types/VersionRemoteCliArgs.js +0 -3
  365. package/dist/commands/types/VersionRemoteCliArgs.js.map +0 -1
  366. package/dist/commands/types/VersionResetCliArgs.js +0 -3
  367. package/dist/commands/types/VersionResetCliArgs.js.map +0 -1
  368. package/dist/commands/types/VersionRevertCliArgs.js +0 -3
  369. package/dist/commands/types/VersionRevertCliArgs.js.map +0 -1
  370. package/dist/commands/types/VersionSetCliArgs.js +0 -3
  371. package/dist/commands/types/VersionSetCliArgs.js.map +0 -1
  372. package/dist/commands/types/VersionValidateCliArgs.js +0 -3
  373. package/dist/commands/types/VersionValidateCliArgs.js.map +0 -1
  374. package/dist/commands/versionCommand.js +0 -134
  375. package/dist/commands/versionCommand.js.map +0 -1
  376. package/dist/core/app.js +0 -95
  377. package/dist/core/app.js.map +0 -1
  378. package/dist/core/changelog/app.js +0 -20
  379. package/dist/core/changelog/app.js.map +0 -1
  380. package/dist/modules/version/VersionManager.js +0 -92
  381. package/dist/modules/version/VersionManager.js.map +0 -1
@@ -0,0 +1,764 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FlowController = void 0;
7
+ const fs_1 = require("fs");
8
+ const path_1 = require("path");
9
+ const semver_1 = __importDefault(require("semver"));
10
+ const simple_git_1 = __importDefault(require("simple-git"));
11
+ const BumpDeriver_1 = require("../version/BumpDeriver");
12
+ const lineTags_1 = require("../git/lineTags");
13
+ const BUMP_RANK = { patch: 0, minor: 1, major: 2 };
14
+ /**
15
+ * The higher of a derived and a declared bump, treating a missing declaration
16
+ * as "no opinion" (DECISIONS D3).
17
+ *
18
+ * A floor is a MAXIMUM against the derived level, never a replacement for it: a
19
+ * declared `minor` must not pull a `major:` in the range down, which is exactly
20
+ * what the override reading would have done.
21
+ */
22
+ function maxBump(derived, declared) {
23
+ if (!declared)
24
+ return derived;
25
+ if (!derived)
26
+ return declared;
27
+ return BUMP_RANK[declared] > BUMP_RANK[derived] ? declared : derived;
28
+ }
29
+ /**
30
+ * FlowController — run a declared phase: promote a branch, derive the version
31
+ * from the commits, tag it.
32
+ *
33
+ * ── THE NUMBER COMES FROM THE HISTORY, NOT FROM A NAME ──
34
+ *
35
+ * This is the one property the existing flow surfaces do not have.
36
+ * `branch finish` reads the version out of the branch name
37
+ * (`release/1.4.0` → `1.4.0`), which means the bump derivation — the whole
38
+ * commitTypes/noteTypes taxonomy a project configures for its changelog — is
39
+ * bypassed on the only path where it matters. Here the range is
40
+ * `<latest tag on this line>..<the phase's branch>` and `deriveBump` grades it,
41
+ * so `feat:` moves the minor whether or not anybody typed a number.
42
+ *
43
+ * ── AND IT IS COMPUTED AFTER THE MERGE, DELIBERATELY ──
44
+ *
45
+ * A promotion's version must describe the work it promotes. Derive before the
46
+ * merge and the range is empty (the target branch has not moved yet), so the
47
+ * derivation falls to the default and a release full of features gets a patch
48
+ * bump. Every step still reports success. So: merge, then derive, then tag —
49
+ * and the tag lands on the merge commit, which is the commit that carries the
50
+ * work.
51
+ *
52
+ * ── WHAT IT REFUSES ──
53
+ *
54
+ * · an unknown phase, listing the ones the project declared
55
+ * · a promotion with nothing to promote (the source carries no commit the
56
+ * target lacks) — that would mint a version for no change
57
+ * · a fast-forward merge unless the phase asked for `ff` in writing: a
58
+ * fast-forward creates no commit, so a pre-merge hook never runs and every
59
+ * gate hung on the promotion silently does not execute
60
+ * · deleting the source branch unless the phase asked for it. On a long-lived
61
+ * integration line that is not a cleanup, it is an outage.
62
+ */
63
+ const OWNER_TOKEN = "FlowController/v1";
64
+ class FlowController {
65
+ constructor(config, root = process.cwd()) {
66
+ this.config = config;
67
+ this.root = root;
68
+ this.git = (0, simple_git_1.default)(this.root);
69
+ }
70
+ /** The phase declaration, or a refusal that names what IS declared. */
71
+ phase(name) {
72
+ var _a, _b;
73
+ const phases = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.flow) === null || _b === void 0 ? void 0 : _b.phases;
74
+ if (!phases || Object.keys(phases).length === 0) {
75
+ throw new Error("No flow is declared. Add a `flow.phases` block to the config " +
76
+ "(see src/config/types/Flow.ts) naming each phase's branch.");
77
+ }
78
+ const p = phases[name];
79
+ if (!p) {
80
+ throw new Error(`Unknown phase '${name}'. Declared: ${Object.keys(phases).join(", ")}`);
81
+ }
82
+ if (!p.branch) {
83
+ throw new Error(`Phase '${name}' declares no branch.`);
84
+ }
85
+ return p;
86
+ }
87
+ /**
88
+ * The phase's branch must EXIST before any question about it means anything.
89
+ *
90
+ * 🔴 WITHOUT THIS A MISSING BRANCH ANSWERS A VERSION. Every tag walk filters
91
+ * on `merge-base --is-ancestor <tag> <branch>`, which simply fails for a
92
+ * branch that is not there — so no tag is reachable, the baseline falls to
93
+ * 0.0.0, and the phase confidently reports `v0.0.1` for a line it cannot see.
94
+ * Measured 2026-08-06 in a `git clone --branch dev` of a repository at v1.3.0:
95
+ * `main` existed only as a remote-tracking ref, and `flow next prod` answered
96
+ * v0.0.1 while the sibling driver answered v1.0.0. A number that names nothing
97
+ * is worse than a refusal, because a caller substitutes it into a tag.
98
+ */
99
+ async assertBranch(branch, role) {
100
+ const ok = await this.git
101
+ .raw(["rev-parse", "--verify", "--quiet", `refs/heads/${branch}`])
102
+ .then(out => String(out).trim() !== "")
103
+ .catch(() => false);
104
+ if (!ok) {
105
+ throw new Error(`${role} '${branch}' does not exist in this repository ` +
106
+ `(a remote-tracking ref is not enough — create the local branch).`);
107
+ }
108
+ }
109
+ prefixOf(p) {
110
+ var _a, _b, _c, _d;
111
+ return (_d = (_a = p.prefix) !== null && _a !== void 0 ? _a : (_c = (_b = this.config) === null || _b === void 0 ? void 0 : _b.tag) === null || _c === void 0 ? void 0 : _c.prefix) !== null && _d !== void 0 ? _d : "";
112
+ }
113
+ strategyOf(p) {
114
+ return p.merge === "ff" ? "ff" : "no-ff";
115
+ }
116
+ /**
117
+ * The highest tag on THIS line, reachable from the phase's branch.
118
+ *
119
+ * The line is `lineTags` (annotated + reachable + version-sorted); this adds
120
+ * the one filter that is specific to the baseline question. A phase with a
121
+ * channel wants that channel's newest tag; a stable phase must not adopt a
122
+ * prerelease as its baseline, or every stable cut would inherit `-dev.N` and
123
+ * never leave it.
124
+ */
125
+ async currentVersion(p) {
126
+ const prefix = this.prefixOf(p);
127
+ for (const name of await this.lineTags(p)) {
128
+ const core = name.slice(prefix.length);
129
+ if (p.channel) {
130
+ if (!core.includes(`-${p.channel}.`))
131
+ continue;
132
+ }
133
+ else if (core.includes("-")) {
134
+ continue;
135
+ }
136
+ return name;
137
+ }
138
+ return "";
139
+ }
140
+ /**
141
+ * Every annotated tag on this line, newest-version first, reachable from the
142
+ * phase's branch. One walk; the baseline questions above and in
143
+ * `nextVersion` filter it.
144
+ *
145
+ * THE WALK ITSELF MOVED to modules/git/lineTags (2026-08-24), because a
146
+ * version TRACK asks the same question about its own branch and the answer
147
+ * must not exist twice. Everything below — why annotated-only, why
148
+ * `--merged`, why a version sort, and why the answer is read from stdout
149
+ * rather than from an exit code — is kept THERE, with the code it governs.
150
+ *
151
+ * Three filters, and each one is load-bearing. ANNOTATED only
152
+ * (`%(objecttype)` is `tag`): a lightweight tag carries no tagger, so it
153
+ * records nothing about who cut it. REACHABLE from the branch (`--merged`):
154
+ * a tag on a side branch names code this line never carried. Sorted by
155
+ * VERSION, not lexically — `-v:refname`, because a lexical sort puts
156
+ * v1.10.0 below v1.9.0 and the baseline would walk backwards on the tenth
157
+ * minor.
158
+ *
159
+ * ── 🔴 REACHABILITY IS READ FROM STDOUT, NEVER FROM AN EXIT CODE ──
160
+ *
161
+ * This used to enumerate every tag and then ask, per tag,
162
+ * `merge-base --is-ancestor <tag>^{commit} <branch>`, mapping a resolved
163
+ * promise to `true` and a rejection to `false`. That command answers ONLY
164
+ * through its exit status: 0 ancestor, 1 not an ancestor, and it prints
165
+ * nothing either way. simple-git 3.27.0 RESOLVES a non-zero exit whose
166
+ * stderr is empty — measured, and `git tag --merged` in FlowManager already
167
+ * avoids the idiom — so `.then(() => true)` fired for BOTH answers and the
168
+ * filter passed every tag. Consequence on the repository this tool manages:
169
+ * `flow next prod` baselined on v1.6.0, a tag that lives only on `dev`, and
170
+ * answered v1.7.0 where the release line stood at v1.0.8 and the correct
171
+ * answer was v1.1.0 — six minor versions ahead, reported as a success.
172
+ * VersionController.resolveBaselineRef carries the same warning for
173
+ * `rev-parse --verify --quiet`: THE ANSWER IS THE OUTPUT, NOT THE ABSENCE
174
+ * OF A THROW.
175
+ *
176
+ * `for-each-ref --merged=<branch>` moves the answer onto stdout, and it
177
+ * costs ONE process instead of one per tag. Both failure directions now
178
+ * converge on the SAME safe answer: if git fails, and whether the wrapper
179
+ * rejects (the catch below) or resolves with empty output, the result is an
180
+ * empty set — no baseline rather than a foreign one. A phase whose branch
181
+ * does not exist yet lands here too, which is the answer it had before.
182
+ */
183
+ async lineTags(p) {
184
+ return (0, lineTags_1.lineTags)(this.git, p.branch, this.prefixOf(p));
185
+ }
186
+ /**
187
+ * The version this phase would cut next.
188
+ *
189
+ * `at` overrides the ref the range ENDS at — the runner passes the merge
190
+ * commit, because after a promotion the branch ref may not have moved yet
191
+ * (a worktree merge lands on a detached HEAD).
192
+ *
193
+ * ── A PRERELEASE HAS TWO BASELINES, AND THEY ARE DIFFERENT QUESTIONS ──
194
+ *
195
+ * The CORE comes from the release line — the newest STABLE tag — because
196
+ * `1.2.0-dev.3` is a preview of the 1.2.0 that is coming, and a preview whose
197
+ * core is derived from another preview drifts away from the line it previews.
198
+ * The COUNTER comes from the newest tag already in this channel AT THAT CORE.
199
+ *
200
+ * Conflating them is not theoretical: with one baseline this method answered
201
+ * `v0.0.1-dev.1` on a repository whose release line was at v1.1.0 (no stable
202
+ * tag matched the channel filter, so the base fell to 0.0.0), and the second
203
+ * cut then recomputed the SAME string and died on an existing tag. Measured
204
+ * 2026-08-06. The bump is applied to the stable core exactly once, and the
205
+ * channel counter never bumps the core again.
206
+ */
207
+ async nextVersion(p, at) {
208
+ var _a, _b, _c, _d, _e, _f, _g, _h;
209
+ await this.assertBranch(p.branch, "the phase's branch");
210
+ const prefix = this.prefixOf(p);
211
+ const tags = await this.lineTags(p);
212
+ const core = (t) => t.slice(prefix.length);
213
+ const stable = (_a = tags.find(t => !core(t).includes("-"))) !== null && _a !== void 0 ? _a : "";
214
+ const current = p.channel
215
+ ? ((_b = tags.find(t => core(t).includes(`-${p.channel}.`))) !== null && _b !== void 0 ? _b : stable)
216
+ : stable;
217
+ // The core is ALWAYS built from the stable line; see the note above.
218
+ const base = stable ? core(stable) : "0.0.0";
219
+ let bump = (_f = (_c = p.bump) !== null && _c !== void 0 ? _c : (_e = (_d = this.config) === null || _d === void 0 ? void 0 : _d.versioning) === null || _e === void 0 ? void 0 : _e.defaultBump) !== null && _f !== void 0 ? _f : "patch";
220
+ let why;
221
+ if (p.derive !== false && stable) {
222
+ // ── THE RANGE, AND WHY IT IS A UNION BEFORE THE MERGE ──
223
+ //
224
+ // After a promotion the target branch contains the source, so one
225
+ // range `current..<merge commit>` is the whole story — that is the
226
+ // `at` case, passed by the runner.
227
+ //
228
+ // BEFORE the merge it is not. `current..main` is EMPTY (main has not
229
+ // moved yet), so a plan that used it derived nothing, fell to
230
+ // defaultBump, and answered `v1.0.1` for a promotion the run then
231
+ // correctly cut as `v1.1.0` — the plan and the act disagreeing about
232
+ // the number, which is the one thing a plan may never do. Measured
233
+ // 2026-08-06 on a two-commit fixture with a `feat:` in it.
234
+ //
235
+ // `current..main` alone is wrong and `current..dev` alone is too: the
236
+ // target may carry commits since the tag that the source lacks (the
237
+ // divergence the plan reports as `behind`). `git log A..B A..C` is the
238
+ // UNION of both, which is exactly what the merge will produce, so the
239
+ // plan grades the same set the run will.
240
+ const ends = at ? [at] : (p.mergeFrom ? [p.branch, p.mergeFrom] : [p.branch]);
241
+ // From the STABLE tag, not from the channel's newest: a prerelease
242
+ // counter moving does not mean the work was already graded.
243
+ const ranges = ends.map(e => `${stable}..${e}`);
244
+ const pathspecs = ((_g = p.paths) !== null && _g !== void 0 ? _g : "").split(/\s+/).filter(Boolean);
245
+ // --no-merges: a merge commit carries no type and never could — its
246
+ // content is the commits it joins, and those are in this range too.
247
+ const args = [
248
+ ...ranges.slice(1),
249
+ "--no-merges",
250
+ ...(pathspecs.length ? ["--", ...pathspecs] : []),
251
+ ];
252
+ const commits = await this.logCommits([...ranges, ...args]);
253
+ if (commits === null || commits === void 0 ? void 0 : commits.length) {
254
+ const evidence = (0, BumpDeriver_1.deriveBump)(commits, this.config);
255
+ why = (0, BumpDeriver_1.explainBump)(evidence);
256
+ // ── A DECLARED phase.bump IS A FLOOR (DECISIONS D3) ──────────
257
+ //
258
+ // Derive from the commits, then never go BELOW what the phase
259
+ // declared. Three readings were possible and this is the one
260
+ // taken:
261
+ //
262
+ // override the declaration always wins — then a `major:` in
263
+ // the range is silently downgraded to the declared
264
+ // level, which is worse than either alternative
265
+ // fallback the declaration applies only when the range is
266
+ // empty — what this did until now, and the opposite
267
+ // of what "a phase may override the level" reads like
268
+ // floor derive, then raise to the declaration if it asked
269
+ // for more. A project writing `minor` on a phase
270
+ // means every promotion through it is AT LEAST a
271
+ // minor, and a `feat!:` can still make it a major.
272
+ //
273
+ // Measured before this: on a one-commit fixture `prod.bump=minor`
274
+ // yielded v1.1.0 and on a repository with a real range the same
275
+ // declaration yielded a patch — the declaration won exactly where
276
+ // it mattered least.
277
+ bump = maxBump(evidence.bump, p.bump);
278
+ if (p.bump && bump !== evidence.bump) {
279
+ // SAID OUT LOUD. Without this the operator reads "derived
280
+ // patch from 3 commits" beside a minor version and has no
281
+ // way to tell which input produced it.
282
+ why = `${why} — raised to ${bump} by the phase's declared floor (phase.bump = ${p.bump})`;
283
+ }
284
+ }
285
+ }
286
+ const nextCore = (_h = semver_1.default.inc(base, bump !== null && bump !== void 0 ? bump : "patch")) !== null && _h !== void 0 ? _h : base;
287
+ if (!p.channel) {
288
+ return { version: `${prefix}${nextCore}`, current: current || "none", why };
289
+ }
290
+ // The counter continues within THIS core. A new core restarts at 1, which
291
+ // is what makes `1.2.0-dev.1` follow `1.1.0-dev.7` rather than `.8`.
292
+ const inChannel = tags.filter(t => core(t).startsWith(`${nextCore}-${p.channel}.`));
293
+ let n = 0;
294
+ for (const t of inChannel) {
295
+ const m = core(t).match(new RegExp(`^${this.escapeRe(nextCore)}-${this.escapeRe(p.channel)}\\.(\\d+)$`));
296
+ if (m)
297
+ n = Math.max(n, parseInt(m[1], 10));
298
+ }
299
+ return { version: `${prefix}${nextCore}-${p.channel}.${n + 1}`, current: current || "none", why };
300
+ }
301
+ /**
302
+ * Remove one worktree this tool created, and deregister it.
303
+ *
304
+ * `keep: true` leaves it for inspection — of the run that just happened. The
305
+ * next run reclaims it (see reclaimWorktrees), because `keep` is a debugging
306
+ * aid and not a licence to hoard checkouts. With back-merges or routes in the
307
+ * same run, that means the LAST merge's worktree is the one left standing:
308
+ * each merge reclaims the leftovers it finds before starting. Bounded on
309
+ * purpose — the alternative is one full checkout per branch, kept forever.
310
+ *
311
+ * `worktree remove` can refuse (a lock, a file it cannot delete), and a
312
+ * refusal that leaves the directory behind is exactly the accumulation this
313
+ * guards against — so the removal falls back to deleting the directory, and
314
+ * `prune` then clears the registration git is left holding.
315
+ */
316
+ async removeWorktree(dir) {
317
+ var _a, _b, _c;
318
+ if (((_c = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.flow) === null || _b === void 0 ? void 0 : _b.worktree) === null || _c === void 0 ? void 0 : _c.keep) === true)
319
+ return;
320
+ // SAFE to swallow: nothing reads this call's outcome. Whether it removed
321
+ // the worktree is re-measured on the next line by LOOKING — existsSync —
322
+ // so a wrapper that misreports the exit status changes nothing.
323
+ await this.git.raw(["worktree", "remove", "--force", dir]).catch(() => { });
324
+ if ((0, fs_1.existsSync)(dir)) {
325
+ try {
326
+ (0, fs_1.rmSync)(dir, { recursive: true, force: true });
327
+ }
328
+ catch ( /* reported by prune */_d) { /* reported by prune */ }
329
+ }
330
+ // SAFE to swallow: housekeeping with no answer. Nothing branches on
331
+ // whether the registration was cleared, and a stale registration is
332
+ // reclaimed by the next run.
333
+ await this.git.raw(["worktree", "prune"]).catch(() => { });
334
+ }
335
+ /**
336
+ * Reclaim leftovers before starting: this phase's directory and any other
337
+ * `flow-*` under the configured root that carries OUR owner marker.
338
+ *
339
+ * A killed process (a laptop closing, a CI timeout, a SIGKILL) leaves a
340
+ * worktree no finally ever runs for. Without this they pile up one full
341
+ * checkout at a time, and the only symptom is a disk that fills.
342
+ *
343
+ * ⚠️ AN UNOWNED DIRECTORY IS REFUSED, NOT RECLAIMED — and the refusal comes
344
+ * FIRST. A directory that merely looks like ours may hold somebody's
345
+ * in-flight work; two sessions have already been lost to a tool removing
346
+ * worktrees it did not create.
347
+ */
348
+ async reclaimWorktrees(current) {
349
+ if ((0, fs_1.existsSync)(current) && !(0, fs_1.existsSync)((0, path_1.join)(current, ".grm-flow", "owner"))) {
350
+ throw new Error(`${current} exists and carries no owner marker — refusing to reuse it.`);
351
+ }
352
+ const rootDir = (0, path_1.join)(current, "..");
353
+ let entries = [];
354
+ try {
355
+ entries = (0, fs_1.readdirSync)(rootDir).filter(e => e.startsWith("flow-"));
356
+ }
357
+ catch (_a) {
358
+ return; // the root does not exist yet
359
+ }
360
+ for (const e of entries) {
361
+ const dir = (0, path_1.join)(rootDir, e);
362
+ if (!(0, fs_1.existsSync)((0, path_1.join)(dir, ".grm-flow", "owner")))
363
+ continue; // not ours
364
+ // SAFE to swallow, for the same reason as removeWorktree: the
365
+ // outcome is re-measured by existsSync rather than inferred.
366
+ await this.git.raw(["worktree", "remove", "--force", dir]).catch(() => { });
367
+ if ((0, fs_1.existsSync)(dir)) {
368
+ try {
369
+ (0, fs_1.rmSync)(dir, { recursive: true, force: true });
370
+ }
371
+ catch ( /* prune reports */_b) { /* prune reports */ }
372
+ }
373
+ }
374
+ // SAFE to swallow: housekeeping with no answer. Nothing branches on
375
+ // whether the registration was cleared, and a stale registration is
376
+ // reclaimed by the next run.
377
+ await this.git.raw(["worktree", "prune"]).catch(() => { });
378
+ }
379
+ /**
380
+ * The commits in a range, read from THIS controller's repository.
381
+ *
382
+ * 🔴 NOT `getGitLogAsJson`. That helper constructs `simpleGit()` with no
383
+ * working directory, so it reads whatever `process.cwd()` happens to be —
384
+ * which is the repository under management only by coincidence. Measured
385
+ * 2026-08-06: seven cases of this suite failed because the derivation was
386
+ * grading the commits of the grm checkout the tests run from instead of the
387
+ * fixture repository it was handed. The CLI never noticed, because there cwd
388
+ * IS the repository. A class that takes a `root` has to honour it.
389
+ */
390
+ async logCommits(args) {
391
+ try {
392
+ const log = await this.git.log(args);
393
+ return log.all.map(c => ({
394
+ hash: c.hash,
395
+ shortHash: c.hash.substring(0, 7),
396
+ message: c.message,
397
+ body: c.body,
398
+ authorName: c.author_name,
399
+ authorEmail: c.author_email,
400
+ date: c.date,
401
+ }));
402
+ }
403
+ catch (_a) {
404
+ // SAFE to swallow: `git log` answers with its OUTPUT, so this is not
405
+ // the exit-code shape lineTags warns about. An empty range and a
406
+ // failed one both produce no commits, and `nextVersion` then falls to
407
+ // the configured defaultBump — a smaller bump than the history would
408
+ // have justified, never a larger one.
409
+ return [];
410
+ }
411
+ }
412
+ escapeRe(s) {
413
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
414
+ }
415
+ /** What `run` would do. Reads only. */
416
+ async plan(name) {
417
+ var _a, _b, _c, _d;
418
+ const p = this.phase(name);
419
+ let ahead = 0, behind = 0;
420
+ if (p.mergeFrom) {
421
+ ahead = await this.count(`${p.branch}..${p.mergeFrom}`);
422
+ behind = await this.count(`${p.mergeFrom}..${p.branch}`);
423
+ }
424
+ const { version, current, why } = await this.nextVersion(p);
425
+ return {
426
+ phase: name,
427
+ branch: p.branch,
428
+ channel: p.channel,
429
+ mergeFrom: p.mergeFrom,
430
+ ahead, behind,
431
+ current, next: version, bumpWhy: why,
432
+ willTag: p.tag !== false,
433
+ willDeleteSource: p.deleteSource === true,
434
+ mergeStrategy: this.strategyOf(p),
435
+ backMerge: (_a = p.backMerge) !== null && _a !== void 0 ? _a : [],
436
+ worktree: ((_d = (_c = (_b = this.config) === null || _b === void 0 ? void 0 : _b.flow) === null || _c === void 0 ? void 0 : _c.worktree) === null || _d === void 0 ? void 0 : _d.enabled) ? this.worktreeDir(name) : undefined,
437
+ };
438
+ }
439
+ async count(range) {
440
+ // SAFE to swallow: `rev-list --count` PRINTS its answer, so the number is
441
+ // read out of stdout and not out of an exit status — see lineTags for
442
+ // the shape that is not safe. Both failure directions land on 0: the
443
+ // catch returns "0", and a wrapper that resolved an error with empty
444
+ // output gives NaN, which the guard below also turns into 0. Zero is the
445
+ // fail-CLOSED direction — `run` refuses a promotion it measures as
446
+ // carrying nothing, so a broken measurement mints no version.
447
+ const out = await this.git.raw(["rev-list", "--count", range]).catch(() => "0");
448
+ const n = parseInt(String(out).trim(), 10);
449
+ return Number.isFinite(n) ? n : 0;
450
+ }
451
+ worktreeDir(phase) {
452
+ var _a, _b, _c, _d;
453
+ const dir = (_d = (_c = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.flow) === null || _b === void 0 ? void 0 : _b.worktree) === null || _c === void 0 ? void 0 : _c.dir) !== null && _d !== void 0 ? _d : ".grm/worktrees";
454
+ return (0, path_1.resolve)(this.root, dir, `flow-${phase}`.replace(/[^A-Za-z0-9_.-]/g, "-"));
455
+ }
456
+ /**
457
+ * mergeInto — carry `source` into `target`, and move `target`'s ref.
458
+ *
459
+ * THE ONE MECHANISM. A promotion, a back-merge and a route are the same act
460
+ * with different names, and writing them three times is how they drift: the
461
+ * promotion would keep its worktree isolation and its expected-value
462
+ * update-ref while a back-merge quietly did a `checkout` in the shared tree.
463
+ * Every caller gets both properties or neither.
464
+ *
465
+ * Returns the merge commit, or "" when there was nothing to merge — the
466
+ * callers treat "nothing to do" differently, so this does not decide it.
467
+ */
468
+ /**
469
+ * THE MERGE ENGINE, exposed so that the only other thing in this codebase
470
+ * that carries a branch into another one does not grow a second copy.
471
+ *
472
+ * `TrackController.forwardPort` cascades a maintenance fix up the tracks,
473
+ * and every hazard `mergeInto` handles applies there identically: a target
474
+ * held in another worktree, `update-ref` desyncing a checked-out branch, a
475
+ * dirty tree that would carry changes across a checkout, `--no-ff` so the
476
+ * pre-merge hooks actually run. Re-implementing that for tracks would put
477
+ * those four decisions in two places, and the first one to drift would do
478
+ * it silently — every step still reporting success.
479
+ *
480
+ * Returns the merge commit, or "" when the target already contains the
481
+ * source (nothing to do is not a failure).
482
+ */
483
+ async mergeBranch(target, source, strategy, label) {
484
+ return this.mergeInto(target, source, strategy, label);
485
+ }
486
+ async mergeInto(target, source, strategy, label) {
487
+ var _a, _b, _c;
488
+ // Both ends must exist. `rev-list --count a..b` FAILS for a missing ref and
489
+ // count() maps a failure to 0, which reads as "nothing to merge" — so a
490
+ // route pointing at a branch that is not there would be reported as
491
+ // skipped-because-already-current.
492
+ await this.assertBranch(target, "the merge target");
493
+ await this.assertBranch(source, "the merge source");
494
+ const ahead = await this.count(`${target}..${source}`);
495
+ if (ahead === 0)
496
+ return "";
497
+ // ── WHO HOLDS THE TARGET DECIDES WHERE THE MERGE HAPPENS ──
498
+ //
499
+ // 🔴 `update-ref` ON A CHECKED-OUT BRANCH DESYNCS THAT CHECKOUT. The ref
500
+ // moves, HEAD follows it, and the working tree and index do NOT — so every
501
+ // file that differs between the old and new commit shows up as a local
502
+ // modification or deletion in a checkout the operator was not even looking
503
+ // at. The promotion path never hit this because its target (the release
504
+ // line) is not the branch anyone stands on; a BACK-MERGE targets the
505
+ // integration line, which is exactly the branch everyone stands on.
506
+ //
507
+ // So: held HERE → merge in place, which is the only way that working tree
508
+ // stays consistent (git updates it as part of the merge). Held in ANOTHER
509
+ // worktree → refuse by name; moving somebody else's checked-out branch is
510
+ // not ours to do.
511
+ const holder = await this.worktreeHolding(target);
512
+ const heldHere = holder !== "" && (0, path_1.resolve)(holder) === (0, path_1.resolve)(this.root);
513
+ if (holder && !heldHere) {
514
+ throw new Error(`${target} is checked out in another worktree (${holder}), so its ref cannot be ` +
515
+ `moved from here without desyncing that checkout. Run the merge there, or detach it.`);
516
+ }
517
+ const useWorktree = ((_c = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.flow) === null || _b === void 0 ? void 0 : _b.worktree) === null || _c === void 0 ? void 0 : _c.enabled) === true && !heldHere;
518
+ let workGit = this.git;
519
+ let createdDir = "";
520
+ // The branch to return to when this merge did not happen in a worktree.
521
+ let restoreTo = "";
522
+ try {
523
+ if (!useWorktree) {
524
+ // ── WITHOUT A WORKTREE THE TARGET HAS TO BE CHECKED OUT ──
525
+ //
526
+ // `git merge <source>` merges into HEAD, so merging into a branch
527
+ // you are not standing on is not a merge at all: with HEAD on main
528
+ // and the target dev, `merge main` answers "Already up to date",
529
+ // dev's ref never moves, and the caller is told it succeeded.
530
+ // Measured 2026-08-06 — five cases of the back-merge and route
531
+ // suites failed exactly here, and the promotion path had hidden it
532
+ // because its target was always the branch you were on.
533
+ const head = (await this.git.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim();
534
+ if (head !== target) {
535
+ // A checkout across a dirty tree either refuses or carries the
536
+ // changes onto the other branch. Neither belongs in a
537
+ // promotion, so it is refused by name — and this is the reason
538
+ // `worktree.enabled` exists.
539
+ const dirty = (await this.git.raw(["status", "--porcelain", "--untracked-files=no"])).trim();
540
+ if (dirty) {
541
+ throw new Error(`${target} is not checked out and the tree is not clean, so it cannot be ` +
542
+ `checked out to merge ${source} into it. Enable flow.worktree, or clean the tree.`);
543
+ }
544
+ await this.git.raw(["checkout", target]);
545
+ restoreTo = head;
546
+ }
547
+ }
548
+ if (useWorktree) {
549
+ const wtDir = this.worktreeDir(label);
550
+ await this.reclaimWorktrees(wtDir);
551
+ (0, fs_1.mkdirSync)((0, path_1.join)(wtDir, ".."), { recursive: true });
552
+ // DETACHED, because git refuses the same branch in two worktrees
553
+ // and the target is very often checked out where you are standing.
554
+ await this.git.raw(["worktree", "add", "--detach", wtDir, target]);
555
+ createdDir = wtDir;
556
+ (0, fs_1.mkdirSync)((0, path_1.join)(wtDir, ".grm-flow"), { recursive: true });
557
+ (0, fs_1.writeFileSync)((0, path_1.join)(wtDir, ".grm-flow", "owner"), OWNER_TOKEN + "\n");
558
+ workGit = (0, simple_git_1.default)(wtDir);
559
+ }
560
+ const args = ["merge", "--no-edit", source];
561
+ // See FlowPhase.merge: `ff` has to be asked for in writing.
562
+ if (strategy === "no-ff")
563
+ args.splice(1, 0, "--no-ff");
564
+ await workGit.raw(args);
565
+ // ── 🔴 A CONFLICT IS NOT AN ERROR HERE. IT IS A RESOLVED PROMISE. ──
566
+ //
567
+ // `git merge` exits 1 on a conflict and writes "CONFLICT (add/add):
568
+ // …" to STDOUT, leaving stderr empty; simple-git 3.27.0 RESOLVES a
569
+ // non-zero exit whose stderr is empty. Measured 2026-08-24 against
570
+ // this repository's own simple-git: the promise resolved with the
571
+ // conflict text as its VALUE and the tree was left at `AA <file>`.
572
+ //
573
+ // So the await above cannot be trusted to have merged anything, and
574
+ // nothing downstream would notice: the promotion goes on to cut a
575
+ // tag over an unmerged index, and every step reports success. This
576
+ // is the same class the lineTags header describes — THE ANSWER IS
577
+ // THE OUTPUT, NOT THE ABSENCE OF A THROW — reaching the write path.
578
+ //
579
+ // The state is read from git rather than from the merge's text,
580
+ // because the text is localised and the index is not.
581
+ const unmerged = (await workGit.raw(["ls-files", "--unmerged"])).trim();
582
+ if (unmerged) {
583
+ // ABORT RATHER THAN LEAVE IT. A caller that continues past this
584
+ // is walking a cascade, and each later step would merge from a
585
+ // branch whose working tree is mid-conflict. Worse on a shared
586
+ // checkout, where the half-merged state belongs to whoever else
587
+ // is standing on that branch.
588
+ await workGit.raw(["merge", "--abort"]).catch(() => { });
589
+ throw new Error(`merging ${source} into ${target} conflicts (${unmerged.split("\n").length} unmerged path(s)); the merge was aborted and nothing moved`);
590
+ }
591
+ const head = (await workGit.revparse(["HEAD"])).trim();
592
+ if (useWorktree) {
593
+ // The worktree is DETACHED, so the merge did not move the branch.
594
+ // `update-ref` with the OLD value as the expected one, so a peer
595
+ // that advanced it in the meantime makes this FAIL rather than
596
+ // silently discarding their work.
597
+ const before = (await this.git.revparse([target])).trim();
598
+ await this.git.raw([
599
+ "update-ref", "-m", `grm flow ${label}: merge ${source}`,
600
+ `refs/heads/${target}`, head, before,
601
+ ]);
602
+ }
603
+ return head;
604
+ }
605
+ finally {
606
+ if (createdDir)
607
+ await this.removeWorktree(createdDir);
608
+ // Put the operator back where they were, even on the throw path: a
609
+ // failed promotion that also leaves you on another branch turns one
610
+ // problem into two.
611
+ if (restoreTo)
612
+ await this.git.raw(["checkout", restoreTo]).catch(() => { });
613
+ }
614
+ }
615
+ /** The route declaration, or a refusal that names what IS declared. */
616
+ route(name) {
617
+ var _a, _b, _c;
618
+ const routes = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.flow) === null || _b === void 0 ? void 0 : _b.routes;
619
+ if (!routes || !routes[name]) {
620
+ throw new Error(`Unknown route '${name}'. Declared: ${routes && Object.keys(routes).length ? Object.keys(routes).join(", ") : "(none)"}`);
621
+ }
622
+ const r = routes[name];
623
+ if (!r.from || !((_c = r.into) === null || _c === void 0 ? void 0 : _c.length)) {
624
+ throw new Error(`Route '${name}' needs both 'from' and a non-empty 'into'.`);
625
+ }
626
+ this.checkDirection(name, r);
627
+ return r;
628
+ }
629
+ /** What `syncRoute` would carry, per target. Reads only. */
630
+ async planRoute(name) {
631
+ const r = this.route(name);
632
+ const ahead = {};
633
+ for (const t of r.into)
634
+ ahead[t] = await this.count(`${t}..${r.from}`);
635
+ return { route: name, ahead };
636
+ }
637
+ /**
638
+ * The worktree path that has `branch` checked out, or "" if none does.
639
+ *
640
+ * `git worktree list --porcelain` is the only surface that answers this for
641
+ * EVERY checkout including the main one; `rev-parse --abbrev-ref HEAD` only
642
+ * ever answers about the directory you asked in, so a branch held by a
643
+ * sibling worktree would read as free.
644
+ */
645
+ async worktreeHolding(branch) {
646
+ const out = await this.git.raw(["worktree", "list", "--porcelain"]).catch(() => "");
647
+ let path = "";
648
+ for (const line of String(out).split("\n")) {
649
+ if (line.startsWith("worktree "))
650
+ path = line.slice("worktree ".length).trim();
651
+ else if (line.startsWith("branch ")) {
652
+ const ref = line.slice("branch ".length).trim();
653
+ if (ref === `refs/heads/${branch}`)
654
+ return path;
655
+ }
656
+ }
657
+ return "";
658
+ }
659
+ /**
660
+ * Run a declared route: carry one branch's content to the others, with no
661
+ * version involved. This is the hotfix/bugfix shape.
662
+ *
663
+ * The DIRECTION is checked against `flow.lines` when both are declared. A
664
+ * hotfix route that says `down` but points up would merge the whole
665
+ * integration line into the release line — a release nobody planned, which
666
+ * every step would report as success.
667
+ */
668
+ async syncRoute(name) {
669
+ const r = this.route(name);
670
+ const merged = {};
671
+ const skipped = [];
672
+ for (const target of r.into) {
673
+ const head = await this.mergeInto(target, r.from, r.merge === "ff" ? "ff" : "no-ff", `route-${name}-${target}`);
674
+ if (head)
675
+ merged[target] = head;
676
+ else
677
+ skipped.push(target);
678
+ }
679
+ return { route: name, merged, skipped };
680
+ }
681
+ /**
682
+ * The declared direction has to match the ladder. A branch not on the ladder
683
+ * is not an error — topic branches are not lines — so it is simply not checked.
684
+ */
685
+ checkDirection(name, r) {
686
+ var _a, _b;
687
+ const lines = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.flow) === null || _b === void 0 ? void 0 : _b.lines;
688
+ if (!(lines === null || lines === void 0 ? void 0 : lines.length) || !r.direction)
689
+ return;
690
+ const from = lines.indexOf(r.from);
691
+ if (from === -1)
692
+ return;
693
+ for (const target of r.into) {
694
+ const to = lines.indexOf(target);
695
+ if (to === -1)
696
+ continue;
697
+ const actual = to > from ? "down" : to < from ? "up" : "same";
698
+ if (actual !== r.direction) {
699
+ throw new Error(`Route '${name}' declares direction '${r.direction}' but ${r.from} -> ${target} ` +
700
+ `is '${actual}' on the declared ladder [${lines.join(" > ")}].`);
701
+ }
702
+ }
703
+ }
704
+ /**
705
+ * Execute the phase.
706
+ *
707
+ * Returns the plan it acted on, with `tagged` set when a tag was created.
708
+ */
709
+ async run(name) {
710
+ var _a;
711
+ const p = this.phase(name);
712
+ const plan = await this.plan(name);
713
+ if (p.mergeFrom && plan.ahead === 0) {
714
+ throw new Error(`${p.mergeFrom} carries nothing that ${p.branch} does not already have. ` +
715
+ `There is nothing to promote.`);
716
+ }
717
+ const mergeCommit = p.mergeFrom
718
+ // The label IS the phase name, so the directory `plan` reports
719
+ // (`flow-<phase>`) is the directory `run` creates. A prettier label
720
+ // here made the plan advertise a path nothing ever used.
721
+ ? await this.mergeInto(p.branch, p.mergeFrom, this.strategyOf(p), name)
722
+ : "";
723
+ // AFTER the merge — see the header. The range now contains the work.
724
+ const { version, current, why } = await this.nextVersion(p, mergeCommit || p.branch);
725
+ plan.next = version;
726
+ plan.current = current;
727
+ plan.bumpWhy = why;
728
+ // The tag is created from the MAIN repository, not from the worktree that
729
+ // performed the merge: the merge commit is in the object database and the
730
+ // branch already points at it, so the worktree has no part left to play —
731
+ // and it has been removed by now. Naming the commit explicitly, because
732
+ // HEAD here is whatever the operator has checked out.
733
+ if (p.tag !== false) {
734
+ await this.git.raw([
735
+ "tag", "-a", version, "-m", `${version}\n\ngrm flow ${name}`,
736
+ ...(mergeCommit ? [mergeCommit] : [p.branch]),
737
+ ]);
738
+ }
739
+ // ── BACK-MERGE, AFTER THE TAG ──
740
+ //
741
+ // After the tag, so every branch that receives the merge also receives the
742
+ // tag and can describe it. Before deleteSource, because a source that is
743
+ // about to be deleted may itself be one of the branches that needs it.
744
+ const backMerged = {};
745
+ for (const target of (_a = p.backMerge) !== null && _a !== void 0 ? _a : []) {
746
+ if (target === p.branch)
747
+ continue; // merging a branch into itself
748
+ const head = await this.mergeInto(target, p.branch, this.strategyOf(p), `back-${name}-${target}`);
749
+ if (head)
750
+ backMerged[target] = head;
751
+ }
752
+ if (p.deleteSource === true && p.mergeFrom) {
753
+ await this.git.raw(["branch", "-d", p.mergeFrom]);
754
+ }
755
+ return {
756
+ ...plan,
757
+ tagged: p.tag !== false ? plan.next : undefined,
758
+ mergeCommit: mergeCommit || undefined,
759
+ backMerged: Object.keys(backMerged).length ? backMerged : undefined,
760
+ };
761
+ }
762
+ }
763
+ exports.FlowController = FlowController;
764
+ //# sourceMappingURL=FlowController.js.map