@poetic-ai/poetic 1.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/SECURITY.md +47 -0
- package/.nvmrc +1 -0
- package/.poetic/README.md +37 -0
- package/.poetic/providers/catalog.json +12051 -0
- package/.poetic/providers/pricing.json +1272 -0
- package/.poetic/providers/registry.json +3369 -0
- package/CHANGELOG.md +552 -0
- package/CODE_OF_CONDUCT.md +40 -0
- package/CONTRIBUTING.md +23 -0
- package/INSTALL.md +454 -0
- package/LICENSE +21 -0
- package/README.md +474 -0
- package/dist/BasicOptimizationCompetitionRunner-5H5TBYO4.js +153 -0
- package/dist/ExecutionTracker-UVONC4C6.js +16 -0
- package/dist/OptimizationConfig-7DFY2TST.js +17 -0
- package/dist/OptimizationEngine-JIMGP3LY.js +1597 -0
- package/dist/PromptStore-U6ZD3ZMQ.js +18 -0
- package/dist/actions-LUJPINLJ.js +322 -0
- package/dist/agent-ingest-3DJUJ7FU.js +53 -0
- package/dist/aggregator-DNCBINFO.js +12 -0
- package/dist/ai-judge-5QT5QJVU.js +156 -0
- package/dist/allowlist-grounding-RO6HKUFI.js +16 -0
- package/dist/allowlist-utils-23V7TJ3G.js +28 -0
- package/dist/anchored-turn-service-JULUCUIK.js +489 -0
- package/dist/api-transport-4TYTNLTJ.js +1087 -0
- package/dist/apply-completion-mode-AW2MOS3R.js +89 -0
- package/dist/artifact-migrator-23L45ISD.js +267 -0
- package/dist/ask-HWVV6QFR.js +135 -0
- package/dist/auth-5KEDKAPP.js +67 -0
- package/dist/auth-7TT3JINV.js +78 -0
- package/dist/auth-E6XUNZ5M.js +68 -0
- package/dist/auth-H3XDZE22.js +134 -0
- package/dist/auth-OC4E6633.js +71 -0
- package/dist/auth-S4CTX4GQ.js +44 -0
- package/dist/auth-YLH3S7EY.js +69 -0
- package/dist/auth-liveness-TDDEZY3T.js +46 -0
- package/dist/auto-optimizer-VPRWOWGU.js +80 -0
- package/dist/autoloop-cleanup-JOGKTLWA.js +109 -0
- package/dist/autoloop-evidence-gates-PCDALGVJ.js +38 -0
- package/dist/autoloop-gate-policy-Z7FVJVXV.js +175 -0
- package/dist/autoloop-helpers-2KTK43GL.js +22 -0
- package/dist/autoloop-ledger-W7QO62PX.js +96 -0
- package/dist/autoloop-ledger-subscriber-Z5RW5EIE.js +162 -0
- package/dist/autoloop-run-defaults-FERGRZGP.js +19 -0
- package/dist/autoloop-run-lock-CT2NWSV3.js +197 -0
- package/dist/autoloop-success-J2VKKBXQ.js +85 -0
- package/dist/autoloop-termination-summary-RN75F422.js +58 -0
- package/dist/autoloop-trajectory-XFIEXP5Z.js +282 -0
- package/dist/autoloop-wall-clock-T7ZVIQOC.js +12 -0
- package/dist/autonomous-loop-controller-PW4XVFGQ.js +4120 -0
- package/dist/backend-P3DAYRP7.js +29 -0
- package/dist/background-executor-CBN552V4.js +257 -0
- package/dist/backlog-execution-intent-U4XYPTV6.js +15 -0
- package/dist/backup-active-store-5WXG6SXT.js +17 -0
- package/dist/backup-telemetry-db-XGLXAA3N.js +254 -0
- package/dist/basic-competition-master-VCSBJVRN.js +344 -0
- package/dist/branch-archive-manager-RP6FP3ZC.js +254 -0
- package/dist/branch-cleanup-manager-RSHAI7YR.js +20 -0
- package/dist/build-gate-YHGRB4QB.js +71 -0
- package/dist/change-summary-WY7J5TOX.js +33 -0
- package/dist/chunk-23A26CSN.js +123 -0
- package/dist/chunk-27UTJD3M.js +265 -0
- package/dist/chunk-2A5CILN3.js +310 -0
- package/dist/chunk-2AQUWJPW.js +225 -0
- package/dist/chunk-2BZ53J6J.js +2344 -0
- package/dist/chunk-2DY5KNVM.js +276 -0
- package/dist/chunk-2EIA4RBE.js +659 -0
- package/dist/chunk-2IUXIGQD.js +1064 -0
- package/dist/chunk-2N42MS2Z.js +2193 -0
- package/dist/chunk-2QJ3H3L7.js +42 -0
- package/dist/chunk-2QLYTVYX.js +791 -0
- package/dist/chunk-2VSQMRCB.js +18 -0
- package/dist/chunk-2XQXYBM2.js +130 -0
- package/dist/chunk-2YFUIER7.js +426 -0
- package/dist/chunk-34CNP2HB.js +148 -0
- package/dist/chunk-35P3W3JX.js +456 -0
- package/dist/chunk-36PEBZAF.js +18 -0
- package/dist/chunk-3AOKYKA7.js +22 -0
- package/dist/chunk-3BCUNHKF.js +475 -0
- package/dist/chunk-3FLXLLB7.js +26 -0
- package/dist/chunk-3FOZ2VHV.js +100 -0
- package/dist/chunk-3G6FZCRF.js +106 -0
- package/dist/chunk-3M57DADF.js +44 -0
- package/dist/chunk-3S62LLWJ.js +543 -0
- package/dist/chunk-3ZPQLGV7.js +2904 -0
- package/dist/chunk-44N5WZZH.js +45 -0
- package/dist/chunk-45FPSA3B.js +125 -0
- package/dist/chunk-4BJ3O4RQ.js +929 -0
- package/dist/chunk-4BOP7T6L.js +2321 -0
- package/dist/chunk-4BTDUT2S.js +42 -0
- package/dist/chunk-4CSS7WVI.js +143 -0
- package/dist/chunk-4CUY7AFY.js +247 -0
- package/dist/chunk-4GSN5O5J.js +62 -0
- package/dist/chunk-4HN6DF7V.js +1027 -0
- package/dist/chunk-4IAPOG5V.js +415 -0
- package/dist/chunk-4IYIZQWV.js +48 -0
- package/dist/chunk-4NXPXE62.js +84 -0
- package/dist/chunk-4RCCF5BR.js +712 -0
- package/dist/chunk-4V7NAQ4R.js +19527 -0
- package/dist/chunk-4VJITV4P.js +445 -0
- package/dist/chunk-4YX7J6QL.js +1859 -0
- package/dist/chunk-527OBWQB.js +338 -0
- package/dist/chunk-5D4A7E3D.js +448 -0
- package/dist/chunk-5DLKYTQX.js +4003 -0
- package/dist/chunk-5EERLVZB.js +139 -0
- package/dist/chunk-5H72XE4H.js +256 -0
- package/dist/chunk-5HDP7XZG.js +91 -0
- package/dist/chunk-5LAMRH4X.js +969 -0
- package/dist/chunk-5LTN43AS.js +1972 -0
- package/dist/chunk-5RBHQYDB.js +2206 -0
- package/dist/chunk-5WCQRDRB.js +588 -0
- package/dist/chunk-5WRLK5KW.js +700 -0
- package/dist/chunk-5ZCXC23G.js +595 -0
- package/dist/chunk-6BM72ZMG.js +31 -0
- package/dist/chunk-6EDAJH2I.js +68 -0
- package/dist/chunk-6EQKFDBH.js +457 -0
- package/dist/chunk-6MFRHTRI.js +115 -0
- package/dist/chunk-6TZJRKNW.js +321 -0
- package/dist/chunk-6V7HGQFZ.js +20 -0
- package/dist/chunk-6VWVO2TU.js +3746 -0
- package/dist/chunk-6Y5TWI7H.js +146 -0
- package/dist/chunk-6Y5U7UFY.js +91 -0
- package/dist/chunk-6ZLAK3XG.js +14 -0
- package/dist/chunk-72XCRQED.js +34 -0
- package/dist/chunk-72YTZMAM.js +589 -0
- package/dist/chunk-73BBJOKA.js +263 -0
- package/dist/chunk-73NCTWKL.js +188 -0
- package/dist/chunk-77I6G4CO.js +1 -0
- package/dist/chunk-7DHRDWFS.js +3104 -0
- package/dist/chunk-7DNSNKJV.js +78 -0
- package/dist/chunk-7FMJVYBS.js +307 -0
- package/dist/chunk-7GDRQBQC.js +419 -0
- package/dist/chunk-7GPCEFUV.js +270 -0
- package/dist/chunk-7IL4A2PP.js +948 -0
- package/dist/chunk-7MMLMXO6.js +3679 -0
- package/dist/chunk-7QCZSLBH.js +1 -0
- package/dist/chunk-7R2WLDOS.js +62 -0
- package/dist/chunk-7T7RUJI7.js +949 -0
- package/dist/chunk-A2WKSVX7.js +43 -0
- package/dist/chunk-A3YGID55.js +133 -0
- package/dist/chunk-A722DEVA.js +14 -0
- package/dist/chunk-ACDIT7OP.js +1376 -0
- package/dist/chunk-ACKIPAOJ.js +302 -0
- package/dist/chunk-APPNGGN7.js +365 -0
- package/dist/chunk-APV6MK5E.js +137 -0
- package/dist/chunk-ASEP3M2W.js +968 -0
- package/dist/chunk-AT4TNPWW.js +2931 -0
- package/dist/chunk-ATVKCSGT.js +250 -0
- package/dist/chunk-AURFMVCD.js +899 -0
- package/dist/chunk-AX6GWE7V.js +47 -0
- package/dist/chunk-AY5EWJPF.js +385 -0
- package/dist/chunk-BAV2HJXS.js +194 -0
- package/dist/chunk-BBHRN366.js +89 -0
- package/dist/chunk-BBPSTTPA.js +1004 -0
- package/dist/chunk-BDATUDDJ.js +992 -0
- package/dist/chunk-BKE5PG5L.js +20414 -0
- package/dist/chunk-BLPHWMDK.js +797 -0
- package/dist/chunk-BSE4R6XD.js +322 -0
- package/dist/chunk-BXGMAU4A.js +396 -0
- package/dist/chunk-BXI4NXL3.js +507 -0
- package/dist/chunk-BZU2O43F.js +1125 -0
- package/dist/chunk-C3L6YQ7P.js +147 -0
- package/dist/chunk-C57KJOUQ.js +121 -0
- package/dist/chunk-CCV7BPSY.js +118 -0
- package/dist/chunk-CD7ISXA4.js +826 -0
- package/dist/chunk-CE5OZBYY.js +21 -0
- package/dist/chunk-CFBIG37O.js +154 -0
- package/dist/chunk-CJC6GZ46.js +457 -0
- package/dist/chunk-CKCDGXIV.js +408 -0
- package/dist/chunk-CKNX3TTP.js +10338 -0
- package/dist/chunk-CLKSETWE.js +10 -0
- package/dist/chunk-CP7H3HSP.js +1552 -0
- package/dist/chunk-CPLEWXNZ.js +66 -0
- package/dist/chunk-CQM3A35X.js +844 -0
- package/dist/chunk-CS6P76D3.js +103 -0
- package/dist/chunk-CTLUBNCW.js +622 -0
- package/dist/chunk-CUSRN6RJ.js +632 -0
- package/dist/chunk-D5EP5D2W.js +26 -0
- package/dist/chunk-D5RYINO7.js +412 -0
- package/dist/chunk-DBFS4HMH.js +751 -0
- package/dist/chunk-DC4ZYMXJ.js +115 -0
- package/dist/chunk-DCBZP442.js +9243 -0
- package/dist/chunk-DCYF7EKG.js +26 -0
- package/dist/chunk-DDMAFNUK.js +5351 -0
- package/dist/chunk-DF5SLDE4.js +966 -0
- package/dist/chunk-DJFW7SMX.js +348 -0
- package/dist/chunk-DQFLLBJW.js +121 -0
- package/dist/chunk-DSFM56OA.js +1203 -0
- package/dist/chunk-DTY4APYV.js +218 -0
- package/dist/chunk-DXH5JBRS.js +437 -0
- package/dist/chunk-E3NTPHEO.js +194 -0
- package/dist/chunk-E74LUIID.js +302 -0
- package/dist/chunk-EI57M5BI.js +194 -0
- package/dist/chunk-EJ4ZAWLV.js +305 -0
- package/dist/chunk-EJGCZGUF.js +1483 -0
- package/dist/chunk-EK2U3YEG.js +486 -0
- package/dist/chunk-ELMFYNV7.js +109 -0
- package/dist/chunk-ENRGKNR5.js +25 -0
- package/dist/chunk-ETYDXCK7.js +679 -0
- package/dist/chunk-EYRH3W74.js +239 -0
- package/dist/chunk-F23DIWNN.js +1024 -0
- package/dist/chunk-F5JO7HAS.js +94 -0
- package/dist/chunk-F7ER6ANO.js +174 -0
- package/dist/chunk-FATUVIIN.js +374 -0
- package/dist/chunk-FC23CTXV.js +322 -0
- package/dist/chunk-FD4ERYEG.js +22 -0
- package/dist/chunk-FH7WOJAE.js +79 -0
- package/dist/chunk-FHOWVDF5.js +1342 -0
- package/dist/chunk-FKAUPHMR.js +96 -0
- package/dist/chunk-FONNFJXA.js +137 -0
- package/dist/chunk-FQ7FSZRW.js +75 -0
- package/dist/chunk-FRG57FPM.js +240 -0
- package/dist/chunk-FUVP64ER.js +31 -0
- package/dist/chunk-FYOILAN5.js +6818 -0
- package/dist/chunk-G35UYQ6Z.js +69 -0
- package/dist/chunk-G36W2T2S.js +1143 -0
- package/dist/chunk-G3L2L5XZ.js +49 -0
- package/dist/chunk-G4THLFV3.js +148 -0
- package/dist/chunk-GAFJEYLK.js +29 -0
- package/dist/chunk-GFGYB2ZU.js +1689 -0
- package/dist/chunk-GG6KJYW6.js +85 -0
- package/dist/chunk-GHHFDU2U.js +55 -0
- package/dist/chunk-GHTZSQB7.js +57 -0
- package/dist/chunk-GK37ILCX.js +1231 -0
- package/dist/chunk-GKN3HMN4.js +2809 -0
- package/dist/chunk-GNVDBVJP.js +156 -0
- package/dist/chunk-GPEL3FBM.js +924 -0
- package/dist/chunk-GPSNGPZS.js +1604 -0
- package/dist/chunk-GSGD5E4C.js +30 -0
- package/dist/chunk-GSUQJJXQ.js +331 -0
- package/dist/chunk-GSV226X6.js +110 -0
- package/dist/chunk-H2AYQIHW.js +224 -0
- package/dist/chunk-H66DXFS5.js +1374 -0
- package/dist/chunk-H6G7QRMQ.js +35 -0
- package/dist/chunk-H7JAGHZT.js +59 -0
- package/dist/chunk-H7ZEFECA.js +316 -0
- package/dist/chunk-HAC6EHZZ.js +79 -0
- package/dist/chunk-HIO33P3G.js +19 -0
- package/dist/chunk-HMVQIPH3.js +547 -0
- package/dist/chunk-HOYBYAOA.js +257 -0
- package/dist/chunk-HX5P3CSP.js +1784 -0
- package/dist/chunk-I46EG2XQ.js +65 -0
- package/dist/chunk-I4NPDSCB.js +279 -0
- package/dist/chunk-I5WRT7ZR.js +514 -0
- package/dist/chunk-IC7I6YIJ.js +301 -0
- package/dist/chunk-IDCSOZVN.js +78 -0
- package/dist/chunk-IFCBYECK.js +112 -0
- package/dist/chunk-IFZCPEY2.js +66 -0
- package/dist/chunk-IKFP2KUR.js +48 -0
- package/dist/chunk-IRFBN336.js +878 -0
- package/dist/chunk-IUXNGKA6.js +152 -0
- package/dist/chunk-IV2RVAN7.js +1356 -0
- package/dist/chunk-IZYIQQ7X.js +53 -0
- package/dist/chunk-J3UUR7DE.js +210 -0
- package/dist/chunk-J54VUAY2.js +566 -0
- package/dist/chunk-J62KPGII.js +464 -0
- package/dist/chunk-J6P3FWWW.js +130 -0
- package/dist/chunk-JKBHJQMT.js +434 -0
- package/dist/chunk-JLS65NUQ.js +14 -0
- package/dist/chunk-JOSYEJKY.js +141 -0
- package/dist/chunk-JPKSXKNB.js +94 -0
- package/dist/chunk-JQNJB2BB.js +2440 -0
- package/dist/chunk-JRVNSWSQ.js +2626 -0
- package/dist/chunk-JSWMRQYG.js +28 -0
- package/dist/chunk-JZKNBBIB.js +152 -0
- package/dist/chunk-K54Y7MLK.js +160 -0
- package/dist/chunk-K65546RE.js +183 -0
- package/dist/chunk-KM3F7SYE.js +702 -0
- package/dist/chunk-KNDYMVWN.js +102 -0
- package/dist/chunk-KNT72VR6.js +132 -0
- package/dist/chunk-KP6YILMU.js +482 -0
- package/dist/chunk-KQEBSK3T.js +274 -0
- package/dist/chunk-KT6VHSPF.js +84 -0
- package/dist/chunk-KTMW65UX.js +14 -0
- package/dist/chunk-KZ5CJVBP.js +1813 -0
- package/dist/chunk-L4427KOE.js +26 -0
- package/dist/chunk-L6OM4A22.js +189 -0
- package/dist/chunk-L7E6XCRA.js +1042 -0
- package/dist/chunk-L7JZLXQL.js +173 -0
- package/dist/chunk-LAMKBTXX.js +40 -0
- package/dist/chunk-LDCF2MKN.js +132 -0
- package/dist/chunk-LEIIWPWQ.js +78 -0
- package/dist/chunk-LFTQVYBB.js +31 -0
- package/dist/chunk-LG3PDRTR.js +2872 -0
- package/dist/chunk-LGHII5ET.js +23 -0
- package/dist/chunk-LH5QY22X.js +1205 -0
- package/dist/chunk-LIVJ6266.js +438 -0
- package/dist/chunk-LKRAR3IH.js +276 -0
- package/dist/chunk-LO23NABI.js +3063 -0
- package/dist/chunk-LO3X5NLS.js +326 -0
- package/dist/chunk-LPITVM7M.js +339 -0
- package/dist/chunk-LR5IJIGV.js +810 -0
- package/dist/chunk-LRGMHROI.js +79 -0
- package/dist/chunk-LUVKFFWR.js +315 -0
- package/dist/chunk-LWCBNGH6.js +35 -0
- package/dist/chunk-LWTN3WRV.js +260 -0
- package/dist/chunk-M3HQYKQX.js +308 -0
- package/dist/chunk-M6GVSPEH.js +1016 -0
- package/dist/chunk-MF5HP6XV.js +221 -0
- package/dist/chunk-MHLCBZJB.js +328 -0
- package/dist/chunk-MN6PL4AN.js +120 -0
- package/dist/chunk-MOEY65Z6.js +5678 -0
- package/dist/chunk-MQ4WA34C.js +206 -0
- package/dist/chunk-MWHF5V7U.js +223 -0
- package/dist/chunk-MWHLBPNU.js +211 -0
- package/dist/chunk-MWK5UZQ3.js +1068 -0
- package/dist/chunk-MYLH2S4G.js +64 -0
- package/dist/chunk-MZ5WYKNA.js +28 -0
- package/dist/chunk-N4VTRA7K.js +131 -0
- package/dist/chunk-N5DX4JAK.js +12 -0
- package/dist/chunk-N65O4XTH.js +5011 -0
- package/dist/chunk-NEQUQHOX.js +223 -0
- package/dist/chunk-NGK6PEOG.js +25 -0
- package/dist/chunk-NJVD4PWE.js +1033 -0
- package/dist/chunk-NM6PMYY4.js +768 -0
- package/dist/chunk-NN4PJDHP.js +708 -0
- package/dist/chunk-NP2V3L7K.js +226 -0
- package/dist/chunk-NRLY536M.js +260 -0
- package/dist/chunk-NRNE225N.js +1270 -0
- package/dist/chunk-NS2K2GTP.js +605 -0
- package/dist/chunk-NS33V3IM.js +51 -0
- package/dist/chunk-NSHASMZZ.js +71 -0
- package/dist/chunk-NWOYOA6H.js +378 -0
- package/dist/chunk-NWRUSEXG.js +322 -0
- package/dist/chunk-NZGDAWIP.js +1905 -0
- package/dist/chunk-O47UOKU3.js +395 -0
- package/dist/chunk-O4G2W3ST.js +9831 -0
- package/dist/chunk-O6V4PNLO.js +63 -0
- package/dist/chunk-OA4GPILI.js +624 -0
- package/dist/chunk-OGMSYL6J.js +227 -0
- package/dist/chunk-OIS7J26S.js +319 -0
- package/dist/chunk-OMX5VL43.js +79 -0
- package/dist/chunk-ON3G73BU.js +264 -0
- package/dist/chunk-OPYFYTWQ.js +220 -0
- package/dist/chunk-OQ6K46CK.js +1734 -0
- package/dist/chunk-OYZYO7TV.js +47 -0
- package/dist/chunk-OZ4REHIN.js +4386 -0
- package/dist/chunk-P47VN5F4.js +282 -0
- package/dist/chunk-P5I4X7A7.js +353 -0
- package/dist/chunk-P6VQROCO.js +594 -0
- package/dist/chunk-P7CQGPLS.js +30 -0
- package/dist/chunk-PCAGC5MR.js +1763 -0
- package/dist/chunk-PFTQBXS6.js +5181 -0
- package/dist/chunk-PGSPX4SU.js +15 -0
- package/dist/chunk-PIKLF7BM.js +432 -0
- package/dist/chunk-PJWJ3SAV.js +22 -0
- package/dist/chunk-PKIFMV72.js +100 -0
- package/dist/chunk-PL37JDNA.js +189 -0
- package/dist/chunk-PTH5E5XO.js +195 -0
- package/dist/chunk-PW6AXLQC.js +4128 -0
- package/dist/chunk-PYITM4N2.js +79 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-Q3RO7N35.js +45 -0
- package/dist/chunk-Q3WIC6GQ.js +2670 -0
- package/dist/chunk-Q5XIXSHX.js +271 -0
- package/dist/chunk-QGJDMEOV.js +34 -0
- package/dist/chunk-QNOB37UH.js +58 -0
- package/dist/chunk-QOCOVLUH.js +462 -0
- package/dist/chunk-QTCJ5CC5.js +172 -0
- package/dist/chunk-QVFV5IP2.js +232 -0
- package/dist/chunk-QVZMFDYG.js +29 -0
- package/dist/chunk-R35PEUKH.js +511 -0
- package/dist/chunk-R4UWBC35.js +200 -0
- package/dist/chunk-R6MLCREW.js +44 -0
- package/dist/chunk-R6W23LKN.js +254 -0
- package/dist/chunk-R7XDDX2A.js +4007 -0
- package/dist/chunk-RDFRCT64.js +168 -0
- package/dist/chunk-RE5VZDFQ.js +58 -0
- package/dist/chunk-RGROYC2G.js +638 -0
- package/dist/chunk-RGWHUI5E.js +68 -0
- package/dist/chunk-RHVG6UNL.js +205 -0
- package/dist/chunk-RI4EX2QE.js +18 -0
- package/dist/chunk-RJAAKDRX.js +17 -0
- package/dist/chunk-ROMHOSMQ.js +185 -0
- package/dist/chunk-RWREC3KJ.js +517 -0
- package/dist/chunk-RYNETRDJ.js +118 -0
- package/dist/chunk-RZY7RKM5.js +500 -0
- package/dist/chunk-S2MNWFAG.js +52 -0
- package/dist/chunk-S2VQCZO4.js +22 -0
- package/dist/chunk-S54MKU6V.js +117 -0
- package/dist/chunk-S5OIDFRM.js +302 -0
- package/dist/chunk-SCW4ZF6R.js +150 -0
- package/dist/chunk-SLS2N4PH.js +2213 -0
- package/dist/chunk-SNLBO4BF.js +247 -0
- package/dist/chunk-SP3LFU6B.js +60 -0
- package/dist/chunk-SQQTDDQA.js +537 -0
- package/dist/chunk-STV6LYYE.js +45 -0
- package/dist/chunk-SURZ2WFE.js +326 -0
- package/dist/chunk-SZ7DL357.js +1047 -0
- package/dist/chunk-T5E4NQCM.js +5742 -0
- package/dist/chunk-TAJPCXSB.js +13 -0
- package/dist/chunk-TAOOYK3P.js +358 -0
- package/dist/chunk-TDSEX5CF.js +24 -0
- package/dist/chunk-TFTGP7Z7.js +174 -0
- package/dist/chunk-TGON4N4O.js +197 -0
- package/dist/chunk-TGQZHDY2.js +2373 -0
- package/dist/chunk-TJJZ2OKV.js +6783 -0
- package/dist/chunk-TRSVUPCX.js +25 -0
- package/dist/chunk-TSXGRLPR.js +107 -0
- package/dist/chunk-U2S3YEX3.js +224 -0
- package/dist/chunk-U45RTRGY.js +818 -0
- package/dist/chunk-U6C3VVWS.js +13 -0
- package/dist/chunk-UDMS5AD3.js +307 -0
- package/dist/chunk-UGX7GI37.js +94 -0
- package/dist/chunk-UH3JJSHK.js +1 -0
- package/dist/chunk-UHRBTZYY.js +208 -0
- package/dist/chunk-UHT2KRG5.js +193 -0
- package/dist/chunk-UI2F6DJ5.js +118 -0
- package/dist/chunk-UMAKSB4Z.js +284 -0
- package/dist/chunk-UR2IBGIM.js +521 -0
- package/dist/chunk-UUH2RVKS.js +585 -0
- package/dist/chunk-UVJ4PJDK.js +4533 -0
- package/dist/chunk-V53UG2OT.js +9924 -0
- package/dist/chunk-V72RMBM4.js +48 -0
- package/dist/chunk-VBNCKCCI.js +16 -0
- package/dist/chunk-VNSYKC25.js +24 -0
- package/dist/chunk-VPHVFK4A.js +1984 -0
- package/dist/chunk-VTLNJQ44.js +133 -0
- package/dist/chunk-VTW7HP3R.js +100 -0
- package/dist/chunk-VVGEPBPS.js +218 -0
- package/dist/chunk-VVLLL7I4.js +166 -0
- package/dist/chunk-VX3UMWB7.js +483 -0
- package/dist/chunk-VXF4Q3FW.js +20 -0
- package/dist/chunk-W3JMT2YY.js +712 -0
- package/dist/chunk-WDUORIHF.js +877 -0
- package/dist/chunk-WDVTY4U6.js +148 -0
- package/dist/chunk-WIFZCHEG.js +12566 -0
- package/dist/chunk-WIRN3F75.js +736 -0
- package/dist/chunk-WMPU2UOV.js +82 -0
- package/dist/chunk-WTOKKE2V.js +784 -0
- package/dist/chunk-WX5IRLF6.js +740 -0
- package/dist/chunk-WZ6U3O7I.js +1581 -0
- package/dist/chunk-XAONGNST.js +57 -0
- package/dist/chunk-XB5YLCLB.js +13 -0
- package/dist/chunk-XEP5NQ5Y.js +688 -0
- package/dist/chunk-XGYF2QMZ.js +351 -0
- package/dist/chunk-XHEKQENB.js +255 -0
- package/dist/chunk-XNO4FM6X.js +1124 -0
- package/dist/chunk-XPHKYHO4.js +878 -0
- package/dist/chunk-XPK2I4NC.js +405 -0
- package/dist/chunk-XPU2XADL.js +2175 -0
- package/dist/chunk-XQD2B6BB.js +507 -0
- package/dist/chunk-XT2ZQVTC.js +558 -0
- package/dist/chunk-XTXJGGUV.js +351 -0
- package/dist/chunk-XUXVDPSZ.js +50 -0
- package/dist/chunk-XV7NZL4B.js +57 -0
- package/dist/chunk-XZE4XARH.js +563 -0
- package/dist/chunk-XZYR5EDO.js +152 -0
- package/dist/chunk-Y3J4JMTU.js +61 -0
- package/dist/chunk-Y55LZN5U.js +52 -0
- package/dist/chunk-Y5VN7DMP.js +112 -0
- package/dist/chunk-Y67VAHN4.js +459 -0
- package/dist/chunk-YAXSKEUH.js +3544 -0
- package/dist/chunk-YB3JD4E6.js +975 -0
- package/dist/chunk-YESZJFK6.js +220 -0
- package/dist/chunk-YGXKOBQQ.js +292 -0
- package/dist/chunk-YMX76IOS.js +31 -0
- package/dist/chunk-YOTXESEH.js +257 -0
- package/dist/chunk-YTYIEZQY.js +119 -0
- package/dist/chunk-YVORHQ2S.js +579 -0
- package/dist/chunk-Z2CUQDAR.js +3429 -0
- package/dist/chunk-Z2KYOFHS.js +7000 -0
- package/dist/chunk-Z6PC7QX6.js +161 -0
- package/dist/chunk-ZDTGECTN.js +235 -0
- package/dist/chunk-ZIPWI2LY.js +151 -0
- package/dist/chunk-ZSKKMTQJ.js +554 -0
- package/dist/chunk-ZTT5IVPY.js +1160 -0
- package/dist/chunk-ZX65UI5W.js +78 -0
- package/dist/chunk-ZYG7GGKO.js +218 -0
- package/dist/chunk-ZZZUL4OF.js +38 -0
- package/dist/cli-utils-IXL26KJT.js +40 -0
- package/dist/cli-validation-WLXWLUJL.js +111 -0
- package/dist/commit-utils-P7CRJF5N.js +202 -0
- package/dist/compete-config-resolver-R5ULXMYH.js +76 -0
- package/dist/compete-request-62JESVET.js +364 -0
- package/dist/compete-results-QEPG6FZX.js +208 -0
- package/dist/competition-outcome-tracker-R32OOZ43.js +38 -0
- package/dist/config-JCOKXOQT.js +166 -0
- package/dist/config-audit-EL3GHXS7.js +360 -0
- package/dist/config-explain-TNILDEVJ.js +12 -0
- package/dist/config-loader-VPFPFO4B.js +38 -0
- package/dist/config-manager-7T4E2BQO.js +67 -0
- package/dist/config-validator-KKOHOW7O.js +72 -0
- package/dist/cost-YC42XUF3.js +53 -0
- package/dist/coverage-orchestrator-CISNKJC2.js +772 -0
- package/dist/coverage-scanner-YVD62MLH.js +12 -0
- package/dist/createCompetitionRunner-LJG6ZQSO.js +46 -0
- package/dist/data-migration-state-VJK64DLT.js +31 -0
- package/dist/db-migrator-XSEIOGWY.js +34 -0
- package/dist/discovery-JGYGDD25.js +25 -0
- package/dist/doctor-GJOYE7AE.js +186 -0
- package/dist/domain-analyzer-AWF3RP6E.js +29 -0
- package/dist/ensure-initialized-744DIZEZ.js +52 -0
- package/dist/entry.js +940 -0
- package/dist/environment-YS45U5ZI.js +81 -0
- package/dist/error-parser-core-PPZ36A4S.js +50 -0
- package/dist/escalation-ladder-MKTCEGSA.js +130 -0
- package/dist/evaluation-context-KV4GZNN7.js +35 -0
- package/dist/evidence-plan-resolver-GBSYSAPX.js +85 -0
- package/dist/execution-data-writer-3ODTBDLH.js +53 -0
- package/dist/execution-policy-applier-ZHD3DCF3.js +31 -0
- package/dist/execution-preflight-Z4Y64V3I.js +209 -0
- package/dist/execution-roles-R3DPPMD3.js +66 -0
- package/dist/exit-code-error-Z4SW2DVK.js +14 -0
- package/dist/external-temp-cleanup-N2RZH4QP.js +311 -0
- package/dist/factory-XBN7DFIM.js +149 -0
- package/dist/file-utils-XIVR2ZMA.js +47 -0
- package/dist/flywheel-autoloop-executor-UILGOFFK.js +249 -0
- package/dist/flywheel-competition-executor-JOBEXTRB.js +259 -0
- package/dist/flywheel-executor-6JFLA6J5.js +369 -0
- package/dist/flywheel-git-isolation-UC5NIEVU.js +48 -0
- package/dist/flywheel-manifest-5UC4VBMA.js +108 -0
- package/dist/flywheel-model-defaults-7CVKP53V.js +27 -0
- package/dist/flywheel-preflight-XEY5SHM6.js +104 -0
- package/dist/flywheel-resume-7HELH7QS.js +23 -0
- package/dist/flywheel-safety-7U7DPOAP.js +28 -0
- package/dist/flywheel-scope-decision-ZHKF6ZIN.js +11 -0
- package/dist/get-telemetry-logger-DPVWWIYY.js +73 -0
- package/dist/git-worktree-IY6V6DUO.js +18 -0
- package/dist/github-pr-manager-4LXEKJTA.js +211 -0
- package/dist/guidance-profile-config-E7XJL2VP.js +117 -0
- package/dist/guidance-profile-renderer-QK2YMAAP.js +21 -0
- package/dist/index-query-4JEUKA44.js +31 -0
- package/dist/index.js +108661 -0
- package/dist/instructions-6BURLQJC.js +64 -0
- package/dist/invoke-provider-auth-GRUYP44M.js +223 -0
- package/dist/judge-scoring.json +80 -0
- package/dist/judge-test.js +555 -0
- package/dist/lab-mode-OTWVHN63.js +39 -0
- package/dist/lab-utils-BJRFLGK4.js +23 -0
- package/dist/linux-host-class-UY4KVLFD.js +29 -0
- package/dist/llm-judge-executor-F7Z3HO77.js +133 -0
- package/dist/local-executor-CEHWE2PL.js +223 -0
- package/dist/logger-33TR6EE5.js +72 -0
- package/dist/loop-spec-XTLQAVZ7.js +191 -0
- package/dist/manager-2HJG5CLT.js +25 -0
- package/dist/matrix-prompt-builder-6UDN5X3F.js +497 -0
- package/dist/matrix-result-parser-7W35EUOV.js +15 -0
- package/dist/metadata-HQ43NDEK.js +22 -0
- package/dist/model-invocations-db-QBO4Y7WZ.js +38 -0
- package/dist/monitor-XGYBG2DW.js +72 -0
- package/dist/next-PB5ZXZKB.js +90 -0
- package/dist/next-ZBDK725T.js +69 -0
- package/dist/optimization-config-resolver-O6WKR47U.js +75 -0
- package/dist/package-3YCWIQQ5.js +10 -0
- package/dist/parallel-orchestrator-NL7YJJU2.js +297 -0
- package/dist/parallel-worker.js +279 -0
- package/dist/parse-git-status-PIAF3OTP.js +10 -0
- package/dist/path-security-ETTH6TZL.js +39 -0
- package/dist/pattern-bank-UNJR5ADV.js +15 -0
- package/dist/plan-backlog-list-fast-VAGYBV3J.js +270 -0
- package/dist/plan-backlog-show-fast-SG2CZPW3.js +406 -0
- package/dist/plan-sprint-list-fast-LURAX47V.js +162 -0
- package/dist/plan-sprint-status-fast-FJAODCHD.js +208 -0
- package/dist/plan-task-status-fast-HNYBMQI4.js +349 -0
- package/dist/plan-to-flywheel-Z4U3GWPN.js +456 -0
- package/dist/planning-backlog-3CQ5QQBQ.js +319 -0
- package/dist/poetic-root-V5DNXEAE.js +17 -0
- package/dist/preflight-OPANWMME.js +12 -0
- package/dist/process-registry-PDZJPTAS.js +27 -0
- package/dist/process-scanner-C22SYXYD.js +22 -0
- package/dist/processes-KMQUD7HY.js +29 -0
- package/dist/processes-json-fast-IBDXZ6WW.js +135 -0
- package/dist/profile-SE5EVXAP.js +149 -0
- package/dist/prompts-WZZPGWBX.js +168 -0
- package/dist/protected-branches-RNTEX7ET.js +57 -0
- package/dist/provider-aware-resource-manager-QBTZJMNP.js +18 -0
- package/dist/provider-matrix-N5X57V3Y.js +154 -0
- package/dist/provider-matrix-renderer-MZDWKKID.js +139 -0
- package/dist/provider-output-forwarding-DERID3TP.js +30 -0
- package/dist/provider-registry-J5NRBJKI.js +128 -0
- package/dist/provider-temp-cleanup-KYGLF6YU.js +14 -0
- package/dist/prune-engine-Q6E2DXBN.js +451 -0
- package/dist/quality-gate-YRHMQAEI.js +70 -0
- package/dist/quickstart-FIRLKGJI.js +62 -0
- package/dist/readiness-VZTMSG6J.js +96 -0
- package/dist/registry-YODFY77A.js +153 -0
- package/dist/repair-helpers-TTV5FEF4.js +117 -0
- package/dist/repo-root-2IGD4H7X.js +22 -0
- package/dist/resolution-engine-D6TX6FRG.js +127 -0
- package/dist/resolve-provider-cli-O2P6XZBZ.js +35 -0
- package/dist/restore-telemetry-db-BQL6DTQF.js +360 -0
- package/dist/result-streamer-WEHW476R.js +19 -0
- package/dist/routing-events-DHPUZDDF.js +27 -0
- package/dist/routing-history-store-UWCEXAP3.js +46 -0
- package/dist/routing-planner-F5WQEUOM.js +160 -0
- package/dist/run-poetic-tui-J6LWRJUP.js +13517 -0
- package/dist/run-simulation.js +376 -0
- package/dist/runner-CS2TNGHA.js +1092 -0
- package/dist/runner-HHH7ZN2Z.js +1571 -0
- package/dist/safety-OCC4KJJR.js +64 -0
- package/dist/safety-stanza-7SV3HGG3.js +60 -0
- package/dist/sandbox-32QXJEMV.js +81 -0
- package/dist/sandbox-RSO7VP6V.js +94 -0
- package/dist/schema-extensions.sql +234 -0
- package/dist/security-2KI5XNDG.js +17 -0
- package/dist/setup-bb-plugin-QAQWZCV5.js +738 -0
- package/dist/setup-claude-code-P7BTTSPO.js +317 -0
- package/dist/setup-temp-cleanup-GASCWZ2I.js +20 -0
- package/dist/shared-utils-D6U6UREP.js +37 -0
- package/dist/simple-artifact-goal-OTXNGZY6.js +25 -0
- package/dist/sprint-UIXPYOXQ.js +338 -0
- package/dist/sprint-bridge-4BHMSC3M.js +68 -0
- package/dist/sprint-execution-service-2B7WHL5L.js +311 -0
- package/dist/sprint-manager-IDQUDNQI.js +91 -0
- package/dist/sqlite-wrapper-UDWCTNLJ.js +17 -0
- package/dist/stale-cleanup-orchestrator-XWXV7KCZ.js +62 -0
- package/dist/storage-access-F6ALDN4S.js +22 -0
- package/dist/synthesis-XD6EDVHF.js +185 -0
- package/dist/task-classifier-LNLXSHOM.js +494 -0
- package/dist/task-list-fast-PTMA4LUC.js +147 -0
- package/dist/task-manager-XAT7GOWB.js +93 -0
- package/dist/task-splitter-U7DJ7W6A.js +79 -0
- package/dist/task-type-detector-OLVOMXZO.js +21 -0
- package/dist/task-type-resolver-KKNQYSB4.js +42 -0
- package/dist/telemetry-5HWBBXLX.js +131 -0
- package/dist/telemetry-health-tracker-DMSSGBZ2.js +11 -0
- package/dist/telemetry-path-resolver-7ICSG276.js +28 -0
- package/dist/telemetry-reliability-XUOZNZZ6.js +125 -0
- package/dist/token-estimator-MEQUL3EJ.js +37 -0
- package/dist/transports-KNSSV2V4.js +255 -0
- package/dist/unified-cost-tracker-4TFRBVPR.js +35 -0
- package/dist/unified-state-cleanup-LJPF2BOW.js +276 -0
- package/dist/universal-cost-calculator-BAJV35GA.js +42 -0
- package/dist/user-agents-GHUGCSKN.js +22 -0
- package/dist/variant-delivery-state-KLRNG6XA.js +33 -0
- package/dist/variant-state-cleanup-MZGGLQAJ.js +280 -0
- package/dist/variant-success-PJXWE3ZV.js +12 -0
- package/dist/variant-worker-KUWKBLAH.js +4196 -0
- package/dist/variant-worker.js +24 -0
- package/dist/variants-JE2FSAQS.js +233 -0
- package/dist/verification-toolchains-V24UHW6Q.js +28 -0
- package/dist/verify-commands-H3DTCSGI.js +37 -0
- package/dist/warning-EGQGUUIO.js +12 -0
- package/dist/work-edge-RWEDWJZF.js +49 -0
- package/dist/work-item-writer-WHAVZXAY.js +19 -0
- package/dist/worker-7SA2VS2Y.js +1435 -0
- package/dist/worker.js +19 -0
- package/dist/worktree-metrics-3DFUYVYE.js +26 -0
- package/dist/writeback-VZKHYHSN.js +44 -0
- package/docs/CLI_REFERENCE.md +7042 -0
- package/docs/PROVIDER_SETUP.md +1570 -0
- package/docs/README.md +96 -0
- package/docs/TROUBLESHOOTING.md +2232 -0
- package/docs/getting-started/QUICK_START.md +294 -0
- package/docs/getting-started/README.md +188 -0
- package/docs/getting-started/SETUP.md +52 -0
- package/docs/reference/AGENT_CONTEXT.md +38 -0
- package/docs/reference/PROVIDER_RELEASE_TIERS.md +34 -0
- package/docs/reference/README.md +381 -0
- package/docs/reference/SECURITY.md +262 -0
- package/integrations/bb-plugin-poetic/README.md +362 -0
- package/integrations/bb-plugin-poetic/app.css +341 -0
- package/integrations/bb-plugin-poetic/app.tsx +5059 -0
- package/integrations/bb-plugin-poetic/package.json +45 -0
- package/integrations/bb-plugin-poetic/server.ts +444 -0
- package/integrations/bb-plugin-poetic/src/adapter.ts +3312 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-model.ts +150 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-schema.ts +355 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-service.ts +419 -0
- package/integrations/bb-plugin-poetic/src/backlog-authoring-view.ts +1026 -0
- package/integrations/bb-plugin-poetic/src/competition-defaults-schema.ts +122 -0
- package/integrations/bb-plugin-poetic/src/competition-defaults-service.ts +105 -0
- package/integrations/bb-plugin-poetic/src/competition-defaults-view.ts +138 -0
- package/integrations/bb-plugin-poetic/src/contract.ts +615 -0
- package/integrations/bb-plugin-poetic/src/finalize-model.ts +205 -0
- package/integrations/bb-plugin-poetic/src/finalize-schema.ts +158 -0
- package/integrations/bb-plugin-poetic/src/finalize-service.ts +382 -0
- package/integrations/bb-plugin-poetic/src/finalize-view.ts +159 -0
- package/integrations/bb-plugin-poetic/src/judge-operations-readback.ts +303 -0
- package/integrations/bb-plugin-poetic/src/judge-operations-schema.ts +33 -0
- package/integrations/bb-plugin-poetic/src/judge-operations-view.ts +459 -0
- package/integrations/bb-plugin-poetic/src/model.ts +1302 -0
- package/integrations/bb-plugin-poetic/src/monitor-service.ts +233 -0
- package/integrations/bb-plugin-poetic/src/panel-read-ux.ts +97 -0
- package/integrations/bb-plugin-poetic/src/patch-preview-schema.ts +166 -0
- package/integrations/bb-plugin-poetic/src/patch-preview-service.ts +480 -0
- package/integrations/bb-plugin-poetic/src/patch-preview-view.ts +109 -0
- package/integrations/bb-plugin-poetic/src/planning-readback.ts +204 -0
- package/integrations/bb-plugin-poetic/src/planning-service.ts +594 -0
- package/integrations/bb-plugin-poetic/src/planning-workspace-schema.ts +95 -0
- package/integrations/bb-plugin-poetic/src/planning-workspace.ts +323 -0
- package/integrations/bb-plugin-poetic/src/poll-handoff.ts +136 -0
- package/integrations/bb-plugin-poetic/src/project-target-server.ts +21 -0
- package/integrations/bb-plugin-poetic/src/project-target.ts +45 -0
- package/integrations/bb-plugin-poetic/src/reference-index.ts +192 -0
- package/integrations/bb-plugin-poetic/src/repository-schema.ts +30 -0
- package/integrations/bb-plugin-poetic/src/result-explorer-view.ts +597 -0
- package/integrations/bb-plugin-poetic/src/result-readback-model.ts +163 -0
- package/integrations/bb-plugin-poetic/src/result-readback-schema.ts +319 -0
- package/integrations/bb-plugin-poetic/src/result-readback-service.ts +333 -0
- package/integrations/bb-plugin-poetic/src/run-page-view.ts +177 -0
- package/integrations/bb-plugin-poetic/src/setup-config-schema.ts +291 -0
- package/integrations/bb-plugin-poetic/src/setup-config-service.ts +590 -0
- package/integrations/bb-plugin-poetic/src/setup-config-view.ts +413 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-model.ts +150 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-schema.ts +136 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-service.ts +341 -0
- package/integrations/bb-plugin-poetic/src/sprint-close-view.ts +116 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-model.ts +714 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-readback.ts +231 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-schema.ts +601 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-service.ts +775 -0
- package/integrations/bb-plugin-poetic/src/sprint-composition-view.ts +1221 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-model.ts +567 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-schema.ts +635 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-service.ts +842 -0
- package/integrations/bb-plugin-poetic/src/task-authoring-view.ts +1227 -0
- package/integrations/bb-plugin-poetic/src/task-detail-readback.ts +56 -0
- package/integrations/bb-plugin-poetic/src/task-detail-schema.ts +144 -0
- package/integrations/bb-plugin-poetic/src/task-navigation.ts +446 -0
- package/integrations/bb-plugin-poetic/src/workbench-route.ts +74 -0
- package/integrations/bb-plugin-poetic/tests/host-contract.test.ts +773 -0
- package/integrations/bb-plugin-poetic/tsconfig.json +18 -0
- package/integrations/bb-plugin-poetic/types/PROVENANCE.json +52 -0
- package/integrations/bb-plugin-poetic/types/bb-plugin-sdk-app.d.ts +1444 -0
- package/integrations/bb-plugin-poetic/types/bb-plugin-sdk.d.ts +13030 -0
- package/integrations/bb-plugin-poetic/vitest.host.config.ts +71 -0
- package/npm-shrinkwrap.json +4950 -0
- package/package.json +331 -0
- package/schemas/README.md +80 -0
- package/schemas/config-v1.schema.json +136 -0
- package/schemas/execution-config.schema.json +47 -0
- package/schemas/judge-scoring.schema.json +370 -0
- package/schemas/poetic.config.schema.json +2214 -0
- package/schemas/provider-config.schema.json +203 -0
- package/schemas/telemetry-config.schema.json +79 -0
- package/schemas/user-preferences.schema.json +141 -0
- package/scripts/assert-node-runtime.mjs +140 -0
- package/scripts/preflight-native.mjs +49 -0
- package/scripts/preinstall-node-check.mjs +78 -0
- package/scripts/setup-git-hooks.mjs +24 -0
- package/scripts/sync.sh +2722 -0
- package/scripts/write-node-launcher.sh +108 -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/.poetic/README.md +37 -0
- package/templates/.poetic/agents/README.md +296 -0
- package/templates/.poetic/agents/api-documenter.md +147 -0
- package/templates/.poetic/agents/backend-architect.md +31 -0
- package/templates/.poetic/agents/code-reviewer.md +157 -0
- package/templates/.poetic/agents/data-scientist.md +179 -0
- package/templates/.poetic/agents/database-optimizer.md +145 -0
- package/templates/.poetic/agents/debugger.md +31 -0
- package/templates/.poetic/agents/deployment-engineer.md +164 -0
- package/templates/.poetic/agents/devops-troubleshooter.md +139 -0
- package/templates/.poetic/agents/frontend-developer.md +150 -0
- package/templates/.poetic/agents/javascript-pro.md +36 -0
- package/templates/.poetic/agents/performance-engineer.md +151 -0
- package/templates/.poetic/agents/python-pro.md +137 -0
- package/templates/.poetic/agents/test-automator.md +147 -0
- package/templates/.poetic/agents/typescript-pro.md +34 -0
- package/templates/.poetic/config/poetic.config.jsonc +69 -0
- package/templates/.poetic/config/project-context.template.json +6 -0
- package/templates/.poetic/config/task-type-aliases.presets/kanban.yaml +14 -0
- package/templates/.poetic/config/task-type-aliases.presets/scrum.yaml +17 -0
- package/templates/.poetic/config/task-type-aliases.presets/xp.yaml +12 -0
- package/templates/.poetic/config/task-type-aliases.yaml +28 -0
- package/templates/.poetic/gitignore.template +55 -0
- package/templates/.poetic/task-types/analysis.yaml +40 -0
- package/templates/.poetic/task-types/architecture.yaml +38 -0
- package/templates/.poetic/task-types/doc.yaml +35 -0
- package/templates/.poetic/task-types/feature.yaml +23 -0
- package/templates/.poetic/task-types/general.yaml +6 -0
- package/templates/.poetic/task-types/security.yaml +39 -0
- package/templates/AGENTS.template.md +99 -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/compete-streak.yaml +78 -0
- package/templates/builtin-workflows/hello-verify.yaml +10 -0
- package/templates/builtin-workflows/judge-regression.yaml +114 -0
- package/templates/builtin-workflows/skills/code-review/SKILL.md +60 -0
- package/templates/builtin-workflows/skills/hello-verify/SKILL.md +6 -0
- package/templates/guard-kit/GUARD_SETUP.md.template +255 -0
- package/templates/guard-kit/check.mjs.template +777 -0
- package/templates/guard-kit/config.json.template +6 -0
- package/templates/guard-kit/poetic-guard.yml.template +189 -0
- package/templates/profiles/README.md +56 -0
- package/templates/profiles/frontier-claude.json +27 -0
- package/templates/profiles/frontier-codex.json +26 -0
|
@@ -0,0 +1,1972 @@
|
|
|
1
|
+
import {
|
|
2
|
+
StaleVersionError
|
|
3
|
+
} from "./chunk-TDSEX5CF.js";
|
|
4
|
+
import {
|
|
5
|
+
generateEnhancements,
|
|
6
|
+
hintsFromEnhancements,
|
|
7
|
+
toEnhancementSet,
|
|
8
|
+
toPersistedFormat
|
|
9
|
+
} from "./chunk-LIVJ6266.js";
|
|
10
|
+
import {
|
|
11
|
+
BUILT_IN_VARIANT_STRATEGIES
|
|
12
|
+
} from "./chunk-VXF4Q3FW.js";
|
|
13
|
+
import {
|
|
14
|
+
getDefaultActivityForCategory
|
|
15
|
+
} from "./chunk-4RCCF5BR.js";
|
|
16
|
+
import {
|
|
17
|
+
isTaskStatus,
|
|
18
|
+
validateStateTransition
|
|
19
|
+
} from "./chunk-KNT72VR6.js";
|
|
20
|
+
import {
|
|
21
|
+
classifyTaskDependency,
|
|
22
|
+
loadAllItems
|
|
23
|
+
} from "./chunk-3BCUNHKF.js";
|
|
24
|
+
import {
|
|
25
|
+
getArchiveShard,
|
|
26
|
+
getArchivedFilePath
|
|
27
|
+
} from "./chunk-OYZYO7TV.js";
|
|
28
|
+
import {
|
|
29
|
+
generateId,
|
|
30
|
+
isValidId
|
|
31
|
+
} from "./chunk-VNSYKC25.js";
|
|
32
|
+
import {
|
|
33
|
+
assertCompletionContractsMet,
|
|
34
|
+
normalizeCompletionContracts
|
|
35
|
+
} from "./chunk-R35PEUKH.js";
|
|
36
|
+
import {
|
|
37
|
+
getPlanningRoot,
|
|
38
|
+
withIndexRegeneration
|
|
39
|
+
} from "./chunk-OPYFYTWQ.js";
|
|
40
|
+
import {
|
|
41
|
+
getBucketArchivePathByKind,
|
|
42
|
+
getBucketByName,
|
|
43
|
+
getBucketPathByKind
|
|
44
|
+
} from "./chunk-HOYBYAOA.js";
|
|
45
|
+
import {
|
|
46
|
+
assertSafePlanningFileId,
|
|
47
|
+
ensureDirectoryExists,
|
|
48
|
+
listMarkdownFiles,
|
|
49
|
+
listMarkdownFilesRecursive,
|
|
50
|
+
listMarkdownFilesRecursiveStrict,
|
|
51
|
+
readMarkdownFile,
|
|
52
|
+
resolvePlanningItemPath,
|
|
53
|
+
writeMarkdownFile
|
|
54
|
+
} from "./chunk-OIS7J26S.js";
|
|
55
|
+
import {
|
|
56
|
+
emitCustomWarning
|
|
57
|
+
} from "./chunk-EJGCZGUF.js";
|
|
58
|
+
|
|
59
|
+
// src/planning/task-manager.ts
|
|
60
|
+
import * as crypto from "crypto";
|
|
61
|
+
import * as fs from "fs/promises";
|
|
62
|
+
import * as path from "path";
|
|
63
|
+
function isBuiltInStrategy(value) {
|
|
64
|
+
return typeof value === "string" && BUILT_IN_VARIANT_STRATEGIES.includes(value);
|
|
65
|
+
}
|
|
66
|
+
function emitTaskManagerWarning(message, metadata) {
|
|
67
|
+
emitCustomWarning(
|
|
68
|
+
"WARN" /* WARN */,
|
|
69
|
+
"configuration" /* CONFIGURATION */,
|
|
70
|
+
message,
|
|
71
|
+
{
|
|
72
|
+
subsystem: "planning/task-manager",
|
|
73
|
+
executionPhase: "execution"
|
|
74
|
+
},
|
|
75
|
+
{ metadata, skipConsole: true }
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
function parseNumber(value, fallback) {
|
|
79
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
80
|
+
if (typeof value === "string") {
|
|
81
|
+
const parsed = Number.parseFloat(value);
|
|
82
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
83
|
+
}
|
|
84
|
+
return fallback;
|
|
85
|
+
}
|
|
86
|
+
function parseOptionalNumber(value) {
|
|
87
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
88
|
+
if (typeof value === "string") {
|
|
89
|
+
const parsed = Number.parseFloat(value);
|
|
90
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
91
|
+
}
|
|
92
|
+
return void 0;
|
|
93
|
+
}
|
|
94
|
+
var RUNTIME_ESTIMATE_PROVENANCES = ["heuristic", "telemetry", "blended", "explicit"];
|
|
95
|
+
var RUNTIME_ESTIMATE_CONFIDENCES = ["low", "medium", "high"];
|
|
96
|
+
function coerceRuntimeEstimateFields(frontMatter) {
|
|
97
|
+
const result = {};
|
|
98
|
+
const minutes = parseOptionalNumber(frontMatter.expectedRuntimeMinutes);
|
|
99
|
+
if (typeof minutes === "number" && minutes > 0) {
|
|
100
|
+
result.expectedRuntimeMinutes = minutes;
|
|
101
|
+
}
|
|
102
|
+
const provenance = frontMatter.runtimeEstimateProvenance;
|
|
103
|
+
if (typeof provenance === "string" && RUNTIME_ESTIMATE_PROVENANCES.includes(provenance)) {
|
|
104
|
+
result.runtimeEstimateProvenance = provenance;
|
|
105
|
+
}
|
|
106
|
+
const confidence = frontMatter.runtimeEstimateConfidence;
|
|
107
|
+
if (typeof confidence === "string" && RUNTIME_ESTIMATE_CONFIDENCES.includes(confidence)) {
|
|
108
|
+
result.runtimeEstimateConfidence = confidence;
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
var VALID_STAGE_OUTPUT_TYPES = [
|
|
113
|
+
"diff",
|
|
114
|
+
"files",
|
|
115
|
+
"text",
|
|
116
|
+
"testResults",
|
|
117
|
+
"json"
|
|
118
|
+
];
|
|
119
|
+
function coerceStageOutputs(value) {
|
|
120
|
+
if (!value || typeof value !== "object") return void 0;
|
|
121
|
+
const outputs = {};
|
|
122
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
123
|
+
if (!key || typeof key !== "string") continue;
|
|
124
|
+
if (typeof raw !== "string") continue;
|
|
125
|
+
if (!VALID_STAGE_OUTPUT_TYPES.includes(raw)) continue;
|
|
126
|
+
outputs[key] = raw;
|
|
127
|
+
}
|
|
128
|
+
return Object.keys(outputs).length > 0 ? outputs : void 0;
|
|
129
|
+
}
|
|
130
|
+
function coerceStageValidationOverride(value) {
|
|
131
|
+
if (!value || typeof value !== "object") return void 0;
|
|
132
|
+
const raw = value;
|
|
133
|
+
const enabled = typeof raw.enabled === "boolean" ? raw.enabled : void 0;
|
|
134
|
+
const target = typeof raw.target === "string" ? raw.target : void 0;
|
|
135
|
+
const threshold = parseOptionalNumber(raw.threshold);
|
|
136
|
+
const maxRetries = parseOptionalNumber(raw.maxRetries);
|
|
137
|
+
const requiredFiles = Array.isArray(raw.requiredFiles) ? raw.requiredFiles.filter(
|
|
138
|
+
(value2) => typeof value2 === "string" && value2.trim().length > 0
|
|
139
|
+
) : void 0;
|
|
140
|
+
const checks = Array.isArray(raw.checks) ? raw.checks : void 0;
|
|
141
|
+
const semanticChecks = Array.isArray(raw.semanticChecks) ? raw.semanticChecks : void 0;
|
|
142
|
+
if (enabled === void 0 && target === void 0 && threshold === void 0 && maxRetries === void 0 && requiredFiles === void 0 && checks === void 0 && semanticChecks === void 0) {
|
|
143
|
+
return void 0;
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
...enabled !== void 0 ? { enabled } : {},
|
|
147
|
+
...target ? { target } : {},
|
|
148
|
+
...threshold !== void 0 ? { threshold } : {},
|
|
149
|
+
...maxRetries !== void 0 ? { maxRetries } : {},
|
|
150
|
+
...requiredFiles && requiredFiles.length > 0 ? { requiredFiles } : {},
|
|
151
|
+
...checks ? { checks } : {},
|
|
152
|
+
...semanticChecks ? { semanticChecks } : {}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function coerceVariantSpec(value) {
|
|
156
|
+
if (typeof value === "string") {
|
|
157
|
+
const [providerRaw, strategyRaw2] = value.split(":").map((v) => v.trim());
|
|
158
|
+
if (!providerRaw) return null;
|
|
159
|
+
const strategy2 = isBuiltInStrategy(strategyRaw2) ? strategyRaw2 : void 0;
|
|
160
|
+
return { provider: providerRaw, ...strategy2 ? { strategy: strategy2 } : {} };
|
|
161
|
+
}
|
|
162
|
+
if (!value || typeof value !== "object") return null;
|
|
163
|
+
const raw = value;
|
|
164
|
+
const provider = typeof raw.provider === "string" ? raw.provider : void 0;
|
|
165
|
+
if (!provider) return null;
|
|
166
|
+
const model = typeof raw.model === "string" ? raw.model : void 0;
|
|
167
|
+
const strategyRaw = typeof raw.strategy === "string" ? raw.strategy : void 0;
|
|
168
|
+
const strategy = isBuiltInStrategy(strategyRaw) ? strategyRaw : void 0;
|
|
169
|
+
const reasoning = typeof raw.reasoning === "string" ? raw.reasoning : void 0;
|
|
170
|
+
return {
|
|
171
|
+
provider,
|
|
172
|
+
...model ? { model } : {},
|
|
173
|
+
...strategy ? { strategy } : {},
|
|
174
|
+
...reasoning ? { reasoning } : {}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
function coerceCompetitionConfig(value) {
|
|
178
|
+
if (!value || typeof value !== "object") return void 0;
|
|
179
|
+
const raw = value;
|
|
180
|
+
const variantsRaw = raw.variants;
|
|
181
|
+
const variants = Array.isArray(variantsRaw) ? variantsRaw.map(coerceVariantSpec).filter((v) => Boolean(v)) : [];
|
|
182
|
+
if (variants.length === 0) return void 0;
|
|
183
|
+
const judgeConfigRaw = raw.judgeConfig;
|
|
184
|
+
const judgeConfig = judgeConfigRaw && typeof judgeConfigRaw === "object" ? {
|
|
185
|
+
type: (() => {
|
|
186
|
+
const obj = judgeConfigRaw;
|
|
187
|
+
const typeRaw = obj.type;
|
|
188
|
+
if (typeof typeRaw === "string" && (typeRaw === "multi-lens" || typeRaw === "multi-agent" || typeRaw === "ai")) {
|
|
189
|
+
return typeRaw;
|
|
190
|
+
}
|
|
191
|
+
return void 0;
|
|
192
|
+
})(),
|
|
193
|
+
threshold: parseOptionalNumber(judgeConfigRaw.threshold),
|
|
194
|
+
runComparison: (() => {
|
|
195
|
+
const value2 = judgeConfigRaw.runComparison;
|
|
196
|
+
return typeof value2 === "boolean" ? value2 : void 0;
|
|
197
|
+
})()
|
|
198
|
+
} : void 0;
|
|
199
|
+
const preserveCandidates = typeof raw.preserveCandidates === "boolean" ? raw.preserveCandidates : void 0;
|
|
200
|
+
const applyWinner = typeof raw.applyWinner === "boolean" ? raw.applyWinner : void 0;
|
|
201
|
+
const tieBreakerRaw = raw.tieBreaker;
|
|
202
|
+
const tieBreaker = tieBreakerRaw && typeof tieBreakerRaw === "object" ? {
|
|
203
|
+
mode: (() => {
|
|
204
|
+
const obj = tieBreakerRaw;
|
|
205
|
+
const modeRaw = obj.mode;
|
|
206
|
+
if (modeRaw === "prefer-first-ranked" || modeRaw === "prefer-strategy" || modeRaw === "prefer-low-drift" || modeRaw === "prefer-smaller-diff" || modeRaw === "prefer-low-drift-then-diff") {
|
|
207
|
+
return modeRaw;
|
|
208
|
+
}
|
|
209
|
+
return void 0;
|
|
210
|
+
})(),
|
|
211
|
+
strategy: (() => {
|
|
212
|
+
const obj = tieBreakerRaw;
|
|
213
|
+
const strategyRaw = obj.strategy;
|
|
214
|
+
if (strategyRaw === "conservative" || strategyRaw === "innovative") {
|
|
215
|
+
return strategyRaw;
|
|
216
|
+
}
|
|
217
|
+
return void 0;
|
|
218
|
+
})()
|
|
219
|
+
} : void 0;
|
|
220
|
+
const normalizedTieBreaker = tieBreaker?.mode ? {
|
|
221
|
+
mode: tieBreaker.mode,
|
|
222
|
+
...tieBreaker.strategy ? { strategy: tieBreaker.strategy } : {}
|
|
223
|
+
} : void 0;
|
|
224
|
+
const verificationPolicyRaw = typeof raw.verificationPolicy === "string" ? raw.verificationPolicy : void 0;
|
|
225
|
+
const verificationPolicy = verificationPolicyRaw === "findings" || verificationPolicyRaw === "blocking" ? verificationPolicyRaw : void 0;
|
|
226
|
+
const repairRaw = raw.repairOnFindings;
|
|
227
|
+
const repairObj = repairRaw && typeof repairRaw === "object" ? repairRaw : null;
|
|
228
|
+
const repairOnFindings = repairObj ? {
|
|
229
|
+
enabled: Boolean(repairObj.enabled),
|
|
230
|
+
...parseOptionalNumber(repairObj.maxIterations) !== void 0 ? {
|
|
231
|
+
maxIterations: parseOptionalNumber(repairObj.maxIterations)
|
|
232
|
+
} : {},
|
|
233
|
+
...parseOptionalNumber(repairObj.timeboxMs) !== void 0 ? { timeboxMs: parseOptionalNumber(repairObj.timeboxMs) } : {}
|
|
234
|
+
} : void 0;
|
|
235
|
+
const result = {
|
|
236
|
+
variants,
|
|
237
|
+
...judgeConfig?.type ? {
|
|
238
|
+
judgeConfig: {
|
|
239
|
+
type: judgeConfig.type,
|
|
240
|
+
...Number.isFinite(judgeConfig.threshold) ? { threshold: judgeConfig.threshold } : {},
|
|
241
|
+
...judgeConfig.runComparison !== void 0 ? { runComparison: judgeConfig.runComparison } : {}
|
|
242
|
+
}
|
|
243
|
+
} : {},
|
|
244
|
+
...preserveCandidates !== void 0 ? { preserveCandidates } : {},
|
|
245
|
+
...applyWinner !== void 0 ? { applyWinner } : {},
|
|
246
|
+
...verificationPolicy ? { verificationPolicy } : {},
|
|
247
|
+
...repairOnFindings ? { repairOnFindings } : {},
|
|
248
|
+
...normalizedTieBreaker ? { tieBreaker: normalizedTieBreaker } : {}
|
|
249
|
+
};
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
function coerceFlywheelConfig(value) {
|
|
253
|
+
if (!value || typeof value !== "object") return void 0;
|
|
254
|
+
const raw = value;
|
|
255
|
+
const typeRaw = typeof raw.type === "string" ? raw.type : void 0;
|
|
256
|
+
const type = typeRaw === "standard" || typeRaw === "competition" || typeRaw === "verify" || typeRaw === "refinement" || typeRaw === "autoloop" ? typeRaw : void 0;
|
|
257
|
+
const inputs = Array.isArray(raw.inputs) ? raw.inputs.filter(
|
|
258
|
+
(v) => typeof v === "string" && v.length > 0
|
|
259
|
+
) : void 0;
|
|
260
|
+
const allowlist = Array.isArray(raw.allowlist) ? raw.allowlist.filter((v) => typeof v === "string" && v.length > 0) : void 0;
|
|
261
|
+
const allowDenylist = Array.isArray(raw.allowDenylist) ? raw.allowDenylist.filter(
|
|
262
|
+
(v) => typeof v === "string" && v.length > 0
|
|
263
|
+
) : void 0;
|
|
264
|
+
const allowlistModeRaw = typeof raw.allowlistMode === "string" ? raw.allowlistMode : void 0;
|
|
265
|
+
const allowlistMode = allowlistModeRaw === "off" || allowlistModeRaw === "warn" || allowlistModeRaw === "strict" || allowlistModeRaw === "filter" ? allowlistModeRaw : void 0;
|
|
266
|
+
const verifyRaw = raw.verify;
|
|
267
|
+
const verifyObj = verifyRaw && typeof verifyRaw === "object" ? verifyRaw : null;
|
|
268
|
+
const verify = verifyObj && Array.isArray(verifyObj.commands) ? {
|
|
269
|
+
commands: verifyObj.commands.filter(
|
|
270
|
+
(v) => typeof v === "string" && v.length > 0
|
|
271
|
+
)
|
|
272
|
+
} : void 0;
|
|
273
|
+
const outputs = coerceStageOutputs(raw.outputs);
|
|
274
|
+
const validation = coerceStageValidationOverride(raw.validation);
|
|
275
|
+
const competition = coerceCompetitionConfig(raw.competition);
|
|
276
|
+
const allowEmptyResults = typeof raw.allowEmptyResults === "boolean" ? raw.allowEmptyResults : void 0;
|
|
277
|
+
const autoloopRaw = raw.autoloop;
|
|
278
|
+
const autoloopObj = autoloopRaw && typeof autoloopRaw === "object" ? autoloopRaw : null;
|
|
279
|
+
const autoloop = autoloopObj ? {
|
|
280
|
+
...parseOptionalNumber(autoloopObj.maxIterations) !== void 0 ? {
|
|
281
|
+
maxIterations: parseOptionalNumber(autoloopObj.maxIterations)
|
|
282
|
+
} : {},
|
|
283
|
+
...parseOptionalNumber(autoloopObj.timeboxMs) !== void 0 ? { timeboxMs: parseOptionalNumber(autoloopObj.timeboxMs) } : {},
|
|
284
|
+
...parseOptionalNumber(autoloopObj.minProgress) !== void 0 ? {
|
|
285
|
+
minProgress: parseOptionalNumber(autoloopObj.minProgress)
|
|
286
|
+
} : {},
|
|
287
|
+
...typeof autoloopObj.stopOnQualityGate === "boolean" ? { stopOnQualityGate: autoloopObj.stopOnQualityGate } : {},
|
|
288
|
+
...Array.isArray(autoloopObj.qualityGateCommands) ? {
|
|
289
|
+
qualityGateCommands: autoloopObj.qualityGateCommands.filter(
|
|
290
|
+
(v) => typeof v === "string" && v.length > 0
|
|
291
|
+
)
|
|
292
|
+
} : {}
|
|
293
|
+
} : void 0;
|
|
294
|
+
const hasAutoloopFields = Boolean(
|
|
295
|
+
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)
|
|
296
|
+
);
|
|
297
|
+
if (!type && (!inputs || inputs.length === 0) && (!allowlist || allowlist.length === 0) && (!allowDenylist || allowDenylist.length === 0) && !allowlistMode && !verify && !outputs && !validation && !competition && allowEmptyResults === void 0 && !hasAutoloopFields)
|
|
298
|
+
return void 0;
|
|
299
|
+
return {
|
|
300
|
+
...type ? { type } : {},
|
|
301
|
+
...inputs && inputs.length > 0 ? { inputs } : {},
|
|
302
|
+
...allowlist && allowlist.length > 0 ? { allowlist } : {},
|
|
303
|
+
...allowDenylist && allowDenylist.length > 0 ? { allowDenylist } : {},
|
|
304
|
+
...allowlistMode ? { allowlistMode } : {},
|
|
305
|
+
...verify && verify.commands.length > 0 ? { verify } : {},
|
|
306
|
+
...outputs ? { outputs } : {},
|
|
307
|
+
...validation ? { validation } : {},
|
|
308
|
+
...competition ? { competition } : {},
|
|
309
|
+
...allowEmptyResults !== void 0 ? { allowEmptyResults } : {},
|
|
310
|
+
...hasAutoloopFields ? { autoloop } : {}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
function coerceTaskYAML(frontMatter) {
|
|
314
|
+
const id = typeof frontMatter.id === "string" ? frontMatter.id : "";
|
|
315
|
+
if (!id) {
|
|
316
|
+
throw new Error('Invalid task frontmatter: missing required field "id"');
|
|
317
|
+
}
|
|
318
|
+
const originalSprintId = typeof frontMatter.originalSprintId === "string" && frontMatter.originalSprintId ? frontMatter.originalSprintId : void 0;
|
|
319
|
+
const sprintId = typeof frontMatter.sprintId === "string" && frontMatter.sprintId || typeof frontMatter.sprint_id === "string" && frontMatter.sprint_id || originalSprintId || "";
|
|
320
|
+
if (!sprintId) {
|
|
321
|
+
throw new Error(`Invalid task frontmatter for '${id}': missing required field "sprintId"`);
|
|
322
|
+
}
|
|
323
|
+
assertSafePlanningFileId(id, "taskId");
|
|
324
|
+
assertSafePlanningFileId(sprintId, "sprintId");
|
|
325
|
+
if (originalSprintId) {
|
|
326
|
+
assertSafePlanningFileId(originalSprintId, "originalSprintId");
|
|
327
|
+
}
|
|
328
|
+
const title = typeof frontMatter.title === "string" ? frontMatter.title : "";
|
|
329
|
+
if (!title) {
|
|
330
|
+
throw new Error(`Invalid task frontmatter for '${id}': missing required field "title"`);
|
|
331
|
+
}
|
|
332
|
+
const version = parseNumber(frontMatter.version, 0);
|
|
333
|
+
const statusRaw = typeof frontMatter.status === "string" ? frontMatter.status : "todo";
|
|
334
|
+
const statusMap = {
|
|
335
|
+
// Canonical statuses
|
|
336
|
+
todo: "todo",
|
|
337
|
+
in_progress: "in_progress",
|
|
338
|
+
review: "review",
|
|
339
|
+
done: "done",
|
|
340
|
+
blocked: "blocked",
|
|
341
|
+
cancelled: "cancelled",
|
|
342
|
+
canceled: "cancelled",
|
|
343
|
+
// Legacy statuses (kebab-case and alternatives)
|
|
344
|
+
pending: "todo",
|
|
345
|
+
"in-progress": "in_progress",
|
|
346
|
+
completed: "done",
|
|
347
|
+
archived: "done"
|
|
348
|
+
};
|
|
349
|
+
const status = statusMap[statusRaw] ?? "todo";
|
|
350
|
+
const priorityRaw = typeof frontMatter.priority === "string" ? frontMatter.priority : "P2";
|
|
351
|
+
const priority = priorityRaw === "P0" || priorityRaw === "P1" || priorityRaw === "P2" || priorityRaw === "P3" ? priorityRaw : "P2";
|
|
352
|
+
const dependencies = Array.isArray(frontMatter.dependencies) ? frontMatter.dependencies.filter((v) => typeof v === "string") : [];
|
|
353
|
+
const subtasksRaw = Array.isArray(frontMatter.subtasks) ? frontMatter.subtasks : [];
|
|
354
|
+
const subtasks = subtasksRaw.map((st) => {
|
|
355
|
+
if (!st || typeof st !== "object") return null;
|
|
356
|
+
const stObj = st;
|
|
357
|
+
const text = typeof stObj.text === "string" ? stObj.text : "";
|
|
358
|
+
if (!text) return null;
|
|
359
|
+
return {
|
|
360
|
+
text,
|
|
361
|
+
completed: Boolean(stObj.completed)
|
|
362
|
+
};
|
|
363
|
+
}).filter((v) => Boolean(v));
|
|
364
|
+
const createdAt = typeof frontMatter.created_at === "string" && frontMatter.created_at || typeof frontMatter.created === "string" && frontMatter.created || (/* @__PURE__ */ new Date()).toISOString();
|
|
365
|
+
const updatedAt = typeof frontMatter.updated_at === "string" && frontMatter.updated_at || typeof frontMatter.updated === "string" && frontMatter.updated || createdAt;
|
|
366
|
+
const metadataRaw = frontMatter.metadata;
|
|
367
|
+
let metadata = metadataRaw && typeof metadataRaw === "object" ? {
|
|
368
|
+
executionIntent: metadataRaw.executionIntent === "analysis" || metadataRaw.executionIntent === "edit" ? metadataRaw.executionIntent : void 0
|
|
369
|
+
} : void 0;
|
|
370
|
+
const routingRaw = frontMatter.routing;
|
|
371
|
+
let routing;
|
|
372
|
+
if (routingRaw && typeof routingRaw === "object") {
|
|
373
|
+
const routingObj = routingRaw;
|
|
374
|
+
const provider = typeof routingObj.provider === "string" ? routingObj.provider : void 0;
|
|
375
|
+
const model = typeof routingObj.model === "string" ? routingObj.model : void 0;
|
|
376
|
+
const strategyRaw = typeof routingObj.strategy === "string" ? routingObj.strategy : void 0;
|
|
377
|
+
const strategy = isBuiltInStrategy(strategyRaw) ? strategyRaw : void 0;
|
|
378
|
+
const reasoning = typeof routingObj.reasoning === "string" ? routingObj.reasoning : void 0;
|
|
379
|
+
const profile = typeof routingObj.profile === "string" ? routingObj.profile : void 0;
|
|
380
|
+
if (provider || model || strategy || reasoning || profile) {
|
|
381
|
+
routing = { provider, model, strategy, reasoning, profile };
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
const executionIntentRaw = frontMatter.executionIntent;
|
|
385
|
+
if (!metadata?.executionIntent && (executionIntentRaw === "analysis" || executionIntentRaw === "edit")) {
|
|
386
|
+
metadata = { executionIntent: executionIntentRaw };
|
|
387
|
+
}
|
|
388
|
+
if (!routing) {
|
|
389
|
+
const provider = typeof frontMatter.provider === "string" ? frontMatter.provider : void 0;
|
|
390
|
+
const model = typeof frontMatter.model === "string" ? frontMatter.model : void 0;
|
|
391
|
+
if (provider && provider !== "multi" || model) {
|
|
392
|
+
routing = {
|
|
393
|
+
provider: provider && provider !== "multi" ? provider : void 0,
|
|
394
|
+
model
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
const flywheel = coerceFlywheelConfig(frontMatter.flywheel);
|
|
399
|
+
const taskClassificationRaw = frontMatter.taskClassification;
|
|
400
|
+
let taskClassification;
|
|
401
|
+
if (taskClassificationRaw && typeof taskClassificationRaw === "object") {
|
|
402
|
+
const classObj = taskClassificationRaw;
|
|
403
|
+
const categoryRaw = typeof classObj.category === "string" ? classObj.category : void 0;
|
|
404
|
+
const activityRaw = typeof classObj.activity === "string" ? classObj.activity : void 0;
|
|
405
|
+
const validCategories = ["execute", "review", "analyze", "test", "document"];
|
|
406
|
+
const validActivities = [
|
|
407
|
+
"planning",
|
|
408
|
+
"research",
|
|
409
|
+
"architecture",
|
|
410
|
+
"design",
|
|
411
|
+
"development",
|
|
412
|
+
"debugging"
|
|
413
|
+
];
|
|
414
|
+
const category = categoryRaw && validCategories.includes(categoryRaw) ? categoryRaw : void 0;
|
|
415
|
+
let activity = activityRaw && validActivities.includes(activityRaw) ? activityRaw : void 0;
|
|
416
|
+
if (category && !activity) {
|
|
417
|
+
activity = getDefaultActivityForCategory(category);
|
|
418
|
+
}
|
|
419
|
+
if (category || activity) {
|
|
420
|
+
taskClassification = { category, activity };
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
const taskTypeRaw = frontMatter.taskType ?? frontMatter.task_type;
|
|
424
|
+
const taskType = typeof taskTypeRaw === "string" && taskTypeRaw.trim().length > 0 ? taskTypeRaw.trim() : void 0;
|
|
425
|
+
const declaredType = typeof frontMatter.declaredType === "string" ? frontMatter.declaredType : void 0;
|
|
426
|
+
const declaredMethodology = typeof frontMatter.declaredMethodology === "string" ? frontMatter.declaredMethodology : void 0;
|
|
427
|
+
const resolvedTaskTypeId = typeof frontMatter.resolvedTaskTypeId === "string" ? frontMatter.resolvedTaskTypeId : void 0;
|
|
428
|
+
const hints = Array.isArray(frontMatter.hints) ? frontMatter.hints.filter((h) => typeof h === "string") : void 0;
|
|
429
|
+
function coerceEnhancementIntent(value) {
|
|
430
|
+
if (!value || typeof value !== "object") return void 0;
|
|
431
|
+
const obj = value;
|
|
432
|
+
const categoryRaw = typeof obj.category === "string" ? obj.category : void 0;
|
|
433
|
+
const activityRaw = typeof obj.activity === "string" ? obj.activity : void 0;
|
|
434
|
+
const confidenceRaw = typeof obj.confidence === "number" ? obj.confidence : void 0;
|
|
435
|
+
const validCategories = ["execute", "review", "analyze", "test", "document"];
|
|
436
|
+
const validActivities = [
|
|
437
|
+
"planning",
|
|
438
|
+
"research",
|
|
439
|
+
"architecture",
|
|
440
|
+
"design",
|
|
441
|
+
"development",
|
|
442
|
+
"debugging"
|
|
443
|
+
];
|
|
444
|
+
const category = categoryRaw && validCategories.includes(categoryRaw) ? categoryRaw : void 0;
|
|
445
|
+
const activity = activityRaw && validActivities.includes(activityRaw) ? activityRaw : void 0;
|
|
446
|
+
if (!category || !activity) return void 0;
|
|
447
|
+
const confidence = typeof confidenceRaw === "number" && confidenceRaw >= 0 && confidenceRaw <= 1 ? confidenceRaw : void 0;
|
|
448
|
+
if (confidence === void 0) return void 0;
|
|
449
|
+
return { category, activity, confidence };
|
|
450
|
+
}
|
|
451
|
+
const enhancementSetRaw = frontMatter.enhancementSet;
|
|
452
|
+
const enhancementSet = enhancementSetRaw && typeof enhancementSetRaw === "object" ? (() => {
|
|
453
|
+
const obj = enhancementSetRaw;
|
|
454
|
+
const version2 = obj.version === 1 ? 1 : void 0;
|
|
455
|
+
const intentRaw = obj.intent;
|
|
456
|
+
if (version2 !== 1 || !intentRaw || typeof intentRaw !== "object") return void 0;
|
|
457
|
+
const intent = coerceEnhancementIntent(intentRaw);
|
|
458
|
+
if (!intent) return void 0;
|
|
459
|
+
const enhancementsRaw = obj.enhancements ?? void 0;
|
|
460
|
+
const enhancements2 = Array.isArray(
|
|
461
|
+
enhancementsRaw
|
|
462
|
+
) ? enhancementsRaw.map((e) => {
|
|
463
|
+
if (!e || typeof e !== "object") return null;
|
|
464
|
+
const eObj = e;
|
|
465
|
+
const kind = typeof eObj.kind === "string" ? eObj.kind : void 0;
|
|
466
|
+
const snippet = typeof eObj.snippet === "string" ? eObj.snippet : void 0;
|
|
467
|
+
if (!kind || !snippet) return null;
|
|
468
|
+
return { kind, snippet };
|
|
469
|
+
}).filter(
|
|
470
|
+
(e) => e !== null
|
|
471
|
+
) : void 0;
|
|
472
|
+
if (!enhancements2) return void 0;
|
|
473
|
+
const acceptanceCriteriaRaw = obj.acceptanceCriteria;
|
|
474
|
+
const acceptanceCriteria = Array.isArray(acceptanceCriteriaRaw) ? acceptanceCriteriaRaw.map((c) => {
|
|
475
|
+
if (!c || typeof c !== "object") return null;
|
|
476
|
+
const cObj = c;
|
|
477
|
+
const id2 = typeof cObj.id === "string" ? cObj.id : void 0;
|
|
478
|
+
const description = typeof cObj.description === "string" ? cObj.description : void 0;
|
|
479
|
+
if (!id2 || !description) return null;
|
|
480
|
+
const weight = typeof cObj.weight === "number" ? cObj.weight : void 0;
|
|
481
|
+
const verification = cObj.verification && typeof cObj.verification === "object" ? cObj.verification : void 0;
|
|
482
|
+
return {
|
|
483
|
+
id: id2,
|
|
484
|
+
description,
|
|
485
|
+
weight,
|
|
486
|
+
verification
|
|
487
|
+
};
|
|
488
|
+
}).filter((c) => c !== null) : void 0;
|
|
489
|
+
const constraintsRaw = obj.constraints;
|
|
490
|
+
const constraints = Array.isArray(constraintsRaw) ? constraintsRaw.map((c) => {
|
|
491
|
+
if (!c || typeof c !== "object") return null;
|
|
492
|
+
const cObj = c;
|
|
493
|
+
const id2 = typeof cObj.id === "string" ? cObj.id : void 0;
|
|
494
|
+
const rule = typeof cObj.rule === "string" ? cObj.rule : void 0;
|
|
495
|
+
if (!id2 || !rule) return null;
|
|
496
|
+
const penaltyPoints = typeof cObj.penaltyPoints === "number" ? cObj.penaltyPoints : void 0;
|
|
497
|
+
const scope = cObj.scope && typeof cObj.scope === "object" ? cObj.scope : void 0;
|
|
498
|
+
const allowIf = Array.isArray(cObj.allowIf) ? cObj.allowIf : void 0;
|
|
499
|
+
return {
|
|
500
|
+
id: id2,
|
|
501
|
+
rule,
|
|
502
|
+
penaltyPoints,
|
|
503
|
+
scope,
|
|
504
|
+
allowIf
|
|
505
|
+
};
|
|
506
|
+
}).filter((c) => c !== null) : void 0;
|
|
507
|
+
const artifactSourcesRaw = obj.artifactSources;
|
|
508
|
+
const artifactSources = artifactSourcesRaw && typeof artifactSourcesRaw === "object" ? (() => {
|
|
509
|
+
const a = artifactSourcesRaw;
|
|
510
|
+
const preferred = Array.isArray(a.preferred) ? a.preferred.filter((v) => typeof v === "string") : void 0;
|
|
511
|
+
const fallback = Array.isArray(a.fallback) ? a.fallback.filter((v) => typeof v === "string") : void 0;
|
|
512
|
+
if (!preferred && !fallback) return void 0;
|
|
513
|
+
return { preferred, fallback };
|
|
514
|
+
})() : void 0;
|
|
515
|
+
return {
|
|
516
|
+
version: 1,
|
|
517
|
+
intent,
|
|
518
|
+
enhancements: enhancements2,
|
|
519
|
+
acceptanceCriteria,
|
|
520
|
+
constraints,
|
|
521
|
+
artifactSources
|
|
522
|
+
};
|
|
523
|
+
})() : void 0;
|
|
524
|
+
const enhancementsLegacyRaw = frontMatter.enhancements;
|
|
525
|
+
const enhancementsLegacy = Array.isArray(
|
|
526
|
+
enhancementsLegacyRaw
|
|
527
|
+
) ? enhancementsLegacyRaw.map((e) => {
|
|
528
|
+
if (!e || typeof e !== "object") return null;
|
|
529
|
+
const obj = e;
|
|
530
|
+
const kind = typeof obj.kind === "string" ? obj.kind : void 0;
|
|
531
|
+
const snippet = typeof obj.snippet === "string" ? obj.snippet : void 0;
|
|
532
|
+
if (!kind || !snippet) return null;
|
|
533
|
+
return { kind, snippet };
|
|
534
|
+
}).filter((e) => e !== null) : void 0;
|
|
535
|
+
const enhancements = enhancementSet?.enhancements ?? enhancementsLegacy;
|
|
536
|
+
const blockedReason = typeof frontMatter.blockedReason === "string" && frontMatter.blockedReason.trim() ? frontMatter.blockedReason.trim() : void 0;
|
|
537
|
+
const blockedReasonHistory = Array.isArray(frontMatter.blockedReasonHistory) ? frontMatter.blockedReasonHistory.filter(
|
|
538
|
+
(value) => typeof value === "string" && value.trim().length > 0
|
|
539
|
+
) : void 0;
|
|
540
|
+
const forceCompletedFrom = isTaskStatus(frontMatter.forceCompletedFrom) && frontMatter.forceCompletedFrom !== "done" ? frontMatter.forceCompletedFrom : void 0;
|
|
541
|
+
const originalBlockedReason = typeof frontMatter.originalBlockedReason === "string" && frontMatter.originalBlockedReason.trim() ? frontMatter.originalBlockedReason.trim() : void 0;
|
|
542
|
+
const cancelledAt = typeof frontMatter.cancelledAt === "string" && frontMatter.cancelledAt.trim() ? frontMatter.cancelledAt.trim() : void 0;
|
|
543
|
+
const cancelledReason = typeof frontMatter.cancelledReason === "string" && frontMatter.cancelledReason.trim() ? frontMatter.cancelledReason.trim() : void 0;
|
|
544
|
+
const completionContract = normalizeCompletionContracts(frontMatter.completionContract);
|
|
545
|
+
const appliedTransitions = Array.isArray(frontMatter.appliedTransitions) ? frontMatter.appliedTransitions.filter(
|
|
546
|
+
(value) => typeof value === "string" && value.length > 0
|
|
547
|
+
) : void 0;
|
|
548
|
+
const lastTransitionReason = typeof frontMatter.lastTransitionReason === "string" && frontMatter.lastTransitionReason.trim() ? frontMatter.lastTransitionReason.trim() : void 0;
|
|
549
|
+
const statusBypassAudit = Array.isArray(frontMatter.statusBypassAudit) ? frontMatter.statusBypassAudit.map((entry) => {
|
|
550
|
+
if (!entry || typeof entry !== "object") return null;
|
|
551
|
+
const obj = entry;
|
|
552
|
+
const fromStatus = obj.fromStatus;
|
|
553
|
+
const toStatus = obj.toStatus;
|
|
554
|
+
const reason = typeof obj.reason === "string" ? obj.reason.trim() : "";
|
|
555
|
+
const at = typeof obj.at === "string" ? obj.at : "";
|
|
556
|
+
if (!isTaskStatus(fromStatus) || !isTaskStatus(toStatus) || !reason || !at) {
|
|
557
|
+
return null;
|
|
558
|
+
}
|
|
559
|
+
const actor = typeof obj.actor === "string" && obj.actor.trim() ? obj.actor.trim() : void 0;
|
|
560
|
+
return { at, fromStatus, toStatus, reason, actor };
|
|
561
|
+
}).filter(
|
|
562
|
+
(entry) => Boolean(entry)
|
|
563
|
+
) : void 0;
|
|
564
|
+
return {
|
|
565
|
+
...frontMatter,
|
|
566
|
+
id,
|
|
567
|
+
kind: "task",
|
|
568
|
+
version,
|
|
569
|
+
sprintId,
|
|
570
|
+
originalSprintId,
|
|
571
|
+
backlogItemId: typeof frontMatter.backlogItemId === "string" ? frontMatter.backlogItemId : void 0,
|
|
572
|
+
planArtifactPath: typeof frontMatter.planArtifactPath === "string" ? frontMatter.planArtifactPath : void 0,
|
|
573
|
+
resultArtifactPath: typeof frontMatter.resultArtifactPath === "string" ? frontMatter.resultArtifactPath : void 0,
|
|
574
|
+
planIntentHash: typeof frontMatter.planIntentHash === "string" ? frontMatter.planIntentHash : void 0,
|
|
575
|
+
planStageId: typeof frontMatter.planStageId === "string" ? frontMatter.planStageId : void 0,
|
|
576
|
+
splitStrategy: frontMatter.splitStrategy === "ai" || frontMatter.splitStrategy === "rule-based" ? frontMatter.splitStrategy : void 0,
|
|
577
|
+
splitMode: frontMatter.splitMode === "rule" || frontMatter.splitMode === "shadow" || frontMatter.splitMode === "llm" ? frontMatter.splitMode : void 0,
|
|
578
|
+
splitTaskType: typeof frontMatter.splitTaskType === "string" ? frontMatter.splitTaskType : void 0,
|
|
579
|
+
taskType,
|
|
580
|
+
declaredType,
|
|
581
|
+
declaredMethodology,
|
|
582
|
+
resolvedTaskTypeId,
|
|
583
|
+
title,
|
|
584
|
+
status,
|
|
585
|
+
priority,
|
|
586
|
+
assignee: typeof frontMatter.assignee === "string" ? frontMatter.assignee : void 0,
|
|
587
|
+
estimatedHours: parseNumber(frontMatter.estimatedHours, 0),
|
|
588
|
+
// AI runtime estimate fields: preserved only when present and valid. Never
|
|
589
|
+
// synthesized — a legacy task without them stays without them (no fake data).
|
|
590
|
+
...coerceRuntimeEstimateFields(frontMatter),
|
|
591
|
+
timeLoggedHours: parseNumber(frontMatter.timeLoggedHours, 0),
|
|
592
|
+
dependencies,
|
|
593
|
+
subtasks,
|
|
594
|
+
hints,
|
|
595
|
+
enhancements,
|
|
596
|
+
enhancementSet,
|
|
597
|
+
routing,
|
|
598
|
+
flywheel,
|
|
599
|
+
taskClassification,
|
|
600
|
+
blockedReason,
|
|
601
|
+
blockedReasonHistory,
|
|
602
|
+
forceCompletedFrom,
|
|
603
|
+
originalBlockedReason,
|
|
604
|
+
statusBypassAudit,
|
|
605
|
+
...completionContract.length > 0 ? { completionContract } : {},
|
|
606
|
+
...appliedTransitions && appliedTransitions.length > 0 ? { appliedTransitions } : {},
|
|
607
|
+
...lastTransitionReason ? { lastTransitionReason } : {},
|
|
608
|
+
metadata,
|
|
609
|
+
created_at: createdAt,
|
|
610
|
+
updated_at: updatedAt,
|
|
611
|
+
started_at: typeof frontMatter.started_at === "string" ? frontMatter.started_at : void 0,
|
|
612
|
+
completed_at: typeof frontMatter.completed_at === "string" ? frontMatter.completed_at : void 0,
|
|
613
|
+
cancelledAt,
|
|
614
|
+
cancelledReason
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
async function generateTaskId(sprintId, title) {
|
|
618
|
+
void sprintId;
|
|
619
|
+
void title;
|
|
620
|
+
return generateId(/* @__PURE__ */ new Date());
|
|
621
|
+
}
|
|
622
|
+
async function createTask(title, sprintId, options = {}, repoRoot) {
|
|
623
|
+
const result = await createTaskWithGuidance(title, sprintId, options, repoRoot);
|
|
624
|
+
return result.task;
|
|
625
|
+
}
|
|
626
|
+
async function createTaskWithGuidance(title, sprintId, options = {}, repoRoot) {
|
|
627
|
+
const planningRoot = repoRoot ?? getPlanningRoot();
|
|
628
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
629
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
630
|
+
await ensureDirectoryExists(tasksDir);
|
|
631
|
+
assertSafePlanningFileId(sprintId, "sprintId");
|
|
632
|
+
const taskId = await generateTaskId(sprintId, title);
|
|
633
|
+
const filePath = resolvePlanningItemPath(tasksDir, taskId, { label: "taskId" });
|
|
634
|
+
const dependencies = [...new Set(options.dependencies ?? [])];
|
|
635
|
+
if (dependencies.includes(taskId)) {
|
|
636
|
+
throw new Error(`Task cannot depend on itself: ${taskId}`);
|
|
637
|
+
}
|
|
638
|
+
if (dependencies.length > 0) {
|
|
639
|
+
const taskPath = getBucketPathByKind("task", planningRoot);
|
|
640
|
+
const taskArchivePath = getBucketArchivePathByKind("task", planningRoot);
|
|
641
|
+
const allItems = await loadAllItems(planningRoot, [taskPath, taskArchivePath]);
|
|
642
|
+
const allIds = new Set(allItems.map((item) => item.id));
|
|
643
|
+
const missingDependencies = dependencies.filter((depId) => !allIds.has(depId));
|
|
644
|
+
if (missingDependencies.length > 0) {
|
|
645
|
+
throw new Error(`Dependency task not found: ${missingDependencies.join(", ")}`);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
649
|
+
const task = {
|
|
650
|
+
id: taskId,
|
|
651
|
+
kind: "task",
|
|
652
|
+
version: 1,
|
|
653
|
+
sprintId,
|
|
654
|
+
backlogItemId: options.backlogItemId,
|
|
655
|
+
planArtifactPath: options.planArtifactPath,
|
|
656
|
+
planIntentHash: options.planIntentHash,
|
|
657
|
+
planStageId: options.planStageId,
|
|
658
|
+
splitStrategy: options.splitStrategy,
|
|
659
|
+
splitMode: options.splitMode,
|
|
660
|
+
splitTaskType: options.splitTaskType,
|
|
661
|
+
// Declared terminology (verbatim, opaque) + its resolved canonical id are
|
|
662
|
+
// carried through from the originating backlog item / decomposition so the
|
|
663
|
+
// declared term actually reaches sprint workflow resolution. Only set when
|
|
664
|
+
// present so legacy tasks stay clean.
|
|
665
|
+
...typeof options.declaredType === "string" && options.declaredType.length > 0 ? { declaredType: options.declaredType } : {},
|
|
666
|
+
...typeof options.declaredMethodology === "string" && options.declaredMethodology.length > 0 ? { declaredMethodology: options.declaredMethodology } : {},
|
|
667
|
+
...typeof options.resolvedTaskTypeId === "string" && options.resolvedTaskTypeId.length > 0 ? { resolvedTaskTypeId: options.resolvedTaskTypeId } : {},
|
|
668
|
+
title,
|
|
669
|
+
status: "todo",
|
|
670
|
+
priority: options.priority ?? "P2",
|
|
671
|
+
assignee: options.assignee,
|
|
672
|
+
estimatedHours: options.estimatedHours ?? 4,
|
|
673
|
+
// AI runtime estimate is optional and never defaulted (absence is honest,
|
|
674
|
+
// not zero/fake). estimatedHours default is untouched.
|
|
675
|
+
...typeof options.expectedRuntimeMinutes === "number" && options.expectedRuntimeMinutes > 0 ? { expectedRuntimeMinutes: options.expectedRuntimeMinutes } : {},
|
|
676
|
+
...options.runtimeEstimateProvenance ? { runtimeEstimateProvenance: options.runtimeEstimateProvenance } : {},
|
|
677
|
+
...options.runtimeEstimateConfidence ? { runtimeEstimateConfidence: options.runtimeEstimateConfidence } : {},
|
|
678
|
+
timeLoggedHours: 0,
|
|
679
|
+
dependencies,
|
|
680
|
+
subtasks: options.subtasks || [],
|
|
681
|
+
routing: options.routing,
|
|
682
|
+
flywheel: options.flywheel,
|
|
683
|
+
created_at: now,
|
|
684
|
+
updated_at: now
|
|
685
|
+
};
|
|
686
|
+
const description = typeof options.description === "string" && options.description.trim().length > 0 ? options.description.trim() : "Task created from sprint planning.";
|
|
687
|
+
let guidance;
|
|
688
|
+
if (options.planStageId) {
|
|
689
|
+
guidance = {
|
|
690
|
+
intent: { category: "execute", activity: "development", confidence: 1 },
|
|
691
|
+
enhancements: [],
|
|
692
|
+
quickReply: "",
|
|
693
|
+
nextCommands: []
|
|
694
|
+
};
|
|
695
|
+
} else {
|
|
696
|
+
guidance = generateEnhancements({
|
|
697
|
+
title,
|
|
698
|
+
description,
|
|
699
|
+
id: taskId,
|
|
700
|
+
itemKind: "task",
|
|
701
|
+
sprintId
|
|
702
|
+
});
|
|
703
|
+
const persistedEnhancements = toPersistedFormat(guidance.enhancements);
|
|
704
|
+
if (persistedEnhancements.length > 0) {
|
|
705
|
+
task.enhancements = persistedEnhancements;
|
|
706
|
+
task.enhancementSet = toEnhancementSet(guidance);
|
|
707
|
+
}
|
|
708
|
+
const hints = hintsFromEnhancements(guidance.enhancements);
|
|
709
|
+
if (hints.length > 0) task.hints = hints;
|
|
710
|
+
}
|
|
711
|
+
const body = `# Task: ${title}
|
|
712
|
+
|
|
713
|
+
**Sprint**: ${sprintId}
|
|
714
|
+
**Status**: To Do
|
|
715
|
+
**Estimated**: ${task.estimatedHours > 0 ? `${task.estimatedHours}h` : "unestimated"}
|
|
716
|
+
${task.planArtifactPath ? `**Plan Artifact**: ${task.planArtifactPath}
|
|
717
|
+
` : ""}${task.planStageId ? `**Plan Stage**: ${task.planStageId}
|
|
718
|
+
` : ""}
|
|
719
|
+
|
|
720
|
+
## Description
|
|
721
|
+
|
|
722
|
+
${description}
|
|
723
|
+
|
|
724
|
+
## Subtasks
|
|
725
|
+
|
|
726
|
+
${task.subtasks.length > 0 ? task.subtasks.map((st, _i) => `- [ ] ${st.text}`).join("\n") : "(No subtasks defined)"}
|
|
727
|
+
|
|
728
|
+
## Notes
|
|
729
|
+
|
|
730
|
+
Created on ${now}
|
|
731
|
+
`;
|
|
732
|
+
await writeMarkdownFile(
|
|
733
|
+
filePath,
|
|
734
|
+
task,
|
|
735
|
+
body
|
|
736
|
+
);
|
|
737
|
+
return { task, filePath, guidance };
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
function formatTaskStatusLabel(status) {
|
|
741
|
+
switch (status) {
|
|
742
|
+
case "todo":
|
|
743
|
+
return "To Do";
|
|
744
|
+
case "in_progress":
|
|
745
|
+
return "In Progress";
|
|
746
|
+
case "review":
|
|
747
|
+
return "Review";
|
|
748
|
+
case "done":
|
|
749
|
+
return "Done";
|
|
750
|
+
case "blocked":
|
|
751
|
+
return "Blocked";
|
|
752
|
+
case "cancelled":
|
|
753
|
+
return "Cancelled";
|
|
754
|
+
default:
|
|
755
|
+
return "To Do";
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
function updateTaskBodyStatusLine(body, status) {
|
|
759
|
+
const desiredLine = `**Status**: ${formatTaskStatusLabel(status)}`;
|
|
760
|
+
if (/^\*\*Status\*\*:/m.test(body)) {
|
|
761
|
+
return body.replace(/^\*\*Status\*\*:\s*.*$/m, desiredLine);
|
|
762
|
+
}
|
|
763
|
+
const afterSprint = body.match(/^\*\*Sprint\*\*:\s*.*$/m);
|
|
764
|
+
if (afterSprint?.index !== void 0) {
|
|
765
|
+
const insertAt = afterSprint.index + afterSprint[0].length;
|
|
766
|
+
return `${body.slice(0, insertAt)}
|
|
767
|
+
${desiredLine}${body.slice(insertAt)}`;
|
|
768
|
+
}
|
|
769
|
+
return `${desiredLine}
|
|
770
|
+
|
|
771
|
+
${body}`;
|
|
772
|
+
}
|
|
773
|
+
function normalizeDescriptionSectionContent(description) {
|
|
774
|
+
const trimmed = description.trim();
|
|
775
|
+
const headingMatch = trimmed.match(/^##\s+Description\b[^\n]*\n?/i);
|
|
776
|
+
if (!headingMatch) return trimmed;
|
|
777
|
+
return trimmed.slice(headingMatch[0].length).trim();
|
|
778
|
+
}
|
|
779
|
+
function isTaskHeaderMetadataLine(line) {
|
|
780
|
+
const trimmed = line.trim();
|
|
781
|
+
return /^#\s+Task:/i.test(trimmed) || /^\*\*(?:Sprint|Status|Estimated|Plan Artifact|Plan Stage)\*\*:/i.test(trimmed);
|
|
782
|
+
}
|
|
783
|
+
function keepTaskHeaderMetadata(prefix) {
|
|
784
|
+
const lines = prefix.split("\n");
|
|
785
|
+
let lastMetadataLineIndex = -1;
|
|
786
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
787
|
+
if (isTaskHeaderMetadataLine(lines[index] ?? "")) {
|
|
788
|
+
lastMetadataLineIndex = index;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
if (lastMetadataLineIndex < 0) return "";
|
|
792
|
+
return lines.slice(0, lastMetadataLineIndex + 1).join("\n").trimEnd();
|
|
793
|
+
}
|
|
794
|
+
function updateTaskBodyDescriptionSection(body, description) {
|
|
795
|
+
const content = normalizeDescriptionSectionContent(description);
|
|
796
|
+
const section = `## Description
|
|
797
|
+
|
|
798
|
+
${content}`;
|
|
799
|
+
const existingHeading = body.match(/^##\s+Description\b[^\n]*$/im);
|
|
800
|
+
if (existingHeading?.index !== void 0) {
|
|
801
|
+
const headingStart = existingHeading.index;
|
|
802
|
+
const afterHeading = headingStart + existingHeading[0].length;
|
|
803
|
+
const nextSectionRelative = body.slice(afterHeading).search(/\n##\s+/);
|
|
804
|
+
const sectionEnd = nextSectionRelative >= 0 ? afterHeading + nextSectionRelative : body.length;
|
|
805
|
+
const before = body.slice(0, headingStart).trimEnd();
|
|
806
|
+
const after = body.slice(sectionEnd).trimStart();
|
|
807
|
+
return `${before}
|
|
808
|
+
|
|
809
|
+
${section}${after ? `
|
|
810
|
+
|
|
811
|
+
${after}` : ""}`.trim();
|
|
812
|
+
}
|
|
813
|
+
const insertBefore = body.search(
|
|
814
|
+
/^##\s+(?:Subtasks|Checklist|Notes|Activity|Acceptance Criteria)\b/im
|
|
815
|
+
);
|
|
816
|
+
if (insertBefore >= 0) {
|
|
817
|
+
const before = keepTaskHeaderMetadata(body.slice(0, insertBefore));
|
|
818
|
+
const after = body.slice(insertBefore).trimStart();
|
|
819
|
+
return `${before ? `${before}
|
|
820
|
+
|
|
821
|
+
` : ""}${section}
|
|
822
|
+
|
|
823
|
+
${after}`.trim();
|
|
824
|
+
}
|
|
825
|
+
const existingMetadata = keepTaskHeaderMetadata(body);
|
|
826
|
+
if (!existingMetadata) return `${section}
|
|
827
|
+
`;
|
|
828
|
+
return `${existingMetadata}
|
|
829
|
+
|
|
830
|
+
${section}`;
|
|
831
|
+
}
|
|
832
|
+
async function updateTaskFields(taskId, updates) {
|
|
833
|
+
const planningRoot = getPlanningRoot();
|
|
834
|
+
if (updates.description !== void 0 && updates.body !== void 0) {
|
|
835
|
+
throw new Error("Cannot update both description and body in one operation");
|
|
836
|
+
}
|
|
837
|
+
if (updates.body !== void 0 && updates.body.trim().length === 0) {
|
|
838
|
+
throw new Error("Task body cannot be empty");
|
|
839
|
+
}
|
|
840
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
841
|
+
const lookup = await getTask(taskId, { includeArchive: false });
|
|
842
|
+
const { frontMatter, body } = await readMarkdownFile(lookup.filePath);
|
|
843
|
+
const nextFrontMatter = {
|
|
844
|
+
...frontMatter,
|
|
845
|
+
...lookup.yaml
|
|
846
|
+
};
|
|
847
|
+
if (updates.title !== void 0) {
|
|
848
|
+
const title = updates.title.trim();
|
|
849
|
+
if (!title) throw new Error("Task title cannot be empty");
|
|
850
|
+
nextFrontMatter.title = title;
|
|
851
|
+
}
|
|
852
|
+
if (updates.priority !== void 0) {
|
|
853
|
+
nextFrontMatter.priority = updates.priority;
|
|
854
|
+
}
|
|
855
|
+
if (updates.estimatedHours !== void 0) {
|
|
856
|
+
nextFrontMatter.estimatedHours = updates.estimatedHours;
|
|
857
|
+
}
|
|
858
|
+
if (updates.expectedRuntimeMinutes !== void 0) {
|
|
859
|
+
nextFrontMatter.expectedRuntimeMinutes = updates.expectedRuntimeMinutes;
|
|
860
|
+
}
|
|
861
|
+
if (updates.assignee !== void 0) {
|
|
862
|
+
const assignee = updates.assignee?.trim() ?? "";
|
|
863
|
+
if (assignee) {
|
|
864
|
+
nextFrontMatter.assignee = assignee;
|
|
865
|
+
} else {
|
|
866
|
+
delete nextFrontMatter.assignee;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
nextFrontMatter.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
870
|
+
nextFrontMatter.version = (lookup.yaml.version ?? 0) + 1;
|
|
871
|
+
const updatedTask = coerceTaskYAML(nextFrontMatter);
|
|
872
|
+
const nextBody = updates.body !== void 0 ? updates.body.trim() : updates.description !== void 0 ? updateTaskBodyDescriptionSection(body, updates.description) : body;
|
|
873
|
+
await writeMarkdownFile(
|
|
874
|
+
lookup.filePath,
|
|
875
|
+
nextFrontMatter,
|
|
876
|
+
updateTaskBodyStatusLine(nextBody, updatedTask.status)
|
|
877
|
+
);
|
|
878
|
+
return updatedTask;
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
async function updateTaskStatus(taskId, newStatus, options = {}) {
|
|
882
|
+
const planningRoot = getPlanningRoot();
|
|
883
|
+
const bypassReasonPre = options.bypassValidation?.reason.trim();
|
|
884
|
+
let contractEval;
|
|
885
|
+
if (newStatus === "done" && !bypassReasonPre) {
|
|
886
|
+
const preEval = await readTaskForCompletionEval(taskId, planningRoot);
|
|
887
|
+
if (preEval.task.status !== "done" && (preEval.task.completionContract?.length ?? 0) > 0) {
|
|
888
|
+
const evaluatedVersion = preEval.task.version;
|
|
889
|
+
const contractKey = completionContractSnapshotKey(preEval.task.completionContract);
|
|
890
|
+
await assertCompletionContractsMet({
|
|
891
|
+
contracts: preEval.task.completionContract,
|
|
892
|
+
bypassReason: bypassReasonPre,
|
|
893
|
+
workingDir: options.completionContractRoot
|
|
894
|
+
});
|
|
895
|
+
contractEval = { evaluatedVersion, contractKey };
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
899
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
900
|
+
const files = await listMarkdownFiles(tasksDir);
|
|
901
|
+
const taskFile = files.find((f) => path.basename(f) === `${taskId}.md`);
|
|
902
|
+
if (!taskFile) {
|
|
903
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
904
|
+
}
|
|
905
|
+
const { frontMatter, body } = await readMarkdownFile(taskFile);
|
|
906
|
+
const task = coerceTaskYAML(frontMatter);
|
|
907
|
+
const currentVersion = task.version;
|
|
908
|
+
if (options.expectedVersion !== void 0 && currentVersion !== options.expectedVersion) {
|
|
909
|
+
throw new StaleVersionError(currentVersion, options.expectedVersion, taskId);
|
|
910
|
+
}
|
|
911
|
+
if (task.status === newStatus && newStatus !== "blocked") {
|
|
912
|
+
if (options?.resultArtifactPath && task.resultArtifactPath !== options.resultArtifactPath) {
|
|
913
|
+
task.resultArtifactPath = options.resultArtifactPath;
|
|
914
|
+
task.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
915
|
+
task.version = currentVersion + 1;
|
|
916
|
+
await writeMarkdownFile(
|
|
917
|
+
taskFile,
|
|
918
|
+
task,
|
|
919
|
+
updateTaskBodyStatusLine(body, task.status)
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
return task;
|
|
923
|
+
}
|
|
924
|
+
const bypass = options.bypassValidation;
|
|
925
|
+
const bypassReason = bypass?.reason.trim();
|
|
926
|
+
if (bypass && !bypassReason) {
|
|
927
|
+
throw new Error("Task status validation bypass requires a reason");
|
|
928
|
+
}
|
|
929
|
+
if (!bypass) {
|
|
930
|
+
const transition = await validateStateTransition(
|
|
931
|
+
planningRoot,
|
|
932
|
+
taskId,
|
|
933
|
+
task.status,
|
|
934
|
+
newStatus
|
|
935
|
+
);
|
|
936
|
+
if (!transition.success) {
|
|
937
|
+
const details = transition.errors?.length ? `: ${transition.errors.join("; ")}` : "";
|
|
938
|
+
throw new Error(`${transition.message}${details}`);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
if (newStatus === "done") {
|
|
942
|
+
if (contractEval) {
|
|
943
|
+
if (currentVersion !== contractEval.evaluatedVersion || completionContractSnapshotKey(task.completionContract) !== contractEval.contractKey) {
|
|
944
|
+
throw new StaleVersionError(
|
|
945
|
+
currentVersion,
|
|
946
|
+
contractEval.evaluatedVersion,
|
|
947
|
+
taskId,
|
|
948
|
+
"completionContract",
|
|
949
|
+
"concurrent task mutation between completion-contract evaluation and status write"
|
|
950
|
+
);
|
|
951
|
+
}
|
|
952
|
+
} else {
|
|
953
|
+
await assertCompletionContractsMet({
|
|
954
|
+
contracts: task.completionContract,
|
|
955
|
+
bypassReason,
|
|
956
|
+
workingDir: options.completionContractRoot
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
const previousStatus = task.status;
|
|
961
|
+
task.status = newStatus;
|
|
962
|
+
task.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
963
|
+
task.version = currentVersion + 1;
|
|
964
|
+
if (bypass && bypassReason) {
|
|
965
|
+
task.statusBypassAudit = [
|
|
966
|
+
...task.statusBypassAudit ?? [],
|
|
967
|
+
{
|
|
968
|
+
at: task.updated_at,
|
|
969
|
+
fromStatus: previousStatus,
|
|
970
|
+
toStatus: newStatus,
|
|
971
|
+
reason: bypassReason,
|
|
972
|
+
...bypass.actor ? { actor: bypass.actor } : {}
|
|
973
|
+
}
|
|
974
|
+
];
|
|
975
|
+
}
|
|
976
|
+
if (previousStatus === "blocked" && newStatus === "blocked" && task.blockedReason && options?.blockedReason && task.blockedReason !== options.blockedReason) {
|
|
977
|
+
task.blockedReasonHistory = [...task.blockedReasonHistory ?? [], task.blockedReason];
|
|
978
|
+
}
|
|
979
|
+
if (newStatus === "blocked" && options?.blockedReason) {
|
|
980
|
+
task.blockedReason = options.blockedReason;
|
|
981
|
+
} else if (newStatus !== "blocked") {
|
|
982
|
+
task.blockedReason = void 0;
|
|
983
|
+
}
|
|
984
|
+
if (newStatus === "in_progress" && !task.started_at) {
|
|
985
|
+
task.started_at = task.updated_at;
|
|
986
|
+
}
|
|
987
|
+
if (newStatus === "done") {
|
|
988
|
+
task.completed_at = task.updated_at;
|
|
989
|
+
} else if (previousStatus === "done") {
|
|
990
|
+
task.completed_at = void 0;
|
|
991
|
+
}
|
|
992
|
+
if (previousStatus === "cancelled" && newStatus !== "cancelled") {
|
|
993
|
+
task.cancelledAt = void 0;
|
|
994
|
+
task.cancelledReason = void 0;
|
|
995
|
+
}
|
|
996
|
+
if (options?.resultArtifactPath) {
|
|
997
|
+
task.resultArtifactPath = options.resultArtifactPath;
|
|
998
|
+
}
|
|
999
|
+
await writeMarkdownFile(
|
|
1000
|
+
taskFile,
|
|
1001
|
+
task,
|
|
1002
|
+
updateTaskBodyStatusLine(body, task.status)
|
|
1003
|
+
);
|
|
1004
|
+
if (newStatus === "done") {
|
|
1005
|
+
const unblockedTaskIds = await autoUnblockDependentTasks(task.id, planningRoot);
|
|
1006
|
+
if (unblockedTaskIds.length > 0) {
|
|
1007
|
+
options.onDependentsUnblocked?.(unblockedTaskIds);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
if (task.sprintId) {
|
|
1011
|
+
try {
|
|
1012
|
+
const { refreshSprintMarkdown } = await import("./sprint-manager-IDQUDNQI.js");
|
|
1013
|
+
await refreshSprintMarkdown(task.sprintId);
|
|
1014
|
+
} catch (refreshError) {
|
|
1015
|
+
const msg = refreshError instanceof Error ? refreshError.message : String(refreshError);
|
|
1016
|
+
emitTaskManagerWarning("Failed to refresh sprint markdown after task status change", {
|
|
1017
|
+
sprintId: task.sprintId,
|
|
1018
|
+
taskId: task.id,
|
|
1019
|
+
error: msg
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
return task;
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
async function updateTaskStatusWithTransitionValidation(taskId, newStatus, options) {
|
|
1027
|
+
const { isArchived } = await getTask(taskId, {
|
|
1028
|
+
includeArchive: true
|
|
1029
|
+
});
|
|
1030
|
+
if (isArchived) {
|
|
1031
|
+
throw new Error(
|
|
1032
|
+
`Cannot update archived task "${taskId}". Reopen or restore the task before changing status.`
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
1035
|
+
return updateTaskStatus(taskId, newStatus, options);
|
|
1036
|
+
}
|
|
1037
|
+
async function addTaskDependency(taskId, dependsOnTaskId) {
|
|
1038
|
+
const planningRoot = getPlanningRoot();
|
|
1039
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1040
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1041
|
+
const files = await listMarkdownFiles(tasksDir);
|
|
1042
|
+
const taskFile = files.find((f) => path.basename(f) === `${taskId}.md`);
|
|
1043
|
+
if (!taskFile) {
|
|
1044
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1045
|
+
}
|
|
1046
|
+
const { frontMatter, body } = await readMarkdownFile(taskFile);
|
|
1047
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1048
|
+
if (task.dependencies.includes(dependsOnTaskId)) {
|
|
1049
|
+
throw new Error(`Dependency already exists: ${taskId} \u2192 ${dependsOnTaskId}`);
|
|
1050
|
+
}
|
|
1051
|
+
if (task.id === dependsOnTaskId) {
|
|
1052
|
+
throw new Error(`Task cannot depend on itself: ${taskId}`);
|
|
1053
|
+
}
|
|
1054
|
+
const taskPath = getBucketPathByKind("task", planningRoot);
|
|
1055
|
+
const taskArchivePath = getBucketArchivePathByKind("task", planningRoot);
|
|
1056
|
+
const allItems = await loadAllItems(planningRoot, [taskPath, taskArchivePath]);
|
|
1057
|
+
const dependencyExists = allItems.some((item) => item.id === dependsOnTaskId);
|
|
1058
|
+
if (!dependencyExists) {
|
|
1059
|
+
throw new Error(`Dependency task not found: ${dependsOnTaskId}`);
|
|
1060
|
+
}
|
|
1061
|
+
const createsCycle = hasDependencyPath(dependsOnTaskId, task.id, allItems);
|
|
1062
|
+
if (createsCycle) {
|
|
1063
|
+
throw new Error(
|
|
1064
|
+
`Circular dependency detected: adding ${task.id} -> ${dependsOnTaskId} would create a cycle`
|
|
1065
|
+
);
|
|
1066
|
+
}
|
|
1067
|
+
task.dependencies.push(dependsOnTaskId);
|
|
1068
|
+
task.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1069
|
+
task.version = task.version + 1;
|
|
1070
|
+
await writeMarkdownFile(
|
|
1071
|
+
taskFile,
|
|
1072
|
+
task,
|
|
1073
|
+
body
|
|
1074
|
+
);
|
|
1075
|
+
return task;
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
async function removeTaskDependency(taskId, dependsOnTaskId) {
|
|
1079
|
+
const planningRoot = getPlanningRoot();
|
|
1080
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1081
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1082
|
+
const files = await listMarkdownFiles(tasksDir);
|
|
1083
|
+
const taskFile = files.find((f) => path.basename(f) === `${taskId}.md`);
|
|
1084
|
+
if (!taskFile) {
|
|
1085
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1086
|
+
}
|
|
1087
|
+
const { frontMatter, body } = await readMarkdownFile(taskFile);
|
|
1088
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1089
|
+
if (!task.dependencies.includes(dependsOnTaskId)) {
|
|
1090
|
+
throw new Error(`Dependency not found on task: ${taskId} \u2192 ${dependsOnTaskId}`);
|
|
1091
|
+
}
|
|
1092
|
+
task.dependencies = task.dependencies.filter((id) => id !== dependsOnTaskId);
|
|
1093
|
+
task.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1094
|
+
task.version += 1;
|
|
1095
|
+
await writeMarkdownFile(
|
|
1096
|
+
taskFile,
|
|
1097
|
+
task,
|
|
1098
|
+
body
|
|
1099
|
+
);
|
|
1100
|
+
return task;
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
function hasDependencyPath(startTaskId, targetTaskId, allItems, visited = /* @__PURE__ */ new Set()) {
|
|
1104
|
+
if (startTaskId === targetTaskId) {
|
|
1105
|
+
return true;
|
|
1106
|
+
}
|
|
1107
|
+
if (visited.has(startTaskId)) {
|
|
1108
|
+
return false;
|
|
1109
|
+
}
|
|
1110
|
+
visited.add(startTaskId);
|
|
1111
|
+
const task = allItems.find((item) => item.id === startTaskId);
|
|
1112
|
+
const dependencies = task?.frontMatter.dependencies;
|
|
1113
|
+
if (!Array.isArray(dependencies) || dependencies.length === 0) {
|
|
1114
|
+
return false;
|
|
1115
|
+
}
|
|
1116
|
+
for (const depId of dependencies) {
|
|
1117
|
+
if (hasDependencyPath(depId, targetTaskId, allItems, visited)) {
|
|
1118
|
+
return true;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
return false;
|
|
1122
|
+
}
|
|
1123
|
+
async function autoUnblockDependentTasks(completedTaskId, planningRoot) {
|
|
1124
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1125
|
+
const files = await listMarkdownFiles(tasksDir);
|
|
1126
|
+
const unblockedTaskIds = [];
|
|
1127
|
+
const rewrites = [];
|
|
1128
|
+
for (const filePath of files) {
|
|
1129
|
+
try {
|
|
1130
|
+
const { frontMatter, body } = await readMarkdownFile(filePath);
|
|
1131
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1132
|
+
if (task.id === completedTaskId) continue;
|
|
1133
|
+
if (task.status !== "blocked") continue;
|
|
1134
|
+
if (!task.dependencies.includes(completedTaskId)) continue;
|
|
1135
|
+
let hasRemainingBlockers = false;
|
|
1136
|
+
for (const depId of task.dependencies) {
|
|
1137
|
+
const dep = await getTaskDependency(depId, { sprintId: task.sprintId });
|
|
1138
|
+
if (dep.missing || !dep.satisfied) {
|
|
1139
|
+
hasRemainingBlockers = true;
|
|
1140
|
+
break;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
if (hasRemainingBlockers) continue;
|
|
1144
|
+
task.status = "todo";
|
|
1145
|
+
task.blockedReason = void 0;
|
|
1146
|
+
task.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1147
|
+
task.version = task.version + 1;
|
|
1148
|
+
rewrites.push({
|
|
1149
|
+
filePath,
|
|
1150
|
+
originalFrontMatter: frontMatter,
|
|
1151
|
+
originalBody: body,
|
|
1152
|
+
nextFrontMatter: task,
|
|
1153
|
+
nextBody: updateTaskBodyStatusLine(body, task.status),
|
|
1154
|
+
taskId: task.id
|
|
1155
|
+
});
|
|
1156
|
+
} catch {
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
const applied = [];
|
|
1160
|
+
for (const rewrite of rewrites) {
|
|
1161
|
+
try {
|
|
1162
|
+
await writeMarkdownFile(rewrite.filePath, rewrite.nextFrontMatter, rewrite.nextBody);
|
|
1163
|
+
applied.push(rewrite);
|
|
1164
|
+
unblockedTaskIds.push(rewrite.taskId);
|
|
1165
|
+
} catch (error) {
|
|
1166
|
+
for (const previous of applied.reverse()) {
|
|
1167
|
+
await writeMarkdownFile(
|
|
1168
|
+
previous.filePath,
|
|
1169
|
+
previous.originalFrontMatter,
|
|
1170
|
+
previous.originalBody
|
|
1171
|
+
).catch(() => void 0);
|
|
1172
|
+
}
|
|
1173
|
+
throw error;
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
return unblockedTaskIds;
|
|
1177
|
+
}
|
|
1178
|
+
async function validateTaskExecution(taskId, options = {}) {
|
|
1179
|
+
const { includeArchive = false } = options;
|
|
1180
|
+
const { yaml: task } = await getTask(taskId, { includeArchive });
|
|
1181
|
+
const blockers = [];
|
|
1182
|
+
if (task.status === "blocked") {
|
|
1183
|
+
blockers.push(`${taskId} (blocked)`);
|
|
1184
|
+
}
|
|
1185
|
+
for (const depId of task.dependencies) {
|
|
1186
|
+
const dep = await getTaskDependency(depId, { sprintId: task.sprintId });
|
|
1187
|
+
if (dep.missing) {
|
|
1188
|
+
blockers.push(`${depId} (not found)`);
|
|
1189
|
+
continue;
|
|
1190
|
+
}
|
|
1191
|
+
if (!dep.satisfied) {
|
|
1192
|
+
blockers.push(`${depId} (status: ${dep.task?.status ?? "unknown"})`);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
return {
|
|
1196
|
+
canExecute: blockers.length === 0,
|
|
1197
|
+
blockers
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
async function logTaskTime(taskId, hours) {
|
|
1201
|
+
const planningRoot = getPlanningRoot();
|
|
1202
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1203
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1204
|
+
const files = await listMarkdownFiles(tasksDir);
|
|
1205
|
+
const taskFile = files.find((f) => path.basename(f) === `${taskId}.md`);
|
|
1206
|
+
if (!taskFile) {
|
|
1207
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1208
|
+
}
|
|
1209
|
+
const { frontMatter, body } = await readMarkdownFile(taskFile);
|
|
1210
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1211
|
+
task.timeLoggedHours += hours;
|
|
1212
|
+
task.version = task.version + 1;
|
|
1213
|
+
task.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1214
|
+
await writeMarkdownFile(
|
|
1215
|
+
taskFile,
|
|
1216
|
+
task,
|
|
1217
|
+
body
|
|
1218
|
+
);
|
|
1219
|
+
return task;
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
function deriveTransitionIdentity(input) {
|
|
1223
|
+
if (input.transitionId) {
|
|
1224
|
+
return crypto.createHash("sha256").update(`id\0${input.transitionId}`).digest("hex");
|
|
1225
|
+
}
|
|
1226
|
+
const payload = [
|
|
1227
|
+
"content",
|
|
1228
|
+
input.taskId,
|
|
1229
|
+
input.targetStatus,
|
|
1230
|
+
input.hoursLogged && input.hoursLogged > 0 ? String(input.hoursLogged) : "0",
|
|
1231
|
+
input.resultArtifactPath ?? ""
|
|
1232
|
+
].join("\0");
|
|
1233
|
+
return crypto.createHash("sha256").update(payload).digest("hex");
|
|
1234
|
+
}
|
|
1235
|
+
async function applyTaskTransitionOutcome(taskId, input) {
|
|
1236
|
+
const planningRoot = getPlanningRoot();
|
|
1237
|
+
const { isArchived } = await getTask(taskId, { includeArchive: true });
|
|
1238
|
+
if (isArchived) {
|
|
1239
|
+
throw new Error(
|
|
1240
|
+
`Cannot update archived task "${taskId}". Reopen or restore the task before changing status.`
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
1243
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1244
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1245
|
+
const files = await listMarkdownFiles(tasksDir);
|
|
1246
|
+
const taskFile = files.find((f) => path.basename(f) === `${taskId}.md`);
|
|
1247
|
+
if (!taskFile) {
|
|
1248
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1249
|
+
}
|
|
1250
|
+
const { frontMatter, body } = await readMarkdownFile(taskFile);
|
|
1251
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1252
|
+
const constituents = input.constituents && input.constituents.length > 0 ? input.constituents : [
|
|
1253
|
+
{
|
|
1254
|
+
identity: deriveTransitionIdentity({
|
|
1255
|
+
taskId,
|
|
1256
|
+
targetStatus: input.targetStatus,
|
|
1257
|
+
hoursLogged: input.hoursLogged,
|
|
1258
|
+
resultArtifactPath: input.resultArtifactPath
|
|
1259
|
+
}),
|
|
1260
|
+
hoursLogged: input.hoursLogged
|
|
1261
|
+
}
|
|
1262
|
+
];
|
|
1263
|
+
const recordedSet = new Set(task.appliedTransitions ?? []);
|
|
1264
|
+
const pendingHourIdentities = [];
|
|
1265
|
+
const seenThisCall = /* @__PURE__ */ new Set();
|
|
1266
|
+
let pendingHours = 0;
|
|
1267
|
+
for (const c of constituents) {
|
|
1268
|
+
if (recordedSet.has(c.identity) || seenThisCall.has(c.identity)) continue;
|
|
1269
|
+
seenThisCall.add(c.identity);
|
|
1270
|
+
pendingHourIdentities.push(c.identity);
|
|
1271
|
+
if (c.hoursLogged && c.hoursLogged > 0) {
|
|
1272
|
+
pendingHours += c.hoursLogged;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
const hoursPending = pendingHours > 0;
|
|
1276
|
+
const statusChanged = task.status !== input.targetStatus;
|
|
1277
|
+
const artifactChanged = Boolean(
|
|
1278
|
+
input.resultArtifactPath && task.resultArtifactPath !== input.resultArtifactPath
|
|
1279
|
+
);
|
|
1280
|
+
const reason = input.reason?.trim();
|
|
1281
|
+
const reasonChanged = Boolean(reason && task.lastTransitionReason !== reason);
|
|
1282
|
+
if (!statusChanged && !artifactChanged && !reasonChanged && !hoursPending) {
|
|
1283
|
+
return { task, statusChanged: false, fileUpdated: false, hoursApplied: 0 };
|
|
1284
|
+
}
|
|
1285
|
+
if (statusChanged) {
|
|
1286
|
+
const transition = await validateStateTransition(
|
|
1287
|
+
planningRoot,
|
|
1288
|
+
taskId,
|
|
1289
|
+
task.status,
|
|
1290
|
+
input.targetStatus
|
|
1291
|
+
);
|
|
1292
|
+
if (!transition.success) {
|
|
1293
|
+
const details = transition.errors?.length ? `: ${transition.errors.join("; ")}` : "";
|
|
1294
|
+
throw new Error(`${transition.message}${details}`);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
if (statusChanged && input.targetStatus === "done") {
|
|
1298
|
+
await assertCompletionContractsMet({
|
|
1299
|
+
contracts: task.completionContract
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1303
|
+
const previousStatus = task.status;
|
|
1304
|
+
if (statusChanged) {
|
|
1305
|
+
task.status = input.targetStatus;
|
|
1306
|
+
if (input.targetStatus === "in_progress" && !task.started_at) {
|
|
1307
|
+
task.started_at = now;
|
|
1308
|
+
}
|
|
1309
|
+
if (input.targetStatus === "done") {
|
|
1310
|
+
task.completed_at = now;
|
|
1311
|
+
} else if (previousStatus === "done") {
|
|
1312
|
+
task.completed_at = void 0;
|
|
1313
|
+
}
|
|
1314
|
+
if (input.targetStatus !== "blocked") {
|
|
1315
|
+
task.blockedReason = void 0;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
if (artifactChanged && input.resultArtifactPath) {
|
|
1319
|
+
task.resultArtifactPath = input.resultArtifactPath;
|
|
1320
|
+
}
|
|
1321
|
+
if (reasonChanged && reason) {
|
|
1322
|
+
task.lastTransitionReason = reason;
|
|
1323
|
+
}
|
|
1324
|
+
let hoursApplied = 0;
|
|
1325
|
+
if (hoursPending) {
|
|
1326
|
+
task.timeLoggedHours += pendingHours;
|
|
1327
|
+
hoursApplied = pendingHours;
|
|
1328
|
+
const next = task.appliedTransitions ? [...task.appliedTransitions] : [];
|
|
1329
|
+
for (const id of pendingHourIdentities) {
|
|
1330
|
+
next.push(id);
|
|
1331
|
+
}
|
|
1332
|
+
task.appliedTransitions = next;
|
|
1333
|
+
}
|
|
1334
|
+
task.version = task.version + 1;
|
|
1335
|
+
task.updated_at = now;
|
|
1336
|
+
await writeMarkdownFile(
|
|
1337
|
+
taskFile,
|
|
1338
|
+
task,
|
|
1339
|
+
updateTaskBodyStatusLine(body, task.status)
|
|
1340
|
+
);
|
|
1341
|
+
if (statusChanged && input.targetStatus === "done") {
|
|
1342
|
+
await autoUnblockDependentTasks(task.id, planningRoot).catch((error) => {
|
|
1343
|
+
emitTaskManagerWarning("Failed to auto-unblock dependent tasks after transition", {
|
|
1344
|
+
taskId: task.id,
|
|
1345
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1346
|
+
});
|
|
1347
|
+
});
|
|
1348
|
+
}
|
|
1349
|
+
if (task.sprintId) {
|
|
1350
|
+
try {
|
|
1351
|
+
const { refreshSprintMarkdown } = await import("./sprint-manager-IDQUDNQI.js");
|
|
1352
|
+
await refreshSprintMarkdown(task.sprintId);
|
|
1353
|
+
} catch (refreshError) {
|
|
1354
|
+
const msg = refreshError instanceof Error ? refreshError.message : String(refreshError);
|
|
1355
|
+
emitTaskManagerWarning("Failed to refresh sprint markdown after task transition", {
|
|
1356
|
+
sprintId: task.sprintId,
|
|
1357
|
+
taskId: task.id,
|
|
1358
|
+
error: msg
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
return { task, statusChanged, fileUpdated: true, hoursApplied };
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1365
|
+
async function findArchivedDuplicate(taskId, planningRoot) {
|
|
1366
|
+
const archiveDir = getBucketArchivePathByKind("task", planningRoot);
|
|
1367
|
+
return findArchivedTaskFile(archiveDir, taskId);
|
|
1368
|
+
}
|
|
1369
|
+
async function readTaskForCompletionEval(taskId, planningRoot) {
|
|
1370
|
+
const currentDir = getBucketPathByKind("task", planningRoot);
|
|
1371
|
+
const files = await listMarkdownFiles(currentDir);
|
|
1372
|
+
const taskFile = files.find((f) => path.basename(f) === `${taskId}.md`);
|
|
1373
|
+
if (!taskFile) {
|
|
1374
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1375
|
+
}
|
|
1376
|
+
const { frontMatter } = await readMarkdownFile(taskFile);
|
|
1377
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1378
|
+
return { task };
|
|
1379
|
+
}
|
|
1380
|
+
function completionContractSnapshotKey(contracts) {
|
|
1381
|
+
if (!contracts || contracts.length === 0) return "";
|
|
1382
|
+
return JSON.stringify(contracts);
|
|
1383
|
+
}
|
|
1384
|
+
async function completeTask(taskId, options = {}) {
|
|
1385
|
+
const planningRoot = getPlanningRoot();
|
|
1386
|
+
const forceCompletion = options.force ?? false;
|
|
1387
|
+
const bypass = options.bypassValidation;
|
|
1388
|
+
const bypassReason = bypass?.reason.trim();
|
|
1389
|
+
if (bypass && !bypassReason) {
|
|
1390
|
+
throw new Error("Task status validation bypass requires a reason");
|
|
1391
|
+
}
|
|
1392
|
+
const preEval = await readTaskForCompletionEval(taskId, planningRoot);
|
|
1393
|
+
const preEvalArchivedDuplicate = await findArchivedDuplicate(taskId, planningRoot);
|
|
1394
|
+
if (preEvalArchivedDuplicate) {
|
|
1395
|
+
throw new Error(
|
|
1396
|
+
`Task ${taskId} has both active and archived records. Completion is blocked to avoid overwriting managed state. Run poetic doctor for details; do not edit managed files manually.`
|
|
1397
|
+
);
|
|
1398
|
+
}
|
|
1399
|
+
if (!forceCompletion && (preEval.task.status === "blocked" || preEval.task.status === "cancelled")) {
|
|
1400
|
+
throw new Error(
|
|
1401
|
+
`Cannot complete task ${preEval.task.id} from status "${preEval.task.status}" without --force. Move it to in_progress/review first.`
|
|
1402
|
+
);
|
|
1403
|
+
}
|
|
1404
|
+
const evaluatedVersion = preEval.task.version;
|
|
1405
|
+
const evaluatedContractKey = completionContractSnapshotKey(preEval.task.completionContract);
|
|
1406
|
+
await assertCompletionContractsMet({
|
|
1407
|
+
contracts: preEval.task.completionContract,
|
|
1408
|
+
bypassReason,
|
|
1409
|
+
workingDir: options.completionContractRoot
|
|
1410
|
+
});
|
|
1411
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1412
|
+
const bucket = getBucketByName("task", planningRoot);
|
|
1413
|
+
if (!bucket) {
|
|
1414
|
+
throw new Error("Bucket not configured: task");
|
|
1415
|
+
}
|
|
1416
|
+
const currentDir = getBucketPathByKind("task", planningRoot);
|
|
1417
|
+
const files = await listMarkdownFiles(currentDir);
|
|
1418
|
+
const taskFile = files.find((f) => path.basename(f) === `${taskId}.md`);
|
|
1419
|
+
if (!taskFile) {
|
|
1420
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1421
|
+
}
|
|
1422
|
+
const archivedDuplicate = await findArchivedDuplicate(taskId, planningRoot);
|
|
1423
|
+
if (archivedDuplicate) {
|
|
1424
|
+
throw new Error(
|
|
1425
|
+
`Task ${taskId} has both active and archived records. Completion is blocked to avoid overwriting managed state. Run poetic doctor for details; do not edit managed files manually.`
|
|
1426
|
+
);
|
|
1427
|
+
}
|
|
1428
|
+
const { frontMatter, body } = await readMarkdownFile(taskFile);
|
|
1429
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1430
|
+
if (task.version !== evaluatedVersion || completionContractSnapshotKey(task.completionContract) !== evaluatedContractKey) {
|
|
1431
|
+
throw new StaleVersionError(
|
|
1432
|
+
task.version,
|
|
1433
|
+
evaluatedVersion,
|
|
1434
|
+
taskId,
|
|
1435
|
+
"completionContract",
|
|
1436
|
+
"concurrent task mutation between completion-contract evaluation and archive write"
|
|
1437
|
+
);
|
|
1438
|
+
}
|
|
1439
|
+
if (!forceCompletion && (task.status === "blocked" || task.status === "cancelled")) {
|
|
1440
|
+
throw new Error(
|
|
1441
|
+
`Cannot complete task ${task.id} from status "${task.status}" without --force. Move it to in_progress/review first.`
|
|
1442
|
+
);
|
|
1443
|
+
}
|
|
1444
|
+
if (task.status !== "done" && !(forceCompletion && (task.status === "blocked" || task.status === "cancelled")) && !bypass) {
|
|
1445
|
+
const transition = await validateStateTransition(planningRoot, taskId, task.status, "done");
|
|
1446
|
+
if (!transition.success) {
|
|
1447
|
+
const details = transition.errors?.length ? `: ${transition.errors.join("; ")}` : "";
|
|
1448
|
+
throw new Error(`${transition.message}${details}`);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1452
|
+
if (forceCompletion && task.status !== "done") {
|
|
1453
|
+
task.forceCompletedFrom = task.status;
|
|
1454
|
+
if (options.preserveBlockedReason && task.status === "blocked" && task.blockedReason) {
|
|
1455
|
+
task.originalBlockedReason = task.blockedReason;
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
const previousStatus = task.status;
|
|
1459
|
+
task.status = "done";
|
|
1460
|
+
task.version = task.version + 1;
|
|
1461
|
+
task.completed_at = now;
|
|
1462
|
+
task.updated_at = now;
|
|
1463
|
+
task.archivedAt = now;
|
|
1464
|
+
task.originalSprintId = task.sprintId;
|
|
1465
|
+
if (bypass && bypassReason) {
|
|
1466
|
+
task.statusBypassAudit = [
|
|
1467
|
+
...task.statusBypassAudit ?? [],
|
|
1468
|
+
{
|
|
1469
|
+
at: now,
|
|
1470
|
+
fromStatus: previousStatus,
|
|
1471
|
+
toStatus: "done",
|
|
1472
|
+
reason: bypassReason,
|
|
1473
|
+
...bypass.actor ? { actor: bypass.actor } : {}
|
|
1474
|
+
}
|
|
1475
|
+
];
|
|
1476
|
+
}
|
|
1477
|
+
const archivedPath = getArchivedFilePath(bucket, task.id, now, planningRoot);
|
|
1478
|
+
await ensureDirectoryExists(path.dirname(archivedPath));
|
|
1479
|
+
await writeMarkdownFile(archivedPath, toArchivedTaskFrontMatter(task), body);
|
|
1480
|
+
try {
|
|
1481
|
+
await detachArchivedTaskFromSprintMembership(task, "archiving");
|
|
1482
|
+
} catch (error) {
|
|
1483
|
+
await fs.unlink(archivedPath).catch(() => void 0);
|
|
1484
|
+
throw error;
|
|
1485
|
+
}
|
|
1486
|
+
const archiveDir = getBucketArchivePathByKind("task", planningRoot);
|
|
1487
|
+
const archivedIndex = archivedTaskIndexes.get(archiveDir);
|
|
1488
|
+
if (archivedIndex) {
|
|
1489
|
+
archivedIndex.set(task.id, archivedPath);
|
|
1490
|
+
}
|
|
1491
|
+
await fs.unlink(taskFile);
|
|
1492
|
+
const unblockedTaskIds = await autoUnblockDependentTasks(task.id, planningRoot).catch(
|
|
1493
|
+
(error) => {
|
|
1494
|
+
emitTaskManagerWarning("Failed to auto-unblock dependent tasks after completion", {
|
|
1495
|
+
taskId: task.id,
|
|
1496
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1497
|
+
});
|
|
1498
|
+
return [];
|
|
1499
|
+
}
|
|
1500
|
+
);
|
|
1501
|
+
return { task, archivedPath, unblockedTaskIds };
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
function toArchivedTaskFrontMatter(task) {
|
|
1505
|
+
const frontMatter = { ...task };
|
|
1506
|
+
delete frontMatter.sprintId;
|
|
1507
|
+
delete frontMatter.sprint_id;
|
|
1508
|
+
return frontMatter;
|
|
1509
|
+
}
|
|
1510
|
+
function getErrorCode(error) {
|
|
1511
|
+
if (!error || typeof error !== "object" || !("code" in error)) return void 0;
|
|
1512
|
+
const code = error.code;
|
|
1513
|
+
return typeof code === "string" ? code : void 0;
|
|
1514
|
+
}
|
|
1515
|
+
async function detachArchivedTaskFromSprintMembership(task, action) {
|
|
1516
|
+
if (!task.sprintId) return;
|
|
1517
|
+
try {
|
|
1518
|
+
const { detachArchivedTaskFromSprint } = await import("./sprint-manager-IDQUDNQI.js");
|
|
1519
|
+
await detachArchivedTaskFromSprint(task.sprintId, task.id, {
|
|
1520
|
+
completed: action === "archiving"
|
|
1521
|
+
});
|
|
1522
|
+
} catch (removeError) {
|
|
1523
|
+
if (getErrorCode(removeError) === "ENOENT") {
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
const removeMessage = removeError instanceof Error ? removeError.message : String(removeError);
|
|
1527
|
+
try {
|
|
1528
|
+
const { refreshSprintMarkdown } = await import("./sprint-manager-IDQUDNQI.js");
|
|
1529
|
+
await refreshSprintMarkdown(task.sprintId);
|
|
1530
|
+
} catch (refreshError) {
|
|
1531
|
+
emitTaskManagerWarning(`Failed to refresh sprint markdown after ${action} task`, {
|
|
1532
|
+
sprintId: task.sprintId,
|
|
1533
|
+
taskId: task.id,
|
|
1534
|
+
action,
|
|
1535
|
+
error: refreshError instanceof Error ? refreshError.message : String(refreshError)
|
|
1536
|
+
});
|
|
1537
|
+
}
|
|
1538
|
+
throw new Error(
|
|
1539
|
+
`Failed to remove task ${task.id} from sprint ${task.sprintId} after ${action}: ${removeMessage}`
|
|
1540
|
+
);
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
function getCancelledTaskArchivePath(taskId, cancelledAt, planningRoot) {
|
|
1544
|
+
const shard = getArchiveShard(cancelledAt);
|
|
1545
|
+
const taskBucket = getBucketPathByKind("task", planningRoot);
|
|
1546
|
+
const archiveRoot = getBucketArchivePathByKind("task", planningRoot);
|
|
1547
|
+
const extraSegments = path.relative(taskBucket, archiveRoot).split(path.sep).filter(Boolean);
|
|
1548
|
+
extraSegments.push("abandoned", shard.year, shard.month);
|
|
1549
|
+
return resolvePlanningItemPath(taskBucket, taskId, {
|
|
1550
|
+
label: "taskId",
|
|
1551
|
+
extraSegments
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1554
|
+
async function cancelTask(taskId, options) {
|
|
1555
|
+
const planningRoot = getPlanningRoot();
|
|
1556
|
+
const reason = options.reason.trim();
|
|
1557
|
+
if (!reason) {
|
|
1558
|
+
throw new Error("Cancellation reason is required");
|
|
1559
|
+
}
|
|
1560
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1561
|
+
const currentDir = getBucketPathByKind("task", planningRoot);
|
|
1562
|
+
const files = await listMarkdownFiles(currentDir);
|
|
1563
|
+
const taskFile = files.find((f) => path.basename(f) === `${taskId}.md`);
|
|
1564
|
+
if (!taskFile) {
|
|
1565
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1566
|
+
}
|
|
1567
|
+
const { frontMatter, body } = await readMarkdownFile(taskFile);
|
|
1568
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1569
|
+
if (options.expectedVersion !== void 0 && task.version !== options.expectedVersion) {
|
|
1570
|
+
throw new StaleVersionError(task.version, options.expectedVersion, taskId);
|
|
1571
|
+
}
|
|
1572
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1573
|
+
const bypass = options.bypassValidation;
|
|
1574
|
+
const bypassReason = bypass?.reason.trim();
|
|
1575
|
+
if (bypass && !bypassReason) {
|
|
1576
|
+
throw new Error("Task status validation bypass requires a reason");
|
|
1577
|
+
}
|
|
1578
|
+
if (!bypass) {
|
|
1579
|
+
const transition = await validateStateTransition(
|
|
1580
|
+
planningRoot,
|
|
1581
|
+
taskId,
|
|
1582
|
+
task.status,
|
|
1583
|
+
"cancelled"
|
|
1584
|
+
);
|
|
1585
|
+
if (!transition.success) {
|
|
1586
|
+
const details = transition.errors?.length ? `: ${transition.errors.join("; ")}` : "";
|
|
1587
|
+
throw new Error(`${transition.message}${details}`);
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
const previousStatus = task.status;
|
|
1591
|
+
task.status = "cancelled";
|
|
1592
|
+
task.version = task.version + 1;
|
|
1593
|
+
task.cancelledAt = now;
|
|
1594
|
+
task.cancelledReason = reason;
|
|
1595
|
+
task.updated_at = now;
|
|
1596
|
+
task.archivedAt = now;
|
|
1597
|
+
task.completed_at = void 0;
|
|
1598
|
+
task.originalSprintId = task.sprintId;
|
|
1599
|
+
if (bypass && bypassReason) {
|
|
1600
|
+
task.statusBypassAudit = [
|
|
1601
|
+
...task.statusBypassAudit ?? [],
|
|
1602
|
+
{
|
|
1603
|
+
at: now,
|
|
1604
|
+
fromStatus: previousStatus,
|
|
1605
|
+
toStatus: "cancelled",
|
|
1606
|
+
reason: bypassReason,
|
|
1607
|
+
...bypass.actor ? { actor: bypass.actor } : {}
|
|
1608
|
+
}
|
|
1609
|
+
];
|
|
1610
|
+
}
|
|
1611
|
+
const archivedPath = getCancelledTaskArchivePath(task.id, now, planningRoot);
|
|
1612
|
+
await ensureDirectoryExists(path.dirname(archivedPath));
|
|
1613
|
+
await writeMarkdownFile(archivedPath, toArchivedTaskFrontMatter(task), body);
|
|
1614
|
+
try {
|
|
1615
|
+
await detachArchivedTaskFromSprintMembership(task, "cancelling");
|
|
1616
|
+
} catch (error) {
|
|
1617
|
+
await fs.unlink(archivedPath).catch(() => void 0);
|
|
1618
|
+
throw error;
|
|
1619
|
+
}
|
|
1620
|
+
const archiveDir = getBucketArchivePathByKind("task", planningRoot);
|
|
1621
|
+
const archivedIndex = archivedTaskIndexes.get(archiveDir);
|
|
1622
|
+
if (archivedIndex) {
|
|
1623
|
+
archivedIndex.set(task.id, archivedPath);
|
|
1624
|
+
}
|
|
1625
|
+
await fs.unlink(taskFile);
|
|
1626
|
+
return { task, archivedPath };
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
async function restoreTask(taskId, options = {}) {
|
|
1630
|
+
const planningRoot = getPlanningRoot();
|
|
1631
|
+
const targetStatus = options.status ?? "in_progress";
|
|
1632
|
+
return withIndexRegeneration(planningRoot, async () => {
|
|
1633
|
+
const { filePath, isArchived } = await getTask(taskId, { includeArchive: true });
|
|
1634
|
+
const { frontMatter, body } = await readMarkdownFile(filePath);
|
|
1635
|
+
const task = coerceTaskYAML(frontMatter);
|
|
1636
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1637
|
+
let restoreIntoSprint = false;
|
|
1638
|
+
let sprintAlreadyMember = false;
|
|
1639
|
+
if (task.sprintId) {
|
|
1640
|
+
const { assertSprintCanAcceptRestoredTask } = await import("./sprint-manager-IDQUDNQI.js");
|
|
1641
|
+
const acceptance = await assertSprintCanAcceptRestoredTask(task.sprintId, task.id);
|
|
1642
|
+
if (acceptance.sprintExists) {
|
|
1643
|
+
restoreIntoSprint = true;
|
|
1644
|
+
sprintAlreadyMember = acceptance.alreadyMember;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
task.status = targetStatus;
|
|
1648
|
+
task.version = task.version + 1;
|
|
1649
|
+
task.updated_at = now;
|
|
1650
|
+
task.completed_at = void 0;
|
|
1651
|
+
delete task.archivedAt;
|
|
1652
|
+
delete task.cancelledAt;
|
|
1653
|
+
delete task.cancelledReason;
|
|
1654
|
+
delete task.originalSprintId;
|
|
1655
|
+
const restoredPath = resolvePlanningItemPath(
|
|
1656
|
+
getBucketPathByKind("task", planningRoot),
|
|
1657
|
+
taskId,
|
|
1658
|
+
{ label: "taskId" }
|
|
1659
|
+
);
|
|
1660
|
+
await ensureDirectoryExists(path.dirname(restoredPath));
|
|
1661
|
+
await writeMarkdownFile(
|
|
1662
|
+
restoredPath,
|
|
1663
|
+
task,
|
|
1664
|
+
body
|
|
1665
|
+
);
|
|
1666
|
+
try {
|
|
1667
|
+
if (restoreIntoSprint && task.sprintId) {
|
|
1668
|
+
const { addTaskToSprint, refreshSprintMarkdown, removeTaskFromSprint } = await import("./sprint-manager-IDQUDNQI.js");
|
|
1669
|
+
if (isArchived && !sprintAlreadyMember) {
|
|
1670
|
+
await addTaskToSprint(task.sprintId, task.id, task.estimatedHours);
|
|
1671
|
+
}
|
|
1672
|
+
try {
|
|
1673
|
+
await refreshSprintMarkdown(task.sprintId);
|
|
1674
|
+
} catch (refreshError) {
|
|
1675
|
+
if (isArchived && !sprintAlreadyMember) {
|
|
1676
|
+
await removeTaskFromSprint(task.sprintId, task.id).catch(() => void 0);
|
|
1677
|
+
}
|
|
1678
|
+
throw refreshError;
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
} catch (restoreError) {
|
|
1682
|
+
if (isArchived) {
|
|
1683
|
+
await fs.unlink(restoredPath).catch(() => void 0);
|
|
1684
|
+
}
|
|
1685
|
+
throw restoreError;
|
|
1686
|
+
}
|
|
1687
|
+
if (isArchived) {
|
|
1688
|
+
await fs.unlink(filePath);
|
|
1689
|
+
const archiveDir = getBucketArchivePathByKind("task", planningRoot);
|
|
1690
|
+
const archivedIndex = archivedTaskIndexes.get(archiveDir);
|
|
1691
|
+
archivedIndex?.delete(task.id);
|
|
1692
|
+
}
|
|
1693
|
+
return { task, restoredPath };
|
|
1694
|
+
});
|
|
1695
|
+
}
|
|
1696
|
+
var MAX_AMBIGUOUS_MATCH_PREVIEW = 5;
|
|
1697
|
+
function resolveTaskIdFromPrefix(candidateIds, query) {
|
|
1698
|
+
const uniqueIds = [...new Set(candidateIds)];
|
|
1699
|
+
const matches = uniqueIds.filter((id) => id === query || id.startsWith(query));
|
|
1700
|
+
if (matches.length === 0) {
|
|
1701
|
+
return null;
|
|
1702
|
+
}
|
|
1703
|
+
if (matches.length === 1) {
|
|
1704
|
+
return matches[0] ?? null;
|
|
1705
|
+
}
|
|
1706
|
+
const preview = matches.slice(0, MAX_AMBIGUOUS_MATCH_PREVIEW).join(", ");
|
|
1707
|
+
const suffix = matches.length > MAX_AMBIGUOUS_MATCH_PREVIEW ? ", ..." : "";
|
|
1708
|
+
throw new Error(
|
|
1709
|
+
`Ambiguous task ID prefix "${query}": matches ${matches.length} tasks (${preview}${suffix}). Use a longer prefix or the full ID.`
|
|
1710
|
+
);
|
|
1711
|
+
}
|
|
1712
|
+
async function loadTaskLookupFromFile(filePath, isArchived) {
|
|
1713
|
+
const { frontMatter } = await readMarkdownFile(filePath);
|
|
1714
|
+
return {
|
|
1715
|
+
yaml: coerceTaskYAML(frontMatter),
|
|
1716
|
+
filePath,
|
|
1717
|
+
isArchived
|
|
1718
|
+
};
|
|
1719
|
+
}
|
|
1720
|
+
async function collectKnownTaskIds(planningRoot, tasksDir, includeArchive) {
|
|
1721
|
+
const ids = [];
|
|
1722
|
+
const activeFiles = await listMarkdownFiles(tasksDir);
|
|
1723
|
+
for (const filePath of activeFiles) {
|
|
1724
|
+
const id = path.basename(filePath, ".md");
|
|
1725
|
+
if (id) {
|
|
1726
|
+
ids.push(id);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
if (includeArchive) {
|
|
1730
|
+
try {
|
|
1731
|
+
const archiveDir = getBucketArchivePathByKind("task", planningRoot);
|
|
1732
|
+
const index = await getArchivedTaskIndex(archiveDir);
|
|
1733
|
+
ids.push(...index.keys());
|
|
1734
|
+
} catch {
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
return ids;
|
|
1738
|
+
}
|
|
1739
|
+
async function getTask(taskId, options = {}) {
|
|
1740
|
+
const { includeArchive = false } = options;
|
|
1741
|
+
const planningRoot = getPlanningRoot();
|
|
1742
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1743
|
+
const activeTaskFile = resolvePlanningItemPath(tasksDir, taskId, { label: "taskId" });
|
|
1744
|
+
try {
|
|
1745
|
+
await fs.access(activeTaskFile);
|
|
1746
|
+
return loadTaskLookupFromFile(activeTaskFile, false);
|
|
1747
|
+
} catch (error) {
|
|
1748
|
+
if (error.code !== "ENOENT") {
|
|
1749
|
+
throw error;
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
if (includeArchive) {
|
|
1753
|
+
try {
|
|
1754
|
+
const archiveDir = getBucketArchivePathByKind("task", planningRoot);
|
|
1755
|
+
const archivedTaskFile = await findArchivedTaskFile(archiveDir, taskId);
|
|
1756
|
+
if (archivedTaskFile) {
|
|
1757
|
+
return loadTaskLookupFromFile(archivedTaskFile, true);
|
|
1758
|
+
}
|
|
1759
|
+
} catch (error) {
|
|
1760
|
+
if (getErrorCode(error) !== "ENOENT") {
|
|
1761
|
+
throw error;
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
const resolvedId = resolveTaskIdFromPrefix(
|
|
1766
|
+
await collectKnownTaskIds(planningRoot, tasksDir, includeArchive),
|
|
1767
|
+
taskId
|
|
1768
|
+
);
|
|
1769
|
+
if (resolvedId && resolvedId !== taskId) {
|
|
1770
|
+
return getTask(resolvedId, options);
|
|
1771
|
+
}
|
|
1772
|
+
throw new Error(`Task not found: ${taskId}`);
|
|
1773
|
+
}
|
|
1774
|
+
var archivedTaskIndexes = /* @__PURE__ */ new Map();
|
|
1775
|
+
function clearArchivedTaskIndex() {
|
|
1776
|
+
archivedTaskIndexes.clear();
|
|
1777
|
+
}
|
|
1778
|
+
async function buildArchivedTaskIndex(archiveDir) {
|
|
1779
|
+
const files = await listMarkdownFilesRecursiveStrict(archiveDir);
|
|
1780
|
+
const index = /* @__PURE__ */ new Map();
|
|
1781
|
+
for (const filePath of files) {
|
|
1782
|
+
const base = path.basename(filePath);
|
|
1783
|
+
if (!base.endsWith(".md")) continue;
|
|
1784
|
+
const id = base.slice(0, -3);
|
|
1785
|
+
if (!id) continue;
|
|
1786
|
+
index.set(id, filePath);
|
|
1787
|
+
}
|
|
1788
|
+
return index;
|
|
1789
|
+
}
|
|
1790
|
+
async function getArchivedTaskIndex(archiveDir) {
|
|
1791
|
+
let index = archivedTaskIndexes.get(archiveDir);
|
|
1792
|
+
if (!index) {
|
|
1793
|
+
index = await buildArchivedTaskIndex(archiveDir);
|
|
1794
|
+
archivedTaskIndexes.set(archiveDir, index);
|
|
1795
|
+
}
|
|
1796
|
+
return index;
|
|
1797
|
+
}
|
|
1798
|
+
async function findArchivedTaskFile(archiveDir, taskId) {
|
|
1799
|
+
if (isValidId(taskId)) {
|
|
1800
|
+
const index = await getArchivedTaskIndex(archiveDir);
|
|
1801
|
+
const directMatch = index.get(taskId);
|
|
1802
|
+
if (directMatch) {
|
|
1803
|
+
return directMatch;
|
|
1804
|
+
}
|
|
1805
|
+
const rebuiltIndex = await buildArchivedTaskIndex(archiveDir);
|
|
1806
|
+
archivedTaskIndexes.set(archiveDir, rebuiltIndex);
|
|
1807
|
+
return rebuiltIndex.get(taskId) ?? null;
|
|
1808
|
+
}
|
|
1809
|
+
const files = await listMarkdownFilesRecursiveStrict(archiveDir);
|
|
1810
|
+
return files.find((f) => path.basename(f) === `${taskId}.md`) ?? null;
|
|
1811
|
+
}
|
|
1812
|
+
async function getTaskAny(taskId) {
|
|
1813
|
+
return getTask(taskId, { includeArchive: true });
|
|
1814
|
+
}
|
|
1815
|
+
async function resolveTask(taskId) {
|
|
1816
|
+
return getTask(taskId, { includeArchive: true });
|
|
1817
|
+
}
|
|
1818
|
+
async function getTaskActive(taskId) {
|
|
1819
|
+
return getTask(taskId, { includeArchive: false });
|
|
1820
|
+
}
|
|
1821
|
+
async function getTaskDependency(depId, options = {}) {
|
|
1822
|
+
try {
|
|
1823
|
+
const result = await getTask(depId, { includeArchive: true });
|
|
1824
|
+
const classification = classifyTaskDependency(depId, {
|
|
1825
|
+
task: { status: result.yaml.status, isArchived: result.isArchived }
|
|
1826
|
+
});
|
|
1827
|
+
return {
|
|
1828
|
+
missing: classification.state === "missing",
|
|
1829
|
+
satisfied: classification.satisfied,
|
|
1830
|
+
isArchived: classification.isArchived,
|
|
1831
|
+
task: result.yaml
|
|
1832
|
+
};
|
|
1833
|
+
} catch {
|
|
1834
|
+
let recordedComplete = false;
|
|
1835
|
+
if (options.sprintId) {
|
|
1836
|
+
try {
|
|
1837
|
+
const { isTaskRecordedCompletedInSprint } = await import("./sprint-manager-IDQUDNQI.js");
|
|
1838
|
+
recordedComplete = await isTaskRecordedCompletedInSprint(options.sprintId, depId);
|
|
1839
|
+
} catch {
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
const classification = classifyTaskDependency(depId, {
|
|
1843
|
+
task: null,
|
|
1844
|
+
recordedComplete
|
|
1845
|
+
});
|
|
1846
|
+
return {
|
|
1847
|
+
missing: classification.state === "missing",
|
|
1848
|
+
satisfied: classification.satisfied,
|
|
1849
|
+
isArchived: classification.isArchived
|
|
1850
|
+
};
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
async function getAllTasks(options = {}) {
|
|
1854
|
+
const { includeArchive = false } = options;
|
|
1855
|
+
const planningRoot = getPlanningRoot();
|
|
1856
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1857
|
+
const results = [];
|
|
1858
|
+
const activeFiles = await listMarkdownFiles(tasksDir);
|
|
1859
|
+
for (const filePath of activeFiles) {
|
|
1860
|
+
try {
|
|
1861
|
+
const { frontMatter } = await readMarkdownFile(filePath);
|
|
1862
|
+
results.push({
|
|
1863
|
+
yaml: coerceTaskYAML(frontMatter),
|
|
1864
|
+
filePath,
|
|
1865
|
+
isArchived: false
|
|
1866
|
+
});
|
|
1867
|
+
} catch {
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
if (includeArchive) {
|
|
1871
|
+
try {
|
|
1872
|
+
const archiveDir = getBucketArchivePathByKind("task", planningRoot);
|
|
1873
|
+
const archiveFiles = await listMarkdownFilesRecursive(archiveDir);
|
|
1874
|
+
for (const filePath of archiveFiles) {
|
|
1875
|
+
try {
|
|
1876
|
+
const { frontMatter } = await readMarkdownFile(filePath);
|
|
1877
|
+
results.push({
|
|
1878
|
+
yaml: coerceTaskYAML(frontMatter),
|
|
1879
|
+
filePath,
|
|
1880
|
+
isArchived: true
|
|
1881
|
+
});
|
|
1882
|
+
} catch {
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
} catch {
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
return results;
|
|
1889
|
+
}
|
|
1890
|
+
async function listTasksLinkedToBacklogItem(backlogItemId, options = {}) {
|
|
1891
|
+
const { includeArchive = false } = options;
|
|
1892
|
+
const allTasks = await getAllTasks({ includeArchive });
|
|
1893
|
+
return allTasks.filter((result) => result.yaml.backlogItemId === backlogItemId).map((result) => ({
|
|
1894
|
+
id: result.yaml.id,
|
|
1895
|
+
title: result.yaml.title,
|
|
1896
|
+
status: result.yaml.status,
|
|
1897
|
+
sprintId: result.yaml.sprintId
|
|
1898
|
+
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
1899
|
+
}
|
|
1900
|
+
async function listTasksInSprint(sprintId, statusFilter) {
|
|
1901
|
+
try {
|
|
1902
|
+
const { listTasksInSprint: listSprintTaskRefs } = await import("./sprint-manager-IDQUDNQI.js");
|
|
1903
|
+
const sprintTasks = await listSprintTaskRefs(sprintId);
|
|
1904
|
+
const tasks2 = [];
|
|
1905
|
+
for (const sprintTask of sprintTasks) {
|
|
1906
|
+
if (sprintTask.missing === true) continue;
|
|
1907
|
+
try {
|
|
1908
|
+
const { yaml: task, isArchived } = await getTask(sprintTask.id, { includeArchive: true });
|
|
1909
|
+
if (isArchived) continue;
|
|
1910
|
+
if (!statusFilter || task.status === statusFilter) {
|
|
1911
|
+
tasks2.push(task);
|
|
1912
|
+
}
|
|
1913
|
+
} catch {
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
return tasks2;
|
|
1917
|
+
} catch (error) {
|
|
1918
|
+
const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
|
|
1919
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1920
|
+
if (code !== "ENOENT" && !message.includes(`Sprint not found: ${sprintId}`)) {
|
|
1921
|
+
throw error;
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
const planningRoot = getPlanningRoot();
|
|
1925
|
+
const tasksDir = getBucketPathByKind("task", planningRoot);
|
|
1926
|
+
const files = await listMarkdownFiles(tasksDir);
|
|
1927
|
+
const tasks = [];
|
|
1928
|
+
for (const file of files) {
|
|
1929
|
+
let task;
|
|
1930
|
+
try {
|
|
1931
|
+
const { frontMatter } = await readMarkdownFile(file);
|
|
1932
|
+
task = coerceTaskYAML(frontMatter);
|
|
1933
|
+
} catch {
|
|
1934
|
+
continue;
|
|
1935
|
+
}
|
|
1936
|
+
if (task.sprintId === sprintId) {
|
|
1937
|
+
if (!statusFilter || task.status === statusFilter) {
|
|
1938
|
+
tasks.push(task);
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
return tasks;
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
export {
|
|
1946
|
+
generateTaskId,
|
|
1947
|
+
createTask,
|
|
1948
|
+
createTaskWithGuidance,
|
|
1949
|
+
updateTaskFields,
|
|
1950
|
+
updateTaskStatus,
|
|
1951
|
+
updateTaskStatusWithTransitionValidation,
|
|
1952
|
+
addTaskDependency,
|
|
1953
|
+
removeTaskDependency,
|
|
1954
|
+
validateTaskExecution,
|
|
1955
|
+
logTaskTime,
|
|
1956
|
+
deriveTransitionIdentity,
|
|
1957
|
+
applyTaskTransitionOutcome,
|
|
1958
|
+
completeTask,
|
|
1959
|
+
cancelTask,
|
|
1960
|
+
restoreTask,
|
|
1961
|
+
resolveTaskIdFromPrefix,
|
|
1962
|
+
getTask,
|
|
1963
|
+
clearArchivedTaskIndex,
|
|
1964
|
+
getTaskAny,
|
|
1965
|
+
resolveTask,
|
|
1966
|
+
getTaskActive,
|
|
1967
|
+
getTaskDependency,
|
|
1968
|
+
getAllTasks,
|
|
1969
|
+
listTasksLinkedToBacklogItem,
|
|
1970
|
+
listTasksInSprint
|
|
1971
|
+
};
|
|
1972
|
+
//# sourceMappingURL=chunk-5LTN43AS.js.map
|