@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.
- package/.build-project/providers/catalog.json +13951 -0
- package/.build-project/providers/pricing.json +1978 -0
- package/.build-project/providers/registry.json +4103 -0
- package/.github/SECURITY.md +75 -0
- package/.nvmrc +1 -0
- package/CHANGELOG.md +661 -0
- package/CODE_OF_CONDUCT.md +44 -0
- package/CONTRIBUTING.md +24 -0
- package/INSTALL.md +623 -0
- package/LICENSE +21 -0
- package/README.md +118 -2
- package/THIRD_PARTY_NOTICES.txt +26 -0
- package/dist/ai-judge-UE5UOYOO.js +191 -0
- package/dist/allowlist-grounding-KPLN6NC5.js +16 -0
- package/dist/allowlist-utils-MZZKKXRD.js +31 -0
- package/dist/apply-completion-mode-EM37UZHB.js +110 -0
- package/dist/artifact-migrator-WPACNSEP.js +276 -0
- package/dist/ask-2OZ4JFQR.js +176 -0
- package/dist/auth-6UKBTJUQ.js +185 -0
- package/dist/auth-H5KJL6HL.js +165 -0
- package/dist/auth-LVJRJDMU.js +12 -0
- package/dist/auth-NHZOCNRR.js +94 -0
- package/dist/auth-PBXHWXGW.js +95 -0
- package/dist/auth-T7Y5DCAH.js +91 -0
- package/dist/auth-TVVKCHQW.js +13 -0
- package/dist/auth-UHB2UCSS.js +97 -0
- package/dist/auth-VACA3VUL.js +98 -0
- package/dist/auth-VVLC77S3.js +44 -0
- package/dist/auth-liveness-XO4AGDDD.js +53 -0
- package/dist/autoloop-cleanup-SI3VGAAR.js +106 -0
- package/dist/autoloop-evidence-gates-J5GG5YQB.js +39 -0
- package/dist/autoloop-gate-policy-SUNAEP6Q.js +169 -0
- package/dist/autoloop-helpers-VQGQNTT6.js +52 -0
- package/dist/autoloop-ledger-P6TIDP7C.js +96 -0
- package/dist/autoloop-ledger-subscriber-HFAGOZXH.js +161 -0
- package/dist/autoloop-run-defaults-GWGZBNT7.js +27 -0
- package/dist/autoloop-run-lock-GBWRM5A2.js +197 -0
- package/dist/autoloop-success-C32QVWOP.js +93 -0
- package/dist/autoloop-termination-summary-GI6IBQWD.js +58 -0
- package/dist/autoloop-trajectory-AMKSQISD.js +70 -0
- package/dist/autoloop-wall-clock-T7ZVIQOC.js +12 -0
- package/dist/automatic-branch-cleanup-R62X2C5O.js +49 -0
- package/dist/autonomous-loop-controller-2WL363LW.js +4386 -0
- package/dist/backend-YUTFDZXZ.js +30 -0
- package/dist/background-executor-Z3ODTMD7.js +260 -0
- package/dist/backlog-75QPEAMW.js +403 -0
- package/dist/backlog-execution-intent-GWUV5TUK.js +19 -0
- package/dist/backup-active-store-XHWLN34M.js +16 -0
- package/dist/backup-machine-stores-UI4LTJOY.js +251 -0
- package/dist/backup-telemetry-db-Z4ICYCNW.js +26 -0
- package/dist/branch-archive-manager-FMSQ7YJF.js +18 -0
- package/dist/branch-cleanup-manager-ST6FJGND.js +35 -0
- package/dist/build-gate-7NKWPY62.js +68 -0
- package/dist/build-root-S7DINODY.js +18 -0
- package/dist/change-summary-R6CB6VXJ.js +50 -0
- package/dist/chunk-24MNKKOM.js +173 -0
- package/dist/chunk-2H6VZFIO.js +235 -0
- package/dist/chunk-2JIX3EKV.js +39 -0
- package/dist/chunk-2KO7HVZM.js +106 -0
- package/dist/chunk-2L36U25O.js +100 -0
- package/dist/chunk-2NMNFUQA.js +475 -0
- package/dist/chunk-2OUAEH67.js +83 -0
- package/dist/chunk-2VLJUXJU.js +115 -0
- package/dist/chunk-2VUEDIUM.js +77 -0
- package/dist/chunk-2Y2IIHPI.js +430 -0
- package/dist/chunk-2YRG3LHZ.js +220 -0
- package/dist/chunk-2Z5Q3SUY.js +65 -0
- package/dist/chunk-32IYXIE5.js +873 -0
- package/dist/chunk-33IGPPUI.js +292 -0
- package/dist/chunk-352PCJLK.js +283 -0
- package/dist/chunk-35J4NE6S.js +226 -0
- package/dist/chunk-3C7WBIVK.js +1016 -0
- package/dist/chunk-3H3EY6U7.js +1225 -0
- package/dist/chunk-3H4MWYIC.js +198 -0
- package/dist/chunk-3HHWQR3N.js +2479 -0
- package/dist/chunk-3JKNRYEE.js +14 -0
- package/dist/chunk-3LECCYZY.js +128 -0
- package/dist/chunk-3LOY6YZI.js +852 -0
- package/dist/chunk-3M57DADF.js +44 -0
- package/dist/chunk-3NOTLVLG.js +3803 -0
- package/dist/chunk-3OPP2OZB.js +1480 -0
- package/dist/chunk-3P5IN5E7.js +9 -0
- package/dist/chunk-3PL22IYZ.js +20 -0
- package/dist/chunk-3REDAJUJ.js +14 -0
- package/dist/chunk-3S2R4XJI.js +203 -0
- package/dist/chunk-3UBZI5DW.js +61 -0
- package/dist/chunk-3VV5OBGG.js +308 -0
- package/dist/chunk-3WY5TU2O.js +823 -0
- package/dist/chunk-43OKHTW4.js +82 -0
- package/dist/chunk-45KUJBDI.js +112 -0
- package/dist/chunk-47X5LM7B.js +224 -0
- package/dist/chunk-4B6FQJ77.js +268 -0
- package/dist/chunk-4BTDUT2S.js +42 -0
- package/dist/chunk-4DJL2VXA.js +24 -0
- package/dist/chunk-4EBSXZ73.js +48 -0
- package/dist/chunk-4QKP6I4C.js +294 -0
- package/dist/chunk-4U6XK2DG.js +300 -0
- package/dist/chunk-4UMRUFBD.js +132 -0
- package/dist/chunk-4US4SYJ4.js +569 -0
- package/dist/chunk-4ZPLWEZO.js +154 -0
- package/dist/chunk-56WPYDJH.js +624 -0
- package/dist/chunk-57WRCJJW.js +50 -0
- package/dist/chunk-5AW4RMNG.js +24 -0
- package/dist/chunk-5EQN56OZ.js +155 -0
- package/dist/chunk-5F43TUIN.js +38 -0
- package/dist/chunk-5FKHIKTS.js +115 -0
- package/dist/chunk-5HDP7XZG.js +91 -0
- package/dist/chunk-5KQETTNS.js +152 -0
- package/dist/chunk-5PDVN2KO.js +498 -0
- package/dist/chunk-5UBIFVRD.js +509 -0
- package/dist/chunk-5YDE3Q62.js +46 -0
- package/dist/chunk-626AJVMU.js +302 -0
- package/dist/chunk-633XZ7UF.js +3583 -0
- package/dist/chunk-63DHNHGA.js +236 -0
- package/dist/chunk-666656AR.js +568 -0
- package/dist/chunk-67YRJPJO.js +19 -0
- package/dist/chunk-6CAU7VBA.js +20 -0
- package/dist/chunk-6CB3KJRY.js +21 -0
- package/dist/chunk-6DBMALXL.js +29 -0
- package/dist/chunk-6E25C4IA.js +269 -0
- package/dist/chunk-6FIBNIQU.js +73 -0
- package/dist/chunk-6G57FYBV.js +189 -0
- package/dist/chunk-6KZKRTG3.js +4885 -0
- package/dist/chunk-6LAH2UV2.js +525 -0
- package/dist/chunk-6PZY2TTU.js +921 -0
- package/dist/chunk-6T6NHXK4.js +230 -0
- package/dist/chunk-6TBEX4R4.js +432 -0
- package/dist/chunk-6TRD7TEE.js +911 -0
- package/dist/chunk-6XCP2RAI.js +47 -0
- package/dist/chunk-726G6WDL.js +351 -0
- package/dist/chunk-75EMT7BF.js +616 -0
- package/dist/chunk-762ACDZJ.js +4696 -0
- package/dist/chunk-77I6G4CO.js +1 -0
- package/dist/chunk-7DJ6SQH3.js +510 -0
- package/dist/chunk-7HPCIOMA.js +1383 -0
- package/dist/chunk-7HYBSRPZ.js +17503 -0
- package/dist/chunk-7KBEOPVB.js +73 -0
- package/dist/chunk-7LHJDJB3.js +2222 -0
- package/dist/chunk-7NVJMH52.js +306 -0
- package/dist/chunk-7RMARDVH.js +33 -0
- package/dist/chunk-7SEWU4QG.js +36 -0
- package/dist/chunk-7TUTZTI2.js +911 -0
- package/dist/chunk-7VBDFPUM.js +340 -0
- package/dist/chunk-7VRJHTGZ.js +6406 -0
- package/dist/chunk-7YAOUUKK.js +493 -0
- package/dist/chunk-AAAODV76.js +860 -0
- package/dist/chunk-AB4HUJVQ.js +339 -0
- package/dist/chunk-AEQWV746.js +611 -0
- package/dist/chunk-AHU3FKPA.js +11639 -0
- package/dist/chunk-AISTV5XU.js +226 -0
- package/dist/chunk-AJBTKGJZ.js +48 -0
- package/dist/chunk-AJJNW7XT.js +248 -0
- package/dist/chunk-AJN5Y5YZ.js +160 -0
- package/dist/chunk-ALDTFNZ3.js +150 -0
- package/dist/chunk-ARARVIZK.js +281 -0
- package/dist/chunk-ATBM6AW5.js +53 -0
- package/dist/chunk-ATKEKM3E.js +206 -0
- package/dist/chunk-AUJLW6JZ.js +92 -0
- package/dist/chunk-AY3MHEFM.js +24 -0
- package/dist/chunk-B7PYTV72.js +236 -0
- package/dist/chunk-B7YRSULE.js +1423 -0
- package/dist/chunk-BAWJNMWF.js +339 -0
- package/dist/chunk-BBPIILO2.js +88 -0
- package/dist/chunk-BD3PGW6A.js +957 -0
- package/dist/chunk-BDPYFAB4.js +44 -0
- package/dist/chunk-BIUV23HH.js +729 -0
- package/dist/chunk-BQ3VAGXH.js +243 -0
- package/dist/chunk-BQJOGAWT.js +31 -0
- package/dist/chunk-BT7EG7CO.js +68 -0
- package/dist/chunk-BV3XQQLU.js +27 -0
- package/dist/chunk-BY6ODHNZ.js +78 -0
- package/dist/chunk-BZRLSZNV.js +79 -0
- package/dist/chunk-C3DH3NCY.js +2773 -0
- package/dist/chunk-C3KCMAJP.js +756 -0
- package/dist/chunk-C7AGUJ5K.js +267 -0
- package/dist/chunk-CBSWKQCX.js +342 -0
- package/dist/chunk-CE5OZBYY.js +21 -0
- package/dist/chunk-CFCVYHSW.js +373 -0
- package/dist/chunk-CHA2HDE5.js +126 -0
- package/dist/chunk-CIHWPGS5.js +146 -0
- package/dist/chunk-CJBSZX3F.js +127 -0
- package/dist/chunk-CLA6QIJM.js +43 -0
- package/dist/chunk-CPSVQR2I.js +365 -0
- package/dist/chunk-CRPRVNQ4.js +254 -0
- package/dist/chunk-CSIE4Y7C.js +1093 -0
- package/dist/chunk-CSOPSYDY.js +142 -0
- package/dist/chunk-CSXLLEGB.js +205 -0
- package/dist/chunk-CTDLERWU.js +293 -0
- package/dist/chunk-CULBXMSK.js +110 -0
- package/dist/chunk-D2M2Y5ID.js +21 -0
- package/dist/chunk-D37WY7SH.js +1060 -0
- package/dist/chunk-D4VJFCGZ.js +89 -0
- package/dist/chunk-D6WTZMZB.js +48 -0
- package/dist/chunk-DBHOWDUH.js +976 -0
- package/dist/chunk-DCACX7BV.js +19364 -0
- package/dist/chunk-DFHX4XYA.js +128 -0
- package/dist/chunk-DIKBRRKE.js +176 -0
- package/dist/chunk-DJG5RIOR.js +9 -0
- package/dist/chunk-DNIOIISW.js +616 -0
- package/dist/chunk-DOA5G7IA.js +315 -0
- package/dist/chunk-DP7FKP6W.js +855 -0
- package/dist/chunk-DS2JZ677.js +79 -0
- package/dist/chunk-DSRLVYBS.js +82 -0
- package/dist/chunk-EAEVKNJA.js +209 -0
- package/dist/chunk-EEUESN3T.js +575 -0
- package/dist/chunk-EJ4LUU5Y.js +73 -0
- package/dist/chunk-EJIWTPSZ.js +1063 -0
- package/dist/chunk-EJVCDTAN.js +116 -0
- package/dist/chunk-EKLUBDBQ.js +627 -0
- package/dist/chunk-EN62WLFD.js +849 -0
- package/dist/chunk-ENYRCL43.js +26 -0
- package/dist/chunk-EP22ZMFO.js +273 -0
- package/dist/chunk-EP4SVAVI.js +87 -0
- package/dist/chunk-EPAMVGI3.js +1562 -0
- package/dist/chunk-EPRMH6HO.js +24 -0
- package/dist/chunk-ES6NWJ36.js +4057 -0
- package/dist/chunk-ETA2K4KI.js +30 -0
- package/dist/chunk-ETAD4NKD.js +31 -0
- package/dist/chunk-EUWIIDQ7.js +93 -0
- package/dist/chunk-EVE3OD2W.js +141 -0
- package/dist/chunk-EXA26FFC.js +459 -0
- package/dist/chunk-EXSPAA35.js +244 -0
- package/dist/chunk-F55YABKV.js +258 -0
- package/dist/chunk-F5DNGU5W.js +27 -0
- package/dist/chunk-F622MJYV.js +103 -0
- package/dist/chunk-F6NIQD74.js +5111 -0
- package/dist/chunk-FAWJTC34.js +43 -0
- package/dist/chunk-FAZBRHGG.js +47 -0
- package/dist/chunk-FIEUSGNJ.js +39 -0
- package/dist/chunk-FKCG7K6H.js +1146 -0
- package/dist/chunk-FOVVXV45.js +229 -0
- package/dist/chunk-FRBPKBFE.js +30 -0
- package/dist/chunk-FSA5BPFI.js +268 -0
- package/dist/chunk-FSJ5TTZ3.js +29 -0
- package/dist/chunk-FT7SGLXT.js +193 -0
- package/dist/chunk-FUUVZZUB.js +62 -0
- package/dist/chunk-FYMRVUNZ.js +1697 -0
- package/dist/chunk-FYTAA5FG.js +162 -0
- package/dist/chunk-G3VB2UCZ.js +3892 -0
- package/dist/chunk-G6OIMVXH.js +405 -0
- package/dist/chunk-G7PQCXVH.js +228 -0
- package/dist/chunk-GAB6UW52.js +1087 -0
- package/dist/chunk-GAFJEYLK.js +29 -0
- package/dist/chunk-GC4CRMTS.js +642 -0
- package/dist/chunk-GFHSIWHL.js +5297 -0
- package/dist/chunk-GI5M67YA.js +735 -0
- package/dist/chunk-GIJWHUWF.js +191 -0
- package/dist/chunk-GO6DRECI.js +1 -0
- package/dist/chunk-GOFVBTMN.js +314 -0
- package/dist/chunk-GQIP72ZJ.js +13 -0
- package/dist/chunk-GQXLXRFA.js +28 -0
- package/dist/chunk-GT6HFKJB.js +48 -0
- package/dist/chunk-GVJGSSKM.js +174 -0
- package/dist/chunk-GWHGTG37.js +36 -0
- package/dist/chunk-GZAJHLKO.js +18 -0
- package/dist/chunk-GZK62I3N.js +314 -0
- package/dist/chunk-H3HGMISG.js +483 -0
- package/dist/chunk-H3ISZJMJ.js +403 -0
- package/dist/chunk-H4HXVWEC.js +9 -0
- package/dist/chunk-H6MJGKAW.js +120 -0
- package/dist/chunk-HBTTGVR5.js +353 -0
- package/dist/chunk-HBZ322WZ.js +35 -0
- package/dist/chunk-HEP3ILP4.js +34 -0
- package/dist/chunk-HGFXODKO.js +106 -0
- package/dist/chunk-HHWDTB6S.js +59 -0
- package/dist/chunk-HKO45NLZ.js +286 -0
- package/dist/chunk-HLVTEA6A.js +89 -0
- package/dist/chunk-HS3SY6HN.js +160 -0
- package/dist/chunk-HT5OCGKN.js +899 -0
- package/dist/chunk-HXIIEMGF.js +78 -0
- package/dist/chunk-I56TH7VM.js +46 -0
- package/dist/chunk-I6FN3R5D.js +352 -0
- package/dist/chunk-I7SCBHJN.js +655 -0
- package/dist/chunk-IJM4GKAT.js +529 -0
- package/dist/chunk-IMEYU36R.js +344 -0
- package/dist/chunk-INJ3SS6A.js +936 -0
- package/dist/chunk-IUKOPCCE.js +441 -0
- package/dist/chunk-IVEPZQJO.js +33 -0
- package/dist/chunk-IVZEONFC.js +43 -0
- package/dist/chunk-IWBHRSG7.js +936 -0
- package/dist/chunk-IYY3HQAD.js +484 -0
- package/dist/chunk-J2ICMYDA.js +48 -0
- package/dist/chunk-J2QCFLUN.js +505 -0
- package/dist/chunk-J5HM6V5P.js +1039 -0
- package/dist/chunk-J6NZX6QH.js +398 -0
- package/dist/chunk-JBBB2Y47.js +432 -0
- package/dist/chunk-JDCZQZU7.js +42 -0
- package/dist/chunk-JEDNXGSS.js +169 -0
- package/dist/chunk-JHP7OT6K.js +89 -0
- package/dist/chunk-JLS65NUQ.js +14 -0
- package/dist/chunk-JNMWYMC6.js +38 -0
- package/dist/chunk-JNSTWNNW.js +25 -0
- package/dist/chunk-JOSK6GEU.js +9564 -0
- package/dist/chunk-JQUMSIGC.js +100 -0
- package/dist/chunk-JVHGMURQ.js +1106 -0
- package/dist/chunk-JYXS47FQ.js +951 -0
- package/dist/chunk-K2ZMW2Z5.js +2147 -0
- package/dist/chunk-K7FAFORM.js +14 -0
- package/dist/chunk-KBJXX3ON.js +333 -0
- package/dist/chunk-KHFKVQWY.js +486 -0
- package/dist/chunk-KHMEI3DQ.js +173 -0
- package/dist/chunk-KHW3UD7B.js +69 -0
- package/dist/chunk-KKQKWAMF.js +365 -0
- package/dist/chunk-KOKXJV2U.js +455 -0
- package/dist/chunk-KQ4NGOJI.js +14 -0
- package/dist/chunk-KQYQOXMS.js +342 -0
- package/dist/chunk-KTMW65UX.js +14 -0
- package/dist/chunk-KUEWV2JH.js +593 -0
- package/dist/chunk-KXYDV3HP.js +1523 -0
- package/dist/chunk-KZ4JMGZ5.js +96 -0
- package/dist/chunk-KZWGBUIO.js +2659 -0
- package/dist/chunk-L2CBG5IX.js +1892 -0
- package/dist/chunk-L2S235CU.js +314 -0
- package/dist/chunk-L32WD57F.js +98 -0
- package/dist/chunk-LDJCKAJP.js +123 -0
- package/dist/chunk-LDWNBEN7.js +541 -0
- package/dist/chunk-LJVH57G2.js +241 -0
- package/dist/chunk-LPQ7NZEN.js +209 -0
- package/dist/chunk-LRGH3CCV.js +148 -0
- package/dist/chunk-LULOGMMM.js +1133 -0
- package/dist/chunk-LWGKN2GY.js +8284 -0
- package/dist/chunk-LX4F24ZH.js +157 -0
- package/dist/chunk-M4BUEXXF.js +839 -0
- package/dist/chunk-M6UHOC4I.js +553 -0
- package/dist/chunk-MCBNWZNO.js +657 -0
- package/dist/chunk-MEMSY6VY.js +223 -0
- package/dist/chunk-MHLEZQQI.js +145 -0
- package/dist/chunk-MJ6WNSIX.js +192 -0
- package/dist/chunk-MKASIKWZ.js +442 -0
- package/dist/chunk-MNOVBYFU.js +60 -0
- package/dist/chunk-MO2BYAAF.js +2896 -0
- package/dist/chunk-MP6P7Y2A.js +180 -0
- package/dist/chunk-MQ4TFJAG.js +3365 -0
- package/dist/chunk-MT2WAIR3.js +131 -0
- package/dist/chunk-MTU7VTNN.js +1122 -0
- package/dist/chunk-MULMXX4V.js +150 -0
- package/dist/chunk-MW2DWWVA.js +147 -0
- package/dist/chunk-MY3ZPUN4.js +151 -0
- package/dist/chunk-MYLH2S4G.js +64 -0
- package/dist/chunk-MZ5WYKNA.js +28 -0
- package/dist/chunk-N3Q2JNPV.js +249 -0
- package/dist/chunk-N5DX4JAK.js +12 -0
- package/dist/chunk-NAINGKHF.js +35 -0
- package/dist/chunk-NEQUQHOX.js +223 -0
- package/dist/chunk-NHNPEZS4.js +1408 -0
- package/dist/chunk-NHTIXJCR.js +17 -0
- package/dist/chunk-NKLPMBNV.js +1154 -0
- package/dist/chunk-NMVZ5YES.js +199 -0
- package/dist/chunk-NRFRY3GE.js +256 -0
- package/dist/chunk-NTD6CSI6.js +1266 -0
- package/dist/chunk-NUO7B3SH.js +318 -0
- package/dist/chunk-NVOHIJKG.js +1319 -0
- package/dist/chunk-NXH3RX7O.js +523 -0
- package/dist/chunk-NXZ3DURF.js +257 -0
- package/dist/chunk-O26L6F7F.js +209 -0
- package/dist/chunk-O5RRIUEP.js +124 -0
- package/dist/chunk-O5X6BKAO.js +10 -0
- package/dist/chunk-O6ZQUVTR.js +31 -0
- package/dist/chunk-O7FE75QZ.js +306 -0
- package/dist/chunk-OC7Z6AJQ.js +81 -0
- package/dist/chunk-OH7IEZ63.js +307 -0
- package/dist/chunk-OI734GRS.js +115 -0
- package/dist/chunk-OJBH62DK.js +684 -0
- package/dist/chunk-OKJLVSTJ.js +247 -0
- package/dist/chunk-OMX5VL43.js +79 -0
- package/dist/chunk-ONHAMBN6.js +12 -0
- package/dist/chunk-ONYPLIVE.js +753 -0
- package/dist/chunk-OSK7QWPD.js +637 -0
- package/dist/chunk-OTXLMJKP.js +438 -0
- package/dist/chunk-OV5PKQMA.js +213 -0
- package/dist/chunk-OXK5HA4B.js +31 -0
- package/dist/chunk-OYDWFQA4.js +272 -0
- package/dist/chunk-OZAUKWHB.js +22 -0
- package/dist/chunk-P5P2EKGH.js +94 -0
- package/dist/chunk-P6SSWAKY.js +29 -0
- package/dist/chunk-P7CQGPLS.js +30 -0
- package/dist/chunk-P7RVCHQV.js +197 -0
- package/dist/chunk-PEBWDYIW.js +726 -0
- package/dist/chunk-PFCXFO7A.js +9193 -0
- package/dist/chunk-PFLDWMX6.js +168 -0
- package/dist/chunk-PHZGLQSK.js +15883 -0
- package/dist/chunk-PNFTPNSR.js +20 -0
- package/dist/chunk-PPHXX4W7.js +175 -0
- package/dist/chunk-PPZESPJT.js +262 -0
- package/dist/chunk-PRDHI2L5.js +296 -0
- package/dist/chunk-PSTKWHHN.js +32 -0
- package/dist/chunk-PV53ODOT.js +555 -0
- package/dist/chunk-PVJBTI7P.js +24 -0
- package/dist/chunk-PXKERBKX.js +100 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-Q3DHEZA5.js +85 -0
- package/dist/chunk-Q5RZDVQK.js +204 -0
- package/dist/chunk-Q64IR2Z2.js +4933 -0
- package/dist/chunk-Q6Z5UGPL.js +398 -0
- package/dist/chunk-QAMAV4DT.js +627 -0
- package/dist/chunk-QBWF4444.js +112 -0
- package/dist/chunk-QDKYT4CI.js +22805 -0
- package/dist/chunk-QFLBRWCJ.js +126 -0
- package/dist/chunk-QILAQACE.js +107 -0
- package/dist/chunk-QJ6OEH4K.js +3683 -0
- package/dist/chunk-QK3NLYTV.js +320 -0
- package/dist/chunk-QOFLUS24.js +535 -0
- package/dist/chunk-QOIASNEJ.js +98 -0
- package/dist/chunk-QP4UTSOV.js +3587 -0
- package/dist/chunk-QP5ST7RI.js +904 -0
- package/dist/chunk-QS5AGRZN.js +167 -0
- package/dist/chunk-QTAOU53N.js +107 -0
- package/dist/chunk-QTCLJHLZ.js +351 -0
- package/dist/chunk-QTOLTG4L.js +119 -0
- package/dist/chunk-QWDV4OSL.js +142 -0
- package/dist/chunk-QWMQ74KD.js +508 -0
- package/dist/chunk-QX6LOMMH.js +158 -0
- package/dist/chunk-QXBKIHY7.js +238 -0
- package/dist/chunk-QXBKTJT6.js +270 -0
- package/dist/chunk-QYQOVOLR.js +196 -0
- package/dist/chunk-R2CKS6WT.js +73 -0
- package/dist/chunk-R2TIYG7U.js +68 -0
- package/dist/chunk-R2W3LESH.js +465 -0
- package/dist/chunk-R5EXHMUN.js +100 -0
- package/dist/chunk-RBBTBCHX.js +289 -0
- package/dist/chunk-RBKLOUXA.js +121 -0
- package/dist/chunk-RCP2Y6DQ.js +86 -0
- package/dist/chunk-RCYEJSD5.js +260 -0
- package/dist/chunk-RFDVSI4N.js +134 -0
- package/dist/chunk-RGJU63FV.js +1717 -0
- package/dist/chunk-RI4EX2QE.js +18 -0
- package/dist/chunk-RIMARPCF.js +152 -0
- package/dist/chunk-RJ6RSNT6.js +42 -0
- package/dist/chunk-RNI2GUIF.js +131 -0
- package/dist/chunk-RPHUWJ3K.js +264 -0
- package/dist/chunk-RPIMAMV7.js +361 -0
- package/dist/chunk-RQFX6YRN.js +49 -0
- package/dist/chunk-RRC5BL7B.js +285 -0
- package/dist/chunk-RSYTSBOO.js +79 -0
- package/dist/chunk-RWQQIKIC.js +35 -0
- package/dist/chunk-RZUBOZH2.js +373 -0
- package/dist/chunk-S2E632FQ.js +380 -0
- package/dist/chunk-S2VQCZO4.js +22 -0
- package/dist/chunk-S2XIMQJQ.js +681 -0
- package/dist/chunk-S47ISY27.js +183 -0
- package/dist/chunk-S6I4KISU.js +142 -0
- package/dist/chunk-S6TAFQI5.js +2403 -0
- package/dist/chunk-SBBNT5ZJ.js +27 -0
- package/dist/chunk-SDJV2DTQ.js +491 -0
- package/dist/chunk-SDPIFNLD.js +33 -0
- package/dist/chunk-SF6YK3JI.js +835 -0
- package/dist/chunk-SK3ZFONO.js +976 -0
- package/dist/chunk-SKTFRFQ7.js +1775 -0
- package/dist/chunk-SNGM452K.js +2002 -0
- package/dist/chunk-STW7OFOA.js +581 -0
- package/dist/chunk-SU6UFUQY.js +1351 -0
- package/dist/chunk-SVJM3LJA.js +27 -0
- package/dist/chunk-SVUNZOPG.js +129 -0
- package/dist/chunk-T5XLUYV3.js +34 -0
- package/dist/chunk-T7E5JS6N.js +57 -0
- package/dist/chunk-TA3N5MMO.js +450 -0
- package/dist/chunk-TAJPCXSB.js +13 -0
- package/dist/chunk-TDEMDRN2.js +1639 -0
- package/dist/chunk-TDSEX5CF.js +24 -0
- package/dist/chunk-TGCVL74Y.js +28 -0
- package/dist/chunk-TGXXYDL4.js +1012 -0
- package/dist/chunk-TIKTYUJO.js +296 -0
- package/dist/chunk-TIZAJD4M.js +6029 -0
- package/dist/chunk-TLSEZZCG.js +5549 -0
- package/dist/chunk-TMBDRHAX.js +19 -0
- package/dist/chunk-TRURQUBP.js +1217 -0
- package/dist/chunk-TSQ256N5.js +152 -0
- package/dist/chunk-TUQMMFEQ.js +2244 -0
- package/dist/chunk-U424MJLC.js +81 -0
- package/dist/chunk-U4DRS6ZW.js +11 -0
- package/dist/chunk-U5KS22IN.js +204 -0
- package/dist/chunk-UAPHFJPN.js +673 -0
- package/dist/chunk-UB7LQITD.js +1040 -0
- package/dist/chunk-UBVRHGAZ.js +237 -0
- package/dist/chunk-UDNNAQN5.js +98 -0
- package/dist/chunk-UJP3XM54.js +342 -0
- package/dist/chunk-UJYDH2MW.js +305 -0
- package/dist/chunk-UKMPASIC.js +399 -0
- package/dist/chunk-UKUL3EHK.js +763 -0
- package/dist/chunk-UPHU64NB.js +1327 -0
- package/dist/chunk-URMSZXAD.js +43 -0
- package/dist/chunk-US3RT6CY.js +525 -0
- package/dist/chunk-UTDEOPKV.js +30 -0
- package/dist/chunk-UUUDKV7N.js +13 -0
- package/dist/chunk-UVKWU3SM.js +39 -0
- package/dist/chunk-V2TVPO3X.js +521 -0
- package/dist/chunk-V3KLVK7B.js +398 -0
- package/dist/chunk-V3YFFHDR.js +17 -0
- package/dist/chunk-VAG6GUBR.js +1162 -0
- package/dist/chunk-VBENAHDA.js +1814 -0
- package/dist/chunk-VBNCKCCI.js +16 -0
- package/dist/chunk-VCGSWN5M.js +1300 -0
- package/dist/chunk-VE2O2I7M.js +115 -0
- package/dist/chunk-VIFHYTI5.js +31 -0
- package/dist/chunk-VJER3FUS.js +5080 -0
- package/dist/chunk-VLMDM56Q.js +268 -0
- package/dist/chunk-VMFZEVVX.js +99 -0
- package/dist/chunk-VNDPQVUZ.js +1853 -0
- package/dist/chunk-VSPJRLGA.js +4783 -0
- package/dist/chunk-VSWC5ZXI.js +103 -0
- package/dist/chunk-VYI4DSZP.js +2017 -0
- package/dist/chunk-W4BAIQ6L.js +1212 -0
- package/dist/chunk-W7VQAL2K.js +2203 -0
- package/dist/chunk-WEI3ZDZH.js +33 -0
- package/dist/chunk-WEIUS5NT.js +26 -0
- package/dist/chunk-WEW7UFWE.js +546 -0
- package/dist/chunk-WGQAXLNA.js +384 -0
- package/dist/chunk-WJAL4JL3.js +206 -0
- package/dist/chunk-WKFOJ5ZG.js +141 -0
- package/dist/chunk-WMWQEFLN.js +2177 -0
- package/dist/chunk-WNECKKO2.js +154 -0
- package/dist/chunk-WPKLYOAM.js +195 -0
- package/dist/chunk-WSH37YQN.js +243 -0
- package/dist/chunk-WV3KQDPE.js +84 -0
- package/dist/chunk-WZFC4V4U.js +389 -0
- package/dist/chunk-XCOIBNET.js +13 -0
- package/dist/chunk-XDM65LBX.js +53 -0
- package/dist/chunk-XGU6PBO5.js +645 -0
- package/dist/chunk-XHOI4V62.js +43 -0
- package/dist/chunk-XIBVFMLQ.js +6858 -0
- package/dist/chunk-XJ2E7YEJ.js +117 -0
- package/dist/chunk-XON4ZCYX.js +69 -0
- package/dist/chunk-XQPEWJPI.js +127 -0
- package/dist/chunk-XSJTIFUY.js +31 -0
- package/dist/chunk-XT7OVWM3.js +64 -0
- package/dist/chunk-XTXYIISX.js +1104 -0
- package/dist/chunk-XV7NZL4B.js +57 -0
- package/dist/chunk-XWIZ6B5S.js +109 -0
- package/dist/chunk-XWLIKOBX.js +240 -0
- package/dist/chunk-XZOXEIN4.js +156 -0
- package/dist/chunk-XZRS7I7W.js +3673 -0
- package/dist/chunk-Y4ZDDHB6.js +44 -0
- package/dist/chunk-Y733RB7T.js +194 -0
- package/dist/chunk-YBHUB4XR.js +14931 -0
- package/dist/chunk-YKC75XK4.js +147 -0
- package/dist/chunk-YKMXFVK7.js +27 -0
- package/dist/chunk-YO5BAJ55.js +225 -0
- package/dist/chunk-YPDCLXNZ.js +568 -0
- package/dist/chunk-YSQPGVFK.js +116 -0
- package/dist/chunk-YTVVTIWJ.js +716 -0
- package/dist/chunk-YVCMDVBB.js +698 -0
- package/dist/chunk-YYTOA6DP.js +114 -0
- package/dist/chunk-Z5WGNULV.js +88 -0
- package/dist/chunk-Z6NGVVXG.js +66 -0
- package/dist/chunk-Z7CDQNH3.js +20 -0
- package/dist/chunk-ZH4G3FU5.js +187 -0
- package/dist/chunk-ZJB6SQPA.js +257 -0
- package/dist/chunk-ZL6E4HMY.js +42 -0
- package/dist/chunk-ZMLOC3DW.js +62 -0
- package/dist/chunk-ZORW64QH.js +101 -0
- package/dist/chunk-ZVVD2XGV.js +1369 -0
- package/dist/cli-utils-ER33ODC5.js +31 -0
- package/dist/cli-validation-6CHPTANV.js +146 -0
- package/dist/commit-utils-3STAY7C7.js +49 -0
- package/dist/compatibility-notice-IHNXR2JR.js +21 -0
- package/dist/compete-config-resolver-V3GDNJMM.js +125 -0
- package/dist/compete-results-XUM3PJHS.js +318 -0
- package/dist/competition-outcome-tracker-NWSMVUPG.js +62 -0
- package/dist/config-4HHE4OIK.js +238 -0
- package/dist/config-D6YAZASH.js +10 -0
- package/dist/config-MIPRDYYV.js +46 -0
- package/dist/config-audit-GA5DCUAI.js +371 -0
- package/dist/config-explain-4LMO556H.js +71 -0
- package/dist/config-loader-RGP634PC.js +51 -0
- package/dist/config-manager-J2UTO635.js +114 -0
- package/dist/config-merger-TVUJBZTS.js +14 -0
- package/dist/config-validator-H4ZVIE56.js +122 -0
- package/dist/cost-HSIV5U2Y.js +85 -0
- package/dist/data-migration-state-OAUL2WPQ.js +35 -0
- package/dist/db-migrator-NUOW5NKR.js +34 -0
- package/dist/default-paths-UILB62BN.js +49 -0
- package/dist/discovery-V6GYUJUC.js +53 -0
- package/dist/doctor-BBSMCDWE.js +271 -0
- package/dist/doctor-context-blocks-LPY75VZA.js +231 -0
- package/dist/doctor-instructions-import-JXHDDOE5.js +70 -0
- package/dist/doctor-purpose-6YJOXPBE.js +30 -0
- package/dist/domain-analyzer-S35ABUNA.js +48 -0
- package/dist/ensure-initialized-Q6PEU55O.js +78 -0
- package/dist/entry.js +922 -0
- package/dist/error-parser-core-MZFMFANN.js +70 -0
- package/dist/evaluation-context-GQBYDAEV.js +63 -0
- package/dist/evidence-plan-resolver-5FUAP3SA.js +111 -0
- package/dist/execution-data-writer-YCG5UH37.js +72 -0
- package/dist/execution-policy-applier-PWZM5LNA.js +63 -0
- package/dist/execution-preflight-DASJWWQF.js +223 -0
- package/dist/execution-roles-KNSNNB2D.js +112 -0
- package/dist/exit-code-error-QIY5DOKF.js +18 -0
- package/dist/external-temp-cleanup-CAW7LQ6R.js +360 -0
- package/dist/factory-YCYCB7AE.js +209 -0
- package/dist/file-utils-ZQYNBQBW.js +45 -0
- package/dist/flywheel-allowlist-revert-H22HA6JE.js +21 -0
- package/dist/flywheel-autoloop-executor-PDOASJEZ.js +316 -0
- package/dist/flywheel-autoloop-unverified-TOKYFCDC.js +36 -0
- package/dist/flywheel-competition-executor-YJUMMEJO.js +320 -0
- package/dist/flywheel-executor-JWU43KAY.js +437 -0
- package/dist/flywheel-git-isolation-FQ2TRWMB.js +56 -0
- package/dist/flywheel-manifest-HDPNMWWF.js +114 -0
- package/dist/flywheel-model-defaults-UHAKTZT3.js +110 -0
- package/dist/flywheel-preflight-III2C7TH.js +163 -0
- package/dist/flywheel-resume-2O45MS7Y.js +31 -0
- package/dist/flywheel-resume-execution-lease-P2BK257J.js +59 -0
- package/dist/flywheel-safety-AVAVFXIJ.js +19 -0
- package/dist/flywheel-scope-decision-ALJUUNGG.js +14 -0
- package/dist/get-telemetry-logger-MPDVO2JA.js +155 -0
- package/dist/git-message-style-KCXGMTDT.js +104 -0
- package/dist/guidance-profile-config-G3K5YQOO.js +113 -0
- package/dist/guidance-profile-renderer-TX4TNDFL.js +23 -0
- package/dist/identity-XLQJ4YJF.js +25 -0
- package/dist/index-query-6NUY4FKX.js +37 -0
- package/dist/index.js +85588 -0
- package/dist/indexer-DL54CM3K.js +44 -0
- package/dist/init-OUZ72344.js +245 -0
- package/dist/instructions-import-offer-NSYXSITC.js +363 -0
- package/dist/instructions-run-NBII7W36.js +114 -0
- package/dist/interrupted-work-E4TLKJLE.js +43 -0
- package/dist/invoke-provider-auth-NEWEIHCI.js +38 -0
- package/dist/judge-scoring.json +64 -0
- package/dist/lab-mode-YXQ2Y3NG.js +44 -0
- package/dist/lab-utils-5QAMDJR5.js +29 -0
- package/dist/linux-host-class-YDWQX65O.js +31 -0
- package/dist/llm-judge-executor-OJSNCTFJ.js +179 -0
- package/dist/local-ci-config-VZ4WWDT5.js +48 -0
- package/dist/local-executor-DCMDDRX2.js +280 -0
- package/dist/logger-5KNKS3O4.js +154 -0
- package/dist/matrix-prompt-builder-4ZBOGZSB.js +527 -0
- package/dist/matrix-result-parser-EZJM4YXP.js +14 -0
- package/dist/merge-batch-RTEEMVDB.js +313 -0
- package/dist/merge-batch-members-VIWGVRHP.js +24 -0
- package/dist/merge-queue-TIIUSOY6.js +126 -0
- package/dist/merge-queue-trust-DUNZ4J65.js +21 -0
- package/dist/metadata-UKSMWM6J.js +29 -0
- package/dist/model-catalog-readiness-R5KJBP5M.js +202 -0
- package/dist/model-invocations-db-XTUPPQ34.js +70 -0
- package/dist/model-resolver-JFZ2MHOJ.js +39 -0
- package/dist/model-resolver-SCQ57KAQ.js +217 -0
- package/dist/model-roles-D3OR4NAH.js +110 -0
- package/dist/monitor-F4SIU5G2.js +96 -0
- package/dist/nested-worktrees-2WUWQ75N.js +23 -0
- package/dist/next-S3IRLVER.js +96 -0
- package/dist/next-UKPFRXOO.js +148 -0
- package/dist/opportunistic-TL4S26VX.js +86 -0
- package/dist/optimization-config-resolver-NAEIYU6A.js +148 -0
- package/dist/package-HJR4QJT4.js +10 -0
- package/dist/parse-git-status-7PIYFPS2.js +21 -0
- package/dist/path-security-5WJSY56G.js +41 -0
- package/dist/paths-JUI7C4KU.js +45 -0
- package/dist/plan-backlog-list-fast-SSTQL5XP.js +89 -0
- package/dist/plan-backlog-show-fast-PFRAQ3JB.js +114 -0
- package/dist/plan-sprint-list-fast-HD2KBZSY.js +110 -0
- package/dist/plan-sprint-status-fast-YFYH7WQF.js +116 -0
- package/dist/plan-task-status-fast-JU5PNLUU.js +114 -0
- package/dist/plan-to-flywheel-PY5MSY2H.js +529 -0
- package/dist/preflight-PJHGTJNZ.js +12 -0
- package/dist/process-registry-B4ZUCN7T.js +28 -0
- package/dist/process-scanner-TU3QHWVB.js +23 -0
- package/dist/processes-6FHVGT72.js +28 -0
- package/dist/processes-json-fast-YWTMUWXB.js +72 -0
- package/dist/profile-HWTC56SG.js +209 -0
- package/dist/project-runtime-paths-2UQNG5Y4.js +41 -0
- package/dist/protected-branches-N36LDBFY.js +71 -0
- package/dist/provider-aware-resource-manager-YTFAHNGJ.js +40 -0
- package/dist/provider-matrix-2KO2V5OM.js +214 -0
- package/dist/provider-matrix-renderer-MEC3PER7.js +139 -0
- package/dist/provider-output-forwarding-2AHL7YMA.js +26 -0
- package/dist/provider-registry-WCZ65QHC.js +136 -0
- package/dist/provider-temp-cleanup-IUNPJCZF.js +14 -0
- package/dist/prune-engine-EOQVWEP6.js +448 -0
- package/dist/publication-turn-S42RZTQF.js +44 -0
- package/dist/quality-gate-JQMVCKOO.js +72 -0
- package/dist/quickstart-3O6FRCFB.js +105 -0
- package/dist/readiness-GW6ABRHB.js +139 -0
- package/dist/readiness-KFZCXDTT.js +215 -0
- package/dist/registry-7XG376SY.js +217 -0
- package/dist/repair-helpers-TTV5FEF4.js +117 -0
- package/dist/repo-root-YG6MQZDW.js +28 -0
- package/dist/resolution-engine-FFEK7HQ2.js +187 -0
- package/dist/resolve-provider-cli-ZEXVZKET.js +44 -0
- package/dist/restore-telemetry-db-E7BR5PO7.js +459 -0
- package/dist/routing-events-AW6SRZ6G.js +13 -0
- package/dist/routing-history-store-FMDDQL6W.js +39 -0
- package/dist/routing-planner-C6OHO3EY.js +221 -0
- package/dist/runner-KHDNQ5KU.js +1194 -0
- package/dist/runner-PIS2BW7Y.js +1801 -0
- package/dist/safety-E3JJVSFL.js +67 -0
- package/dist/safety-stanza-HE6GXP4G.js +49 -0
- package/dist/sandbox-7LBZC5PE.js +72 -0
- package/dist/sandbox-ASWCDYZL.js +80 -0
- package/dist/schema-extensions.sql +234 -0
- package/dist/security-JI22TBEB.js +17 -0
- package/dist/setup-bb-plugin-FQXLA76Y.js +531 -0
- package/dist/setup-claude-code-NF4ZSHVE.js +197 -0
- package/dist/setup-temp-cleanup-2APZ4HMA.js +29 -0
- package/dist/shared-utils-34HJZ6JX.js +40 -0
- package/dist/simple-artifact-goal-MQLDDMMX.js +29 -0
- package/dist/sprint-N7JFTEGL.js +403 -0
- package/dist/sprint-bridge-KJXIBNRJ.js +117 -0
- package/dist/sprint-completion-dependents-34SR7JVL.js +43 -0
- package/dist/sprint-execution-service-A6JPUBWY.js +376 -0
- package/dist/sprint-manager-MU2ZUWN2.js +140 -0
- package/dist/sqlite-timeout-config-U2CT4LKU.js +13 -0
- package/dist/sqlite-wrapper-FSGJ2QEW.js +19 -0
- package/dist/stale-cleanup-orchestrator-4X6324VF.js +71 -0
- package/dist/storage-access-I3V5LER7.js +31 -0
- package/dist/store-XVG64ZR2.js +25 -0
- package/dist/task-classifier-MN2DYE5R.js +558 -0
- package/dist/task-list-fast-7AT6LTTA.js +112 -0
- package/dist/task-manager-LHPBBRRE.js +136 -0
- package/dist/task-report-OLPAWBTK.js +64 -0
- package/dist/task-type-detector-6RG3YNZF.js +27 -0
- package/dist/task-type-resolver-EQHOUIHT.js +64 -0
- package/dist/telemetry-5VYSK772.js +212 -0
- package/dist/telemetry-health-tracker-4GFW2EMP.js +12 -0
- package/dist/telemetry-path-resolver-H3NFHHQY.js +34 -0
- package/dist/telemetry-reliability-URJDTNPZ.js +76 -0
- package/dist/transports-NREZQTJK.js +106 -0
- package/dist/unified-cost-tracker-5MTBJ2CL.js +59 -0
- package/dist/unified-state-cleanup-GGAXLHXF.js +292 -0
- package/dist/universal-cost-calculator-JTFEJVWK.js +70 -0
- package/dist/user-agents-QLIGPLP2.js +30 -0
- package/dist/variant-execution-I4ZZUAWY.js +319 -0
- package/dist/variant-opt-parser-JHCXKY2K.js +251 -0
- package/dist/variant-request-input-PL37N3AN.js +11 -0
- package/dist/variant-state-cleanup-KHMXRBZN.js +287 -0
- package/dist/variant-worker-COB5YTJX.js +4517 -0
- package/dist/variant-worker.js +26 -0
- package/dist/variants-XGDSXYG3.js +267 -0
- package/dist/verification-command-YSPU4VBH.js +66 -0
- package/dist/verify-command-timeout-DQUYH33Z.js +11 -0
- package/dist/verify-commands-LOHMOFKC.js +65 -0
- package/dist/warning-JSKSFKBT.js +13 -0
- package/dist/work-edge-K65NHVWY.js +50 -0
- package/dist/work-item-writer-KY5ZWZWW.js +30 -0
- package/dist/worker-JNXXEIT6.js +1504 -0
- package/dist/worker.js +21 -0
- package/dist/workspace-tree-identity-JO5PSKTW.js +52 -0
- package/dist/worktree-environment-WTVABAQW.js +64 -0
- package/dist/worktree-metrics-VZRQI26T.js +66 -0
- package/dist/writeback-TQFQBJNU.js +50 -0
- package/docs/CLI_REFERENCE.md +8287 -0
- package/docs/PROVIDER_SETUP.md +1737 -0
- package/docs/README.md +96 -0
- package/docs/TROUBLESHOOTING.md +2209 -0
- package/docs/getting-started/QUICK_START.md +260 -0
- package/docs/getting-started/README.md +198 -0
- package/docs/getting-started/SETUP.md +25 -0
- package/docs/reference/AGENT_CONTEXT.md +84 -0
- package/docs/reference/DELIVERY_ONBOARDING.md +198 -0
- package/docs/reference/PROVIDER_RELEASE_TIERS.md +34 -0
- package/docs/reference/SECURITY.md +291 -0
- package/docs/reference/TELEMETRY_PRIVACY.md +259 -0
- package/integrations/bb-plugin-build/README.md +391 -0
- package/integrations/bb-plugin-build/app.css +431 -0
- package/integrations/bb-plugin-build/app.tsx +6210 -0
- package/integrations/bb-plugin-build/package.json +45 -0
- package/integrations/bb-plugin-build/server.ts +488 -0
- package/integrations/bb-plugin-build/src/adapter.ts +3672 -0
- package/integrations/bb-plugin-build/src/backlog-authoring-model.ts +150 -0
- package/integrations/bb-plugin-build/src/backlog-authoring-schema.ts +458 -0
- package/integrations/bb-plugin-build/src/backlog-authoring-service.ts +467 -0
- package/integrations/bb-plugin-build/src/backlog-authoring-view.ts +1025 -0
- package/integrations/bb-plugin-build/src/command-evidence-schema.ts +13 -0
- package/integrations/bb-plugin-build/src/competition-defaults-schema.ts +122 -0
- package/integrations/bb-plugin-build/src/competition-defaults-service.ts +105 -0
- package/integrations/bb-plugin-build/src/competition-defaults-view.ts +138 -0
- package/integrations/bb-plugin-build/src/contract.ts +718 -0
- package/integrations/bb-plugin-build/src/execution-activity-view.ts +98 -0
- package/integrations/bb-plugin-build/src/finalize-model.ts +205 -0
- package/integrations/bb-plugin-build/src/finalize-schema.ts +150 -0
- package/integrations/bb-plugin-build/src/finalize-service.ts +330 -0
- package/integrations/bb-plugin-build/src/finalize-view.ts +159 -0
- package/integrations/bb-plugin-build/src/judge-operations-readback.ts +303 -0
- package/integrations/bb-plugin-build/src/judge-operations-schema.ts +33 -0
- package/integrations/bb-plugin-build/src/judge-operations-view.ts +459 -0
- package/integrations/bb-plugin-build/src/model.ts +1318 -0
- package/integrations/bb-plugin-build/src/monitor-service.ts +233 -0
- package/integrations/bb-plugin-build/src/panel-read-ux.ts +97 -0
- package/integrations/bb-plugin-build/src/patch-preview-schema.ts +166 -0
- package/integrations/bb-plugin-build/src/patch-preview-service.ts +480 -0
- package/integrations/bb-plugin-build/src/patch-preview-view.ts +109 -0
- package/integrations/bb-plugin-build/src/planning-readback.ts +228 -0
- package/integrations/bb-plugin-build/src/planning-service.ts +647 -0
- package/integrations/bb-plugin-build/src/planning-sync-evidence.ts +37 -0
- package/integrations/bb-plugin-build/src/planning-workspace-readback.ts +33 -0
- package/integrations/bb-plugin-build/src/planning-workspace-schema.ts +131 -0
- package/integrations/bb-plugin-build/src/planning-workspace.ts +333 -0
- package/integrations/bb-plugin-build/src/poll-handoff.ts +136 -0
- package/integrations/bb-plugin-build/src/project-target-server.ts +21 -0
- package/integrations/bb-plugin-build/src/project-target.ts +45 -0
- package/integrations/bb-plugin-build/src/reference-index.ts +218 -0
- package/integrations/bb-plugin-build/src/repository-identity.ts +17 -0
- package/integrations/bb-plugin-build/src/repository-schema.ts +30 -0
- package/integrations/bb-plugin-build/src/result-explorer-view.ts +597 -0
- package/integrations/bb-plugin-build/src/result-readback-model.ts +163 -0
- package/integrations/bb-plugin-build/src/result-readback-schema.ts +319 -0
- package/integrations/bb-plugin-build/src/result-readback-service.ts +333 -0
- package/integrations/bb-plugin-build/src/run-page-view.ts +332 -0
- package/integrations/bb-plugin-build/src/setup-config-schema.ts +293 -0
- package/integrations/bb-plugin-build/src/setup-config-service.ts +620 -0
- package/integrations/bb-plugin-build/src/setup-config-view.ts +388 -0
- package/integrations/bb-plugin-build/src/sprint-close-model.ts +150 -0
- package/integrations/bb-plugin-build/src/sprint-close-schema.ts +128 -0
- package/integrations/bb-plugin-build/src/sprint-close-service.ts +293 -0
- package/integrations/bb-plugin-build/src/sprint-close-view.ts +116 -0
- package/integrations/bb-plugin-build/src/sprint-composition-model.ts +709 -0
- package/integrations/bb-plugin-build/src/sprint-composition-readback.ts +231 -0
- package/integrations/bb-plugin-build/src/sprint-composition-schema.ts +597 -0
- package/integrations/bb-plugin-build/src/sprint-composition-service.ts +773 -0
- package/integrations/bb-plugin-build/src/sprint-composition-view.ts +1221 -0
- package/integrations/bb-plugin-build/src/sprint-execution-schema.ts +188 -0
- package/integrations/bb-plugin-build/src/sprint-execution-service.ts +289 -0
- package/integrations/bb-plugin-build/src/sprint-execution-view.ts +54 -0
- package/integrations/bb-plugin-build/src/task-authoring-model.ts +563 -0
- package/integrations/bb-plugin-build/src/task-authoring-schema.ts +629 -0
- package/integrations/bb-plugin-build/src/task-authoring-service.ts +842 -0
- package/integrations/bb-plugin-build/src/task-authoring-view.ts +1227 -0
- package/integrations/bb-plugin-build/src/task-catalog-schema.ts +46 -0
- package/integrations/bb-plugin-build/src/task-catalog-service.ts +44 -0
- package/integrations/bb-plugin-build/src/task-detail-readback.ts +56 -0
- package/integrations/bb-plugin-build/src/task-detail-schema.ts +171 -0
- package/integrations/bb-plugin-build/src/task-navigation.ts +446 -0
- package/integrations/bb-plugin-build/src/workbench-route.ts +74 -0
- package/package.json +306 -4
- package/schemas/README.md +80 -0
- package/schemas/build.config.schema.json +2110 -0
- package/schemas/config-v1.schema.json +136 -0
- package/schemas/execution-config.schema.json +47 -0
- package/schemas/judge-scoring.schema.json +257 -0
- package/schemas/provider-config.schema.json +179 -0
- package/schemas/telemetry-config.schema.json +79 -0
- package/schemas/user-preferences.schema.json +141 -0
- package/scripts/assert-node-runtime.mjs +146 -0
- package/scripts/preflight-native.mjs +49 -0
- package/scripts/setup-git-hooks.mjs +39 -0
- package/scripts/sync.sh +2871 -0
- package/scripts/write-node-launcher.sh +138 -0
- package/src/resources/gemini/slash-packs/default/plan.toml +15 -0
- package/src/resources/gemini/slash-packs/default/summary.toml +16 -0
- package/src/resources/gemini/slash-packs/default/tests.toml +16 -0
- package/templates/.build-project/README.md +41 -0
- package/templates/.build-project/agents/README.md +50 -0
- package/templates/.build-project/agents/architect.md +10 -0
- package/templates/.build-project/agents/code-reviewer.md +10 -0
- package/templates/.build-project/agents/debugger.md +10 -0
- package/templates/.build-project/agents/documenter.md +10 -0
- package/templates/.build-project/agents/test-automator.md +10 -0
- package/templates/.build-project/config/build.config.jsonc +64 -0
- package/templates/.build-project/config/project-context.template.json +6 -0
- package/templates/.build-project/config/task-type-aliases.presets/kanban.yaml +14 -0
- package/templates/.build-project/config/task-type-aliases.presets/scrum.yaml +17 -0
- package/templates/.build-project/config/task-type-aliases.presets/xp.yaml +12 -0
- package/templates/.build-project/config/task-type-aliases.yaml +29 -0
- package/templates/.build-project/gitignore.template +70 -0
- package/templates/.build-project/task-types/analysis.yaml +38 -0
- package/templates/.build-project/task-types/architecture.yaml +35 -0
- package/templates/.build-project/task-types/doc.yaml +34 -0
- package/templates/.build-project/task-types/feature.yaml +22 -0
- package/templates/.build-project/task-types/general.yaml +4 -0
- package/templates/.build-project/task-types/security.yaml +38 -0
- package/templates/AGENTS.template.md +85 -0
- package/templates/CLAUDE.template.md +1 -0
- package/templates/GEMINI.template.md +1 -0
- package/templates/builtin-workflows/code-review.yaml +73 -0
- package/templates/builtin-workflows/skills/code-review/SKILL.md +61 -0
- package/templates/builtin-workflows/skills/execution-contract-analysis/SKILL.md +24 -0
- package/templates/builtin-workflows/skills/execution-contract-code/SKILL.md +19 -0
- package/templates/builtin-workflows/skills/execution-contract-structured/SKILL.md +17 -0
- package/templates/ci/incident-intake.mjs +787 -0
- package/templates/ci/incidents.yml.template +103 -0
- package/templates/ci/node.yml.template +17 -0
- package/templates/ci/python.yml.template +17 -0
- package/templates/guard-kit/GUARD_SETUP.md.template +258 -0
- package/templates/guard-kit/build-guard.yml.template +189 -0
- package/templates/guard-kit/check.mjs.template +932 -0
- package/templates/guard-kit/config.json.template +7 -0
- package/templates/guard-kit/policy.json.template +1 -0
- package/templates/profiles/README.md +57 -0
- package/templates/profiles/frontier-claude.json +23 -0
- package/templates/profiles/frontier-codex.json +23 -0
|
@@ -0,0 +1,2222 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadSprintCompletedTaskIds
|
|
3
|
+
} from "./chunk-R5EXHMUN.js";
|
|
4
|
+
import {
|
|
5
|
+
isTaskStatus,
|
|
6
|
+
normalizeTaskStatus
|
|
7
|
+
} from "./chunk-NAINGKHF.js";
|
|
8
|
+
import {
|
|
9
|
+
generateEnhancements,
|
|
10
|
+
getArchiveShard,
|
|
11
|
+
getArchivedFilePath,
|
|
12
|
+
hintsFromEnhancements,
|
|
13
|
+
isTaskHeaderMetadataLine,
|
|
14
|
+
toEnhancementSet,
|
|
15
|
+
toPersistedFormat
|
|
16
|
+
} from "./chunk-US3RT6CY.js";
|
|
17
|
+
import {
|
|
18
|
+
getDefaultActivityForCategory
|
|
19
|
+
} from "./chunk-GI5M67YA.js";
|
|
20
|
+
import {
|
|
21
|
+
classifyTaskDependency,
|
|
22
|
+
detectCircularDependencies,
|
|
23
|
+
loadAllItems,
|
|
24
|
+
validateDependencies
|
|
25
|
+
} from "./chunk-NXH3RX7O.js";
|
|
26
|
+
import {
|
|
27
|
+
assertCompletionContractsMet,
|
|
28
|
+
normalizeCompletionContracts,
|
|
29
|
+
recordUnverifiedCompletion
|
|
30
|
+
} from "./chunk-MCBNWZNO.js";
|
|
31
|
+
import {
|
|
32
|
+
keepActivity
|
|
33
|
+
} from "./chunk-J2QCFLUN.js";
|
|
34
|
+
import {
|
|
35
|
+
getPlanningRoot,
|
|
36
|
+
withIndexRegeneration
|
|
37
|
+
} from "./chunk-CSXLLEGB.js";
|
|
38
|
+
import {
|
|
39
|
+
parseWorkOwnership,
|
|
40
|
+
projectWorkOwnership
|
|
41
|
+
} from "./chunk-6G57FYBV.js";
|
|
42
|
+
import {
|
|
43
|
+
assertBucketWriteAvailable
|
|
44
|
+
} from "./chunk-AJBTKGJZ.js";
|
|
45
|
+
import {
|
|
46
|
+
getBucketArchivePathByKind,
|
|
47
|
+
getBucketByName,
|
|
48
|
+
getBucketPathByKind,
|
|
49
|
+
listEnabledBuckets
|
|
50
|
+
} from "./chunk-V3KLVK7B.js";
|
|
51
|
+
import {
|
|
52
|
+
StaleVersionError
|
|
53
|
+
} from "./chunk-TDSEX5CF.js";
|
|
54
|
+
import {
|
|
55
|
+
retiredJudgeSelectionError
|
|
56
|
+
} from "./chunk-IVZEONFC.js";
|
|
57
|
+
import {
|
|
58
|
+
parseVariantIdentifier
|
|
59
|
+
} from "./chunk-TGXXYDL4.js";
|
|
60
|
+
import {
|
|
61
|
+
findFencedCodeSpans,
|
|
62
|
+
matchOutsideFences
|
|
63
|
+
} from "./chunk-R2TIYG7U.js";
|
|
64
|
+
import {
|
|
65
|
+
generateId,
|
|
66
|
+
isValidId
|
|
67
|
+
} from "./chunk-4DJL2VXA.js";
|
|
68
|
+
import {
|
|
69
|
+
normalizeReasoningEffortInput
|
|
70
|
+
} from "./chunk-4BTDUT2S.js";
|
|
71
|
+
import {
|
|
72
|
+
assertSafePlanningFileId,
|
|
73
|
+
ensureDirectoryExists,
|
|
74
|
+
fileExists,
|
|
75
|
+
listMarkdownFiles,
|
|
76
|
+
listMarkdownFilesRecursive,
|
|
77
|
+
listMarkdownFilesRecursiveStrict,
|
|
78
|
+
readMarkdownFile,
|
|
79
|
+
resolvePlanningItemPath,
|
|
80
|
+
writeMarkdownFile
|
|
81
|
+
} from "./chunk-352PCJLK.js";
|
|
82
|
+
import {
|
|
83
|
+
emitCustomWarning
|
|
84
|
+
} from "./chunk-7VRJHTGZ.js";
|
|
85
|
+
|
|
86
|
+
// src/planning/task-manager.ts
|
|
87
|
+
import * as crypto from "crypto";
|
|
88
|
+
import * as fs from "fs/promises";
|
|
89
|
+
import * as path2 from "path";
|
|
90
|
+
|
|
91
|
+
// src/planning/task-execution-controls.ts
|
|
92
|
+
function asRecord(value) {
|
|
93
|
+
return value && typeof value === "object" && !Array.isArray(value) ? { ...value } : {};
|
|
94
|
+
}
|
|
95
|
+
function cleanList(values) {
|
|
96
|
+
return [...new Set(values.map((value) => value.trim()).filter((value) => value.length > 0))];
|
|
97
|
+
}
|
|
98
|
+
function applyTaskExecutionControlUpdates(frontMatter, updates) {
|
|
99
|
+
if (updates.executionIntent !== void 0) {
|
|
100
|
+
const metadata = asRecord(frontMatter.metadata);
|
|
101
|
+
if (updates.executionIntent === null) {
|
|
102
|
+
delete metadata.executionIntent;
|
|
103
|
+
} else {
|
|
104
|
+
metadata.executionIntent = updates.executionIntent;
|
|
105
|
+
}
|
|
106
|
+
delete frontMatter.executionIntent;
|
|
107
|
+
if (Object.keys(metadata).length > 0) {
|
|
108
|
+
frontMatter.metadata = metadata;
|
|
109
|
+
} else {
|
|
110
|
+
delete frontMatter.metadata;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (updates.allowlist === void 0 && updates.verifyCommands === void 0 && updates.allowEmptyResults === void 0) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const flywheel = asRecord(frontMatter.flywheel);
|
|
117
|
+
if (updates.allowlist !== void 0) {
|
|
118
|
+
const allowlist = cleanList(updates.allowlist);
|
|
119
|
+
if (allowlist.length > 0) {
|
|
120
|
+
flywheel.allowlist = allowlist;
|
|
121
|
+
} else {
|
|
122
|
+
delete flywheel.allowlist;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (updates.verifyCommands !== void 0) {
|
|
126
|
+
const commands = cleanList(updates.verifyCommands);
|
|
127
|
+
if (commands.length > 0) {
|
|
128
|
+
flywheel.verify = { ...asRecord(flywheel.verify), commands };
|
|
129
|
+
} else {
|
|
130
|
+
delete flywheel.verify;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (updates.allowEmptyResults !== void 0) {
|
|
134
|
+
if (updates.allowEmptyResults === null) {
|
|
135
|
+
delete flywheel.allowEmptyResults;
|
|
136
|
+
} else {
|
|
137
|
+
flywheel.allowEmptyResults = updates.allowEmptyResults;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (Object.keys(flywheel).length > 0) {
|
|
141
|
+
frontMatter.flywheel = flywheel;
|
|
142
|
+
} else {
|
|
143
|
+
delete frontMatter.flywheel;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/planning/task-status.ts
|
|
148
|
+
import * as path from "path";
|
|
149
|
+
var ALLOWED_TASK_TRANSITIONS = {
|
|
150
|
+
todo: ["in_progress", "review", "done", "blocked", "cancelled"],
|
|
151
|
+
in_progress: ["review", "done", "todo", "blocked", "cancelled"],
|
|
152
|
+
review: ["done", "in_progress", "blocked", "cancelled"],
|
|
153
|
+
done: ["in_progress", "review", "cancelled"],
|
|
154
|
+
blocked: ["todo", "in_progress", "review", "done", "blocked", "cancelled"],
|
|
155
|
+
cancelled: ["todo", "in_progress"]
|
|
156
|
+
};
|
|
157
|
+
async function validateStateTransition(rootDir, itemId, fromState, toState) {
|
|
158
|
+
try {
|
|
159
|
+
if (!isTaskStatus(fromState) || !isTaskStatus(toState)) {
|
|
160
|
+
return {
|
|
161
|
+
success: false,
|
|
162
|
+
message: `Invalid state transition: ${fromState} \u2192 ${toState}`
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
const allowed = ALLOWED_TASK_TRANSITIONS[fromState];
|
|
166
|
+
if (!allowed.includes(toState)) {
|
|
167
|
+
return {
|
|
168
|
+
success: false,
|
|
169
|
+
message: `Invalid state transition: ${fromState} \u2192 ${toState}`
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const activeDirs = [];
|
|
173
|
+
const dependencyDirs = [];
|
|
174
|
+
for (const bucket of listEnabledBuckets(rootDir)) {
|
|
175
|
+
const activePath = getBucketPathByKind(bucket.name, rootDir);
|
|
176
|
+
activeDirs.push(activePath);
|
|
177
|
+
dependencyDirs.push(activePath, getBucketArchivePathByKind(bucket.name, rootDir));
|
|
178
|
+
}
|
|
179
|
+
const activeItems = await loadAllItems(rootDir, activeDirs);
|
|
180
|
+
const circularCheck = detectCircularDependencies(itemId, activeItems);
|
|
181
|
+
if (!circularCheck.valid) {
|
|
182
|
+
return {
|
|
183
|
+
success: false,
|
|
184
|
+
message: "Circular dependency detected",
|
|
185
|
+
errors: circularCheck.errors.map((e) => e.message)
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const dependencyItems = await loadAllItems(rootDir, dependencyDirs);
|
|
189
|
+
const transitioningItem = dependencyItems.find((item) => item.id === itemId);
|
|
190
|
+
const sprintId = transitioningItem && typeof transitioningItem.frontMatter.sprintId === "string" ? transitioningItem.frontMatter.sprintId : typeof transitioningItem?.frontMatter.originalSprintId === "string" ? transitioningItem.frontMatter.originalSprintId : void 0;
|
|
191
|
+
const depCheck = validateDependencies(dependencyItems, {
|
|
192
|
+
reportOnlyFiles: transitioningItem ? /* @__PURE__ */ new Set([path.resolve(transitioningItem.filePath)]) : void 0,
|
|
193
|
+
// Scoped to the transitioning task's own sprint ledger: completion
|
|
194
|
+
// evidence from an unrelated sprint must not resolve this dependency.
|
|
195
|
+
recordedCompleteIds: await loadSprintCompletedTaskIds(sprintId, rootDir)
|
|
196
|
+
});
|
|
197
|
+
if (!depCheck.valid) {
|
|
198
|
+
return {
|
|
199
|
+
success: false,
|
|
200
|
+
message: "Missing dependencies",
|
|
201
|
+
errors: depCheck.errors.map((e) => e.message)
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
success: true,
|
|
206
|
+
message: `Transition ${fromState} \u2192 ${toState} is valid`
|
|
207
|
+
};
|
|
208
|
+
} catch (error) {
|
|
209
|
+
return {
|
|
210
|
+
success: false,
|
|
211
|
+
message: `Validation error: ${error}`
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/planning/task-manager.ts
|
|
217
|
+
function emitTaskManagerWarning(message, metadata) {
|
|
218
|
+
emitCustomWarning(
|
|
219
|
+
"WARN" /* WARN */,
|
|
220
|
+
"configuration" /* CONFIGURATION */,
|
|
221
|
+
message,
|
|
222
|
+
{
|
|
223
|
+
subsystem: "planning/task-manager",
|
|
224
|
+
executionPhase: "execution"
|
|
225
|
+
},
|
|
226
|
+
{ metadata, skipConsole: true }
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
var DEPRECATED_VARIANT_STRATEGY_TOKENS = /* @__PURE__ */ new Set([
|
|
230
|
+
"conservative",
|
|
231
|
+
"innovative",
|
|
232
|
+
"hybrid"
|
|
233
|
+
]);
|
|
234
|
+
var FUSION_VARIANT_TOKEN = "fusion";
|
|
235
|
+
var warnedDeprecatedStrategyField = false;
|
|
236
|
+
function warnDeprecatedStrategyField(field) {
|
|
237
|
+
if (warnedDeprecatedStrategyField) return;
|
|
238
|
+
warnedDeprecatedStrategyField = true;
|
|
239
|
+
emitTaskManagerWarning(
|
|
240
|
+
`Ignoring '${field}': variant strategies were removed (ADR-025). Use provider, model, or reasoning instead.`,
|
|
241
|
+
{ field }
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
function parseNumber(value, fallback) {
|
|
245
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
246
|
+
if (typeof value === "string") {
|
|
247
|
+
const parsed = Number.parseFloat(value);
|
|
248
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
249
|
+
}
|
|
250
|
+
return fallback;
|
|
251
|
+
}
|
|
252
|
+
function parseOptionalNumber(value) {
|
|
253
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
254
|
+
if (typeof value === "string") {
|
|
255
|
+
const parsed = Number.parseFloat(value);
|
|
256
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
257
|
+
}
|
|
258
|
+
return void 0;
|
|
259
|
+
}
|
|
260
|
+
var RUNTIME_ESTIMATE_PROVENANCES = ["heuristic", "telemetry", "blended", "explicit"];
|
|
261
|
+
var RUNTIME_ESTIMATE_CONFIDENCES = ["low", "medium", "high"];
|
|
262
|
+
function coerceRuntimeEstimateFields(frontMatter) {
|
|
263
|
+
const result = {};
|
|
264
|
+
const minutes = parseOptionalNumber(frontMatter.expectedRuntimeMinutes);
|
|
265
|
+
if (typeof minutes === "number" && minutes > 0) {
|
|
266
|
+
result.expectedRuntimeMinutes = minutes;
|
|
267
|
+
}
|
|
268
|
+
const provenance = frontMatter.runtimeEstimateProvenance;
|
|
269
|
+
if (typeof provenance === "string" && RUNTIME_ESTIMATE_PROVENANCES.includes(provenance)) {
|
|
270
|
+
result.runtimeEstimateProvenance = provenance;
|
|
271
|
+
}
|
|
272
|
+
const confidence = frontMatter.runtimeEstimateConfidence;
|
|
273
|
+
if (typeof confidence === "string" && RUNTIME_ESTIMATE_CONFIDENCES.includes(confidence)) {
|
|
274
|
+
result.runtimeEstimateConfidence = confidence;
|
|
275
|
+
}
|
|
276
|
+
return result;
|
|
277
|
+
}
|
|
278
|
+
var VALID_STAGE_OUTPUT_TYPES = [
|
|
279
|
+
"diff",
|
|
280
|
+
"files",
|
|
281
|
+
"text",
|
|
282
|
+
"testResults",
|
|
283
|
+
"json"
|
|
284
|
+
];
|
|
285
|
+
function coerceStageOutputs(value) {
|
|
286
|
+
if (!value || typeof value !== "object") return void 0;
|
|
287
|
+
const outputs = {};
|
|
288
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
289
|
+
if (!key || typeof key !== "string") continue;
|
|
290
|
+
if (typeof raw !== "string") continue;
|
|
291
|
+
if (!VALID_STAGE_OUTPUT_TYPES.includes(raw)) continue;
|
|
292
|
+
outputs[key] = raw;
|
|
293
|
+
}
|
|
294
|
+
return Object.keys(outputs).length > 0 ? outputs : void 0;
|
|
295
|
+
}
|
|
296
|
+
function coerceStageValidationOverride(value) {
|
|
297
|
+
if (!value || typeof value !== "object") return void 0;
|
|
298
|
+
const raw = value;
|
|
299
|
+
const enabled = typeof raw.enabled === "boolean" ? raw.enabled : void 0;
|
|
300
|
+
const target = typeof raw.target === "string" ? raw.target : void 0;
|
|
301
|
+
const threshold = parseOptionalNumber(raw.threshold);
|
|
302
|
+
const maxRetries = parseOptionalNumber(raw.maxRetries);
|
|
303
|
+
const requiredFiles = Array.isArray(raw.requiredFiles) ? raw.requiredFiles.filter(
|
|
304
|
+
(value2) => typeof value2 === "string" && value2.trim().length > 0
|
|
305
|
+
) : void 0;
|
|
306
|
+
const checks = Array.isArray(raw.checks) ? raw.checks : void 0;
|
|
307
|
+
const semanticChecks = Array.isArray(raw.semanticChecks) ? raw.semanticChecks : void 0;
|
|
308
|
+
if (enabled === void 0 && target === void 0 && threshold === void 0 && maxRetries === void 0 && requiredFiles === void 0 && checks === void 0 && semanticChecks === void 0) {
|
|
309
|
+
return void 0;
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
312
|
+
...enabled !== void 0 ? { enabled } : {},
|
|
313
|
+
...target ? { target } : {},
|
|
314
|
+
...threshold !== void 0 ? { threshold } : {},
|
|
315
|
+
...maxRetries !== void 0 ? { maxRetries } : {},
|
|
316
|
+
...requiredFiles && requiredFiles.length > 0 ? { requiredFiles } : {},
|
|
317
|
+
...checks ? { checks } : {},
|
|
318
|
+
...semanticChecks ? { semanticChecks } : {}
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
function coerceVariantSpec(value) {
|
|
322
|
+
if (typeof value === "string") {
|
|
323
|
+
const spec = value.trim();
|
|
324
|
+
const parsed = parseVariantIdentifier(spec);
|
|
325
|
+
const provider2 = parsed.provider?.trim();
|
|
326
|
+
if (!provider2) return null;
|
|
327
|
+
const modelSegments = parsed.model ? parsed.model.split(":") : [];
|
|
328
|
+
const preModeToken = modelSegments.at(-1)?.trim().toLowerCase();
|
|
329
|
+
if (preModeToken === FUSION_VARIANT_TOKEN) {
|
|
330
|
+
emitTaskManagerWarning(
|
|
331
|
+
`Ignoring variant '${spec}': '${FUSION_VARIANT_TOKEN}' is a run mode, not a variant token (ADR-025). Run 'build run fusion' instead.`,
|
|
332
|
+
{ variant: spec, token: FUSION_VARIANT_TOKEN }
|
|
333
|
+
);
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
if (preModeToken && DEPRECATED_VARIANT_STRATEGY_TOKENS.has(preModeToken)) {
|
|
337
|
+
modelSegments.pop();
|
|
338
|
+
warnDeprecatedStrategyField("variant.strategy");
|
|
339
|
+
}
|
|
340
|
+
const model2 = modelSegments.join(":").trim();
|
|
341
|
+
return {
|
|
342
|
+
provider: provider2,
|
|
343
|
+
...model2 ? { model: model2 } : {},
|
|
344
|
+
...parsed.reasoningEffort ? { reasoning: parsed.reasoningEffort } : {}
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
if (!value || typeof value !== "object") return null;
|
|
348
|
+
const raw = value;
|
|
349
|
+
const provider = typeof raw.provider === "string" ? raw.provider : void 0;
|
|
350
|
+
if (!provider) return null;
|
|
351
|
+
const model = typeof raw.model === "string" ? raw.model : void 0;
|
|
352
|
+
if (typeof raw.strategy === "string" && raw.strategy.trim().length > 0) {
|
|
353
|
+
warnDeprecatedStrategyField("variant.strategy");
|
|
354
|
+
}
|
|
355
|
+
const reasoning = typeof raw.reasoning === "string" ? raw.reasoning : void 0;
|
|
356
|
+
return {
|
|
357
|
+
provider,
|
|
358
|
+
...model ? { model } : {},
|
|
359
|
+
...reasoning ? { reasoning } : {}
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function coerceCompetitionConfig(value) {
|
|
363
|
+
if (!value || typeof value !== "object") return void 0;
|
|
364
|
+
const raw = value;
|
|
365
|
+
const variantsRaw = raw.variants;
|
|
366
|
+
const variants = Array.isArray(variantsRaw) ? variantsRaw.map(coerceVariantSpec).filter((v) => Boolean(v)) : [];
|
|
367
|
+
if (variants.length === 0) return void 0;
|
|
368
|
+
const judgeConfigRaw = raw.judgeConfig;
|
|
369
|
+
const retiredJudgeRun = (() => {
|
|
370
|
+
if (!judgeConfigRaw || typeof judgeConfigRaw !== "object") return void 0;
|
|
371
|
+
const obj = judgeConfigRaw;
|
|
372
|
+
if (typeof obj.type === "string" && retiredJudgeSelectionError(obj.type)) return [obj.type];
|
|
373
|
+
const run = Array.isArray(obj.judgeRun) ? obj.judgeRun.filter((entry) => typeof entry === "string") : [];
|
|
374
|
+
return run.some((entry) => retiredJudgeSelectionError(entry)) ? run : void 0;
|
|
375
|
+
})();
|
|
376
|
+
const judgeConfig = judgeConfigRaw && typeof judgeConfigRaw === "object" ? {
|
|
377
|
+
type: (() => {
|
|
378
|
+
const typeRaw = judgeConfigRaw.type;
|
|
379
|
+
if (typeof typeRaw === "string" && (typeRaw === "multi-lens" || typeRaw === "ai")) {
|
|
380
|
+
return typeRaw;
|
|
381
|
+
}
|
|
382
|
+
return void 0;
|
|
383
|
+
})(),
|
|
384
|
+
threshold: parseOptionalNumber(judgeConfigRaw.threshold),
|
|
385
|
+
runComparison: (() => {
|
|
386
|
+
const value2 = judgeConfigRaw.runComparison;
|
|
387
|
+
return typeof value2 === "boolean" ? value2 : void 0;
|
|
388
|
+
})()
|
|
389
|
+
} : void 0;
|
|
390
|
+
const preserveCandidates = typeof raw.preserveCandidates === "boolean" ? raw.preserveCandidates : void 0;
|
|
391
|
+
const applyWinner = typeof raw.applyWinner === "boolean" ? raw.applyWinner : void 0;
|
|
392
|
+
const tieBreakerRaw = raw.tieBreaker;
|
|
393
|
+
const tieBreakerMode = tieBreakerRaw && typeof tieBreakerRaw === "object" ? (() => {
|
|
394
|
+
const modeRaw = tieBreakerRaw.mode;
|
|
395
|
+
if (modeRaw === "prefer-first-ranked" || modeRaw === "prefer-low-drift" || modeRaw === "prefer-smaller-diff" || modeRaw === "prefer-low-drift-then-diff") {
|
|
396
|
+
return modeRaw;
|
|
397
|
+
}
|
|
398
|
+
return void 0;
|
|
399
|
+
})() : void 0;
|
|
400
|
+
const normalizedTieBreaker = tieBreakerMode ? { mode: tieBreakerMode } : void 0;
|
|
401
|
+
const verificationPolicyRaw = typeof raw.verificationPolicy === "string" ? raw.verificationPolicy : void 0;
|
|
402
|
+
const verificationPolicy = verificationPolicyRaw === "findings" || verificationPolicyRaw === "blocking" ? verificationPolicyRaw : void 0;
|
|
403
|
+
const repairRaw = raw.repairOnFindings;
|
|
404
|
+
const repairObj = repairRaw && typeof repairRaw === "object" ? repairRaw : null;
|
|
405
|
+
const repairOnFindings = repairObj ? {
|
|
406
|
+
enabled: Boolean(repairObj.enabled),
|
|
407
|
+
...parseOptionalNumber(repairObj.maxIterations) !== void 0 ? {
|
|
408
|
+
maxIterations: parseOptionalNumber(repairObj.maxIterations)
|
|
409
|
+
} : {},
|
|
410
|
+
...parseOptionalNumber(repairObj.timeboxMs) !== void 0 ? { timeboxMs: parseOptionalNumber(repairObj.timeboxMs) } : {}
|
|
411
|
+
} : void 0;
|
|
412
|
+
const result = {
|
|
413
|
+
variants,
|
|
414
|
+
...judgeConfig?.type || retiredJudgeRun ? {
|
|
415
|
+
judgeConfig: {
|
|
416
|
+
...judgeConfig?.type ? { type: judgeConfig.type } : {},
|
|
417
|
+
...retiredJudgeRun ? { judgeRun: retiredJudgeRun } : {},
|
|
418
|
+
...Number.isFinite(judgeConfig?.threshold) ? { threshold: judgeConfig?.threshold } : {},
|
|
419
|
+
...judgeConfig?.runComparison !== void 0 ? { runComparison: judgeConfig.runComparison } : {}
|
|
420
|
+
}
|
|
421
|
+
} : {},
|
|
422
|
+
...preserveCandidates !== void 0 ? { preserveCandidates } : {},
|
|
423
|
+
...applyWinner !== void 0 ? { applyWinner } : {},
|
|
424
|
+
...verificationPolicy ? { verificationPolicy } : {},
|
|
425
|
+
...repairOnFindings ? { repairOnFindings } : {},
|
|
426
|
+
...normalizedTieBreaker ? { tieBreaker: normalizedTieBreaker } : {}
|
|
427
|
+
};
|
|
428
|
+
return result;
|
|
429
|
+
}
|
|
430
|
+
function coerceFlywheelConfig(value) {
|
|
431
|
+
if (!value || typeof value !== "object") return void 0;
|
|
432
|
+
const raw = value;
|
|
433
|
+
const typeRaw = typeof raw.type === "string" ? raw.type : void 0;
|
|
434
|
+
const stageTypes = ["standard", "competition", "verify", "refinement", "autoloop"];
|
|
435
|
+
const type = stageTypes.includes(typeRaw ?? "") ? typeRaw : void 0;
|
|
436
|
+
const modelReasoningEffort = normalizeReasoningEffortInput(raw.modelReasoningEffort);
|
|
437
|
+
const inputs = Array.isArray(raw.inputs) ? raw.inputs.filter(
|
|
438
|
+
(v) => typeof v === "string" && v.length > 0
|
|
439
|
+
) : void 0;
|
|
440
|
+
const allowlist = Array.isArray(raw.allowlist) ? raw.allowlist.filter((v) => typeof v === "string" && v.length > 0) : void 0;
|
|
441
|
+
const allowDenylist = Array.isArray(raw.allowDenylist) ? raw.allowDenylist.filter(
|
|
442
|
+
(v) => typeof v === "string" && v.length > 0
|
|
443
|
+
) : void 0;
|
|
444
|
+
const allowlistModeRaw = typeof raw.allowlistMode === "string" ? raw.allowlistMode : void 0;
|
|
445
|
+
const allowlistMode = allowlistModeRaw === "off" || allowlistModeRaw === "warn" || allowlistModeRaw === "strict" || allowlistModeRaw === "filter" ? allowlistModeRaw : void 0;
|
|
446
|
+
const verifyRaw = raw.verify;
|
|
447
|
+
const verifyObj = verifyRaw && typeof verifyRaw === "object" ? verifyRaw : null;
|
|
448
|
+
const verify = verifyObj && Array.isArray(verifyObj.commands) ? {
|
|
449
|
+
commands: verifyObj.commands.filter(
|
|
450
|
+
(v) => typeof v === "string" && v.length > 0
|
|
451
|
+
)
|
|
452
|
+
} : void 0;
|
|
453
|
+
const outputs = coerceStageOutputs(raw.outputs);
|
|
454
|
+
const validation = coerceStageValidationOverride(raw.validation);
|
|
455
|
+
const competition = coerceCompetitionConfig(raw.competition);
|
|
456
|
+
const allowEmptyResults = typeof raw.allowEmptyResults === "boolean" ? raw.allowEmptyResults : void 0;
|
|
457
|
+
const autoloopRaw = raw.autoloop;
|
|
458
|
+
const autoloopObj = autoloopRaw && typeof autoloopRaw === "object" ? autoloopRaw : null;
|
|
459
|
+
const autoloop = autoloopObj ? {
|
|
460
|
+
...parseOptionalNumber(autoloopObj.maxIterations) !== void 0 ? {
|
|
461
|
+
maxIterations: parseOptionalNumber(autoloopObj.maxIterations)
|
|
462
|
+
} : {},
|
|
463
|
+
...parseOptionalNumber(autoloopObj.timeboxMs) !== void 0 ? { timeboxMs: parseOptionalNumber(autoloopObj.timeboxMs) } : {},
|
|
464
|
+
...parseOptionalNumber(autoloopObj.minProgress) !== void 0 ? {
|
|
465
|
+
minProgress: parseOptionalNumber(autoloopObj.minProgress)
|
|
466
|
+
} : {},
|
|
467
|
+
...typeof autoloopObj.stopOnQualityGate === "boolean" ? { stopOnQualityGate: autoloopObj.stopOnQualityGate } : {},
|
|
468
|
+
...Array.isArray(autoloopObj.qualityGateCommands) ? {
|
|
469
|
+
qualityGateCommands: autoloopObj.qualityGateCommands.filter(
|
|
470
|
+
(v) => typeof v === "string" && v.length > 0
|
|
471
|
+
)
|
|
472
|
+
} : {}
|
|
473
|
+
} : void 0;
|
|
474
|
+
const hasAutoloopFields = Boolean(
|
|
475
|
+
autoloop && (autoloop.maxIterations !== void 0 || autoloop.timeboxMs !== void 0 || autoloop.minProgress !== void 0 || autoloop.stopOnQualityGate !== void 0 || Array.isArray(autoloop.qualityGateCommands) && autoloop.qualityGateCommands.length > 0)
|
|
476
|
+
);
|
|
477
|
+
if (!type && !modelReasoningEffort && (!inputs || inputs.length === 0) && (!allowlist || allowlist.length === 0) && (!allowDenylist || allowDenylist.length === 0) && !allowlistMode && !verify && !outputs && !validation && !competition && allowEmptyResults === void 0 && !hasAutoloopFields)
|
|
478
|
+
return void 0;
|
|
479
|
+
return {
|
|
480
|
+
...type ? { type } : {},
|
|
481
|
+
...modelReasoningEffort ? { modelReasoningEffort } : {},
|
|
482
|
+
...inputs && inputs.length > 0 ? { inputs } : {},
|
|
483
|
+
...allowlist && allowlist.length > 0 ? { allowlist } : {},
|
|
484
|
+
...allowDenylist && allowDenylist.length > 0 ? { allowDenylist } : {},
|
|
485
|
+
...allowlistMode ? { allowlistMode } : {},
|
|
486
|
+
...verify && verify.commands.length > 0 ? { verify } : {},
|
|
487
|
+
...outputs ? { outputs } : {},
|
|
488
|
+
...validation ? { validation } : {},
|
|
489
|
+
...competition ? { competition } : {},
|
|
490
|
+
...allowEmptyResults !== void 0 ? { allowEmptyResults } : {},
|
|
491
|
+
...hasAutoloopFields ? { autoloop } : {}
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
function coerceTaskYAML(frontMatter) {
|
|
495
|
+
const id = typeof frontMatter.id === "string" ? frontMatter.id : "";
|
|
496
|
+
if (!id) {
|
|
497
|
+
throw new Error('Invalid task frontmatter: missing required field "id"');
|
|
498
|
+
}
|
|
499
|
+
const originalSprintId = typeof frontMatter.originalSprintId === "string" && frontMatter.originalSprintId ? frontMatter.originalSprintId : void 0;
|
|
500
|
+
const sprintId = typeof frontMatter.sprintId === "string" && frontMatter.sprintId || typeof frontMatter.sprint_id === "string" && frontMatter.sprint_id || originalSprintId || "";
|
|
501
|
+
if (!sprintId) {
|
|
502
|
+
throw new Error(`Invalid task frontmatter for '${id}': missing required field "sprintId"`);
|
|
503
|
+
}
|
|
504
|
+
assertSafePlanningFileId(id, "taskId");
|
|
505
|
+
assertSafePlanningFileId(sprintId, "sprintId");
|
|
506
|
+
if (originalSprintId) {
|
|
507
|
+
assertSafePlanningFileId(originalSprintId, "originalSprintId");
|
|
508
|
+
}
|
|
509
|
+
const title = typeof frontMatter.title === "string" ? frontMatter.title : "";
|
|
510
|
+
if (!title) {
|
|
511
|
+
throw new Error(`Invalid task frontmatter for '${id}': missing required field "title"`);
|
|
512
|
+
}
|
|
513
|
+
const version = parseNumber(frontMatter.version, 0);
|
|
514
|
+
const statusRaw = typeof frontMatter.status === "string" ? frontMatter.status : "todo";
|
|
515
|
+
const status = normalizeTaskStatus(statusRaw);
|
|
516
|
+
const priorityRaw = typeof frontMatter.priority === "string" ? frontMatter.priority : "P2";
|
|
517
|
+
const priority = priorityRaw === "P0" || priorityRaw === "P1" || priorityRaw === "P2" || priorityRaw === "P3" ? priorityRaw : "P2";
|
|
518
|
+
const dependencies = Array.isArray(frontMatter.dependencies) ? frontMatter.dependencies.filter((v) => typeof v === "string") : [];
|
|
519
|
+
const subtasksRaw = Array.isArray(frontMatter.subtasks) ? frontMatter.subtasks : [];
|
|
520
|
+
const subtasks = subtasksRaw.map((st) => {
|
|
521
|
+
if (!st || typeof st !== "object") return null;
|
|
522
|
+
const stObj = st;
|
|
523
|
+
const text = typeof stObj.text === "string" ? stObj.text : "";
|
|
524
|
+
if (!text) return null;
|
|
525
|
+
return {
|
|
526
|
+
text,
|
|
527
|
+
completed: Boolean(stObj.completed)
|
|
528
|
+
};
|
|
529
|
+
}).filter((v) => Boolean(v));
|
|
530
|
+
const createdAt = typeof frontMatter.created_at === "string" && frontMatter.created_at || typeof frontMatter.created === "string" && frontMatter.created || (/* @__PURE__ */ new Date()).toISOString();
|
|
531
|
+
const updatedAt = typeof frontMatter.updated_at === "string" && frontMatter.updated_at || typeof frontMatter.updated === "string" && frontMatter.updated || createdAt;
|
|
532
|
+
const metadataRaw = frontMatter.metadata;
|
|
533
|
+
let metadata;
|
|
534
|
+
if (metadataRaw && typeof metadataRaw === "object" && !Array.isArray(metadataRaw)) {
|
|
535
|
+
metadata = {};
|
|
536
|
+
if (metadataRaw.executionIntent === "analysis" || metadataRaw.executionIntent === "edit") {
|
|
537
|
+
metadata.executionIntent = metadataRaw.executionIntent;
|
|
538
|
+
}
|
|
539
|
+
for (const key of ["modifiesFiles", "readsFiles", "producesText"]) {
|
|
540
|
+
const value = metadataRaw[key];
|
|
541
|
+
if (typeof value === "boolean") metadata[key] = value;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
const routingRaw = frontMatter.routing;
|
|
545
|
+
let routing;
|
|
546
|
+
if (routingRaw && typeof routingRaw === "object") {
|
|
547
|
+
const routingObj = routingRaw;
|
|
548
|
+
const provider = typeof routingObj.provider === "string" ? routingObj.provider : void 0;
|
|
549
|
+
const model = typeof routingObj.model === "string" ? routingObj.model : void 0;
|
|
550
|
+
const deprecatedStrategy = typeof routingObj.strategy === "string" && routingObj.strategy.trim().length > 0 ? routingObj.strategy : void 0;
|
|
551
|
+
if (deprecatedStrategy) {
|
|
552
|
+
warnDeprecatedStrategyField("routing.strategy");
|
|
553
|
+
}
|
|
554
|
+
const reasoning = typeof routingObj.reasoning === "string" ? routingObj.reasoning : void 0;
|
|
555
|
+
const profile = typeof routingObj.profile === "string" ? routingObj.profile : void 0;
|
|
556
|
+
if (provider || model || reasoning || profile) {
|
|
557
|
+
routing = { provider, model, reasoning, profile, strategy: deprecatedStrategy };
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
const executionIntentRaw = frontMatter.executionIntent;
|
|
561
|
+
if (!metadata?.executionIntent && (executionIntentRaw === "analysis" || executionIntentRaw === "edit")) {
|
|
562
|
+
metadata = { ...metadata, executionIntent: executionIntentRaw };
|
|
563
|
+
}
|
|
564
|
+
if (!routing) {
|
|
565
|
+
const provider = typeof frontMatter.provider === "string" ? frontMatter.provider : void 0;
|
|
566
|
+
const model = typeof frontMatter.model === "string" ? frontMatter.model : void 0;
|
|
567
|
+
if (provider && provider !== "multi" || model) {
|
|
568
|
+
routing = {
|
|
569
|
+
provider: provider && provider !== "multi" ? provider : void 0,
|
|
570
|
+
model
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
const flywheel = coerceFlywheelConfig(frontMatter.flywheel);
|
|
575
|
+
const taskClassificationRaw = frontMatter.taskClassification;
|
|
576
|
+
let taskClassification;
|
|
577
|
+
if (taskClassificationRaw && typeof taskClassificationRaw === "object") {
|
|
578
|
+
const classObj = taskClassificationRaw;
|
|
579
|
+
const categoryRaw = typeof classObj.category === "string" ? classObj.category : void 0;
|
|
580
|
+
const activityRaw = typeof classObj.activity === "string" ? classObj.activity : void 0;
|
|
581
|
+
const validCategories = ["execute", "review", "analyze", "test", "document"];
|
|
582
|
+
const validActivities = [
|
|
583
|
+
"planning",
|
|
584
|
+
"research",
|
|
585
|
+
"architecture",
|
|
586
|
+
"design",
|
|
587
|
+
"development",
|
|
588
|
+
"debugging"
|
|
589
|
+
];
|
|
590
|
+
const category = categoryRaw && validCategories.includes(categoryRaw) ? categoryRaw : void 0;
|
|
591
|
+
let activity = activityRaw && validActivities.includes(activityRaw) ? activityRaw : void 0;
|
|
592
|
+
if (category && !activity) {
|
|
593
|
+
activity = getDefaultActivityForCategory(category);
|
|
594
|
+
}
|
|
595
|
+
if (category || activity) {
|
|
596
|
+
taskClassification = { category, activity };
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
const taskTypeRaw = frontMatter.taskType ?? frontMatter.task_type;
|
|
600
|
+
const taskType = typeof taskTypeRaw === "string" && taskTypeRaw.trim().length > 0 ? taskTypeRaw.trim() : void 0;
|
|
601
|
+
const declaredType = typeof frontMatter.declaredType === "string" ? frontMatter.declaredType : void 0;
|
|
602
|
+
const declaredMethodology = typeof frontMatter.declaredMethodology === "string" ? frontMatter.declaredMethodology : void 0;
|
|
603
|
+
const resolvedTaskTypeId = typeof frontMatter.resolvedTaskTypeId === "string" ? frontMatter.resolvedTaskTypeId : void 0;
|
|
604
|
+
const hints = Array.isArray(frontMatter.hints) ? frontMatter.hints.filter((h) => typeof h === "string") : void 0;
|
|
605
|
+
function coerceEnhancementIntent(value) {
|
|
606
|
+
if (!value || typeof value !== "object") return void 0;
|
|
607
|
+
const obj = value;
|
|
608
|
+
const categoryRaw = typeof obj.category === "string" ? obj.category : void 0;
|
|
609
|
+
const activityRaw = typeof obj.activity === "string" ? obj.activity : void 0;
|
|
610
|
+
const confidenceRaw = typeof obj.confidence === "number" ? obj.confidence : void 0;
|
|
611
|
+
const validCategories = ["execute", "review", "analyze", "test", "document"];
|
|
612
|
+
const validActivities = [
|
|
613
|
+
"planning",
|
|
614
|
+
"research",
|
|
615
|
+
"architecture",
|
|
616
|
+
"design",
|
|
617
|
+
"development",
|
|
618
|
+
"debugging"
|
|
619
|
+
];
|
|
620
|
+
const category = categoryRaw && validCategories.includes(categoryRaw) ? categoryRaw : void 0;
|
|
621
|
+
const activity = activityRaw && validActivities.includes(activityRaw) ? activityRaw : void 0;
|
|
622
|
+
if (!category || !activity) return void 0;
|
|
623
|
+
const confidence = typeof confidenceRaw === "number" && confidenceRaw >= 0 && confidenceRaw <= 1 ? confidenceRaw : void 0;
|
|
624
|
+
if (confidence === void 0) return void 0;
|
|
625
|
+
return { category, activity, confidence };
|
|
626
|
+
}
|
|
627
|
+
const enhancementSetRaw = frontMatter.enhancementSet;
|
|
628
|
+
const enhancementSet = enhancementSetRaw && typeof enhancementSetRaw === "object" ? (() => {
|
|
629
|
+
const obj = enhancementSetRaw;
|
|
630
|
+
const version2 = obj.version === 1 ? 1 : void 0;
|
|
631
|
+
const intentRaw = obj.intent;
|
|
632
|
+
if (version2 !== 1 || !intentRaw || typeof intentRaw !== "object") return void 0;
|
|
633
|
+
const intent = coerceEnhancementIntent(intentRaw);
|
|
634
|
+
if (!intent) return void 0;
|
|
635
|
+
const enhancementsRaw = obj.enhancements ?? void 0;
|
|
636
|
+
const enhancements2 = Array.isArray(
|
|
637
|
+
enhancementsRaw
|
|
638
|
+
) ? enhancementsRaw.map((e) => {
|
|
639
|
+
if (!e || typeof e !== "object") return null;
|
|
640
|
+
const eObj = e;
|
|
641
|
+
const kind = typeof eObj.kind === "string" ? eObj.kind : void 0;
|
|
642
|
+
const snippet = typeof eObj.snippet === "string" ? eObj.snippet : void 0;
|
|
643
|
+
if (!kind || !snippet) return null;
|
|
644
|
+
return { kind, snippet };
|
|
645
|
+
}).filter(
|
|
646
|
+
(e) => e !== null
|
|
647
|
+
) : void 0;
|
|
648
|
+
if (!enhancements2) return void 0;
|
|
649
|
+
const acceptanceCriteriaRaw = obj.acceptanceCriteria;
|
|
650
|
+
const acceptanceCriteria = Array.isArray(acceptanceCriteriaRaw) ? acceptanceCriteriaRaw.map((c) => {
|
|
651
|
+
if (!c || typeof c !== "object") return null;
|
|
652
|
+
const cObj = c;
|
|
653
|
+
const id2 = typeof cObj.id === "string" ? cObj.id : void 0;
|
|
654
|
+
const description = typeof cObj.description === "string" ? cObj.description : void 0;
|
|
655
|
+
if (!id2 || !description) return null;
|
|
656
|
+
const weight = typeof cObj.weight === "number" ? cObj.weight : void 0;
|
|
657
|
+
const verification = cObj.verification && typeof cObj.verification === "object" ? cObj.verification : void 0;
|
|
658
|
+
return {
|
|
659
|
+
id: id2,
|
|
660
|
+
description,
|
|
661
|
+
weight,
|
|
662
|
+
verification
|
|
663
|
+
};
|
|
664
|
+
}).filter((c) => c !== null) : void 0;
|
|
665
|
+
const constraintsRaw = obj.constraints;
|
|
666
|
+
const constraints = Array.isArray(constraintsRaw) ? constraintsRaw.map((c) => {
|
|
667
|
+
if (!c || typeof c !== "object") return null;
|
|
668
|
+
const cObj = c;
|
|
669
|
+
const id2 = typeof cObj.id === "string" ? cObj.id : void 0;
|
|
670
|
+
const rule = typeof cObj.rule === "string" ? cObj.rule : void 0;
|
|
671
|
+
if (!id2 || !rule) return null;
|
|
672
|
+
const penaltyPoints = typeof cObj.penaltyPoints === "number" ? cObj.penaltyPoints : void 0;
|
|
673
|
+
const scope = cObj.scope && typeof cObj.scope === "object" ? cObj.scope : void 0;
|
|
674
|
+
const allowIf = Array.isArray(cObj.allowIf) ? cObj.allowIf : void 0;
|
|
675
|
+
return {
|
|
676
|
+
id: id2,
|
|
677
|
+
rule,
|
|
678
|
+
penaltyPoints,
|
|
679
|
+
scope,
|
|
680
|
+
allowIf
|
|
681
|
+
};
|
|
682
|
+
}).filter((c) => c !== null) : void 0;
|
|
683
|
+
const artifactSourcesRaw = obj.artifactSources;
|
|
684
|
+
const artifactSources = artifactSourcesRaw && typeof artifactSourcesRaw === "object" ? (() => {
|
|
685
|
+
const a = artifactSourcesRaw;
|
|
686
|
+
const preferred = Array.isArray(a.preferred) ? a.preferred.filter((v) => typeof v === "string") : void 0;
|
|
687
|
+
const fallback = Array.isArray(a.fallback) ? a.fallback.filter((v) => typeof v === "string") : void 0;
|
|
688
|
+
if (!preferred && !fallback) return void 0;
|
|
689
|
+
return { preferred, fallback };
|
|
690
|
+
})() : void 0;
|
|
691
|
+
return {
|
|
692
|
+
version: 1,
|
|
693
|
+
intent,
|
|
694
|
+
enhancements: enhancements2,
|
|
695
|
+
acceptanceCriteria,
|
|
696
|
+
constraints,
|
|
697
|
+
artifactSources
|
|
698
|
+
};
|
|
699
|
+
})() : void 0;
|
|
700
|
+
const enhancementsLegacyRaw = frontMatter.enhancements;
|
|
701
|
+
const enhancementsLegacy = Array.isArray(
|
|
702
|
+
enhancementsLegacyRaw
|
|
703
|
+
) ? enhancementsLegacyRaw.map((e) => {
|
|
704
|
+
if (!e || typeof e !== "object") return null;
|
|
705
|
+
const obj = e;
|
|
706
|
+
const kind = typeof obj.kind === "string" ? obj.kind : void 0;
|
|
707
|
+
const snippet = typeof obj.snippet === "string" ? obj.snippet : void 0;
|
|
708
|
+
if (!kind || !snippet) return null;
|
|
709
|
+
return { kind, snippet };
|
|
710
|
+
}).filter((e) => e !== null) : void 0;
|
|
711
|
+
const enhancements = enhancementSet?.enhancements ?? enhancementsLegacy;
|
|
712
|
+
const blockedReason = typeof frontMatter.blockedReason === "string" && frontMatter.blockedReason.trim() ? frontMatter.blockedReason.trim() : void 0;
|
|
713
|
+
const blockedReasonHistory = Array.isArray(frontMatter.blockedReasonHistory) ? frontMatter.blockedReasonHistory.filter(
|
|
714
|
+
(value) => typeof value === "string" && value.trim().length > 0
|
|
715
|
+
) : void 0;
|
|
716
|
+
const forceCompletedFrom = isTaskStatus(frontMatter.forceCompletedFrom) && frontMatter.forceCompletedFrom !== "done" ? frontMatter.forceCompletedFrom : void 0;
|
|
717
|
+
const originalBlockedReason = typeof frontMatter.originalBlockedReason === "string" && frontMatter.originalBlockedReason.trim() ? frontMatter.originalBlockedReason.trim() : void 0;
|
|
718
|
+
const cancelledAt = typeof frontMatter.cancelledAt === "string" && frontMatter.cancelledAt.trim() ? frontMatter.cancelledAt.trim() : void 0;
|
|
719
|
+
const cancelledReason = typeof frontMatter.cancelledReason === "string" && frontMatter.cancelledReason.trim() ? frontMatter.cancelledReason.trim() : void 0;
|
|
720
|
+
const completionContract = normalizeCompletionContracts(frontMatter.completionContract);
|
|
721
|
+
const appliedTransitions = Array.isArray(frontMatter.appliedTransitions) ? frontMatter.appliedTransitions.filter(
|
|
722
|
+
(value) => typeof value === "string" && value.length > 0
|
|
723
|
+
) : void 0;
|
|
724
|
+
const lastTransitionReason = typeof frontMatter.lastTransitionReason === "string" && frontMatter.lastTransitionReason.trim() ? frontMatter.lastTransitionReason.trim() : void 0;
|
|
725
|
+
const ownership = parseWorkOwnership(frontMatter.ownership);
|
|
726
|
+
const statusBypassAudit = Array.isArray(frontMatter.statusBypassAudit) ? frontMatter.statusBypassAudit.map((entry) => {
|
|
727
|
+
if (!entry || typeof entry !== "object") return null;
|
|
728
|
+
const obj = entry;
|
|
729
|
+
const fromStatus = obj.fromStatus;
|
|
730
|
+
const toStatus = obj.toStatus;
|
|
731
|
+
const reason = typeof obj.reason === "string" ? obj.reason.trim() : "";
|
|
732
|
+
const at = typeof obj.at === "string" ? obj.at : "";
|
|
733
|
+
if (!isTaskStatus(fromStatus) || !isTaskStatus(toStatus) || !reason || !at) {
|
|
734
|
+
return null;
|
|
735
|
+
}
|
|
736
|
+
const actor = typeof obj.actor === "string" && obj.actor.trim() ? obj.actor.trim() : void 0;
|
|
737
|
+
return { at, fromStatus, toStatus, reason, actor };
|
|
738
|
+
}).filter(
|
|
739
|
+
(entry) => Boolean(entry)
|
|
740
|
+
) : void 0;
|
|
741
|
+
const coerced = {
|
|
742
|
+
...frontMatter,
|
|
743
|
+
id,
|
|
744
|
+
kind: "task",
|
|
745
|
+
version,
|
|
746
|
+
sprintId,
|
|
747
|
+
originalSprintId,
|
|
748
|
+
backlogItemId: typeof frontMatter.backlogItemId === "string" ? frontMatter.backlogItemId : void 0,
|
|
749
|
+
planArtifactPath: typeof frontMatter.planArtifactPath === "string" ? frontMatter.planArtifactPath : void 0,
|
|
750
|
+
resultArtifactPath: typeof frontMatter.resultArtifactPath === "string" ? frontMatter.resultArtifactPath : void 0,
|
|
751
|
+
planIntentHash: typeof frontMatter.planIntentHash === "string" ? frontMatter.planIntentHash : void 0,
|
|
752
|
+
planStageId: typeof frontMatter.planStageId === "string" ? frontMatter.planStageId : void 0,
|
|
753
|
+
splitStrategy: frontMatter.splitStrategy === "ai" || frontMatter.splitStrategy === "rule-based" ? frontMatter.splitStrategy : void 0,
|
|
754
|
+
splitMode: frontMatter.splitMode === "rule" || frontMatter.splitMode === "shadow" || frontMatter.splitMode === "llm" ? frontMatter.splitMode : void 0,
|
|
755
|
+
splitTaskType: typeof frontMatter.splitTaskType === "string" ? frontMatter.splitTaskType : void 0,
|
|
756
|
+
splitSourceBacklogItemId: typeof frontMatter.splitSourceBacklogItemId === "string" ? frontMatter.splitSourceBacklogItemId : void 0,
|
|
757
|
+
taskType,
|
|
758
|
+
declaredType,
|
|
759
|
+
declaredMethodology,
|
|
760
|
+
resolvedTaskTypeId,
|
|
761
|
+
title,
|
|
762
|
+
status,
|
|
763
|
+
priority,
|
|
764
|
+
assignee: typeof frontMatter.assignee === "string" ? frontMatter.assignee : void 0,
|
|
765
|
+
estimatedHours: parseNumber(frontMatter.estimatedHours, 0),
|
|
766
|
+
// AI runtime estimate fields: preserved only when present and valid. Never
|
|
767
|
+
// synthesized — a legacy task without them stays without them (no fake data).
|
|
768
|
+
...coerceRuntimeEstimateFields(frontMatter),
|
|
769
|
+
timeLoggedHours: parseNumber(frontMatter.timeLoggedHours, 0),
|
|
770
|
+
dependencies,
|
|
771
|
+
subtasks,
|
|
772
|
+
hints,
|
|
773
|
+
enhancements,
|
|
774
|
+
enhancementSet,
|
|
775
|
+
routing,
|
|
776
|
+
flywheel,
|
|
777
|
+
taskClassification,
|
|
778
|
+
blockedReason,
|
|
779
|
+
blockedReasonHistory,
|
|
780
|
+
forceCompletedFrom,
|
|
781
|
+
originalBlockedReason,
|
|
782
|
+
statusBypassAudit,
|
|
783
|
+
...completionContract.length > 0 ? { completionContract } : {},
|
|
784
|
+
...appliedTransitions && appliedTransitions.length > 0 ? { appliedTransitions } : {},
|
|
785
|
+
...lastTransitionReason ? { lastTransitionReason } : {},
|
|
786
|
+
metadata,
|
|
787
|
+
created_at: createdAt,
|
|
788
|
+
updated_at: updatedAt,
|
|
789
|
+
started_at: typeof frontMatter.started_at === "string" ? frontMatter.started_at : void 0,
|
|
790
|
+
completed_at: typeof frontMatter.completed_at === "string" ? frontMatter.completed_at : void 0,
|
|
791
|
+
cancelledAt,
|
|
792
|
+
cancelledReason
|
|
793
|
+
};
|
|
794
|
+
if (ownership) {
|
|
795
|
+
coerced.ownership = ownership;
|
|
796
|
+
} else {
|
|
797
|
+
delete coerced.ownership;
|
|
798
|
+
}
|
|
799
|
+
return coerced;
|
|
800
|
+
}
|
|
801
|
+
async function generateTaskId(sprintId, title) {
|
|
802
|
+
void sprintId;
|
|
803
|
+
void title;
|
|
804
|
+
return generateId(/* @__PURE__ */ new Date());
|
|
805
|
+
}
|
|
806
|
+
async function createTask(title, sprintId, options = {}, repoRoot) {
|
|
807
|
+
const result = await createTaskWithGuidance(title, sprintId, options, repoRoot);
|
|
808
|
+
return result.task;
|
|
809
|
+
}
|
|
810
|
+
async function createTaskWithGuidance(title, sprintId, options = {}, repoRoot) {
|
|
811
|
+
const planningRoot = repoRoot ?? getPlanningRoot();
|
|
812
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
813
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
814
|
+
assertBucketWriteAvailable(planningRoot);
|
|
815
|
+
await ensureDirectoryExists(tasksDir);
|
|
816
|
+
assertSafePlanningFileId(sprintId, "sprintId");
|
|
817
|
+
const taskId = await generateTaskId(sprintId, title);
|
|
818
|
+
const filePath = resolvePlanningItemPath(tasksDir, taskId, { label: "taskId" });
|
|
819
|
+
const dependencies = [...new Set(options.dependencies ?? [])];
|
|
820
|
+
if (dependencies.includes(taskId)) {
|
|
821
|
+
throw new Error(`Task cannot depend on itself: ${taskId}`);
|
|
822
|
+
}
|
|
823
|
+
if (dependencies.length > 0) {
|
|
824
|
+
const taskPath = getBucketPathByKind("task", planningRoot);
|
|
825
|
+
const taskArchivePath = getBucketArchivePathByKind("task", planningRoot);
|
|
826
|
+
const allItems = await loadAllItems(planningRoot, [taskPath, taskArchivePath]);
|
|
827
|
+
const allIds = new Set(allItems.map((item) => item.id));
|
|
828
|
+
const missingDependencies = dependencies.filter((depId) => !allIds.has(depId));
|
|
829
|
+
if (missingDependencies.length > 0) {
|
|
830
|
+
throw new Error(`Dependency task not found: ${missingDependencies.join(", ")}`);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
834
|
+
const ownership = parseWorkOwnership(options.ownership);
|
|
835
|
+
const task = {
|
|
836
|
+
id: taskId,
|
|
837
|
+
kind: "task",
|
|
838
|
+
version: 1,
|
|
839
|
+
sprintId,
|
|
840
|
+
backlogItemId: options.backlogItemId,
|
|
841
|
+
planArtifactPath: options.planArtifactPath,
|
|
842
|
+
planIntentHash: options.planIntentHash,
|
|
843
|
+
planStageId: options.planStageId,
|
|
844
|
+
splitStrategy: options.splitStrategy,
|
|
845
|
+
splitMode: options.splitMode,
|
|
846
|
+
splitTaskType: options.splitTaskType,
|
|
847
|
+
splitSourceBacklogItemId: options.splitSourceBacklogItemId,
|
|
848
|
+
// Declared terminology (verbatim, opaque) + its resolved canonical id are
|
|
849
|
+
// carried through from the originating backlog item / decomposition so the
|
|
850
|
+
// declared term actually reaches sprint workflow resolution. Only set when
|
|
851
|
+
// present so legacy tasks stay clean.
|
|
852
|
+
...typeof options.declaredType === "string" && options.declaredType.length > 0 ? { declaredType: options.declaredType } : {},
|
|
853
|
+
...typeof options.declaredMethodology === "string" && options.declaredMethodology.length > 0 ? { declaredMethodology: options.declaredMethodology } : {},
|
|
854
|
+
...typeof options.resolvedTaskTypeId === "string" && options.resolvedTaskTypeId.length > 0 ? { resolvedTaskTypeId: options.resolvedTaskTypeId } : {},
|
|
855
|
+
title,
|
|
856
|
+
status: "todo",
|
|
857
|
+
priority: options.priority ?? "P2",
|
|
858
|
+
assignee: options.assignee ?? (ownership?.kind === "human" ? ownership.id : void 0),
|
|
859
|
+
...ownership ? { ownership } : {},
|
|
860
|
+
estimatedHours: options.estimatedHours ?? 0,
|
|
861
|
+
// AI runtime estimate is optional and never defaulted (absence is honest,
|
|
862
|
+
// not zero/fake). Human hours are legacy Scrum accounting: do not
|
|
863
|
+
// fabricate a 4h default when the caller omitted them.
|
|
864
|
+
...typeof options.expectedRuntimeMinutes === "number" && options.expectedRuntimeMinutes > 0 ? { expectedRuntimeMinutes: options.expectedRuntimeMinutes } : {},
|
|
865
|
+
...options.runtimeEstimateProvenance ? { runtimeEstimateProvenance: options.runtimeEstimateProvenance } : {},
|
|
866
|
+
...options.runtimeEstimateConfidence ? { runtimeEstimateConfidence: options.runtimeEstimateConfidence } : {},
|
|
867
|
+
timeLoggedHours: 0,
|
|
868
|
+
dependencies,
|
|
869
|
+
subtasks: options.subtasks || [],
|
|
870
|
+
routing: options.routing,
|
|
871
|
+
flywheel: options.flywheel,
|
|
872
|
+
...options.metadata ? { metadata: options.metadata } : {},
|
|
873
|
+
created_at: now,
|
|
874
|
+
updated_at: now
|
|
875
|
+
};
|
|
876
|
+
const description = typeof options.description === "string" && options.description.trim().length > 0 ? options.description.trim() : "Task created from sprint planning.";
|
|
877
|
+
let guidance;
|
|
878
|
+
if (options.planStageId) {
|
|
879
|
+
guidance = {
|
|
880
|
+
intent: { category: "execute", activity: "development", confidence: 1 },
|
|
881
|
+
enhancements: [],
|
|
882
|
+
quickReply: "",
|
|
883
|
+
nextCommands: []
|
|
884
|
+
};
|
|
885
|
+
} else {
|
|
886
|
+
guidance = generateEnhancements({
|
|
887
|
+
title,
|
|
888
|
+
description,
|
|
889
|
+
id: taskId,
|
|
890
|
+
itemKind: "task",
|
|
891
|
+
sprintId
|
|
892
|
+
});
|
|
893
|
+
const persistedEnhancements = toPersistedFormat(guidance.enhancements);
|
|
894
|
+
if (persistedEnhancements.length > 0) {
|
|
895
|
+
task.enhancements = persistedEnhancements;
|
|
896
|
+
task.enhancementSet = toEnhancementSet(guidance);
|
|
897
|
+
}
|
|
898
|
+
const hints = hintsFromEnhancements(guidance.enhancements);
|
|
899
|
+
if (hints.length > 0) task.hints = hints;
|
|
900
|
+
}
|
|
901
|
+
const body = `# Task: ${title}
|
|
902
|
+
|
|
903
|
+
**Sprint**: ${sprintId}
|
|
904
|
+
**Status**: To Do
|
|
905
|
+
${task.planArtifactPath ? `**Plan Artifact**: ${task.planArtifactPath}
|
|
906
|
+
` : ""}${task.planStageId ? `**Plan Stage**: ${task.planStageId}
|
|
907
|
+
` : ""}
|
|
908
|
+
|
|
909
|
+
## Description
|
|
910
|
+
|
|
911
|
+
${description}
|
|
912
|
+
|
|
913
|
+
## Subtasks
|
|
914
|
+
|
|
915
|
+
${task.subtasks.length > 0 ? task.subtasks.map((st, _i) => `- [ ] ${st.text}`).join("\n") : "(No subtasks defined)"}
|
|
916
|
+
|
|
917
|
+
## Notes
|
|
918
|
+
|
|
919
|
+
Created on ${now}
|
|
920
|
+
`;
|
|
921
|
+
const persisted = { ...task };
|
|
922
|
+
if (typeof options.estimatedHours !== "number") {
|
|
923
|
+
delete persisted.estimatedHours;
|
|
924
|
+
}
|
|
925
|
+
if (task.timeLoggedHours === 0) {
|
|
926
|
+
delete persisted.timeLoggedHours;
|
|
927
|
+
}
|
|
928
|
+
await writeMarkdownFile(
|
|
929
|
+
filePath,
|
|
930
|
+
persisted,
|
|
931
|
+
body
|
|
932
|
+
);
|
|
933
|
+
return { task, filePath, guidance };
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
function formatTaskStatusLabel(status) {
|
|
937
|
+
switch (status) {
|
|
938
|
+
case "todo":
|
|
939
|
+
return "To Do";
|
|
940
|
+
case "in_progress":
|
|
941
|
+
return "In Progress";
|
|
942
|
+
case "review":
|
|
943
|
+
return "Review";
|
|
944
|
+
case "done":
|
|
945
|
+
return "Done";
|
|
946
|
+
case "blocked":
|
|
947
|
+
return "Blocked";
|
|
948
|
+
case "cancelled":
|
|
949
|
+
return "Cancelled";
|
|
950
|
+
default:
|
|
951
|
+
return "To Do";
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
function updateTaskBodyStatusLine(body, status) {
|
|
955
|
+
const desiredLine = `**Status**: ${formatTaskStatusLabel(status)}`;
|
|
956
|
+
if (/^\*\*Status\*\*:/m.test(body)) {
|
|
957
|
+
return body.replace(/^\*\*Status\*\*:\s*.*$/m, desiredLine);
|
|
958
|
+
}
|
|
959
|
+
const afterSprint = body.match(/^\*\*Sprint\*\*:\s*.*$/m);
|
|
960
|
+
if (afterSprint?.index !== void 0) {
|
|
961
|
+
const insertAt = afterSprint.index + afterSprint[0].length;
|
|
962
|
+
return `${body.slice(0, insertAt)}
|
|
963
|
+
${desiredLine}${body.slice(insertAt)}`;
|
|
964
|
+
}
|
|
965
|
+
return `${desiredLine}
|
|
966
|
+
|
|
967
|
+
${body}`;
|
|
968
|
+
}
|
|
969
|
+
function normalizeDescriptionSectionContent(description) {
|
|
970
|
+
const trimmed = description.trim();
|
|
971
|
+
const headingMatch = trimmed.match(/^##\s+Description\b[^\n]*\n?/i);
|
|
972
|
+
if (!headingMatch) return trimmed;
|
|
973
|
+
return trimmed.slice(headingMatch[0].length).trim();
|
|
974
|
+
}
|
|
975
|
+
function keepTaskHeaderMetadata(prefix) {
|
|
976
|
+
const lines = prefix.split("\n");
|
|
977
|
+
let lastMetadataLineIndex = -1;
|
|
978
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
979
|
+
if (isTaskHeaderMetadataLine(lines[index] ?? "")) {
|
|
980
|
+
lastMetadataLineIndex = index;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
if (lastMetadataLineIndex < 0) return "";
|
|
984
|
+
return lines.slice(0, lastMetadataLineIndex + 1).join("\n").trimEnd();
|
|
985
|
+
}
|
|
986
|
+
function updateTaskBodyDescriptionSection(body, description) {
|
|
987
|
+
const content = normalizeDescriptionSectionContent(description);
|
|
988
|
+
const section = `## Description
|
|
989
|
+
|
|
990
|
+
${content}`;
|
|
991
|
+
const spans = findFencedCodeSpans(body);
|
|
992
|
+
const existingHeading = matchOutsideFences(body, /^##\s+Description\b[^\n]*$/im, 0, spans);
|
|
993
|
+
if (existingHeading?.index !== void 0) {
|
|
994
|
+
const headingStart = existingHeading.index;
|
|
995
|
+
const afterHeading = headingStart + existingHeading[0].length;
|
|
996
|
+
const sectionEnd = matchOutsideFences(body, /^##\s+/m, afterHeading, spans)?.index ?? body.length;
|
|
997
|
+
const before = body.slice(0, headingStart).trimEnd();
|
|
998
|
+
const after = body.slice(sectionEnd).trimStart();
|
|
999
|
+
return `${before}
|
|
1000
|
+
|
|
1001
|
+
${section}${after ? `
|
|
1002
|
+
|
|
1003
|
+
${after}` : ""}`.trim();
|
|
1004
|
+
}
|
|
1005
|
+
const insertBefore = matchOutsideFences(body, /^##\s+/m, 0, spans)?.index ?? -1;
|
|
1006
|
+
if (insertBefore >= 0) {
|
|
1007
|
+
const before = keepTaskHeaderMetadata(body.slice(0, insertBefore));
|
|
1008
|
+
const after = body.slice(insertBefore).trimStart();
|
|
1009
|
+
return `${before ? `${before}
|
|
1010
|
+
|
|
1011
|
+
` : ""}${section}
|
|
1012
|
+
|
|
1013
|
+
${after}`.trim();
|
|
1014
|
+
}
|
|
1015
|
+
const existingMetadata = keepTaskHeaderMetadata(body);
|
|
1016
|
+
if (!existingMetadata) return `${section}
|
|
1017
|
+
`;
|
|
1018
|
+
return `${existingMetadata}
|
|
1019
|
+
|
|
1020
|
+
${section}`;
|
|
1021
|
+
}
|
|
1022
|
+
async function updateTaskFields(taskId, updates) {
|
|
1023
|
+
const planningRoot = getPlanningRoot();
|
|
1024
|
+
if (updates.description !== void 0 && updates.body !== void 0) {
|
|
1025
|
+
throw new Error("Cannot update both description and body in one operation");
|
|
1026
|
+
}
|
|
1027
|
+
if (updates.body !== void 0 && updates.body.trim().length === 0) {
|
|
1028
|
+
throw new Error("Task body cannot be empty");
|
|
1029
|
+
}
|
|
1030
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1031
|
+
const lookup = await getTask(taskId, { includeArchive: false });
|
|
1032
|
+
const { frontMatter, body } = await readMarkdownFile(lookup.filePath);
|
|
1033
|
+
const nextFrontMatter = {
|
|
1034
|
+
...frontMatter,
|
|
1035
|
+
...lookup.yaml
|
|
1036
|
+
};
|
|
1037
|
+
if (updates.title !== void 0) {
|
|
1038
|
+
const title = updates.title.trim();
|
|
1039
|
+
if (!title) throw new Error("Task title cannot be empty");
|
|
1040
|
+
nextFrontMatter.title = title;
|
|
1041
|
+
}
|
|
1042
|
+
if (updates.priority !== void 0) nextFrontMatter.priority = updates.priority;
|
|
1043
|
+
if (updates.estimatedHours !== void 0) {
|
|
1044
|
+
nextFrontMatter.estimatedHours = updates.estimatedHours;
|
|
1045
|
+
}
|
|
1046
|
+
if (updates.expectedRuntimeMinutes !== void 0) {
|
|
1047
|
+
nextFrontMatter.expectedRuntimeMinutes = updates.expectedRuntimeMinutes;
|
|
1048
|
+
}
|
|
1049
|
+
if (updates.assignee !== void 0) {
|
|
1050
|
+
const assignee = updates.assignee?.trim() ?? "";
|
|
1051
|
+
if (assignee) {
|
|
1052
|
+
nextFrontMatter.assignee = assignee;
|
|
1053
|
+
} else {
|
|
1054
|
+
delete nextFrontMatter.assignee;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
if (updates.ownership !== void 0) {
|
|
1058
|
+
if (updates.ownership === null) {
|
|
1059
|
+
delete nextFrontMatter.ownership;
|
|
1060
|
+
} else {
|
|
1061
|
+
const ownership = parseWorkOwnership(updates.ownership);
|
|
1062
|
+
if (ownership) {
|
|
1063
|
+
nextFrontMatter.ownership = ownership;
|
|
1064
|
+
} else {
|
|
1065
|
+
delete nextFrontMatter.ownership;
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
applyTaskExecutionControlUpdates(nextFrontMatter, updates);
|
|
1070
|
+
nextFrontMatter.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1071
|
+
nextFrontMatter.version = (lookup.yaml.version ?? 0) + 1;
|
|
1072
|
+
const updatedTask = coerceTaskYAML(nextFrontMatter);
|
|
1073
|
+
const nextBody = updates.body !== void 0 ? updates.body.trim() : updates.description !== void 0 ? updateTaskBodyDescriptionSection(body, updates.description) : body;
|
|
1074
|
+
await writeMarkdownFile(
|
|
1075
|
+
lookup.filePath,
|
|
1076
|
+
nextFrontMatter,
|
|
1077
|
+
keepActivity(`Task ${taskId}`, body, updateTaskBodyStatusLine(nextBody, updatedTask.status))
|
|
1078
|
+
);
|
|
1079
|
+
return updatedTask;
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
async function applyTaskOwnershipLifecycle(taskId, operation, options = {}) {
|
|
1083
|
+
const planningRoot = getPlanningRoot();
|
|
1084
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1085
|
+
const lookup = await getTask(taskId, { includeArchive: false });
|
|
1086
|
+
const canonical = parseWorkOwnership(lookup.yaml.ownership);
|
|
1087
|
+
const current = options.legacyAssigneePolicy === "ignore" ? canonical ?? null : projectWorkOwnership(canonical, lookup.yaml.assignee);
|
|
1088
|
+
const result = operation(current, (/* @__PURE__ */ new Date()).toISOString());
|
|
1089
|
+
if (!result.ok) {
|
|
1090
|
+
return { task: lookup.yaml, result };
|
|
1091
|
+
}
|
|
1092
|
+
const task = await updateTaskFields(taskId, {
|
|
1093
|
+
ownership: result.ownership,
|
|
1094
|
+
assignee: result.ownership ? result.ownership.id : null
|
|
1095
|
+
});
|
|
1096
|
+
return { task, result };
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
1099
|
+
async function updateTaskStatus(taskId, newStatus, options = {}) {
|
|
1100
|
+
const planningRoot = getPlanningRoot();
|
|
1101
|
+
const bypassReasonPre = options.bypassValidation?.reason.trim();
|
|
1102
|
+
let contractEval;
|
|
1103
|
+
let unverifiedLabel;
|
|
1104
|
+
if (newStatus === "done" && !bypassReasonPre) {
|
|
1105
|
+
const preEval = await readTaskForCompletionEval(taskId, planningRoot);
|
|
1106
|
+
if (preEval.task.status !== "done" && (preEval.task.completionContract?.length ?? 0) > 0) {
|
|
1107
|
+
const evaluatedVersion = preEval.task.version;
|
|
1108
|
+
const contractKey = completionContractSnapshotKey(preEval.task.completionContract);
|
|
1109
|
+
const gate = await assertCompletionContractsMet({
|
|
1110
|
+
contracts: preEval.task.completionContract,
|
|
1111
|
+
bypassReason: bypassReasonPre,
|
|
1112
|
+
workingDir: options.completionContractRoot
|
|
1113
|
+
});
|
|
1114
|
+
if (gate.unverifiedLabel) {
|
|
1115
|
+
unverifiedLabel = gate.unverifiedLabel;
|
|
1116
|
+
options.onUnverifiedCompletion?.(gate.unverifiedLabel);
|
|
1117
|
+
}
|
|
1118
|
+
contractEval = { evaluatedVersion, contractKey };
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1122
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1123
|
+
const files = await listMarkdownFiles(tasksDir);
|
|
1124
|
+
const taskFile = files.find((f) => path2.basename(f) === `${taskId}.md`);
|
|
1125
|
+
if (!taskFile) {
|
|
1126
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1127
|
+
}
|
|
1128
|
+
const { frontMatter, body } = await readMarkdownFile(taskFile);
|
|
1129
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1130
|
+
const currentVersion = task.version;
|
|
1131
|
+
if (options.expectedVersion !== void 0 && currentVersion !== options.expectedVersion) {
|
|
1132
|
+
throw new StaleVersionError(currentVersion, options.expectedVersion, taskId);
|
|
1133
|
+
}
|
|
1134
|
+
if (task.status === newStatus && newStatus !== "blocked") {
|
|
1135
|
+
if (options?.resultArtifactPath && task.resultArtifactPath !== options.resultArtifactPath) {
|
|
1136
|
+
task.resultArtifactPath = options.resultArtifactPath;
|
|
1137
|
+
task.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1138
|
+
task.version = currentVersion + 1;
|
|
1139
|
+
await writeMarkdownFile(
|
|
1140
|
+
taskFile,
|
|
1141
|
+
task,
|
|
1142
|
+
updateTaskBodyStatusLine(body, task.status)
|
|
1143
|
+
);
|
|
1144
|
+
}
|
|
1145
|
+
return task;
|
|
1146
|
+
}
|
|
1147
|
+
const bypass = options.bypassValidation;
|
|
1148
|
+
const bypassReason = bypass?.reason.trim();
|
|
1149
|
+
if (bypass && !bypassReason) {
|
|
1150
|
+
throw new Error("Task status validation bypass requires a reason");
|
|
1151
|
+
}
|
|
1152
|
+
if (!bypass) {
|
|
1153
|
+
const transition = await validateStateTransition(
|
|
1154
|
+
planningRoot,
|
|
1155
|
+
taskId,
|
|
1156
|
+
task.status,
|
|
1157
|
+
newStatus
|
|
1158
|
+
);
|
|
1159
|
+
if (!transition.success) {
|
|
1160
|
+
const details = transition.errors?.length ? `: ${transition.errors.join("; ")}` : "";
|
|
1161
|
+
throw new Error(`${transition.message}${details}`);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
if (newStatus === "done") {
|
|
1165
|
+
if (contractEval) {
|
|
1166
|
+
if (currentVersion !== contractEval.evaluatedVersion || completionContractSnapshotKey(task.completionContract) !== contractEval.contractKey) {
|
|
1167
|
+
throw new StaleVersionError(
|
|
1168
|
+
currentVersion,
|
|
1169
|
+
contractEval.evaluatedVersion,
|
|
1170
|
+
taskId,
|
|
1171
|
+
"completionContract",
|
|
1172
|
+
"concurrent task mutation between completion-contract evaluation and status write"
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
} else {
|
|
1176
|
+
const gate = await assertCompletionContractsMet({
|
|
1177
|
+
contracts: task.completionContract,
|
|
1178
|
+
bypassReason,
|
|
1179
|
+
workingDir: options.completionContractRoot
|
|
1180
|
+
});
|
|
1181
|
+
if (gate.unverifiedLabel) {
|
|
1182
|
+
unverifiedLabel = gate.unverifiedLabel;
|
|
1183
|
+
options.onUnverifiedCompletion?.(gate.unverifiedLabel);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
const previousStatus = task.status;
|
|
1188
|
+
task.status = newStatus;
|
|
1189
|
+
task.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1190
|
+
task.version = currentVersion + 1;
|
|
1191
|
+
if (bypass && bypassReason) {
|
|
1192
|
+
task.statusBypassAudit = [
|
|
1193
|
+
...task.statusBypassAudit ?? [],
|
|
1194
|
+
{
|
|
1195
|
+
at: task.updated_at,
|
|
1196
|
+
fromStatus: previousStatus,
|
|
1197
|
+
toStatus: newStatus,
|
|
1198
|
+
reason: bypassReason,
|
|
1199
|
+
...bypass.actor ? { actor: bypass.actor } : {}
|
|
1200
|
+
}
|
|
1201
|
+
];
|
|
1202
|
+
}
|
|
1203
|
+
if (previousStatus === "blocked" && newStatus === "blocked" && task.blockedReason && options?.blockedReason && task.blockedReason !== options.blockedReason) {
|
|
1204
|
+
task.blockedReasonHistory = [...task.blockedReasonHistory ?? [], task.blockedReason];
|
|
1205
|
+
}
|
|
1206
|
+
if (newStatus === "blocked" && options?.blockedReason) {
|
|
1207
|
+
task.blockedReason = options.blockedReason;
|
|
1208
|
+
} else if (newStatus !== "blocked") {
|
|
1209
|
+
task.blockedReason = void 0;
|
|
1210
|
+
}
|
|
1211
|
+
if (newStatus === "in_progress" && !task.started_at) {
|
|
1212
|
+
task.started_at = task.updated_at;
|
|
1213
|
+
}
|
|
1214
|
+
if (newStatus === "done") {
|
|
1215
|
+
task.completed_at = task.updated_at;
|
|
1216
|
+
} else if (previousStatus === "done") {
|
|
1217
|
+
task.completed_at = void 0;
|
|
1218
|
+
}
|
|
1219
|
+
if (previousStatus === "cancelled" && newStatus !== "cancelled") {
|
|
1220
|
+
task.cancelledAt = void 0;
|
|
1221
|
+
task.cancelledReason = void 0;
|
|
1222
|
+
}
|
|
1223
|
+
if (options?.resultArtifactPath) {
|
|
1224
|
+
task.resultArtifactPath = options.resultArtifactPath;
|
|
1225
|
+
}
|
|
1226
|
+
await writeMarkdownFile(
|
|
1227
|
+
taskFile,
|
|
1228
|
+
task,
|
|
1229
|
+
updateTaskBodyStatusLine(body, task.status)
|
|
1230
|
+
);
|
|
1231
|
+
await recordUnverifiedCompletion(taskFile, unverifiedLabel, task.updated_at);
|
|
1232
|
+
if (newStatus === "done") {
|
|
1233
|
+
const unblockedTaskIds = await autoUnblockDependentTasks(task.id, planningRoot);
|
|
1234
|
+
if (unblockedTaskIds.length > 0) {
|
|
1235
|
+
options.onDependentsUnblocked?.(unblockedTaskIds);
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
if (task.sprintId) {
|
|
1239
|
+
try {
|
|
1240
|
+
const { refreshSprintMarkdown } = await import("./sprint-manager-MU2ZUWN2.js");
|
|
1241
|
+
await refreshSprintMarkdown(task.sprintId);
|
|
1242
|
+
} catch (refreshError) {
|
|
1243
|
+
const msg = refreshError instanceof Error ? refreshError.message : String(refreshError);
|
|
1244
|
+
emitTaskManagerWarning("Failed to refresh sprint markdown after task status change", {
|
|
1245
|
+
sprintId: task.sprintId,
|
|
1246
|
+
taskId: task.id,
|
|
1247
|
+
error: msg
|
|
1248
|
+
});
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
return task;
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
async function updateTaskStatusWithTransitionValidation(taskId, newStatus, options) {
|
|
1255
|
+
const { isArchived } = await getTask(taskId, {
|
|
1256
|
+
includeArchive: true
|
|
1257
|
+
});
|
|
1258
|
+
if (isArchived) {
|
|
1259
|
+
throw new Error(
|
|
1260
|
+
`Cannot update archived task "${taskId}". Reopen or restore the task before changing status.`
|
|
1261
|
+
);
|
|
1262
|
+
}
|
|
1263
|
+
return updateTaskStatus(taskId, newStatus, options);
|
|
1264
|
+
}
|
|
1265
|
+
async function addTaskDependency(taskId, dependsOnTaskId) {
|
|
1266
|
+
const planningRoot = getPlanningRoot();
|
|
1267
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1268
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1269
|
+
const files = await listMarkdownFiles(tasksDir);
|
|
1270
|
+
const taskFile = files.find((f) => path2.basename(f) === `${taskId}.md`);
|
|
1271
|
+
if (!taskFile) {
|
|
1272
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1273
|
+
}
|
|
1274
|
+
const { frontMatter, body } = await readMarkdownFile(taskFile);
|
|
1275
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1276
|
+
if (task.dependencies.includes(dependsOnTaskId)) {
|
|
1277
|
+
throw new Error(`Dependency already exists: ${taskId} \u2192 ${dependsOnTaskId}`);
|
|
1278
|
+
}
|
|
1279
|
+
if (task.id === dependsOnTaskId) {
|
|
1280
|
+
throw new Error(`Task cannot depend on itself: ${taskId}`);
|
|
1281
|
+
}
|
|
1282
|
+
const taskPath = getBucketPathByKind("task", planningRoot);
|
|
1283
|
+
const taskArchivePath = getBucketArchivePathByKind("task", planningRoot);
|
|
1284
|
+
const allItems = await loadAllItems(planningRoot, [taskPath, taskArchivePath]);
|
|
1285
|
+
const dependencyExists = allItems.some((item) => item.id === dependsOnTaskId);
|
|
1286
|
+
if (!dependencyExists) {
|
|
1287
|
+
throw new Error(`Dependency task not found: ${dependsOnTaskId}`);
|
|
1288
|
+
}
|
|
1289
|
+
const createsCycle = hasDependencyPath(dependsOnTaskId, task.id, allItems);
|
|
1290
|
+
if (createsCycle) {
|
|
1291
|
+
throw new Error(
|
|
1292
|
+
`Circular dependency detected: adding ${task.id} -> ${dependsOnTaskId} would create a cycle`
|
|
1293
|
+
);
|
|
1294
|
+
}
|
|
1295
|
+
task.dependencies.push(dependsOnTaskId);
|
|
1296
|
+
task.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1297
|
+
task.version = task.version + 1;
|
|
1298
|
+
await writeMarkdownFile(
|
|
1299
|
+
taskFile,
|
|
1300
|
+
task,
|
|
1301
|
+
body
|
|
1302
|
+
);
|
|
1303
|
+
return task;
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
async function removeTaskDependency(taskId, dependsOnTaskId) {
|
|
1307
|
+
const planningRoot = getPlanningRoot();
|
|
1308
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1309
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1310
|
+
const files = await listMarkdownFiles(tasksDir);
|
|
1311
|
+
const taskFile = files.find((f) => path2.basename(f) === `${taskId}.md`);
|
|
1312
|
+
if (!taskFile) {
|
|
1313
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1314
|
+
}
|
|
1315
|
+
const { frontMatter, body } = await readMarkdownFile(taskFile);
|
|
1316
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1317
|
+
if (!task.dependencies.includes(dependsOnTaskId)) {
|
|
1318
|
+
throw new Error(`Dependency not found on task: ${taskId} \u2192 ${dependsOnTaskId}`);
|
|
1319
|
+
}
|
|
1320
|
+
task.dependencies = task.dependencies.filter((id) => id !== dependsOnTaskId);
|
|
1321
|
+
task.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1322
|
+
task.version += 1;
|
|
1323
|
+
await writeMarkdownFile(
|
|
1324
|
+
taskFile,
|
|
1325
|
+
task,
|
|
1326
|
+
body
|
|
1327
|
+
);
|
|
1328
|
+
return task;
|
|
1329
|
+
});
|
|
1330
|
+
}
|
|
1331
|
+
function hasDependencyPath(startTaskId, targetTaskId, allItems, visited = /* @__PURE__ */ new Set()) {
|
|
1332
|
+
if (startTaskId === targetTaskId) {
|
|
1333
|
+
return true;
|
|
1334
|
+
}
|
|
1335
|
+
if (visited.has(startTaskId)) {
|
|
1336
|
+
return false;
|
|
1337
|
+
}
|
|
1338
|
+
visited.add(startTaskId);
|
|
1339
|
+
const task = allItems.find((item) => item.id === startTaskId);
|
|
1340
|
+
const dependencies = task?.frontMatter.dependencies;
|
|
1341
|
+
if (!Array.isArray(dependencies) || dependencies.length === 0) {
|
|
1342
|
+
return false;
|
|
1343
|
+
}
|
|
1344
|
+
for (const depId of dependencies) {
|
|
1345
|
+
if (hasDependencyPath(depId, targetTaskId, allItems, visited)) {
|
|
1346
|
+
return true;
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
return false;
|
|
1350
|
+
}
|
|
1351
|
+
async function autoUnblockDependentTasks(completedTaskId, planningRoot) {
|
|
1352
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1353
|
+
const files = await listMarkdownFiles(tasksDir);
|
|
1354
|
+
const unblockedTaskIds = [];
|
|
1355
|
+
const rewrites = [];
|
|
1356
|
+
for (const filePath of files) {
|
|
1357
|
+
try {
|
|
1358
|
+
const { frontMatter, body } = await readMarkdownFile(filePath);
|
|
1359
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1360
|
+
if (task.id === completedTaskId) continue;
|
|
1361
|
+
if (task.status !== "blocked") continue;
|
|
1362
|
+
if (!task.dependencies.includes(completedTaskId)) continue;
|
|
1363
|
+
let hasRemainingBlockers = false;
|
|
1364
|
+
for (const depId of task.dependencies) {
|
|
1365
|
+
const dep = await getTaskDependency(depId, { sprintId: task.sprintId });
|
|
1366
|
+
if (dep.missing || !dep.satisfied) {
|
|
1367
|
+
hasRemainingBlockers = true;
|
|
1368
|
+
break;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
if (hasRemainingBlockers) continue;
|
|
1372
|
+
task.status = "todo";
|
|
1373
|
+
task.blockedReason = void 0;
|
|
1374
|
+
task.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1375
|
+
task.version = task.version + 1;
|
|
1376
|
+
rewrites.push({
|
|
1377
|
+
filePath,
|
|
1378
|
+
originalFrontMatter: frontMatter,
|
|
1379
|
+
originalBody: body,
|
|
1380
|
+
nextFrontMatter: task,
|
|
1381
|
+
nextBody: updateTaskBodyStatusLine(body, task.status),
|
|
1382
|
+
taskId: task.id
|
|
1383
|
+
});
|
|
1384
|
+
} catch {
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
const applied = [];
|
|
1388
|
+
for (const rewrite of rewrites) {
|
|
1389
|
+
try {
|
|
1390
|
+
await writeMarkdownFile(rewrite.filePath, rewrite.nextFrontMatter, rewrite.nextBody);
|
|
1391
|
+
applied.push(rewrite);
|
|
1392
|
+
unblockedTaskIds.push(rewrite.taskId);
|
|
1393
|
+
} catch (error) {
|
|
1394
|
+
for (const previous of applied.reverse()) {
|
|
1395
|
+
await writeMarkdownFile(
|
|
1396
|
+
previous.filePath,
|
|
1397
|
+
previous.originalFrontMatter,
|
|
1398
|
+
previous.originalBody
|
|
1399
|
+
).catch(() => void 0);
|
|
1400
|
+
}
|
|
1401
|
+
throw error;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
return unblockedTaskIds;
|
|
1405
|
+
}
|
|
1406
|
+
async function validateTaskExecution(taskId, options = {}) {
|
|
1407
|
+
const { includeArchive = false } = options;
|
|
1408
|
+
const { yaml: task } = await getTask(taskId, { includeArchive });
|
|
1409
|
+
const blockers = [];
|
|
1410
|
+
if (task.status === "blocked") {
|
|
1411
|
+
blockers.push(`${taskId} (blocked)`);
|
|
1412
|
+
}
|
|
1413
|
+
for (const depId of task.dependencies) {
|
|
1414
|
+
const dep = await getTaskDependency(depId, { sprintId: task.sprintId });
|
|
1415
|
+
if (dep.missing) {
|
|
1416
|
+
blockers.push(`${depId} (not found)`);
|
|
1417
|
+
continue;
|
|
1418
|
+
}
|
|
1419
|
+
if (!dep.satisfied) {
|
|
1420
|
+
blockers.push(`${depId} (status: ${dep.task?.status ?? "unknown"})`);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
return {
|
|
1424
|
+
canExecute: blockers.length === 0,
|
|
1425
|
+
blockers
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
async function logTaskTime(taskId, hours) {
|
|
1429
|
+
const planningRoot = getPlanningRoot();
|
|
1430
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1431
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1432
|
+
const files = await listMarkdownFiles(tasksDir);
|
|
1433
|
+
const taskFile = files.find((f) => path2.basename(f) === `${taskId}.md`);
|
|
1434
|
+
if (!taskFile) {
|
|
1435
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1436
|
+
}
|
|
1437
|
+
const { frontMatter, body } = await readMarkdownFile(taskFile);
|
|
1438
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1439
|
+
task.timeLoggedHours += hours;
|
|
1440
|
+
task.version = task.version + 1;
|
|
1441
|
+
task.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1442
|
+
await writeMarkdownFile(
|
|
1443
|
+
taskFile,
|
|
1444
|
+
task,
|
|
1445
|
+
body
|
|
1446
|
+
);
|
|
1447
|
+
return task;
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
function deriveTransitionIdentity(input) {
|
|
1451
|
+
if (input.transitionId) {
|
|
1452
|
+
return crypto.createHash("sha256").update(`id\0${input.transitionId}`).digest("hex");
|
|
1453
|
+
}
|
|
1454
|
+
const payload = [
|
|
1455
|
+
"content",
|
|
1456
|
+
input.taskId,
|
|
1457
|
+
input.targetStatus,
|
|
1458
|
+
input.hoursLogged && input.hoursLogged > 0 ? String(input.hoursLogged) : "0",
|
|
1459
|
+
input.resultArtifactPath ?? ""
|
|
1460
|
+
].join("\0");
|
|
1461
|
+
return crypto.createHash("sha256").update(payload).digest("hex");
|
|
1462
|
+
}
|
|
1463
|
+
async function applyTaskTransitionOutcome(taskId, input) {
|
|
1464
|
+
const planningRoot = getPlanningRoot();
|
|
1465
|
+
const { isArchived } = await getTask(taskId, { includeArchive: true });
|
|
1466
|
+
if (isArchived) {
|
|
1467
|
+
throw new Error(
|
|
1468
|
+
`Cannot update archived task "${taskId}". Reopen or restore the task before changing status.`
|
|
1469
|
+
);
|
|
1470
|
+
}
|
|
1471
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1472
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1473
|
+
const files = await listMarkdownFiles(tasksDir);
|
|
1474
|
+
const taskFile = files.find((f) => path2.basename(f) === `${taskId}.md`);
|
|
1475
|
+
if (!taskFile) {
|
|
1476
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1477
|
+
}
|
|
1478
|
+
const { frontMatter, body } = await readMarkdownFile(taskFile);
|
|
1479
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1480
|
+
const constituents = input.constituents && input.constituents.length > 0 ? input.constituents : [
|
|
1481
|
+
{
|
|
1482
|
+
identity: deriveTransitionIdentity({
|
|
1483
|
+
taskId,
|
|
1484
|
+
targetStatus: input.targetStatus,
|
|
1485
|
+
hoursLogged: input.hoursLogged,
|
|
1486
|
+
resultArtifactPath: input.resultArtifactPath
|
|
1487
|
+
}),
|
|
1488
|
+
hoursLogged: input.hoursLogged
|
|
1489
|
+
}
|
|
1490
|
+
];
|
|
1491
|
+
const recordedSet = new Set(task.appliedTransitions ?? []);
|
|
1492
|
+
const pendingHourIdentities = [];
|
|
1493
|
+
const seenThisCall = /* @__PURE__ */ new Set();
|
|
1494
|
+
let pendingHours = 0;
|
|
1495
|
+
for (const c of constituents) {
|
|
1496
|
+
if (recordedSet.has(c.identity) || seenThisCall.has(c.identity)) continue;
|
|
1497
|
+
seenThisCall.add(c.identity);
|
|
1498
|
+
pendingHourIdentities.push(c.identity);
|
|
1499
|
+
if (c.hoursLogged && c.hoursLogged > 0) {
|
|
1500
|
+
pendingHours += c.hoursLogged;
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
const hoursPending = pendingHours > 0;
|
|
1504
|
+
const statusChanged = task.status !== input.targetStatus;
|
|
1505
|
+
const artifactChanged = Boolean(
|
|
1506
|
+
input.resultArtifactPath && task.resultArtifactPath !== input.resultArtifactPath
|
|
1507
|
+
);
|
|
1508
|
+
const reason = input.reason?.trim();
|
|
1509
|
+
const reasonChanged = Boolean(reason && task.lastTransitionReason !== reason);
|
|
1510
|
+
if (!statusChanged && !artifactChanged && !reasonChanged && !hoursPending) {
|
|
1511
|
+
return { task, statusChanged: false, fileUpdated: false, hoursApplied: 0 };
|
|
1512
|
+
}
|
|
1513
|
+
if (statusChanged) {
|
|
1514
|
+
const transition = await validateStateTransition(
|
|
1515
|
+
planningRoot,
|
|
1516
|
+
taskId,
|
|
1517
|
+
task.status,
|
|
1518
|
+
input.targetStatus
|
|
1519
|
+
);
|
|
1520
|
+
if (!transition.success) {
|
|
1521
|
+
const details = transition.errors?.length ? `: ${transition.errors.join("; ")}` : "";
|
|
1522
|
+
throw new Error(`${transition.message}${details}`);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
let transitionGate = {};
|
|
1526
|
+
if (statusChanged && input.targetStatus === "done") {
|
|
1527
|
+
transitionGate = await assertCompletionContractsMet({
|
|
1528
|
+
contracts: task.completionContract
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1531
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1532
|
+
const previousStatus = task.status;
|
|
1533
|
+
if (statusChanged) {
|
|
1534
|
+
task.status = input.targetStatus;
|
|
1535
|
+
if (input.targetStatus === "in_progress" && !task.started_at) {
|
|
1536
|
+
task.started_at = now;
|
|
1537
|
+
}
|
|
1538
|
+
if (input.targetStatus === "done") {
|
|
1539
|
+
task.completed_at = now;
|
|
1540
|
+
} else if (previousStatus === "done") {
|
|
1541
|
+
task.completed_at = void 0;
|
|
1542
|
+
}
|
|
1543
|
+
if (input.targetStatus !== "blocked") {
|
|
1544
|
+
task.blockedReason = void 0;
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
if (artifactChanged && input.resultArtifactPath) {
|
|
1548
|
+
task.resultArtifactPath = input.resultArtifactPath;
|
|
1549
|
+
}
|
|
1550
|
+
if (reasonChanged && reason) {
|
|
1551
|
+
task.lastTransitionReason = reason;
|
|
1552
|
+
}
|
|
1553
|
+
let hoursApplied = 0;
|
|
1554
|
+
if (hoursPending) {
|
|
1555
|
+
task.timeLoggedHours += pendingHours;
|
|
1556
|
+
hoursApplied = pendingHours;
|
|
1557
|
+
const next = task.appliedTransitions ? [...task.appliedTransitions] : [];
|
|
1558
|
+
for (const id of pendingHourIdentities) {
|
|
1559
|
+
next.push(id);
|
|
1560
|
+
}
|
|
1561
|
+
task.appliedTransitions = next;
|
|
1562
|
+
}
|
|
1563
|
+
task.version = task.version + 1;
|
|
1564
|
+
task.updated_at = now;
|
|
1565
|
+
await writeMarkdownFile(
|
|
1566
|
+
taskFile,
|
|
1567
|
+
task,
|
|
1568
|
+
updateTaskBodyStatusLine(body, task.status)
|
|
1569
|
+
);
|
|
1570
|
+
await recordUnverifiedCompletion(taskFile, transitionGate.unverifiedLabel, now);
|
|
1571
|
+
if (statusChanged && input.targetStatus === "done") {
|
|
1572
|
+
await autoUnblockDependentTasks(task.id, planningRoot).catch((error) => {
|
|
1573
|
+
emitTaskManagerWarning("Failed to auto-unblock dependent tasks after transition", {
|
|
1574
|
+
taskId: task.id,
|
|
1575
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1576
|
+
});
|
|
1577
|
+
});
|
|
1578
|
+
}
|
|
1579
|
+
if (task.sprintId) {
|
|
1580
|
+
try {
|
|
1581
|
+
const { refreshSprintMarkdown } = await import("./sprint-manager-MU2ZUWN2.js");
|
|
1582
|
+
await refreshSprintMarkdown(task.sprintId);
|
|
1583
|
+
} catch (refreshError) {
|
|
1584
|
+
const msg = refreshError instanceof Error ? refreshError.message : String(refreshError);
|
|
1585
|
+
emitTaskManagerWarning("Failed to refresh sprint markdown after task transition", {
|
|
1586
|
+
sprintId: task.sprintId,
|
|
1587
|
+
taskId: task.id,
|
|
1588
|
+
error: msg
|
|
1589
|
+
});
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
return {
|
|
1593
|
+
task,
|
|
1594
|
+
statusChanged,
|
|
1595
|
+
fileUpdated: true,
|
|
1596
|
+
hoursApplied,
|
|
1597
|
+
unverifiedLabel: transitionGate.unverifiedLabel
|
|
1598
|
+
};
|
|
1599
|
+
});
|
|
1600
|
+
}
|
|
1601
|
+
async function findArchivedTaskPath(taskId, planningRoot) {
|
|
1602
|
+
const archiveDir = getBucketArchivePathByKind("task", planningRoot);
|
|
1603
|
+
return findArchivedTaskFile(archiveDir, taskId);
|
|
1604
|
+
}
|
|
1605
|
+
async function readTaskForCompletionEval(taskId, planningRoot) {
|
|
1606
|
+
const currentDir = getBucketPathByKind("task", planningRoot);
|
|
1607
|
+
const files = await listMarkdownFiles(currentDir);
|
|
1608
|
+
const taskFile = files.find((f) => path2.basename(f) === `${taskId}.md`);
|
|
1609
|
+
if (!taskFile) {
|
|
1610
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1611
|
+
}
|
|
1612
|
+
const { frontMatter } = await readMarkdownFile(taskFile);
|
|
1613
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1614
|
+
return { task };
|
|
1615
|
+
}
|
|
1616
|
+
function completionContractSnapshotKey(contracts) {
|
|
1617
|
+
if (!contracts || contracts.length === 0) return "";
|
|
1618
|
+
return JSON.stringify(contracts);
|
|
1619
|
+
}
|
|
1620
|
+
async function completeTask(taskId, options = {}) {
|
|
1621
|
+
const planningRoot = getPlanningRoot();
|
|
1622
|
+
const forceCompletion = options.force ?? false;
|
|
1623
|
+
const bypass = options.bypassValidation;
|
|
1624
|
+
const bypassReason = bypass?.reason.trim();
|
|
1625
|
+
if (bypass && !bypassReason) {
|
|
1626
|
+
throw new Error("Task status validation bypass requires a reason");
|
|
1627
|
+
}
|
|
1628
|
+
const preEval = await readTaskForCompletionEval(taskId, planningRoot);
|
|
1629
|
+
const preEvalArchivedDuplicate = await findArchivedTaskPath(taskId, planningRoot);
|
|
1630
|
+
if (preEvalArchivedDuplicate) {
|
|
1631
|
+
throw new Error(
|
|
1632
|
+
`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.`
|
|
1633
|
+
);
|
|
1634
|
+
}
|
|
1635
|
+
if (!forceCompletion && (preEval.task.status === "blocked" || preEval.task.status === "cancelled")) {
|
|
1636
|
+
throw new Error(
|
|
1637
|
+
`Cannot complete task ${preEval.task.id} from status "${preEval.task.status}" without --force. Move it to in_progress/review first.`
|
|
1638
|
+
);
|
|
1639
|
+
}
|
|
1640
|
+
const evaluatedVersion = preEval.task.version;
|
|
1641
|
+
const evaluatedContractKey = completionContractSnapshotKey(preEval.task.completionContract);
|
|
1642
|
+
const completionGate = await assertCompletionContractsMet({
|
|
1643
|
+
contracts: preEval.task.completionContract,
|
|
1644
|
+
bypassReason,
|
|
1645
|
+
workingDir: options.completionContractRoot
|
|
1646
|
+
});
|
|
1647
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1648
|
+
const bucket = getBucketByName("task", planningRoot);
|
|
1649
|
+
if (!bucket) {
|
|
1650
|
+
throw new Error("Bucket not configured: task");
|
|
1651
|
+
}
|
|
1652
|
+
const currentDir = getBucketPathByKind("task", planningRoot);
|
|
1653
|
+
const files = await listMarkdownFiles(currentDir);
|
|
1654
|
+
const taskFile = files.find((f) => path2.basename(f) === `${taskId}.md`);
|
|
1655
|
+
if (!taskFile) {
|
|
1656
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1657
|
+
}
|
|
1658
|
+
const archivedDuplicate = await findArchivedTaskPath(taskId, planningRoot);
|
|
1659
|
+
if (archivedDuplicate) {
|
|
1660
|
+
throw new Error(
|
|
1661
|
+
`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.`
|
|
1662
|
+
);
|
|
1663
|
+
}
|
|
1664
|
+
const { frontMatter, body } = await readMarkdownFile(taskFile);
|
|
1665
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1666
|
+
if (task.version !== evaluatedVersion || completionContractSnapshotKey(task.completionContract) !== evaluatedContractKey) {
|
|
1667
|
+
throw new StaleVersionError(
|
|
1668
|
+
task.version,
|
|
1669
|
+
evaluatedVersion,
|
|
1670
|
+
taskId,
|
|
1671
|
+
"completionContract",
|
|
1672
|
+
"concurrent task mutation between completion-contract evaluation and archive write"
|
|
1673
|
+
);
|
|
1674
|
+
}
|
|
1675
|
+
if (!forceCompletion && (task.status === "blocked" || task.status === "cancelled")) {
|
|
1676
|
+
throw new Error(
|
|
1677
|
+
`Cannot complete task ${task.id} from status "${task.status}" without --force. Move it to in_progress/review first.`
|
|
1678
|
+
);
|
|
1679
|
+
}
|
|
1680
|
+
if (task.status !== "done" && !(forceCompletion && (task.status === "blocked" || task.status === "cancelled")) && !bypass) {
|
|
1681
|
+
const transition = await validateStateTransition(planningRoot, taskId, task.status, "done");
|
|
1682
|
+
if (!transition.success) {
|
|
1683
|
+
const details = transition.errors?.length ? `: ${transition.errors.join("; ")}` : "";
|
|
1684
|
+
throw new Error(`${transition.message}${details}`);
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1688
|
+
if (forceCompletion && task.status !== "done") {
|
|
1689
|
+
task.forceCompletedFrom = task.status;
|
|
1690
|
+
if (options.preserveBlockedReason && task.status === "blocked" && task.blockedReason) {
|
|
1691
|
+
task.originalBlockedReason = task.blockedReason;
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
const previousStatus = task.status;
|
|
1695
|
+
task.status = "done";
|
|
1696
|
+
task.version = task.version + 1;
|
|
1697
|
+
task.completed_at = now;
|
|
1698
|
+
task.updated_at = now;
|
|
1699
|
+
task.archivedAt = now;
|
|
1700
|
+
task.originalSprintId = task.sprintId;
|
|
1701
|
+
if (bypass && bypassReason) {
|
|
1702
|
+
task.statusBypassAudit = [
|
|
1703
|
+
...task.statusBypassAudit ?? [],
|
|
1704
|
+
{
|
|
1705
|
+
at: now,
|
|
1706
|
+
fromStatus: previousStatus,
|
|
1707
|
+
toStatus: "done",
|
|
1708
|
+
reason: bypassReason,
|
|
1709
|
+
...bypass.actor ? { actor: bypass.actor } : {}
|
|
1710
|
+
}
|
|
1711
|
+
];
|
|
1712
|
+
}
|
|
1713
|
+
const archivedPath = getArchivedFilePath(bucket, task.id, now, planningRoot);
|
|
1714
|
+
await ensureDirectoryExists(path2.dirname(archivedPath));
|
|
1715
|
+
const archivedBody = updateTaskBodyStatusLine(body, task.status);
|
|
1716
|
+
await writeMarkdownFile(archivedPath, toArchivedTaskFrontMatter(task), archivedBody);
|
|
1717
|
+
await recordUnverifiedCompletion(archivedPath, completionGate.unverifiedLabel, now);
|
|
1718
|
+
try {
|
|
1719
|
+
await detachArchivedTaskFromSprintMembership(task, "archiving");
|
|
1720
|
+
} catch (error) {
|
|
1721
|
+
await fs.unlink(archivedPath).catch(() => void 0);
|
|
1722
|
+
throw error;
|
|
1723
|
+
}
|
|
1724
|
+
const archiveDir = getBucketArchivePathByKind("task", planningRoot);
|
|
1725
|
+
const archivedIndex = archivedTaskIndexes.get(archiveDir);
|
|
1726
|
+
if (archivedIndex) {
|
|
1727
|
+
archivedIndex.set(task.id, archivedPath);
|
|
1728
|
+
}
|
|
1729
|
+
await fs.unlink(taskFile);
|
|
1730
|
+
const unblockedTaskIds = await autoUnblockDependentTasks(task.id, planningRoot).catch(
|
|
1731
|
+
(error) => {
|
|
1732
|
+
emitTaskManagerWarning("Failed to auto-unblock dependent tasks after completion", {
|
|
1733
|
+
taskId: task.id,
|
|
1734
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1735
|
+
});
|
|
1736
|
+
return [];
|
|
1737
|
+
}
|
|
1738
|
+
);
|
|
1739
|
+
return {
|
|
1740
|
+
task,
|
|
1741
|
+
archivedPath,
|
|
1742
|
+
unblockedTaskIds,
|
|
1743
|
+
unverifiedLabel: completionGate.unverifiedLabel
|
|
1744
|
+
};
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
function toArchivedTaskFrontMatter(task) {
|
|
1748
|
+
const frontMatter = { ...task };
|
|
1749
|
+
delete frontMatter.sprintId;
|
|
1750
|
+
delete frontMatter.sprint_id;
|
|
1751
|
+
return frontMatter;
|
|
1752
|
+
}
|
|
1753
|
+
function getErrorCode(error) {
|
|
1754
|
+
if (!error || typeof error !== "object" || !("code" in error)) return void 0;
|
|
1755
|
+
const code = error.code;
|
|
1756
|
+
return typeof code === "string" ? code : void 0;
|
|
1757
|
+
}
|
|
1758
|
+
async function detachArchivedTaskFromSprintMembership(task, action) {
|
|
1759
|
+
if (!task.sprintId) return;
|
|
1760
|
+
try {
|
|
1761
|
+
const { detachArchivedTaskFromSprint } = await import("./sprint-manager-MU2ZUWN2.js");
|
|
1762
|
+
await detachArchivedTaskFromSprint(task.sprintId, task.id, {
|
|
1763
|
+
completed: action === "archiving"
|
|
1764
|
+
});
|
|
1765
|
+
} catch (removeError) {
|
|
1766
|
+
if (getErrorCode(removeError) === "ENOENT") {
|
|
1767
|
+
return;
|
|
1768
|
+
}
|
|
1769
|
+
const removeMessage = removeError instanceof Error ? removeError.message : String(removeError);
|
|
1770
|
+
try {
|
|
1771
|
+
const { refreshSprintMarkdown } = await import("./sprint-manager-MU2ZUWN2.js");
|
|
1772
|
+
await refreshSprintMarkdown(task.sprintId);
|
|
1773
|
+
} catch (refreshError) {
|
|
1774
|
+
emitTaskManagerWarning(`Failed to refresh sprint markdown after ${action} task`, {
|
|
1775
|
+
sprintId: task.sprintId,
|
|
1776
|
+
taskId: task.id,
|
|
1777
|
+
action,
|
|
1778
|
+
error: refreshError instanceof Error ? refreshError.message : String(refreshError)
|
|
1779
|
+
});
|
|
1780
|
+
}
|
|
1781
|
+
throw new Error(
|
|
1782
|
+
`Failed to remove task ${task.id} from sprint ${task.sprintId} after ${action}: ${removeMessage}`
|
|
1783
|
+
);
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
function getCancelledTaskArchivePath(taskId, cancelledAt, planningRoot) {
|
|
1787
|
+
const shard = getArchiveShard(cancelledAt);
|
|
1788
|
+
const taskBucket = getBucketPathByKind("task", planningRoot);
|
|
1789
|
+
const archiveRoot = getBucketArchivePathByKind("task", planningRoot);
|
|
1790
|
+
const extraSegments = path2.relative(taskBucket, archiveRoot).split(path2.sep).filter(Boolean);
|
|
1791
|
+
extraSegments.push("abandoned", shard.year, shard.month);
|
|
1792
|
+
return resolvePlanningItemPath(taskBucket, taskId, {
|
|
1793
|
+
label: "taskId",
|
|
1794
|
+
extraSegments
|
|
1795
|
+
});
|
|
1796
|
+
}
|
|
1797
|
+
async function cancelTask(taskId, options) {
|
|
1798
|
+
const planningRoot = getPlanningRoot();
|
|
1799
|
+
const reason = options.reason.trim();
|
|
1800
|
+
if (!reason) {
|
|
1801
|
+
throw new Error("Cancellation reason is required");
|
|
1802
|
+
}
|
|
1803
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1804
|
+
const currentDir = getBucketPathByKind("task", planningRoot);
|
|
1805
|
+
const files = await listMarkdownFiles(currentDir);
|
|
1806
|
+
const taskFile = files.find((f) => path2.basename(f) === `${taskId}.md`);
|
|
1807
|
+
if (!taskFile) {
|
|
1808
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1809
|
+
}
|
|
1810
|
+
const { frontMatter, body } = await readMarkdownFile(taskFile);
|
|
1811
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1812
|
+
if (options.expectedVersion !== void 0 && task.version !== options.expectedVersion) {
|
|
1813
|
+
throw new StaleVersionError(task.version, options.expectedVersion, taskId);
|
|
1814
|
+
}
|
|
1815
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1816
|
+
const bypass = options.bypassValidation;
|
|
1817
|
+
const bypassReason = bypass?.reason.trim();
|
|
1818
|
+
if (bypass && !bypassReason) {
|
|
1819
|
+
throw new Error("Task status validation bypass requires a reason");
|
|
1820
|
+
}
|
|
1821
|
+
if (!bypass) {
|
|
1822
|
+
const transition = await validateStateTransition(
|
|
1823
|
+
planningRoot,
|
|
1824
|
+
taskId,
|
|
1825
|
+
task.status,
|
|
1826
|
+
"cancelled"
|
|
1827
|
+
);
|
|
1828
|
+
if (!transition.success) {
|
|
1829
|
+
const details = transition.errors?.length ? `: ${transition.errors.join("; ")}` : "";
|
|
1830
|
+
throw new Error(`${transition.message}${details}`);
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
const previousStatus = task.status;
|
|
1834
|
+
task.status = "cancelled";
|
|
1835
|
+
task.version = task.version + 1;
|
|
1836
|
+
task.cancelledAt = now;
|
|
1837
|
+
task.cancelledReason = reason;
|
|
1838
|
+
task.updated_at = now;
|
|
1839
|
+
task.archivedAt = now;
|
|
1840
|
+
task.completed_at = void 0;
|
|
1841
|
+
task.originalSprintId = task.sprintId;
|
|
1842
|
+
if (bypass && bypassReason) {
|
|
1843
|
+
task.statusBypassAudit = [
|
|
1844
|
+
...task.statusBypassAudit ?? [],
|
|
1845
|
+
{
|
|
1846
|
+
at: now,
|
|
1847
|
+
fromStatus: previousStatus,
|
|
1848
|
+
toStatus: "cancelled",
|
|
1849
|
+
reason: bypassReason,
|
|
1850
|
+
...bypass.actor ? { actor: bypass.actor } : {}
|
|
1851
|
+
}
|
|
1852
|
+
];
|
|
1853
|
+
}
|
|
1854
|
+
const archivedPath = getCancelledTaskArchivePath(task.id, now, planningRoot);
|
|
1855
|
+
await ensureDirectoryExists(path2.dirname(archivedPath));
|
|
1856
|
+
const archivedBody = updateTaskBodyStatusLine(body, task.status);
|
|
1857
|
+
await writeMarkdownFile(archivedPath, toArchivedTaskFrontMatter(task), archivedBody);
|
|
1858
|
+
try {
|
|
1859
|
+
await detachArchivedTaskFromSprintMembership(task, "cancelling");
|
|
1860
|
+
} catch (error) {
|
|
1861
|
+
await fs.unlink(archivedPath).catch(() => void 0);
|
|
1862
|
+
throw error;
|
|
1863
|
+
}
|
|
1864
|
+
const archiveDir = getBucketArchivePathByKind("task", planningRoot);
|
|
1865
|
+
const archivedIndex = archivedTaskIndexes.get(archiveDir);
|
|
1866
|
+
if (archivedIndex) {
|
|
1867
|
+
archivedIndex.set(task.id, archivedPath);
|
|
1868
|
+
}
|
|
1869
|
+
await fs.unlink(taskFile);
|
|
1870
|
+
return { task, archivedPath };
|
|
1871
|
+
});
|
|
1872
|
+
}
|
|
1873
|
+
async function restoreTask(taskId, options = {}) {
|
|
1874
|
+
const planningRoot = getPlanningRoot();
|
|
1875
|
+
const targetStatus = options.status ?? "in_progress";
|
|
1876
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1877
|
+
const { filePath, isArchived } = await getTask(taskId, { includeArchive: true });
|
|
1878
|
+
const { frontMatter, body } = await readMarkdownFile(filePath);
|
|
1879
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1880
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1881
|
+
let restoreIntoSprint = false;
|
|
1882
|
+
let sprintAlreadyMember = false;
|
|
1883
|
+
if (task.sprintId) {
|
|
1884
|
+
const { assertSprintCanAcceptRestoredTask } = await import("./sprint-manager-MU2ZUWN2.js");
|
|
1885
|
+
const acceptance = await assertSprintCanAcceptRestoredTask(task.sprintId, task.id);
|
|
1886
|
+
if (acceptance.sprintExists) {
|
|
1887
|
+
restoreIntoSprint = true;
|
|
1888
|
+
sprintAlreadyMember = acceptance.alreadyMember;
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
task.status = targetStatus;
|
|
1892
|
+
task.version = task.version + 1;
|
|
1893
|
+
task.updated_at = now;
|
|
1894
|
+
task.completed_at = void 0;
|
|
1895
|
+
delete task.archivedAt;
|
|
1896
|
+
delete task.cancelledAt;
|
|
1897
|
+
delete task.cancelledReason;
|
|
1898
|
+
delete task.originalSprintId;
|
|
1899
|
+
const restoredPath = resolvePlanningItemPath(
|
|
1900
|
+
getBucketPathByKind("task", planningRoot),
|
|
1901
|
+
taskId,
|
|
1902
|
+
{ label: "taskId" }
|
|
1903
|
+
);
|
|
1904
|
+
await ensureDirectoryExists(path2.dirname(restoredPath));
|
|
1905
|
+
await writeMarkdownFile(
|
|
1906
|
+
restoredPath,
|
|
1907
|
+
task,
|
|
1908
|
+
body
|
|
1909
|
+
);
|
|
1910
|
+
try {
|
|
1911
|
+
if (restoreIntoSprint && task.sprintId) {
|
|
1912
|
+
const { addTaskToSprint, refreshSprintMarkdown, removeTaskFromSprint } = await import("./sprint-manager-MU2ZUWN2.js");
|
|
1913
|
+
if (isArchived && !sprintAlreadyMember) {
|
|
1914
|
+
await addTaskToSprint(task.sprintId, task.id, task.estimatedHours);
|
|
1915
|
+
}
|
|
1916
|
+
try {
|
|
1917
|
+
await refreshSprintMarkdown(task.sprintId);
|
|
1918
|
+
} catch (refreshError) {
|
|
1919
|
+
if (isArchived && !sprintAlreadyMember) {
|
|
1920
|
+
await removeTaskFromSprint(task.sprintId, task.id).catch(() => void 0);
|
|
1921
|
+
}
|
|
1922
|
+
throw refreshError;
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
} catch (restoreError) {
|
|
1926
|
+
if (isArchived) {
|
|
1927
|
+
await fs.unlink(restoredPath).catch(() => void 0);
|
|
1928
|
+
}
|
|
1929
|
+
throw restoreError;
|
|
1930
|
+
}
|
|
1931
|
+
if (isArchived) {
|
|
1932
|
+
await fs.unlink(filePath);
|
|
1933
|
+
const archiveDir = getBucketArchivePathByKind("task", planningRoot);
|
|
1934
|
+
const archivedIndex = archivedTaskIndexes.get(archiveDir);
|
|
1935
|
+
archivedIndex?.delete(task.id);
|
|
1936
|
+
}
|
|
1937
|
+
return { task, restoredPath };
|
|
1938
|
+
});
|
|
1939
|
+
}
|
|
1940
|
+
var MAX_AMBIGUOUS_MATCH_PREVIEW = 5;
|
|
1941
|
+
function resolveTaskIdFromPrefix(candidateIds, query) {
|
|
1942
|
+
const uniqueIds = [...new Set(candidateIds)];
|
|
1943
|
+
const matches = uniqueIds.filter((id) => id === query || id.startsWith(query));
|
|
1944
|
+
if (matches.length === 0) {
|
|
1945
|
+
return null;
|
|
1946
|
+
}
|
|
1947
|
+
if (matches.length === 1) {
|
|
1948
|
+
return matches[0] ?? null;
|
|
1949
|
+
}
|
|
1950
|
+
const preview = matches.slice(0, MAX_AMBIGUOUS_MATCH_PREVIEW).join(", ");
|
|
1951
|
+
const suffix = matches.length > MAX_AMBIGUOUS_MATCH_PREVIEW ? ", ..." : "";
|
|
1952
|
+
throw new Error(
|
|
1953
|
+
`Ambiguous task ID prefix "${query}": matches ${matches.length} tasks (${preview}${suffix}). Use a longer prefix or the full ID.`
|
|
1954
|
+
);
|
|
1955
|
+
}
|
|
1956
|
+
async function loadTaskLookupFromFile(filePath, isArchived) {
|
|
1957
|
+
const { frontMatter } = await readMarkdownFile(filePath);
|
|
1958
|
+
return {
|
|
1959
|
+
yaml: coerceTaskYAML(frontMatter),
|
|
1960
|
+
filePath,
|
|
1961
|
+
isArchived
|
|
1962
|
+
};
|
|
1963
|
+
}
|
|
1964
|
+
async function collectKnownTaskIds(planningRoot, tasksDir, includeArchive) {
|
|
1965
|
+
const ids = [];
|
|
1966
|
+
const activeFiles = await listMarkdownFiles(tasksDir);
|
|
1967
|
+
for (const filePath of activeFiles) {
|
|
1968
|
+
const id = path2.basename(filePath, ".md");
|
|
1969
|
+
if (id) {
|
|
1970
|
+
ids.push(id);
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
if (includeArchive) {
|
|
1974
|
+
try {
|
|
1975
|
+
const archiveDir = getBucketArchivePathByKind("task", planningRoot);
|
|
1976
|
+
const index = await getArchivedTaskIndex(archiveDir);
|
|
1977
|
+
ids.push(...index.keys());
|
|
1978
|
+
} catch {
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
return ids;
|
|
1982
|
+
}
|
|
1983
|
+
var TaskNotFoundError = class extends Error {
|
|
1984
|
+
constructor(taskId) {
|
|
1985
|
+
super(`Task not found: ${taskId}`);
|
|
1986
|
+
this.taskId = taskId;
|
|
1987
|
+
this.name = "TaskNotFoundError";
|
|
1988
|
+
}
|
|
1989
|
+
taskId;
|
|
1990
|
+
};
|
|
1991
|
+
async function getTask(taskId, options = {}) {
|
|
1992
|
+
const { filePath, isArchived } = await locateTaskFile(taskId, options);
|
|
1993
|
+
return loadTaskLookupFromFile(filePath, isArchived);
|
|
1994
|
+
}
|
|
1995
|
+
async function locateTaskFile(taskId, options = {}) {
|
|
1996
|
+
const { includeArchive = false } = options;
|
|
1997
|
+
const planningRoot = getPlanningRoot();
|
|
1998
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1999
|
+
const activeTaskFile = resolvePlanningItemPath(tasksDir, taskId, { label: "taskId" });
|
|
2000
|
+
try {
|
|
2001
|
+
await fs.access(activeTaskFile);
|
|
2002
|
+
return { filePath: activeTaskFile, isArchived: false };
|
|
2003
|
+
} catch (error) {
|
|
2004
|
+
if (error.code !== "ENOENT") {
|
|
2005
|
+
throw error;
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
if (includeArchive) {
|
|
2009
|
+
try {
|
|
2010
|
+
const archiveDir = getBucketArchivePathByKind("task", planningRoot);
|
|
2011
|
+
const archivedTaskFile = await findArchivedTaskFile(archiveDir, taskId);
|
|
2012
|
+
if (archivedTaskFile) {
|
|
2013
|
+
return { filePath: archivedTaskFile, isArchived: true };
|
|
2014
|
+
}
|
|
2015
|
+
} catch (error) {
|
|
2016
|
+
if (getErrorCode(error) !== "ENOENT") {
|
|
2017
|
+
throw error;
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
const resolvedId = resolveTaskIdFromPrefix(
|
|
2022
|
+
await collectKnownTaskIds(planningRoot, tasksDir, includeArchive),
|
|
2023
|
+
taskId
|
|
2024
|
+
);
|
|
2025
|
+
if (resolvedId && resolvedId !== taskId) {
|
|
2026
|
+
return locateTaskFile(resolvedId, options);
|
|
2027
|
+
}
|
|
2028
|
+
throw new TaskNotFoundError(taskId);
|
|
2029
|
+
}
|
|
2030
|
+
var archivedTaskIndexes = /* @__PURE__ */ new Map();
|
|
2031
|
+
function clearArchivedTaskIndex() {
|
|
2032
|
+
archivedTaskIndexes.clear();
|
|
2033
|
+
}
|
|
2034
|
+
async function buildArchivedTaskIndex(archiveDir) {
|
|
2035
|
+
const files = await listMarkdownFilesRecursiveStrict(archiveDir);
|
|
2036
|
+
const index = /* @__PURE__ */ new Map();
|
|
2037
|
+
for (const filePath of files) {
|
|
2038
|
+
const base = path2.basename(filePath);
|
|
2039
|
+
if (!base.endsWith(".md")) continue;
|
|
2040
|
+
const id = base.slice(0, -3);
|
|
2041
|
+
if (!id) continue;
|
|
2042
|
+
index.set(id, filePath);
|
|
2043
|
+
}
|
|
2044
|
+
return index;
|
|
2045
|
+
}
|
|
2046
|
+
async function getArchivedTaskIndex(archiveDir) {
|
|
2047
|
+
let index = archivedTaskIndexes.get(archiveDir);
|
|
2048
|
+
if (!index) {
|
|
2049
|
+
index = await buildArchivedTaskIndex(archiveDir);
|
|
2050
|
+
archivedTaskIndexes.set(archiveDir, index);
|
|
2051
|
+
}
|
|
2052
|
+
return index;
|
|
2053
|
+
}
|
|
2054
|
+
async function findArchivedTaskFile(archiveDir, taskId) {
|
|
2055
|
+
if (isValidId(taskId)) {
|
|
2056
|
+
const index = await getArchivedTaskIndex(archiveDir);
|
|
2057
|
+
const directMatch = index.get(taskId);
|
|
2058
|
+
if (directMatch && await fileExists(directMatch)) {
|
|
2059
|
+
return directMatch;
|
|
2060
|
+
}
|
|
2061
|
+
const rebuiltIndex = await buildArchivedTaskIndex(archiveDir);
|
|
2062
|
+
archivedTaskIndexes.set(archiveDir, rebuiltIndex);
|
|
2063
|
+
return rebuiltIndex.get(taskId) ?? null;
|
|
2064
|
+
}
|
|
2065
|
+
const files = await listMarkdownFilesRecursiveStrict(archiveDir);
|
|
2066
|
+
return files.find((f) => path2.basename(f) === `${taskId}.md`) ?? null;
|
|
2067
|
+
}
|
|
2068
|
+
async function getTaskDependency(depId, options = {}) {
|
|
2069
|
+
try {
|
|
2070
|
+
const result = await getTask(depId, { includeArchive: true });
|
|
2071
|
+
const classification = classifyTaskDependency(depId, {
|
|
2072
|
+
task: { status: result.yaml.status, isArchived: result.isArchived }
|
|
2073
|
+
});
|
|
2074
|
+
return {
|
|
2075
|
+
missing: classification.state === "missing",
|
|
2076
|
+
satisfied: classification.satisfied,
|
|
2077
|
+
isArchived: classification.isArchived,
|
|
2078
|
+
task: result.yaml
|
|
2079
|
+
};
|
|
2080
|
+
} catch {
|
|
2081
|
+
let recordedComplete = false;
|
|
2082
|
+
if (options.sprintId) {
|
|
2083
|
+
try {
|
|
2084
|
+
const { isTaskRecordedCompletedInSprint } = await import("./sprint-manager-MU2ZUWN2.js");
|
|
2085
|
+
recordedComplete = await isTaskRecordedCompletedInSprint(options.sprintId, depId);
|
|
2086
|
+
} catch {
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
const classification = classifyTaskDependency(depId, {
|
|
2090
|
+
task: null,
|
|
2091
|
+
recordedComplete
|
|
2092
|
+
});
|
|
2093
|
+
return {
|
|
2094
|
+
missing: classification.state === "missing",
|
|
2095
|
+
satisfied: classification.satisfied,
|
|
2096
|
+
isArchived: classification.isArchived
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
async function getAllTasks(options = {}) {
|
|
2101
|
+
const { includeArchive = false } = options;
|
|
2102
|
+
const planningRoot = getPlanningRoot();
|
|
2103
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
2104
|
+
const results = [];
|
|
2105
|
+
const activeFiles = await listMarkdownFiles(tasksDir);
|
|
2106
|
+
for (const filePath of activeFiles) {
|
|
2107
|
+
try {
|
|
2108
|
+
const { frontMatter } = await readMarkdownFile(filePath);
|
|
2109
|
+
results.push({
|
|
2110
|
+
yaml: coerceTaskYAML(frontMatter),
|
|
2111
|
+
filePath,
|
|
2112
|
+
isArchived: false
|
|
2113
|
+
});
|
|
2114
|
+
} catch {
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
if (includeArchive) {
|
|
2118
|
+
try {
|
|
2119
|
+
const archiveDir = getBucketArchivePathByKind("task", planningRoot);
|
|
2120
|
+
const archiveFiles = await listMarkdownFilesRecursive(archiveDir);
|
|
2121
|
+
for (const filePath of archiveFiles) {
|
|
2122
|
+
try {
|
|
2123
|
+
const { frontMatter } = await readMarkdownFile(filePath);
|
|
2124
|
+
results.push({
|
|
2125
|
+
yaml: coerceTaskYAML(frontMatter),
|
|
2126
|
+
filePath,
|
|
2127
|
+
isArchived: true
|
|
2128
|
+
});
|
|
2129
|
+
} catch {
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
} catch {
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
return results;
|
|
2136
|
+
}
|
|
2137
|
+
async function listTasksLinkedToBacklogItem(backlogItemId, options = {}) {
|
|
2138
|
+
const { includeArchive = false } = options;
|
|
2139
|
+
const allTasks = await getAllTasks({ includeArchive });
|
|
2140
|
+
return allTasks.filter((result) => result.yaml.backlogItemId === backlogItemId).map((result) => ({
|
|
2141
|
+
id: result.yaml.id,
|
|
2142
|
+
title: result.yaml.title,
|
|
2143
|
+
status: result.yaml.status,
|
|
2144
|
+
sprintId: result.yaml.sprintId
|
|
2145
|
+
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
2146
|
+
}
|
|
2147
|
+
async function listTasksInSprint(sprintId, statusFilter) {
|
|
2148
|
+
try {
|
|
2149
|
+
const { listTasksInSprint: listSprintTaskRefs } = await import("./sprint-manager-MU2ZUWN2.js");
|
|
2150
|
+
const sprintTasks = await listSprintTaskRefs(sprintId);
|
|
2151
|
+
const tasks2 = [];
|
|
2152
|
+
for (const sprintTask of sprintTasks) {
|
|
2153
|
+
if (sprintTask.missing === true) continue;
|
|
2154
|
+
try {
|
|
2155
|
+
const { yaml: task, isArchived } = await getTask(sprintTask.id, { includeArchive: true });
|
|
2156
|
+
if (isArchived) continue;
|
|
2157
|
+
if (!statusFilter || task.status === statusFilter) {
|
|
2158
|
+
tasks2.push(task);
|
|
2159
|
+
}
|
|
2160
|
+
} catch {
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
return tasks2;
|
|
2164
|
+
} catch (error) {
|
|
2165
|
+
const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
|
|
2166
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2167
|
+
if (code !== "ENOENT" && !message.includes(`Sprint not found: ${sprintId}`)) {
|
|
2168
|
+
throw error;
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
const planningRoot = getPlanningRoot();
|
|
2172
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
2173
|
+
const files = await listMarkdownFiles(tasksDir);
|
|
2174
|
+
const tasks = [];
|
|
2175
|
+
for (const file of files) {
|
|
2176
|
+
let task;
|
|
2177
|
+
try {
|
|
2178
|
+
const { frontMatter } = await readMarkdownFile(file);
|
|
2179
|
+
task = coerceTaskYAML(frontMatter);
|
|
2180
|
+
} catch {
|
|
2181
|
+
continue;
|
|
2182
|
+
}
|
|
2183
|
+
if (task.sprintId === sprintId) {
|
|
2184
|
+
if (!statusFilter || task.status === statusFilter) {
|
|
2185
|
+
tasks.push(task);
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
return tasks;
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
export {
|
|
2193
|
+
validateStateTransition,
|
|
2194
|
+
generateTaskId,
|
|
2195
|
+
createTask,
|
|
2196
|
+
createTaskWithGuidance,
|
|
2197
|
+
updateTaskFields,
|
|
2198
|
+
applyTaskOwnershipLifecycle,
|
|
2199
|
+
updateTaskStatus,
|
|
2200
|
+
updateTaskStatusWithTransitionValidation,
|
|
2201
|
+
addTaskDependency,
|
|
2202
|
+
removeTaskDependency,
|
|
2203
|
+
autoUnblockDependentTasks,
|
|
2204
|
+
validateTaskExecution,
|
|
2205
|
+
logTaskTime,
|
|
2206
|
+
deriveTransitionIdentity,
|
|
2207
|
+
applyTaskTransitionOutcome,
|
|
2208
|
+
findArchivedTaskPath,
|
|
2209
|
+
completeTask,
|
|
2210
|
+
cancelTask,
|
|
2211
|
+
restoreTask,
|
|
2212
|
+
resolveTaskIdFromPrefix,
|
|
2213
|
+
TaskNotFoundError,
|
|
2214
|
+
getTask,
|
|
2215
|
+
locateTaskFile,
|
|
2216
|
+
clearArchivedTaskIndex,
|
|
2217
|
+
getTaskDependency,
|
|
2218
|
+
getAllTasks,
|
|
2219
|
+
listTasksLinkedToBacklogItem,
|
|
2220
|
+
listTasksInSprint
|
|
2221
|
+
};
|
|
2222
|
+
//# sourceMappingURL=chunk-7LHJDJB3.js.map
|