@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.
Files changed (782) hide show
  1. package/.github/SECURITY.md +47 -0
  2. package/.nvmrc +1 -0
  3. package/.poetic/README.md +37 -0
  4. package/.poetic/providers/catalog.json +12051 -0
  5. package/.poetic/providers/pricing.json +1272 -0
  6. package/.poetic/providers/registry.json +3369 -0
  7. package/CHANGELOG.md +552 -0
  8. package/CODE_OF_CONDUCT.md +40 -0
  9. package/CONTRIBUTING.md +23 -0
  10. package/INSTALL.md +454 -0
  11. package/LICENSE +21 -0
  12. package/README.md +474 -0
  13. package/dist/BasicOptimizationCompetitionRunner-5H5TBYO4.js +153 -0
  14. package/dist/ExecutionTracker-UVONC4C6.js +16 -0
  15. package/dist/OptimizationConfig-7DFY2TST.js +17 -0
  16. package/dist/OptimizationEngine-JIMGP3LY.js +1597 -0
  17. package/dist/PromptStore-U6ZD3ZMQ.js +18 -0
  18. package/dist/actions-LUJPINLJ.js +322 -0
  19. package/dist/agent-ingest-3DJUJ7FU.js +53 -0
  20. package/dist/aggregator-DNCBINFO.js +12 -0
  21. package/dist/ai-judge-5QT5QJVU.js +156 -0
  22. package/dist/allowlist-grounding-RO6HKUFI.js +16 -0
  23. package/dist/allowlist-utils-23V7TJ3G.js +28 -0
  24. package/dist/anchored-turn-service-JULUCUIK.js +489 -0
  25. package/dist/api-transport-4TYTNLTJ.js +1087 -0
  26. package/dist/apply-completion-mode-AW2MOS3R.js +89 -0
  27. package/dist/artifact-migrator-23L45ISD.js +267 -0
  28. package/dist/ask-HWVV6QFR.js +135 -0
  29. package/dist/auth-5KEDKAPP.js +67 -0
  30. package/dist/auth-7TT3JINV.js +78 -0
  31. package/dist/auth-E6XUNZ5M.js +68 -0
  32. package/dist/auth-H3XDZE22.js +134 -0
  33. package/dist/auth-OC4E6633.js +71 -0
  34. package/dist/auth-S4CTX4GQ.js +44 -0
  35. package/dist/auth-YLH3S7EY.js +69 -0
  36. package/dist/auth-liveness-TDDEZY3T.js +46 -0
  37. package/dist/auto-optimizer-VPRWOWGU.js +80 -0
  38. package/dist/autoloop-cleanup-JOGKTLWA.js +109 -0
  39. package/dist/autoloop-evidence-gates-PCDALGVJ.js +38 -0
  40. package/dist/autoloop-gate-policy-Z7FVJVXV.js +175 -0
  41. package/dist/autoloop-helpers-2KTK43GL.js +22 -0
  42. package/dist/autoloop-ledger-W7QO62PX.js +96 -0
  43. package/dist/autoloop-ledger-subscriber-Z5RW5EIE.js +162 -0
  44. package/dist/autoloop-run-defaults-FERGRZGP.js +19 -0
  45. package/dist/autoloop-run-lock-CT2NWSV3.js +197 -0
  46. package/dist/autoloop-success-J2VKKBXQ.js +85 -0
  47. package/dist/autoloop-termination-summary-RN75F422.js +58 -0
  48. package/dist/autoloop-trajectory-XFIEXP5Z.js +282 -0
  49. package/dist/autoloop-wall-clock-T7ZVIQOC.js +12 -0
  50. package/dist/autonomous-loop-controller-PW4XVFGQ.js +4120 -0
  51. package/dist/backend-P3DAYRP7.js +29 -0
  52. package/dist/background-executor-CBN552V4.js +257 -0
  53. package/dist/backlog-execution-intent-U4XYPTV6.js +15 -0
  54. package/dist/backup-active-store-5WXG6SXT.js +17 -0
  55. package/dist/backup-telemetry-db-XGLXAA3N.js +254 -0
  56. package/dist/basic-competition-master-VCSBJVRN.js +344 -0
  57. package/dist/branch-archive-manager-RP6FP3ZC.js +254 -0
  58. package/dist/branch-cleanup-manager-RSHAI7YR.js +20 -0
  59. package/dist/build-gate-YHGRB4QB.js +71 -0
  60. package/dist/change-summary-WY7J5TOX.js +33 -0
  61. package/dist/chunk-23A26CSN.js +123 -0
  62. package/dist/chunk-27UTJD3M.js +265 -0
  63. package/dist/chunk-2A5CILN3.js +310 -0
  64. package/dist/chunk-2AQUWJPW.js +225 -0
  65. package/dist/chunk-2BZ53J6J.js +2344 -0
  66. package/dist/chunk-2DY5KNVM.js +276 -0
  67. package/dist/chunk-2EIA4RBE.js +659 -0
  68. package/dist/chunk-2IUXIGQD.js +1064 -0
  69. package/dist/chunk-2N42MS2Z.js +2193 -0
  70. package/dist/chunk-2QJ3H3L7.js +42 -0
  71. package/dist/chunk-2QLYTVYX.js +791 -0
  72. package/dist/chunk-2VSQMRCB.js +18 -0
  73. package/dist/chunk-2XQXYBM2.js +130 -0
  74. package/dist/chunk-2YFUIER7.js +426 -0
  75. package/dist/chunk-34CNP2HB.js +148 -0
  76. package/dist/chunk-35P3W3JX.js +456 -0
  77. package/dist/chunk-36PEBZAF.js +18 -0
  78. package/dist/chunk-3AOKYKA7.js +22 -0
  79. package/dist/chunk-3BCUNHKF.js +475 -0
  80. package/dist/chunk-3FLXLLB7.js +26 -0
  81. package/dist/chunk-3FOZ2VHV.js +100 -0
  82. package/dist/chunk-3G6FZCRF.js +106 -0
  83. package/dist/chunk-3M57DADF.js +44 -0
  84. package/dist/chunk-3S62LLWJ.js +543 -0
  85. package/dist/chunk-3ZPQLGV7.js +2904 -0
  86. package/dist/chunk-44N5WZZH.js +45 -0
  87. package/dist/chunk-45FPSA3B.js +125 -0
  88. package/dist/chunk-4BJ3O4RQ.js +929 -0
  89. package/dist/chunk-4BOP7T6L.js +2321 -0
  90. package/dist/chunk-4BTDUT2S.js +42 -0
  91. package/dist/chunk-4CSS7WVI.js +143 -0
  92. package/dist/chunk-4CUY7AFY.js +247 -0
  93. package/dist/chunk-4GSN5O5J.js +62 -0
  94. package/dist/chunk-4HN6DF7V.js +1027 -0
  95. package/dist/chunk-4IAPOG5V.js +415 -0
  96. package/dist/chunk-4IYIZQWV.js +48 -0
  97. package/dist/chunk-4NXPXE62.js +84 -0
  98. package/dist/chunk-4RCCF5BR.js +712 -0
  99. package/dist/chunk-4V7NAQ4R.js +19527 -0
  100. package/dist/chunk-4VJITV4P.js +445 -0
  101. package/dist/chunk-4YX7J6QL.js +1859 -0
  102. package/dist/chunk-527OBWQB.js +338 -0
  103. package/dist/chunk-5D4A7E3D.js +448 -0
  104. package/dist/chunk-5DLKYTQX.js +4003 -0
  105. package/dist/chunk-5EERLVZB.js +139 -0
  106. package/dist/chunk-5H72XE4H.js +256 -0
  107. package/dist/chunk-5HDP7XZG.js +91 -0
  108. package/dist/chunk-5LAMRH4X.js +969 -0
  109. package/dist/chunk-5LTN43AS.js +1972 -0
  110. package/dist/chunk-5RBHQYDB.js +2206 -0
  111. package/dist/chunk-5WCQRDRB.js +588 -0
  112. package/dist/chunk-5WRLK5KW.js +700 -0
  113. package/dist/chunk-5ZCXC23G.js +595 -0
  114. package/dist/chunk-6BM72ZMG.js +31 -0
  115. package/dist/chunk-6EDAJH2I.js +68 -0
  116. package/dist/chunk-6EQKFDBH.js +457 -0
  117. package/dist/chunk-6MFRHTRI.js +115 -0
  118. package/dist/chunk-6TZJRKNW.js +321 -0
  119. package/dist/chunk-6V7HGQFZ.js +20 -0
  120. package/dist/chunk-6VWVO2TU.js +3746 -0
  121. package/dist/chunk-6Y5TWI7H.js +146 -0
  122. package/dist/chunk-6Y5U7UFY.js +91 -0
  123. package/dist/chunk-6ZLAK3XG.js +14 -0
  124. package/dist/chunk-72XCRQED.js +34 -0
  125. package/dist/chunk-72YTZMAM.js +589 -0
  126. package/dist/chunk-73BBJOKA.js +263 -0
  127. package/dist/chunk-73NCTWKL.js +188 -0
  128. package/dist/chunk-77I6G4CO.js +1 -0
  129. package/dist/chunk-7DHRDWFS.js +3104 -0
  130. package/dist/chunk-7DNSNKJV.js +78 -0
  131. package/dist/chunk-7FMJVYBS.js +307 -0
  132. package/dist/chunk-7GDRQBQC.js +419 -0
  133. package/dist/chunk-7GPCEFUV.js +270 -0
  134. package/dist/chunk-7IL4A2PP.js +948 -0
  135. package/dist/chunk-7MMLMXO6.js +3679 -0
  136. package/dist/chunk-7QCZSLBH.js +1 -0
  137. package/dist/chunk-7R2WLDOS.js +62 -0
  138. package/dist/chunk-7T7RUJI7.js +949 -0
  139. package/dist/chunk-A2WKSVX7.js +43 -0
  140. package/dist/chunk-A3YGID55.js +133 -0
  141. package/dist/chunk-A722DEVA.js +14 -0
  142. package/dist/chunk-ACDIT7OP.js +1376 -0
  143. package/dist/chunk-ACKIPAOJ.js +302 -0
  144. package/dist/chunk-APPNGGN7.js +365 -0
  145. package/dist/chunk-APV6MK5E.js +137 -0
  146. package/dist/chunk-ASEP3M2W.js +968 -0
  147. package/dist/chunk-AT4TNPWW.js +2931 -0
  148. package/dist/chunk-ATVKCSGT.js +250 -0
  149. package/dist/chunk-AURFMVCD.js +899 -0
  150. package/dist/chunk-AX6GWE7V.js +47 -0
  151. package/dist/chunk-AY5EWJPF.js +385 -0
  152. package/dist/chunk-BAV2HJXS.js +194 -0
  153. package/dist/chunk-BBHRN366.js +89 -0
  154. package/dist/chunk-BBPSTTPA.js +1004 -0
  155. package/dist/chunk-BDATUDDJ.js +992 -0
  156. package/dist/chunk-BKE5PG5L.js +20414 -0
  157. package/dist/chunk-BLPHWMDK.js +797 -0
  158. package/dist/chunk-BSE4R6XD.js +322 -0
  159. package/dist/chunk-BXGMAU4A.js +396 -0
  160. package/dist/chunk-BXI4NXL3.js +507 -0
  161. package/dist/chunk-BZU2O43F.js +1125 -0
  162. package/dist/chunk-C3L6YQ7P.js +147 -0
  163. package/dist/chunk-C57KJOUQ.js +121 -0
  164. package/dist/chunk-CCV7BPSY.js +118 -0
  165. package/dist/chunk-CD7ISXA4.js +826 -0
  166. package/dist/chunk-CE5OZBYY.js +21 -0
  167. package/dist/chunk-CFBIG37O.js +154 -0
  168. package/dist/chunk-CJC6GZ46.js +457 -0
  169. package/dist/chunk-CKCDGXIV.js +408 -0
  170. package/dist/chunk-CKNX3TTP.js +10338 -0
  171. package/dist/chunk-CLKSETWE.js +10 -0
  172. package/dist/chunk-CP7H3HSP.js +1552 -0
  173. package/dist/chunk-CPLEWXNZ.js +66 -0
  174. package/dist/chunk-CQM3A35X.js +844 -0
  175. package/dist/chunk-CS6P76D3.js +103 -0
  176. package/dist/chunk-CTLUBNCW.js +622 -0
  177. package/dist/chunk-CUSRN6RJ.js +632 -0
  178. package/dist/chunk-D5EP5D2W.js +26 -0
  179. package/dist/chunk-D5RYINO7.js +412 -0
  180. package/dist/chunk-DBFS4HMH.js +751 -0
  181. package/dist/chunk-DC4ZYMXJ.js +115 -0
  182. package/dist/chunk-DCBZP442.js +9243 -0
  183. package/dist/chunk-DCYF7EKG.js +26 -0
  184. package/dist/chunk-DDMAFNUK.js +5351 -0
  185. package/dist/chunk-DF5SLDE4.js +966 -0
  186. package/dist/chunk-DJFW7SMX.js +348 -0
  187. package/dist/chunk-DQFLLBJW.js +121 -0
  188. package/dist/chunk-DSFM56OA.js +1203 -0
  189. package/dist/chunk-DTY4APYV.js +218 -0
  190. package/dist/chunk-DXH5JBRS.js +437 -0
  191. package/dist/chunk-E3NTPHEO.js +194 -0
  192. package/dist/chunk-E74LUIID.js +302 -0
  193. package/dist/chunk-EI57M5BI.js +194 -0
  194. package/dist/chunk-EJ4ZAWLV.js +305 -0
  195. package/dist/chunk-EJGCZGUF.js +1483 -0
  196. package/dist/chunk-EK2U3YEG.js +486 -0
  197. package/dist/chunk-ELMFYNV7.js +109 -0
  198. package/dist/chunk-ENRGKNR5.js +25 -0
  199. package/dist/chunk-ETYDXCK7.js +679 -0
  200. package/dist/chunk-EYRH3W74.js +239 -0
  201. package/dist/chunk-F23DIWNN.js +1024 -0
  202. package/dist/chunk-F5JO7HAS.js +94 -0
  203. package/dist/chunk-F7ER6ANO.js +174 -0
  204. package/dist/chunk-FATUVIIN.js +374 -0
  205. package/dist/chunk-FC23CTXV.js +322 -0
  206. package/dist/chunk-FD4ERYEG.js +22 -0
  207. package/dist/chunk-FH7WOJAE.js +79 -0
  208. package/dist/chunk-FHOWVDF5.js +1342 -0
  209. package/dist/chunk-FKAUPHMR.js +96 -0
  210. package/dist/chunk-FONNFJXA.js +137 -0
  211. package/dist/chunk-FQ7FSZRW.js +75 -0
  212. package/dist/chunk-FRG57FPM.js +240 -0
  213. package/dist/chunk-FUVP64ER.js +31 -0
  214. package/dist/chunk-FYOILAN5.js +6818 -0
  215. package/dist/chunk-G35UYQ6Z.js +69 -0
  216. package/dist/chunk-G36W2T2S.js +1143 -0
  217. package/dist/chunk-G3L2L5XZ.js +49 -0
  218. package/dist/chunk-G4THLFV3.js +148 -0
  219. package/dist/chunk-GAFJEYLK.js +29 -0
  220. package/dist/chunk-GFGYB2ZU.js +1689 -0
  221. package/dist/chunk-GG6KJYW6.js +85 -0
  222. package/dist/chunk-GHHFDU2U.js +55 -0
  223. package/dist/chunk-GHTZSQB7.js +57 -0
  224. package/dist/chunk-GK37ILCX.js +1231 -0
  225. package/dist/chunk-GKN3HMN4.js +2809 -0
  226. package/dist/chunk-GNVDBVJP.js +156 -0
  227. package/dist/chunk-GPEL3FBM.js +924 -0
  228. package/dist/chunk-GPSNGPZS.js +1604 -0
  229. package/dist/chunk-GSGD5E4C.js +30 -0
  230. package/dist/chunk-GSUQJJXQ.js +331 -0
  231. package/dist/chunk-GSV226X6.js +110 -0
  232. package/dist/chunk-H2AYQIHW.js +224 -0
  233. package/dist/chunk-H66DXFS5.js +1374 -0
  234. package/dist/chunk-H6G7QRMQ.js +35 -0
  235. package/dist/chunk-H7JAGHZT.js +59 -0
  236. package/dist/chunk-H7ZEFECA.js +316 -0
  237. package/dist/chunk-HAC6EHZZ.js +79 -0
  238. package/dist/chunk-HIO33P3G.js +19 -0
  239. package/dist/chunk-HMVQIPH3.js +547 -0
  240. package/dist/chunk-HOYBYAOA.js +257 -0
  241. package/dist/chunk-HX5P3CSP.js +1784 -0
  242. package/dist/chunk-I46EG2XQ.js +65 -0
  243. package/dist/chunk-I4NPDSCB.js +279 -0
  244. package/dist/chunk-I5WRT7ZR.js +514 -0
  245. package/dist/chunk-IC7I6YIJ.js +301 -0
  246. package/dist/chunk-IDCSOZVN.js +78 -0
  247. package/dist/chunk-IFCBYECK.js +112 -0
  248. package/dist/chunk-IFZCPEY2.js +66 -0
  249. package/dist/chunk-IKFP2KUR.js +48 -0
  250. package/dist/chunk-IRFBN336.js +878 -0
  251. package/dist/chunk-IUXNGKA6.js +152 -0
  252. package/dist/chunk-IV2RVAN7.js +1356 -0
  253. package/dist/chunk-IZYIQQ7X.js +53 -0
  254. package/dist/chunk-J3UUR7DE.js +210 -0
  255. package/dist/chunk-J54VUAY2.js +566 -0
  256. package/dist/chunk-J62KPGII.js +464 -0
  257. package/dist/chunk-J6P3FWWW.js +130 -0
  258. package/dist/chunk-JKBHJQMT.js +434 -0
  259. package/dist/chunk-JLS65NUQ.js +14 -0
  260. package/dist/chunk-JOSYEJKY.js +141 -0
  261. package/dist/chunk-JPKSXKNB.js +94 -0
  262. package/dist/chunk-JQNJB2BB.js +2440 -0
  263. package/dist/chunk-JRVNSWSQ.js +2626 -0
  264. package/dist/chunk-JSWMRQYG.js +28 -0
  265. package/dist/chunk-JZKNBBIB.js +152 -0
  266. package/dist/chunk-K54Y7MLK.js +160 -0
  267. package/dist/chunk-K65546RE.js +183 -0
  268. package/dist/chunk-KM3F7SYE.js +702 -0
  269. package/dist/chunk-KNDYMVWN.js +102 -0
  270. package/dist/chunk-KNT72VR6.js +132 -0
  271. package/dist/chunk-KP6YILMU.js +482 -0
  272. package/dist/chunk-KQEBSK3T.js +274 -0
  273. package/dist/chunk-KT6VHSPF.js +84 -0
  274. package/dist/chunk-KTMW65UX.js +14 -0
  275. package/dist/chunk-KZ5CJVBP.js +1813 -0
  276. package/dist/chunk-L4427KOE.js +26 -0
  277. package/dist/chunk-L6OM4A22.js +189 -0
  278. package/dist/chunk-L7E6XCRA.js +1042 -0
  279. package/dist/chunk-L7JZLXQL.js +173 -0
  280. package/dist/chunk-LAMKBTXX.js +40 -0
  281. package/dist/chunk-LDCF2MKN.js +132 -0
  282. package/dist/chunk-LEIIWPWQ.js +78 -0
  283. package/dist/chunk-LFTQVYBB.js +31 -0
  284. package/dist/chunk-LG3PDRTR.js +2872 -0
  285. package/dist/chunk-LGHII5ET.js +23 -0
  286. package/dist/chunk-LH5QY22X.js +1205 -0
  287. package/dist/chunk-LIVJ6266.js +438 -0
  288. package/dist/chunk-LKRAR3IH.js +276 -0
  289. package/dist/chunk-LO23NABI.js +3063 -0
  290. package/dist/chunk-LO3X5NLS.js +326 -0
  291. package/dist/chunk-LPITVM7M.js +339 -0
  292. package/dist/chunk-LR5IJIGV.js +810 -0
  293. package/dist/chunk-LRGMHROI.js +79 -0
  294. package/dist/chunk-LUVKFFWR.js +315 -0
  295. package/dist/chunk-LWCBNGH6.js +35 -0
  296. package/dist/chunk-LWTN3WRV.js +260 -0
  297. package/dist/chunk-M3HQYKQX.js +308 -0
  298. package/dist/chunk-M6GVSPEH.js +1016 -0
  299. package/dist/chunk-MF5HP6XV.js +221 -0
  300. package/dist/chunk-MHLCBZJB.js +328 -0
  301. package/dist/chunk-MN6PL4AN.js +120 -0
  302. package/dist/chunk-MOEY65Z6.js +5678 -0
  303. package/dist/chunk-MQ4WA34C.js +206 -0
  304. package/dist/chunk-MWHF5V7U.js +223 -0
  305. package/dist/chunk-MWHLBPNU.js +211 -0
  306. package/dist/chunk-MWK5UZQ3.js +1068 -0
  307. package/dist/chunk-MYLH2S4G.js +64 -0
  308. package/dist/chunk-MZ5WYKNA.js +28 -0
  309. package/dist/chunk-N4VTRA7K.js +131 -0
  310. package/dist/chunk-N5DX4JAK.js +12 -0
  311. package/dist/chunk-N65O4XTH.js +5011 -0
  312. package/dist/chunk-NEQUQHOX.js +223 -0
  313. package/dist/chunk-NGK6PEOG.js +25 -0
  314. package/dist/chunk-NJVD4PWE.js +1033 -0
  315. package/dist/chunk-NM6PMYY4.js +768 -0
  316. package/dist/chunk-NN4PJDHP.js +708 -0
  317. package/dist/chunk-NP2V3L7K.js +226 -0
  318. package/dist/chunk-NRLY536M.js +260 -0
  319. package/dist/chunk-NRNE225N.js +1270 -0
  320. package/dist/chunk-NS2K2GTP.js +605 -0
  321. package/dist/chunk-NS33V3IM.js +51 -0
  322. package/dist/chunk-NSHASMZZ.js +71 -0
  323. package/dist/chunk-NWOYOA6H.js +378 -0
  324. package/dist/chunk-NWRUSEXG.js +322 -0
  325. package/dist/chunk-NZGDAWIP.js +1905 -0
  326. package/dist/chunk-O47UOKU3.js +395 -0
  327. package/dist/chunk-O4G2W3ST.js +9831 -0
  328. package/dist/chunk-O6V4PNLO.js +63 -0
  329. package/dist/chunk-OA4GPILI.js +624 -0
  330. package/dist/chunk-OGMSYL6J.js +227 -0
  331. package/dist/chunk-OIS7J26S.js +319 -0
  332. package/dist/chunk-OMX5VL43.js +79 -0
  333. package/dist/chunk-ON3G73BU.js +264 -0
  334. package/dist/chunk-OPYFYTWQ.js +220 -0
  335. package/dist/chunk-OQ6K46CK.js +1734 -0
  336. package/dist/chunk-OYZYO7TV.js +47 -0
  337. package/dist/chunk-OZ4REHIN.js +4386 -0
  338. package/dist/chunk-P47VN5F4.js +282 -0
  339. package/dist/chunk-P5I4X7A7.js +353 -0
  340. package/dist/chunk-P6VQROCO.js +594 -0
  341. package/dist/chunk-P7CQGPLS.js +30 -0
  342. package/dist/chunk-PCAGC5MR.js +1763 -0
  343. package/dist/chunk-PFTQBXS6.js +5181 -0
  344. package/dist/chunk-PGSPX4SU.js +15 -0
  345. package/dist/chunk-PIKLF7BM.js +432 -0
  346. package/dist/chunk-PJWJ3SAV.js +22 -0
  347. package/dist/chunk-PKIFMV72.js +100 -0
  348. package/dist/chunk-PL37JDNA.js +189 -0
  349. package/dist/chunk-PTH5E5XO.js +195 -0
  350. package/dist/chunk-PW6AXLQC.js +4128 -0
  351. package/dist/chunk-PYITM4N2.js +79 -0
  352. package/dist/chunk-PZ5AY32C.js +10 -0
  353. package/dist/chunk-Q3RO7N35.js +45 -0
  354. package/dist/chunk-Q3WIC6GQ.js +2670 -0
  355. package/dist/chunk-Q5XIXSHX.js +271 -0
  356. package/dist/chunk-QGJDMEOV.js +34 -0
  357. package/dist/chunk-QNOB37UH.js +58 -0
  358. package/dist/chunk-QOCOVLUH.js +462 -0
  359. package/dist/chunk-QTCJ5CC5.js +172 -0
  360. package/dist/chunk-QVFV5IP2.js +232 -0
  361. package/dist/chunk-QVZMFDYG.js +29 -0
  362. package/dist/chunk-R35PEUKH.js +511 -0
  363. package/dist/chunk-R4UWBC35.js +200 -0
  364. package/dist/chunk-R6MLCREW.js +44 -0
  365. package/dist/chunk-R6W23LKN.js +254 -0
  366. package/dist/chunk-R7XDDX2A.js +4007 -0
  367. package/dist/chunk-RDFRCT64.js +168 -0
  368. package/dist/chunk-RE5VZDFQ.js +58 -0
  369. package/dist/chunk-RGROYC2G.js +638 -0
  370. package/dist/chunk-RGWHUI5E.js +68 -0
  371. package/dist/chunk-RHVG6UNL.js +205 -0
  372. package/dist/chunk-RI4EX2QE.js +18 -0
  373. package/dist/chunk-RJAAKDRX.js +17 -0
  374. package/dist/chunk-ROMHOSMQ.js +185 -0
  375. package/dist/chunk-RWREC3KJ.js +517 -0
  376. package/dist/chunk-RYNETRDJ.js +118 -0
  377. package/dist/chunk-RZY7RKM5.js +500 -0
  378. package/dist/chunk-S2MNWFAG.js +52 -0
  379. package/dist/chunk-S2VQCZO4.js +22 -0
  380. package/dist/chunk-S54MKU6V.js +117 -0
  381. package/dist/chunk-S5OIDFRM.js +302 -0
  382. package/dist/chunk-SCW4ZF6R.js +150 -0
  383. package/dist/chunk-SLS2N4PH.js +2213 -0
  384. package/dist/chunk-SNLBO4BF.js +247 -0
  385. package/dist/chunk-SP3LFU6B.js +60 -0
  386. package/dist/chunk-SQQTDDQA.js +537 -0
  387. package/dist/chunk-STV6LYYE.js +45 -0
  388. package/dist/chunk-SURZ2WFE.js +326 -0
  389. package/dist/chunk-SZ7DL357.js +1047 -0
  390. package/dist/chunk-T5E4NQCM.js +5742 -0
  391. package/dist/chunk-TAJPCXSB.js +13 -0
  392. package/dist/chunk-TAOOYK3P.js +358 -0
  393. package/dist/chunk-TDSEX5CF.js +24 -0
  394. package/dist/chunk-TFTGP7Z7.js +174 -0
  395. package/dist/chunk-TGON4N4O.js +197 -0
  396. package/dist/chunk-TGQZHDY2.js +2373 -0
  397. package/dist/chunk-TJJZ2OKV.js +6783 -0
  398. package/dist/chunk-TRSVUPCX.js +25 -0
  399. package/dist/chunk-TSXGRLPR.js +107 -0
  400. package/dist/chunk-U2S3YEX3.js +224 -0
  401. package/dist/chunk-U45RTRGY.js +818 -0
  402. package/dist/chunk-U6C3VVWS.js +13 -0
  403. package/dist/chunk-UDMS5AD3.js +307 -0
  404. package/dist/chunk-UGX7GI37.js +94 -0
  405. package/dist/chunk-UH3JJSHK.js +1 -0
  406. package/dist/chunk-UHRBTZYY.js +208 -0
  407. package/dist/chunk-UHT2KRG5.js +193 -0
  408. package/dist/chunk-UI2F6DJ5.js +118 -0
  409. package/dist/chunk-UMAKSB4Z.js +284 -0
  410. package/dist/chunk-UR2IBGIM.js +521 -0
  411. package/dist/chunk-UUH2RVKS.js +585 -0
  412. package/dist/chunk-UVJ4PJDK.js +4533 -0
  413. package/dist/chunk-V53UG2OT.js +9924 -0
  414. package/dist/chunk-V72RMBM4.js +48 -0
  415. package/dist/chunk-VBNCKCCI.js +16 -0
  416. package/dist/chunk-VNSYKC25.js +24 -0
  417. package/dist/chunk-VPHVFK4A.js +1984 -0
  418. package/dist/chunk-VTLNJQ44.js +133 -0
  419. package/dist/chunk-VTW7HP3R.js +100 -0
  420. package/dist/chunk-VVGEPBPS.js +218 -0
  421. package/dist/chunk-VVLLL7I4.js +166 -0
  422. package/dist/chunk-VX3UMWB7.js +483 -0
  423. package/dist/chunk-VXF4Q3FW.js +20 -0
  424. package/dist/chunk-W3JMT2YY.js +712 -0
  425. package/dist/chunk-WDUORIHF.js +877 -0
  426. package/dist/chunk-WDVTY4U6.js +148 -0
  427. package/dist/chunk-WIFZCHEG.js +12566 -0
  428. package/dist/chunk-WIRN3F75.js +736 -0
  429. package/dist/chunk-WMPU2UOV.js +82 -0
  430. package/dist/chunk-WTOKKE2V.js +784 -0
  431. package/dist/chunk-WX5IRLF6.js +740 -0
  432. package/dist/chunk-WZ6U3O7I.js +1581 -0
  433. package/dist/chunk-XAONGNST.js +57 -0
  434. package/dist/chunk-XB5YLCLB.js +13 -0
  435. package/dist/chunk-XEP5NQ5Y.js +688 -0
  436. package/dist/chunk-XGYF2QMZ.js +351 -0
  437. package/dist/chunk-XHEKQENB.js +255 -0
  438. package/dist/chunk-XNO4FM6X.js +1124 -0
  439. package/dist/chunk-XPHKYHO4.js +878 -0
  440. package/dist/chunk-XPK2I4NC.js +405 -0
  441. package/dist/chunk-XPU2XADL.js +2175 -0
  442. package/dist/chunk-XQD2B6BB.js +507 -0
  443. package/dist/chunk-XT2ZQVTC.js +558 -0
  444. package/dist/chunk-XTXJGGUV.js +351 -0
  445. package/dist/chunk-XUXVDPSZ.js +50 -0
  446. package/dist/chunk-XV7NZL4B.js +57 -0
  447. package/dist/chunk-XZE4XARH.js +563 -0
  448. package/dist/chunk-XZYR5EDO.js +152 -0
  449. package/dist/chunk-Y3J4JMTU.js +61 -0
  450. package/dist/chunk-Y55LZN5U.js +52 -0
  451. package/dist/chunk-Y5VN7DMP.js +112 -0
  452. package/dist/chunk-Y67VAHN4.js +459 -0
  453. package/dist/chunk-YAXSKEUH.js +3544 -0
  454. package/dist/chunk-YB3JD4E6.js +975 -0
  455. package/dist/chunk-YESZJFK6.js +220 -0
  456. package/dist/chunk-YGXKOBQQ.js +292 -0
  457. package/dist/chunk-YMX76IOS.js +31 -0
  458. package/dist/chunk-YOTXESEH.js +257 -0
  459. package/dist/chunk-YTYIEZQY.js +119 -0
  460. package/dist/chunk-YVORHQ2S.js +579 -0
  461. package/dist/chunk-Z2CUQDAR.js +3429 -0
  462. package/dist/chunk-Z2KYOFHS.js +7000 -0
  463. package/dist/chunk-Z6PC7QX6.js +161 -0
  464. package/dist/chunk-ZDTGECTN.js +235 -0
  465. package/dist/chunk-ZIPWI2LY.js +151 -0
  466. package/dist/chunk-ZSKKMTQJ.js +554 -0
  467. package/dist/chunk-ZTT5IVPY.js +1160 -0
  468. package/dist/chunk-ZX65UI5W.js +78 -0
  469. package/dist/chunk-ZYG7GGKO.js +218 -0
  470. package/dist/chunk-ZZZUL4OF.js +38 -0
  471. package/dist/cli-utils-IXL26KJT.js +40 -0
  472. package/dist/cli-validation-WLXWLUJL.js +111 -0
  473. package/dist/commit-utils-P7CRJF5N.js +202 -0
  474. package/dist/compete-config-resolver-R5ULXMYH.js +76 -0
  475. package/dist/compete-request-62JESVET.js +364 -0
  476. package/dist/compete-results-QEPG6FZX.js +208 -0
  477. package/dist/competition-outcome-tracker-R32OOZ43.js +38 -0
  478. package/dist/config-JCOKXOQT.js +166 -0
  479. package/dist/config-audit-EL3GHXS7.js +360 -0
  480. package/dist/config-explain-TNILDEVJ.js +12 -0
  481. package/dist/config-loader-VPFPFO4B.js +38 -0
  482. package/dist/config-manager-7T4E2BQO.js +67 -0
  483. package/dist/config-validator-KKOHOW7O.js +72 -0
  484. package/dist/cost-YC42XUF3.js +53 -0
  485. package/dist/coverage-orchestrator-CISNKJC2.js +772 -0
  486. package/dist/coverage-scanner-YVD62MLH.js +12 -0
  487. package/dist/createCompetitionRunner-LJG6ZQSO.js +46 -0
  488. package/dist/data-migration-state-VJK64DLT.js +31 -0
  489. package/dist/db-migrator-XSEIOGWY.js +34 -0
  490. package/dist/discovery-JGYGDD25.js +25 -0
  491. package/dist/doctor-GJOYE7AE.js +186 -0
  492. package/dist/domain-analyzer-AWF3RP6E.js +29 -0
  493. package/dist/ensure-initialized-744DIZEZ.js +52 -0
  494. package/dist/entry.js +940 -0
  495. package/dist/environment-YS45U5ZI.js +81 -0
  496. package/dist/error-parser-core-PPZ36A4S.js +50 -0
  497. package/dist/escalation-ladder-MKTCEGSA.js +130 -0
  498. package/dist/evaluation-context-KV4GZNN7.js +35 -0
  499. package/dist/evidence-plan-resolver-GBSYSAPX.js +85 -0
  500. package/dist/execution-data-writer-3ODTBDLH.js +53 -0
  501. package/dist/execution-policy-applier-ZHD3DCF3.js +31 -0
  502. package/dist/execution-preflight-Z4Y64V3I.js +209 -0
  503. package/dist/execution-roles-R3DPPMD3.js +66 -0
  504. package/dist/exit-code-error-Z4SW2DVK.js +14 -0
  505. package/dist/external-temp-cleanup-N2RZH4QP.js +311 -0
  506. package/dist/factory-XBN7DFIM.js +149 -0
  507. package/dist/file-utils-XIVR2ZMA.js +47 -0
  508. package/dist/flywheel-autoloop-executor-UILGOFFK.js +249 -0
  509. package/dist/flywheel-competition-executor-JOBEXTRB.js +259 -0
  510. package/dist/flywheel-executor-6JFLA6J5.js +369 -0
  511. package/dist/flywheel-git-isolation-UC5NIEVU.js +48 -0
  512. package/dist/flywheel-manifest-5UC4VBMA.js +108 -0
  513. package/dist/flywheel-model-defaults-7CVKP53V.js +27 -0
  514. package/dist/flywheel-preflight-XEY5SHM6.js +104 -0
  515. package/dist/flywheel-resume-7HELH7QS.js +23 -0
  516. package/dist/flywheel-safety-7U7DPOAP.js +28 -0
  517. package/dist/flywheel-scope-decision-ZHKF6ZIN.js +11 -0
  518. package/dist/get-telemetry-logger-DPVWWIYY.js +73 -0
  519. package/dist/git-worktree-IY6V6DUO.js +18 -0
  520. package/dist/github-pr-manager-4LXEKJTA.js +211 -0
  521. package/dist/guidance-profile-config-E7XJL2VP.js +117 -0
  522. package/dist/guidance-profile-renderer-QK2YMAAP.js +21 -0
  523. package/dist/index-query-4JEUKA44.js +31 -0
  524. package/dist/index.js +108661 -0
  525. package/dist/instructions-6BURLQJC.js +64 -0
  526. package/dist/invoke-provider-auth-GRUYP44M.js +223 -0
  527. package/dist/judge-scoring.json +80 -0
  528. package/dist/judge-test.js +555 -0
  529. package/dist/lab-mode-OTWVHN63.js +39 -0
  530. package/dist/lab-utils-BJRFLGK4.js +23 -0
  531. package/dist/linux-host-class-UY4KVLFD.js +29 -0
  532. package/dist/llm-judge-executor-F7Z3HO77.js +133 -0
  533. package/dist/local-executor-CEHWE2PL.js +223 -0
  534. package/dist/logger-33TR6EE5.js +72 -0
  535. package/dist/loop-spec-XTLQAVZ7.js +191 -0
  536. package/dist/manager-2HJG5CLT.js +25 -0
  537. package/dist/matrix-prompt-builder-6UDN5X3F.js +497 -0
  538. package/dist/matrix-result-parser-7W35EUOV.js +15 -0
  539. package/dist/metadata-HQ43NDEK.js +22 -0
  540. package/dist/model-invocations-db-QBO4Y7WZ.js +38 -0
  541. package/dist/monitor-XGYBG2DW.js +72 -0
  542. package/dist/next-PB5ZXZKB.js +90 -0
  543. package/dist/next-ZBDK725T.js +69 -0
  544. package/dist/optimization-config-resolver-O6WKR47U.js +75 -0
  545. package/dist/package-3YCWIQQ5.js +10 -0
  546. package/dist/parallel-orchestrator-NL7YJJU2.js +297 -0
  547. package/dist/parallel-worker.js +279 -0
  548. package/dist/parse-git-status-PIAF3OTP.js +10 -0
  549. package/dist/path-security-ETTH6TZL.js +39 -0
  550. package/dist/pattern-bank-UNJR5ADV.js +15 -0
  551. package/dist/plan-backlog-list-fast-VAGYBV3J.js +270 -0
  552. package/dist/plan-backlog-show-fast-SG2CZPW3.js +406 -0
  553. package/dist/plan-sprint-list-fast-LURAX47V.js +162 -0
  554. package/dist/plan-sprint-status-fast-FJAODCHD.js +208 -0
  555. package/dist/plan-task-status-fast-HNYBMQI4.js +349 -0
  556. package/dist/plan-to-flywheel-Z4U3GWPN.js +456 -0
  557. package/dist/planning-backlog-3CQ5QQBQ.js +319 -0
  558. package/dist/poetic-root-V5DNXEAE.js +17 -0
  559. package/dist/preflight-OPANWMME.js +12 -0
  560. package/dist/process-registry-PDZJPTAS.js +27 -0
  561. package/dist/process-scanner-C22SYXYD.js +22 -0
  562. package/dist/processes-KMQUD7HY.js +29 -0
  563. package/dist/processes-json-fast-IBDXZ6WW.js +135 -0
  564. package/dist/profile-SE5EVXAP.js +149 -0
  565. package/dist/prompts-WZZPGWBX.js +168 -0
  566. package/dist/protected-branches-RNTEX7ET.js +57 -0
  567. package/dist/provider-aware-resource-manager-QBTZJMNP.js +18 -0
  568. package/dist/provider-matrix-N5X57V3Y.js +154 -0
  569. package/dist/provider-matrix-renderer-MZDWKKID.js +139 -0
  570. package/dist/provider-output-forwarding-DERID3TP.js +30 -0
  571. package/dist/provider-registry-J5NRBJKI.js +128 -0
  572. package/dist/provider-temp-cleanup-KYGLF6YU.js +14 -0
  573. package/dist/prune-engine-Q6E2DXBN.js +451 -0
  574. package/dist/quality-gate-YRHMQAEI.js +70 -0
  575. package/dist/quickstart-FIRLKGJI.js +62 -0
  576. package/dist/readiness-VZTMSG6J.js +96 -0
  577. package/dist/registry-YODFY77A.js +153 -0
  578. package/dist/repair-helpers-TTV5FEF4.js +117 -0
  579. package/dist/repo-root-2IGD4H7X.js +22 -0
  580. package/dist/resolution-engine-D6TX6FRG.js +127 -0
  581. package/dist/resolve-provider-cli-O2P6XZBZ.js +35 -0
  582. package/dist/restore-telemetry-db-BQL6DTQF.js +360 -0
  583. package/dist/result-streamer-WEHW476R.js +19 -0
  584. package/dist/routing-events-DHPUZDDF.js +27 -0
  585. package/dist/routing-history-store-UWCEXAP3.js +46 -0
  586. package/dist/routing-planner-F5WQEUOM.js +160 -0
  587. package/dist/run-poetic-tui-J6LWRJUP.js +13517 -0
  588. package/dist/run-simulation.js +376 -0
  589. package/dist/runner-CS2TNGHA.js +1092 -0
  590. package/dist/runner-HHH7ZN2Z.js +1571 -0
  591. package/dist/safety-OCC4KJJR.js +64 -0
  592. package/dist/safety-stanza-7SV3HGG3.js +60 -0
  593. package/dist/sandbox-32QXJEMV.js +81 -0
  594. package/dist/sandbox-RSO7VP6V.js +94 -0
  595. package/dist/schema-extensions.sql +234 -0
  596. package/dist/security-2KI5XNDG.js +17 -0
  597. package/dist/setup-bb-plugin-QAQWZCV5.js +738 -0
  598. package/dist/setup-claude-code-P7BTTSPO.js +317 -0
  599. package/dist/setup-temp-cleanup-GASCWZ2I.js +20 -0
  600. package/dist/shared-utils-D6U6UREP.js +37 -0
  601. package/dist/simple-artifact-goal-OTXNGZY6.js +25 -0
  602. package/dist/sprint-UIXPYOXQ.js +338 -0
  603. package/dist/sprint-bridge-4BHMSC3M.js +68 -0
  604. package/dist/sprint-execution-service-2B7WHL5L.js +311 -0
  605. package/dist/sprint-manager-IDQUDNQI.js +91 -0
  606. package/dist/sqlite-wrapper-UDWCTNLJ.js +17 -0
  607. package/dist/stale-cleanup-orchestrator-XWXV7KCZ.js +62 -0
  608. package/dist/storage-access-F6ALDN4S.js +22 -0
  609. package/dist/synthesis-XD6EDVHF.js +185 -0
  610. package/dist/task-classifier-LNLXSHOM.js +494 -0
  611. package/dist/task-list-fast-PTMA4LUC.js +147 -0
  612. package/dist/task-manager-XAT7GOWB.js +93 -0
  613. package/dist/task-splitter-U7DJ7W6A.js +79 -0
  614. package/dist/task-type-detector-OLVOMXZO.js +21 -0
  615. package/dist/task-type-resolver-KKNQYSB4.js +42 -0
  616. package/dist/telemetry-5HWBBXLX.js +131 -0
  617. package/dist/telemetry-health-tracker-DMSSGBZ2.js +11 -0
  618. package/dist/telemetry-path-resolver-7ICSG276.js +28 -0
  619. package/dist/telemetry-reliability-XUOZNZZ6.js +125 -0
  620. package/dist/token-estimator-MEQUL3EJ.js +37 -0
  621. package/dist/transports-KNSSV2V4.js +255 -0
  622. package/dist/unified-cost-tracker-4TFRBVPR.js +35 -0
  623. package/dist/unified-state-cleanup-LJPF2BOW.js +276 -0
  624. package/dist/universal-cost-calculator-BAJV35GA.js +42 -0
  625. package/dist/user-agents-GHUGCSKN.js +22 -0
  626. package/dist/variant-delivery-state-KLRNG6XA.js +33 -0
  627. package/dist/variant-state-cleanup-MZGGLQAJ.js +280 -0
  628. package/dist/variant-success-PJXWE3ZV.js +12 -0
  629. package/dist/variant-worker-KUWKBLAH.js +4196 -0
  630. package/dist/variant-worker.js +24 -0
  631. package/dist/variants-JE2FSAQS.js +233 -0
  632. package/dist/verification-toolchains-V24UHW6Q.js +28 -0
  633. package/dist/verify-commands-H3DTCSGI.js +37 -0
  634. package/dist/warning-EGQGUUIO.js +12 -0
  635. package/dist/work-edge-RWEDWJZF.js +49 -0
  636. package/dist/work-item-writer-WHAVZXAY.js +19 -0
  637. package/dist/worker-7SA2VS2Y.js +1435 -0
  638. package/dist/worker.js +19 -0
  639. package/dist/worktree-metrics-3DFUYVYE.js +26 -0
  640. package/dist/writeback-VZKHYHSN.js +44 -0
  641. package/docs/CLI_REFERENCE.md +7042 -0
  642. package/docs/PROVIDER_SETUP.md +1570 -0
  643. package/docs/README.md +96 -0
  644. package/docs/TROUBLESHOOTING.md +2232 -0
  645. package/docs/getting-started/QUICK_START.md +294 -0
  646. package/docs/getting-started/README.md +188 -0
  647. package/docs/getting-started/SETUP.md +52 -0
  648. package/docs/reference/AGENT_CONTEXT.md +38 -0
  649. package/docs/reference/PROVIDER_RELEASE_TIERS.md +34 -0
  650. package/docs/reference/README.md +381 -0
  651. package/docs/reference/SECURITY.md +262 -0
  652. package/integrations/bb-plugin-poetic/README.md +362 -0
  653. package/integrations/bb-plugin-poetic/app.css +341 -0
  654. package/integrations/bb-plugin-poetic/app.tsx +5059 -0
  655. package/integrations/bb-plugin-poetic/package.json +45 -0
  656. package/integrations/bb-plugin-poetic/server.ts +444 -0
  657. package/integrations/bb-plugin-poetic/src/adapter.ts +3312 -0
  658. package/integrations/bb-plugin-poetic/src/backlog-authoring-model.ts +150 -0
  659. package/integrations/bb-plugin-poetic/src/backlog-authoring-schema.ts +355 -0
  660. package/integrations/bb-plugin-poetic/src/backlog-authoring-service.ts +419 -0
  661. package/integrations/bb-plugin-poetic/src/backlog-authoring-view.ts +1026 -0
  662. package/integrations/bb-plugin-poetic/src/competition-defaults-schema.ts +122 -0
  663. package/integrations/bb-plugin-poetic/src/competition-defaults-service.ts +105 -0
  664. package/integrations/bb-plugin-poetic/src/competition-defaults-view.ts +138 -0
  665. package/integrations/bb-plugin-poetic/src/contract.ts +615 -0
  666. package/integrations/bb-plugin-poetic/src/finalize-model.ts +205 -0
  667. package/integrations/bb-plugin-poetic/src/finalize-schema.ts +158 -0
  668. package/integrations/bb-plugin-poetic/src/finalize-service.ts +382 -0
  669. package/integrations/bb-plugin-poetic/src/finalize-view.ts +159 -0
  670. package/integrations/bb-plugin-poetic/src/judge-operations-readback.ts +303 -0
  671. package/integrations/bb-plugin-poetic/src/judge-operations-schema.ts +33 -0
  672. package/integrations/bb-plugin-poetic/src/judge-operations-view.ts +459 -0
  673. package/integrations/bb-plugin-poetic/src/model.ts +1302 -0
  674. package/integrations/bb-plugin-poetic/src/monitor-service.ts +233 -0
  675. package/integrations/bb-plugin-poetic/src/panel-read-ux.ts +97 -0
  676. package/integrations/bb-plugin-poetic/src/patch-preview-schema.ts +166 -0
  677. package/integrations/bb-plugin-poetic/src/patch-preview-service.ts +480 -0
  678. package/integrations/bb-plugin-poetic/src/patch-preview-view.ts +109 -0
  679. package/integrations/bb-plugin-poetic/src/planning-readback.ts +204 -0
  680. package/integrations/bb-plugin-poetic/src/planning-service.ts +594 -0
  681. package/integrations/bb-plugin-poetic/src/planning-workspace-schema.ts +95 -0
  682. package/integrations/bb-plugin-poetic/src/planning-workspace.ts +323 -0
  683. package/integrations/bb-plugin-poetic/src/poll-handoff.ts +136 -0
  684. package/integrations/bb-plugin-poetic/src/project-target-server.ts +21 -0
  685. package/integrations/bb-plugin-poetic/src/project-target.ts +45 -0
  686. package/integrations/bb-plugin-poetic/src/reference-index.ts +192 -0
  687. package/integrations/bb-plugin-poetic/src/repository-schema.ts +30 -0
  688. package/integrations/bb-plugin-poetic/src/result-explorer-view.ts +597 -0
  689. package/integrations/bb-plugin-poetic/src/result-readback-model.ts +163 -0
  690. package/integrations/bb-plugin-poetic/src/result-readback-schema.ts +319 -0
  691. package/integrations/bb-plugin-poetic/src/result-readback-service.ts +333 -0
  692. package/integrations/bb-plugin-poetic/src/run-page-view.ts +177 -0
  693. package/integrations/bb-plugin-poetic/src/setup-config-schema.ts +291 -0
  694. package/integrations/bb-plugin-poetic/src/setup-config-service.ts +590 -0
  695. package/integrations/bb-plugin-poetic/src/setup-config-view.ts +413 -0
  696. package/integrations/bb-plugin-poetic/src/sprint-close-model.ts +150 -0
  697. package/integrations/bb-plugin-poetic/src/sprint-close-schema.ts +136 -0
  698. package/integrations/bb-plugin-poetic/src/sprint-close-service.ts +341 -0
  699. package/integrations/bb-plugin-poetic/src/sprint-close-view.ts +116 -0
  700. package/integrations/bb-plugin-poetic/src/sprint-composition-model.ts +714 -0
  701. package/integrations/bb-plugin-poetic/src/sprint-composition-readback.ts +231 -0
  702. package/integrations/bb-plugin-poetic/src/sprint-composition-schema.ts +601 -0
  703. package/integrations/bb-plugin-poetic/src/sprint-composition-service.ts +775 -0
  704. package/integrations/bb-plugin-poetic/src/sprint-composition-view.ts +1221 -0
  705. package/integrations/bb-plugin-poetic/src/task-authoring-model.ts +567 -0
  706. package/integrations/bb-plugin-poetic/src/task-authoring-schema.ts +635 -0
  707. package/integrations/bb-plugin-poetic/src/task-authoring-service.ts +842 -0
  708. package/integrations/bb-plugin-poetic/src/task-authoring-view.ts +1227 -0
  709. package/integrations/bb-plugin-poetic/src/task-detail-readback.ts +56 -0
  710. package/integrations/bb-plugin-poetic/src/task-detail-schema.ts +144 -0
  711. package/integrations/bb-plugin-poetic/src/task-navigation.ts +446 -0
  712. package/integrations/bb-plugin-poetic/src/workbench-route.ts +74 -0
  713. package/integrations/bb-plugin-poetic/tests/host-contract.test.ts +773 -0
  714. package/integrations/bb-plugin-poetic/tsconfig.json +18 -0
  715. package/integrations/bb-plugin-poetic/types/PROVENANCE.json +52 -0
  716. package/integrations/bb-plugin-poetic/types/bb-plugin-sdk-app.d.ts +1444 -0
  717. package/integrations/bb-plugin-poetic/types/bb-plugin-sdk.d.ts +13030 -0
  718. package/integrations/bb-plugin-poetic/vitest.host.config.ts +71 -0
  719. package/npm-shrinkwrap.json +4950 -0
  720. package/package.json +331 -0
  721. package/schemas/README.md +80 -0
  722. package/schemas/config-v1.schema.json +136 -0
  723. package/schemas/execution-config.schema.json +47 -0
  724. package/schemas/judge-scoring.schema.json +370 -0
  725. package/schemas/poetic.config.schema.json +2214 -0
  726. package/schemas/provider-config.schema.json +203 -0
  727. package/schemas/telemetry-config.schema.json +79 -0
  728. package/schemas/user-preferences.schema.json +141 -0
  729. package/scripts/assert-node-runtime.mjs +140 -0
  730. package/scripts/preflight-native.mjs +49 -0
  731. package/scripts/preinstall-node-check.mjs +78 -0
  732. package/scripts/setup-git-hooks.mjs +24 -0
  733. package/scripts/sync.sh +2722 -0
  734. package/scripts/write-node-launcher.sh +108 -0
  735. package/src/resources/gemini/slash-packs/default/plan.toml +15 -0
  736. package/src/resources/gemini/slash-packs/default/summary.toml +16 -0
  737. package/src/resources/gemini/slash-packs/default/tests.toml +16 -0
  738. package/templates/.poetic/README.md +37 -0
  739. package/templates/.poetic/agents/README.md +296 -0
  740. package/templates/.poetic/agents/api-documenter.md +147 -0
  741. package/templates/.poetic/agents/backend-architect.md +31 -0
  742. package/templates/.poetic/agents/code-reviewer.md +157 -0
  743. package/templates/.poetic/agents/data-scientist.md +179 -0
  744. package/templates/.poetic/agents/database-optimizer.md +145 -0
  745. package/templates/.poetic/agents/debugger.md +31 -0
  746. package/templates/.poetic/agents/deployment-engineer.md +164 -0
  747. package/templates/.poetic/agents/devops-troubleshooter.md +139 -0
  748. package/templates/.poetic/agents/frontend-developer.md +150 -0
  749. package/templates/.poetic/agents/javascript-pro.md +36 -0
  750. package/templates/.poetic/agents/performance-engineer.md +151 -0
  751. package/templates/.poetic/agents/python-pro.md +137 -0
  752. package/templates/.poetic/agents/test-automator.md +147 -0
  753. package/templates/.poetic/agents/typescript-pro.md +34 -0
  754. package/templates/.poetic/config/poetic.config.jsonc +69 -0
  755. package/templates/.poetic/config/project-context.template.json +6 -0
  756. package/templates/.poetic/config/task-type-aliases.presets/kanban.yaml +14 -0
  757. package/templates/.poetic/config/task-type-aliases.presets/scrum.yaml +17 -0
  758. package/templates/.poetic/config/task-type-aliases.presets/xp.yaml +12 -0
  759. package/templates/.poetic/config/task-type-aliases.yaml +28 -0
  760. package/templates/.poetic/gitignore.template +55 -0
  761. package/templates/.poetic/task-types/analysis.yaml +40 -0
  762. package/templates/.poetic/task-types/architecture.yaml +38 -0
  763. package/templates/.poetic/task-types/doc.yaml +35 -0
  764. package/templates/.poetic/task-types/feature.yaml +23 -0
  765. package/templates/.poetic/task-types/general.yaml +6 -0
  766. package/templates/.poetic/task-types/security.yaml +39 -0
  767. package/templates/AGENTS.template.md +99 -0
  768. package/templates/CLAUDE.template.md +1 -0
  769. package/templates/GEMINI.template.md +1 -0
  770. package/templates/builtin-workflows/code-review.yaml +73 -0
  771. package/templates/builtin-workflows/compete-streak.yaml +78 -0
  772. package/templates/builtin-workflows/hello-verify.yaml +10 -0
  773. package/templates/builtin-workflows/judge-regression.yaml +114 -0
  774. package/templates/builtin-workflows/skills/code-review/SKILL.md +60 -0
  775. package/templates/builtin-workflows/skills/hello-verify/SKILL.md +6 -0
  776. package/templates/guard-kit/GUARD_SETUP.md.template +255 -0
  777. package/templates/guard-kit/check.mjs.template +777 -0
  778. package/templates/guard-kit/config.json.template +6 -0
  779. package/templates/guard-kit/poetic-guard.yml.template +189 -0
  780. package/templates/profiles/README.md +56 -0
  781. package/templates/profiles/frontier-claude.json +27 -0
  782. package/templates/profiles/frontier-codex.json +26 -0
@@ -0,0 +1,1221 @@
1
+ /**
2
+ * Pure BB presentation for the BPAU-03 sprint-composition lane.
3
+ *
4
+ * This module is presentation only. It maps already-canonical BPAU-03 evidence
5
+ * to bounded, plain-language rows and controls, and it converts a form draft into
6
+ * exactly one typed BPAU-03 request. It holds the same authority boundary as the
7
+ * rest of this plugin:
8
+ *
9
+ * - Poetic is authoritative. No capacity, readiness, integrity, membership, or
10
+ * resulting status is computed, merged, re-sorted, or defaulted here: every
11
+ * rendered number and state comes from a BPAU-03 projection, a BPAU-00B
12
+ * identity envelope, or an authoritative reread.
13
+ * - Absent evidence renders as an explicit `unavailable` with Poetic's own
14
+ * reason. A missing value is never replaced by a guess or an empty success.
15
+ * - The vocabulary is the closed BPAU-03 vocabulary. Sprint execution,
16
+ * complete/close/tidy/unlock/prune-missing, custom task creation, splitting,
17
+ * provider/model selection, bulk scheduling, and force/dry-run/no-sync have
18
+ * no control here and are refused with an explicit notice.
19
+ * - `addSprintWorkFromBacklog` is labelled "Add from backlog". It is never
20
+ * described as attaching an existing task.
21
+ * - A submission changes nothing on screen until Poetic's reread arrives: the
22
+ * awaiting phase renders the pre-submission evidence unchanged.
23
+ *
24
+ * Nothing here spawns a process, reads a file, or touches the network, and this
25
+ * module wires no shared application file: it is loadable on its own.
26
+ */
27
+
28
+ import {
29
+ requiresMembershipConsent,
30
+ requiresNewIdentityConsent,
31
+ SPRINT_COMPOSITION_DISCLOSURE,
32
+ SPRINT_COMPOSITION_EFFECT_COPY,
33
+ SPRINT_COMPOSITION_LABELS,
34
+ type SprintCompositionConsentState,
35
+ sprintCompositionConsentPayload,
36
+ sprintCompositionRequestedIdentities,
37
+ } from './sprint-composition-model.js';
38
+ import { sprintMembershipIds, sprintMembershipState } from './sprint-composition-readback.js';
39
+ import {
40
+ type ApplySprintCompositionInput,
41
+ type ApplySprintCompositionOutput,
42
+ applySprintCompositionInputSchema,
43
+ type GetSprintOutput,
44
+ type ListSprintsOutput,
45
+ SPRINT_COMPOSITION_OUTCOME_VERSION,
46
+ SPRINT_COMPOSITION_VOCABULARY,
47
+ type SprintCompositionAction,
48
+ type SprintCompositionEvidence,
49
+ type SprintStatusEnvelope,
50
+ } from './sprint-composition-schema.js';
51
+ import type { GetTaskDetailOutput } from './task-detail-schema.js';
52
+
53
+ export type { SprintCompositionConsentState };
54
+
55
+ export const SPRINT_COMPOSITION_VIEW_VERSION = '1.0.0' as const;
56
+
57
+ /** Bound on any single emitted line. */
58
+ export const SPRINT_COMPOSITION_MAX_LINE_CHARS = 240;
59
+
60
+ /** Bound on how many identities one row lists. */
61
+ export const SPRINT_COMPOSITION_LIST_LIMIT = 12;
62
+
63
+ /** Plain label for evidence Poetic did not publish. */
64
+ const UNAVAILABLE = 'unavailable';
65
+
66
+ export interface SprintCompositionRow {
67
+ /** Stable row id, usable as a render key. */
68
+ id: string;
69
+ label: string;
70
+ value: string;
71
+ }
72
+
73
+ function truncateLine(text: string): string {
74
+ const normalized = text.replace(/\s+/g, ' ').trim();
75
+ if (normalized.length <= SPRINT_COMPOSITION_MAX_LINE_CHARS) return normalized;
76
+ return `${normalized.slice(0, SPRINT_COMPOSITION_MAX_LINE_CHARS - 3)}...`;
77
+ }
78
+
79
+ function row(id: string, label: string, value: string): SprintCompositionRow {
80
+ return { id, label, value: truncateLine(value) };
81
+ }
82
+
83
+ /** Render a list of identities. An empty list is a published "none". */
84
+ function formatIdentities(values: readonly string[]): string {
85
+ if (values.length === 0) return 'none';
86
+ const shown = values.slice(0, SPRINT_COMPOSITION_LIST_LIMIT);
87
+ const remaining = values.length - shown.length;
88
+ return remaining > 0 ? `${shown.join(', ')} (+${remaining} more)` : shown.join(', ');
89
+ }
90
+
91
+ function formatOptional(value: string | null | undefined): string {
92
+ const trimmed = value?.trim() ?? '';
93
+ return trimmed.length > 0 ? trimmed : UNAVAILABLE;
94
+ }
95
+
96
+ /**
97
+ * Capacity exactly as Poetic published it. The three numbers are carried
98
+ * verbatim; utilization is never recomputed from the other two.
99
+ */
100
+ function formatCapacity(capacity: {
101
+ allocatedHours: number;
102
+ totalHours: number;
103
+ utilizationPercent: number;
104
+ }): string {
105
+ return `${capacity.allocatedHours}h allocated of ${capacity.totalHours}h, ${capacity.utilizationPercent}% utilization (Poetic-computed)`;
106
+ }
107
+
108
+ /* ------------------------------------------------------------------ *
109
+ * Read-only projections: sprint list and single-sprint composition
110
+ * ------------------------------------------------------------------ */
111
+
112
+ export interface SprintCompositionListView {
113
+ state: 'available' | 'unavailable';
114
+ scope: ListSprintsOutput['scope'];
115
+ headline: string;
116
+ rows: readonly SprintCompositionRow[];
117
+ /** Sprint ids Poetic published, in Poetic's own order. */
118
+ sprintIds: readonly string[];
119
+ notes: readonly string[];
120
+ }
121
+
122
+ /**
123
+ * Render Poetic's sprint list. Order, totals, and per-sprint capacity are
124
+ * carried verbatim; an unavailable list is never an empty sprint list.
125
+ */
126
+ export function buildSprintListView(output: ListSprintsOutput): SprintCompositionListView {
127
+ if (output.sprints.state !== 'available') {
128
+ return {
129
+ state: 'unavailable',
130
+ scope: output.scope,
131
+ headline: 'Sprint list unavailable',
132
+ rows: [],
133
+ sprintIds: [],
134
+ notes: [truncateLine(output.sprints.reason)],
135
+ };
136
+ }
137
+ const envelope = output.sprints.value;
138
+ return {
139
+ state: 'available',
140
+ scope: output.scope,
141
+ headline: `Sprints (${output.scope}): ${envelope.total}`,
142
+ rows: envelope.sprints.map((sprint) =>
143
+ row(
144
+ `sprint-${sprint.id}`,
145
+ `${sprint.name} (${sprint.id})`,
146
+ `${sprint.status}, ${sprint.startDate} to ${sprint.endDate}, ${sprint.taskCount} task(s), ${formatCapacity(sprint.capacity)}`
147
+ )
148
+ ),
149
+ sprintIds: envelope.sprints.map((sprint) => sprint.id),
150
+ notes: [],
151
+ };
152
+ }
153
+
154
+ export interface SprintCompositionSprintView {
155
+ state: 'available' | 'unavailable';
156
+ sprintId: string;
157
+ headline: string;
158
+ rows: readonly SprintCompositionRow[];
159
+ /** Task ids Poetic lists as members, in Poetic's own order. */
160
+ membership: readonly string[];
161
+ /** Task ids the sprint references with no resolvable task file. */
162
+ missingTaskIds: readonly string[];
163
+ /** Integrity notes as Poetic reported them. BB reports, never repairs. */
164
+ integrityNotes: readonly string[];
165
+ notes: readonly string[];
166
+ }
167
+
168
+ function unavailableSprintView(
169
+ sprintId: string,
170
+ reason: string,
171
+ integrityNotes: readonly string[] = []
172
+ ): SprintCompositionSprintView {
173
+ return {
174
+ state: 'unavailable',
175
+ sprintId,
176
+ headline: `Sprint ${sprintId} composition unavailable`,
177
+ rows: [],
178
+ membership: [],
179
+ missingTaskIds: [],
180
+ integrityNotes: integrityNotes.map(truncateLine),
181
+ notes: [truncateLine(reason)],
182
+ };
183
+ }
184
+
185
+ /**
186
+ * Render one sprint's composition from Poetic's status projection. Capacity,
187
+ * readiness, membership, and integrity are all Poetic-computed; the only thing
188
+ * added here is labelling.
189
+ */
190
+ export function buildSprintCompositionSprintView(
191
+ sprintId: string,
192
+ sprint: SprintCompositionEvidence<SprintStatusEnvelope>,
193
+ integrityNotes: readonly string[] = []
194
+ ): SprintCompositionSprintView {
195
+ if (sprint.state !== 'available') {
196
+ return unavailableSprintView(sprintId, sprint.reason, integrityNotes);
197
+ }
198
+ const value = sprint.value;
199
+ const progress = value.progress;
200
+ return {
201
+ state: 'available',
202
+ sprintId: value.sprintId,
203
+ headline: `Sprint ${value.name} (${value.sprintId}): ${value.status}`,
204
+ rows: [
205
+ row('sprint-id', 'Sprint', `${value.name} (${value.sprintId})`),
206
+ row('sprint-status', 'Status', `${value.status}${value.archived ? ', archived' : ''}`),
207
+ row(
208
+ 'sprint-dates',
209
+ 'Dates',
210
+ `${formatOptional(value.startDate)} to ${formatOptional(value.endDate)}`
211
+ ),
212
+ row('sprint-goal', 'Goal', formatOptional(value.goal)),
213
+ row('sprint-capacity', 'Capacity', formatCapacity(value.capacity)),
214
+ row(
215
+ 'sprint-completed-capacity',
216
+ 'Completed capacity',
217
+ `${value.completedCapacity.totalDoneHours}h done (${value.completedCapacity.activeDoneHours}h active, ${value.completedCapacity.archivedDoneHours}h archived across ${value.completedCapacity.archivedTaskCount} archived task(s))`
218
+ ),
219
+ row(
220
+ 'sprint-progress',
221
+ 'Progress',
222
+ `${progress.done} done, ${progress.in_progress} in progress, ${progress.review} in review, ${progress.todo} to do, ${progress.blocked} blocked, ${progress.cancelled} cancelled of ${progress.total}`
223
+ ),
224
+ row(
225
+ 'sprint-readiness',
226
+ 'Readiness',
227
+ `all done ${progress.allDone ? 'yes' : 'no'}, all terminal ${progress.allTerminal ? 'yes' : 'no'}, closable ${progress.closable ? 'yes' : 'no'} (Poetic-computed)`
228
+ ),
229
+ row(
230
+ 'sprint-integrity',
231
+ 'Integrity',
232
+ progress.integrityClean ? 'clean' : 'not clean (Poetic-reported)'
233
+ ),
234
+ row('sprint-membership', 'Members', formatIdentities(sprintMembershipIds(value))),
235
+ row(
236
+ 'sprint-missing-references',
237
+ 'Missing task references',
238
+ formatIdentities(value.missingTaskIds)
239
+ ),
240
+ ],
241
+ membership: sprintMembershipIds(value),
242
+ missingTaskIds: value.missingTaskIds,
243
+ integrityNotes: integrityNotes.map(truncateLine),
244
+ notes: [],
245
+ };
246
+ }
247
+
248
+ /** Render a `getSprint` projection, carrying its integrity notes through. */
249
+ export function buildSprintCompositionSprintViewFromOutput(
250
+ output: GetSprintOutput
251
+ ): SprintCompositionSprintView {
252
+ return buildSprintCompositionSprintView(output.sprintId, output.sprint, output.integrityNotes);
253
+ }
254
+
255
+ /* ------------------------------------------------------------------ *
256
+ * Form: explicit identities, proportionate consent, one typed request
257
+ * ------------------------------------------------------------------ */
258
+
259
+ /**
260
+ * Which identity a field names. Every action selects its identities explicitly:
261
+ * there is no implicit "current sprint", "next sprint", or "selected task".
262
+ */
263
+ export type SprintCompositionFieldKind =
264
+ | 'sprint-id'
265
+ | 'source-sprint-id'
266
+ | 'target-sprint-id'
267
+ | 'backlog-item-id'
268
+ | 'task-id'
269
+ | 'text'
270
+ | 'date'
271
+ | 'hours'
272
+ | 'minutes'
273
+ | 'priority';
274
+
275
+ export interface SprintCompositionFormField {
276
+ id: string;
277
+ label: string;
278
+ kind: SprintCompositionFieldKind;
279
+ required: boolean;
280
+ }
281
+
282
+ const SPRINT_COMPOSITION_FIELDS: Readonly<
283
+ Record<SprintCompositionAction, readonly SprintCompositionFormField[]>
284
+ > = {
285
+ createSprint: [
286
+ { id: 'name', label: 'Sprint name', kind: 'text', required: true },
287
+ { id: 'start', label: 'Start date', kind: 'date', required: true },
288
+ { id: 'end', label: 'End date', kind: 'date', required: true },
289
+ { id: 'goal', label: 'Goal', kind: 'text', required: false },
290
+ { id: 'hours', label: 'Capacity hours', kind: 'hours', required: false },
291
+ ],
292
+ renameSprint: [
293
+ { id: 'sprintId', label: 'Sprint', kind: 'sprint-id', required: true },
294
+ { id: 'name', label: 'New sprint name', kind: 'text', required: true },
295
+ ],
296
+ addSprintWorkFromBacklog: [
297
+ { id: 'sprintId', label: 'Sprint', kind: 'sprint-id', required: true },
298
+ { id: 'backlogItemId', label: 'Backlog item', kind: 'backlog-item-id', required: true },
299
+ { id: 'estimate', label: 'Estimate hours', kind: 'hours', required: true },
300
+ {
301
+ id: 'expectedRuntimeMinutes',
302
+ label: 'Expected runtime minutes',
303
+ kind: 'minutes',
304
+ required: false,
305
+ },
306
+ { id: 'priority', label: 'Priority', kind: 'priority', required: false },
307
+ ],
308
+ removeSprintTask: [
309
+ { id: 'sprintId', label: 'Sprint', kind: 'sprint-id', required: true },
310
+ { id: 'taskId', label: 'Task', kind: 'task-id', required: true },
311
+ ],
312
+ migrateSprintTask: [
313
+ { id: 'taskId', label: 'Task', kind: 'task-id', required: true },
314
+ { id: 'sourceSprintId', label: 'Source sprint', kind: 'source-sprint-id', required: true },
315
+ { id: 'targetSprintId', label: 'Target sprint', kind: 'target-sprint-id', required: true },
316
+ ],
317
+ };
318
+
319
+ export function sprintCompositionFormFields(
320
+ action: SprintCompositionAction
321
+ ): readonly SprintCompositionFormField[] {
322
+ return SPRINT_COMPOSITION_FIELDS[action];
323
+ }
324
+
325
+ export const SPRINT_COMPOSITION_CONSENT_LABELS: Readonly<
326
+ Record<keyof SprintCompositionConsentState, string>
327
+ > = {
328
+ hostExecution: 'Poetic runs as my host user in the repository shown above.',
329
+ managedPlanningMutation: 'This mutates managed planning state that Poetic owns.',
330
+ automaticCommitAndPush:
331
+ "Poetic's built-in managed sync commits and pushes these planning changes.",
332
+ selectedRepositoryAndBranch: 'I mean this repository path and this branch.',
333
+ newIdentityCreation: 'A new Poetic-minted id will exist after this action.',
334
+ sprintMembershipChange: 'This changes which sprint holds the task.',
335
+ };
336
+
337
+ /** The consent lines an action requires; nothing more is asked for. */
338
+ export function sprintCompositionRequiredConsentKeys(
339
+ action: SprintCompositionAction
340
+ ): Array<keyof SprintCompositionConsentState> {
341
+ const keys: Array<keyof SprintCompositionConsentState> = [
342
+ 'hostExecution',
343
+ 'managedPlanningMutation',
344
+ 'automaticCommitAndPush',
345
+ 'selectedRepositoryAndBranch',
346
+ ];
347
+ if (requiresNewIdentityConsent(action)) keys.push('newIdentityCreation');
348
+ if (requiresMembershipConsent(action)) keys.push('sprintMembershipChange');
349
+ return keys;
350
+ }
351
+
352
+ export interface SprintCompositionConfirmation {
353
+ action: SprintCompositionAction;
354
+ /** The product label. Never "attach existing task". */
355
+ title: string;
356
+ /** What the command is asked to do, from BPAU-03's effect copy. */
357
+ effect: string;
358
+ /** Extra disclosures, present only where the effect earns them. */
359
+ disclosures: readonly string[];
360
+ requiredConsentKeys: ReadonlyArray<keyof SprintCompositionConsentState>;
361
+ /** True when the action changes which sprint holds a task. */
362
+ crossSprint: boolean;
363
+ }
364
+
365
+ const CROSS_SPRINT_DISCLOSURES: Readonly<Partial<Record<SprintCompositionAction, string[]>>> = {
366
+ removeSprintTask: [
367
+ 'The task leaves this sprint. It stops counting toward this sprint capacity and is scheduled in no sprint until you add it to one.',
368
+ 'Poetic keeps the task file. BB cannot read the sprint id recorded inside the task file, so a stale reference there would not be visible here.',
369
+ ],
370
+ migrateSprintTask: [
371
+ 'The task leaves the source sprint and joins the target sprint. Both sprint capacities change, and Poetic resets the task status to todo.',
372
+ 'A mid-flight failure can leave the task listed by both sprints. BB reports what the sprint rereads say and repairs nothing.',
373
+ ],
374
+ addSprintWorkFromBacklog: [
375
+ 'Poetic creates a new task from the backlog item and attaches it to the sprint you named. The backlog item itself is not moved.',
376
+ 'Poetic creates the task file before attaching it and has no rollback, so a created-but-unattached task is possible and is reported as such.',
377
+ ],
378
+ };
379
+
380
+ /**
381
+ * Build the confirmation for one action. Create and rename stay proportionate:
382
+ * they carry the effect copy and nothing more, because neither changes which
383
+ * sprint holds a task.
384
+ */
385
+ export function buildSprintCompositionConfirmation(
386
+ action: SprintCompositionAction
387
+ ): SprintCompositionConfirmation {
388
+ return {
389
+ action,
390
+ title: SPRINT_COMPOSITION_LABELS[action],
391
+ effect: SPRINT_COMPOSITION_EFFECT_COPY[action],
392
+ disclosures: (CROSS_SPRINT_DISCLOSURES[action] ?? []).map(truncateLine),
393
+ requiredConsentKeys: sprintCompositionRequiredConsentKeys(action),
394
+ crossSprint: requiresMembershipConsent(action),
395
+ };
396
+ }
397
+
398
+ /** The repository and project identity the request is bound to. */
399
+ export interface SprintCompositionSelection {
400
+ projectId: string;
401
+ sourceId: string;
402
+ repositoryPath: string;
403
+ branch: string | null;
404
+ }
405
+
406
+ /**
407
+ * Form values as the operator left them. Every value is the raw string the
408
+ * control holds; an empty optional string is omitted from the request rather
409
+ * than sent as a default.
410
+ */
411
+ export type SprintCompositionDraft =
412
+ | {
413
+ action: 'createSprint';
414
+ name: string;
415
+ start: string;
416
+ end: string;
417
+ goal: string;
418
+ hours: string;
419
+ }
420
+ | { action: 'renameSprint'; sprintId: string; name: string }
421
+ | {
422
+ action: 'addSprintWorkFromBacklog';
423
+ sprintId: string;
424
+ backlogItemId: string;
425
+ estimate: string;
426
+ expectedRuntimeMinutes: string;
427
+ priority: string;
428
+ }
429
+ | { action: 'removeSprintTask'; sprintId: string; taskId: string }
430
+ | {
431
+ action: 'migrateSprintTask';
432
+ taskId: string;
433
+ sourceSprintId: string;
434
+ targetSprintId: string;
435
+ };
436
+
437
+ /**
438
+ * Canonical evidence the form reads. Nothing here is optional-with-a-default:
439
+ * a missing projection makes the affected control refuse rather than guess.
440
+ */
441
+ export interface SprintCompositionCanonicalEvidence {
442
+ sprints: ListSprintsOutput;
443
+ /** The sprint the action names; the target sprint for a migration. */
444
+ sprint: GetSprintOutput | null;
445
+ /** The source sprint for a migration. */
446
+ sourceSprint: GetSprintOutput | null;
447
+ }
448
+
449
+ export type SprintCompositionDraftRefusalReason =
450
+ | 'incomplete'
451
+ | 'incomplete-consent'
452
+ | 'invalid-value'
453
+ | 'ambiguous-target'
454
+ | 'stale-membership';
455
+
456
+ export type SprintCompositionRequestDraft =
457
+ | { state: 'ready'; request: ApplySprintCompositionInput }
458
+ | {
459
+ state: 'refused';
460
+ reason: SprintCompositionDraftRefusalReason;
461
+ message: string;
462
+ /** Field ids the operator still has to resolve, when applicable. */
463
+ fieldIds: readonly string[];
464
+ };
465
+
466
+ type SprintCompositionDraftValues = Readonly<Record<string, string>>;
467
+
468
+ function trimmedDraftValues(draft: SprintCompositionDraft): SprintCompositionDraftValues {
469
+ const values: Record<string, string> = {};
470
+ for (const [key, value] of Object.entries(draft)) {
471
+ if (key === 'action') continue;
472
+ values[key] = typeof value === 'string' ? value.trim() : '';
473
+ }
474
+ return values;
475
+ }
476
+
477
+ /** An absent field reads as empty text, never as `undefined`. */
478
+ function draftValue(values: SprintCompositionDraftValues, fieldId: string): string {
479
+ return values[fieldId] ?? '';
480
+ }
481
+
482
+ function missingRequiredFieldIds(draft: SprintCompositionDraft): string[] {
483
+ const values = trimmedDraftValues(draft);
484
+ return sprintCompositionFormFields(draft.action)
485
+ .filter((field) => field.required && draftValue(values, field.id).length === 0)
486
+ .map((field) => field.id);
487
+ }
488
+
489
+ /** Optional numeric fields: an empty value is omitted, a bad value is refused. */
490
+ function optionalNumber(value: string): number | undefined | 'invalid' {
491
+ if (value.length === 0) return undefined;
492
+ const parsed = Number(value);
493
+ return Number.isFinite(parsed) ? parsed : 'invalid';
494
+ }
495
+
496
+ function draftInput(
497
+ draft: SprintCompositionDraft
498
+ ): { input: Record<string, unknown> } | { invalidFieldIds: string[] } {
499
+ const values = trimmedDraftValues(draft);
500
+ const invalidFieldIds: string[] = [];
501
+ const optional = (fieldId: string): number | undefined => {
502
+ const parsed = optionalNumber(draftValue(values, fieldId));
503
+ if (parsed === 'invalid') {
504
+ invalidFieldIds.push(fieldId);
505
+ return undefined;
506
+ }
507
+ return parsed;
508
+ };
509
+
510
+ let input: Record<string, unknown>;
511
+ switch (draft.action) {
512
+ case 'createSprint': {
513
+ const hours = optional('hours');
514
+ const goal = draftValue(values, 'goal');
515
+ input = {
516
+ name: draftValue(values, 'name'),
517
+ start: draftValue(values, 'start'),
518
+ end: draftValue(values, 'end'),
519
+ ...(goal.length > 0 ? { goal } : {}),
520
+ ...(hours === undefined ? {} : { hours }),
521
+ };
522
+ break;
523
+ }
524
+ case 'renameSprint':
525
+ input = { sprintId: draftValue(values, 'sprintId'), name: draftValue(values, 'name') };
526
+ break;
527
+ case 'addSprintWorkFromBacklog': {
528
+ const estimate = Number(draftValue(values, 'estimate'));
529
+ if (!Number.isFinite(estimate)) invalidFieldIds.push('estimate');
530
+ const runtime = optional('expectedRuntimeMinutes');
531
+ const priority = draftValue(values, 'priority');
532
+ input = {
533
+ sprintId: draftValue(values, 'sprintId'),
534
+ backlogItemId: draftValue(values, 'backlogItemId'),
535
+ estimate,
536
+ ...(runtime === undefined ? {} : { expectedRuntimeMinutes: runtime }),
537
+ ...(priority.length > 0 ? { priority } : {}),
538
+ };
539
+ break;
540
+ }
541
+ case 'removeSprintTask':
542
+ input = { sprintId: draftValue(values, 'sprintId'), taskId: draftValue(values, 'taskId') };
543
+ break;
544
+ case 'migrateSprintTask':
545
+ input = {
546
+ taskId: draftValue(values, 'taskId'),
547
+ sourceSprintId: draftValue(values, 'sourceSprintId'),
548
+ targetSprintId: draftValue(values, 'targetSprintId'),
549
+ };
550
+ break;
551
+ }
552
+ return invalidFieldIds.length > 0 ? { invalidFieldIds } : { input };
553
+ }
554
+
555
+ function membershipEvidence(
556
+ sprint: GetSprintOutput | null,
557
+ sprintId: string
558
+ ): SprintCompositionEvidence<SprintStatusEnvelope> | null {
559
+ if (sprint === null || sprint.sprintId !== sprintId) return null;
560
+ return sprint.sprint;
561
+ }
562
+
563
+ /**
564
+ * Refuse a target BB cannot pin to canonical evidence, and a membership
565
+ * observation that no longer matches Poetic's own membership.
566
+ *
567
+ * A sprint id absent from the published sprint list is ambiguous, not simply
568
+ * wrong: BB will not submit a mutation against an identity Poetic has not
569
+ * confirmed. An unavailable list is ambiguous for the same reason.
570
+ */
571
+ function targetRefusal(
572
+ draft: SprintCompositionDraft,
573
+ evidence: SprintCompositionCanonicalEvidence
574
+ ): { reason: SprintCompositionDraftRefusalReason; message: string; fieldIds: string[] } | null {
575
+ const values = trimmedDraftValues(draft);
576
+ const list = evidence.sprints.sprints;
577
+ const knownSprintIds = list.state === 'available' ? list.value.sprints.map((s) => s.id) : null;
578
+
579
+ const sprintFields = sprintCompositionFormFields(draft.action).filter(
580
+ (field) =>
581
+ field.kind === 'sprint-id' ||
582
+ field.kind === 'source-sprint-id' ||
583
+ field.kind === 'target-sprint-id'
584
+ );
585
+ for (const field of sprintFields) {
586
+ const sprintId = draftValue(values, field.id);
587
+ if (knownSprintIds === null) {
588
+ return {
589
+ reason: 'ambiguous-target',
590
+ message: `Poetic did not publish a sprint list (${list.state === 'unavailable' ? list.reason : UNAVAILABLE}), so BB cannot confirm sprint ${sprintId} and will not submit.`,
591
+ fieldIds: [field.id],
592
+ };
593
+ }
594
+ if (!knownSprintIds.includes(sprintId)) {
595
+ return {
596
+ reason: 'ambiguous-target',
597
+ message: `Poetic does not list sprint ${sprintId}, so the ${field.label.toLowerCase()} is ambiguous and BB will not submit.`,
598
+ fieldIds: [field.id],
599
+ };
600
+ }
601
+ }
602
+
603
+ if (
604
+ draft.action === 'migrateSprintTask' &&
605
+ draftValue(values, 'sourceSprintId') === draftValue(values, 'targetSprintId')
606
+ ) {
607
+ return {
608
+ reason: 'ambiguous-target',
609
+ message:
610
+ 'The source sprint and the target sprint are the same sprint, so there is no migration to perform.',
611
+ fieldIds: ['sourceSprintId', 'targetSprintId'],
612
+ };
613
+ }
614
+
615
+ if (draft.action === 'removeSprintTask' || draft.action === 'migrateSprintTask') {
616
+ const isRemove = draft.action === 'removeSprintTask';
617
+ const sprintId = draftValue(values, isRemove ? 'sprintId' : 'sourceSprintId');
618
+ const taskId = draftValue(values, 'taskId');
619
+ const sprint = isRemove
620
+ ? membershipEvidence(evidence.sprint, sprintId)
621
+ : membershipEvidence(evidence.sourceSprint, sprintId);
622
+ const fieldIds = isRemove ? ['taskId'] : ['taskId', 'sourceSprintId'];
623
+ if (sprint === null || sprint.state !== 'available') {
624
+ return {
625
+ reason: 'stale-membership',
626
+ message: `BB has no canonical membership for sprint ${sprintId}${sprint !== null && sprint.state === 'unavailable' ? ` (${sprint.reason})` : ''}, so it will not submit a membership change it cannot confirm.`,
627
+ fieldIds,
628
+ };
629
+ }
630
+ const state = sprintMembershipState(sprint.value, taskId);
631
+ if (state !== 'present') {
632
+ return {
633
+ reason: 'stale-membership',
634
+ message:
635
+ state === 'missing-reference'
636
+ ? `Sprint ${sprintId} references task ${taskId} as a task id with no resolvable task file, so BB will not submit.`
637
+ : `Poetic does not list task ${taskId} as a member of sprint ${sprintId}, so the membership you are looking at is stale.`,
638
+ fieldIds,
639
+ };
640
+ }
641
+ }
642
+ return null;
643
+ }
644
+
645
+ /** Membership as last read, so BPAU-03 can refuse a drifted submission. */
646
+ function observedMembership(
647
+ draft: SprintCompositionDraft,
648
+ evidence: SprintCompositionCanonicalEvidence
649
+ ): string[] {
650
+ const values = trimmedDraftValues(draft);
651
+ if (draft.action === 'removeSprintTask') {
652
+ const sprint = membershipEvidence(evidence.sprint, draftValue(values, 'sprintId'));
653
+ return sprint !== null && sprint.state === 'available' ? sprintMembershipIds(sprint.value) : [];
654
+ }
655
+ if (draft.action === 'migrateSprintTask') {
656
+ const sprint = membershipEvidence(evidence.sourceSprint, draftValue(values, 'sourceSprintId'));
657
+ return sprint !== null && sprint.state === 'available' ? sprintMembershipIds(sprint.value) : [];
658
+ }
659
+ return [];
660
+ }
661
+
662
+ /**
663
+ * Convert a confirmed draft into exactly one typed BPAU-03 request.
664
+ *
665
+ * The request is produced by the BPAU-03 schema itself, so this cannot smuggle a
666
+ * field the lane does not accept, and a value Poetic would refuse is refused
667
+ * here instead of being sent. Consent conversion is BPAU-03's, so a disabled
668
+ * submit control and a refused submission always agree.
669
+ */
670
+ export function buildSprintCompositionRequest(input: {
671
+ draft: SprintCompositionDraft;
672
+ consent: SprintCompositionConsentState;
673
+ selection: SprintCompositionSelection;
674
+ evidence: SprintCompositionCanonicalEvidence;
675
+ }): SprintCompositionRequestDraft {
676
+ const { draft, consent, selection, evidence } = input;
677
+
678
+ const missing = missingRequiredFieldIds(draft);
679
+ if (missing.length > 0) {
680
+ return {
681
+ state: 'refused',
682
+ reason: 'incomplete',
683
+ message: 'Every required identity and value must be selected explicitly before submitting.',
684
+ fieldIds: missing,
685
+ };
686
+ }
687
+
688
+ const built = draftInput(draft);
689
+ if ('invalidFieldIds' in built) {
690
+ return {
691
+ state: 'refused',
692
+ reason: 'invalid-value',
693
+ message: 'A numeric field does not hold a number, so BB will not submit it.',
694
+ fieldIds: built.invalidFieldIds,
695
+ };
696
+ }
697
+
698
+ const ambiguity = targetRefusal(draft, evidence);
699
+ if (ambiguity !== null) {
700
+ return {
701
+ state: 'refused',
702
+ reason: ambiguity.reason,
703
+ message: truncateLine(ambiguity.message),
704
+ fieldIds: ambiguity.fieldIds,
705
+ };
706
+ }
707
+
708
+ const consentPayload = sprintCompositionConsentPayload(draft.action, consent);
709
+ if (consentPayload === null) {
710
+ return {
711
+ state: 'refused',
712
+ reason: 'incomplete-consent',
713
+ message: 'Every consent line this action requires must be acknowledged before submitting.',
714
+ fieldIds: [],
715
+ };
716
+ }
717
+
718
+ const candidate = {
719
+ projectId: selection.projectId,
720
+ sourceId: selection.sourceId,
721
+ action: draft.action,
722
+ input: built.input,
723
+ consent: consentPayload,
724
+ expected: {
725
+ repositoryPath: selection.repositoryPath,
726
+ branch: selection.branch,
727
+ entityIds: [] as string[],
728
+ observedMembership: observedMembership(draft, evidence),
729
+ },
730
+ };
731
+
732
+ const parsed = applySprintCompositionInputSchema.safeParse(candidate);
733
+ if (!parsed.success) {
734
+ return {
735
+ state: 'refused',
736
+ reason: 'invalid-value',
737
+ message: `Poetic's sprint-composition contract refused this input: ${parsed.error.issues[0]?.message ?? 'invalid request'}`,
738
+ fieldIds: parsed.error.issues.flatMap((issue) =>
739
+ issue.path.length > 0 ? [String(issue.path[issue.path.length - 1])] : []
740
+ ),
741
+ };
742
+ }
743
+
744
+ // The declared identities come from BPAU-03's own derivation, so consent and
745
+ // the request always name the same entities.
746
+ const identities = [...new Set(sprintCompositionRequestedIdentities(parsed.data))];
747
+ const withIdentities = applySprintCompositionInputSchema.safeParse({
748
+ ...candidate,
749
+ expected: { ...candidate.expected, entityIds: identities },
750
+ });
751
+ if (!withIdentities.success) {
752
+ return {
753
+ state: 'refused',
754
+ reason: 'invalid-value',
755
+ message: 'The declared identities did not satisfy the sprint-composition contract.',
756
+ fieldIds: [],
757
+ };
758
+ }
759
+ return { state: 'ready', request: withIdentities.data };
760
+ }
761
+
762
+ /* ------------------------------------------------------------------ *
763
+ * Prohibited actions
764
+ * ------------------------------------------------------------------ */
765
+
766
+ /**
767
+ * Controls this lane deliberately does not offer. They are named so a refusal
768
+ * is explicit rather than a control that silently does nothing.
769
+ */
770
+ export const SPRINT_COMPOSITION_PROHIBITED_ACTIONS = [
771
+ 'createCustomTask',
772
+ 'completeSprint',
773
+ 'closeSprint',
774
+ 'tidySprint',
775
+ 'unlockSprint',
776
+ 'pruneMissingTasks',
777
+ 'runSprint',
778
+ 'applySprint',
779
+ 'splitTask',
780
+ 'selectProvider',
781
+ 'selectModel',
782
+ 'bulkSchedule',
783
+ 'dragAndDropSchedule',
784
+ 'forceMutation',
785
+ 'dryRun',
786
+ 'suppressSync',
787
+ ] as const;
788
+
789
+ export type SprintCompositionProhibitedAction =
790
+ (typeof SPRINT_COMPOSITION_PROHIBITED_ACTIONS)[number];
791
+
792
+ const PROHIBITED_NOTICES: Readonly<Record<SprintCompositionProhibitedAction, string>> = {
793
+ createCustomTask:
794
+ 'Creating a custom task is a different product and is not offered here. "Add from backlog" creates a task from an existing backlog item.',
795
+ completeSprint: 'Completing a sprint is not offered here.',
796
+ closeSprint: 'Closing a sprint is not offered here.',
797
+ tidySprint: 'Tidying a sprint is not offered here.',
798
+ unlockSprint: 'Unlocking a sprint is not offered here.',
799
+ pruneMissingTasks:
800
+ 'Repairing sprint integrity is not offered here. BB reports missing task references and does not prune them.',
801
+ runSprint: 'Sprint execution is not offered here. This surface only composes sprints.',
802
+ applySprint: 'Applying sprint results is not offered here.',
803
+ splitTask: 'Splitting work is not offered here.',
804
+ selectProvider: 'Provider selection is not offered here.',
805
+ selectModel: 'Model selection is not offered here.',
806
+ bulkSchedule:
807
+ 'Bulk scheduling is not offered here. Each action names its own sprint, task, and backlog identities.',
808
+ dragAndDropSchedule:
809
+ 'Drag-and-drop scheduling is not offered here: presentation never changes before Poetic confirms the change.',
810
+ forceMutation: 'BB never passes --force.',
811
+ dryRun: 'BB never passes --dry-run.',
812
+ suppressSync: "BB never passes --no-sync: Poetic's managed sync always runs.",
813
+ };
814
+
815
+ export function isSprintCompositionAction(value: string): value is SprintCompositionAction {
816
+ return (SPRINT_COMPOSITION_VOCABULARY as readonly string[]).includes(value);
817
+ }
818
+
819
+ /**
820
+ * Explicit refusal for anything outside the closed vocabulary. A named excluded
821
+ * control gets its own reason; anything else is refused as out of vocabulary.
822
+ */
823
+ export function sprintCompositionProhibitedRefusal(
824
+ requestedAction: string
825
+ ): { action: string; message: string } | null {
826
+ if (isSprintCompositionAction(requestedAction)) return null;
827
+ const known = (SPRINT_COMPOSITION_PROHIBITED_ACTIONS as readonly string[]).includes(
828
+ requestedAction
829
+ );
830
+ return {
831
+ action: requestedAction,
832
+ message: truncateLine(
833
+ known
834
+ ? PROHIBITED_NOTICES[requestedAction as SprintCompositionProhibitedAction]
835
+ : `"${requestedAction}" is not a sprint-composition action, so BB will not submit it.`
836
+ ),
837
+ };
838
+ }
839
+
840
+ /** Every excluded control, as notices for the surface to render. */
841
+ export function sprintCompositionProhibitedNotices(): readonly string[] {
842
+ return SPRINT_COMPOSITION_PROHIBITED_ACTIONS.map((action) =>
843
+ truncateLine(PROHIBITED_NOTICES[action])
844
+ );
845
+ }
846
+
847
+ /* ------------------------------------------------------------------ *
848
+ * Outcome presentation
849
+ * ------------------------------------------------------------------ */
850
+
851
+ export type SprintCompositionOutcomeState =
852
+ | 'applied'
853
+ | 'applied-incomplete'
854
+ | 'overlap-conflict'
855
+ | 'refused'
856
+ | 'partial-effect'
857
+ | 'unknown';
858
+
859
+ /**
860
+ * Overlap recovery as Poetic published it. Recovery is a Poetic CLI action, so
861
+ * this carries guidance only and offers no BB control.
862
+ */
863
+ export interface SprintCompositionOverlapRecovery {
864
+ conflictingSprintId: string | null;
865
+ guidance: string;
866
+ /** Recovery is never a BB control. */
867
+ control: null;
868
+ }
869
+
870
+ export interface SprintCompositionOutcomeView {
871
+ action: SprintCompositionAction;
872
+ actionLabel: string;
873
+ state: SprintCompositionOutcomeState;
874
+ headline: string;
875
+ rows: readonly SprintCompositionRow[];
876
+ notes: readonly string[];
877
+ /** Present only for a create that Poetic refused as an overlap. */
878
+ recovery: SprintCompositionOverlapRecovery | null;
879
+ /** True when the reported effect is not a clean applied outcome. */
880
+ degraded: boolean;
881
+ }
882
+
883
+ const OUTCOME_STATES: Readonly<
884
+ Record<ApplySprintCompositionOutput['effect']['phase'], SprintCompositionOutcomeState>
885
+ > = {
886
+ applied: 'applied',
887
+ 'applied-incomplete': 'applied-incomplete',
888
+ 'overlap-conflict': 'overlap-conflict',
889
+ 'refused-before-launch': 'refused',
890
+ 'refused-before-effect': 'refused',
891
+ 'failed-after-partial-effect': 'partial-effect',
892
+ 'unknown-after-timeout': 'unknown',
893
+ };
894
+
895
+ const OUTCOME_HEADLINES: Readonly<Record<SprintCompositionOutcomeState, string>> = {
896
+ applied: 'applied',
897
+ 'applied-incomplete': 'applied, with unconfirmed effects',
898
+ 'overlap-conflict': 'refused: sprint dates overlap an existing sprint',
899
+ refused: 'refused; nothing changed',
900
+ 'partial-effect': 'failed after a partial effect',
901
+ unknown: 'outcome unknown',
902
+ };
903
+
904
+ /**
905
+ * Resulting task status from the authoritative reread only. A status BB could not
906
+ * reread is unavailable; it is never predicted from the action that just ran.
907
+ */
908
+ function taskStatusRowValue(
909
+ evidence: SprintCompositionEvidence<GetTaskDetailOutput> | undefined
910
+ ): string {
911
+ if (evidence === undefined) return UNAVAILABLE;
912
+ if (evidence.state !== 'available') return `${UNAVAILABLE}: ${evidence.reason}`;
913
+ const task = evidence.value.task;
914
+ if (task.state === 'missing') return 'missing';
915
+ if (task.state === 'unavailable') return `${UNAVAILABLE}: ${task.reason}`;
916
+ return formatOptional(task.value.status);
917
+ }
918
+
919
+ function overlapRecovery(
920
+ outcome: ApplySprintCompositionOutput
921
+ ): SprintCompositionOverlapRecovery | null {
922
+ const identity = outcome.identityOutcome;
923
+ if (identity === null || identity.kind !== 'sprintCreateV1') return null;
924
+ if (identity.value.state !== 'overlap-conflict') return null;
925
+ return {
926
+ conflictingSprintId: identity.value.conflictingSprintId ?? null,
927
+ guidance: truncateLine(
928
+ identity.value.recoveryText ??
929
+ 'Poetic published no recovery text for this overlap. Choose dates that do not overlap the conflicting sprint, or resolve the overlap with the Poetic CLI.'
930
+ ),
931
+ control: null,
932
+ };
933
+ }
934
+
935
+ function commandNotes(outcome: ApplySprintCompositionOutput): string[] {
936
+ const notes: string[] = [];
937
+ switch (outcome.command.state) {
938
+ case 'timed_out':
939
+ notes.push(
940
+ 'Poetic did not answer before this action timed out. Nothing was retried, and whether the change applied is unknown until you reread the sprint.'
941
+ );
942
+ break;
943
+ case 'failed':
944
+ notes.push(
945
+ `Poetic reported a failure${outcome.command.exitCode === null ? '' : ` (exit ${outcome.command.exitCode})`}${outcome.command.diagnostics === null ? '.' : `: ${outcome.command.diagnostics}`}`
946
+ );
947
+ break;
948
+ case 'ambiguous':
949
+ notes.push(
950
+ "Poetic's answer was ambiguous: BB could not establish what changed and reports neither success nor failure."
951
+ );
952
+ break;
953
+ default:
954
+ break;
955
+ }
956
+ // Only the two identity-minting actions publish a BPAU-00B envelope, so a
957
+ // missing envelope is a gap for those and expected for the other three.
958
+ if (
959
+ outcome.identityOutcome === null &&
960
+ requiresNewIdentityConsent(outcome.action) &&
961
+ outcome.command.state !== 'failed'
962
+ ) {
963
+ notes.push(
964
+ 'Poetic published no structured identity evidence for this action, so BB reports the effect as unconfirmed rather than substituting the newest sprint it can see.'
965
+ );
966
+ }
967
+ if (outcome.sync.state !== 'remote_verified') {
968
+ notes.push(
969
+ 'A zero exit code is not proof of a remote push. The sync state above is what Poetic reported on a fresh reread.'
970
+ );
971
+ }
972
+ return notes;
973
+ }
974
+
975
+ /**
976
+ * Render one BPAU-03 outcome. Every value comes from the outcome record: the
977
+ * effect phase is reported, never inferred from the exit code, and the resulting
978
+ * status comes from the authoritative reread rather than from a prediction.
979
+ */
980
+ export function buildSprintCompositionOutcomeView(
981
+ outcome: ApplySprintCompositionOutput
982
+ ): SprintCompositionOutcomeView {
983
+ const state = OUTCOME_STATES[outcome.effect.phase];
984
+ const label = SPRINT_COMPOSITION_LABELS[outcome.action];
985
+ const rows: SprintCompositionRow[] = [
986
+ row('outcome-action', 'Action', label),
987
+ row('outcome-phase', 'Effect', outcome.effect.phase),
988
+ row(
989
+ 'outcome-created',
990
+ 'Created identities',
991
+ formatIdentities(outcome.effect.createdIdentities)
992
+ ),
993
+ row(
994
+ 'outcome-affected',
995
+ 'Affected identities',
996
+ formatIdentities(outcome.effect.affectedIdentities)
997
+ ),
998
+ row('outcome-requested', 'Requested identities', formatIdentities(outcome.requestedIdentities)),
999
+ row(
1000
+ 'outcome-command',
1001
+ 'Poetic command',
1002
+ `${outcome.command.state}, exit ${outcome.command.exitCode === null ? UNAVAILABLE : outcome.command.exitCode}, ${outcome.command.attempts} attempt`
1003
+ ),
1004
+ row(
1005
+ 'outcome-sync',
1006
+ 'Planning sync',
1007
+ `${outcome.sync.state}${outcome.sync.detail === null ? '' : `: ${outcome.sync.detail}`}`
1008
+ ),
1009
+ row(
1010
+ 'outcome-task-status',
1011
+ 'Task status (canonical reread)',
1012
+ taskStatusRowValue(outcome.canonicalRereads.task)
1013
+ ),
1014
+ ];
1015
+
1016
+ const identity = outcome.identityOutcome;
1017
+ if (identity !== null && identity.kind === 'sprintAddTaskV1') {
1018
+ rows.push(
1019
+ row(
1020
+ 'outcome-add-capacity',
1021
+ 'Sprint capacity after add',
1022
+ `${identity.value.capacity.allocatedHours ?? UNAVAILABLE} of ${identity.value.capacity.totalHours ?? UNAVAILABLE} hours (Poetic-reported)`
1023
+ ),
1024
+ row(
1025
+ 'outcome-add-estimate',
1026
+ 'Estimate applied',
1027
+ `${identity.value.estimatedHours} hours from ${identity.value.estimateSource}`
1028
+ )
1029
+ );
1030
+ }
1031
+
1032
+ const recovery = overlapRecovery(outcome);
1033
+ if (recovery !== null) {
1034
+ rows.push(
1035
+ row(
1036
+ 'outcome-conflicting-sprint',
1037
+ 'Conflicting sprint',
1038
+ recovery.conflictingSprintId ?? UNAVAILABLE
1039
+ ),
1040
+ row('outcome-recovery', 'Recovery', recovery.guidance)
1041
+ );
1042
+ }
1043
+
1044
+ return {
1045
+ action: outcome.action,
1046
+ actionLabel: label,
1047
+ state,
1048
+ headline: truncateLine(`${label} ${OUTCOME_HEADLINES[state]}`),
1049
+ rows,
1050
+ notes: [...outcome.integrityNotes, ...outcome.syncWarnings, ...commandNotes(outcome)].map(
1051
+ truncateLine
1052
+ ),
1053
+ recovery,
1054
+ degraded: state !== 'applied',
1055
+ };
1056
+ }
1057
+
1058
+ /* ------------------------------------------------------------------ *
1059
+ * Composed view
1060
+ * ------------------------------------------------------------------ */
1061
+
1062
+ /**
1063
+ * Presentation phase.
1064
+ *
1065
+ * `awaiting-poetic` renders the pre-submission evidence unchanged: BB shows no
1066
+ * optimistic membership, capacity, or status while a submission is in flight.
1067
+ */
1068
+ export type SprintCompositionPhase =
1069
+ | { kind: 'idle' }
1070
+ | { kind: 'awaiting-poetic'; request: ApplySprintCompositionInput }
1071
+ | { kind: 'settled'; outcome: ApplySprintCompositionOutput };
1072
+
1073
+ export interface SprintCompositionSubmitControl {
1074
+ id: 'submit';
1075
+ label: string;
1076
+ enabled: boolean;
1077
+ /** Null only when the control is enabled. */
1078
+ disabledReason: string | null;
1079
+ }
1080
+
1081
+ export interface SprintCompositionView {
1082
+ viewVersion: typeof SPRINT_COMPOSITION_VIEW_VERSION;
1083
+ outcomeVersion: typeof SPRINT_COMPOSITION_OUTCOME_VERSION;
1084
+ phase: SprintCompositionPhase['kind'];
1085
+ action: SprintCompositionAction;
1086
+ actionLabel: string;
1087
+ headline: string;
1088
+ /** Poetic's own lane disclosure, carried verbatim. */
1089
+ disclosure: typeof SPRINT_COMPOSITION_DISCLOSURE;
1090
+ fields: readonly SprintCompositionFormField[];
1091
+ confirmation: SprintCompositionConfirmation;
1092
+ submit: SprintCompositionSubmitControl;
1093
+ /** The single typed request a confirmed draft would emit; null otherwise. */
1094
+ request: ApplySprintCompositionInput | null;
1095
+ /** Why the draft cannot be submitted, when it cannot. */
1096
+ refusal: Extract<SprintCompositionRequestDraft, { state: 'refused' }> | null;
1097
+ sprints: SprintCompositionListView;
1098
+ sprint: SprintCompositionSprintView | null;
1099
+ sourceSprint: SprintCompositionSprintView | null;
1100
+ outcome: SprintCompositionOutcomeView | null;
1101
+ /** True while BB is waiting for Poetic's reread. */
1102
+ awaitingCanonicalReread: boolean;
1103
+ notes: readonly string[];
1104
+ prohibited: readonly string[];
1105
+ }
1106
+
1107
+ export interface SprintCompositionViewInput {
1108
+ phase: SprintCompositionPhase;
1109
+ selection: SprintCompositionSelection;
1110
+ draft: SprintCompositionDraft;
1111
+ consent: SprintCompositionConsentState;
1112
+ evidence: SprintCompositionCanonicalEvidence;
1113
+ /** True when a submission for this scope is already in flight. */
1114
+ submissionInFlight?: boolean;
1115
+ }
1116
+
1117
+ function sprintViewFor(output: GetSprintOutput | null): SprintCompositionSprintView | null {
1118
+ return output === null ? null : buildSprintCompositionSprintViewFromOutput(output);
1119
+ }
1120
+
1121
+ /**
1122
+ * Sprint views after a settled submission come from the outcome's own rereads,
1123
+ * which are the authority for the resulting composition. A member the reread
1124
+ * could not supply stays explicitly unavailable.
1125
+ */
1126
+ function settledSprintViews(outcome: ApplySprintCompositionOutput): {
1127
+ sprint: SprintCompositionSprintView | null;
1128
+ sourceSprint: SprintCompositionSprintView | null;
1129
+ } {
1130
+ const rereads = outcome.canonicalRereads;
1131
+ const primary = rereads.targetSprint ?? rereads.sprint;
1132
+ const primaryId =
1133
+ primary !== undefined && primary.state === 'available' ? primary.value.sprintId : UNAVAILABLE;
1134
+ const sourceId =
1135
+ rereads.sourceSprint !== undefined && rereads.sourceSprint.state === 'available'
1136
+ ? rereads.sourceSprint.value.sprintId
1137
+ : UNAVAILABLE;
1138
+ return {
1139
+ sprint: primary === undefined ? null : buildSprintCompositionSprintView(primaryId, primary),
1140
+ sourceSprint:
1141
+ rereads.sourceSprint === undefined
1142
+ ? null
1143
+ : buildSprintCompositionSprintView(sourceId, rereads.sourceSprint),
1144
+ };
1145
+ }
1146
+
1147
+ /**
1148
+ * Build the whole sprint-composition surface for one phase.
1149
+ *
1150
+ * Deterministic in its inputs: the same evidence and draft always render the
1151
+ * same view, and no field is derived from anything other than those inputs.
1152
+ */
1153
+ export function buildSprintCompositionView(
1154
+ input: SprintCompositionViewInput
1155
+ ): SprintCompositionView {
1156
+ const { phase, draft, consent, selection, evidence } = input;
1157
+ const action = draft.action;
1158
+ const label = SPRINT_COMPOSITION_LABELS[action];
1159
+ const inFlight = input.submissionInFlight === true || phase.kind === 'awaiting-poetic';
1160
+
1161
+ const draftResult = buildSprintCompositionRequest({ draft, consent, selection, evidence });
1162
+ const refusal = draftResult.state === 'refused' ? draftResult : null;
1163
+
1164
+ const disabledReason = inFlight
1165
+ ? 'A sprint-composition submission is already in flight for this action. BB submits it once and waits for Poetic.'
1166
+ : (refusal?.message ?? null);
1167
+
1168
+ const listView = buildSprintListView(evidence.sprints);
1169
+ const settled = phase.kind === 'settled' ? settledSprintViews(phase.outcome) : null;
1170
+ const outcomeView =
1171
+ phase.kind === 'settled' ? buildSprintCompositionOutcomeView(phase.outcome) : null;
1172
+
1173
+ const notes: string[] = [];
1174
+ if (phase.kind === 'awaiting-poetic') {
1175
+ notes.push(
1176
+ 'Waiting for Poetic. The composition shown below is the evidence read before this submission; nothing changes until Poetic answers and BB rereads.'
1177
+ );
1178
+ }
1179
+ if (settled !== null) {
1180
+ notes.push(
1181
+ 'The composition shown below comes from the reread Poetic answered with after this action.'
1182
+ );
1183
+ if (settled.sprint === null && settled.sourceSprint === null) {
1184
+ notes.push(
1185
+ 'Poetic supplied no sprint reread for this action, so the resulting composition is unavailable.'
1186
+ );
1187
+ }
1188
+ }
1189
+
1190
+ return {
1191
+ viewVersion: SPRINT_COMPOSITION_VIEW_VERSION,
1192
+ outcomeVersion: SPRINT_COMPOSITION_OUTCOME_VERSION,
1193
+ phase: phase.kind,
1194
+ action,
1195
+ actionLabel: label,
1196
+ headline:
1197
+ outcomeView !== null
1198
+ ? outcomeView.headline
1199
+ : phase.kind === 'awaiting-poetic'
1200
+ ? `${label}: waiting for Poetic`
1201
+ : `${label}: review and confirm`,
1202
+ disclosure: SPRINT_COMPOSITION_DISCLOSURE,
1203
+ fields: sprintCompositionFormFields(action),
1204
+ confirmation: buildSprintCompositionConfirmation(action),
1205
+ submit: {
1206
+ id: 'submit',
1207
+ label,
1208
+ enabled: disabledReason === null,
1209
+ disabledReason,
1210
+ },
1211
+ request: phase.kind === 'idle' && draftResult.state === 'ready' ? draftResult.request : null,
1212
+ refusal,
1213
+ sprints: listView,
1214
+ sprint: settled === null ? sprintViewFor(evidence.sprint) : settled.sprint,
1215
+ sourceSprint: settled === null ? sprintViewFor(evidence.sourceSprint) : settled.sourceSprint,
1216
+ outcome: outcomeView,
1217
+ awaitingCanonicalReread: phase.kind === 'awaiting-poetic',
1218
+ notes: notes.map(truncateLine),
1219
+ prohibited: sprintCompositionProhibitedNotices(),
1220
+ };
1221
+ }