@ebrindley/build 0.0.0-stage → 1.42.1-rc28

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 (878) hide show
  1. package/.build-project/providers/catalog.json +13951 -0
  2. package/.build-project/providers/pricing.json +1978 -0
  3. package/.build-project/providers/registry.json +4103 -0
  4. package/.github/SECURITY.md +75 -0
  5. package/.nvmrc +1 -0
  6. package/CHANGELOG.md +661 -0
  7. package/CODE_OF_CONDUCT.md +44 -0
  8. package/CONTRIBUTING.md +24 -0
  9. package/INSTALL.md +623 -0
  10. package/LICENSE +21 -0
  11. package/README.md +118 -2
  12. package/THIRD_PARTY_NOTICES.txt +26 -0
  13. package/dist/ai-judge-UE5UOYOO.js +191 -0
  14. package/dist/allowlist-grounding-KPLN6NC5.js +16 -0
  15. package/dist/allowlist-utils-MZZKKXRD.js +31 -0
  16. package/dist/apply-completion-mode-EM37UZHB.js +110 -0
  17. package/dist/artifact-migrator-WPACNSEP.js +276 -0
  18. package/dist/ask-2OZ4JFQR.js +176 -0
  19. package/dist/auth-6UKBTJUQ.js +185 -0
  20. package/dist/auth-H5KJL6HL.js +165 -0
  21. package/dist/auth-LVJRJDMU.js +12 -0
  22. package/dist/auth-NHZOCNRR.js +94 -0
  23. package/dist/auth-PBXHWXGW.js +95 -0
  24. package/dist/auth-T7Y5DCAH.js +91 -0
  25. package/dist/auth-TVVKCHQW.js +13 -0
  26. package/dist/auth-UHB2UCSS.js +97 -0
  27. package/dist/auth-VACA3VUL.js +98 -0
  28. package/dist/auth-VVLC77S3.js +44 -0
  29. package/dist/auth-liveness-XO4AGDDD.js +53 -0
  30. package/dist/autoloop-cleanup-SI3VGAAR.js +106 -0
  31. package/dist/autoloop-evidence-gates-J5GG5YQB.js +39 -0
  32. package/dist/autoloop-gate-policy-SUNAEP6Q.js +169 -0
  33. package/dist/autoloop-helpers-VQGQNTT6.js +52 -0
  34. package/dist/autoloop-ledger-P6TIDP7C.js +96 -0
  35. package/dist/autoloop-ledger-subscriber-HFAGOZXH.js +161 -0
  36. package/dist/autoloop-run-defaults-GWGZBNT7.js +27 -0
  37. package/dist/autoloop-run-lock-GBWRM5A2.js +197 -0
  38. package/dist/autoloop-success-C32QVWOP.js +93 -0
  39. package/dist/autoloop-termination-summary-GI6IBQWD.js +58 -0
  40. package/dist/autoloop-trajectory-AMKSQISD.js +70 -0
  41. package/dist/autoloop-wall-clock-T7ZVIQOC.js +12 -0
  42. package/dist/automatic-branch-cleanup-R62X2C5O.js +49 -0
  43. package/dist/autonomous-loop-controller-2WL363LW.js +4386 -0
  44. package/dist/backend-YUTFDZXZ.js +30 -0
  45. package/dist/background-executor-Z3ODTMD7.js +260 -0
  46. package/dist/backlog-75QPEAMW.js +403 -0
  47. package/dist/backlog-execution-intent-GWUV5TUK.js +19 -0
  48. package/dist/backup-active-store-XHWLN34M.js +16 -0
  49. package/dist/backup-machine-stores-UI4LTJOY.js +251 -0
  50. package/dist/backup-telemetry-db-Z4ICYCNW.js +26 -0
  51. package/dist/branch-archive-manager-FMSQ7YJF.js +18 -0
  52. package/dist/branch-cleanup-manager-ST6FJGND.js +35 -0
  53. package/dist/build-gate-7NKWPY62.js +68 -0
  54. package/dist/build-root-S7DINODY.js +18 -0
  55. package/dist/change-summary-R6CB6VXJ.js +50 -0
  56. package/dist/chunk-24MNKKOM.js +173 -0
  57. package/dist/chunk-2H6VZFIO.js +235 -0
  58. package/dist/chunk-2JIX3EKV.js +39 -0
  59. package/dist/chunk-2KO7HVZM.js +106 -0
  60. package/dist/chunk-2L36U25O.js +100 -0
  61. package/dist/chunk-2NMNFUQA.js +475 -0
  62. package/dist/chunk-2OUAEH67.js +83 -0
  63. package/dist/chunk-2VLJUXJU.js +115 -0
  64. package/dist/chunk-2VUEDIUM.js +77 -0
  65. package/dist/chunk-2Y2IIHPI.js +430 -0
  66. package/dist/chunk-2YRG3LHZ.js +220 -0
  67. package/dist/chunk-2Z5Q3SUY.js +65 -0
  68. package/dist/chunk-32IYXIE5.js +873 -0
  69. package/dist/chunk-33IGPPUI.js +292 -0
  70. package/dist/chunk-352PCJLK.js +283 -0
  71. package/dist/chunk-35J4NE6S.js +226 -0
  72. package/dist/chunk-3C7WBIVK.js +1016 -0
  73. package/dist/chunk-3H3EY6U7.js +1225 -0
  74. package/dist/chunk-3H4MWYIC.js +198 -0
  75. package/dist/chunk-3HHWQR3N.js +2479 -0
  76. package/dist/chunk-3JKNRYEE.js +14 -0
  77. package/dist/chunk-3LECCYZY.js +128 -0
  78. package/dist/chunk-3LOY6YZI.js +852 -0
  79. package/dist/chunk-3M57DADF.js +44 -0
  80. package/dist/chunk-3NOTLVLG.js +3803 -0
  81. package/dist/chunk-3OPP2OZB.js +1480 -0
  82. package/dist/chunk-3P5IN5E7.js +9 -0
  83. package/dist/chunk-3PL22IYZ.js +20 -0
  84. package/dist/chunk-3REDAJUJ.js +14 -0
  85. package/dist/chunk-3S2R4XJI.js +203 -0
  86. package/dist/chunk-3UBZI5DW.js +61 -0
  87. package/dist/chunk-3VV5OBGG.js +308 -0
  88. package/dist/chunk-3WY5TU2O.js +823 -0
  89. package/dist/chunk-43OKHTW4.js +82 -0
  90. package/dist/chunk-45KUJBDI.js +112 -0
  91. package/dist/chunk-47X5LM7B.js +224 -0
  92. package/dist/chunk-4B6FQJ77.js +268 -0
  93. package/dist/chunk-4BTDUT2S.js +42 -0
  94. package/dist/chunk-4DJL2VXA.js +24 -0
  95. package/dist/chunk-4EBSXZ73.js +48 -0
  96. package/dist/chunk-4QKP6I4C.js +294 -0
  97. package/dist/chunk-4U6XK2DG.js +300 -0
  98. package/dist/chunk-4UMRUFBD.js +132 -0
  99. package/dist/chunk-4US4SYJ4.js +569 -0
  100. package/dist/chunk-4ZPLWEZO.js +154 -0
  101. package/dist/chunk-56WPYDJH.js +624 -0
  102. package/dist/chunk-57WRCJJW.js +50 -0
  103. package/dist/chunk-5AW4RMNG.js +24 -0
  104. package/dist/chunk-5EQN56OZ.js +155 -0
  105. package/dist/chunk-5F43TUIN.js +38 -0
  106. package/dist/chunk-5FKHIKTS.js +115 -0
  107. package/dist/chunk-5HDP7XZG.js +91 -0
  108. package/dist/chunk-5KQETTNS.js +152 -0
  109. package/dist/chunk-5PDVN2KO.js +498 -0
  110. package/dist/chunk-5UBIFVRD.js +509 -0
  111. package/dist/chunk-5YDE3Q62.js +46 -0
  112. package/dist/chunk-626AJVMU.js +302 -0
  113. package/dist/chunk-633XZ7UF.js +3583 -0
  114. package/dist/chunk-63DHNHGA.js +236 -0
  115. package/dist/chunk-666656AR.js +568 -0
  116. package/dist/chunk-67YRJPJO.js +19 -0
  117. package/dist/chunk-6CAU7VBA.js +20 -0
  118. package/dist/chunk-6CB3KJRY.js +21 -0
  119. package/dist/chunk-6DBMALXL.js +29 -0
  120. package/dist/chunk-6E25C4IA.js +269 -0
  121. package/dist/chunk-6FIBNIQU.js +73 -0
  122. package/dist/chunk-6G57FYBV.js +189 -0
  123. package/dist/chunk-6KZKRTG3.js +4885 -0
  124. package/dist/chunk-6LAH2UV2.js +525 -0
  125. package/dist/chunk-6PZY2TTU.js +921 -0
  126. package/dist/chunk-6T6NHXK4.js +230 -0
  127. package/dist/chunk-6TBEX4R4.js +432 -0
  128. package/dist/chunk-6TRD7TEE.js +911 -0
  129. package/dist/chunk-6XCP2RAI.js +47 -0
  130. package/dist/chunk-726G6WDL.js +351 -0
  131. package/dist/chunk-75EMT7BF.js +616 -0
  132. package/dist/chunk-762ACDZJ.js +4696 -0
  133. package/dist/chunk-77I6G4CO.js +1 -0
  134. package/dist/chunk-7DJ6SQH3.js +510 -0
  135. package/dist/chunk-7HPCIOMA.js +1383 -0
  136. package/dist/chunk-7HYBSRPZ.js +17503 -0
  137. package/dist/chunk-7KBEOPVB.js +73 -0
  138. package/dist/chunk-7LHJDJB3.js +2222 -0
  139. package/dist/chunk-7NVJMH52.js +306 -0
  140. package/dist/chunk-7RMARDVH.js +33 -0
  141. package/dist/chunk-7SEWU4QG.js +36 -0
  142. package/dist/chunk-7TUTZTI2.js +911 -0
  143. package/dist/chunk-7VBDFPUM.js +340 -0
  144. package/dist/chunk-7VRJHTGZ.js +6406 -0
  145. package/dist/chunk-7YAOUUKK.js +493 -0
  146. package/dist/chunk-AAAODV76.js +860 -0
  147. package/dist/chunk-AB4HUJVQ.js +339 -0
  148. package/dist/chunk-AEQWV746.js +611 -0
  149. package/dist/chunk-AHU3FKPA.js +11639 -0
  150. package/dist/chunk-AISTV5XU.js +226 -0
  151. package/dist/chunk-AJBTKGJZ.js +48 -0
  152. package/dist/chunk-AJJNW7XT.js +248 -0
  153. package/dist/chunk-AJN5Y5YZ.js +160 -0
  154. package/dist/chunk-ALDTFNZ3.js +150 -0
  155. package/dist/chunk-ARARVIZK.js +281 -0
  156. package/dist/chunk-ATBM6AW5.js +53 -0
  157. package/dist/chunk-ATKEKM3E.js +206 -0
  158. package/dist/chunk-AUJLW6JZ.js +92 -0
  159. package/dist/chunk-AY3MHEFM.js +24 -0
  160. package/dist/chunk-B7PYTV72.js +236 -0
  161. package/dist/chunk-B7YRSULE.js +1423 -0
  162. package/dist/chunk-BAWJNMWF.js +339 -0
  163. package/dist/chunk-BBPIILO2.js +88 -0
  164. package/dist/chunk-BD3PGW6A.js +957 -0
  165. package/dist/chunk-BDPYFAB4.js +44 -0
  166. package/dist/chunk-BIUV23HH.js +729 -0
  167. package/dist/chunk-BQ3VAGXH.js +243 -0
  168. package/dist/chunk-BQJOGAWT.js +31 -0
  169. package/dist/chunk-BT7EG7CO.js +68 -0
  170. package/dist/chunk-BV3XQQLU.js +27 -0
  171. package/dist/chunk-BY6ODHNZ.js +78 -0
  172. package/dist/chunk-BZRLSZNV.js +79 -0
  173. package/dist/chunk-C3DH3NCY.js +2773 -0
  174. package/dist/chunk-C3KCMAJP.js +756 -0
  175. package/dist/chunk-C7AGUJ5K.js +267 -0
  176. package/dist/chunk-CBSWKQCX.js +342 -0
  177. package/dist/chunk-CE5OZBYY.js +21 -0
  178. package/dist/chunk-CFCVYHSW.js +373 -0
  179. package/dist/chunk-CHA2HDE5.js +126 -0
  180. package/dist/chunk-CIHWPGS5.js +146 -0
  181. package/dist/chunk-CJBSZX3F.js +127 -0
  182. package/dist/chunk-CLA6QIJM.js +43 -0
  183. package/dist/chunk-CPSVQR2I.js +365 -0
  184. package/dist/chunk-CRPRVNQ4.js +254 -0
  185. package/dist/chunk-CSIE4Y7C.js +1093 -0
  186. package/dist/chunk-CSOPSYDY.js +142 -0
  187. package/dist/chunk-CSXLLEGB.js +205 -0
  188. package/dist/chunk-CTDLERWU.js +293 -0
  189. package/dist/chunk-CULBXMSK.js +110 -0
  190. package/dist/chunk-D2M2Y5ID.js +21 -0
  191. package/dist/chunk-D37WY7SH.js +1060 -0
  192. package/dist/chunk-D4VJFCGZ.js +89 -0
  193. package/dist/chunk-D6WTZMZB.js +48 -0
  194. package/dist/chunk-DBHOWDUH.js +976 -0
  195. package/dist/chunk-DCACX7BV.js +19364 -0
  196. package/dist/chunk-DFHX4XYA.js +128 -0
  197. package/dist/chunk-DIKBRRKE.js +176 -0
  198. package/dist/chunk-DJG5RIOR.js +9 -0
  199. package/dist/chunk-DNIOIISW.js +616 -0
  200. package/dist/chunk-DOA5G7IA.js +315 -0
  201. package/dist/chunk-DP7FKP6W.js +855 -0
  202. package/dist/chunk-DS2JZ677.js +79 -0
  203. package/dist/chunk-DSRLVYBS.js +82 -0
  204. package/dist/chunk-EAEVKNJA.js +209 -0
  205. package/dist/chunk-EEUESN3T.js +575 -0
  206. package/dist/chunk-EJ4LUU5Y.js +73 -0
  207. package/dist/chunk-EJIWTPSZ.js +1063 -0
  208. package/dist/chunk-EJVCDTAN.js +116 -0
  209. package/dist/chunk-EKLUBDBQ.js +627 -0
  210. package/dist/chunk-EN62WLFD.js +849 -0
  211. package/dist/chunk-ENYRCL43.js +26 -0
  212. package/dist/chunk-EP22ZMFO.js +273 -0
  213. package/dist/chunk-EP4SVAVI.js +87 -0
  214. package/dist/chunk-EPAMVGI3.js +1562 -0
  215. package/dist/chunk-EPRMH6HO.js +24 -0
  216. package/dist/chunk-ES6NWJ36.js +4057 -0
  217. package/dist/chunk-ETA2K4KI.js +30 -0
  218. package/dist/chunk-ETAD4NKD.js +31 -0
  219. package/dist/chunk-EUWIIDQ7.js +93 -0
  220. package/dist/chunk-EVE3OD2W.js +141 -0
  221. package/dist/chunk-EXA26FFC.js +459 -0
  222. package/dist/chunk-EXSPAA35.js +244 -0
  223. package/dist/chunk-F55YABKV.js +258 -0
  224. package/dist/chunk-F5DNGU5W.js +27 -0
  225. package/dist/chunk-F622MJYV.js +103 -0
  226. package/dist/chunk-F6NIQD74.js +5111 -0
  227. package/dist/chunk-FAWJTC34.js +43 -0
  228. package/dist/chunk-FAZBRHGG.js +47 -0
  229. package/dist/chunk-FIEUSGNJ.js +39 -0
  230. package/dist/chunk-FKCG7K6H.js +1146 -0
  231. package/dist/chunk-FOVVXV45.js +229 -0
  232. package/dist/chunk-FRBPKBFE.js +30 -0
  233. package/dist/chunk-FSA5BPFI.js +268 -0
  234. package/dist/chunk-FSJ5TTZ3.js +29 -0
  235. package/dist/chunk-FT7SGLXT.js +193 -0
  236. package/dist/chunk-FUUVZZUB.js +62 -0
  237. package/dist/chunk-FYMRVUNZ.js +1697 -0
  238. package/dist/chunk-FYTAA5FG.js +162 -0
  239. package/dist/chunk-G3VB2UCZ.js +3892 -0
  240. package/dist/chunk-G6OIMVXH.js +405 -0
  241. package/dist/chunk-G7PQCXVH.js +228 -0
  242. package/dist/chunk-GAB6UW52.js +1087 -0
  243. package/dist/chunk-GAFJEYLK.js +29 -0
  244. package/dist/chunk-GC4CRMTS.js +642 -0
  245. package/dist/chunk-GFHSIWHL.js +5297 -0
  246. package/dist/chunk-GI5M67YA.js +735 -0
  247. package/dist/chunk-GIJWHUWF.js +191 -0
  248. package/dist/chunk-GO6DRECI.js +1 -0
  249. package/dist/chunk-GOFVBTMN.js +314 -0
  250. package/dist/chunk-GQIP72ZJ.js +13 -0
  251. package/dist/chunk-GQXLXRFA.js +28 -0
  252. package/dist/chunk-GT6HFKJB.js +48 -0
  253. package/dist/chunk-GVJGSSKM.js +174 -0
  254. package/dist/chunk-GWHGTG37.js +36 -0
  255. package/dist/chunk-GZAJHLKO.js +18 -0
  256. package/dist/chunk-GZK62I3N.js +314 -0
  257. package/dist/chunk-H3HGMISG.js +483 -0
  258. package/dist/chunk-H3ISZJMJ.js +403 -0
  259. package/dist/chunk-H4HXVWEC.js +9 -0
  260. package/dist/chunk-H6MJGKAW.js +120 -0
  261. package/dist/chunk-HBTTGVR5.js +353 -0
  262. package/dist/chunk-HBZ322WZ.js +35 -0
  263. package/dist/chunk-HEP3ILP4.js +34 -0
  264. package/dist/chunk-HGFXODKO.js +106 -0
  265. package/dist/chunk-HHWDTB6S.js +59 -0
  266. package/dist/chunk-HKO45NLZ.js +286 -0
  267. package/dist/chunk-HLVTEA6A.js +89 -0
  268. package/dist/chunk-HS3SY6HN.js +160 -0
  269. package/dist/chunk-HT5OCGKN.js +899 -0
  270. package/dist/chunk-HXIIEMGF.js +78 -0
  271. package/dist/chunk-I56TH7VM.js +46 -0
  272. package/dist/chunk-I6FN3R5D.js +352 -0
  273. package/dist/chunk-I7SCBHJN.js +655 -0
  274. package/dist/chunk-IJM4GKAT.js +529 -0
  275. package/dist/chunk-IMEYU36R.js +344 -0
  276. package/dist/chunk-INJ3SS6A.js +936 -0
  277. package/dist/chunk-IUKOPCCE.js +441 -0
  278. package/dist/chunk-IVEPZQJO.js +33 -0
  279. package/dist/chunk-IVZEONFC.js +43 -0
  280. package/dist/chunk-IWBHRSG7.js +936 -0
  281. package/dist/chunk-IYY3HQAD.js +484 -0
  282. package/dist/chunk-J2ICMYDA.js +48 -0
  283. package/dist/chunk-J2QCFLUN.js +505 -0
  284. package/dist/chunk-J5HM6V5P.js +1039 -0
  285. package/dist/chunk-J6NZX6QH.js +398 -0
  286. package/dist/chunk-JBBB2Y47.js +432 -0
  287. package/dist/chunk-JDCZQZU7.js +42 -0
  288. package/dist/chunk-JEDNXGSS.js +169 -0
  289. package/dist/chunk-JHP7OT6K.js +89 -0
  290. package/dist/chunk-JLS65NUQ.js +14 -0
  291. package/dist/chunk-JNMWYMC6.js +38 -0
  292. package/dist/chunk-JNSTWNNW.js +25 -0
  293. package/dist/chunk-JOSK6GEU.js +9564 -0
  294. package/dist/chunk-JQUMSIGC.js +100 -0
  295. package/dist/chunk-JVHGMURQ.js +1106 -0
  296. package/dist/chunk-JYXS47FQ.js +951 -0
  297. package/dist/chunk-K2ZMW2Z5.js +2147 -0
  298. package/dist/chunk-K7FAFORM.js +14 -0
  299. package/dist/chunk-KBJXX3ON.js +333 -0
  300. package/dist/chunk-KHFKVQWY.js +486 -0
  301. package/dist/chunk-KHMEI3DQ.js +173 -0
  302. package/dist/chunk-KHW3UD7B.js +69 -0
  303. package/dist/chunk-KKQKWAMF.js +365 -0
  304. package/dist/chunk-KOKXJV2U.js +455 -0
  305. package/dist/chunk-KQ4NGOJI.js +14 -0
  306. package/dist/chunk-KQYQOXMS.js +342 -0
  307. package/dist/chunk-KTMW65UX.js +14 -0
  308. package/dist/chunk-KUEWV2JH.js +593 -0
  309. package/dist/chunk-KXYDV3HP.js +1523 -0
  310. package/dist/chunk-KZ4JMGZ5.js +96 -0
  311. package/dist/chunk-KZWGBUIO.js +2659 -0
  312. package/dist/chunk-L2CBG5IX.js +1892 -0
  313. package/dist/chunk-L2S235CU.js +314 -0
  314. package/dist/chunk-L32WD57F.js +98 -0
  315. package/dist/chunk-LDJCKAJP.js +123 -0
  316. package/dist/chunk-LDWNBEN7.js +541 -0
  317. package/dist/chunk-LJVH57G2.js +241 -0
  318. package/dist/chunk-LPQ7NZEN.js +209 -0
  319. package/dist/chunk-LRGH3CCV.js +148 -0
  320. package/dist/chunk-LULOGMMM.js +1133 -0
  321. package/dist/chunk-LWGKN2GY.js +8284 -0
  322. package/dist/chunk-LX4F24ZH.js +157 -0
  323. package/dist/chunk-M4BUEXXF.js +839 -0
  324. package/dist/chunk-M6UHOC4I.js +553 -0
  325. package/dist/chunk-MCBNWZNO.js +657 -0
  326. package/dist/chunk-MEMSY6VY.js +223 -0
  327. package/dist/chunk-MHLEZQQI.js +145 -0
  328. package/dist/chunk-MJ6WNSIX.js +192 -0
  329. package/dist/chunk-MKASIKWZ.js +442 -0
  330. package/dist/chunk-MNOVBYFU.js +60 -0
  331. package/dist/chunk-MO2BYAAF.js +2896 -0
  332. package/dist/chunk-MP6P7Y2A.js +180 -0
  333. package/dist/chunk-MQ4TFJAG.js +3365 -0
  334. package/dist/chunk-MT2WAIR3.js +131 -0
  335. package/dist/chunk-MTU7VTNN.js +1122 -0
  336. package/dist/chunk-MULMXX4V.js +150 -0
  337. package/dist/chunk-MW2DWWVA.js +147 -0
  338. package/dist/chunk-MY3ZPUN4.js +151 -0
  339. package/dist/chunk-MYLH2S4G.js +64 -0
  340. package/dist/chunk-MZ5WYKNA.js +28 -0
  341. package/dist/chunk-N3Q2JNPV.js +249 -0
  342. package/dist/chunk-N5DX4JAK.js +12 -0
  343. package/dist/chunk-NAINGKHF.js +35 -0
  344. package/dist/chunk-NEQUQHOX.js +223 -0
  345. package/dist/chunk-NHNPEZS4.js +1408 -0
  346. package/dist/chunk-NHTIXJCR.js +17 -0
  347. package/dist/chunk-NKLPMBNV.js +1154 -0
  348. package/dist/chunk-NMVZ5YES.js +199 -0
  349. package/dist/chunk-NRFRY3GE.js +256 -0
  350. package/dist/chunk-NTD6CSI6.js +1266 -0
  351. package/dist/chunk-NUO7B3SH.js +318 -0
  352. package/dist/chunk-NVOHIJKG.js +1319 -0
  353. package/dist/chunk-NXH3RX7O.js +523 -0
  354. package/dist/chunk-NXZ3DURF.js +257 -0
  355. package/dist/chunk-O26L6F7F.js +209 -0
  356. package/dist/chunk-O5RRIUEP.js +124 -0
  357. package/dist/chunk-O5X6BKAO.js +10 -0
  358. package/dist/chunk-O6ZQUVTR.js +31 -0
  359. package/dist/chunk-O7FE75QZ.js +306 -0
  360. package/dist/chunk-OC7Z6AJQ.js +81 -0
  361. package/dist/chunk-OH7IEZ63.js +307 -0
  362. package/dist/chunk-OI734GRS.js +115 -0
  363. package/dist/chunk-OJBH62DK.js +684 -0
  364. package/dist/chunk-OKJLVSTJ.js +247 -0
  365. package/dist/chunk-OMX5VL43.js +79 -0
  366. package/dist/chunk-ONHAMBN6.js +12 -0
  367. package/dist/chunk-ONYPLIVE.js +753 -0
  368. package/dist/chunk-OSK7QWPD.js +637 -0
  369. package/dist/chunk-OTXLMJKP.js +438 -0
  370. package/dist/chunk-OV5PKQMA.js +213 -0
  371. package/dist/chunk-OXK5HA4B.js +31 -0
  372. package/dist/chunk-OYDWFQA4.js +272 -0
  373. package/dist/chunk-OZAUKWHB.js +22 -0
  374. package/dist/chunk-P5P2EKGH.js +94 -0
  375. package/dist/chunk-P6SSWAKY.js +29 -0
  376. package/dist/chunk-P7CQGPLS.js +30 -0
  377. package/dist/chunk-P7RVCHQV.js +197 -0
  378. package/dist/chunk-PEBWDYIW.js +726 -0
  379. package/dist/chunk-PFCXFO7A.js +9193 -0
  380. package/dist/chunk-PFLDWMX6.js +168 -0
  381. package/dist/chunk-PHZGLQSK.js +15883 -0
  382. package/dist/chunk-PNFTPNSR.js +20 -0
  383. package/dist/chunk-PPHXX4W7.js +175 -0
  384. package/dist/chunk-PPZESPJT.js +262 -0
  385. package/dist/chunk-PRDHI2L5.js +296 -0
  386. package/dist/chunk-PSTKWHHN.js +32 -0
  387. package/dist/chunk-PV53ODOT.js +555 -0
  388. package/dist/chunk-PVJBTI7P.js +24 -0
  389. package/dist/chunk-PXKERBKX.js +100 -0
  390. package/dist/chunk-PZ5AY32C.js +10 -0
  391. package/dist/chunk-Q3DHEZA5.js +85 -0
  392. package/dist/chunk-Q5RZDVQK.js +204 -0
  393. package/dist/chunk-Q64IR2Z2.js +4933 -0
  394. package/dist/chunk-Q6Z5UGPL.js +398 -0
  395. package/dist/chunk-QAMAV4DT.js +627 -0
  396. package/dist/chunk-QBWF4444.js +112 -0
  397. package/dist/chunk-QDKYT4CI.js +22805 -0
  398. package/dist/chunk-QFLBRWCJ.js +126 -0
  399. package/dist/chunk-QILAQACE.js +107 -0
  400. package/dist/chunk-QJ6OEH4K.js +3683 -0
  401. package/dist/chunk-QK3NLYTV.js +320 -0
  402. package/dist/chunk-QOFLUS24.js +535 -0
  403. package/dist/chunk-QOIASNEJ.js +98 -0
  404. package/dist/chunk-QP4UTSOV.js +3587 -0
  405. package/dist/chunk-QP5ST7RI.js +904 -0
  406. package/dist/chunk-QS5AGRZN.js +167 -0
  407. package/dist/chunk-QTAOU53N.js +107 -0
  408. package/dist/chunk-QTCLJHLZ.js +351 -0
  409. package/dist/chunk-QTOLTG4L.js +119 -0
  410. package/dist/chunk-QWDV4OSL.js +142 -0
  411. package/dist/chunk-QWMQ74KD.js +508 -0
  412. package/dist/chunk-QX6LOMMH.js +158 -0
  413. package/dist/chunk-QXBKIHY7.js +238 -0
  414. package/dist/chunk-QXBKTJT6.js +270 -0
  415. package/dist/chunk-QYQOVOLR.js +196 -0
  416. package/dist/chunk-R2CKS6WT.js +73 -0
  417. package/dist/chunk-R2TIYG7U.js +68 -0
  418. package/dist/chunk-R2W3LESH.js +465 -0
  419. package/dist/chunk-R5EXHMUN.js +100 -0
  420. package/dist/chunk-RBBTBCHX.js +289 -0
  421. package/dist/chunk-RBKLOUXA.js +121 -0
  422. package/dist/chunk-RCP2Y6DQ.js +86 -0
  423. package/dist/chunk-RCYEJSD5.js +260 -0
  424. package/dist/chunk-RFDVSI4N.js +134 -0
  425. package/dist/chunk-RGJU63FV.js +1717 -0
  426. package/dist/chunk-RI4EX2QE.js +18 -0
  427. package/dist/chunk-RIMARPCF.js +152 -0
  428. package/dist/chunk-RJ6RSNT6.js +42 -0
  429. package/dist/chunk-RNI2GUIF.js +131 -0
  430. package/dist/chunk-RPHUWJ3K.js +264 -0
  431. package/dist/chunk-RPIMAMV7.js +361 -0
  432. package/dist/chunk-RQFX6YRN.js +49 -0
  433. package/dist/chunk-RRC5BL7B.js +285 -0
  434. package/dist/chunk-RSYTSBOO.js +79 -0
  435. package/dist/chunk-RWQQIKIC.js +35 -0
  436. package/dist/chunk-RZUBOZH2.js +373 -0
  437. package/dist/chunk-S2E632FQ.js +380 -0
  438. package/dist/chunk-S2VQCZO4.js +22 -0
  439. package/dist/chunk-S2XIMQJQ.js +681 -0
  440. package/dist/chunk-S47ISY27.js +183 -0
  441. package/dist/chunk-S6I4KISU.js +142 -0
  442. package/dist/chunk-S6TAFQI5.js +2403 -0
  443. package/dist/chunk-SBBNT5ZJ.js +27 -0
  444. package/dist/chunk-SDJV2DTQ.js +491 -0
  445. package/dist/chunk-SDPIFNLD.js +33 -0
  446. package/dist/chunk-SF6YK3JI.js +835 -0
  447. package/dist/chunk-SK3ZFONO.js +976 -0
  448. package/dist/chunk-SKTFRFQ7.js +1775 -0
  449. package/dist/chunk-SNGM452K.js +2002 -0
  450. package/dist/chunk-STW7OFOA.js +581 -0
  451. package/dist/chunk-SU6UFUQY.js +1351 -0
  452. package/dist/chunk-SVJM3LJA.js +27 -0
  453. package/dist/chunk-SVUNZOPG.js +129 -0
  454. package/dist/chunk-T5XLUYV3.js +34 -0
  455. package/dist/chunk-T7E5JS6N.js +57 -0
  456. package/dist/chunk-TA3N5MMO.js +450 -0
  457. package/dist/chunk-TAJPCXSB.js +13 -0
  458. package/dist/chunk-TDEMDRN2.js +1639 -0
  459. package/dist/chunk-TDSEX5CF.js +24 -0
  460. package/dist/chunk-TGCVL74Y.js +28 -0
  461. package/dist/chunk-TGXXYDL4.js +1012 -0
  462. package/dist/chunk-TIKTYUJO.js +296 -0
  463. package/dist/chunk-TIZAJD4M.js +6029 -0
  464. package/dist/chunk-TLSEZZCG.js +5549 -0
  465. package/dist/chunk-TMBDRHAX.js +19 -0
  466. package/dist/chunk-TRURQUBP.js +1217 -0
  467. package/dist/chunk-TSQ256N5.js +152 -0
  468. package/dist/chunk-TUQMMFEQ.js +2244 -0
  469. package/dist/chunk-U424MJLC.js +81 -0
  470. package/dist/chunk-U4DRS6ZW.js +11 -0
  471. package/dist/chunk-U5KS22IN.js +204 -0
  472. package/dist/chunk-UAPHFJPN.js +673 -0
  473. package/dist/chunk-UB7LQITD.js +1040 -0
  474. package/dist/chunk-UBVRHGAZ.js +237 -0
  475. package/dist/chunk-UDNNAQN5.js +98 -0
  476. package/dist/chunk-UJP3XM54.js +342 -0
  477. package/dist/chunk-UJYDH2MW.js +305 -0
  478. package/dist/chunk-UKMPASIC.js +399 -0
  479. package/dist/chunk-UKUL3EHK.js +763 -0
  480. package/dist/chunk-UPHU64NB.js +1327 -0
  481. package/dist/chunk-URMSZXAD.js +43 -0
  482. package/dist/chunk-US3RT6CY.js +525 -0
  483. package/dist/chunk-UTDEOPKV.js +30 -0
  484. package/dist/chunk-UUUDKV7N.js +13 -0
  485. package/dist/chunk-UVKWU3SM.js +39 -0
  486. package/dist/chunk-V2TVPO3X.js +521 -0
  487. package/dist/chunk-V3KLVK7B.js +398 -0
  488. package/dist/chunk-V3YFFHDR.js +17 -0
  489. package/dist/chunk-VAG6GUBR.js +1162 -0
  490. package/dist/chunk-VBENAHDA.js +1814 -0
  491. package/dist/chunk-VBNCKCCI.js +16 -0
  492. package/dist/chunk-VCGSWN5M.js +1300 -0
  493. package/dist/chunk-VE2O2I7M.js +115 -0
  494. package/dist/chunk-VIFHYTI5.js +31 -0
  495. package/dist/chunk-VJER3FUS.js +5080 -0
  496. package/dist/chunk-VLMDM56Q.js +268 -0
  497. package/dist/chunk-VMFZEVVX.js +99 -0
  498. package/dist/chunk-VNDPQVUZ.js +1853 -0
  499. package/dist/chunk-VSPJRLGA.js +4783 -0
  500. package/dist/chunk-VSWC5ZXI.js +103 -0
  501. package/dist/chunk-VYI4DSZP.js +2017 -0
  502. package/dist/chunk-W4BAIQ6L.js +1212 -0
  503. package/dist/chunk-W7VQAL2K.js +2203 -0
  504. package/dist/chunk-WEI3ZDZH.js +33 -0
  505. package/dist/chunk-WEIUS5NT.js +26 -0
  506. package/dist/chunk-WEW7UFWE.js +546 -0
  507. package/dist/chunk-WGQAXLNA.js +384 -0
  508. package/dist/chunk-WJAL4JL3.js +206 -0
  509. package/dist/chunk-WKFOJ5ZG.js +141 -0
  510. package/dist/chunk-WMWQEFLN.js +2177 -0
  511. package/dist/chunk-WNECKKO2.js +154 -0
  512. package/dist/chunk-WPKLYOAM.js +195 -0
  513. package/dist/chunk-WSH37YQN.js +243 -0
  514. package/dist/chunk-WV3KQDPE.js +84 -0
  515. package/dist/chunk-WZFC4V4U.js +389 -0
  516. package/dist/chunk-XCOIBNET.js +13 -0
  517. package/dist/chunk-XDM65LBX.js +53 -0
  518. package/dist/chunk-XGU6PBO5.js +645 -0
  519. package/dist/chunk-XHOI4V62.js +43 -0
  520. package/dist/chunk-XIBVFMLQ.js +6858 -0
  521. package/dist/chunk-XJ2E7YEJ.js +117 -0
  522. package/dist/chunk-XON4ZCYX.js +69 -0
  523. package/dist/chunk-XQPEWJPI.js +127 -0
  524. package/dist/chunk-XSJTIFUY.js +31 -0
  525. package/dist/chunk-XT7OVWM3.js +64 -0
  526. package/dist/chunk-XTXYIISX.js +1104 -0
  527. package/dist/chunk-XV7NZL4B.js +57 -0
  528. package/dist/chunk-XWIZ6B5S.js +109 -0
  529. package/dist/chunk-XWLIKOBX.js +240 -0
  530. package/dist/chunk-XZOXEIN4.js +156 -0
  531. package/dist/chunk-XZRS7I7W.js +3673 -0
  532. package/dist/chunk-Y4ZDDHB6.js +44 -0
  533. package/dist/chunk-Y733RB7T.js +194 -0
  534. package/dist/chunk-YBHUB4XR.js +14931 -0
  535. package/dist/chunk-YKC75XK4.js +147 -0
  536. package/dist/chunk-YKMXFVK7.js +27 -0
  537. package/dist/chunk-YO5BAJ55.js +225 -0
  538. package/dist/chunk-YPDCLXNZ.js +568 -0
  539. package/dist/chunk-YSQPGVFK.js +116 -0
  540. package/dist/chunk-YTVVTIWJ.js +716 -0
  541. package/dist/chunk-YVCMDVBB.js +698 -0
  542. package/dist/chunk-YYTOA6DP.js +114 -0
  543. package/dist/chunk-Z5WGNULV.js +88 -0
  544. package/dist/chunk-Z6NGVVXG.js +66 -0
  545. package/dist/chunk-Z7CDQNH3.js +20 -0
  546. package/dist/chunk-ZH4G3FU5.js +187 -0
  547. package/dist/chunk-ZJB6SQPA.js +257 -0
  548. package/dist/chunk-ZL6E4HMY.js +42 -0
  549. package/dist/chunk-ZMLOC3DW.js +62 -0
  550. package/dist/chunk-ZORW64QH.js +101 -0
  551. package/dist/chunk-ZVVD2XGV.js +1369 -0
  552. package/dist/cli-utils-ER33ODC5.js +31 -0
  553. package/dist/cli-validation-6CHPTANV.js +146 -0
  554. package/dist/commit-utils-3STAY7C7.js +49 -0
  555. package/dist/compatibility-notice-IHNXR2JR.js +21 -0
  556. package/dist/compete-config-resolver-V3GDNJMM.js +125 -0
  557. package/dist/compete-results-XUM3PJHS.js +318 -0
  558. package/dist/competition-outcome-tracker-NWSMVUPG.js +62 -0
  559. package/dist/config-4HHE4OIK.js +238 -0
  560. package/dist/config-D6YAZASH.js +10 -0
  561. package/dist/config-MIPRDYYV.js +46 -0
  562. package/dist/config-audit-GA5DCUAI.js +371 -0
  563. package/dist/config-explain-4LMO556H.js +71 -0
  564. package/dist/config-loader-RGP634PC.js +51 -0
  565. package/dist/config-manager-J2UTO635.js +114 -0
  566. package/dist/config-merger-TVUJBZTS.js +14 -0
  567. package/dist/config-validator-H4ZVIE56.js +122 -0
  568. package/dist/cost-HSIV5U2Y.js +85 -0
  569. package/dist/data-migration-state-OAUL2WPQ.js +35 -0
  570. package/dist/db-migrator-NUOW5NKR.js +34 -0
  571. package/dist/default-paths-UILB62BN.js +49 -0
  572. package/dist/discovery-V6GYUJUC.js +53 -0
  573. package/dist/doctor-BBSMCDWE.js +271 -0
  574. package/dist/doctor-context-blocks-LPY75VZA.js +231 -0
  575. package/dist/doctor-instructions-import-JXHDDOE5.js +70 -0
  576. package/dist/doctor-purpose-6YJOXPBE.js +30 -0
  577. package/dist/domain-analyzer-S35ABUNA.js +48 -0
  578. package/dist/ensure-initialized-Q6PEU55O.js +78 -0
  579. package/dist/entry.js +922 -0
  580. package/dist/error-parser-core-MZFMFANN.js +70 -0
  581. package/dist/evaluation-context-GQBYDAEV.js +63 -0
  582. package/dist/evidence-plan-resolver-5FUAP3SA.js +111 -0
  583. package/dist/execution-data-writer-YCG5UH37.js +72 -0
  584. package/dist/execution-policy-applier-PWZM5LNA.js +63 -0
  585. package/dist/execution-preflight-DASJWWQF.js +223 -0
  586. package/dist/execution-roles-KNSNNB2D.js +112 -0
  587. package/dist/exit-code-error-QIY5DOKF.js +18 -0
  588. package/dist/external-temp-cleanup-CAW7LQ6R.js +360 -0
  589. package/dist/factory-YCYCB7AE.js +209 -0
  590. package/dist/file-utils-ZQYNBQBW.js +45 -0
  591. package/dist/flywheel-allowlist-revert-H22HA6JE.js +21 -0
  592. package/dist/flywheel-autoloop-executor-PDOASJEZ.js +316 -0
  593. package/dist/flywheel-autoloop-unverified-TOKYFCDC.js +36 -0
  594. package/dist/flywheel-competition-executor-YJUMMEJO.js +320 -0
  595. package/dist/flywheel-executor-JWU43KAY.js +437 -0
  596. package/dist/flywheel-git-isolation-FQ2TRWMB.js +56 -0
  597. package/dist/flywheel-manifest-HDPNMWWF.js +114 -0
  598. package/dist/flywheel-model-defaults-UHAKTZT3.js +110 -0
  599. package/dist/flywheel-preflight-III2C7TH.js +163 -0
  600. package/dist/flywheel-resume-2O45MS7Y.js +31 -0
  601. package/dist/flywheel-resume-execution-lease-P2BK257J.js +59 -0
  602. package/dist/flywheel-safety-AVAVFXIJ.js +19 -0
  603. package/dist/flywheel-scope-decision-ALJUUNGG.js +14 -0
  604. package/dist/get-telemetry-logger-MPDVO2JA.js +155 -0
  605. package/dist/git-message-style-KCXGMTDT.js +104 -0
  606. package/dist/guidance-profile-config-G3K5YQOO.js +113 -0
  607. package/dist/guidance-profile-renderer-TX4TNDFL.js +23 -0
  608. package/dist/identity-XLQJ4YJF.js +25 -0
  609. package/dist/index-query-6NUY4FKX.js +37 -0
  610. package/dist/index.js +85588 -0
  611. package/dist/indexer-DL54CM3K.js +44 -0
  612. package/dist/init-OUZ72344.js +245 -0
  613. package/dist/instructions-import-offer-NSYXSITC.js +363 -0
  614. package/dist/instructions-run-NBII7W36.js +114 -0
  615. package/dist/interrupted-work-E4TLKJLE.js +43 -0
  616. package/dist/invoke-provider-auth-NEWEIHCI.js +38 -0
  617. package/dist/judge-scoring.json +64 -0
  618. package/dist/lab-mode-YXQ2Y3NG.js +44 -0
  619. package/dist/lab-utils-5QAMDJR5.js +29 -0
  620. package/dist/linux-host-class-YDWQX65O.js +31 -0
  621. package/dist/llm-judge-executor-OJSNCTFJ.js +179 -0
  622. package/dist/local-ci-config-VZ4WWDT5.js +48 -0
  623. package/dist/local-executor-DCMDDRX2.js +280 -0
  624. package/dist/logger-5KNKS3O4.js +154 -0
  625. package/dist/matrix-prompt-builder-4ZBOGZSB.js +527 -0
  626. package/dist/matrix-result-parser-EZJM4YXP.js +14 -0
  627. package/dist/merge-batch-RTEEMVDB.js +313 -0
  628. package/dist/merge-batch-members-VIWGVRHP.js +24 -0
  629. package/dist/merge-queue-TIIUSOY6.js +126 -0
  630. package/dist/merge-queue-trust-DUNZ4J65.js +21 -0
  631. package/dist/metadata-UKSMWM6J.js +29 -0
  632. package/dist/model-catalog-readiness-R5KJBP5M.js +202 -0
  633. package/dist/model-invocations-db-XTUPPQ34.js +70 -0
  634. package/dist/model-resolver-JFZ2MHOJ.js +39 -0
  635. package/dist/model-resolver-SCQ57KAQ.js +217 -0
  636. package/dist/model-roles-D3OR4NAH.js +110 -0
  637. package/dist/monitor-F4SIU5G2.js +96 -0
  638. package/dist/nested-worktrees-2WUWQ75N.js +23 -0
  639. package/dist/next-S3IRLVER.js +96 -0
  640. package/dist/next-UKPFRXOO.js +148 -0
  641. package/dist/opportunistic-TL4S26VX.js +86 -0
  642. package/dist/optimization-config-resolver-NAEIYU6A.js +148 -0
  643. package/dist/package-HJR4QJT4.js +10 -0
  644. package/dist/parse-git-status-7PIYFPS2.js +21 -0
  645. package/dist/path-security-5WJSY56G.js +41 -0
  646. package/dist/paths-JUI7C4KU.js +45 -0
  647. package/dist/plan-backlog-list-fast-SSTQL5XP.js +89 -0
  648. package/dist/plan-backlog-show-fast-PFRAQ3JB.js +114 -0
  649. package/dist/plan-sprint-list-fast-HD2KBZSY.js +110 -0
  650. package/dist/plan-sprint-status-fast-YFYH7WQF.js +116 -0
  651. package/dist/plan-task-status-fast-JU5PNLUU.js +114 -0
  652. package/dist/plan-to-flywheel-PY5MSY2H.js +529 -0
  653. package/dist/preflight-PJHGTJNZ.js +12 -0
  654. package/dist/process-registry-B4ZUCN7T.js +28 -0
  655. package/dist/process-scanner-TU3QHWVB.js +23 -0
  656. package/dist/processes-6FHVGT72.js +28 -0
  657. package/dist/processes-json-fast-YWTMUWXB.js +72 -0
  658. package/dist/profile-HWTC56SG.js +209 -0
  659. package/dist/project-runtime-paths-2UQNG5Y4.js +41 -0
  660. package/dist/protected-branches-N36LDBFY.js +71 -0
  661. package/dist/provider-aware-resource-manager-YTFAHNGJ.js +40 -0
  662. package/dist/provider-matrix-2KO2V5OM.js +214 -0
  663. package/dist/provider-matrix-renderer-MEC3PER7.js +139 -0
  664. package/dist/provider-output-forwarding-2AHL7YMA.js +26 -0
  665. package/dist/provider-registry-WCZ65QHC.js +136 -0
  666. package/dist/provider-temp-cleanup-IUNPJCZF.js +14 -0
  667. package/dist/prune-engine-EOQVWEP6.js +448 -0
  668. package/dist/publication-turn-S42RZTQF.js +44 -0
  669. package/dist/quality-gate-JQMVCKOO.js +72 -0
  670. package/dist/quickstart-3O6FRCFB.js +105 -0
  671. package/dist/readiness-GW6ABRHB.js +139 -0
  672. package/dist/readiness-KFZCXDTT.js +215 -0
  673. package/dist/registry-7XG376SY.js +217 -0
  674. package/dist/repair-helpers-TTV5FEF4.js +117 -0
  675. package/dist/repo-root-YG6MQZDW.js +28 -0
  676. package/dist/resolution-engine-FFEK7HQ2.js +187 -0
  677. package/dist/resolve-provider-cli-ZEXVZKET.js +44 -0
  678. package/dist/restore-telemetry-db-E7BR5PO7.js +459 -0
  679. package/dist/routing-events-AW6SRZ6G.js +13 -0
  680. package/dist/routing-history-store-FMDDQL6W.js +39 -0
  681. package/dist/routing-planner-C6OHO3EY.js +221 -0
  682. package/dist/runner-KHDNQ5KU.js +1194 -0
  683. package/dist/runner-PIS2BW7Y.js +1801 -0
  684. package/dist/safety-E3JJVSFL.js +67 -0
  685. package/dist/safety-stanza-HE6GXP4G.js +49 -0
  686. package/dist/sandbox-7LBZC5PE.js +72 -0
  687. package/dist/sandbox-ASWCDYZL.js +80 -0
  688. package/dist/schema-extensions.sql +234 -0
  689. package/dist/security-JI22TBEB.js +17 -0
  690. package/dist/setup-bb-plugin-FQXLA76Y.js +531 -0
  691. package/dist/setup-claude-code-NF4ZSHVE.js +197 -0
  692. package/dist/setup-temp-cleanup-2APZ4HMA.js +29 -0
  693. package/dist/shared-utils-34HJZ6JX.js +40 -0
  694. package/dist/simple-artifact-goal-MQLDDMMX.js +29 -0
  695. package/dist/sprint-N7JFTEGL.js +403 -0
  696. package/dist/sprint-bridge-KJXIBNRJ.js +117 -0
  697. package/dist/sprint-completion-dependents-34SR7JVL.js +43 -0
  698. package/dist/sprint-execution-service-A6JPUBWY.js +376 -0
  699. package/dist/sprint-manager-MU2ZUWN2.js +140 -0
  700. package/dist/sqlite-timeout-config-U2CT4LKU.js +13 -0
  701. package/dist/sqlite-wrapper-FSGJ2QEW.js +19 -0
  702. package/dist/stale-cleanup-orchestrator-4X6324VF.js +71 -0
  703. package/dist/storage-access-I3V5LER7.js +31 -0
  704. package/dist/store-XVG64ZR2.js +25 -0
  705. package/dist/task-classifier-MN2DYE5R.js +558 -0
  706. package/dist/task-list-fast-7AT6LTTA.js +112 -0
  707. package/dist/task-manager-LHPBBRRE.js +136 -0
  708. package/dist/task-report-OLPAWBTK.js +64 -0
  709. package/dist/task-type-detector-6RG3YNZF.js +27 -0
  710. package/dist/task-type-resolver-EQHOUIHT.js +64 -0
  711. package/dist/telemetry-5VYSK772.js +212 -0
  712. package/dist/telemetry-health-tracker-4GFW2EMP.js +12 -0
  713. package/dist/telemetry-path-resolver-H3NFHHQY.js +34 -0
  714. package/dist/telemetry-reliability-URJDTNPZ.js +76 -0
  715. package/dist/transports-NREZQTJK.js +106 -0
  716. package/dist/unified-cost-tracker-5MTBJ2CL.js +59 -0
  717. package/dist/unified-state-cleanup-GGAXLHXF.js +292 -0
  718. package/dist/universal-cost-calculator-JTFEJVWK.js +70 -0
  719. package/dist/user-agents-QLIGPLP2.js +30 -0
  720. package/dist/variant-execution-I4ZZUAWY.js +319 -0
  721. package/dist/variant-opt-parser-JHCXKY2K.js +251 -0
  722. package/dist/variant-request-input-PL37N3AN.js +11 -0
  723. package/dist/variant-state-cleanup-KHMXRBZN.js +287 -0
  724. package/dist/variant-worker-COB5YTJX.js +4517 -0
  725. package/dist/variant-worker.js +26 -0
  726. package/dist/variants-XGDSXYG3.js +267 -0
  727. package/dist/verification-command-YSPU4VBH.js +66 -0
  728. package/dist/verify-command-timeout-DQUYH33Z.js +11 -0
  729. package/dist/verify-commands-LOHMOFKC.js +65 -0
  730. package/dist/warning-JSKSFKBT.js +13 -0
  731. package/dist/work-edge-K65NHVWY.js +50 -0
  732. package/dist/work-item-writer-KY5ZWZWW.js +30 -0
  733. package/dist/worker-JNXXEIT6.js +1504 -0
  734. package/dist/worker.js +21 -0
  735. package/dist/workspace-tree-identity-JO5PSKTW.js +52 -0
  736. package/dist/worktree-environment-WTVABAQW.js +64 -0
  737. package/dist/worktree-metrics-VZRQI26T.js +66 -0
  738. package/dist/writeback-TQFQBJNU.js +50 -0
  739. package/docs/CLI_REFERENCE.md +8287 -0
  740. package/docs/PROVIDER_SETUP.md +1737 -0
  741. package/docs/README.md +96 -0
  742. package/docs/TROUBLESHOOTING.md +2209 -0
  743. package/docs/getting-started/QUICK_START.md +260 -0
  744. package/docs/getting-started/README.md +198 -0
  745. package/docs/getting-started/SETUP.md +25 -0
  746. package/docs/reference/AGENT_CONTEXT.md +84 -0
  747. package/docs/reference/DELIVERY_ONBOARDING.md +198 -0
  748. package/docs/reference/PROVIDER_RELEASE_TIERS.md +34 -0
  749. package/docs/reference/SECURITY.md +291 -0
  750. package/docs/reference/TELEMETRY_PRIVACY.md +259 -0
  751. package/integrations/bb-plugin-build/README.md +391 -0
  752. package/integrations/bb-plugin-build/app.css +431 -0
  753. package/integrations/bb-plugin-build/app.tsx +6210 -0
  754. package/integrations/bb-plugin-build/package.json +45 -0
  755. package/integrations/bb-plugin-build/server.ts +488 -0
  756. package/integrations/bb-plugin-build/src/adapter.ts +3672 -0
  757. package/integrations/bb-plugin-build/src/backlog-authoring-model.ts +150 -0
  758. package/integrations/bb-plugin-build/src/backlog-authoring-schema.ts +458 -0
  759. package/integrations/bb-plugin-build/src/backlog-authoring-service.ts +467 -0
  760. package/integrations/bb-plugin-build/src/backlog-authoring-view.ts +1025 -0
  761. package/integrations/bb-plugin-build/src/command-evidence-schema.ts +13 -0
  762. package/integrations/bb-plugin-build/src/competition-defaults-schema.ts +122 -0
  763. package/integrations/bb-plugin-build/src/competition-defaults-service.ts +105 -0
  764. package/integrations/bb-plugin-build/src/competition-defaults-view.ts +138 -0
  765. package/integrations/bb-plugin-build/src/contract.ts +718 -0
  766. package/integrations/bb-plugin-build/src/execution-activity-view.ts +98 -0
  767. package/integrations/bb-plugin-build/src/finalize-model.ts +205 -0
  768. package/integrations/bb-plugin-build/src/finalize-schema.ts +150 -0
  769. package/integrations/bb-plugin-build/src/finalize-service.ts +330 -0
  770. package/integrations/bb-plugin-build/src/finalize-view.ts +159 -0
  771. package/integrations/bb-plugin-build/src/judge-operations-readback.ts +303 -0
  772. package/integrations/bb-plugin-build/src/judge-operations-schema.ts +33 -0
  773. package/integrations/bb-plugin-build/src/judge-operations-view.ts +459 -0
  774. package/integrations/bb-plugin-build/src/model.ts +1318 -0
  775. package/integrations/bb-plugin-build/src/monitor-service.ts +233 -0
  776. package/integrations/bb-plugin-build/src/panel-read-ux.ts +97 -0
  777. package/integrations/bb-plugin-build/src/patch-preview-schema.ts +166 -0
  778. package/integrations/bb-plugin-build/src/patch-preview-service.ts +480 -0
  779. package/integrations/bb-plugin-build/src/patch-preview-view.ts +109 -0
  780. package/integrations/bb-plugin-build/src/planning-readback.ts +228 -0
  781. package/integrations/bb-plugin-build/src/planning-service.ts +647 -0
  782. package/integrations/bb-plugin-build/src/planning-sync-evidence.ts +37 -0
  783. package/integrations/bb-plugin-build/src/planning-workspace-readback.ts +33 -0
  784. package/integrations/bb-plugin-build/src/planning-workspace-schema.ts +131 -0
  785. package/integrations/bb-plugin-build/src/planning-workspace.ts +333 -0
  786. package/integrations/bb-plugin-build/src/poll-handoff.ts +136 -0
  787. package/integrations/bb-plugin-build/src/project-target-server.ts +21 -0
  788. package/integrations/bb-plugin-build/src/project-target.ts +45 -0
  789. package/integrations/bb-plugin-build/src/reference-index.ts +218 -0
  790. package/integrations/bb-plugin-build/src/repository-identity.ts +17 -0
  791. package/integrations/bb-plugin-build/src/repository-schema.ts +30 -0
  792. package/integrations/bb-plugin-build/src/result-explorer-view.ts +597 -0
  793. package/integrations/bb-plugin-build/src/result-readback-model.ts +163 -0
  794. package/integrations/bb-plugin-build/src/result-readback-schema.ts +319 -0
  795. package/integrations/bb-plugin-build/src/result-readback-service.ts +333 -0
  796. package/integrations/bb-plugin-build/src/run-page-view.ts +332 -0
  797. package/integrations/bb-plugin-build/src/setup-config-schema.ts +293 -0
  798. package/integrations/bb-plugin-build/src/setup-config-service.ts +620 -0
  799. package/integrations/bb-plugin-build/src/setup-config-view.ts +388 -0
  800. package/integrations/bb-plugin-build/src/sprint-close-model.ts +150 -0
  801. package/integrations/bb-plugin-build/src/sprint-close-schema.ts +128 -0
  802. package/integrations/bb-plugin-build/src/sprint-close-service.ts +293 -0
  803. package/integrations/bb-plugin-build/src/sprint-close-view.ts +116 -0
  804. package/integrations/bb-plugin-build/src/sprint-composition-model.ts +709 -0
  805. package/integrations/bb-plugin-build/src/sprint-composition-readback.ts +231 -0
  806. package/integrations/bb-plugin-build/src/sprint-composition-schema.ts +597 -0
  807. package/integrations/bb-plugin-build/src/sprint-composition-service.ts +773 -0
  808. package/integrations/bb-plugin-build/src/sprint-composition-view.ts +1221 -0
  809. package/integrations/bb-plugin-build/src/sprint-execution-schema.ts +188 -0
  810. package/integrations/bb-plugin-build/src/sprint-execution-service.ts +289 -0
  811. package/integrations/bb-plugin-build/src/sprint-execution-view.ts +54 -0
  812. package/integrations/bb-plugin-build/src/task-authoring-model.ts +563 -0
  813. package/integrations/bb-plugin-build/src/task-authoring-schema.ts +629 -0
  814. package/integrations/bb-plugin-build/src/task-authoring-service.ts +842 -0
  815. package/integrations/bb-plugin-build/src/task-authoring-view.ts +1227 -0
  816. package/integrations/bb-plugin-build/src/task-catalog-schema.ts +46 -0
  817. package/integrations/bb-plugin-build/src/task-catalog-service.ts +44 -0
  818. package/integrations/bb-plugin-build/src/task-detail-readback.ts +56 -0
  819. package/integrations/bb-plugin-build/src/task-detail-schema.ts +171 -0
  820. package/integrations/bb-plugin-build/src/task-navigation.ts +446 -0
  821. package/integrations/bb-plugin-build/src/workbench-route.ts +74 -0
  822. package/package.json +306 -4
  823. package/schemas/README.md +80 -0
  824. package/schemas/build.config.schema.json +2110 -0
  825. package/schemas/config-v1.schema.json +136 -0
  826. package/schemas/execution-config.schema.json +47 -0
  827. package/schemas/judge-scoring.schema.json +257 -0
  828. package/schemas/provider-config.schema.json +179 -0
  829. package/schemas/telemetry-config.schema.json +79 -0
  830. package/schemas/user-preferences.schema.json +141 -0
  831. package/scripts/assert-node-runtime.mjs +146 -0
  832. package/scripts/preflight-native.mjs +49 -0
  833. package/scripts/setup-git-hooks.mjs +39 -0
  834. package/scripts/sync.sh +2871 -0
  835. package/scripts/write-node-launcher.sh +138 -0
  836. package/src/resources/gemini/slash-packs/default/plan.toml +15 -0
  837. package/src/resources/gemini/slash-packs/default/summary.toml +16 -0
  838. package/src/resources/gemini/slash-packs/default/tests.toml +16 -0
  839. package/templates/.build-project/README.md +41 -0
  840. package/templates/.build-project/agents/README.md +50 -0
  841. package/templates/.build-project/agents/architect.md +10 -0
  842. package/templates/.build-project/agents/code-reviewer.md +10 -0
  843. package/templates/.build-project/agents/debugger.md +10 -0
  844. package/templates/.build-project/agents/documenter.md +10 -0
  845. package/templates/.build-project/agents/test-automator.md +10 -0
  846. package/templates/.build-project/config/build.config.jsonc +64 -0
  847. package/templates/.build-project/config/project-context.template.json +6 -0
  848. package/templates/.build-project/config/task-type-aliases.presets/kanban.yaml +14 -0
  849. package/templates/.build-project/config/task-type-aliases.presets/scrum.yaml +17 -0
  850. package/templates/.build-project/config/task-type-aliases.presets/xp.yaml +12 -0
  851. package/templates/.build-project/config/task-type-aliases.yaml +29 -0
  852. package/templates/.build-project/gitignore.template +70 -0
  853. package/templates/.build-project/task-types/analysis.yaml +38 -0
  854. package/templates/.build-project/task-types/architecture.yaml +35 -0
  855. package/templates/.build-project/task-types/doc.yaml +34 -0
  856. package/templates/.build-project/task-types/feature.yaml +22 -0
  857. package/templates/.build-project/task-types/general.yaml +4 -0
  858. package/templates/.build-project/task-types/security.yaml +38 -0
  859. package/templates/AGENTS.template.md +85 -0
  860. package/templates/CLAUDE.template.md +1 -0
  861. package/templates/GEMINI.template.md +1 -0
  862. package/templates/builtin-workflows/code-review.yaml +73 -0
  863. package/templates/builtin-workflows/skills/code-review/SKILL.md +61 -0
  864. package/templates/builtin-workflows/skills/execution-contract-analysis/SKILL.md +24 -0
  865. package/templates/builtin-workflows/skills/execution-contract-code/SKILL.md +19 -0
  866. package/templates/builtin-workflows/skills/execution-contract-structured/SKILL.md +17 -0
  867. package/templates/ci/incident-intake.mjs +787 -0
  868. package/templates/ci/incidents.yml.template +103 -0
  869. package/templates/ci/node.yml.template +17 -0
  870. package/templates/ci/python.yml.template +17 -0
  871. package/templates/guard-kit/GUARD_SETUP.md.template +258 -0
  872. package/templates/guard-kit/build-guard.yml.template +189 -0
  873. package/templates/guard-kit/check.mjs.template +932 -0
  874. package/templates/guard-kit/config.json.template +7 -0
  875. package/templates/guard-kit/policy.json.template +1 -0
  876. package/templates/profiles/README.md +57 -0
  877. package/templates/profiles/frontier-claude.json +23 -0
  878. package/templates/profiles/frontier-codex.json +23 -0
@@ -0,0 +1,1892 @@
1
+ import {
2
+ findArchivedTaskPath,
3
+ locateTaskFile,
4
+ validateStateTransition
5
+ } from "./chunk-7LHJDJB3.js";
6
+ import {
7
+ normalizeTaskStatus
8
+ } from "./chunk-NAINGKHF.js";
9
+ import {
10
+ getArchivedFilePath
11
+ } from "./chunk-US3RT6CY.js";
12
+ import {
13
+ classifyTaskDependency
14
+ } from "./chunk-NXH3RX7O.js";
15
+ import {
16
+ assertCompletionContractsMet,
17
+ normalizeCompletionContracts,
18
+ recordUnverifiedCompletion
19
+ } from "./chunk-MCBNWZNO.js";
20
+ import {
21
+ getPlanningRoot,
22
+ withIndexRegeneration,
23
+ withPlanningLock
24
+ } from "./chunk-CSXLLEGB.js";
25
+ import {
26
+ bucketArchiveRootForProjectRoot
27
+ } from "./chunk-VAG6GUBR.js";
28
+ import {
29
+ assertBucketWriteAvailable
30
+ } from "./chunk-AJBTKGJZ.js";
31
+ import {
32
+ getBucketArchivePathByKind,
33
+ getBucketByName,
34
+ getBucketPathByKind
35
+ } from "./chunk-V3KLVK7B.js";
36
+ import {
37
+ signalCoordinator
38
+ } from "./chunk-GC4CRMTS.js";
39
+ import {
40
+ evaluateStaleReclaim
41
+ } from "./chunk-P7CQGPLS.js";
42
+ import {
43
+ assertSafePathComponent
44
+ } from "./chunk-S2VQCZO4.js";
45
+ import {
46
+ generateId
47
+ } from "./chunk-4DJL2VXA.js";
48
+ import {
49
+ assertSafePlanningFileId,
50
+ ensureDirectoryExists,
51
+ listMarkdownFiles,
52
+ listMarkdownFilesRecursive,
53
+ readMarkdownFile,
54
+ resolvePlanningItemPath,
55
+ writeMarkdownFile
56
+ } from "./chunk-352PCJLK.js";
57
+ import {
58
+ lockOwnerIsAlive,
59
+ processIsAlive,
60
+ readProcessIdentity
61
+ } from "./chunk-MT2WAIR3.js";
62
+ import {
63
+ BUILD_SPRINT_LOCK_RETRY_TIMEOUT_MS,
64
+ BUILD_SPRINT_LOCK_STALE_AFTER_MS,
65
+ emitCustomWarning,
66
+ readEnv
67
+ } from "./chunk-7VRJHTGZ.js";
68
+
69
+ // src/planning/sprint-manager.ts
70
+ import * as fs2 from "fs/promises";
71
+ import * as path2 from "path";
72
+
73
+ // src/planning/sprint-lock.ts
74
+ import { randomUUID } from "crypto";
75
+ import * as fs from "fs/promises";
76
+ import * as path from "path";
77
+ var heldSprintLocks = /* @__PURE__ */ new Map();
78
+ var DEFAULT_LOCK_RETRY_TIMEOUT_MS = 3e4;
79
+ var DEFAULT_LOCK_STALE_AFTER_MS = 30 * 6e4;
80
+ var SPRINT_LOCK_HANDOFF_ENV = "BUILD_SPRINT_LOCK_HANDOFF_TOKEN";
81
+ function shouldReclaimSprintLock(params) {
82
+ if (params.ownerToken === null) {
83
+ return false;
84
+ }
85
+ return evaluateStaleReclaim(
86
+ {
87
+ ageMs: params.ageMs,
88
+ holder: params.existingPid === null ? null : { sameHost: true, pidAlive: params.ownerAlive }
89
+ },
90
+ {
91
+ staleMs: getSprintLockStaleAfterMs(),
92
+ corruptPayload: "reclaim",
93
+ foreignHost: { kind: "never" },
94
+ ageBoundary: "gte",
95
+ sameHostDeadPid: "immediate"
96
+ }
97
+ ) === "reclaim";
98
+ }
99
+ function emitSprintLockWarning(message, metadata) {
100
+ emitCustomWarning(
101
+ "WARN" /* WARN */,
102
+ "workspace_edits" /* WORKSPACE_EDITS */,
103
+ message,
104
+ {
105
+ taskId: "sprint-lock",
106
+ subsystem: "planning/sprint-lock",
107
+ executionPhase: "execution"
108
+ },
109
+ { metadata, skipConsole: true }
110
+ );
111
+ }
112
+ function getSprintLockRetryTimeoutMs() {
113
+ return readEnv(BUILD_SPRINT_LOCK_RETRY_TIMEOUT_MS).value ?? DEFAULT_LOCK_RETRY_TIMEOUT_MS;
114
+ }
115
+ function getSprintLockStaleAfterMs() {
116
+ return readEnv(BUILD_SPRINT_LOCK_STALE_AFTER_MS).value ?? DEFAULT_LOCK_STALE_AFTER_MS;
117
+ }
118
+ function getSprintLockPath(sprintId) {
119
+ const safeSprintId = assertSafePathComponent(sprintId, "sprintId");
120
+ return path.join(getPlanningRoot(), ".build-project", `sprint-${safeSprintId}.lock`);
121
+ }
122
+ function getSprintActivationLockPath() {
123
+ return path.join(getPlanningRoot(), ".build-project", "sprint-activation.lock");
124
+ }
125
+ async function readSprintLockOwnerToken(lockPath) {
126
+ try {
127
+ const content = await fs.readFile(lockPath, "utf-8");
128
+ return content.trim().split("\n")[0] ?? "";
129
+ } catch {
130
+ return null;
131
+ }
132
+ }
133
+ async function readSprintLockSnapshot(lockPath) {
134
+ const snapshotPath = `${lockPath}.snapshot.${process.pid}.${Date.now().toString(36)}.${randomUUID()}`;
135
+ try {
136
+ await fs.link(lockPath, snapshotPath);
137
+ } catch (error) {
138
+ if (error.code === "ENOENT") {
139
+ return null;
140
+ }
141
+ throw error;
142
+ }
143
+ try {
144
+ const [content, stat2] = await Promise.all([
145
+ fs.readFile(snapshotPath, "utf-8"),
146
+ fs.stat(snapshotPath)
147
+ ]);
148
+ const lines = content.trim().split("\n");
149
+ return {
150
+ ownerToken: lines[0] ?? "",
151
+ ownerIdentity: lines[2]?.trim() || void 0,
152
+ dev: stat2.dev,
153
+ ino: stat2.ino,
154
+ mtimeMs: stat2.mtimeMs
155
+ };
156
+ } finally {
157
+ await fs.unlink(snapshotPath).catch(() => void 0);
158
+ }
159
+ }
160
+ async function unlinkSprintLockIfOwnerStillMatches(lockPath, expectedOwnerToken, expectedIdentity) {
161
+ const reclaimPath = `${lockPath}.reclaim.${process.pid}.${Date.now().toString(36)}.${randomUUID()}`;
162
+ try {
163
+ await fs.link(lockPath, reclaimPath);
164
+ } catch (error) {
165
+ if (error.code === "ENOENT") {
166
+ return false;
167
+ }
168
+ throw error;
169
+ }
170
+ try {
171
+ const [content, reclaimStat] = await Promise.all([
172
+ fs.readFile(reclaimPath, "utf-8"),
173
+ fs.stat(reclaimPath)
174
+ ]);
175
+ const currentOwnerToken = content.trim().split("\n")[0] ?? "";
176
+ if (currentOwnerToken !== expectedOwnerToken) {
177
+ return false;
178
+ }
179
+ if (expectedIdentity && (reclaimStat.dev !== expectedIdentity.dev || reclaimStat.ino !== expectedIdentity.ino)) {
180
+ return false;
181
+ }
182
+ const currentStat = await fs.stat(lockPath).catch(() => null);
183
+ if (!currentStat || currentStat.dev !== reclaimStat.dev || currentStat.ino !== reclaimStat.ino) {
184
+ return false;
185
+ }
186
+ await fs.unlink(lockPath);
187
+ return true;
188
+ } finally {
189
+ await fs.unlink(reclaimPath).catch(() => void 0);
190
+ }
191
+ }
192
+ async function unlinkPartialSprintLock(lockPath) {
193
+ await fs.unlink(lockPath).catch((unlinkError) => {
194
+ if (unlinkError.code !== "ENOENT") throw unlinkError;
195
+ });
196
+ }
197
+ async function acquireNamedLock(lockKey, lockPath, busyLabel, retryTimeoutMs = getSprintLockRetryTimeoutMs()) {
198
+ const heldLock = heldSprintLocks.get(lockKey);
199
+ if (heldLock) {
200
+ heldLock.count += 1;
201
+ return {
202
+ ownerToken: heldLock.ownerToken,
203
+ release: async () => {
204
+ heldLock.count -= 1;
205
+ if (heldLock.count <= 0) {
206
+ heldSprintLocks.delete(lockKey);
207
+ await heldLock.releaseFileLock();
208
+ }
209
+ }
210
+ };
211
+ }
212
+ await fs.mkdir(path.dirname(lockPath), { recursive: true });
213
+ const retryDeadlineMs = Date.now() + retryTimeoutMs;
214
+ let judgedOwner;
215
+ const createHeldLease = (ownerToken, identity) => {
216
+ const cleanupName = `planning-sprint-lock:${lockKey}:${ownerToken}`;
217
+ const releaseFileLock = async () => {
218
+ try {
219
+ await unlinkSprintLockIfOwnerStillMatches(lockPath, ownerToken, identity);
220
+ } catch {
221
+ } finally {
222
+ signalCoordinator.unregister(cleanupName);
223
+ }
224
+ };
225
+ const held = {
226
+ count: 1,
227
+ ownerToken,
228
+ releaseFileLock
229
+ };
230
+ heldSprintLocks.set(lockKey, held);
231
+ const release = async () => {
232
+ held.count -= 1;
233
+ if (held.count <= 0) {
234
+ heldSprintLocks.delete(lockKey);
235
+ await held.releaseFileLock();
236
+ }
237
+ };
238
+ signalCoordinator.register(cleanupName, release, {
239
+ priority: "critical",
240
+ phase: "artifact-cleanup"
241
+ });
242
+ return { ownerToken, release };
243
+ };
244
+ while (true) {
245
+ try {
246
+ const handle = await fs.open(lockPath, "wx");
247
+ const ownerToken = `${process.pid}:${randomUUID()}`;
248
+ const ownerIdentity = readProcessIdentity(process.pid) ?? "";
249
+ try {
250
+ await handle.writeFile(
251
+ `${ownerToken}
252
+ ${(/* @__PURE__ */ new Date()).toISOString()}
253
+ ${ownerIdentity}
254
+ `,
255
+ "utf-8"
256
+ );
257
+ await handle.close();
258
+ } catch (writeError) {
259
+ await handle.close().catch(() => {
260
+ });
261
+ await unlinkPartialSprintLock(lockPath);
262
+ throw writeError;
263
+ }
264
+ const stat2 = await fs.stat(lockPath);
265
+ return createHeldLease(ownerToken, { dev: stat2.dev, ino: stat2.ino });
266
+ } catch (err) {
267
+ if (err.code !== "EEXIST") throw err;
268
+ const snapshot = await readSprintLockSnapshot(lockPath);
269
+ const firstLine = snapshot?.ownerToken ?? null;
270
+ const parsedPid = firstLine === null ? Number.NaN : Number.parseInt(firstLine.split(":")[0] ?? "", 10);
271
+ const existingPid = Number.isFinite(parsedPid) && parsedPid > 0 ? parsedPid : null;
272
+ const handoffToken = process.env[SPRINT_LOCK_HANDOFF_ENV];
273
+ if (handoffToken && firstLine === handoffToken) {
274
+ await unlinkSprintLockIfOwnerStillMatches(lockPath, handoffToken, snapshot ?? void 0);
275
+ continue;
276
+ }
277
+ let ownerAlive = false;
278
+ if (existingPid !== null && firstLine !== null) {
279
+ if (judgedOwner?.token !== firstLine) {
280
+ judgedOwner = {
281
+ token: firstLine,
282
+ alive: lockOwnerIsAlive(existingPid, snapshot?.ownerIdentity)
283
+ };
284
+ }
285
+ ownerAlive = judgedOwner.alive && processIsAlive(existingPid);
286
+ }
287
+ try {
288
+ const ageMs = Date.now() - (snapshot?.mtimeMs ?? Date.now());
289
+ if (firstLine !== null && shouldReclaimSprintLock({
290
+ ageMs,
291
+ ownerToken: firstLine,
292
+ existingPid,
293
+ ownerAlive
294
+ })) {
295
+ if (existingPid === null) {
296
+ emitSprintLockWarning(
297
+ `[sprint-lock] Reclaiming stale lock ${path.basename(lockPath)} (unknown owner, lock age ${Math.round(ageMs / 1e3)}s exceeds threshold).`,
298
+ {
299
+ lockKey,
300
+ lockPath,
301
+ ageMs,
302
+ operation: "reclaim-stale-lock"
303
+ }
304
+ );
305
+ }
306
+ await unlinkSprintLockIfOwnerStillMatches(lockPath, firstLine, snapshot ?? void 0);
307
+ continue;
308
+ }
309
+ } catch {
310
+ }
311
+ if (Date.now() < retryDeadlineMs) {
312
+ await new Promise((resolve) => setTimeout(resolve, 10));
313
+ continue;
314
+ }
315
+ throw new Error(`${busyLabel} is busy (PID ${existingPid ?? "unknown"})`);
316
+ }
317
+ }
318
+ }
319
+ async function acquireSprintLock(sprintId) {
320
+ const lease = await acquireSprintLockLease(sprintId);
321
+ return lease.release;
322
+ }
323
+ async function acquireSprintLockLease(sprintId) {
324
+ return acquireNamedLock(`sprint:${sprintId}`, getSprintLockPath(sprintId), `Sprint ${sprintId}`);
325
+ }
326
+ async function withSprintLock(sprintId, fn) {
327
+ return withPlanningLock(getPlanningRoot(), async () => {
328
+ const lease = await acquireNamedLock(
329
+ `sprint:${sprintId}`,
330
+ getSprintLockPath(sprintId),
331
+ `Sprint ${sprintId}`,
332
+ 0
333
+ );
334
+ try {
335
+ return await fn();
336
+ } finally {
337
+ await lease.release();
338
+ }
339
+ });
340
+ }
341
+ async function withSprintActivationLock(fn) {
342
+ return withPlanningLock(getPlanningRoot(), async () => {
343
+ const lease = await acquireNamedLock(
344
+ "activation",
345
+ getSprintActivationLockPath(),
346
+ "Sprint activation",
347
+ 0
348
+ );
349
+ try {
350
+ return await fn();
351
+ } finally {
352
+ await lease.release();
353
+ }
354
+ });
355
+ }
356
+ function getSprintLockHandoffEnv(ownerToken) {
357
+ return { [SPRINT_LOCK_HANDOFF_ENV]: ownerToken };
358
+ }
359
+ async function getSprintLockOwnerToken(sprintId) {
360
+ return readSprintLockOwnerToken(getSprintLockPath(sprintId));
361
+ }
362
+ async function refreshSprintLock(sprintId) {
363
+ const lockKey = `sprint:${sprintId}`;
364
+ const heldLock = heldSprintLocks.get(lockKey);
365
+ if (!heldLock) return false;
366
+ const lockPath = getSprintLockPath(sprintId);
367
+ try {
368
+ const currentOwnerToken = await readSprintLockOwnerToken(lockPath);
369
+ if (currentOwnerToken !== heldLock.ownerToken) return false;
370
+ const now = /* @__PURE__ */ new Date();
371
+ await fs.utimes(lockPath, now, now);
372
+ return true;
373
+ } catch {
374
+ return false;
375
+ }
376
+ }
377
+ async function unlockSprintLock(sprintId, options = {}) {
378
+ const lockPath = getSprintLockPath(sprintId);
379
+ const snapshot = await readSprintLockSnapshot(lockPath);
380
+ let ownerToken = "";
381
+ if (!snapshot) {
382
+ return { success: true, message: `Sprint ${sprintId} is not locked` };
383
+ }
384
+ ownerToken = snapshot.ownerToken;
385
+ const ownerPid = Number.parseInt(ownerToken.split(":")[0] ?? "0", 10);
386
+ const ownerAlive = lockOwnerIsAlive(ownerPid, snapshot.ownerIdentity);
387
+ if (ownerAlive && !options.force) {
388
+ return {
389
+ success: false,
390
+ message: `Sprint ${sprintId} is locked by live PID ${ownerPid}; rerun with --force only after confirming the run is hung`
391
+ };
392
+ }
393
+ await unlinkSprintLockIfOwnerStillMatches(lockPath, ownerToken, {
394
+ dev: snapshot.dev,
395
+ ino: snapshot.ino
396
+ });
397
+ return { success: true, message: `Unlocked sprint ${sprintId}` };
398
+ }
399
+
400
+ // src/planning/sprint-manager.ts
401
+ function isGenuinelyAbsentTaskError(error) {
402
+ if (error && typeof error === "object" && "code" in error) {
403
+ const code = error.code;
404
+ if (code === "ENOENT") return true;
405
+ }
406
+ const message = error instanceof Error ? error.message : String(error);
407
+ return message.includes("Task not found");
408
+ }
409
+ var DEFAULT_SPRINT_CAPACITY_HOURS = 40;
410
+ function parseTaskNumber(value, fallback) {
411
+ if (typeof value === "number" && Number.isFinite(value)) return value;
412
+ if (typeof value === "string") {
413
+ const parsed = Number.parseFloat(value);
414
+ if (Number.isFinite(parsed)) return parsed;
415
+ }
416
+ return fallback;
417
+ }
418
+ function coerceSprintTaskFrontMatter(frontMatter) {
419
+ const id = typeof frontMatter.id === "string" ? frontMatter.id : "";
420
+ if (!id) {
421
+ throw new Error('Invalid task frontmatter: missing required field "id"');
422
+ }
423
+ const originalSprintId = typeof frontMatter.originalSprintId === "string" && frontMatter.originalSprintId ? frontMatter.originalSprintId : void 0;
424
+ const sprintId = typeof frontMatter.sprintId === "string" && frontMatter.sprintId || typeof frontMatter.sprint_id === "string" && frontMatter.sprint_id || originalSprintId || "";
425
+ if (!sprintId) {
426
+ throw new Error(`Invalid task frontmatter for '${id}': missing required field "sprintId"`);
427
+ }
428
+ const statusRaw = typeof frontMatter.status === "string" ? frontMatter.status : "todo";
429
+ const priorityRaw = typeof frontMatter.priority === "string" ? frontMatter.priority : void 0;
430
+ const priority = priorityRaw === "P0" || priorityRaw === "P1" || priorityRaw === "P2" || priorityRaw === "P3" ? priorityRaw : void 0;
431
+ return {
432
+ id,
433
+ title: typeof frontMatter.title === "string" && frontMatter.title ? frontMatter.title : id,
434
+ priority,
435
+ estimatedHours: parseTaskNumber(frontMatter.estimatedHours, 0),
436
+ ...typeof frontMatter.expectedRuntimeMinutes === "number" && Number.isFinite(frontMatter.expectedRuntimeMinutes) && frontMatter.expectedRuntimeMinutes > 0 ? { expectedRuntimeMinutes: frontMatter.expectedRuntimeMinutes } : {},
437
+ status: normalizeTaskStatus(statusRaw),
438
+ sprintId,
439
+ originalSprintId,
440
+ backlogItemId: typeof frontMatter.backlogItemId === "string" ? frontMatter.backlogItemId : void 0,
441
+ planArtifactPath: typeof frontMatter.planArtifactPath === "string" ? frontMatter.planArtifactPath : void 0,
442
+ resultArtifactPath: typeof frontMatter.resultArtifactPath === "string" ? frontMatter.resultArtifactPath : void 0,
443
+ planStageId: typeof frontMatter.planStageId === "string" ? frontMatter.planStageId : void 0,
444
+ dependencies: Array.isArray(frontMatter.dependencies) ? frontMatter.dependencies.filter((value) => typeof value === "string") : [],
445
+ blockedReason: typeof frontMatter.blockedReason === "string" ? frontMatter.blockedReason : void 0,
446
+ lastTransitionReason: typeof frontMatter.lastTransitionReason === "string" ? frontMatter.lastTransitionReason.trim() || void 0 : void 0,
447
+ version: parseTaskNumber(frontMatter.version, 0),
448
+ completionContract: normalizeCompletionContracts(frontMatter.completionContract)
449
+ };
450
+ }
451
+ async function loadTaskLookupFromFile(filePath, isArchived) {
452
+ const { frontMatter } = await readMarkdownFile(filePath);
453
+ return {
454
+ yaml: coerceSprintTaskFrontMatter(frontMatter),
455
+ filePath,
456
+ isArchived
457
+ };
458
+ }
459
+ async function getTask(taskId, options = {}) {
460
+ const { filePath, isArchived } = await locateTaskFile(taskId, options);
461
+ return loadTaskLookupFromFile(filePath, isArchived);
462
+ }
463
+ async function archiveTaskForSprintClose(taskId, options) {
464
+ const planningRoot = getPlanningRoot();
465
+ const bucket = getBucketByName("task", planningRoot);
466
+ if (!bucket) {
467
+ throw new Error("Bucket not configured: task");
468
+ }
469
+ const lookup = await getTask(taskId, { includeArchive: true });
470
+ if (lookup.isArchived) {
471
+ return {};
472
+ }
473
+ if (await findArchivedTaskPath(taskId, planningRoot)) {
474
+ throw new Error(
475
+ `Task ${taskId} has both active and archived records. Completion is blocked to avoid overwriting managed state. Run build doctor for details; do not edit managed files manually.`
476
+ );
477
+ }
478
+ const { frontMatter, body } = await readMarkdownFile(lookup.filePath);
479
+ const rawTask = frontMatter;
480
+ const task = coerceSprintTaskFrontMatter(rawTask);
481
+ const forceCompletion = options.force ?? false;
482
+ if (!forceCompletion && (task.status === "blocked" || task.status === "cancelled")) {
483
+ throw new Error(
484
+ `Cannot complete task ${task.id} from status "${task.status}" without --force. Move it to in_progress/review first.`
485
+ );
486
+ }
487
+ if (task.status !== "done" && !(forceCompletion && (task.status === "blocked" || task.status === "cancelled"))) {
488
+ const transition = await validateStateTransition(planningRoot, taskId, task.status, "done");
489
+ if (!transition.success) {
490
+ const details = transition.errors?.length ? `: ${transition.errors.join("; ")}` : "";
491
+ throw new Error(`${transition.message}${details}`);
492
+ }
493
+ }
494
+ const gate = await assertCompletionContractsMet({
495
+ contracts: task.completionContract,
496
+ workingDir: options.completionContractRoot
497
+ });
498
+ const now = (/* @__PURE__ */ new Date()).toISOString();
499
+ if (forceCompletion && task.status !== "done") {
500
+ rawTask.forceCompletedFrom = task.status;
501
+ if (options.preserveBlockedReason && task.status === "blocked" && task.blockedReason) {
502
+ rawTask.originalBlockedReason = task.blockedReason;
503
+ }
504
+ }
505
+ rawTask.status = "done";
506
+ rawTask.version = task.version + 1;
507
+ rawTask.completed_at = now;
508
+ rawTask.updated_at = now;
509
+ rawTask.archivedAt = now;
510
+ rawTask.originalSprintId = task.sprintId;
511
+ delete rawTask.sprintId;
512
+ delete rawTask.sprint_id;
513
+ const archivedPath = getArchivedFilePath(bucket, task.id, now, planningRoot);
514
+ await ensureDirectoryExists(path2.dirname(archivedPath));
515
+ await writeMarkdownFile(archivedPath, rawTask, body);
516
+ await recordUnverifiedCompletion(archivedPath, gate.unverifiedLabel, now);
517
+ await fs2.unlink(lookup.filePath);
518
+ return { archivedPath, unverifiedLabel: gate.unverifiedLabel };
519
+ }
520
+ async function findSprintOverlapConflict(sprintsDir, startDate, endDate) {
521
+ const start = parseStrictDateOnly(startDate);
522
+ const end = parseStrictDateOnly(endDate);
523
+ if (!start || !end) return null;
524
+ const existing = await listMarkdownFiles(sprintsDir).catch(() => []);
525
+ for (const file of existing) {
526
+ try {
527
+ const { frontMatter } = await readMarkdownFile(file);
528
+ const fm = frontMatter;
529
+ if (fm.status === "completed") continue;
530
+ const existingId = typeof fm.id === "string" ? fm.id : "";
531
+ const existingStart = typeof fm.startDate === "string" ? fm.startDate : typeof fm.start_date === "string" ? fm.start_date : "";
532
+ const existingEnd = typeof fm.endDate === "string" ? fm.endDate : typeof fm.end_date === "string" ? fm.end_date : "";
533
+ if (!existingStart) continue;
534
+ if (existingStart === startDate) {
535
+ return {
536
+ conflictingSprintId: existingId,
537
+ conflictingStartDate: existingStart,
538
+ conflictingEndDate: existingEnd,
539
+ kind: "exact"
540
+ };
541
+ }
542
+ if (existingStart && existingEnd) {
543
+ const existingStartDate = parseStrictDateOnly(existingStart);
544
+ const existingEndDate = parseStrictDateOnly(existingEnd);
545
+ if (existingStartDate && existingEndDate && start.getTime() < existingEndDate.getTime() && end.getTime() > existingStartDate.getTime()) {
546
+ return {
547
+ conflictingSprintId: existingId,
548
+ conflictingStartDate: existingStart,
549
+ conflictingEndDate: existingEnd,
550
+ kind: "range"
551
+ };
552
+ }
553
+ }
554
+ } catch {
555
+ }
556
+ }
557
+ return null;
558
+ }
559
+ function emitSprintManagerWarning(message, metadata, severity = "WARN" /* WARN */) {
560
+ emitCustomWarning(
561
+ severity,
562
+ "configuration" /* CONFIGURATION */,
563
+ message,
564
+ {
565
+ subsystem: "planning/sprint-manager",
566
+ executionPhase: "execution"
567
+ },
568
+ { metadata, skipConsole: true }
569
+ );
570
+ }
571
+ function parseStrictDateOnly(value) {
572
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
573
+ if (!match) return null;
574
+ const [, yearText, monthText, dayText] = match;
575
+ const year = Number(yearText);
576
+ const month = Number(monthText);
577
+ const day = Number(dayText);
578
+ const date = new Date(Date.UTC(year, month - 1, day));
579
+ if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day) {
580
+ return null;
581
+ }
582
+ return date;
583
+ }
584
+ async function ensureSprintDoesNotAlreadyLinkBacklogItem(sprintId, taskIds, backlogItemId) {
585
+ if (!backlogItemId) return;
586
+ for (const existingTaskId of taskIds) {
587
+ try {
588
+ const linkedTask = await getTask(existingTaskId, {
589
+ includeArchive: true
590
+ });
591
+ if (linkedTask.yaml.backlogItemId === backlogItemId) {
592
+ throw new Error(
593
+ `Backlog item ${backlogItemId} is already represented in sprint ${sprintId} by task ${existingTaskId}`
594
+ );
595
+ }
596
+ } catch (error) {
597
+ if (error instanceof Error && error.message.includes("already represented in sprint")) {
598
+ throw error;
599
+ }
600
+ if (error instanceof Error && error.message.startsWith("Task not found:")) {
601
+ continue;
602
+ }
603
+ emitSprintManagerWarning(
604
+ `Could not inspect task ${existingTaskId} while checking sprint ${sprintId}`,
605
+ {
606
+ sprintId,
607
+ taskId: existingTaskId,
608
+ error: error instanceof Error ? error.message : String(error)
609
+ }
610
+ );
611
+ throw new Error(
612
+ `Cannot safely add task to sprint ${sprintId}: existing task ${existingTaskId} could not be inspected`
613
+ );
614
+ }
615
+ }
616
+ }
617
+ function formatSprintStatusLabel(status) {
618
+ switch (status) {
619
+ case "planning":
620
+ return "Planning";
621
+ case "active":
622
+ return "Active";
623
+ case "completed":
624
+ return "Completed";
625
+ default:
626
+ return "Planning";
627
+ }
628
+ }
629
+ function formatSprintTaskStatusLabel(status) {
630
+ switch (status) {
631
+ case "todo":
632
+ return "todo";
633
+ case "in_progress":
634
+ return "in_progress";
635
+ case "review":
636
+ return "review";
637
+ case "done":
638
+ return "done";
639
+ case "blocked":
640
+ return "blocked";
641
+ case "cancelled":
642
+ return "cancelled";
643
+ default:
644
+ return "todo";
645
+ }
646
+ }
647
+ function renderSprintTasksSummaryTable(tasks) {
648
+ const header = "| Task | Estimated Hours | Status |\n|------|-----------------|--------|";
649
+ if (tasks.length === 0) {
650
+ return `${header}
651
+ | (No tasks yet) | - | - |`;
652
+ }
653
+ const rows = tasks.map((t) => {
654
+ const taskCell = `${t.id}: ${t.title}`.replaceAll("\n", " ").trim();
655
+ const estimateCell = t.estimatedHours > 0 ? `${t.estimatedHours}h` : "-";
656
+ return `| ${taskCell} | ${estimateCell} | ${formatSprintTaskStatusLabel(t.status)} |`;
657
+ }).join("\n");
658
+ return `${header}
659
+ ${rows}`;
660
+ }
661
+ function updateSprintBodyOverview(body, sprint, tasks) {
662
+ const total = tasks.length;
663
+ const done = tasks.filter((t) => t.status === "done").length;
664
+ const progressLine = total === 0 ? "**Progress**: 0 tasks" : `**Progress**: ${done}/${total} tasks (${(done / total * 100).toFixed(1)}%)`;
665
+ let updated = body;
666
+ if (/^\*\*Status\*\*:/m.test(updated)) {
667
+ updated = updated.replace(
668
+ /^\*\*Status\*\*:\s*.*$/m,
669
+ `**Status**: ${formatSprintStatusLabel(sprint.status)}`
670
+ );
671
+ }
672
+ if (/^\*\*Progress\*\*:/m.test(updated)) {
673
+ updated = updated.replace(/^\*\*Progress\*\*:\s*.*$/m, progressLine);
674
+ }
675
+ return updated;
676
+ }
677
+ function updateSprintBodyTasksSummary(body, tasks) {
678
+ const table = renderSprintTasksSummaryTable(tasks);
679
+ const replacement = `## Tasks Summary
680
+
681
+ ${table}
682
+ `;
683
+ if (/^## Tasks Summary\s*$/m.test(body)) {
684
+ const headingMatch = body.match(/^## Tasks Summary\s*$/m);
685
+ if (headingMatch?.index !== void 0) {
686
+ const sectionStart = headingMatch.index;
687
+ const afterHeadingIndex = sectionStart + headingMatch[0].length;
688
+ const rest = body.slice(afterHeadingIndex);
689
+ const nextSectionMatch = rest.match(/\n## /);
690
+ const sectionEnd = nextSectionMatch && nextSectionMatch.index !== void 0 ? afterHeadingIndex + nextSectionMatch.index + 1 : body.length;
691
+ return `${body.slice(0, sectionStart)}${replacement.trimEnd()}
692
+ ${body.slice(sectionEnd)}`;
693
+ }
694
+ }
695
+ if (/^## Notes\s*$/m.test(body)) {
696
+ return body.replace(/^## Notes\s*$/m, `${replacement}
697
+ ## Notes`);
698
+ }
699
+ return `${body.trimEnd()}
700
+
701
+ ${replacement}
702
+ `;
703
+ }
704
+ async function listArchivedDoneTasksForSprint(sprintId) {
705
+ const planningRoot = getPlanningRoot();
706
+ const archiveRoot = getBucketArchivePathByKind("task", planningRoot);
707
+ const files = await listMarkdownFilesRecursive(archiveRoot).catch(() => []);
708
+ const tasks = [];
709
+ for (const file of files) {
710
+ if (path2.basename(file).toLowerCase() === "readme.md") {
711
+ continue;
712
+ }
713
+ try {
714
+ const { frontMatter } = await readMarkdownFile(file);
715
+ const fm = frontMatter;
716
+ const originalSprintId = typeof fm.originalSprintId === "string" ? fm.originalSprintId : void 0;
717
+ if (originalSprintId !== sprintId) {
718
+ continue;
719
+ }
720
+ if (fm.status !== "done") {
721
+ continue;
722
+ }
723
+ const id = typeof fm.id === "string" ? fm.id : path2.basename(file, ".md");
724
+ tasks.push({
725
+ id,
726
+ title: typeof fm.title === "string" ? fm.title : id,
727
+ status: "done",
728
+ estimatedHours: typeof fm.estimatedHours === "number" ? fm.estimatedHours : 0
729
+ });
730
+ } catch {
731
+ }
732
+ }
733
+ return tasks;
734
+ }
735
+ function applyDerivedSprintMetrics(sprint, tasks, archivedDoneHours = 0) {
736
+ if (!sprint.velocity) {
737
+ return;
738
+ }
739
+ if (!Number.isFinite(sprint.velocity.forecast)) {
740
+ sprint.velocity.forecast = sprint.capacity.totalHours;
741
+ }
742
+ const activeDoneHours = tasks.filter((task) => task.status === "done").reduce((sum, task) => sum + task.estimatedHours, 0);
743
+ sprint.velocity.actual = activeDoneHours + archivedDoneHours;
744
+ }
745
+ function sourceHasLegacyCapacity(frontMatter) {
746
+ return frontMatter.capacity != null && typeof frontMatter.capacity === "object" || frontMatter.total_capacity_hours != null || frontMatter.totalHours != null || frontMatter.total_capacity != null;
747
+ }
748
+ function sourceHasLegacyVelocity(frontMatter) {
749
+ return frontMatter.velocity != null && typeof frontMatter.velocity === "object";
750
+ }
751
+ function toPersistedSprintFrontMatter(sprint, sourceFrontMatter, options = {}) {
752
+ const persisted = { ...sprint };
753
+ const keepCapacity = options.authorLegacyScrum === true || sourceFrontMatter !== void 0 && sourceHasLegacyCapacity(sourceFrontMatter);
754
+ const keepVelocity = options.authorLegacyScrum === true || sourceFrontMatter !== void 0 && sourceHasLegacyVelocity(sourceFrontMatter);
755
+ if (!keepCapacity) {
756
+ delete persisted.capacity;
757
+ }
758
+ if (!keepVelocity) {
759
+ delete persisted.velocity;
760
+ }
761
+ return persisted;
762
+ }
763
+ async function writeSprintMarkdownFile(filePath, sprint, body, sourceFrontMatter, options = {}) {
764
+ await writeMarkdownFile(
765
+ filePath,
766
+ toPersistedSprintFrontMatter(sprint, sourceFrontMatter, options),
767
+ body
768
+ );
769
+ }
770
+ async function refreshSprintMarkdownById(sprintId, options = {}) {
771
+ const sprintPath = await resolveSprintPath(sprintId, {
772
+ includeArchive: options.includeArchive
773
+ });
774
+ const { frontMatter, body } = await readMarkdownFile(sprintPath);
775
+ const sprint = coerceSprintYAML(frontMatter);
776
+ const tasks = await listTasksInSprint(sprintId);
777
+ const archivedDoneTasks = await listArchivedDoneTasksForSprint(sprintId);
778
+ const archivedDoneHours = archivedDoneTasks.reduce((sum, task) => sum + task.estimatedHours, 0);
779
+ applyDerivedSprintMetrics(sprint, tasks, archivedDoneHours);
780
+ const reportedTasks = [...tasks, ...archivedDoneTasks];
781
+ const updatedBody = updateSprintBodyTasksSummary(
782
+ updateSprintBodyOverview(body, sprint, reportedTasks),
783
+ reportedTasks
784
+ );
785
+ sprint.updated_at = (/* @__PURE__ */ new Date()).toISOString();
786
+ await writeSprintMarkdownFile(
787
+ sprintPath,
788
+ sprint,
789
+ updatedBody,
790
+ frontMatter
791
+ );
792
+ }
793
+ async function fileExists(filePath) {
794
+ try {
795
+ await fs2.access(filePath);
796
+ return true;
797
+ } catch {
798
+ return false;
799
+ }
800
+ }
801
+ async function assertSprintFileExists(sprintId, options = {}) {
802
+ const filePath = await resolveSprintPath(sprintId, options);
803
+ if (!await fileExists(filePath)) {
804
+ throw new Error(`Sprint not found: ${sprintId}`);
805
+ }
806
+ return filePath;
807
+ }
808
+ async function resolveSprintPath(sprintId, options = {}) {
809
+ const planningRoot = getPlanningRoot();
810
+ const sprintsDir = getBucketPathByKind("sprint", planningRoot);
811
+ const activePath = resolvePlanningItemPath(sprintsDir, sprintId, { label: "sprintId" });
812
+ if (await fileExists(activePath)) {
813
+ return activePath;
814
+ }
815
+ if (!options.includeArchive) {
816
+ return activePath;
817
+ }
818
+ const archiveRoot = bucketArchiveRootForProjectRoot(planningRoot, "sprint", sprintsDir);
819
+ if (!await fileExists(archiveRoot)) {
820
+ return activePath;
821
+ }
822
+ const archivedFiles = await listMarkdownFilesRecursive(archiveRoot).catch(() => []);
823
+ const match = archivedFiles.find((file) => path2.basename(file) === `${sprintId}.md`);
824
+ if (!match) {
825
+ return activePath;
826
+ }
827
+ return match;
828
+ }
829
+ function parseNumber(value, fallback) {
830
+ if (typeof value === "number" && Number.isFinite(value)) return value;
831
+ if (typeof value === "string") {
832
+ const parsed = Number.parseFloat(value);
833
+ if (Number.isFinite(parsed)) return parsed;
834
+ }
835
+ return fallback;
836
+ }
837
+ function coerceDateString(value) {
838
+ if (typeof value === "string") return value;
839
+ if (value instanceof Date && !Number.isNaN(value.getTime())) {
840
+ return formatLocalDateString(value);
841
+ }
842
+ return "";
843
+ }
844
+ function formatLocalDateString(value) {
845
+ const year = value.getFullYear();
846
+ const month = `${value.getMonth() + 1}`.padStart(2, "0");
847
+ const day = `${value.getDate()}`.padStart(2, "0");
848
+ return `${year}-${month}-${day}`;
849
+ }
850
+ function coerceSprintCapacity(frontMatter) {
851
+ const capacity = frontMatter.capacity;
852
+ if (capacity && typeof capacity === "object") {
853
+ const totalHours2 = parseNumber(capacity.totalHours, 0);
854
+ const allocatedHours2 = parseNumber(capacity.allocatedHours, 0);
855
+ const remainingHours2 = parseNumber(capacity.remainingHours, totalHours2 - allocatedHours2);
856
+ const utilizationPercent2 = totalHours2 > 0 ? parseNumber(capacity.utilizationPercent, allocatedHours2 / totalHours2 * 100) : 0;
857
+ return { totalHours: totalHours2, allocatedHours: allocatedHours2, remainingHours: remainingHours2, utilizationPercent: utilizationPercent2 };
858
+ }
859
+ const totalHours = parseNumber(
860
+ frontMatter.total_capacity_hours ?? frontMatter.totalHours ?? frontMatter.total_capacity,
861
+ 0
862
+ );
863
+ const allocatedHours = parseNumber(
864
+ frontMatter.planned_capacity_hours ?? frontMatter.allocated_hours ?? frontMatter.allocatedHours,
865
+ 0
866
+ );
867
+ const remainingHours = totalHours > 0 ? Math.max(0, totalHours - allocatedHours) : 0;
868
+ const utilizationPercent = totalHours > 0 ? allocatedHours / totalHours * 100 : 0;
869
+ return { totalHours, allocatedHours, remainingHours, utilizationPercent };
870
+ }
871
+ function coerceSprintYAML(frontMatter) {
872
+ const id = typeof frontMatter.id === "string" ? frontMatter.id : "";
873
+ if (!id) {
874
+ throw new Error('Invalid sprint frontmatter: missing required field "id"');
875
+ }
876
+ assertSafePlanningFileId(id, "sprintId");
877
+ const kindRaw = typeof frontMatter.kind === "string" ? frontMatter.kind : "sprint";
878
+ const kind = kindRaw === "sprint" ? "sprint" : "sprint";
879
+ const title = typeof frontMatter.title === "string" && frontMatter.title || typeof frontMatter.name === "string" && frontMatter.name || id;
880
+ const name = typeof frontMatter.name === "string" && frontMatter.name || typeof frontMatter.title === "string" && frontMatter.title || id;
881
+ const startDate = coerceDateString(frontMatter.startDate) || coerceDateString(frontMatter.start_date) || "";
882
+ const endDate = coerceDateString(frontMatter.endDate) || coerceDateString(frontMatter.end_date) || "";
883
+ if (!startDate || !endDate) {
884
+ throw new Error(
885
+ `Invalid sprint frontmatter for '${id}': missing "startDate"/"endDate" (or legacy start_date/end_date)`
886
+ );
887
+ }
888
+ const goal = typeof frontMatter.goal === "string" ? frontMatter.goal : typeof frontMatter.goal_summary === "string" ? frontMatter.goal_summary : void 0;
889
+ const statusRaw = typeof frontMatter.status === "string" ? frontMatter.status : "planning";
890
+ const status = statusRaw === "active" || statusRaw === "planning" || statusRaw === "completed" ? statusRaw : "planning";
891
+ const taskIds = Array.isArray(frontMatter.taskIds) ? frontMatter.taskIds.filter((v) => typeof v === "string") : [];
892
+ const completedTaskIds = Array.isArray(frontMatter.completedTaskIds) ? frontMatter.completedTaskIds.filter((v) => typeof v === "string") : [];
893
+ const createdAt = typeof frontMatter.created_at === "string" && frontMatter.created_at || typeof frontMatter.createdAt === "string" && frontMatter.createdAt || typeof frontMatter.created === "string" && frontMatter.created || (/* @__PURE__ */ new Date()).toISOString();
894
+ const updatedAt = typeof frontMatter.updated_at === "string" && frontMatter.updated_at || typeof frontMatter.updatedAt === "string" && frontMatter.updatedAt || typeof frontMatter.updated === "string" && frontMatter.updated || createdAt;
895
+ const velocityRaw = frontMatter.velocity;
896
+ const velocity = velocityRaw && typeof velocityRaw === "object" ? {
897
+ forecast: parseNumber(velocityRaw.forecast, 0),
898
+ actual: parseNumber(velocityRaw.actual, 0)
899
+ } : void 0;
900
+ return {
901
+ ...frontMatter,
902
+ id,
903
+ kind,
904
+ title,
905
+ name,
906
+ startDate,
907
+ endDate,
908
+ goal,
909
+ status,
910
+ capacity: coerceSprintCapacity(frontMatter),
911
+ taskIds,
912
+ completedTaskIds,
913
+ velocity,
914
+ created_at: createdAt,
915
+ updated_at: updatedAt,
916
+ completed_at: typeof frontMatter.completed_at === "string" ? frontMatter.completed_at : void 0
917
+ };
918
+ }
919
+ async function createSprint(name, startDate, endDate, options = {}) {
920
+ const planningRoot = getPlanningRoot();
921
+ const sprintsDir = getBucketPathByKind("sprint", planningRoot);
922
+ assertBucketWriteAvailable(planningRoot);
923
+ await ensureDirectoryExists(sprintsDir);
924
+ const start = parseStrictDateOnly(startDate);
925
+ const end = parseStrictDateOnly(endDate);
926
+ if (!start || !end) {
927
+ throw new Error(`Invalid sprint dates: start=${startDate} end=${endDate}`);
928
+ }
929
+ if (end.getTime() <= start.getTime()) {
930
+ throw new Error("Invalid sprint date range: endDate must be after startDate");
931
+ }
932
+ return withSprintActivationLock(async () => {
933
+ if (!options.allowDuplicateStartDate) {
934
+ const conflict = await findSprintOverlapConflict(sprintsDir, startDate, endDate);
935
+ if (conflict) {
936
+ const idSuffix = conflict.conflictingSprintId ? ` (${conflict.conflictingSprintId})` : "";
937
+ if (conflict.kind === "exact") {
938
+ throw Object.assign(
939
+ new Error(
940
+ `Sprint already active for date ${startDate}${idSuffix}. View it: build plan sprint status. Close it: build plan sprint close${conflict.conflictingSprintId ? ` ${conflict.conflictingSprintId}` : ""}.`
941
+ ),
942
+ { code: "SPRINT_ALREADY_EXISTS_FOR_DATE" }
943
+ );
944
+ } else {
945
+ throw new Error(
946
+ `Sprint date range overlaps existing sprint${idSuffix} (${conflict.conflictingStartDate} to ${conflict.conflictingEndDate}). View it: build plan sprint status. Close it: build plan sprint close${conflict.conflictingSprintId ? ` ${conflict.conflictingSprintId}` : ""}.`
947
+ );
948
+ }
949
+ }
950
+ }
951
+ const sprintId = generateId(/* @__PURE__ */ new Date());
952
+ const filePath = resolvePlanningItemPath(sprintsDir, sprintId, { label: "sprintId" });
953
+ try {
954
+ await fs2.access(filePath);
955
+ throw new Error(
956
+ `Sprint already active for date ${startDate}. View it: build plan sprint status. Close it: build plan sprint close.`
957
+ );
958
+ } catch (error) {
959
+ if (error.code !== "ENOENT") {
960
+ throw error;
961
+ }
962
+ }
963
+ const authoredHours = typeof options.totalHours === "number" && Number.isFinite(options.totalHours) ? options.totalHours : void 0;
964
+ const totalHours = authoredHours ?? 0;
965
+ const now = (/* @__PURE__ */ new Date()).toISOString();
966
+ const sprint = {
967
+ id: sprintId,
968
+ kind: "sprint",
969
+ title: name,
970
+ name,
971
+ startDate,
972
+ endDate,
973
+ goal: options.goal,
974
+ status: "planning",
975
+ capacity: {
976
+ totalHours,
977
+ allocatedHours: 0,
978
+ remainingHours: totalHours,
979
+ utilizationPercent: 0
980
+ },
981
+ taskIds: [],
982
+ ...authoredHours !== void 0 ? {
983
+ velocity: {
984
+ forecast: authoredHours,
985
+ actual: 0
986
+ }
987
+ } : {},
988
+ created_at: now,
989
+ updated_at: now
990
+ };
991
+ const body = `# Sprint: ${name}
992
+
993
+ **Duration**: ${startDate} to ${endDate}
994
+ **Status**: ${formatSprintStatusLabel(sprint.status)}
995
+ **Progress**: 0 tasks
996
+
997
+ ## Sprint Goal
998
+
999
+ ${options.goal || "No specific goal set"}
1000
+
1001
+ ## Tasks Summary
1002
+
1003
+ ${renderSprintTasksSummaryTable([])}
1004
+
1005
+ ## Notes
1006
+
1007
+ Sprint created on ${now}
1008
+ `;
1009
+ await withIndexRegeneration(planningRoot, async () => {
1010
+ await writeSprintMarkdownFile(filePath, sprint, body, void 0, {
1011
+ authorLegacyScrum: authoredHours !== void 0
1012
+ });
1013
+ });
1014
+ return sprint;
1015
+ });
1016
+ }
1017
+ async function getCurrentSprint() {
1018
+ const planningRoot = getPlanningRoot();
1019
+ const sprintsDir = getBucketPathByKind("sprint", planningRoot);
1020
+ try {
1021
+ const files = await listMarkdownFiles(sprintsDir);
1022
+ if (files.length === 0) return null;
1023
+ let activeCandidate = null;
1024
+ let planningCandidate = null;
1025
+ for (const file of files) {
1026
+ let sprint;
1027
+ try {
1028
+ const { frontMatter } = await readMarkdownFile(file);
1029
+ sprint = coerceSprintYAML(frontMatter);
1030
+ } catch {
1031
+ continue;
1032
+ }
1033
+ if (sprint.status === "active") {
1034
+ activeCandidate = { yaml: sprint, filePath: file };
1035
+ } else if (sprint.status === "planning") {
1036
+ planningCandidate = { yaml: sprint, filePath: file };
1037
+ }
1038
+ }
1039
+ return activeCandidate ?? planningCandidate;
1040
+ } catch {
1041
+ return null;
1042
+ }
1043
+ }
1044
+ async function assertSprintAcceptsNewTask(sprintId) {
1045
+ const activePath = await resolveSprintPath(sprintId);
1046
+ const isActive = await fileExists(activePath);
1047
+ const resolvedPath = isActive ? activePath : await resolveSprintPath(sprintId, { includeArchive: true });
1048
+ if (!isActive && !await fileExists(resolvedPath)) {
1049
+ throw new Error(`Sprint not found: ${sprintId}`);
1050
+ }
1051
+ const { frontMatter } = await readMarkdownFile(resolvedPath);
1052
+ const sprint = coerceSprintYAML(frontMatter);
1053
+ if (sprint.status === "completed") {
1054
+ throw new Error(`Cannot add task to completed sprint ${sprintId}`);
1055
+ }
1056
+ if (!isActive) {
1057
+ throw new Error(`Cannot add task to archived sprint ${sprintId}`);
1058
+ }
1059
+ }
1060
+ async function addTaskToSprint(sprintId, taskId, estimatedHours) {
1061
+ const planningRoot = getPlanningRoot();
1062
+ const filePath = await assertSprintFileExists(sprintId);
1063
+ const tasksDir = getBucketPathByKind("task", planningRoot);
1064
+ return withSprintLock(sprintId, async () => {
1065
+ const { frontMatter, body } = await readMarkdownFile(filePath);
1066
+ const sprint = coerceSprintYAML(frontMatter);
1067
+ if (sprint.status === "completed") {
1068
+ throw new Error(`Cannot add task ${taskId} to completed sprint ${sprintId}`);
1069
+ }
1070
+ if (sprint.taskIds.includes(taskId)) {
1071
+ throw new Error(`Task ${taskId} is already in sprint ${sprintId}`);
1072
+ }
1073
+ const taskLookup = await getTask(taskId, { includeArchive: true });
1074
+ if (taskLookup.isArchived) {
1075
+ throw new Error(
1076
+ `Cannot add archived task ${taskId} to sprint ${sprintId}; restore the task before assigning it`
1077
+ );
1078
+ }
1079
+ await ensureSprintDoesNotAlreadyLinkBacklogItem(
1080
+ sprintId,
1081
+ sprint.taskIds,
1082
+ taskLookup.yaml.backlogItemId
1083
+ );
1084
+ const taskDependencies = Array.isArray(taskLookup?.yaml?.dependencies) ? taskLookup.yaml.dependencies : [];
1085
+ if (taskDependencies.length > 0) {
1086
+ const unsatisfiedDependencies = [];
1087
+ const completedTaskIds = new Set(sprint.completedTaskIds ?? []);
1088
+ for (const dependencyId of taskDependencies) {
1089
+ try {
1090
+ const dependencyLookup = await getTask(dependencyId, {
1091
+ includeArchive: true
1092
+ });
1093
+ if (!dependencyLookup) {
1094
+ unsatisfiedDependencies.push(dependencyId);
1095
+ continue;
1096
+ }
1097
+ const classification = classifyTaskDependency(dependencyId, {
1098
+ task: {
1099
+ status: dependencyLookup.yaml.status,
1100
+ isArchived: dependencyLookup.isArchived
1101
+ }
1102
+ });
1103
+ const isInSameSprint = dependencyLookup.yaml.sprintId === sprintId && sprint.taskIds.includes(dependencyId);
1104
+ if (!classification.satisfied && !isInSameSprint) {
1105
+ unsatisfiedDependencies.push(dependencyId);
1106
+ }
1107
+ } catch {
1108
+ const classification = classifyTaskDependency(dependencyId, {
1109
+ task: null,
1110
+ recordedComplete: completedTaskIds.has(dependencyId)
1111
+ });
1112
+ if (!classification.satisfied) {
1113
+ unsatisfiedDependencies.push(dependencyId);
1114
+ }
1115
+ }
1116
+ }
1117
+ if (unsatisfiedDependencies.length > 0) {
1118
+ throw new Error(
1119
+ `Task ${taskId} has unsatisfied dependency/dependencies not in sprint ${sprintId}: ${unsatisfiedDependencies.join(", ")}`
1120
+ );
1121
+ }
1122
+ }
1123
+ sprint.taskIds.push(taskId);
1124
+ sprint.completedTaskIds = (sprint.completedTaskIds ?? []).filter((id) => id !== taskId);
1125
+ sprint.updated_at = (/* @__PURE__ */ new Date()).toISOString();
1126
+ let allocatedHours = 0;
1127
+ for (const id of sprint.taskIds) {
1128
+ try {
1129
+ const taskPath = resolvePlanningItemPath(tasksDir, id, { label: "taskId" });
1130
+ const { frontMatter: taskFrontMatter } = await readMarkdownFile(taskPath);
1131
+ const tfm = taskFrontMatter;
1132
+ const taskHours = typeof tfm.estimatedHours === "number" ? tfm.estimatedHours : 0;
1133
+ allocatedHours += taskHours;
1134
+ } catch {
1135
+ if (id === taskId) {
1136
+ allocatedHours += estimatedHours;
1137
+ }
1138
+ }
1139
+ }
1140
+ sprint.capacity.allocatedHours = allocatedHours;
1141
+ sprint.capacity.remainingHours = Math.max(0, sprint.capacity.totalHours - allocatedHours);
1142
+ sprint.capacity.utilizationPercent = sprint.capacity.totalHours > 0 ? allocatedHours / sprint.capacity.totalHours * 100 : 0;
1143
+ await withIndexRegeneration(planningRoot, async () => {
1144
+ const { frontMatter: taskFrontMatter, body: taskBody } = await readMarkdownFile(
1145
+ taskLookup.filePath
1146
+ );
1147
+ const rawTask = taskFrontMatter;
1148
+ const currentSprintId = typeof rawTask.sprintId === "string" ? rawTask.sprintId : typeof rawTask.sprint_id === "string" ? rawTask.sprint_id : void 0;
1149
+ if (currentSprintId && currentSprintId !== sprintId) {
1150
+ let stillLinkedToCurrentSprint = false;
1151
+ try {
1152
+ const currentSprintPath = await resolveSprintPath(currentSprintId, {
1153
+ includeArchive: false
1154
+ });
1155
+ const { frontMatter: currentSprintFrontMatter } = await readMarkdownFile(currentSprintPath);
1156
+ const currentSprint = coerceSprintYAML(
1157
+ currentSprintFrontMatter
1158
+ );
1159
+ stillLinkedToCurrentSprint = currentSprint.taskIds.includes(taskId);
1160
+ } catch {
1161
+ stillLinkedToCurrentSprint = false;
1162
+ }
1163
+ if (stillLinkedToCurrentSprint) {
1164
+ throw new Error(
1165
+ `Task ${taskId} is already assigned to sprint ${currentSprintId}; remove it before adding to ${sprintId}`
1166
+ );
1167
+ }
1168
+ }
1169
+ rawTask.sprintId = sprintId;
1170
+ delete rawTask.sprint_id;
1171
+ rawTask.updated_at = (/* @__PURE__ */ new Date()).toISOString();
1172
+ rawTask.version = parseTaskNumber(rawTask.version, 0) + 1;
1173
+ await writeMarkdownFile(
1174
+ taskLookup.filePath,
1175
+ rawTask,
1176
+ taskBody
1177
+ );
1178
+ await writeSprintMarkdownFile(filePath, sprint, body, frontMatter);
1179
+ try {
1180
+ await refreshSprintMarkdownById(sprintId, { includeArchive: false });
1181
+ } catch {
1182
+ }
1183
+ });
1184
+ return sprint;
1185
+ });
1186
+ }
1187
+ async function removeTaskFromSprint(sprintId, taskId, _estimatedHours) {
1188
+ const planningRoot = getPlanningRoot();
1189
+ const filePath = resolvePlanningItemPath(getBucketPathByKind("sprint", planningRoot), sprintId, {
1190
+ label: "sprintId"
1191
+ });
1192
+ const tasksDir = getBucketPathByKind("task", planningRoot);
1193
+ return withSprintLock(sprintId, async () => {
1194
+ const { frontMatter, body } = await readMarkdownFile(filePath);
1195
+ const sprint = coerceSprintYAML(frontMatter);
1196
+ if (sprint.status === "completed") {
1197
+ throw new Error(`Cannot remove task ${taskId} from completed sprint ${sprintId}`);
1198
+ }
1199
+ if (!sprint.taskIds.includes(taskId)) {
1200
+ return sprint;
1201
+ }
1202
+ sprint.taskIds = sprint.taskIds.filter((id) => id !== taskId);
1203
+ sprint.updated_at = (/* @__PURE__ */ new Date()).toISOString();
1204
+ let allocatedHours = 0;
1205
+ for (const id of sprint.taskIds) {
1206
+ try {
1207
+ const taskPath = resolvePlanningItemPath(tasksDir, id, { label: "taskId" });
1208
+ const { frontMatter: taskFrontMatter } = await readMarkdownFile(taskPath);
1209
+ const tfm = taskFrontMatter;
1210
+ const taskHours = typeof tfm.estimatedHours === "number" ? tfm.estimatedHours : 0;
1211
+ allocatedHours += taskHours;
1212
+ } catch {
1213
+ }
1214
+ }
1215
+ sprint.capacity.allocatedHours = allocatedHours;
1216
+ sprint.capacity.remainingHours = Math.max(0, sprint.capacity.totalHours - allocatedHours);
1217
+ sprint.capacity.utilizationPercent = sprint.capacity.totalHours > 0 ? allocatedHours / sprint.capacity.totalHours * 100 : 0;
1218
+ await withIndexRegeneration(planningRoot, async () => {
1219
+ try {
1220
+ const taskLookup = await getTask(taskId, { includeArchive: true });
1221
+ const { frontMatter: taskFrontMatter, body: taskBody } = await readMarkdownFile(
1222
+ taskLookup.filePath
1223
+ );
1224
+ const rawTask = taskFrontMatter;
1225
+ if (rawTask.sprintId === sprintId || rawTask.sprint_id === sprintId) {
1226
+ if (!rawTask.originalSprintId) {
1227
+ rawTask.originalSprintId = rawTask.sprintId ?? rawTask.sprint_id;
1228
+ }
1229
+ delete rawTask.sprintId;
1230
+ delete rawTask.sprint_id;
1231
+ rawTask.updated_at = (/* @__PURE__ */ new Date()).toISOString();
1232
+ rawTask.version = parseTaskNumber(rawTask.version, 0) + 1;
1233
+ await writeMarkdownFile(
1234
+ taskLookup.filePath,
1235
+ rawTask,
1236
+ taskBody
1237
+ );
1238
+ }
1239
+ } catch {
1240
+ }
1241
+ await writeSprintMarkdownFile(filePath, sprint, body, frontMatter);
1242
+ try {
1243
+ await refreshSprintMarkdownById(sprintId, { includeArchive: false });
1244
+ } catch {
1245
+ }
1246
+ });
1247
+ return sprint;
1248
+ });
1249
+ }
1250
+ async function detachArchivedTaskFromSprint(sprintId, taskId, options = {}) {
1251
+ const planningRoot = getPlanningRoot();
1252
+ let filePath;
1253
+ try {
1254
+ filePath = await resolveSprintPath(sprintId, { includeArchive: true });
1255
+ } catch (error) {
1256
+ if (error instanceof Error && error.message.includes(`Sprint not found: ${sprintId}`)) {
1257
+ const notFound = new Error(error.message);
1258
+ notFound.code = "ENOENT";
1259
+ throw notFound;
1260
+ }
1261
+ throw error;
1262
+ }
1263
+ const tasksDir = getBucketPathByKind("task", planningRoot);
1264
+ return withSprintLock(sprintId, async () => {
1265
+ const { frontMatter, body } = await readMarkdownFile(filePath);
1266
+ const sprint = coerceSprintYAML(frontMatter);
1267
+ if (!sprint.taskIds.includes(taskId)) {
1268
+ return sprint;
1269
+ }
1270
+ sprint.taskIds = sprint.taskIds.filter((id) => id !== taskId);
1271
+ if (options.completed) {
1272
+ sprint.completedTaskIds = [.../* @__PURE__ */ new Set([...sprint.completedTaskIds ?? [], taskId])];
1273
+ }
1274
+ sprint.updated_at = (/* @__PURE__ */ new Date()).toISOString();
1275
+ let allocatedHours = 0;
1276
+ for (const id of sprint.taskIds) {
1277
+ try {
1278
+ const taskPath = resolvePlanningItemPath(tasksDir, id, { label: "taskId" });
1279
+ const { frontMatter: taskFrontMatter } = await readMarkdownFile(taskPath);
1280
+ const tfm = taskFrontMatter;
1281
+ const taskHours = typeof tfm.estimatedHours === "number" ? tfm.estimatedHours : 0;
1282
+ allocatedHours += taskHours;
1283
+ } catch {
1284
+ }
1285
+ }
1286
+ sprint.capacity.allocatedHours = allocatedHours;
1287
+ sprint.capacity.remainingHours = Math.max(0, sprint.capacity.totalHours - allocatedHours);
1288
+ sprint.capacity.utilizationPercent = sprint.capacity.totalHours > 0 ? allocatedHours / sprint.capacity.totalHours * 100 : 0;
1289
+ await withIndexRegeneration(planningRoot, async () => {
1290
+ await writeSprintMarkdownFile(filePath, sprint, body, frontMatter);
1291
+ try {
1292
+ await refreshSprintMarkdownById(sprintId, { includeArchive: true });
1293
+ } catch {
1294
+ }
1295
+ });
1296
+ return sprint;
1297
+ });
1298
+ }
1299
+ async function isTaskRecordedCompletedInSprint(sprintId, taskId) {
1300
+ const sprintPath = await resolveSprintPath(sprintId, { includeArchive: true });
1301
+ const { frontMatter } = await readMarkdownFile(sprintPath);
1302
+ const sprint = coerceSprintYAML(frontMatter);
1303
+ return (sprint.completedTaskIds ?? []).includes(taskId);
1304
+ }
1305
+ async function assertSprintCanAcceptRestoredTask(sprintId, taskId) {
1306
+ const sprintPath = await resolveSprintPath(sprintId, { includeArchive: true });
1307
+ if (!await fileExists(sprintPath)) {
1308
+ return { sprintExists: false, alreadyMember: false };
1309
+ }
1310
+ const { frontMatter } = await readMarkdownFile(sprintPath);
1311
+ const sprint = coerceSprintYAML(frontMatter);
1312
+ if (sprint.status === "completed") {
1313
+ throw new Error(
1314
+ `Cannot restore task ${taskId} into completed sprint ${sprintId}; reopen the sprint or restore the task into an active sprint first.`
1315
+ );
1316
+ }
1317
+ return { sprintExists: true, alreadyMember: sprint.taskIds.includes(taskId) };
1318
+ }
1319
+ async function calculateCapacity(sprintId) {
1320
+ const filePath = await assertSprintFileExists(sprintId, { includeArchive: true });
1321
+ const { frontMatter } = await readMarkdownFile(filePath);
1322
+ const sprint = coerceSprintYAML(frontMatter);
1323
+ let allocatedHours = 0;
1324
+ for (const id of sprint.taskIds) {
1325
+ try {
1326
+ const taskHours = (await getTask(id, { includeArchive: true })).yaml.estimatedHours ?? 0;
1327
+ allocatedHours += taskHours;
1328
+ } catch {
1329
+ }
1330
+ }
1331
+ const remainingHours = Math.max(0, sprint.capacity.totalHours - allocatedHours);
1332
+ const utilizationPercent = sprint.capacity.totalHours > 0 ? allocatedHours / sprint.capacity.totalHours * 100 : 0;
1333
+ return {
1334
+ totalHours: sprint.capacity.totalHours,
1335
+ allocatedHours,
1336
+ remainingHours,
1337
+ utilizationPercent
1338
+ };
1339
+ }
1340
+ function checkCapacityWarning(capacity, additionalHours = 0) {
1341
+ if (capacity.totalHours <= 0) {
1342
+ return null;
1343
+ }
1344
+ const projectedAllocation = capacity.allocatedHours + additionalHours;
1345
+ const projectedUtilization = projectedAllocation / capacity.totalHours * 100;
1346
+ if (projectedUtilization > 100) {
1347
+ return {
1348
+ level: "error",
1349
+ message: `Sprint overcommitted: ${projectedAllocation}h / ${capacity.totalHours}h (${projectedUtilization.toFixed(1)}% utilization)`
1350
+ };
1351
+ }
1352
+ if (projectedUtilization >= 80) {
1353
+ return {
1354
+ level: "warning",
1355
+ message: `Approaching capacity: ${projectedAllocation}h / ${capacity.totalHours}h (${projectedUtilization.toFixed(1)}% utilization)`
1356
+ };
1357
+ }
1358
+ return null;
1359
+ }
1360
+ async function listTasksInSprint(sprintId) {
1361
+ const sprintPath = await assertSprintFileExists(sprintId, {
1362
+ includeArchive: true
1363
+ });
1364
+ const { frontMatter } = await readMarkdownFile(sprintPath);
1365
+ const sprint = coerceSprintYAML(frontMatter);
1366
+ const tasks = [];
1367
+ for (const taskId of sprint.taskIds) {
1368
+ try {
1369
+ const result = await getTask(taskId, { includeArchive: true });
1370
+ if (result.isArchived) {
1371
+ continue;
1372
+ }
1373
+ const taskFrontMatter = result.yaml;
1374
+ const rawStatus = taskFrontMatter.status;
1375
+ tasks.push({
1376
+ id: taskFrontMatter.id ?? taskId,
1377
+ title: taskFrontMatter.title ?? taskId,
1378
+ priority: taskFrontMatter.priority,
1379
+ estimatedHours: taskFrontMatter.estimatedHours ?? 0,
1380
+ ...typeof taskFrontMatter.expectedRuntimeMinutes === "number" && taskFrontMatter.expectedRuntimeMinutes > 0 ? { expectedRuntimeMinutes: taskFrontMatter.expectedRuntimeMinutes } : {},
1381
+ status: typeof rawStatus === "string" && ["todo", "in_progress", "review", "done", "blocked", "cancelled"].includes(rawStatus) ? rawStatus : "todo",
1382
+ planArtifactPath: taskFrontMatter.planArtifactPath,
1383
+ resultArtifactPath: taskFrontMatter.resultArtifactPath,
1384
+ planStageId: taskFrontMatter.planStageId,
1385
+ blockedReason: taskFrontMatter.blockedReason,
1386
+ lastTransitionReason: taskFrontMatter.lastTransitionReason
1387
+ });
1388
+ } catch (error) {
1389
+ if (!isGenuinelyAbsentTaskError(error)) {
1390
+ throw error;
1391
+ }
1392
+ tasks.push({
1393
+ id: taskId,
1394
+ title: `(Missing Task: ${taskId})`,
1395
+ estimatedHours: 0,
1396
+ status: "todo",
1397
+ missing: true
1398
+ });
1399
+ }
1400
+ }
1401
+ return tasks;
1402
+ }
1403
+ function computeSprintTerminalReadiness(tasks) {
1404
+ const missingTaskIds = tasks.filter((t) => t.missing === true).map((t) => t.id);
1405
+ const realTasks = tasks.filter((t) => t.missing !== true);
1406
+ const incompleteTaskIds = realTasks.filter((t) => t.status !== "done").map((t) => t.id);
1407
+ const allDone = realTasks.length > 0 && incompleteTaskIds.length === 0;
1408
+ const ready = allDone && missingTaskIds.length === 0;
1409
+ return { ready, allDone, incompleteTaskIds, missingTaskIds };
1410
+ }
1411
+ function assertSprintTerminalReady(sprintId, tasks, options = {}) {
1412
+ const readiness = computeSprintTerminalReadiness(tasks);
1413
+ if (options.force) return readiness;
1414
+ const issues = [];
1415
+ if (readiness.incompleteTaskIds.length > 0) {
1416
+ issues.push(
1417
+ `${readiness.incompleteTaskIds.length} task(s) not completed: ${readiness.incompleteTaskIds.join(", ")}`
1418
+ );
1419
+ }
1420
+ if (readiness.missingTaskIds.length > 0) {
1421
+ issues.push(
1422
+ `${readiness.missingTaskIds.length} missing task ref(s): ${readiness.missingTaskIds.join(", ")} (run \`build plan sprint prune-missing ${sprintId}\` or pass --force)`
1423
+ );
1424
+ }
1425
+ if (issues.length > 0) {
1426
+ throw new Error(
1427
+ `Cannot close sprint ${sprintId}: ${issues.join("; ")}. Use --force to override.`
1428
+ );
1429
+ }
1430
+ return readiness;
1431
+ }
1432
+ async function countArchivedTasksForSprint(sprintId, status) {
1433
+ const planningRoot = getPlanningRoot();
1434
+ const archiveRoot = getBucketArchivePathByKind("task", planningRoot);
1435
+ const files = await listMarkdownFilesRecursive(archiveRoot).catch(() => []);
1436
+ let count = 0;
1437
+ for (const file of files) {
1438
+ if (path2.basename(file).toLowerCase() === "readme.md") {
1439
+ continue;
1440
+ }
1441
+ try {
1442
+ const { frontMatter } = await readMarkdownFile(file);
1443
+ const fm = frontMatter;
1444
+ const originalSprintId = typeof fm.originalSprintId === "string" ? fm.originalSprintId : void 0;
1445
+ if (originalSprintId === sprintId && (status === void 0 || fm.status === status)) {
1446
+ count++;
1447
+ }
1448
+ } catch {
1449
+ }
1450
+ }
1451
+ return count;
1452
+ }
1453
+ async function findReadySprintsForBatchClose() {
1454
+ const sprints = await listSprints(false);
1455
+ const ready = [];
1456
+ const skipped = [];
1457
+ for (const sprint of sprints) {
1458
+ if (sprint.status !== "active" && sprint.status !== "planning") {
1459
+ continue;
1460
+ }
1461
+ const tasks = await listTasksInSprint(sprint.id);
1462
+ const readiness = computeSprintTerminalReadiness(tasks);
1463
+ if (readiness.ready) {
1464
+ ready.push({ sprintId: sprint.id, totalTasks: tasks.length });
1465
+ continue;
1466
+ }
1467
+ if (tasks.length === 0) {
1468
+ const archivedTaskCount = await countArchivedTasksForSprint(sprint.id);
1469
+ if (archivedTaskCount > 0 || sprint.taskIds.length > 0) {
1470
+ ready.push({
1471
+ sprintId: sprint.id,
1472
+ totalTasks: archivedTaskCount > 0 ? archivedTaskCount : sprint.taskIds.length
1473
+ });
1474
+ }
1475
+ continue;
1476
+ }
1477
+ if (readiness.allDone && readiness.missingTaskIds.length > 0) {
1478
+ skipped.push({
1479
+ sprintId: sprint.id,
1480
+ reason: `${readiness.missingTaskIds.length} missing task ref(s); run prune-missing or close --force`
1481
+ });
1482
+ }
1483
+ }
1484
+ return { ready, skipped };
1485
+ }
1486
+ async function refreshSprintMarkdown(sprintId) {
1487
+ await refreshSprintMarkdownById(sprintId, { includeArchive: false });
1488
+ }
1489
+ async function activateSprint(sprintId) {
1490
+ await withSprintActivationLock(async () => {
1491
+ const sprintPath = await resolveSprintPath(sprintId, {
1492
+ includeArchive: false
1493
+ });
1494
+ const { frontMatter, body } = await readMarkdownFile(sprintPath);
1495
+ const sprint = coerceSprintYAML(frontMatter);
1496
+ if (sprint.status !== "planning") {
1497
+ return;
1498
+ }
1499
+ sprint.status = "active";
1500
+ sprint.updated_at = (/* @__PURE__ */ new Date()).toISOString();
1501
+ const tasks = await listTasksInSprint(sprintId);
1502
+ const reportedTasks = [...tasks, ...await listArchivedDoneTasksForSprint(sprintId)];
1503
+ const updatedBody = updateSprintBodyTasksSummary(
1504
+ updateSprintBodyOverview(body, sprint, reportedTasks),
1505
+ reportedTasks
1506
+ );
1507
+ await withIndexRegeneration(getPlanningRoot(), async () => {
1508
+ await writeSprintMarkdownFile(
1509
+ sprintPath,
1510
+ sprint,
1511
+ updatedBody,
1512
+ frontMatter
1513
+ );
1514
+ });
1515
+ const planningRoot = getPlanningRoot();
1516
+ const sprintsDir = getBucketPathByKind("sprint", planningRoot);
1517
+ const allFiles = await listMarkdownFiles(sprintsDir).catch(() => []);
1518
+ for (const file of allFiles) {
1519
+ if (file === sprintPath) continue;
1520
+ try {
1521
+ await withSprintLock(path2.basename(file, ".md"), async () => {
1522
+ const { frontMatter: otherFm, body: otherBody } = await readMarkdownFile(file);
1523
+ const other = coerceSprintYAML(otherFm);
1524
+ if (other.status === "active") {
1525
+ other.status = "planning";
1526
+ other.updated_at = (/* @__PURE__ */ new Date()).toISOString();
1527
+ await writeSprintMarkdownFile(
1528
+ file,
1529
+ other,
1530
+ otherBody,
1531
+ otherFm
1532
+ );
1533
+ }
1534
+ });
1535
+ } catch (err) {
1536
+ const message = err instanceof Error ? err.message : String(err);
1537
+ if (message.includes("is busy") || message.includes("Timed out")) {
1538
+ throw new Error(
1539
+ `Cannot activate sprint ${sprintId}: another sprint file is locked (${path2.basename(file)}): ${message}`
1540
+ );
1541
+ }
1542
+ emitSprintManagerWarning("Skipped sprint deactivation check during activation", {
1543
+ sprintId,
1544
+ file: path2.basename(file),
1545
+ error: message
1546
+ });
1547
+ }
1548
+ }
1549
+ });
1550
+ }
1551
+ async function completeSprint(sprintId, options = {}) {
1552
+ const forceTaskCompletion = options.forceTaskCompletion ?? false;
1553
+ const planningRoot = getPlanningRoot();
1554
+ const currentPath = resolvePlanningItemPath(
1555
+ getBucketPathByKind("sprint", planningRoot),
1556
+ sprintId,
1557
+ { label: "sprintId" }
1558
+ );
1559
+ const archivedTaskPaths = [];
1560
+ const unverifiedTasks = [];
1561
+ let touchedPaths = [];
1562
+ return withSprintLock(sprintId, async () => {
1563
+ const sprintPath = await resolveSprintPath(sprintId, {
1564
+ includeArchive: true
1565
+ });
1566
+ const { frontMatter, body } = await readMarkdownFile(sprintPath);
1567
+ const sprint = coerceSprintYAML(frontMatter);
1568
+ if (sprintPath !== currentPath && sprint.status === "completed") {
1569
+ return { sprint, archivedPath: sprintPath, archivedTaskPaths: [], touchedPaths: [] };
1570
+ }
1571
+ sprint.status = "completed";
1572
+ sprint.completed_at = (/* @__PURE__ */ new Date()).toISOString();
1573
+ sprint.updated_at = sprint.completed_at;
1574
+ const completedAt = sprint.completed_at;
1575
+ const tasks = await listTasksInSprint(sprintId);
1576
+ const archivedDoneTasks = await listArchivedDoneTasksForSprint(sprintId);
1577
+ const archivedDoneHours = archivedDoneTasks.reduce((sum, task) => sum + task.estimatedHours, 0);
1578
+ applyDerivedSprintMetrics(sprint, tasks, archivedDoneHours);
1579
+ assertSprintTerminalReady(sprintId, tasks, { force: forceTaskCompletion });
1580
+ const sprintBucket = getBucketByName("sprint", planningRoot);
1581
+ if (!sprintBucket) throw new Error("Bucket not configured: sprint");
1582
+ const archivedPath = getArchivedFilePath(sprintBucket, sprintId, completedAt, planningRoot);
1583
+ const reportedTasks = [...tasks, ...archivedDoneTasks];
1584
+ const updatedBody = updateSprintBodyTasksSummary(
1585
+ updateSprintBodyOverview(body, sprint, reportedTasks),
1586
+ reportedTasks
1587
+ );
1588
+ await withIndexRegeneration(planningRoot, async () => {
1589
+ const sprintRollbackSnapshot = {
1590
+ filePath: currentPath,
1591
+ frontMatter,
1592
+ body
1593
+ };
1594
+ const completedTaskSnapshots = [];
1595
+ const rollbackCompletedTasks = async () => {
1596
+ const rollbackFailures = [];
1597
+ for (const snapshot of completedTaskSnapshots.reverse()) {
1598
+ try {
1599
+ await ensureDirectoryExists(path2.dirname(snapshot.activePath));
1600
+ await writeMarkdownFile(snapshot.activePath, snapshot.frontMatter, snapshot.body);
1601
+ await fs2.unlink(snapshot.archivedPath).catch(() => void 0);
1602
+ } catch (rollbackErr) {
1603
+ rollbackFailures.push(
1604
+ `${snapshot.taskId}: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)}`
1605
+ );
1606
+ }
1607
+ }
1608
+ try {
1609
+ await writeMarkdownFile(
1610
+ sprintRollbackSnapshot.filePath,
1611
+ sprintRollbackSnapshot.frontMatter,
1612
+ sprintRollbackSnapshot.body
1613
+ );
1614
+ } catch (rollbackErr) {
1615
+ rollbackFailures.push(
1616
+ `${sprintId}: ${rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr)}`
1617
+ );
1618
+ }
1619
+ return rollbackFailures;
1620
+ };
1621
+ const warnRollbackFailures = (rollbackFailures) => {
1622
+ if (rollbackFailures.length > 0) {
1623
+ emitSprintManagerWarning(
1624
+ "Partial rollback during completeSprint; manual recovery required",
1625
+ {
1626
+ sprintId,
1627
+ failures: rollbackFailures
1628
+ },
1629
+ "ERROR" /* ERROR */
1630
+ );
1631
+ }
1632
+ };
1633
+ for (const taskId of sprint.taskIds) {
1634
+ try {
1635
+ let taskSnapshot;
1636
+ try {
1637
+ const taskLookup = await getTask(taskId, { includeArchive: true });
1638
+ if (!taskLookup.isArchived) {
1639
+ const { frontMatter: taskFrontMatter, body: taskBody } = await readMarkdownFile(
1640
+ taskLookup.filePath
1641
+ );
1642
+ taskSnapshot = {
1643
+ activePath: taskLookup.filePath,
1644
+ frontMatter: taskFrontMatter,
1645
+ body: taskBody
1646
+ };
1647
+ }
1648
+ } catch (snapshotError) {
1649
+ const errorMessage = snapshotError instanceof Error ? snapshotError.message : String(snapshotError);
1650
+ if (errorMessage.includes("Task not found")) {
1651
+ continue;
1652
+ }
1653
+ throw snapshotError;
1654
+ }
1655
+ const completed = await archiveTaskForSprintClose(taskId, {
1656
+ force: forceTaskCompletion,
1657
+ preserveBlockedReason: true,
1658
+ completionContractRoot: planningRoot
1659
+ });
1660
+ if (completed?.unverifiedLabel) {
1661
+ unverifiedTasks.push({ taskId, label: completed.unverifiedLabel });
1662
+ }
1663
+ if (taskSnapshot) {
1664
+ const archivedPath2 = completed?.archivedPath;
1665
+ if (archivedPath2) {
1666
+ completedTaskSnapshots.push({
1667
+ taskId,
1668
+ activePath: taskSnapshot.activePath,
1669
+ archivedPath: archivedPath2,
1670
+ frontMatter: taskSnapshot.frontMatter,
1671
+ body: taskSnapshot.body
1672
+ });
1673
+ archivedTaskPaths.push({
1674
+ id: taskId,
1675
+ activePath: taskSnapshot.activePath,
1676
+ archivedPath: archivedPath2
1677
+ });
1678
+ }
1679
+ }
1680
+ } catch (error) {
1681
+ const errorMessage = error instanceof Error ? error.message : String(error);
1682
+ if (!errorMessage.includes("Task not found")) {
1683
+ warnRollbackFailures(await rollbackCompletedTasks());
1684
+ throw error;
1685
+ }
1686
+ }
1687
+ }
1688
+ try {
1689
+ await ensureDirectoryExists(path2.dirname(archivedPath));
1690
+ await writeSprintMarkdownFile(
1691
+ archivedPath,
1692
+ sprint,
1693
+ updatedBody,
1694
+ frontMatter
1695
+ );
1696
+ await fs2.unlink(currentPath);
1697
+ } catch (error) {
1698
+ await fs2.unlink(archivedPath).catch(() => void 0);
1699
+ warnRollbackFailures(await rollbackCompletedTasks());
1700
+ throw error;
1701
+ }
1702
+ const { completeSprintDependents } = await import("./sprint-completion-dependents-34SR7JVL.js");
1703
+ const completionFiles = { planningRoot, currentPath, archivedPath, archivedTaskPaths };
1704
+ touchedPaths = await completeSprintDependents(completionFiles, emitSprintManagerWarning);
1705
+ });
1706
+ return {
1707
+ sprint,
1708
+ archivedPath,
1709
+ archivedTaskPaths,
1710
+ touchedPaths,
1711
+ ...unverifiedTasks.length > 0 ? { unverifiedTasks } : {}
1712
+ };
1713
+ });
1714
+ }
1715
+ async function closeSprint(sprintId, options = {}) {
1716
+ const result = await closeSprintWithSyncPaths(sprintId, options);
1717
+ return result.sprint;
1718
+ }
1719
+ async function closeSprintWithSyncPaths(sprintId, options = {}) {
1720
+ const planningRoot = getPlanningRoot();
1721
+ const currentPath = await resolveSprintPath(sprintId, {
1722
+ includeArchive: true
1723
+ });
1724
+ const { frontMatter } = await readMarkdownFile(currentPath);
1725
+ const sprint = coerceSprintYAML(frontMatter);
1726
+ if (options.dryRun) {
1727
+ const tasks = await listTasksInSprint(sprintId);
1728
+ assertSprintTerminalReady(sprintId, tasks, { force: options.force });
1729
+ return { sprint, touchedPaths: [] };
1730
+ }
1731
+ if (options.noArchive) {
1732
+ return withSprintLock(sprintId, async () => {
1733
+ const { frontMatter: lockedFrontMatter, body: lockedBody } = await readMarkdownFile(currentPath);
1734
+ const lockedSprint = coerceSprintYAML(lockedFrontMatter);
1735
+ if (lockedSprint.status === "completed") {
1736
+ return { sprint: lockedSprint, touchedPaths: [] };
1737
+ }
1738
+ const lockedTasks = await listTasksInSprint(sprintId);
1739
+ assertSprintTerminalReady(sprintId, lockedTasks, { force: options.force });
1740
+ lockedSprint.status = "completed";
1741
+ lockedSprint.completed_at = (/* @__PURE__ */ new Date()).toISOString();
1742
+ lockedSprint.updated_at = lockedSprint.completed_at;
1743
+ const archivedDoneTasks = await listArchivedDoneTasksForSprint(sprintId);
1744
+ const lockedArchivedDoneHours = archivedDoneTasks.reduce(
1745
+ (sum, task) => sum + task.estimatedHours,
1746
+ 0
1747
+ );
1748
+ applyDerivedSprintMetrics(lockedSprint, lockedTasks, lockedArchivedDoneHours);
1749
+ const reportedTasks = [...lockedTasks, ...archivedDoneTasks];
1750
+ const updatedBody = updateSprintBodyTasksSummary(
1751
+ updateSprintBodyOverview(lockedBody, lockedSprint, reportedTasks),
1752
+ reportedTasks
1753
+ );
1754
+ await withIndexRegeneration(planningRoot, async () => {
1755
+ await writeSprintMarkdownFile(
1756
+ currentPath,
1757
+ lockedSprint,
1758
+ updatedBody,
1759
+ lockedFrontMatter
1760
+ );
1761
+ });
1762
+ return { sprint: lockedSprint, touchedPaths: [currentPath] };
1763
+ });
1764
+ }
1765
+ const result = await completeSprint(sprintId, {
1766
+ forceTaskCompletion: Boolean(options.force)
1767
+ });
1768
+ return {
1769
+ sprint: result.sprint,
1770
+ touchedPaths: result.touchedPaths,
1771
+ ...result.unverifiedTasks ? { unverifiedTasks: result.unverifiedTasks } : {}
1772
+ };
1773
+ }
1774
+ async function listSprints(archived = false) {
1775
+ const planningRoot = getPlanningRoot();
1776
+ const liveDir = getBucketPathByKind("sprint", planningRoot);
1777
+ const sprintsDir = archived ? bucketArchiveRootForProjectRoot(planningRoot, "sprint", liveDir) : liveDir;
1778
+ const files = archived ? await listMarkdownFilesRecursive(sprintsDir) : await listMarkdownFiles(sprintsDir);
1779
+ const sprints = [];
1780
+ for (const file of files) {
1781
+ try {
1782
+ const { frontMatter } = await readMarkdownFile(file);
1783
+ sprints.push(coerceSprintYAML(frontMatter));
1784
+ } catch (error) {
1785
+ const msg = error instanceof Error ? error.message : String(error);
1786
+ emitSprintManagerWarning("Skipping malformed sprint file", {
1787
+ file,
1788
+ error: msg,
1789
+ archived
1790
+ });
1791
+ }
1792
+ }
1793
+ return sprints;
1794
+ }
1795
+ async function renameSprint(sprintId, newName) {
1796
+ const trimmedName = newName.trim();
1797
+ if (!trimmedName) {
1798
+ throw new Error("Sprint name cannot be empty");
1799
+ }
1800
+ const planningRoot = getPlanningRoot();
1801
+ return withSprintLock(sprintId, async () => {
1802
+ const sprintPath = await resolveSprintPath(sprintId, {
1803
+ includeArchive: false
1804
+ });
1805
+ const { frontMatter, body } = await readMarkdownFile(sprintPath);
1806
+ const sprint = coerceSprintYAML(frontMatter);
1807
+ if (sprint.status === "completed") {
1808
+ throw new Error(
1809
+ `Cannot rename sprint '${sprintId}': completed sprints are read-only (assumption A2)`
1810
+ );
1811
+ }
1812
+ sprint.name = trimmedName;
1813
+ sprint.title = trimmedName;
1814
+ sprint.updated_at = (/* @__PURE__ */ new Date()).toISOString();
1815
+ const updatedBody = body.replace(/^# Sprint:.*$/m, `# Sprint: ${trimmedName}`);
1816
+ await withIndexRegeneration(planningRoot, async () => {
1817
+ await writeSprintMarkdownFile(
1818
+ sprintPath,
1819
+ sprint,
1820
+ updatedBody,
1821
+ frontMatter
1822
+ );
1823
+ });
1824
+ return sprint;
1825
+ });
1826
+ }
1827
+ async function findFinishedSprints(options = {}) {
1828
+ const referenceDate = options.referenceDate ?? /* @__PURE__ */ new Date();
1829
+ const activeSprints = await listSprints(false);
1830
+ const finishedSprints = [];
1831
+ for (const sprint of activeSprints) {
1832
+ if (sprint.status === "completed") {
1833
+ continue;
1834
+ }
1835
+ if (!sprint.endDate) {
1836
+ continue;
1837
+ }
1838
+ const refDateStr = formatLocalDateString(referenceDate);
1839
+ if (sprint.endDate >= refDateStr) {
1840
+ continue;
1841
+ }
1842
+ const tasks = await listTasksInSprint(sprint.id);
1843
+ const readiness = computeSprintTerminalReadiness(tasks);
1844
+ const completedTasks = tasks.filter((t) => t.missing !== true && t.status === "done").length;
1845
+ const allTasksCompleted = tasks.length === 0 || readiness.ready;
1846
+ if (allTasksCompleted) {
1847
+ finishedSprints.push({
1848
+ sprintId: sprint.id,
1849
+ endDate: sprint.endDate,
1850
+ totalTasks: tasks.length,
1851
+ completedTasks
1852
+ });
1853
+ }
1854
+ }
1855
+ return finishedSprints;
1856
+ }
1857
+
1858
+ export {
1859
+ acquireSprintLock,
1860
+ acquireSprintLockLease,
1861
+ withSprintLock,
1862
+ getSprintLockHandoffEnv,
1863
+ getSprintLockOwnerToken,
1864
+ refreshSprintLock,
1865
+ unlockSprintLock,
1866
+ DEFAULT_SPRINT_CAPACITY_HOURS,
1867
+ findSprintOverlapConflict,
1868
+ createSprint,
1869
+ getCurrentSprint,
1870
+ assertSprintAcceptsNewTask,
1871
+ addTaskToSprint,
1872
+ removeTaskFromSprint,
1873
+ detachArchivedTaskFromSprint,
1874
+ isTaskRecordedCompletedInSprint,
1875
+ assertSprintCanAcceptRestoredTask,
1876
+ calculateCapacity,
1877
+ checkCapacityWarning,
1878
+ listTasksInSprint,
1879
+ computeSprintTerminalReadiness,
1880
+ assertSprintTerminalReady,
1881
+ countArchivedTasksForSprint,
1882
+ findReadySprintsForBatchClose,
1883
+ refreshSprintMarkdown,
1884
+ activateSprint,
1885
+ completeSprint,
1886
+ closeSprint,
1887
+ closeSprintWithSyncPaths,
1888
+ listSprints,
1889
+ renameSprint,
1890
+ findFinishedSprints
1891
+ };
1892
+ //# sourceMappingURL=chunk-L2CBG5IX.js.map