@unbrained/pm-cli 2026.7.13 → 2026.7.14

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 (487) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +28 -0
  3. package/dist/cli/commands/aggregate.d.ts +1 -1
  4. package/dist/cli/commands/aggregate.js +18 -6
  5. package/dist/cli/commands/aggregate.js.map +1 -1
  6. package/dist/cli/commands/context.d.ts +16 -1
  7. package/dist/cli/commands/context.js +98 -16
  8. package/dist/cli/commands/context.js.map +1 -1
  9. package/dist/cli/commands/create.d.ts +1 -1
  10. package/dist/cli/commands/create.js +11 -7
  11. package/dist/cli/commands/create.js.map +1 -1
  12. package/dist/cli/commands/deps.d.ts +6 -96
  13. package/dist/cli/commands/deps.js +4 -214
  14. package/dist/cli/commands/deps.js.map +1 -1
  15. package/dist/cli/commands/docs.d.ts +2 -44
  16. package/dist/cli/commands/docs.js +8 -13
  17. package/dist/cli/commands/docs.js.map +1 -1
  18. package/dist/cli/commands/files.d.ts +6 -134
  19. package/dist/cli/commands/files.js +4 -294
  20. package/dist/cli/commands/files.js.map +1 -1
  21. package/dist/cli/commands/get.js +15 -2
  22. package/dist/cli/commands/get.js.map +1 -1
  23. package/dist/cli/commands/list.js +5 -6
  24. package/dist/cli/commands/list.js.map +1 -1
  25. package/dist/cli/commands/next.d.ts +3 -1
  26. package/dist/cli/commands/next.js +77 -20
  27. package/dist/cli/commands/next.js.map +1 -1
  28. package/dist/cli/commands/update-many.js +6 -3
  29. package/dist/cli/commands/update-many.js.map +1 -1
  30. package/dist/cli/commands/update.js +14 -7
  31. package/dist/cli/commands/update.js.map +1 -1
  32. package/dist/cli/commands/validate.d.ts +1 -1
  33. package/dist/cli/commands/validate.js +32 -35
  34. package/dist/cli/commands/validate.js.map +1 -1
  35. package/dist/cli/main.d.ts +2 -14
  36. package/dist/cli/main.js +27 -8
  37. package/dist/cli/main.js.map +1 -1
  38. package/dist/cli-bundle/chunks/append-DYQWQK2J.js +11 -0
  39. package/dist/cli-bundle/chunks/{append-2FS6MVG7.js → append-PVZJDM6J.js} +5 -5
  40. package/dist/cli-bundle/chunks/{chunk-J2WAWP4U.js → chunk-2FNWQXZ2.js} +4 -4
  41. package/dist/cli-bundle/chunks/{chunk-YFGYDZRP.js → chunk-2GA3NK35.js} +4 -4
  42. package/dist/cli-bundle/chunks/{chunk-XFEIASAC.js → chunk-2QIQGYPW.js} +2 -2
  43. package/dist/cli-bundle/chunks/{chunk-3WCGYH5Q.js → chunk-3CMRNVTO.js} +7 -7
  44. package/dist/cli-bundle/chunks/chunk-3HKUXVKV.js +9 -0
  45. package/dist/cli-bundle/chunks/{chunk-VDAZPPRU.js → chunk-3I3LRT2G.js} +2 -2
  46. package/dist/cli-bundle/chunks/{chunk-3P3RFJIQ.js → chunk-3TL7WOEF.js} +2 -2
  47. package/dist/cli-bundle/chunks/{chunk-4SHJ5JS3.js → chunk-44LNIULG.js} +4 -4
  48. package/dist/cli-bundle/chunks/{chunk-QFOAWBOB.js → chunk-4DY4KPQI.js} +11 -10
  49. package/dist/cli-bundle/chunks/{chunk-QFOAWBOB.js.map → chunk-4DY4KPQI.js.map} +2 -2
  50. package/dist/cli-bundle/chunks/{chunk-BVCF4ULV.js → chunk-4RXTMU57.js} +5 -5
  51. package/dist/cli-bundle/chunks/{chunk-XMI2TRY5.js → chunk-4WREH7RT.js} +4 -4
  52. package/dist/cli-bundle/chunks/{chunk-JYUGUXFW.js → chunk-5CT5BW6E.js} +5 -5
  53. package/dist/cli-bundle/chunks/{chunk-NA5SBIB4.js → chunk-5URI7TPJ.js} +44 -44
  54. package/dist/cli-bundle/chunks/chunk-5URI7TPJ.js.map +7 -0
  55. package/dist/cli-bundle/chunks/{chunk-QGH6WL6L.js → chunk-655STMGA.js} +2 -2
  56. package/dist/cli-bundle/chunks/{chunk-DGKBWCMA.js → chunk-6IIVBC56.js} +4 -4
  57. package/dist/cli-bundle/chunks/{chunk-SRQLQUO6.js → chunk-6MHSBDGD.js} +7 -7
  58. package/dist/cli-bundle/chunks/{chunk-SRQLQUO6.js.map → chunk-6MHSBDGD.js.map} +2 -2
  59. package/dist/cli-bundle/chunks/{chunk-D4GPNYYP.js → chunk-6OTZMORS.js} +6 -6
  60. package/dist/cli-bundle/chunks/{chunk-JVRVXO6M.js → chunk-6PKA3SJQ.js} +6 -6
  61. package/dist/cli-bundle/chunks/{chunk-2PR4ZTRO.js → chunk-6TTOHMTB.js} +8 -8
  62. package/dist/cli-bundle/chunks/{chunk-2PR4ZTRO.js.map → chunk-6TTOHMTB.js.map} +1 -1
  63. package/dist/cli-bundle/chunks/chunk-6X5MZ5R2.js +9 -0
  64. package/dist/cli-bundle/chunks/chunk-76UBY2EE.js +5 -0
  65. package/dist/cli-bundle/chunks/{chunk-ZS2KPCJN.js → chunk-7QDSYUMF.js} +7 -7
  66. package/dist/cli-bundle/chunks/{chunk-Z7TFPIJ6.js → chunk-7TQMR6LK.js} +7 -7
  67. package/dist/cli-bundle/chunks/{chunk-AHA4POA6.js → chunk-ABRCOSDC.js} +3 -3
  68. package/dist/cli-bundle/chunks/{chunk-XY3CC3EM.js → chunk-AFWZRL7M.js} +59 -53
  69. package/dist/cli-bundle/chunks/chunk-AFWZRL7M.js.map +7 -0
  70. package/dist/cli-bundle/chunks/{chunk-KQJVTQVK.js → chunk-ANSJHDOZ.js} +2 -2
  71. package/dist/cli-bundle/chunks/{chunk-OMT4NO7T.js → chunk-B5DZYTT3.js} +113 -24
  72. package/dist/cli-bundle/chunks/chunk-B5DZYTT3.js.map +7 -0
  73. package/dist/cli-bundle/chunks/chunk-B7SWOIP6.js +5 -0
  74. package/dist/cli-bundle/chunks/{chunk-D2LXG7WX.js → chunk-BN62TO2S.js} +5 -5
  75. package/dist/cli-bundle/chunks/chunk-BN62TO2S.js.map +1 -0
  76. package/dist/cli-bundle/chunks/{chunk-ZTSV7P2T.js → chunk-BPD26E3P.js} +357 -42
  77. package/dist/cli-bundle/chunks/chunk-BPD26E3P.js.map +1 -0
  78. package/dist/cli-bundle/chunks/{chunk-RKGFUC4O.js → chunk-CDJYP7OQ.js} +36 -14
  79. package/dist/cli-bundle/chunks/chunk-CDJYP7OQ.js.map +1 -0
  80. package/dist/cli-bundle/chunks/{chunk-VLFLRFJP.js → chunk-CIOZ376P.js} +20 -13
  81. package/dist/cli-bundle/chunks/chunk-CIOZ376P.js.map +1 -0
  82. package/dist/cli-bundle/chunks/{chunk-HXTCZSAI.js → chunk-DBZVUJTK.js} +3 -3
  83. package/dist/cli-bundle/chunks/{chunk-2QNOWOIB.js → chunk-DO5RGJXT.js} +3 -3
  84. package/dist/cli-bundle/chunks/{chunk-MKONZ4UO.js → chunk-DRNJPEPQ.js} +4 -4
  85. package/dist/cli-bundle/chunks/{chunk-XDT2PSXA.js → chunk-DVOLZJ3C.js} +12 -11
  86. package/dist/cli-bundle/chunks/{chunk-XDT2PSXA.js.map → chunk-DVOLZJ3C.js.map} +1 -1
  87. package/dist/cli-bundle/chunks/{chunk-H36FXA7B.js → chunk-DYEX6NFH.js} +4 -4
  88. package/dist/cli-bundle/chunks/{chunk-G3IB5GTD.js → chunk-E2WC6S4P.js} +15 -11
  89. package/dist/cli-bundle/chunks/chunk-E2WC6S4P.js.map +7 -0
  90. package/dist/cli-bundle/chunks/{chunk-GAJ7U7B4.js → chunk-ERL2YFJ2.js} +3 -3
  91. package/dist/cli-bundle/chunks/{chunk-FPEYOFEF.js → chunk-F7PSHRNO.js} +3 -3
  92. package/dist/cli-bundle/chunks/{chunk-UH7OLT6F.js → chunk-FDSBDNYE.js} +2 -2
  93. package/dist/cli-bundle/chunks/{chunk-DGJF32JF.js → chunk-FIGXOCEQ.js} +66 -21
  94. package/dist/cli-bundle/chunks/chunk-FIGXOCEQ.js.map +7 -0
  95. package/dist/cli-bundle/chunks/{chunk-RQAY7C5T.js → chunk-FJZDA6MS.js} +3 -3
  96. package/dist/cli-bundle/chunks/{chunk-B4TVNGRX.js → chunk-FO7GMJKG.js} +3 -3
  97. package/dist/cli-bundle/chunks/chunk-FRQ63VPB.js +5 -0
  98. package/dist/cli-bundle/chunks/{chunk-UTYNQ2WH.js → chunk-FS6UM5WH.js} +48 -27
  99. package/dist/cli-bundle/chunks/chunk-FS6UM5WH.js.map +7 -0
  100. package/dist/cli-bundle/chunks/{chunk-U252II47.js → chunk-FTQLW4JD.js} +4 -4
  101. package/dist/cli-bundle/chunks/{chunk-TNGLCRKS.js → chunk-GSEADLRH.js} +1821 -1809
  102. package/dist/cli-bundle/chunks/chunk-GSEADLRH.js.map +1 -0
  103. package/dist/cli-bundle/chunks/{chunk-TGG7YGMC.js → chunk-GXXC7QSK.js} +53 -47
  104. package/dist/cli-bundle/chunks/chunk-GXXC7QSK.js.map +1 -0
  105. package/dist/cli-bundle/chunks/{chunk-AGD4VZXH.js → chunk-H2QBAKLQ.js} +3 -3
  106. package/dist/cli-bundle/chunks/{chunk-CJVQ4XIG.js → chunk-HAMLIWAF.js} +4 -4
  107. package/dist/cli-bundle/chunks/{chunk-56DX6QYG.js → chunk-HL7V2PHX.js} +19 -13
  108. package/dist/cli-bundle/chunks/chunk-HL7V2PHX.js.map +1 -0
  109. package/dist/cli-bundle/chunks/{chunk-7QOIQTPB.js → chunk-HLHSQ5CA.js} +4 -4
  110. package/dist/cli-bundle/chunks/{chunk-AHC7J6XD.js → chunk-IA3YFTXT.js} +6 -6
  111. package/dist/cli-bundle/chunks/{chunk-5ZCVF4WF.js → chunk-IAPHYPRL.js} +2 -2
  112. package/dist/cli-bundle/chunks/{chunk-OCSQWIOW.js → chunk-IFZA4VB5.js} +4 -4
  113. package/dist/cli-bundle/chunks/{chunk-6O2HJENY.js → chunk-IGED7NH2.js} +61 -48
  114. package/dist/cli-bundle/chunks/chunk-IGED7NH2.js.map +7 -0
  115. package/dist/cli-bundle/chunks/{chunk-RPCCQDG2.js → chunk-ILLUE5DI.js} +36 -14
  116. package/dist/cli-bundle/chunks/chunk-ILLUE5DI.js.map +7 -0
  117. package/dist/cli-bundle/chunks/{chunk-4WMFM77X.js → chunk-J4NZOP3I.js} +5 -5
  118. package/dist/cli-bundle/chunks/{chunk-57JVERX3.js → chunk-JAF4TUQ7.js} +4 -4
  119. package/dist/cli-bundle/chunks/chunk-JAF4TUQ7.js.map +7 -0
  120. package/dist/cli-bundle/chunks/{chunk-MTNKSSSO.js → chunk-JL7WZ4O2.js} +3 -3
  121. package/dist/cli-bundle/chunks/{chunk-AZ52LTCY.js → chunk-K7WNZ7KD.js} +3 -3
  122. package/dist/cli-bundle/chunks/{chunk-2OLSXXIV.js → chunk-KADLSPIU.js} +4 -4
  123. package/dist/cli-bundle/chunks/{chunk-RQKORMM4.js → chunk-KB726FMH.js} +4 -4
  124. package/dist/cli-bundle/chunks/{chunk-WKSFBBZT.js → chunk-L24HCJFC.js} +114 -25
  125. package/dist/cli-bundle/chunks/chunk-L24HCJFC.js.map +1 -0
  126. package/dist/cli-bundle/chunks/{chunk-LDO24J5I.js → chunk-LWTIRS3Y.js} +365 -43
  127. package/dist/cli-bundle/chunks/chunk-LWTIRS3Y.js.map +7 -0
  128. package/dist/cli-bundle/chunks/{chunk-TZTQ4TVV.js → chunk-M6ASXYCU.js} +4 -4
  129. package/dist/cli-bundle/chunks/{chunk-WDDOAU7Z.js → chunk-M7EWN4TF.js} +3 -3
  130. package/dist/cli-bundle/chunks/{chunk-327DSGW2.js → chunk-MD6ULIPJ.js} +3 -3
  131. package/dist/cli-bundle/chunks/{chunk-OKDBHOON.js → chunk-MKL4CP2I.js} +61 -48
  132. package/dist/cli-bundle/chunks/chunk-MKL4CP2I.js.map +1 -0
  133. package/dist/cli-bundle/chunks/{chunk-M52DG2QJ.js → chunk-MQZ3PLCF.js} +2 -2
  134. package/dist/cli-bundle/chunks/{chunk-GQ2CQNGI.js → chunk-N3CMP4NI.js} +2 -2
  135. package/dist/cli-bundle/chunks/{chunk-J7SBFUZC.js → chunk-NAQYVWSQ.js} +4 -4
  136. package/dist/cli-bundle/chunks/{chunk-U2GMYP3L.js → chunk-NKW36AMT.js} +4 -4
  137. package/dist/cli-bundle/chunks/{chunk-5WEYOVZ7.js → chunk-OBDLEQG5.js} +19 -12
  138. package/dist/cli-bundle/chunks/chunk-OBDLEQG5.js.map +7 -0
  139. package/dist/cli-bundle/chunks/{chunk-VL4LYTJN.js → chunk-OI4S4KCI.js} +18 -12
  140. package/dist/cli-bundle/chunks/chunk-OI4S4KCI.js.map +7 -0
  141. package/dist/cli-bundle/chunks/{chunk-FCVVMAEX.js → chunk-P6MYFH6K.js} +60 -22
  142. package/dist/cli-bundle/chunks/chunk-P6MYFH6K.js.map +1 -0
  143. package/dist/cli-bundle/chunks/{chunk-FTQQAPRX.js → chunk-PHKP3AGR.js} +8 -8
  144. package/dist/cli-bundle/chunks/{chunk-WVUXNIYO.js → chunk-Q37E63AM.js} +4 -4
  145. package/dist/cli-bundle/chunks/{chunk-JVXV7ANV.js → chunk-Q7E6OYZK.js} +2 -2
  146. package/dist/cli-bundle/chunks/{chunk-WVUYATII.js → chunk-QABYZYLU.js} +4 -4
  147. package/dist/cli-bundle/chunks/{chunk-QRRUGIJN.js → chunk-QASRVKUQ.js} +45 -45
  148. package/dist/cli-bundle/chunks/chunk-QASRVKUQ.js.map +1 -0
  149. package/dist/cli-bundle/chunks/{chunk-L4262MFB.js → chunk-QK2ZN6UL.js} +14 -5
  150. package/dist/cli-bundle/chunks/{chunk-L4262MFB.js.map → chunk-QK2ZN6UL.js.map} +1 -1
  151. package/dist/cli-bundle/chunks/{chunk-7TQPV7HR.js → chunk-QSPARJWF.js} +2 -2
  152. package/dist/cli-bundle/chunks/{chunk-GTKILM6F.js → chunk-QZ7LT3XE.js} +3 -3
  153. package/dist/cli-bundle/chunks/{chunk-L3VKY6R6.js → chunk-RA5AIAMP.js} +3 -3
  154. package/dist/cli-bundle/chunks/{chunk-BJS27ALI.js → chunk-RGXD5JJR.js} +6 -6
  155. package/dist/cli-bundle/chunks/{chunk-TSEPW2P6.js → chunk-RMF3IOYQ.js} +7 -7
  156. package/dist/cli-bundle/chunks/{chunk-QXYKH56X.js → chunk-T4BRCB6Z.js} +1894 -1875
  157. package/dist/cli-bundle/chunks/chunk-T4BRCB6Z.js.map +7 -0
  158. package/dist/cli-bundle/chunks/{chunk-TGGTXC52.js → chunk-TH7U4KLY.js} +3 -3
  159. package/dist/cli-bundle/chunks/{chunk-LP4UATP6.js → chunk-TWLDBKQU.js} +3 -3
  160. package/dist/cli-bundle/chunks/{chunk-OTZ3C2NE.js → chunk-TZ2PSLLT.js} +49 -28
  161. package/dist/cli-bundle/chunks/chunk-TZ2PSLLT.js.map +1 -0
  162. package/dist/cli-bundle/chunks/{chunk-UK222BHQ.js → chunk-TZRTLMWM.js} +4 -4
  163. package/dist/cli-bundle/chunks/{chunk-6E6S2X6S.js → chunk-UB2QYSTO.js} +8 -8
  164. package/dist/cli-bundle/chunks/{chunk-S6CXUSYC.js → chunk-UGTVWL3E.js} +5 -5
  165. package/dist/cli-bundle/chunks/{chunk-BNS6QHTZ.js → chunk-UJ4HJYWL.js} +2 -2
  166. package/dist/cli-bundle/chunks/{chunk-BYVOEJPQ.js → chunk-UKUIIBDW.js} +4 -4
  167. package/dist/cli-bundle/chunks/{chunk-SGDBVR7X.js → chunk-UVBA6F5A.js} +2 -2
  168. package/dist/cli-bundle/chunks/{chunk-DZRZMBBF.js → chunk-VJTAEIPC.js} +5 -5
  169. package/dist/cli-bundle/chunks/{chunk-74PWVJON.js → chunk-W6HZ55JO.js} +2 -2
  170. package/dist/cli-bundle/chunks/{chunk-HR2MQAO5.js → chunk-WD6MSYMP.js} +13 -4
  171. package/dist/cli-bundle/chunks/{chunk-HR2MQAO5.js.map → chunk-WD6MSYMP.js.map} +2 -2
  172. package/dist/cli-bundle/chunks/{chunk-P7IFURWH.js → chunk-WPAWZW7S.js} +2 -2
  173. package/dist/cli-bundle/chunks/{chunk-36LEOWSX.js → chunk-WQUEHPZB.js} +2 -2
  174. package/dist/cli-bundle/chunks/{chunk-FCKJF7G2.js → chunk-WRKB56FC.js} +3 -3
  175. package/dist/cli-bundle/chunks/{chunk-KR5EHAN4.js → chunk-X3GYR4P2.js} +2 -2
  176. package/dist/cli-bundle/chunks/{chunk-J567OZJY.js → chunk-X6BVXQ52.js} +16 -12
  177. package/dist/cli-bundle/chunks/chunk-X6BVXQ52.js.map +1 -0
  178. package/dist/cli-bundle/chunks/chunk-Y72FV7RM.js +178 -0
  179. package/dist/cli-bundle/chunks/chunk-Y72FV7RM.js.map +7 -0
  180. package/dist/cli-bundle/chunks/{chunk-OWW2KXOV.js → chunk-YQYG2V23.js} +2 -2
  181. package/dist/cli-bundle/chunks/{chunk-G2SCT7BC.js → chunk-YVKE5ZDM.js} +4 -4
  182. package/dist/cli-bundle/chunks/{chunk-QHIN4UTF.js → chunk-ZAYYDNB3.js} +4 -4
  183. package/dist/cli-bundle/chunks/chunk-ZHBI2AP7.js +9 -0
  184. package/dist/cli-bundle/chunks/chunk-ZNP64HOW.js +175 -0
  185. package/dist/cli-bundle/chunks/chunk-ZNP64HOW.js.map +1 -0
  186. package/dist/cli-bundle/chunks/{chunk-GNVBUNJQ.js → chunk-ZTRBSABY.js} +3 -3
  187. package/dist/cli-bundle/chunks/{chunk-PY32KGQU.js → chunk-ZUKSZVBW.js} +5 -5
  188. package/dist/cli-bundle/chunks/{close-CU56F47E.js → close-LZECOMHO.js} +5 -5
  189. package/dist/cli-bundle/chunks/close-RI4JQQHU.js +12 -0
  190. package/dist/cli-bundle/chunks/close-many-LY2XJ52M.js +21 -0
  191. package/dist/cli-bundle/chunks/{close-many-ZQ2WP67J.js → close-many-ZHI6A5TN.js} +12 -12
  192. package/dist/cli-bundle/chunks/comments-35M273DN.js +13 -0
  193. package/dist/cli-bundle/chunks/{comments-UDUMKXL6.js → comments-AJWRTFZ5.js} +7 -7
  194. package/dist/cli-bundle/chunks/{copy-VFHECFBV.js → copy-GMXYKBXT.js} +4 -4
  195. package/dist/cli-bundle/chunks/copy-NPYM7M7U.js +9 -0
  196. package/dist/cli-bundle/chunks/create-F53OBTOU.js +27 -0
  197. package/dist/cli-bundle/chunks/{create-CE2X3SGF.js → create-HU4Q7RJX.js} +11 -9
  198. package/dist/cli-bundle/chunks/{delete-2JXQCHHT.js → delete-GSDZLTRC.js} +4 -4
  199. package/dist/cli-bundle/chunks/delete-ODRWJWAM.js +10 -0
  200. package/dist/cli-bundle/chunks/deps-U57I7EAK.js +16 -0
  201. package/dist/cli-bundle/chunks/{deps-FPXNLO6C.js → deps-WWB7P2GT.js} +7 -4
  202. package/dist/cli-bundle/chunks/docs-G7N4E2JO.js +14 -0
  203. package/dist/cli-bundle/chunks/{docs-AMAR4OHU.js → docs-MQIY2ZQS.js} +7 -7
  204. package/dist/cli-bundle/chunks/files-TBZD7V6H.js +18 -0
  205. package/dist/cli-bundle/chunks/{files-JFHN7DYM.js → files-TTY6N2AV.js} +7 -7
  206. package/dist/cli-bundle/chunks/focus-U5TRVCRS.js +10 -0
  207. package/dist/cli-bundle/chunks/{focus-QFN2RRZ7.js → focus-XT6YVFFX.js} +5 -5
  208. package/dist/cli-bundle/chunks/{history-compact-G34XMABV.js → history-compact-KKVUWB4V.js} +8 -8
  209. package/dist/cli-bundle/chunks/{history-compact-SAHT5D46.js → history-compact-M7GHYVFN.js} +8 -8
  210. package/dist/cli-bundle/chunks/{history-redact-IFJDNKLZ.js → history-redact-3DVZOILD.js} +6 -6
  211. package/dist/cli-bundle/chunks/history-redact-JIHZLHDP.js +16 -0
  212. package/dist/cli-bundle/chunks/{history-repair-NXLQTCVN.js → history-repair-ITDUMK4N.js} +8 -8
  213. package/dist/cli-bundle/chunks/history-repair-NAFCHLH7.js +18 -0
  214. package/dist/cli-bundle/chunks/{learnings-5CZKAMBS.js → learnings-FGO3NSFW.js} +7 -7
  215. package/dist/cli-bundle/chunks/learnings-SONGPSHI.js +13 -0
  216. package/dist/cli-bundle/chunks/notes-BSD53H2W.js +13 -0
  217. package/dist/cli-bundle/chunks/{notes-POMK37UI.js → notes-NQ6RXVW6.js} +7 -7
  218. package/dist/cli-bundle/chunks/{plan-YBNYNT3A.js → plan-2NNEO46V.js} +10 -10
  219. package/dist/cli-bundle/chunks/plan-AWLYGBNV.js +24 -0
  220. package/dist/cli-bundle/chunks/{profile-JNKSU6EQ.js → profile-AAQUU6T3.js} +9 -9
  221. package/dist/cli-bundle/chunks/{profile-A2WPVG6I.js → profile-U725ATWZ.js} +9 -9
  222. package/dist/cli-bundle/chunks/{register-list-query-UG4ZA5AU.js → register-list-query-BUWCYHBT.js} +14 -13
  223. package/dist/cli-bundle/chunks/{register-list-query-UG4ZA5AU.js.map → register-list-query-BUWCYHBT.js.map} +1 -1
  224. package/dist/cli-bundle/chunks/{register-list-query-KJULL4W3.js → register-list-query-KTZ6AGE7.js} +16 -15
  225. package/dist/cli-bundle/chunks/{register-list-query-KJULL4W3.js.map → register-list-query-KTZ6AGE7.js.map} +1 -1
  226. package/dist/cli-bundle/chunks/{register-mutation-3OXYXBKH.js → register-mutation-4FMGJJF7.js} +29 -29
  227. package/dist/cli-bundle/chunks/{register-mutation-WK265BM7.js → register-mutation-UELYYOR7.js} +29 -29
  228. package/dist/cli-bundle/chunks/{register-operations-C5SQH3FJ.js → register-operations-ISUX6LY5.js} +33 -29
  229. package/dist/cli-bundle/chunks/{register-operations-C5SQH3FJ.js.map → register-operations-ISUX6LY5.js.map} +1 -1
  230. package/dist/cli-bundle/chunks/{register-operations-FH3PBHYN.js → register-operations-JVW24J2Y.js} +35 -31
  231. package/dist/cli-bundle/chunks/{register-operations-FH3PBHYN.js.map → register-operations-JVW24J2Y.js.map} +1 -1
  232. package/dist/cli-bundle/chunks/{register-setup-CCK7CJVR.js → register-setup-5XNGKJ22.js} +15 -15
  233. package/dist/cli-bundle/chunks/{register-setup-CPZBGSOJ.js → register-setup-ZTNY6S7R.js} +15 -15
  234. package/dist/cli-bundle/chunks/restore-66GLMHIX.js +14 -0
  235. package/dist/cli-bundle/chunks/{restore-IVS5XGYR.js → restore-B3BAB6X2.js} +6 -6
  236. package/dist/cli-bundle/chunks/{schema-P2MF23JO.js → schema-LZNUYHDB.js} +6 -6
  237. package/dist/cli-bundle/chunks/schema-LZNUYHDB.js.map +7 -0
  238. package/dist/cli-bundle/chunks/{schema-R3U2REY4.js → schema-U7IM2DXV.js} +6 -6
  239. package/dist/cli-bundle/chunks/schema-U7IM2DXV.js.map +1 -0
  240. package/dist/cli-bundle/chunks/update-2XGHIVQ2.js +21 -0
  241. package/dist/cli-bundle/chunks/update-2XGHIVQ2.js.map +7 -0
  242. package/dist/cli-bundle/chunks/{update-YBIQESMH.js → update-Q3UCILNR.js} +12 -12
  243. package/dist/cli-bundle/chunks/update-Q3UCILNR.js.map +1 -0
  244. package/dist/cli-bundle/chunks/{update-many-F3CIV5SQ.js → update-many-75K57FS3.js} +19 -19
  245. package/dist/cli-bundle/chunks/update-many-75K57FS3.js.map +1 -0
  246. package/dist/cli-bundle/chunks/update-many-U42YA445.js +30 -0
  247. package/dist/cli-bundle/chunks/update-many-U42YA445.js.map +7 -0
  248. package/dist/cli-bundle/main.js +39 -16
  249. package/dist/cli-bundle/main.js.map +2 -2
  250. package/dist/cli-bundle/sdk-runtime.js +56 -53
  251. package/dist/cli-bundle/sdk-testing.js +6 -6
  252. package/dist/cli-bundle/sdk.js +115 -55
  253. package/dist/cli-bundle/sdk.js.map +2 -2
  254. package/dist/core/extensions/command-hook-context.d.ts +40 -0
  255. package/dist/core/extensions/command-hook-context.js +14 -0
  256. package/dist/core/extensions/command-hook-context.js.map +1 -0
  257. package/dist/core/extensions/index.d.ts +1 -0
  258. package/dist/core/extensions/index.js +4 -3
  259. package/dist/core/extensions/index.js.map +1 -1
  260. package/dist/core/item/parse.d.ts +2 -0
  261. package/dist/core/item/parse.js +11 -2
  262. package/dist/core/item/parse.js.map +1 -1
  263. package/dist/core/store/paths.d.ts +2 -0
  264. package/dist/core/store/paths.js +10 -2
  265. package/dist/core/store/paths.js.map +1 -1
  266. package/dist/mcp/tool-definitions.js +12 -2
  267. package/dist/mcp/tool-definitions.js.map +1 -1
  268. package/dist/sdk/context-packing.d.ts +114 -0
  269. package/dist/sdk/context-packing.js +219 -0
  270. package/dist/sdk/context-packing.js.map +1 -0
  271. package/dist/sdk/context-relevance.d.ts +1 -1
  272. package/dist/sdk/context-relevance.js +4 -2
  273. package/dist/sdk/context-relevance.js.map +1 -1
  274. package/dist/sdk/context-usage.d.ts +79 -0
  275. package/dist/sdk/context-usage.js +193 -0
  276. package/dist/sdk/context-usage.js.map +1 -0
  277. package/dist/sdk/dependencies.d.ts +145 -0
  278. package/dist/sdk/dependencies.js +327 -0
  279. package/dist/sdk/dependencies.js.map +1 -0
  280. package/dist/sdk/docs.d.ts +48 -0
  281. package/dist/sdk/docs.js +15 -0
  282. package/dist/sdk/docs.js.map +1 -0
  283. package/dist/sdk/files.d.ts +135 -0
  284. package/dist/sdk/files.js +320 -0
  285. package/dist/sdk/files.js.map +1 -0
  286. package/dist/sdk/index.d.ts +6 -0
  287. package/dist/sdk/index.js +8 -2
  288. package/dist/sdk/index.js.map +1 -1
  289. package/dist/{cli/commands → sdk}/linked-artifacts.d.ts +11 -5
  290. package/dist/{cli/commands → sdk}/linked-artifacts.js +49 -25
  291. package/dist/sdk/linked-artifacts.js.map +1 -0
  292. package/dist/sdk/runtime.d.ts +4 -4
  293. package/dist/sdk/runtime.js +7 -4
  294. package/dist/sdk/runtime.js.map +1 -1
  295. package/dist/sdk/workspace.js +3 -2
  296. package/dist/sdk/workspace.js.map +1 -1
  297. package/docs/AGENT_GUIDE.md +1 -1
  298. package/docs/CONFIGURATION.md +1 -0
  299. package/docs/PR_REVIEW_LOOP.md +21 -11
  300. package/docs/SDK.md +94 -0
  301. package/marketplace.json +2 -2
  302. package/package.json +1 -1
  303. package/packages/pm-beads/package.json +1 -1
  304. package/packages/pm-calendar/package.json +1 -1
  305. package/packages/pm-command-kit/package.json +1 -1
  306. package/packages/pm-governance-audit/package.json +1 -1
  307. package/packages/pm-guide-shell/package.json +1 -1
  308. package/packages/pm-kanban/package.json +1 -1
  309. package/packages/pm-lifecycle-hooks/package.json +1 -1
  310. package/packages/pm-linked-test-adapters/package.json +1 -1
  311. package/packages/pm-search-advanced/package.json +1 -1
  312. package/packages/pm-templates/package.json +1 -1
  313. package/packages/pm-todos/package.json +1 -1
  314. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  315. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  316. package/dist/cli/commands/linked-artifacts.js.map +0 -1
  317. package/dist/cli-bundle/chunks/append-CTKFDEAX.js +0 -11
  318. package/dist/cli-bundle/chunks/chunk-56DX6QYG.js.map +0 -1
  319. package/dist/cli-bundle/chunks/chunk-57JVERX3.js.map +0 -7
  320. package/dist/cli-bundle/chunks/chunk-5WEYOVZ7.js.map +0 -7
  321. package/dist/cli-bundle/chunks/chunk-6O2HJENY.js.map +0 -7
  322. package/dist/cli-bundle/chunks/chunk-CCAGZCZK.js +0 -17
  323. package/dist/cli-bundle/chunks/chunk-CCAGZCZK.js.map +0 -7
  324. package/dist/cli-bundle/chunks/chunk-D2LXG7WX.js.map +0 -1
  325. package/dist/cli-bundle/chunks/chunk-DGJF32JF.js.map +0 -7
  326. package/dist/cli-bundle/chunks/chunk-FCVVMAEX.js.map +0 -1
  327. package/dist/cli-bundle/chunks/chunk-FUOK7JZ6.js +0 -14
  328. package/dist/cli-bundle/chunks/chunk-FUOK7JZ6.js.map +0 -1
  329. package/dist/cli-bundle/chunks/chunk-G3IB5GTD.js.map +0 -7
  330. package/dist/cli-bundle/chunks/chunk-J567OZJY.js.map +0 -1
  331. package/dist/cli-bundle/chunks/chunk-LDO24J5I.js.map +0 -7
  332. package/dist/cli-bundle/chunks/chunk-NA5SBIB4.js.map +0 -7
  333. package/dist/cli-bundle/chunks/chunk-OKDBHOON.js.map +0 -1
  334. package/dist/cli-bundle/chunks/chunk-OMT4NO7T.js.map +0 -7
  335. package/dist/cli-bundle/chunks/chunk-OTZ3C2NE.js.map +0 -1
  336. package/dist/cli-bundle/chunks/chunk-QRRUGIJN.js.map +0 -1
  337. package/dist/cli-bundle/chunks/chunk-QXYKH56X.js.map +0 -7
  338. package/dist/cli-bundle/chunks/chunk-RKGFUC4O.js.map +0 -1
  339. package/dist/cli-bundle/chunks/chunk-RPCCQDG2.js.map +0 -7
  340. package/dist/cli-bundle/chunks/chunk-TGG7YGMC.js.map +0 -1
  341. package/dist/cli-bundle/chunks/chunk-TNGLCRKS.js.map +0 -1
  342. package/dist/cli-bundle/chunks/chunk-UTYNQ2WH.js.map +0 -7
  343. package/dist/cli-bundle/chunks/chunk-VL4LYTJN.js.map +0 -7
  344. package/dist/cli-bundle/chunks/chunk-VLFLRFJP.js.map +0 -1
  345. package/dist/cli-bundle/chunks/chunk-WKSFBBZT.js.map +0 -1
  346. package/dist/cli-bundle/chunks/chunk-XY3CC3EM.js.map +0 -7
  347. package/dist/cli-bundle/chunks/chunk-ZTSV7P2T.js.map +0 -1
  348. package/dist/cli-bundle/chunks/close-BWM7FTF4.js +0 -12
  349. package/dist/cli-bundle/chunks/close-many-AUHTVFUQ.js +0 -21
  350. package/dist/cli-bundle/chunks/comments-7D5VPBZI.js +0 -13
  351. package/dist/cli-bundle/chunks/copy-QJ6ZVWZV.js +0 -9
  352. package/dist/cli-bundle/chunks/create-FGMTTYOI.js +0 -25
  353. package/dist/cli-bundle/chunks/delete-L2GMMMPR.js +0 -10
  354. package/dist/cli-bundle/chunks/deps-KTFI4RWD.js +0 -13
  355. package/dist/cli-bundle/chunks/docs-VNURA275.js +0 -14
  356. package/dist/cli-bundle/chunks/files-UNFPZLTG.js +0 -18
  357. package/dist/cli-bundle/chunks/focus-MI2UHBP4.js +0 -10
  358. package/dist/cli-bundle/chunks/history-redact-VAHGBUHI.js +0 -16
  359. package/dist/cli-bundle/chunks/history-repair-DDYQXR43.js +0 -18
  360. package/dist/cli-bundle/chunks/learnings-VWJEKHEO.js +0 -13
  361. package/dist/cli-bundle/chunks/notes-NGVJJJQO.js +0 -13
  362. package/dist/cli-bundle/chunks/plan-U6SQJUFI.js +0 -24
  363. package/dist/cli-bundle/chunks/restore-AX6ZMGHZ.js +0 -14
  364. package/dist/cli-bundle/chunks/update-XYHF3YZF.js +0 -21
  365. package/dist/cli-bundle/chunks/update-many-5HKVHFUL.js +0 -30
  366. /package/dist/cli-bundle/chunks/{append-CTKFDEAX.js.map → append-DYQWQK2J.js.map} +0 -0
  367. /package/dist/cli-bundle/chunks/{append-2FS6MVG7.js.map → append-PVZJDM6J.js.map} +0 -0
  368. /package/dist/cli-bundle/chunks/{chunk-J2WAWP4U.js.map → chunk-2FNWQXZ2.js.map} +0 -0
  369. /package/dist/cli-bundle/chunks/{chunk-YFGYDZRP.js.map → chunk-2GA3NK35.js.map} +0 -0
  370. /package/dist/cli-bundle/chunks/{chunk-XFEIASAC.js.map → chunk-2QIQGYPW.js.map} +0 -0
  371. /package/dist/cli-bundle/chunks/{chunk-3WCGYH5Q.js.map → chunk-3CMRNVTO.js.map} +0 -0
  372. /package/dist/cli-bundle/chunks/{close-BWM7FTF4.js.map → chunk-3HKUXVKV.js.map} +0 -0
  373. /package/dist/cli-bundle/chunks/{chunk-VDAZPPRU.js.map → chunk-3I3LRT2G.js.map} +0 -0
  374. /package/dist/cli-bundle/chunks/{chunk-3P3RFJIQ.js.map → chunk-3TL7WOEF.js.map} +0 -0
  375. /package/dist/cli-bundle/chunks/{chunk-4SHJ5JS3.js.map → chunk-44LNIULG.js.map} +0 -0
  376. /package/dist/cli-bundle/chunks/{chunk-BVCF4ULV.js.map → chunk-4RXTMU57.js.map} +0 -0
  377. /package/dist/cli-bundle/chunks/{chunk-XMI2TRY5.js.map → chunk-4WREH7RT.js.map} +0 -0
  378. /package/dist/cli-bundle/chunks/{chunk-JYUGUXFW.js.map → chunk-5CT5BW6E.js.map} +0 -0
  379. /package/dist/cli-bundle/chunks/{chunk-QGH6WL6L.js.map → chunk-655STMGA.js.map} +0 -0
  380. /package/dist/cli-bundle/chunks/{chunk-DGKBWCMA.js.map → chunk-6IIVBC56.js.map} +0 -0
  381. /package/dist/cli-bundle/chunks/{chunk-D4GPNYYP.js.map → chunk-6OTZMORS.js.map} +0 -0
  382. /package/dist/cli-bundle/chunks/{chunk-JVRVXO6M.js.map → chunk-6PKA3SJQ.js.map} +0 -0
  383. /package/dist/cli-bundle/chunks/{close-many-AUHTVFUQ.js.map → chunk-6X5MZ5R2.js.map} +0 -0
  384. /package/dist/cli-bundle/chunks/{close-CU56F47E.js.map → chunk-76UBY2EE.js.map} +0 -0
  385. /package/dist/cli-bundle/chunks/{chunk-ZS2KPCJN.js.map → chunk-7QDSYUMF.js.map} +0 -0
  386. /package/dist/cli-bundle/chunks/{chunk-Z7TFPIJ6.js.map → chunk-7TQMR6LK.js.map} +0 -0
  387. /package/dist/cli-bundle/chunks/{chunk-AHA4POA6.js.map → chunk-ABRCOSDC.js.map} +0 -0
  388. /package/dist/cli-bundle/chunks/{chunk-KQJVTQVK.js.map → chunk-ANSJHDOZ.js.map} +0 -0
  389. /package/dist/cli-bundle/chunks/{close-many-ZQ2WP67J.js.map → chunk-B7SWOIP6.js.map} +0 -0
  390. /package/dist/cli-bundle/chunks/{chunk-HXTCZSAI.js.map → chunk-DBZVUJTK.js.map} +0 -0
  391. /package/dist/cli-bundle/chunks/{chunk-2QNOWOIB.js.map → chunk-DO5RGJXT.js.map} +0 -0
  392. /package/dist/cli-bundle/chunks/{chunk-MKONZ4UO.js.map → chunk-DRNJPEPQ.js.map} +0 -0
  393. /package/dist/cli-bundle/chunks/{chunk-H36FXA7B.js.map → chunk-DYEX6NFH.js.map} +0 -0
  394. /package/dist/cli-bundle/chunks/{chunk-GAJ7U7B4.js.map → chunk-ERL2YFJ2.js.map} +0 -0
  395. /package/dist/cli-bundle/chunks/{chunk-FPEYOFEF.js.map → chunk-F7PSHRNO.js.map} +0 -0
  396. /package/dist/cli-bundle/chunks/{chunk-UH7OLT6F.js.map → chunk-FDSBDNYE.js.map} +0 -0
  397. /package/dist/cli-bundle/chunks/{chunk-RQAY7C5T.js.map → chunk-FJZDA6MS.js.map} +0 -0
  398. /package/dist/cli-bundle/chunks/{chunk-B4TVNGRX.js.map → chunk-FO7GMJKG.js.map} +0 -0
  399. /package/dist/cli-bundle/chunks/{comments-UDUMKXL6.js.map → chunk-FRQ63VPB.js.map} +0 -0
  400. /package/dist/cli-bundle/chunks/{chunk-U252II47.js.map → chunk-FTQLW4JD.js.map} +0 -0
  401. /package/dist/cli-bundle/chunks/{chunk-AGD4VZXH.js.map → chunk-H2QBAKLQ.js.map} +0 -0
  402. /package/dist/cli-bundle/chunks/{chunk-CJVQ4XIG.js.map → chunk-HAMLIWAF.js.map} +0 -0
  403. /package/dist/cli-bundle/chunks/{chunk-7QOIQTPB.js.map → chunk-HLHSQ5CA.js.map} +0 -0
  404. /package/dist/cli-bundle/chunks/{chunk-AHC7J6XD.js.map → chunk-IA3YFTXT.js.map} +0 -0
  405. /package/dist/cli-bundle/chunks/{chunk-5ZCVF4WF.js.map → chunk-IAPHYPRL.js.map} +0 -0
  406. /package/dist/cli-bundle/chunks/{chunk-OCSQWIOW.js.map → chunk-IFZA4VB5.js.map} +0 -0
  407. /package/dist/cli-bundle/chunks/{chunk-4WMFM77X.js.map → chunk-J4NZOP3I.js.map} +0 -0
  408. /package/dist/cli-bundle/chunks/{chunk-MTNKSSSO.js.map → chunk-JL7WZ4O2.js.map} +0 -0
  409. /package/dist/cli-bundle/chunks/{chunk-AZ52LTCY.js.map → chunk-K7WNZ7KD.js.map} +0 -0
  410. /package/dist/cli-bundle/chunks/{chunk-2OLSXXIV.js.map → chunk-KADLSPIU.js.map} +0 -0
  411. /package/dist/cli-bundle/chunks/{chunk-RQKORMM4.js.map → chunk-KB726FMH.js.map} +0 -0
  412. /package/dist/cli-bundle/chunks/{chunk-TZTQ4TVV.js.map → chunk-M6ASXYCU.js.map} +0 -0
  413. /package/dist/cli-bundle/chunks/{chunk-WDDOAU7Z.js.map → chunk-M7EWN4TF.js.map} +0 -0
  414. /package/dist/cli-bundle/chunks/{chunk-327DSGW2.js.map → chunk-MD6ULIPJ.js.map} +0 -0
  415. /package/dist/cli-bundle/chunks/{chunk-M52DG2QJ.js.map → chunk-MQZ3PLCF.js.map} +0 -0
  416. /package/dist/cli-bundle/chunks/{chunk-GQ2CQNGI.js.map → chunk-N3CMP4NI.js.map} +0 -0
  417. /package/dist/cli-bundle/chunks/{chunk-J7SBFUZC.js.map → chunk-NAQYVWSQ.js.map} +0 -0
  418. /package/dist/cli-bundle/chunks/{chunk-U2GMYP3L.js.map → chunk-NKW36AMT.js.map} +0 -0
  419. /package/dist/cli-bundle/chunks/{chunk-FTQQAPRX.js.map → chunk-PHKP3AGR.js.map} +0 -0
  420. /package/dist/cli-bundle/chunks/{chunk-WVUXNIYO.js.map → chunk-Q37E63AM.js.map} +0 -0
  421. /package/dist/cli-bundle/chunks/{chunk-JVXV7ANV.js.map → chunk-Q7E6OYZK.js.map} +0 -0
  422. /package/dist/cli-bundle/chunks/{chunk-WVUYATII.js.map → chunk-QABYZYLU.js.map} +0 -0
  423. /package/dist/cli-bundle/chunks/{chunk-7TQPV7HR.js.map → chunk-QSPARJWF.js.map} +0 -0
  424. /package/dist/cli-bundle/chunks/{chunk-GTKILM6F.js.map → chunk-QZ7LT3XE.js.map} +0 -0
  425. /package/dist/cli-bundle/chunks/{chunk-L3VKY6R6.js.map → chunk-RA5AIAMP.js.map} +0 -0
  426. /package/dist/cli-bundle/chunks/{chunk-BJS27ALI.js.map → chunk-RGXD5JJR.js.map} +0 -0
  427. /package/dist/cli-bundle/chunks/{chunk-TSEPW2P6.js.map → chunk-RMF3IOYQ.js.map} +0 -0
  428. /package/dist/cli-bundle/chunks/{chunk-TGGTXC52.js.map → chunk-TH7U4KLY.js.map} +0 -0
  429. /package/dist/cli-bundle/chunks/{chunk-LP4UATP6.js.map → chunk-TWLDBKQU.js.map} +0 -0
  430. /package/dist/cli-bundle/chunks/{chunk-UK222BHQ.js.map → chunk-TZRTLMWM.js.map} +0 -0
  431. /package/dist/cli-bundle/chunks/{chunk-6E6S2X6S.js.map → chunk-UB2QYSTO.js.map} +0 -0
  432. /package/dist/cli-bundle/chunks/{chunk-S6CXUSYC.js.map → chunk-UGTVWL3E.js.map} +0 -0
  433. /package/dist/cli-bundle/chunks/{chunk-BNS6QHTZ.js.map → chunk-UJ4HJYWL.js.map} +0 -0
  434. /package/dist/cli-bundle/chunks/{chunk-BYVOEJPQ.js.map → chunk-UKUIIBDW.js.map} +0 -0
  435. /package/dist/cli-bundle/chunks/{chunk-SGDBVR7X.js.map → chunk-UVBA6F5A.js.map} +0 -0
  436. /package/dist/cli-bundle/chunks/{chunk-DZRZMBBF.js.map → chunk-VJTAEIPC.js.map} +0 -0
  437. /package/dist/cli-bundle/chunks/{chunk-74PWVJON.js.map → chunk-W6HZ55JO.js.map} +0 -0
  438. /package/dist/cli-bundle/chunks/{chunk-P7IFURWH.js.map → chunk-WPAWZW7S.js.map} +0 -0
  439. /package/dist/cli-bundle/chunks/{chunk-36LEOWSX.js.map → chunk-WQUEHPZB.js.map} +0 -0
  440. /package/dist/cli-bundle/chunks/{chunk-FCKJF7G2.js.map → chunk-WRKB56FC.js.map} +0 -0
  441. /package/dist/cli-bundle/chunks/{chunk-KR5EHAN4.js.map → chunk-X3GYR4P2.js.map} +0 -0
  442. /package/dist/cli-bundle/chunks/{chunk-OWW2KXOV.js.map → chunk-YQYG2V23.js.map} +0 -0
  443. /package/dist/cli-bundle/chunks/{chunk-G2SCT7BC.js.map → chunk-YVKE5ZDM.js.map} +0 -0
  444. /package/dist/cli-bundle/chunks/{chunk-QHIN4UTF.js.map → chunk-ZAYYDNB3.js.map} +0 -0
  445. /package/dist/cli-bundle/chunks/{comments-7D5VPBZI.js.map → chunk-ZHBI2AP7.js.map} +0 -0
  446. /package/dist/cli-bundle/chunks/{chunk-GNVBUNJQ.js.map → chunk-ZTRBSABY.js.map} +0 -0
  447. /package/dist/cli-bundle/chunks/{chunk-PY32KGQU.js.map → chunk-ZUKSZVBW.js.map} +0 -0
  448. /package/dist/cli-bundle/chunks/{copy-VFHECFBV.js.map → close-LZECOMHO.js.map} +0 -0
  449. /package/dist/cli-bundle/chunks/{copy-QJ6ZVWZV.js.map → close-RI4JQQHU.js.map} +0 -0
  450. /package/dist/cli-bundle/chunks/{create-FGMTTYOI.js.map → close-many-LY2XJ52M.js.map} +0 -0
  451. /package/dist/cli-bundle/chunks/{create-CE2X3SGF.js.map → close-many-ZHI6A5TN.js.map} +0 -0
  452. /package/dist/cli-bundle/chunks/{delete-L2GMMMPR.js.map → comments-35M273DN.js.map} +0 -0
  453. /package/dist/cli-bundle/chunks/{delete-2JXQCHHT.js.map → comments-AJWRTFZ5.js.map} +0 -0
  454. /package/dist/cli-bundle/chunks/{deps-FPXNLO6C.js.map → copy-GMXYKBXT.js.map} +0 -0
  455. /package/dist/cli-bundle/chunks/{deps-KTFI4RWD.js.map → copy-NPYM7M7U.js.map} +0 -0
  456. /package/dist/cli-bundle/chunks/{docs-VNURA275.js.map → create-F53OBTOU.js.map} +0 -0
  457. /package/dist/cli-bundle/chunks/{docs-AMAR4OHU.js.map → create-HU4Q7RJX.js.map} +0 -0
  458. /package/dist/cli-bundle/chunks/{files-JFHN7DYM.js.map → delete-GSDZLTRC.js.map} +0 -0
  459. /package/dist/cli-bundle/chunks/{files-UNFPZLTG.js.map → delete-ODRWJWAM.js.map} +0 -0
  460. /package/dist/cli-bundle/chunks/{focus-MI2UHBP4.js.map → deps-U57I7EAK.js.map} +0 -0
  461. /package/dist/cli-bundle/chunks/{focus-QFN2RRZ7.js.map → deps-WWB7P2GT.js.map} +0 -0
  462. /package/dist/cli-bundle/chunks/{history-compact-SAHT5D46.js.map → docs-G7N4E2JO.js.map} +0 -0
  463. /package/dist/cli-bundle/chunks/{history-compact-G34XMABV.js.map → docs-MQIY2ZQS.js.map} +0 -0
  464. /package/dist/cli-bundle/chunks/{history-redact-VAHGBUHI.js.map → files-TBZD7V6H.js.map} +0 -0
  465. /package/dist/cli-bundle/chunks/{history-redact-IFJDNKLZ.js.map → files-TTY6N2AV.js.map} +0 -0
  466. /package/dist/cli-bundle/chunks/{history-repair-DDYQXR43.js.map → focus-U5TRVCRS.js.map} +0 -0
  467. /package/dist/cli-bundle/chunks/{history-repair-NXLQTCVN.js.map → focus-XT6YVFFX.js.map} +0 -0
  468. /package/dist/cli-bundle/chunks/{learnings-5CZKAMBS.js.map → history-compact-KKVUWB4V.js.map} +0 -0
  469. /package/dist/cli-bundle/chunks/{learnings-VWJEKHEO.js.map → history-compact-M7GHYVFN.js.map} +0 -0
  470. /package/dist/cli-bundle/chunks/{notes-POMK37UI.js.map → history-redact-3DVZOILD.js.map} +0 -0
  471. /package/dist/cli-bundle/chunks/{notes-NGVJJJQO.js.map → history-redact-JIHZLHDP.js.map} +0 -0
  472. /package/dist/cli-bundle/chunks/{plan-YBNYNT3A.js.map → history-repair-ITDUMK4N.js.map} +0 -0
  473. /package/dist/cli-bundle/chunks/{plan-U6SQJUFI.js.map → history-repair-NAFCHLH7.js.map} +0 -0
  474. /package/dist/cli-bundle/chunks/{profile-JNKSU6EQ.js.map → learnings-FGO3NSFW.js.map} +0 -0
  475. /package/dist/cli-bundle/chunks/{profile-A2WPVG6I.js.map → learnings-SONGPSHI.js.map} +0 -0
  476. /package/dist/cli-bundle/chunks/{restore-AX6ZMGHZ.js.map → notes-BSD53H2W.js.map} +0 -0
  477. /package/dist/cli-bundle/chunks/{restore-IVS5XGYR.js.map → notes-NQ6RXVW6.js.map} +0 -0
  478. /package/dist/cli-bundle/chunks/{schema-R3U2REY4.js.map → plan-2NNEO46V.js.map} +0 -0
  479. /package/dist/cli-bundle/chunks/{schema-P2MF23JO.js.map → plan-AWLYGBNV.js.map} +0 -0
  480. /package/dist/cli-bundle/chunks/{update-YBIQESMH.js.map → profile-AAQUU6T3.js.map} +0 -0
  481. /package/dist/cli-bundle/chunks/{update-XYHF3YZF.js.map → profile-U725ATWZ.js.map} +0 -0
  482. /package/dist/cli-bundle/chunks/{register-mutation-3OXYXBKH.js.map → register-mutation-4FMGJJF7.js.map} +0 -0
  483. /package/dist/cli-bundle/chunks/{register-mutation-WK265BM7.js.map → register-mutation-UELYYOR7.js.map} +0 -0
  484. /package/dist/cli-bundle/chunks/{register-setup-CCK7CJVR.js.map → register-setup-5XNGKJ22.js.map} +0 -0
  485. /package/dist/cli-bundle/chunks/{register-setup-CPZBGSOJ.js.map → register-setup-ZTNY6S7R.js.map} +0 -0
  486. /package/dist/cli-bundle/chunks/{update-many-5HKVHFUL.js.map → restore-66GLMHIX.js.map} +0 -0
  487. /package/dist/cli-bundle/chunks/{update-many-F3CIV5SQ.js.map → restore-B3BAB6X2.js.map} +0 -0
@@ -22,6 +22,7 @@ import {
22
22
  appendLineAtomic,
23
23
  coerceFiniteNumber,
24
24
  collectRegisteredItemFieldNames,
25
+ createEmptyExtensionHookRegistry,
25
26
  ensureDir,
26
27
  ensureRuntimeSchemaFileScaffold,
27
28
  evictOldestMemoEntries,
@@ -55,7 +56,24 @@ import {
55
56
  toErrorMessage,
56
57
  weekdayOrderIndex,
57
58
  writeFileAtomic
58
- } from "./chunk-XY3CC3EM.js";
59
+ } from "./chunk-AFWZRL7M.js";
60
+
61
+ // dist/core/extensions/command-hook-context.js
62
+ !(function() {
63
+ try {
64
+ var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
65
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "3efead0c-2ad9-5fa1-af60-57b781a534fc");
66
+ } catch (e2) {
67
+ }
68
+ })();
69
+ function createCoreCommandHookContext(options) {
70
+ return {
71
+ ...options,
72
+ hooks: createEmptyExtensionHookRegistry(),
73
+ profileEnabled: Boolean(options.globalOptions.profile),
74
+ migrationBlockers: []
75
+ };
76
+ }
59
77
 
60
78
  // dist/core/shared/serial-queue.js
61
79
  !(function() {
@@ -98,7 +116,7 @@ function createSerialQueue() {
98
116
  !(function() {
99
117
  try {
100
118
  var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
101
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "6664eb48-fc42-5e7f-83d8-7ab3e9b19f23");
119
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "27bb9504-233c-5768-8932-d1cae84313be");
102
120
  } catch (e2) {
103
121
  }
104
122
  })();
@@ -170,7 +188,7 @@ function getActiveCommandResult() {
170
188
  return activeCommandResult;
171
189
  }
172
190
  function recordAfterCommandAffectedItem(item) {
173
- if (!item || (activeExtensionHooks?.afterCommand?.length ?? 0) === 0) {
191
+ if (!item) {
174
192
  return;
175
193
  }
176
194
  activeAfterCommandAffectedItems.push(item);
@@ -2262,2173 +2280,2173 @@ function resolveIsoOrRelative(input, now = /* @__PURE__ */ new Date(), fieldLabe
2262
2280
  return new Date(timestamp).toISOString();
2263
2281
  }
2264
2282
 
2265
- // dist/core/schema/runtime-field-values.js
2283
+ // dist/core/lock/lock.js
2284
+ import fs from "node:fs/promises";
2285
+ import path from "node:path";
2286
+ import { randomUUID } from "node:crypto";
2266
2287
  !(function() {
2267
2288
  try {
2268
2289
  var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
2269
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "e31fbd91-9662-592e-abd5-1db822ac04eb");
2290
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "d23246e1-c423-5100-bcde-8162e01587f0");
2270
2291
  } catch (e2) {
2271
2292
  }
2272
2293
  })();
2273
- function toCamelToken(value) {
2274
- const segments = value.trim().replaceAll(/[^A-Za-z0-9]+/g, " ").split(/\s+/).filter((segment) => segment.length > 0).map((segment) => segment.toLowerCase());
2275
- if (segments.length === 0) {
2276
- return value;
2294
+ function parseLockInfo(raw) {
2295
+ let parsed;
2296
+ try {
2297
+ parsed = JSON.parse(raw);
2298
+ } catch {
2299
+ return {
2300
+ info: null,
2301
+ warnings: ["lock_info_invalid_json"]
2302
+ };
2277
2303
  }
2278
- const [first, ...rest] = segments;
2279
- return `${first}${rest.map((segment) => `${segment.slice(0, 1).toUpperCase()}${segment.slice(1)}`).join("")}`;
2280
- }
2281
- function resolveCandidateOptionKeys(definition) {
2282
- return [
2283
- .../* @__PURE__ */ new Set([
2284
- runtimeFieldOptionTarget(definition),
2285
- toCamelToken(definition.key),
2286
- toCamelToken(definition.cli_flag),
2287
- ...definition.cli_aliases.map((alias) => toCamelToken(alias))
2288
- ])
2289
- ];
2304
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
2305
+ return {
2306
+ info: null,
2307
+ warnings: ["lock_info_invalid_shape"]
2308
+ };
2309
+ }
2310
+ const candidate = parsed;
2311
+ const id = candidate.id;
2312
+ const pid = candidate.pid;
2313
+ const owner = candidate.owner;
2314
+ const createdAt = candidate.created_at;
2315
+ const ttlSeconds = candidate.ttl_seconds;
2316
+ if (typeof id !== "string" || typeof pid !== "number" || !Number.isFinite(pid) || typeof owner !== "string" || typeof createdAt !== "string" || typeof ttlSeconds !== "number" || !Number.isFinite(ttlSeconds)) {
2317
+ return {
2318
+ info: null,
2319
+ warnings: ["lock_info_invalid_shape"]
2320
+ };
2321
+ }
2322
+ return {
2323
+ info: {
2324
+ id,
2325
+ pid,
2326
+ owner,
2327
+ created_at: createdAt,
2328
+ ttl_seconds: ttlSeconds
2329
+ },
2330
+ warnings: []
2331
+ };
2290
2332
  }
2291
- function readRuntimeFieldOptionValue(options, definition) {
2292
- for (const candidateKey of resolveCandidateOptionKeys(definition)) {
2293
- if (!Object.hasOwn(options, candidateKey)) {
2294
- continue;
2295
- }
2296
- const value = options[candidateKey];
2297
- if (value !== void 0) {
2298
- return value;
2333
+ async function readLockInfo(lockPath) {
2334
+ try {
2335
+ const raw = await fs.readFile(lockPath, "utf8");
2336
+ await runActiveOnReadHooks({
2337
+ path: lockPath,
2338
+ scope: "project"
2339
+ });
2340
+ return parseLockInfo(raw);
2341
+ } catch (error) {
2342
+ if (isErrno(error, "ENOENT")) {
2343
+ return {
2344
+ info: null,
2345
+ warnings: []
2346
+ };
2299
2347
  }
2348
+ return {
2349
+ info: null,
2350
+ warnings: ["lock_info_read_failed"]
2351
+ };
2300
2352
  }
2301
- return void 0;
2302
2353
  }
2303
- function normalizeStringArrayValue(value) {
2304
- if (Array.isArray(value)) {
2305
- return value.flatMap((entry) => normalizeStringArrayValue(entry)).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
2306
- }
2307
- if (typeof value === "string") {
2308
- return value.split(/[,\n|]/).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
2309
- }
2310
- if (value === void 0 || value === null) {
2311
- return [];
2354
+ function isErrno(error, code) {
2355
+ return typeof error === "object" && error !== null && "code" in error && error.code === code;
2356
+ }
2357
+ async function emitLockWriteHook(lockPath, op) {
2358
+ await runActiveOnWriteHooks({
2359
+ path: lockPath,
2360
+ scope: "project",
2361
+ op
2362
+ });
2363
+ }
2364
+ function buildLockPayload(id, owner, ttlSeconds) {
2365
+ return {
2366
+ id,
2367
+ pid: process.pid,
2368
+ owner,
2369
+ created_at: nowIso(),
2370
+ ttl_seconds: ttlSeconds
2371
+ };
2372
+ }
2373
+ async function createLockFile(lockPath, id, owner, ttlSeconds) {
2374
+ await fs.mkdir(path.dirname(lockPath), { recursive: true });
2375
+ const handle = await fs.open(lockPath, "wx");
2376
+ try {
2377
+ await handle.writeFile(`${JSON.stringify(buildLockPayload(id, owner, ttlSeconds), null, 2)}
2378
+ `, "utf8");
2379
+ } finally {
2380
+ await handle.close();
2312
2381
  }
2313
- return [String(value).trim()].filter((entry) => entry.length > 0);
2382
+ await emitLockWriteHook(lockPath, "lock:create");
2314
2383
  }
2315
- function parseBooleanValue(raw, label) {
2316
- if (typeof raw === "boolean") {
2317
- return raw;
2384
+ async function unlinkLockWithHook(lockPath, op) {
2385
+ try {
2386
+ await fs.unlink(lockPath);
2387
+ await emitLockWriteHook(lockPath, op);
2388
+ return true;
2389
+ } catch {
2390
+ return false;
2318
2391
  }
2319
- if (typeof raw === "number") {
2320
- if (raw === 1) {
2321
- return true;
2322
- }
2323
- if (raw === 0) {
2324
- return false;
2392
+ }
2393
+ function isStaleLock(info, ttlSeconds) {
2394
+ const createdAtMs = info?.created_at ? Date.parse(info.created_at) : Number.NaN;
2395
+ const ageMs = Number.isFinite(createdAtMs) ? Date.now() - createdAtMs : Number.POSITIVE_INFINITY;
2396
+ return ageMs > ttlSeconds * 1e3;
2397
+ }
2398
+ function lockOwnerSuffix(info) {
2399
+ return info?.owner ? ` (owner ${info.owner})` : "";
2400
+ }
2401
+ var LOCK_WAIT_INITIAL_DELAY_MS = 25;
2402
+ var LOCK_WAIT_MAX_DELAY_MS = 200;
2403
+ var LOCK_CONFLICT_RETRY_HINT_MS = 250;
2404
+ var MAX_STALE_LOCK_REMOVALS = 3;
2405
+ var STALE_CLEANUP_GATE_SUFFIX = ".stale-cleanup";
2406
+ var STALE_CLEANUP_GATE_OWNER_FILE = "owner.json";
2407
+ var STALE_CLEANUP_GATE_STALE_MS = 1e4;
2408
+ var STALE_CLEANUP_GATE_MAX_ACTIVE_MS = 5 * 6e4;
2409
+ function parseNonNegativeIntegerWaitMs(value) {
2410
+ if (typeof value === "string") {
2411
+ const trimmed = value.trim();
2412
+ if (!/^\d+$/.test(trimmed)) {
2413
+ return void 0;
2325
2414
  }
2415
+ const parsed = Number(trimmed);
2416
+ return Number.isSafeInteger(parsed) ? parsed : void 0;
2326
2417
  }
2327
- if (typeof raw === "string") {
2328
- const normalized = raw.trim().toLowerCase();
2329
- if (normalized === "true" || normalized === "1" || normalized === "yes") {
2330
- return true;
2331
- }
2332
- if (normalized === "false" || normalized === "0" || normalized === "no") {
2333
- return false;
2334
- }
2418
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
2419
+ return Math.trunc(value);
2335
2420
  }
2336
- throw new PmCliError(`${label} must be one of true|false|1|0|yes|no`, EXIT_CODE.USAGE);
2421
+ return void 0;
2337
2422
  }
2338
- function parseNumberValue(raw, label) {
2339
- if (typeof raw === "number" && Number.isFinite(raw)) {
2340
- return raw;
2423
+ function resolveLockWaitMs(waitMs) {
2424
+ const envRaw = process.env.PM_LOCK_WAIT_MS;
2425
+ const envParsed = parseNonNegativeIntegerWaitMs(envRaw);
2426
+ if (envParsed !== void 0) {
2427
+ return envParsed;
2341
2428
  }
2342
- const candidate = typeof raw === "string" ? raw.trim() : String(raw);
2343
- const parsed = Number(candidate);
2344
- if (!Number.isFinite(parsed)) {
2345
- throw new PmCliError(`${label} must be a number`, EXIT_CODE.USAGE);
2429
+ const callerParsed = parseNonNegativeIntegerWaitMs(waitMs);
2430
+ if (callerParsed !== void 0) {
2431
+ return callerParsed;
2346
2432
  }
2347
- return parsed;
2433
+ return 0;
2348
2434
  }
2349
- function coerceRuntimeFieldValue(definition, rawValue, labelOverride) {
2350
- const label = labelOverride ?? `--${definition.cli_flag}`;
2351
- if (definition.repeatable || definition.type === "string_array") {
2352
- const values = normalizeStringArrayValue(rawValue);
2353
- if (definition.type === "number") {
2354
- return values.map((value) => parseNumberValue(value, label));
2355
- }
2356
- if (definition.type === "boolean") {
2357
- return values.map((value) => parseBooleanValue(value, label));
2435
+ function sleepWithJitter(baseDelayMs) {
2436
+ const jitteredMs = Math.max(1, Math.round(baseDelayMs * (0.5 + Math.random())));
2437
+ return new Promise((resolve) => setTimeout(resolve, jitteredMs));
2438
+ }
2439
+ function buildLockConflictError(id, info, waitedMs) {
2440
+ const waitedSuffix = waitedMs > 0 ? ` after waiting ${waitedMs}ms` : "";
2441
+ return new PmCliError(`Item ${id} is locked${lockOwnerSuffix(info)}${waitedSuffix}`, EXIT_CODE.CONFLICT, {
2442
+ code: "lock_conflict",
2443
+ recovery: {
2444
+ retry_after_ms: LOCK_CONFLICT_RETRY_HINT_MS
2358
2445
  }
2359
- return values;
2360
- }
2361
- const scalarRaw = Array.isArray(rawValue) ? rawValue[rawValue.length - 1] : rawValue;
2362
- if (scalarRaw === void 0) {
2363
- return void 0;
2364
- }
2365
- if (definition.type === "number") {
2366
- return parseNumberValue(scalarRaw, label);
2367
- }
2368
- if (definition.type === "boolean") {
2369
- return parseBooleanValue(scalarRaw, label);
2370
- }
2371
- return typeof scalarRaw === "string" ? scalarRaw : String(scalarRaw);
2446
+ });
2372
2447
  }
2373
- function shouldRequireFieldOnCreate(definition, itemTypeName) {
2374
- if (!definition.required && !definition.required_on_create) {
2375
- return false;
2448
+ function resolveLockOverrideRelease(result) {
2449
+ if (typeof result === "function") {
2450
+ return result;
2376
2451
  }
2377
- if (definition.required_types.length === 0) {
2378
- return true;
2452
+ if (typeof result === "object" && result !== null && "release" in result) {
2453
+ const release = result.release;
2454
+ return typeof release === "function" ? release : null;
2379
2455
  }
2380
- if (!itemTypeName) {
2381
- return false;
2456
+ return null;
2457
+ }
2458
+ function throwIfStaleLockNeedsForce(id, lockInfo, force, forceRequired) {
2459
+ if (!force && forceRequired) {
2460
+ const warningSuffix = lockInfo.warnings.length > 0 ? ` (${lockInfo.warnings.join(",")})` : "";
2461
+ throw new PmCliError(`Item ${id} lock is stale${warningSuffix}; rerun with --force when supported for this command`, EXIT_CODE.CONFLICT);
2382
2462
  }
2383
- return definition.required_types.map((value) => value.toLowerCase()).includes(itemTypeName.trim().toLowerCase());
2384
2463
  }
2385
- function collectRuntimeCreateFieldValues(options, fieldRegistry, itemTypeName) {
2386
- const values = {};
2387
- const missingRequiredFlags = [];
2388
- for (const definition of fieldRegistry.command_to_fields.get("create") ?? []) {
2389
- const rawValue = readRuntimeFieldOptionValue(options, definition);
2390
- if (rawValue === void 0) {
2391
- if (shouldRequireFieldOnCreate(definition, itemTypeName)) {
2392
- missingRequiredFlags.push(`--${definition.cli_flag}`);
2393
- }
2394
- continue;
2395
- }
2396
- values[definition.metadata_key] = coerceRuntimeFieldValue(definition, rawValue);
2464
+ function parseStaleCleanupGateOwner(raw) {
2465
+ let parsed;
2466
+ try {
2467
+ parsed = JSON.parse(raw);
2468
+ } catch {
2469
+ return null;
2397
2470
  }
2398
- return {
2399
- values,
2400
- missing_required_flags: [...new Set(missingRequiredFlags)].sort((left, right) => left.localeCompare(right))
2401
- };
2402
- }
2403
- function collectRuntimeUpdateFieldValues(options, fieldRegistry, commands = ["update"]) {
2404
- const values = {};
2405
- const definitions = (commands ?? ["update"]).flatMap((command) => fieldRegistry.command_to_fields.get(command) ?? []);
2406
- const seen = /* @__PURE__ */ new Set();
2407
- for (const definition of definitions) {
2408
- const rawValue = readRuntimeFieldOptionValue(options, definition);
2409
- if (rawValue === void 0) {
2410
- continue;
2411
- }
2412
- if (seen.has(definition.metadata_key)) {
2413
- continue;
2414
- }
2415
- seen.add(definition.metadata_key);
2416
- values[definition.metadata_key] = coerceRuntimeFieldValue(definition, rawValue);
2471
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
2472
+ return null;
2417
2473
  }
2418
- return values;
2474
+ const candidate = parsed;
2475
+ const pid = candidate.pid;
2476
+ const token = candidate.token;
2477
+ if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || typeof token !== "string" || token.length === 0) {
2478
+ return null;
2479
+ }
2480
+ return { pid, token };
2419
2481
  }
2420
-
2421
- // dist/core/item/item-format-version.js
2422
- !(function() {
2482
+ async function readStaleCleanupGateOwner(gatePath) {
2423
2483
  try {
2424
- var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
2425
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "08a25299-87bd-5c86-8e00-c42c5183e555");
2426
- } catch (e2) {
2427
- }
2428
- })();
2429
- var BASELINE_ITEM_FORMAT_VERSION = 1;
2430
- var CURRENT_ITEM_FORMAT_VERSION = 1;
2431
- function effectiveItemFormatVersion(metadata) {
2432
- const raw = metadata.pm_format_version;
2433
- if (typeof raw === "number" && Number.isInteger(raw) && raw >= BASELINE_ITEM_FORMAT_VERSION) {
2434
- return raw;
2484
+ return parseStaleCleanupGateOwner(await fs.readFile(path.join(gatePath, STALE_CLEANUP_GATE_OWNER_FILE), "utf8"));
2485
+ } catch {
2486
+ return null;
2435
2487
  }
2436
- return BASELINE_ITEM_FORMAT_VERSION;
2437
2488
  }
2438
- function normalizeItemFormatVersion(value) {
2439
- if (typeof value !== "number" || !Number.isInteger(value) || value <= BASELINE_ITEM_FORMAT_VERSION) {
2440
- return void 0;
2489
+ function isProcessAlive(pid) {
2490
+ try {
2491
+ process.kill(pid, 0);
2492
+ return true;
2493
+ } catch (error) {
2494
+ if (isErrno(error, "ESRCH")) {
2495
+ return false;
2496
+ }
2497
+ return true;
2441
2498
  }
2442
- return value;
2443
2499
  }
2444
- function classifyItemFormatVersion(version, current = CURRENT_ITEM_FORMAT_VERSION) {
2445
- if (version < current) {
2446
- return "outdated";
2447
- }
2448
- if (version > current) {
2449
- return "ahead";
2500
+ async function removeStaleCleanupGateDirectory(gatePath) {
2501
+ try {
2502
+ await fs.rm(gatePath, { recursive: true, force: true });
2503
+ return true;
2504
+ } catch {
2505
+ return false;
2450
2506
  }
2451
- return "current";
2452
2507
  }
2453
- function scanItemFormatVersions(entries, current = CURRENT_ITEM_FORMAT_VERSION) {
2454
- const outdated = [];
2455
- const ahead = [];
2456
- for (const entry of entries) {
2457
- const status = classifyItemFormatVersion(entry.version, current);
2458
- if (status === "outdated") {
2459
- outdated.push(entry.ref);
2460
- } else if (status === "ahead") {
2461
- ahead.push(entry.ref);
2462
- }
2508
+ async function releaseStaleCleanupGate(gatePath, token) {
2509
+ const owner = await readStaleCleanupGateOwner(gatePath);
2510
+ if (owner === null || owner.token !== token) {
2511
+ return;
2463
2512
  }
2464
- return {
2465
- outdated: outdated.sort((left, right) => left.localeCompare(right)),
2466
- ahead: ahead.sort((left, right) => left.localeCompare(right))
2467
- };
2513
+ await removeStaleCleanupGateDirectory(gatePath);
2468
2514
  }
2469
-
2470
- // dist/core/item/status.js
2471
- !(function() {
2515
+ async function tryCreateStaleCleanupGate(gatePath) {
2472
2516
  try {
2473
- var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
2474
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "fd8870cc-85e1-502e-acd4-a6049537c9e3");
2475
- } catch (e2) {
2476
- }
2477
- })();
2478
- var STATUS_ALIAS_MAP = {
2479
- "in-progress": "in_progress",
2480
- cancelled: "canceled"
2481
- };
2482
- function normalizeStatusInput(value, registry) {
2483
- if (registry) {
2484
- const normalizedFromRegistry = normalizeStatusInputWithRegistry(value, registry);
2485
- if (normalizedFromRegistry) {
2486
- return normalizedFromRegistry;
2517
+ await fs.mkdir(gatePath);
2518
+ } catch (error) {
2519
+ if (isErrno(error, "EEXIST")) {
2520
+ return null;
2487
2521
  }
2522
+ return null;
2488
2523
  }
2489
- if (typeof value !== "string") {
2490
- return void 0;
2491
- }
2492
- const normalized = value.trim().toLowerCase();
2493
- if (!normalized) {
2494
- return void 0;
2495
- }
2496
- const canonical = STATUS_ALIAS_MAP[normalized] ?? normalized;
2497
- if (!STATUS_VALUES.includes(canonical)) {
2498
- return void 0;
2499
- }
2500
- return canonical;
2501
- }
2502
- function normalizeStatusForRegistry(status, registry) {
2503
- return normalizeStatusInput(status, registry) ?? status;
2504
- }
2505
- function isTerminalStatus(status, registry) {
2506
- return registry.terminal_statuses.has(normalizeStatusForRegistry(status, registry));
2507
- }
2508
-
2509
- // dist/core/item/item-format.js
2510
- import { encode as encodeToon } from "@toon-format/toon";
2511
-
2512
- // dist/core/item/toon-decode.js
2513
- import { decode as decodeToon } from "@toon-format/toon";
2514
- !(function() {
2524
+ const owner = { pid: process.pid, token: randomUUID() };
2515
2525
  try {
2516
- var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
2517
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "748d78fa-94ca-562d-bf40-05ec1b2bffc2");
2518
- } catch (e2) {
2526
+ await fs.writeFile(path.join(gatePath, STALE_CLEANUP_GATE_OWNER_FILE), `${JSON.stringify(owner)}
2527
+ `, "utf8");
2528
+ } catch {
2529
+ await removeStaleCleanupGateDirectory(gatePath);
2530
+ return null;
2519
2531
  }
2520
- })();
2521
- function escapeBracketsInQuotedScalars(content) {
2522
- return content.split("\n").map((line) => {
2523
- const separatorIndex = line.indexOf(": ");
2524
- const bracketIndex = line.indexOf("[");
2525
- if (separatorIndex === -1 || bracketIndex === -1 || bracketIndex < separatorIndex) {
2526
- return line;
2527
- }
2528
- const key = line.slice(0, separatorIndex + 2);
2529
- const value = line.slice(separatorIndex + 2);
2530
- if (!value.startsWith('"')) {
2531
- return line;
2532
- }
2533
- return key + value.replaceAll("[", "\\u005b");
2534
- }).join("\n");
2532
+ return owner;
2535
2533
  }
2536
- function decodeToonItemContent(content) {
2534
+ async function removeExpiredStaleCleanupGate(gatePath) {
2535
+ let gateAgeMs;
2537
2536
  try {
2538
- return { value: decodeToon(content), usedScalarBracketEscape: false };
2539
- } catch (strictError) {
2540
- const escaped = escapeBracketsInQuotedScalars(content);
2541
- if (escaped === content) {
2542
- throw strictError;
2537
+ const stats = await fs.stat(gatePath);
2538
+ gateAgeMs = Date.now() - stats.mtimeMs;
2539
+ if (gateAgeMs <= STALE_CLEANUP_GATE_STALE_MS) {
2540
+ return false;
2543
2541
  }
2544
- return { value: decodeToon(escaped), usedScalarBracketEscape: true };
2542
+ } catch (error) {
2543
+ return isErrno(error, "ENOENT");
2544
+ }
2545
+ const owner = await readStaleCleanupGateOwner(gatePath);
2546
+ if (owner !== null && isProcessAlive(owner.pid) && gateAgeMs <= STALE_CLEANUP_GATE_MAX_ACTIVE_MS) {
2547
+ return false;
2545
2548
  }
2549
+ return removeStaleCleanupGateDirectory(gatePath);
2546
2550
  }
2547
-
2548
- // dist/core/shared/conflict-markers.js
2549
- !(function() {
2550
- try {
2551
- var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
2552
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "d4a8b193-c056-5ac6-b08f-a3fcc10a5ba9");
2553
- } catch (e2) {
2551
+ async function acquireStaleCleanupGate(lockPath, _id) {
2552
+ const gatePath = `${lockPath}${STALE_CLEANUP_GATE_SUFFIX}`;
2553
+ const owner = await tryCreateStaleCleanupGate(gatePath);
2554
+ if (owner !== null) {
2555
+ return async () => releaseStaleCleanupGate(gatePath, owner.token);
2554
2556
  }
2555
- })();
2556
- var CONFLICT_MARKER_PATTERN = /^\s*(<<<<<<<|=======|>>>>>>>)(?:\s.*)?$/;
2557
- function findMergeConflictMarkers(content) {
2558
- if (content.length === 0) {
2559
- return [];
2557
+ if (!await removeExpiredStaleCleanupGate(gatePath)) {
2558
+ return null;
2560
2559
  }
2561
- const lines = content.split(/\r?\n/);
2562
- const matches = [];
2563
- for (let index = 0; index < lines.length; index += 1) {
2564
- const line = lines[index] ?? "";
2565
- const markerMatch = line.match(CONFLICT_MARKER_PATTERN);
2566
- if (!markerMatch) {
2567
- continue;
2568
- }
2569
- const marker = markerMatch[1];
2570
- matches.push({
2571
- line: index + 1,
2572
- marker,
2573
- text: line
2574
- });
2560
+ const recoveredOwner = await tryCreateStaleCleanupGate(gatePath);
2561
+ if (recoveredOwner === null) {
2562
+ return null;
2575
2563
  }
2576
- return matches;
2577
- }
2578
- function findFirstMergeConflictMarker(content) {
2579
- const matches = findMergeConflictMarkers(content);
2580
- return matches[0];
2564
+ return async () => releaseStaleCleanupGate(gatePath, recoveredOwner.token);
2581
2565
  }
2582
-
2583
- // dist/core/item/item-format.js
2584
- !(function() {
2585
- try {
2586
- var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
2587
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "bc77f061-b1cd-5989-9a55-cd4259d397e0");
2588
- } catch (e2) {
2566
+ async function removeConfirmedStaleLock(params) {
2567
+ const releaseCleanupGate = await acquireStaleCleanupGate(params.lockPath, params.id);
2568
+ if (releaseCleanupGate === null) {
2569
+ return {
2570
+ lockInfo: params.fallbackLockInfo,
2571
+ shouldRetryCreate: false,
2572
+ staleRemovalCounted: false
2573
+ };
2589
2574
  }
2590
- })();
2591
- var LINKED_TEST_PM_CONTEXT_MODE_VALUES = /* @__PURE__ */ new Set([
2592
- "schema",
2593
- "tracker",
2594
- "auto"
2595
- ]);
2596
- var ITEM_TEST_RUN_STATUS_VALUES = /* @__PURE__ */ new Set([
2597
- "passed",
2598
- "failed",
2599
- "stopped",
2600
- "canceled"
2601
- ]);
2602
- var PLAN_STEP_STATUS_SET = new Set(PLAN_STEP_STATUS_VALUES);
2603
- function normalizePathValue(value) {
2604
- return value.replaceAll("\\", "/");
2605
- }
2606
- function firstNonZeroComparison(comparisons) {
2607
- for (const comparison of comparisons) {
2608
- if (comparison !== 0) {
2609
- return comparison;
2575
+ try {
2576
+ const currentLockInfo = await readLockInfo(params.lockPath);
2577
+ if (currentLockInfo.info === null && currentLockInfo.warnings.length === 0) {
2578
+ return {
2579
+ lockInfo: currentLockInfo,
2580
+ shouldRetryCreate: true,
2581
+ staleRemovalCounted: false
2582
+ };
2583
+ }
2584
+ if (!isStaleLock(currentLockInfo.info, params.ttlSeconds)) {
2585
+ return {
2586
+ lockInfo: currentLockInfo,
2587
+ shouldRetryCreate: false,
2588
+ staleRemovalCounted: false
2589
+ };
2590
+ }
2591
+ throwIfStaleLockNeedsForce(params.id, currentLockInfo, params.force, params.forceRequiredForStaleLock);
2592
+ if (params.staleRemovals >= MAX_STALE_LOCK_REMOVALS) {
2593
+ throw buildLockConflictError(params.id, currentLockInfo.info, Date.now() - params.startedAtMs);
2610
2594
  }
2595
+ return {
2596
+ lockInfo: currentLockInfo,
2597
+ shouldRetryCreate: await unlinkLockWithHook(params.lockPath, "lock:stale_remove"),
2598
+ staleRemovalCounted: true
2599
+ };
2600
+ } finally {
2601
+ await releaseCleanupGate();
2611
2602
  }
2612
- return 0;
2613
2603
  }
2614
- function deleteUndefinedFields(record) {
2615
- for (const [key, value] of Object.entries(record)) {
2616
- if (value === void 0) {
2617
- delete record[key];
2604
+ async function acquireLock(pmRoot, id, ttlSeconds, owner, force = false, forceRequiredForStaleLock = true, waitMs) {
2605
+ const lockOverride = await runActiveServiceOverride("lock_acquire", {
2606
+ pm_root: pmRoot,
2607
+ id,
2608
+ ttl_seconds: ttlSeconds,
2609
+ owner,
2610
+ force,
2611
+ force_required_for_stale_lock: forceRequiredForStaleLock
2612
+ });
2613
+ if (lockOverride.handled) {
2614
+ const release = resolveLockOverrideRelease(lockOverride.result);
2615
+ if (release) {
2616
+ return async () => {
2617
+ await Promise.resolve(release());
2618
+ await runActiveServiceOverride("lock_release", {
2619
+ pm_root: pmRoot,
2620
+ id,
2621
+ owner
2622
+ });
2623
+ };
2618
2624
  }
2619
2625
  }
2620
- }
2621
- var REQUIRED_STRING_FIELDS = [
2622
- "id",
2623
- "title",
2624
- "description",
2625
- "created_at",
2626
- "updated_at"
2627
- ];
2628
- var STATIC_ITEM_METADATA_FIELD_SET = new Set(ITEM_METADATA_KEY_ORDER);
2629
- function resolveRuntimeSchemaValidationContext(options) {
2630
- if (!options?.schema) {
2631
- return void 0;
2626
+ const lockPath = getLockPath(pmRoot, id);
2627
+ const waitBudgetMs = resolveLockWaitMs(waitMs);
2628
+ const startedAtMs = Date.now();
2629
+ let staleRemovals = 0;
2630
+ let backoffMs = LOCK_WAIT_INITIAL_DELAY_MS;
2631
+ for (; ; ) {
2632
+ try {
2633
+ await createLockFile(lockPath, id, owner, ttlSeconds);
2634
+ return async () => {
2635
+ await unlinkLockWithHook(lockPath, "lock:release");
2636
+ await runActiveServiceOverride("lock_release", {
2637
+ pm_root: pmRoot,
2638
+ id,
2639
+ owner
2640
+ });
2641
+ };
2642
+ } catch (error) {
2643
+ if (!isErrno(error, "EEXIST")) {
2644
+ throw new PmCliError(`Failed to acquire lock for ${id}: ${toErrorMessage(error)}`, EXIT_CODE.GENERIC_FAILURE);
2645
+ }
2646
+ let lockInfo = await readLockInfo(lockPath);
2647
+ if (isStaleLock(lockInfo.info, ttlSeconds)) {
2648
+ const staleRemoval = await removeConfirmedStaleLock({
2649
+ lockPath,
2650
+ id,
2651
+ ttlSeconds,
2652
+ force,
2653
+ forceRequiredForStaleLock,
2654
+ staleRemovals,
2655
+ waitBudgetMs,
2656
+ startedAtMs,
2657
+ fallbackLockInfo: lockInfo
2658
+ });
2659
+ lockInfo = staleRemoval.lockInfo;
2660
+ if (staleRemoval.staleRemovalCounted) {
2661
+ staleRemovals += 1;
2662
+ }
2663
+ if (staleRemoval.shouldRetryCreate) {
2664
+ continue;
2665
+ }
2666
+ }
2667
+ const elapsedMs = Date.now() - startedAtMs;
2668
+ if (waitBudgetMs === 0 || elapsedMs >= waitBudgetMs) {
2669
+ throw buildLockConflictError(id, lockInfo.info, waitBudgetMs === 0 ? 0 : elapsedMs);
2670
+ }
2671
+ await sleepWithJitter(Math.min(backoffMs, waitBudgetMs - elapsedMs));
2672
+ backoffMs = Math.min(backoffMs * 2, LOCK_WAIT_MAX_DELAY_MS);
2673
+ }
2632
2674
  }
2633
- return {
2634
- statusRegistry: resolveRuntimeStatusRegistry(options.schema),
2635
- fieldRegistry: resolveRuntimeFieldRegistry(options.schema),
2636
- unknownFieldPolicy: options.schema.unknown_field_policy ?? "allow",
2637
- extensionFieldNames: new Set(options.extensionFieldNames ?? []),
2638
- onWarning: options.onWarning
2639
- };
2640
2675
  }
2641
- function runtimeFieldRequiredForType(definition, typeName) {
2642
- if (!definition.required) {
2643
- return false;
2676
+
2677
+ // dist/core/schema/runtime-field-values.js
2678
+ !(function() {
2679
+ try {
2680
+ var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
2681
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "e31fbd91-9662-592e-abd5-1db822ac04eb");
2682
+ } catch (e2) {
2644
2683
  }
2645
- if (definition.required_types.length === 0) {
2646
- return true;
2684
+ })();
2685
+ function toCamelToken(value) {
2686
+ const segments = value.trim().replaceAll(/[^A-Za-z0-9]+/g, " ").split(/\s+/).filter((segment) => segment.length > 0).map((segment) => segment.toLowerCase());
2687
+ if (segments.length === 0) {
2688
+ return value;
2647
2689
  }
2648
- return definition.required_types.map((value) => value.toLowerCase()).includes(typeName.trim().toLowerCase());
2690
+ const [first, ...rest] = segments;
2691
+ return `${first}${rest.map((segment) => `${segment.slice(0, 1).toUpperCase()}${segment.slice(1)}`).join("")}`;
2649
2692
  }
2650
- function validationError(message) {
2651
- throw new PmCliError(`Invalid item metadata: ${message}`, EXIT_CODE.GENERIC_FAILURE);
2693
+ function resolveCandidateOptionKeys(definition) {
2694
+ return [
2695
+ .../* @__PURE__ */ new Set([
2696
+ runtimeFieldOptionTarget(definition),
2697
+ toCamelToken(definition.key),
2698
+ toCamelToken(definition.cli_flag),
2699
+ ...definition.cli_aliases.map((alias) => toCamelToken(alias))
2700
+ ])
2701
+ ];
2652
2702
  }
2653
- function buildKnownItemMetadataKeys(runtimeContext) {
2654
- const knownKeys = new Set(STATIC_ITEM_METADATA_FIELD_SET);
2655
- for (const definition of runtimeContext.fieldRegistry?.definitions ?? []) {
2656
- knownKeys.add(definition.metadata_key);
2657
- }
2658
- for (const fieldName of runtimeContext.extensionFieldNames) {
2659
- knownKeys.add(fieldName);
2703
+ function readRuntimeFieldOptionValue(options, definition) {
2704
+ for (const candidateKey of resolveCandidateOptionKeys(definition)) {
2705
+ if (!Object.hasOwn(options, candidateKey)) {
2706
+ continue;
2707
+ }
2708
+ const value = options[candidateKey];
2709
+ if (value !== void 0) {
2710
+ return value;
2711
+ }
2660
2712
  }
2661
- return knownKeys;
2713
+ return void 0;
2662
2714
  }
2663
- function assertItemMetadataCondition(condition, message) {
2664
- if (!condition) {
2665
- validationError(message);
2715
+ function normalizeStringArrayValue(value) {
2716
+ if (Array.isArray(value)) {
2717
+ return value.flatMap((entry) => normalizeStringArrayValue(entry)).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
2666
2718
  }
2667
- }
2668
- function assertTimestampField(record, fieldName) {
2669
- const rawValue = record[fieldName];
2670
- assertItemMetadataCondition(typeof rawValue === "string", `${fieldName} must be a string`);
2671
- const timestamp = rawValue;
2672
- assertItemMetadataCondition(isTimestampLiteral(timestamp), `${fieldName} must be a valid ISO timestamp`);
2673
- }
2674
- function assertPositiveIntegerField(record, fieldName, messagePrefix) {
2675
- const value = record[fieldName];
2676
- if (value === void 0) {
2677
- return;
2719
+ if (typeof value === "string") {
2720
+ return value.split(/[,\n|]/).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
2678
2721
  }
2679
- assertItemMetadataCondition(typeof value === "number" && Number.isInteger(value) && value >= 1, `${messagePrefix} must be an integer >= 1`);
2680
- }
2681
- function assertOptionalTimestampString(record, fieldName, messagePrefix) {
2682
- const value = record[fieldName];
2683
- if (value === void 0) {
2684
- return;
2722
+ if (value === void 0 || value === null) {
2723
+ return [];
2685
2724
  }
2686
- assertItemMetadataCondition(typeof value === "string", `${messagePrefix} must be a string`);
2687
- assertItemMetadataCondition(isTimestampLiteral(value), `${messagePrefix} must be a valid ISO timestamp`);
2725
+ return [String(value).trim()].filter((entry) => entry.length > 0);
2688
2726
  }
2689
- function assertRecurrenceWeekdays(value) {
2690
- if (value === void 0) {
2691
- return;
2692
- }
2693
- assertItemMetadataCondition(Array.isArray(value), "event.recurrence.by_weekday must be an array");
2694
- for (const weekday of value) {
2695
- assertItemMetadataCondition(typeof weekday === "string", "event.recurrence.by_weekday entries must be strings");
2696
- const normalizedWeekday = weekday.trim().toLowerCase();
2697
- assertItemMetadataCondition(RECURRENCE_WEEKDAY_VALUES.includes(normalizedWeekday), `event.recurrence.by_weekday entries must be one of: ${RECURRENCE_WEEKDAY_VALUES.join(", ")}`);
2727
+ function parseBooleanValue(raw, label) {
2728
+ if (typeof raw === "boolean") {
2729
+ return raw;
2698
2730
  }
2699
- }
2700
- function assertRecurrenceMonthDays(value) {
2701
- if (value === void 0) {
2702
- return;
2731
+ if (typeof raw === "number") {
2732
+ if (raw === 1) {
2733
+ return true;
2734
+ }
2735
+ if (raw === 0) {
2736
+ return false;
2737
+ }
2703
2738
  }
2704
- assertItemMetadataCondition(Array.isArray(value), "event.recurrence.by_month_day must be an array");
2705
- for (const day of value) {
2706
- assertItemMetadataCondition(typeof day === "number" && Number.isInteger(day) && day >= 1 && day <= 31, "event.recurrence.by_month_day entries must be integers 1..31");
2739
+ if (typeof raw === "string") {
2740
+ const normalized = raw.trim().toLowerCase();
2741
+ if (normalized === "true" || normalized === "1" || normalized === "yes") {
2742
+ return true;
2743
+ }
2744
+ if (normalized === "false" || normalized === "0" || normalized === "no") {
2745
+ return false;
2746
+ }
2707
2747
  }
2748
+ throw new PmCliError(`${label} must be one of true|false|1|0|yes|no`, EXIT_CODE.USAGE);
2708
2749
  }
2709
- function assertRecurrenceExdates(value) {
2710
- if (value === void 0) {
2711
- return;
2712
- }
2713
- assertItemMetadataCondition(Array.isArray(value), "event.recurrence.exdates must be an array");
2714
- for (const exdate of value) {
2715
- assertItemMetadataCondition(typeof exdate === "string", "event.recurrence.exdates entries must be strings");
2716
- assertItemMetadataCondition(isTimestampLiteral(exdate), "event.recurrence.exdates entries must be valid ISO timestamps");
2717
- }
2718
- }
2719
- function assertValidRecurrenceRule(recurrence) {
2720
- assertItemMetadataCondition(typeof recurrence === "object" && recurrence !== null && !Array.isArray(recurrence), "event.recurrence must be an object");
2721
- const recurrenceRecord = recurrence;
2722
- assertItemMetadataCondition(typeof recurrenceRecord.freq === "string", "event.recurrence.freq must be a string");
2723
- const frequency = recurrenceRecord.freq.trim().toLowerCase();
2724
- assertItemMetadataCondition(RECURRENCE_FREQUENCY_VALUES.includes(frequency), `event.recurrence.freq must be one of: ${RECURRENCE_FREQUENCY_VALUES.join(", ")}`);
2725
- assertPositiveIntegerField(recurrenceRecord, "interval", "event.recurrence.interval");
2726
- assertPositiveIntegerField(recurrenceRecord, "count", "event.recurrence.count");
2727
- assertOptionalTimestampString(recurrenceRecord, "until", "event.recurrence.until");
2728
- assertRecurrenceWeekdays(recurrenceRecord.by_weekday);
2729
- assertRecurrenceMonthDays(recurrenceRecord.by_month_day);
2730
- assertRecurrenceExdates(recurrenceRecord.exdates);
2731
- }
2732
- function assertRequiredItemMetadataFields(record) {
2733
- for (const fieldName of REQUIRED_STRING_FIELDS) {
2734
- assertItemMetadataCondition(typeof record[fieldName] === "string", `${fieldName} is required and must be a string`);
2750
+ function parseNumberValue(raw, label) {
2751
+ if (typeof raw === "number" && Number.isFinite(raw)) {
2752
+ return raw;
2735
2753
  }
2736
- const itemType = record.type;
2737
- assertItemMetadataCondition(typeof itemType === "string" && itemType.trim().length > 0, "type must be a non-empty string");
2738
- const formatVersion = record.pm_format_version;
2739
- if (formatVersion !== void 0) {
2740
- assertItemMetadataCondition(typeof formatVersion === "number" && Number.isInteger(formatVersion) && formatVersion >= BASELINE_ITEM_FORMAT_VERSION, `pm_format_version must be an integer >= ${BASELINE_ITEM_FORMAT_VERSION}`);
2754
+ const candidate = typeof raw === "string" ? raw.trim() : String(raw);
2755
+ const parsed = Number(candidate);
2756
+ if (!Number.isFinite(parsed)) {
2757
+ throw new PmCliError(`${label} must be a number`, EXIT_CODE.USAGE);
2741
2758
  }
2742
- return itemType;
2743
- }
2744
- function assertStatusItemMetadataField(record, runtimeContext) {
2745
- const status = record.status;
2746
- assertItemMetadataCondition(typeof status === "string" && status.trim().length > 0, "status must be a non-empty string");
2747
- const statusRegistry = runtimeContext?.statusRegistry;
2748
- const normalizedStatus = normalizeStatusInput(status, statusRegistry);
2749
- const statusDomain = statusRegistry ? statusRegistry.definitions.map((definition) => definition.id) : [...STATUS_VALUES];
2750
- assertItemMetadataCondition(normalizedStatus !== void 0, `status must be one of: ${statusDomain.join(", ")}`);
2759
+ return parsed;
2751
2760
  }
2752
- function assertPriorityAndTags(record) {
2753
- const priority = record.priority;
2754
- assertItemMetadataCondition(typeof priority === "number" && Number.isInteger(priority) && [0, 1, 2, 3, 4].includes(priority), "priority must be an integer 0..4");
2755
- const tags = record.tags;
2756
- assertItemMetadataCondition(Array.isArray(tags), "tags must be an array");
2757
- for (const tag of tags) {
2758
- assertItemMetadataCondition(typeof tag === "string", "tags entries must be strings");
2761
+ function coerceRuntimeFieldValue(definition, rawValue, labelOverride) {
2762
+ const label = labelOverride ?? `--${definition.cli_flag}`;
2763
+ if (definition.repeatable || definition.type === "string_array") {
2764
+ const values = normalizeStringArrayValue(rawValue);
2765
+ if (definition.type === "number") {
2766
+ return values.map((value) => parseNumberValue(value, label));
2767
+ }
2768
+ if (definition.type === "boolean") {
2769
+ return values.map((value) => parseBooleanValue(value, label));
2770
+ }
2771
+ return values;
2759
2772
  }
2760
- }
2761
- function assertConfidenceItemMetadataField(record) {
2762
- const confidence = record.confidence;
2763
- if (confidence === void 0) {
2764
- return;
2773
+ const scalarRaw = Array.isArray(rawValue) ? rawValue[rawValue.length - 1] : rawValue;
2774
+ if (scalarRaw === void 0) {
2775
+ return void 0;
2765
2776
  }
2766
- if (typeof confidence === "number") {
2767
- assertItemMetadataCondition(Number.isInteger(confidence) && confidence >= 0 && confidence <= 100, "confidence number value must be an integer 0..100");
2768
- return;
2777
+ if (definition.type === "number") {
2778
+ return parseNumberValue(scalarRaw, label);
2769
2779
  }
2770
- if (typeof confidence === "string") {
2771
- const normalizedConfidence = confidence.trim().toLowerCase();
2772
- const isKnownTextConfidence = normalizedConfidence === "med" || CONFIDENCE_TEXT_VALUES.includes(normalizedConfidence);
2773
- assertItemMetadataCondition(isKnownTextConfidence, `confidence string value must be one of: ${[...CONFIDENCE_TEXT_VALUES, "med"].join(", ")}`);
2774
- return;
2780
+ if (definition.type === "boolean") {
2781
+ return parseBooleanValue(scalarRaw, label);
2775
2782
  }
2776
- assertItemMetadataCondition(false, "confidence must be a number or string");
2783
+ return typeof scalarRaw === "string" ? scalarRaw : String(scalarRaw);
2777
2784
  }
2778
- function assertSeverityItemMetadataField(record) {
2779
- const severity = record.severity;
2780
- if (severity === void 0) {
2781
- return;
2785
+ function shouldRequireFieldOnCreate(definition, itemTypeName) {
2786
+ if (!definition.required && !definition.required_on_create) {
2787
+ return false;
2782
2788
  }
2783
- if (typeof severity !== "string") {
2784
- validationError("severity must be a string");
2789
+ if (definition.required_types.length === 0) {
2790
+ return true;
2785
2791
  }
2786
- const normalizedSeverity = severity.trim().toLowerCase();
2787
- const isKnownSeverity = normalizedSeverity === "med" || ISSUE_SEVERITY_VALUES.includes(normalizedSeverity);
2788
- assertItemMetadataCondition(isKnownSeverity, `severity value must be one of: ${[...ISSUE_SEVERITY_VALUES, "med"].join(", ")}`);
2789
- }
2790
- function assertRegressionItemMetadataField(record) {
2791
- if (record.regression !== void 0 && typeof record.regression !== "boolean") {
2792
- validationError("regression must be a boolean");
2792
+ if (!itemTypeName) {
2793
+ return false;
2793
2794
  }
2795
+ return definition.required_types.map((value) => value.toLowerCase()).includes(itemTypeName.trim().toLowerCase());
2794
2796
  }
2795
- function assertReminderEntries(record) {
2796
- const reminders = record.reminders;
2797
- if (reminders === void 0) {
2798
- return;
2799
- }
2800
- assertItemMetadataCondition(Array.isArray(reminders), "reminders must be an array");
2801
- for (const reminder of reminders) {
2802
- assertItemMetadataCondition(typeof reminder === "object" && reminder !== null && !Array.isArray(reminder), "reminders entries must be objects");
2803
- const reminderRecord = reminder;
2804
- assertItemMetadataCondition(typeof reminderRecord.at === "string", "reminder.at must be a string");
2805
- assertItemMetadataCondition(isTimestampLiteral(reminderRecord.at), "reminder.at must be a valid ISO timestamp");
2806
- assertItemMetadataCondition(typeof reminderRecord.text === "string", "reminder.text must be a string");
2807
- assertItemMetadataCondition(reminderRecord.text.trim().length > 0, "reminder.text must not be empty");
2797
+ function collectRuntimeCreateFieldValues(options, fieldRegistry, itemTypeName) {
2798
+ const values = {};
2799
+ const missingRequiredFlags = [];
2800
+ for (const definition of fieldRegistry.command_to_fields.get("create") ?? []) {
2801
+ const rawValue = readRuntimeFieldOptionValue(options, definition);
2802
+ if (rawValue === void 0) {
2803
+ if (shouldRequireFieldOnCreate(definition, itemTypeName)) {
2804
+ missingRequiredFlags.push(`--${definition.cli_flag}`);
2805
+ }
2806
+ continue;
2807
+ }
2808
+ values[definition.metadata_key] = coerceRuntimeFieldValue(definition, rawValue);
2808
2809
  }
2810
+ return {
2811
+ values,
2812
+ missing_required_flags: [...new Set(missingRequiredFlags)].sort((left, right) => left.localeCompare(right))
2813
+ };
2809
2814
  }
2810
- function assertEventStringFields(eventRecord) {
2811
- for (const stringField of [
2812
- "title",
2813
- "description",
2814
- "location",
2815
- "timezone"
2816
- ]) {
2817
- if (eventRecord[stringField] !== void 0) {
2818
- assertItemMetadataCondition(typeof eventRecord[stringField] === "string", `event.${stringField} must be a string`);
2819
- assertItemMetadataCondition(eventRecord[stringField].trim().length > 0, `event.${stringField} must not be empty`);
2815
+ function collectRuntimeUpdateFieldValues(options, fieldRegistry, commands = ["update"]) {
2816
+ const values = {};
2817
+ const definitions = (commands ?? ["update"]).flatMap((command) => fieldRegistry.command_to_fields.get(command) ?? []);
2818
+ const seen = /* @__PURE__ */ new Set();
2819
+ for (const definition of definitions) {
2820
+ const rawValue = readRuntimeFieldOptionValue(options, definition);
2821
+ if (rawValue === void 0) {
2822
+ continue;
2823
+ }
2824
+ if (seen.has(definition.metadata_key)) {
2825
+ continue;
2820
2826
  }
2827
+ seen.add(definition.metadata_key);
2828
+ values[definition.metadata_key] = coerceRuntimeFieldValue(definition, rawValue);
2821
2829
  }
2830
+ return values;
2822
2831
  }
2823
- function assertEventRecurrence(eventRecord) {
2824
- if (eventRecord.recurrence === void 0) {
2825
- return;
2832
+
2833
+ // dist/core/item/item-format-version.js
2834
+ !(function() {
2835
+ try {
2836
+ var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
2837
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "08a25299-87bd-5c86-8e00-c42c5183e555");
2838
+ } catch (e2) {
2826
2839
  }
2827
- assertValidRecurrenceRule(eventRecord.recurrence);
2828
- if (eventRecord.recurrence.until !== void 0) {
2829
- assertItemMetadataCondition(compareTimestampStrings(eventRecord.recurrence.until, eventRecord.start_at) >= 0, "event.recurrence.until must be at or after event.start_at");
2840
+ })();
2841
+ var BASELINE_ITEM_FORMAT_VERSION = 1;
2842
+ var CURRENT_ITEM_FORMAT_VERSION = 1;
2843
+ function effectiveItemFormatVersion(metadata) {
2844
+ const raw = metadata.pm_format_version;
2845
+ if (typeof raw === "number" && Number.isInteger(raw) && raw >= BASELINE_ITEM_FORMAT_VERSION) {
2846
+ return raw;
2830
2847
  }
2848
+ return BASELINE_ITEM_FORMAT_VERSION;
2831
2849
  }
2832
- function assertCalendarEventEntry(event) {
2833
- assertItemMetadataCondition(typeof event === "object" && event !== null && !Array.isArray(event), "events entries must be objects");
2834
- const eventRecord = event;
2835
- assertItemMetadataCondition(typeof eventRecord.start_at === "string", "event.start_at must be a string");
2836
- assertItemMetadataCondition(isTimestampLiteral(eventRecord.start_at), "event.start_at must be a valid ISO timestamp");
2837
- if (eventRecord.end_at !== void 0) {
2838
- assertItemMetadataCondition(typeof eventRecord.end_at === "string", "event.end_at must be a string");
2839
- assertItemMetadataCondition(isTimestampLiteral(eventRecord.end_at), "event.end_at must be a valid ISO timestamp");
2840
- assertItemMetadataCondition(compareTimestampStrings(eventRecord.end_at, eventRecord.start_at) > 0, "event.end_at must be after event.start_at");
2841
- }
2842
- assertEventStringFields(eventRecord);
2843
- if (eventRecord.all_day !== void 0) {
2844
- assertItemMetadataCondition(typeof eventRecord.all_day === "boolean", "event.all_day must be a boolean");
2850
+ function normalizeItemFormatVersion(value) {
2851
+ if (typeof value !== "number" || !Number.isInteger(value) || value <= BASELINE_ITEM_FORMAT_VERSION) {
2852
+ return void 0;
2845
2853
  }
2846
- assertEventRecurrence(eventRecord);
2854
+ return value;
2847
2855
  }
2848
- function assertCalendarEvents(record) {
2849
- const events = record.events;
2850
- if (events === void 0) {
2851
- return;
2856
+ function classifyItemFormatVersion(version, current = CURRENT_ITEM_FORMAT_VERSION) {
2857
+ if (version < current) {
2858
+ return "outdated";
2852
2859
  }
2853
- assertItemMetadataCondition(Array.isArray(events), "events must be an array");
2854
- for (const event of events) {
2855
- assertCalendarEventEntry(event);
2860
+ if (version > current) {
2861
+ return "ahead";
2856
2862
  }
2863
+ return "current";
2857
2864
  }
2858
- function assertOptionalStringFields(record) {
2859
- for (const fieldName of [
2860
- "source_type",
2861
- "source_owner",
2862
- "design",
2863
- "external_ref"
2864
- ]) {
2865
- const value = record[fieldName];
2866
- if (value !== void 0) {
2867
- assertItemMetadataCondition(typeof value === "string", `${fieldName} must be a string`);
2865
+ function scanItemFormatVersions(entries, current = CURRENT_ITEM_FORMAT_VERSION) {
2866
+ const outdated = [];
2867
+ const ahead = [];
2868
+ for (const entry of entries) {
2869
+ const status = classifyItemFormatVersion(entry.version, current);
2870
+ if (status === "outdated") {
2871
+ outdated.push(entry.ref);
2872
+ } else if (status === "ahead") {
2873
+ ahead.push(entry.ref);
2868
2874
  }
2869
2875
  }
2876
+ return {
2877
+ outdated: outdated.sort((left, right) => left.localeCompare(right)),
2878
+ ahead: ahead.sort((left, right) => left.localeCompare(right))
2879
+ };
2870
2880
  }
2871
- function assertTypeOptionsField(record) {
2872
- const typeOptions = record.type_options;
2873
- if (typeOptions === void 0) {
2874
- return;
2875
- }
2876
- assertItemMetadataCondition(typeof typeOptions === "object" && typeOptions !== null && !Array.isArray(typeOptions), "type_options must be an object");
2877
- for (const [optionKey, optionValue] of Object.entries(typeOptions)) {
2878
- assertItemMetadataCondition(optionKey.trim().length > 0, "type_options keys must be non-empty");
2879
- assertItemMetadataCondition(typeof optionValue === "string", "type_options values must be strings");
2880
- const optionText = optionValue;
2881
- assertItemMetadataCondition(optionText.trim().length > 0, "type_options values must be non-empty strings");
2882
- }
2883
- }
2884
- function coerceRuntimeItemMetadataFields(record, itemType, runtimeContext) {
2885
- if (!runtimeContext?.fieldRegistry) {
2886
- return;
2881
+
2882
+ // dist/core/item/status.js
2883
+ !(function() {
2884
+ try {
2885
+ var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
2886
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "fd8870cc-85e1-502e-acd4-a6049537c9e3");
2887
+ } catch (e2) {
2887
2888
  }
2888
- for (const definition of runtimeContext.fieldRegistry.definitions) {
2889
- const fieldValue = record[definition.metadata_key];
2890
- if (fieldValue === void 0) {
2891
- if (runtimeFieldRequiredForType(definition, itemType)) {
2892
- validationError(`missing required schema field: ${definition.metadata_key}`);
2893
- }
2894
- continue;
2895
- }
2896
- try {
2897
- record[definition.metadata_key] = coerceRuntimeFieldValue(definition, fieldValue, `metadata field "${definition.metadata_key}"`);
2898
- } catch (error) {
2899
- validationError(String(error?.message).replace(/^Invalid\s+/u, ""));
2889
+ })();
2890
+ var STATUS_ALIAS_MAP = {
2891
+ "in-progress": "in_progress",
2892
+ cancelled: "canceled"
2893
+ };
2894
+ function normalizeStatusInput(value, registry) {
2895
+ if (registry) {
2896
+ const normalizedFromRegistry = normalizeStatusInputWithRegistry(value, registry);
2897
+ if (normalizedFromRegistry) {
2898
+ return normalizedFromRegistry;
2900
2899
  }
2901
2900
  }
2902
- }
2903
- function assertRuntimeUnknownItemMetadataFields(record, runtimeContext) {
2904
- if (!runtimeContext || runtimeContext.unknownFieldPolicy === "allow") {
2905
- return;
2901
+ if (typeof value !== "string") {
2902
+ return void 0;
2906
2903
  }
2907
- const knownKeys = buildKnownItemMetadataKeys(runtimeContext);
2908
- const unknownKeys = Object.keys(record).filter((key) => !knownKeys.has(key)).sort((left, right) => left.localeCompare(right));
2909
- if (unknownKeys.length === 0) {
2910
- return;
2904
+ const normalized = value.trim().toLowerCase();
2905
+ if (!normalized) {
2906
+ return void 0;
2911
2907
  }
2912
- if (runtimeContext.unknownFieldPolicy === "reject") {
2913
- validationError(`unknown schema fields are not allowed: ${unknownKeys.join(", ")}`);
2914
- } else {
2915
- runtimeContext.onWarning?.(`item_unknown_schema_fields:${unknownKeys.join(",")}`);
2908
+ const canonical = STATUS_ALIAS_MAP[normalized] ?? normalized;
2909
+ if (!STATUS_VALUES.includes(canonical)) {
2910
+ return void 0;
2916
2911
  }
2912
+ return canonical;
2917
2913
  }
2918
- function assertValidItemMetadata(itemMetadata, runtimeContext) {
2919
- assertItemMetadataCondition(typeof itemMetadata === "object" && itemMetadata !== null && !Array.isArray(itemMetadata), "item metadata must be an object");
2920
- const record = itemMetadata;
2921
- const itemType = assertRequiredItemMetadataFields(record);
2922
- assertStatusItemMetadataField(record, runtimeContext);
2923
- assertPriorityAndTags(record);
2924
- assertConfidenceItemMetadataField(record);
2925
- assertSeverityItemMetadataField(record);
2926
- assertRegressionItemMetadataField(record);
2927
- assertTimestampField(record, "created_at");
2928
- assertTimestampField(record, "updated_at");
2929
- if (record.deadline !== void 0) {
2930
- assertTimestampField(record, "deadline");
2931
- }
2932
- assertReminderEntries(record);
2933
- assertCalendarEvents(record);
2934
- assertOptionalTimestampString(record, "closed_at", "closed_at");
2935
- assertOptionalStringFields(record);
2936
- assertTypeOptionsField(record);
2937
- coerceRuntimeItemMetadataFields(record, itemType, runtimeContext);
2938
- assertRuntimeUnknownItemMetadataFields(record, runtimeContext);
2914
+ function normalizeStatusForRegistry(status, registry) {
2915
+ return normalizeStatusInput(status, registry) ?? status;
2939
2916
  }
2940
- function sortDependencies(values) {
2941
- if (!values || values.length === 0)
2942
- return void 0;
2943
- return [...values].map((value) => ({
2944
- id: value.id.trim().toLowerCase(),
2945
- kind: value.kind,
2946
- created_at: value.created_at,
2947
- author: value.author?.trim() || void 0,
2948
- source_kind: value.source_kind?.trim() || void 0
2949
- })).sort((a, b) => {
2950
- const byCreated = compareTimestampStrings(a.created_at, b.created_at);
2951
- if (byCreated !== 0)
2952
- return byCreated;
2953
- const byId = a.id.localeCompare(b.id);
2954
- if (byId !== 0)
2955
- return byId;
2956
- const byKind = a.kind.localeCompare(b.kind);
2957
- if (byKind !== 0)
2958
- return byKind;
2959
- return (a.source_kind ?? "").localeCompare(b.source_kind ?? "");
2960
- });
2917
+ function isTerminalStatus(status, registry) {
2918
+ return registry.terminal_statuses.has(normalizeStatusForRegistry(status, registry));
2961
2919
  }
2962
- function sortLogValues(values) {
2963
- if (!values || values.length === 0)
2964
- return void 0;
2965
- return [...values].sort((a, b) => {
2966
- const byCreated = compareTimestampStrings(a.created_at, b.created_at);
2967
- if (byCreated !== 0)
2968
- return byCreated;
2969
- const byText = a.text.localeCompare(b.text);
2970
- if (byText !== 0)
2971
- return byText;
2972
- return a.author.localeCompare(b.author);
2973
- });
2920
+
2921
+ // dist/core/item/item-format.js
2922
+ import { encode as encodeToon } from "@toon-format/toon";
2923
+
2924
+ // dist/core/item/toon-decode.js
2925
+ import { decode as decodeToon } from "@toon-format/toon";
2926
+ !(function() {
2927
+ try {
2928
+ var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
2929
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "748d78fa-94ca-562d-bf40-05ec1b2bffc2");
2930
+ } catch (e2) {
2931
+ }
2932
+ })();
2933
+ function escapeBracketsInQuotedScalars(content) {
2934
+ return content.split("\n").map((line) => {
2935
+ const separatorIndex = line.indexOf(": ");
2936
+ const bracketIndex = line.indexOf("[");
2937
+ if (separatorIndex === -1 || bracketIndex === -1 || bracketIndex < separatorIndex) {
2938
+ return line;
2939
+ }
2940
+ const key = line.slice(0, separatorIndex + 2);
2941
+ const value = line.slice(separatorIndex + 2);
2942
+ if (!value.startsWith('"')) {
2943
+ return line;
2944
+ }
2945
+ return key + value.replaceAll("[", "\\u005b");
2946
+ }).join("\n");
2974
2947
  }
2975
- function sortReminders(values) {
2976
- if (!values || values.length === 0)
2977
- return void 0;
2978
- const normalized = [...values].map((value) => ({
2979
- at: value.at,
2980
- text: value.text.trim()
2981
- })).filter((value) => value.text.length > 0).sort((a, b) => {
2982
- const byAt = compareTimestampStrings(a.at, b.at);
2983
- if (byAt !== 0)
2984
- return byAt;
2985
- return a.text.localeCompare(b.text);
2986
- });
2987
- return normalized.length === 0 ? void 0 : normalized;
2948
+ function decodeToonItemContent(content) {
2949
+ try {
2950
+ return { value: decodeToon(content), usedScalarBracketEscape: false };
2951
+ } catch (strictError) {
2952
+ const escaped = escapeBracketsInQuotedScalars(content);
2953
+ if (escaped === content) {
2954
+ throw strictError;
2955
+ }
2956
+ return { value: decodeToon(escaped), usedScalarBracketEscape: true };
2957
+ }
2988
2958
  }
2989
- function normalizeRecurrenceRule(value) {
2990
- if (!value) {
2991
- return void 0;
2959
+
2960
+ // dist/core/shared/conflict-markers.js
2961
+ !(function() {
2962
+ try {
2963
+ var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
2964
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "d4a8b193-c056-5ac6-b08f-a3fcc10a5ba9");
2965
+ } catch (e2) {
2992
2966
  }
2993
- const normalizedFrequency = value.freq.trim().toLowerCase();
2994
- if (!RECURRENCE_FREQUENCY_VALUES.includes(normalizedFrequency)) {
2995
- return void 0;
2967
+ })();
2968
+ var CONFLICT_MARKER_PATTERN = /^\s*(<<<<<<<|=======|>>>>>>>)(?:\s.*)?$/;
2969
+ function findMergeConflictMarkers(content) {
2970
+ if (content.length === 0) {
2971
+ return [];
2996
2972
  }
2997
- const byWeekday = Array.from(new Set((value.by_weekday ?? []).map((weekday) => weekday.trim().toLowerCase()).filter((weekday) => RECURRENCE_WEEKDAY_VALUES.includes(weekday)))).sort((a, b) => weekdayOrderIndex(a) - weekdayOrderIndex(b));
2998
- const byMonthDay = Array.from(new Set((value.by_month_day ?? []).filter((day) => Number.isInteger(day) && day >= 1 && day <= 31).map((day) => day))).sort((a, b) => a - b);
2999
- const exdates = Array.from(new Set((value.exdates ?? []).map((timestamp) => timestamp.trim()).filter((timestamp) => isTimestampLiteral(timestamp)))).sort((a, b) => compareTimestampStrings(a, b));
3000
- const normalized = {
3001
- freq: normalizedFrequency,
3002
- interval: value.interval !== void 0 && value.interval > 1 ? value.interval : void 0,
3003
- count: value.count,
3004
- until: value.until?.trim() || void 0,
3005
- by_weekday: byWeekday.length > 0 ? byWeekday : void 0,
3006
- by_month_day: byMonthDay.length > 0 ? byMonthDay : void 0,
3007
- exdates: exdates.length > 0 ? exdates : void 0
3008
- };
3009
- for (const [key, fieldValue] of Object.entries(normalized)) {
3010
- if (fieldValue === void 0) {
3011
- delete normalized[key];
2973
+ const lines = content.split(/\r?\n/);
2974
+ const matches = [];
2975
+ for (let index = 0; index < lines.length; index += 1) {
2976
+ const line = lines[index] ?? "";
2977
+ const markerMatch = line.match(CONFLICT_MARKER_PATTERN);
2978
+ if (!markerMatch) {
2979
+ continue;
3012
2980
  }
2981
+ const marker = markerMatch[1];
2982
+ matches.push({
2983
+ line: index + 1,
2984
+ marker,
2985
+ text: line
2986
+ });
3013
2987
  }
3014
- return normalized;
2988
+ return matches;
3015
2989
  }
3016
- function sortEvents(values) {
3017
- if (!Array.isArray(values) || values.length === 0) {
3018
- return void 0;
2990
+ function findFirstMergeConflictMarker(content) {
2991
+ const matches = findMergeConflictMarkers(content);
2992
+ return matches[0];
2993
+ }
2994
+
2995
+ // dist/core/item/item-format.js
2996
+ !(function() {
2997
+ try {
2998
+ var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
2999
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "bc77f061-b1cd-5989-9a55-cd4259d397e0");
3000
+ } catch (e2) {
3019
3001
  }
3020
- const normalized = [...values].map(normalizeCalendarEvent).sort(compareCalendarEvents);
3021
- return normalized;
3002
+ })();
3003
+ var LINKED_TEST_PM_CONTEXT_MODE_VALUES = /* @__PURE__ */ new Set([
3004
+ "schema",
3005
+ "tracker",
3006
+ "auto"
3007
+ ]);
3008
+ var ITEM_TEST_RUN_STATUS_VALUES = /* @__PURE__ */ new Set([
3009
+ "passed",
3010
+ "failed",
3011
+ "stopped",
3012
+ "canceled"
3013
+ ]);
3014
+ var PLAN_STEP_STATUS_SET = new Set(PLAN_STEP_STATUS_VALUES);
3015
+ function normalizePathValue(value) {
3016
+ return value.replaceAll("\\", "/");
3022
3017
  }
3023
- function normalizeCalendarEvent(value) {
3024
- const event = {
3025
- start_at: value.start_at,
3026
- end_at: value.end_at || void 0,
3027
- title: value.title?.trim() || void 0,
3028
- description: value.description?.trim() || void 0,
3029
- location: value.location?.trim() || void 0,
3030
- all_day: value.all_day,
3031
- timezone: value.timezone?.trim() || void 0,
3032
- recurrence: normalizeRecurrenceRule(value.recurrence)
3033
- };
3034
- deleteUndefinedFields(event);
3035
- return event;
3018
+ function firstNonZeroComparison(comparisons) {
3019
+ for (const comparison of comparisons) {
3020
+ if (comparison !== 0) {
3021
+ return comparison;
3022
+ }
3023
+ }
3024
+ return 0;
3036
3025
  }
3037
- function compareCalendarEvents(a, b) {
3038
- return firstNonZeroComparison([
3039
- compareTimestampStrings(a.start_at, b.start_at),
3040
- (a.end_at ?? "").localeCompare(b.end_at ?? ""),
3041
- (a.title ?? "").localeCompare(b.title ?? ""),
3042
- Number(Boolean(a.all_day)) - Number(Boolean(b.all_day)),
3043
- (a.timezone ?? "").localeCompare(b.timezone ?? ""),
3044
- (a.location ?? "").localeCompare(b.location ?? ""),
3045
- (a.description ?? "").localeCompare(b.description ?? ""),
3046
- JSON.stringify(a.recurrence ?? {}).localeCompare(JSON.stringify(b.recurrence ?? {}))
3047
- ]);
3048
- }
3049
- function normalizeFiles(values) {
3050
- if (!values || values.length === 0)
3051
- return void 0;
3052
- return values.map((value) => ({
3053
- path: normalizePathValue(value.path),
3054
- scope: value.scope,
3055
- note: value.note?.trim() || void 0
3056
- }));
3026
+ function deleteUndefinedFields(record) {
3027
+ for (const [key, value] of Object.entries(record)) {
3028
+ if (value === void 0) {
3029
+ delete record[key];
3030
+ }
3031
+ }
3057
3032
  }
3058
- function normalizeTestRunSummaries(values) {
3059
- if (!values || values.length === 0)
3033
+ var REQUIRED_STRING_FIELDS = [
3034
+ "id",
3035
+ "title",
3036
+ "description",
3037
+ "created_at",
3038
+ "updated_at"
3039
+ ];
3040
+ var STATIC_ITEM_METADATA_FIELD_SET = new Set(ITEM_METADATA_KEY_ORDER);
3041
+ function resolveRuntimeSchemaValidationContext(options) {
3042
+ if (!options?.schema) {
3060
3043
  return void 0;
3061
- const normalized = values.map(normalizeTestRunSummary).filter((value) => value.run_id.length > 0 && value.started_at.length > 0 && value.finished_at.length > 0 && value.recorded_at.length > 0).sort((a, b) => firstNonZeroComparison([
3062
- compareTimestampStrings(a.recorded_at, b.recorded_at),
3063
- a.run_id.localeCompare(b.run_id),
3064
- a.kind.localeCompare(b.kind)
3065
- ]));
3066
- return normalized.length > 0 ? normalized : void 0;
3044
+ }
3045
+ return {
3046
+ statusRegistry: resolveRuntimeStatusRegistry(options.schema),
3047
+ fieldRegistry: resolveRuntimeFieldRegistry(options.schema),
3048
+ unknownFieldPolicy: options.schema.unknown_field_policy ?? "allow",
3049
+ extensionFieldNames: new Set(options.extensionFieldNames ?? []),
3050
+ onWarning: options.onWarning
3051
+ };
3067
3052
  }
3068
- function normalizeNonNegativeInteger(value) {
3069
- return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : void 0;
3053
+ function runtimeFieldRequiredForType(definition, typeName) {
3054
+ if (!definition.required) {
3055
+ return false;
3056
+ }
3057
+ if (definition.required_types.length === 0) {
3058
+ return true;
3059
+ }
3060
+ return definition.required_types.map((value) => value.toLowerCase()).includes(typeName.trim().toLowerCase());
3070
3061
  }
3071
- function normalizePositiveInteger(value) {
3072
- return typeof value === "number" && Number.isFinite(value) && value >= 1 ? Math.floor(value) : void 0;
3062
+ function validationError(message) {
3063
+ throw new PmCliError(`Invalid item metadata: ${message}`, EXIT_CODE.GENERIC_FAILURE);
3073
3064
  }
3074
- function stringOrEmpty(value) {
3075
- return typeof value === "string" ? value : "";
3065
+ function buildKnownItemMetadataKeys(runtimeContext) {
3066
+ const knownKeys = new Set(STATIC_ITEM_METADATA_FIELD_SET);
3067
+ for (const definition of runtimeContext.fieldRegistry?.definitions ?? []) {
3068
+ knownKeys.add(definition.metadata_key);
3069
+ }
3070
+ for (const fieldName of runtimeContext.extensionFieldNames) {
3071
+ knownKeys.add(fieldName);
3072
+ }
3073
+ return knownKeys;
3076
3074
  }
3077
- function normalizeTestRunSummary(value) {
3078
- const runId = typeof value.run_id === "string" ? value.run_id.trim() : "";
3079
- const kind = value.kind === "test" || value.kind === "test-all" ? value.kind : "test";
3080
- const status = ITEM_TEST_RUN_STATUS_VALUES.has(value.status) ? value.status : "failed";
3081
- const summary = {
3082
- run_id: runId,
3083
- kind,
3084
- status,
3085
- started_at: stringOrEmpty(value.started_at),
3086
- finished_at: stringOrEmpty(value.finished_at),
3087
- recorded_at: stringOrEmpty(value.recorded_at),
3088
- attempt: normalizePositiveInteger(value.attempt),
3089
- resumed_from: value.resumed_from?.trim() || void 0,
3090
- passed: normalizeNonNegativeInteger(value.passed) ?? 0,
3091
- failed: normalizeNonNegativeInteger(value.failed) ?? 0,
3092
- skipped: normalizeNonNegativeInteger(value.skipped) ?? 0,
3093
- items: normalizeNonNegativeInteger(value.items),
3094
- linked_tests: normalizeNonNegativeInteger(value.linked_tests),
3095
- fail_on_skipped_triggered: value.fail_on_skipped_triggered === true ? true : void 0
3096
- };
3097
- deleteUndefinedFields(summary);
3098
- return summary;
3075
+ function assertItemMetadataCondition(condition, message) {
3076
+ if (!condition) {
3077
+ validationError(message);
3078
+ }
3099
3079
  }
3100
- function sortTests(values) {
3101
- if (!Array.isArray(values) || values.length === 0)
3102
- return void 0;
3103
- return [...values].map(normalizeLinkedTest).sort(compareLinkedTests);
3080
+ function assertTimestampField(record, fieldName) {
3081
+ const rawValue = record[fieldName];
3082
+ assertItemMetadataCondition(typeof rawValue === "string", `${fieldName} must be a string`);
3083
+ const timestamp = rawValue;
3084
+ assertItemMetadataCondition(isTimestampLiteral(timestamp), `${fieldName} must be a valid ISO timestamp`);
3104
3085
  }
3105
- function normalizeTrimmedStringList(value) {
3106
- if (!Array.isArray(value)) {
3107
- return void 0;
3086
+ function assertPositiveIntegerField(record, fieldName, messagePrefix) {
3087
+ const value = record[fieldName];
3088
+ if (value === void 0) {
3089
+ return;
3108
3090
  }
3109
- const normalized = [
3110
- ...new Set(value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter((entry) => entry.length > 0))
3111
- ].sort((a, b) => a.localeCompare(b));
3112
- return normalized.length > 0 ? normalized : void 0;
3091
+ assertItemMetadataCondition(typeof value === "number" && Number.isInteger(value) && value >= 1, `${messagePrefix} must be an integer >= 1`);
3113
3092
  }
3114
- function isPlainObjectRecord(value) {
3115
- if (!value || typeof value !== "object" || Array.isArray(value)) {
3116
- return false;
3093
+ function assertOptionalTimestampString(record, fieldName, messagePrefix) {
3094
+ const value = record[fieldName];
3095
+ if (value === void 0) {
3096
+ return;
3117
3097
  }
3118
- const prototype = Object.getPrototypeOf(value);
3119
- return prototype === Object.prototype || prototype === null;
3120
- }
3121
- function isUnsafeObjectKey(key) {
3122
- return key === "__proto__" || key === "constructor" || key === "prototype";
3098
+ assertItemMetadataCondition(typeof value === "string", `${messagePrefix} must be a string`);
3099
+ assertItemMetadataCondition(isTimestampLiteral(value), `${messagePrefix} must be a valid ISO timestamp`);
3123
3100
  }
3124
- function normalizeStringRecord(value) {
3125
- if (!isPlainObjectRecord(value)) {
3126
- return void 0;
3101
+ function assertRecurrenceWeekdays(value) {
3102
+ if (value === void 0) {
3103
+ return;
3127
3104
  }
3128
- const entries = Object.entries(value).map(([key, recordValue]) => [key.trim(), String(recordValue).trim()]).filter(([key, recordValue]) => key.length > 0 && !isUnsafeObjectKey(key) && recordValue.length > 0).sort(([left], [right]) => left.localeCompare(right));
3129
- return entries.length > 0 ? Object.fromEntries(entries) : void 0;
3130
- }
3131
- function normalizeNumericRecord(value) {
3132
- if (!isPlainObjectRecord(value)) {
3133
- return void 0;
3105
+ assertItemMetadataCondition(Array.isArray(value), "event.recurrence.by_weekday must be an array");
3106
+ for (const weekday of value) {
3107
+ assertItemMetadataCondition(typeof weekday === "string", "event.recurrence.by_weekday entries must be strings");
3108
+ const normalizedWeekday = weekday.trim().toLowerCase();
3109
+ assertItemMetadataCondition(RECURRENCE_WEEKDAY_VALUES.includes(normalizedWeekday), `event.recurrence.by_weekday entries must be one of: ${RECURRENCE_WEEKDAY_VALUES.join(", ")}`);
3134
3110
  }
3135
- const entries = Object.entries(value).map(([key, recordValue]) => [key.trim(), Number(recordValue)]).filter(([key, recordValue]) => key.length > 0 && !isUnsafeObjectKey(key) && Number.isFinite(recordValue)).sort(([left], [right]) => left.localeCompare(right));
3136
- return entries.length > 0 ? Object.fromEntries(entries) : void 0;
3137
3111
  }
3138
- function normalizeLinkedTestContextMode(value) {
3139
- const normalized = value?.trim().toLowerCase();
3140
- if (!normalized || !LINKED_TEST_PM_CONTEXT_MODE_VALUES.has(normalized)) {
3141
- return void 0;
3112
+ function assertRecurrenceMonthDays(value) {
3113
+ if (value === void 0) {
3114
+ return;
3115
+ }
3116
+ assertItemMetadataCondition(Array.isArray(value), "event.recurrence.by_month_day must be an array");
3117
+ for (const day of value) {
3118
+ assertItemMetadataCondition(typeof day === "number" && Number.isInteger(day) && day >= 1 && day <= 31, "event.recurrence.by_month_day entries must be integers 1..31");
3142
3119
  }
3143
- return normalized;
3144
3120
  }
3145
- function normalizeLinkedTest(value) {
3146
- const test = {
3147
- command: value.command?.trim() || void 0,
3148
- path: value.path ? normalizePathValue(value.path) : void 0,
3149
- scope: value.scope,
3150
- timeout_seconds: typeof value.timeout_seconds === "number" && Number.isFinite(value.timeout_seconds) && value.timeout_seconds > 0 ? value.timeout_seconds : void 0,
3151
- pm_context_mode: normalizeLinkedTestContextMode(value.pm_context_mode),
3152
- env_set: normalizeStringRecord(value.env_set),
3153
- env_clear: normalizeTrimmedStringList(value.env_clear),
3154
- shared_host_safe: value.shared_host_safe === true ? true : void 0,
3155
- assert_stdout_contains: normalizeTrimmedStringList(value.assert_stdout_contains),
3156
- assert_stdout_regex: normalizeTrimmedStringList(value.assert_stdout_regex),
3157
- assert_stderr_contains: normalizeTrimmedStringList(value.assert_stderr_contains),
3158
- assert_stderr_regex: normalizeTrimmedStringList(value.assert_stderr_regex),
3159
- assert_stdout_min_lines: normalizeNonNegativeInteger(value.assert_stdout_min_lines),
3160
- assert_json_field_equals: normalizeStringRecord(value.assert_json_field_equals),
3161
- assert_json_field_gte: normalizeNumericRecord(value.assert_json_field_gte),
3162
- note: value.note?.trim() || void 0
3163
- };
3164
- deleteUndefinedFields(test);
3165
- return test;
3121
+ function assertRecurrenceExdates(value) {
3122
+ if (value === void 0) {
3123
+ return;
3124
+ }
3125
+ assertItemMetadataCondition(Array.isArray(value), "event.recurrence.exdates must be an array");
3126
+ for (const exdate of value) {
3127
+ assertItemMetadataCondition(typeof exdate === "string", "event.recurrence.exdates entries must be strings");
3128
+ assertItemMetadataCondition(isTimestampLiteral(exdate), "event.recurrence.exdates entries must be valid ISO timestamps");
3129
+ }
3166
3130
  }
3167
- function compareLinkedTests(a, b) {
3168
- return firstNonZeroComparison([
3169
- a.scope.localeCompare(b.scope),
3170
- compareOptionalStrings(a.path, b.path),
3171
- compareOptionalStrings(a.command, b.command),
3172
- compareOptionalNumbers(a.timeout_seconds, b.timeout_seconds),
3173
- compareOptionalStrings(a.pm_context_mode, b.pm_context_mode),
3174
- Number(Boolean(a.shared_host_safe)) - Number(Boolean(b.shared_host_safe)),
3175
- compareJsonValues(a.env_clear, b.env_clear, []),
3176
- compareJsonValues(a.env_set, b.env_set, {}),
3177
- compareJsonValues(a.assert_stdout_contains, b.assert_stdout_contains, []),
3178
- compareJsonValues(a.assert_stdout_regex, b.assert_stdout_regex, []),
3179
- compareJsonValues(a.assert_stderr_contains, b.assert_stderr_contains, []),
3180
- compareJsonValues(a.assert_stderr_regex, b.assert_stderr_regex, []),
3181
- compareOptionalNumbers(a.assert_stdout_min_lines, b.assert_stdout_min_lines),
3182
- compareJsonValues(a.assert_json_field_equals, b.assert_json_field_equals, {}),
3183
- compareJsonValues(a.assert_json_field_gte, b.assert_json_field_gte, {}),
3184
- compareOptionalStrings(a.note, b.note)
3185
- ]);
3131
+ function assertValidRecurrenceRule(recurrence) {
3132
+ assertItemMetadataCondition(typeof recurrence === "object" && recurrence !== null && !Array.isArray(recurrence), "event.recurrence must be an object");
3133
+ const recurrenceRecord = recurrence;
3134
+ assertItemMetadataCondition(typeof recurrenceRecord.freq === "string", "event.recurrence.freq must be a string");
3135
+ const frequency = recurrenceRecord.freq.trim().toLowerCase();
3136
+ assertItemMetadataCondition(RECURRENCE_FREQUENCY_VALUES.includes(frequency), `event.recurrence.freq must be one of: ${RECURRENCE_FREQUENCY_VALUES.join(", ")}`);
3137
+ assertPositiveIntegerField(recurrenceRecord, "interval", "event.recurrence.interval");
3138
+ assertPositiveIntegerField(recurrenceRecord, "count", "event.recurrence.count");
3139
+ assertOptionalTimestampString(recurrenceRecord, "until", "event.recurrence.until");
3140
+ assertRecurrenceWeekdays(recurrenceRecord.by_weekday);
3141
+ assertRecurrenceMonthDays(recurrenceRecord.by_month_day);
3142
+ assertRecurrenceExdates(recurrenceRecord.exdates);
3186
3143
  }
3187
- function compareOptionalStrings(left, right) {
3188
- return (left ?? "").localeCompare(right ?? "");
3144
+ function assertRequiredItemMetadataFields(record) {
3145
+ for (const fieldName of REQUIRED_STRING_FIELDS) {
3146
+ assertItemMetadataCondition(typeof record[fieldName] === "string", `${fieldName} is required and must be a string`);
3147
+ }
3148
+ const itemType = record.type;
3149
+ assertItemMetadataCondition(typeof itemType === "string" && itemType.trim().length > 0, "type must be a non-empty string");
3150
+ const formatVersion = record.pm_format_version;
3151
+ if (formatVersion !== void 0) {
3152
+ assertItemMetadataCondition(typeof formatVersion === "number" && Number.isInteger(formatVersion) && formatVersion >= BASELINE_ITEM_FORMAT_VERSION, `pm_format_version must be an integer >= ${BASELINE_ITEM_FORMAT_VERSION}`);
3153
+ }
3154
+ return itemType;
3189
3155
  }
3190
- function compareOptionalNumbers(left, right) {
3191
- return (left ?? 0) - (right ?? 0);
3156
+ function assertStatusItemMetadataField(record, runtimeContext) {
3157
+ const status = record.status;
3158
+ assertItemMetadataCondition(typeof status === "string" && status.trim().length > 0, "status must be a non-empty string");
3159
+ const statusRegistry = runtimeContext?.statusRegistry;
3160
+ const normalizedStatus = normalizeStatusInput(status, statusRegistry);
3161
+ const statusDomain = statusRegistry ? statusRegistry.definitions.map((definition) => definition.id) : [...STATUS_VALUES];
3162
+ assertItemMetadataCondition(normalizedStatus !== void 0, `status must be one of: ${statusDomain.join(", ")}`);
3192
3163
  }
3193
- function compareJsonValues(left, right, fallback) {
3194
- return JSON.stringify(left ?? fallback).localeCompare(JSON.stringify(right ?? fallback));
3164
+ function assertPriorityAndTags(record) {
3165
+ const priority = record.priority;
3166
+ assertItemMetadataCondition(typeof priority === "number" && Number.isInteger(priority) && [0, 1, 2, 3, 4].includes(priority), "priority must be an integer 0..4");
3167
+ const tags = record.tags;
3168
+ assertItemMetadataCondition(Array.isArray(tags), "tags must be an array");
3169
+ for (const tag of tags) {
3170
+ assertItemMetadataCondition(typeof tag === "string", "tags entries must be strings");
3171
+ }
3195
3172
  }
3196
- function sortDocs(values) {
3197
- if (!values || values.length === 0)
3198
- return void 0;
3199
- return [...values].map((value) => ({
3200
- path: normalizePathValue(value.path),
3201
- scope: value.scope,
3202
- note: value.note?.trim() || void 0
3203
- })).sort((a, b) => {
3204
- const byScope = a.scope.localeCompare(b.scope);
3205
- if (byScope !== 0)
3206
- return byScope;
3207
- const byPath = a.path.localeCompare(b.path);
3208
- if (byPath !== 0)
3209
- return byPath;
3210
- return (a.note ?? "").localeCompare(b.note ?? "");
3211
- });
3173
+ function assertConfidenceItemMetadataField(record) {
3174
+ const confidence = record.confidence;
3175
+ if (confidence === void 0) {
3176
+ return;
3177
+ }
3178
+ if (typeof confidence === "number") {
3179
+ assertItemMetadataCondition(Number.isInteger(confidence) && confidence >= 0 && confidence <= 100, "confidence number value must be an integer 0..100");
3180
+ return;
3181
+ }
3182
+ if (typeof confidence === "string") {
3183
+ const normalizedConfidence = confidence.trim().toLowerCase();
3184
+ const isKnownTextConfidence = normalizedConfidence === "med" || CONFIDENCE_TEXT_VALUES.includes(normalizedConfidence);
3185
+ assertItemMetadataCondition(isKnownTextConfidence, `confidence string value must be one of: ${[...CONFIDENCE_TEXT_VALUES, "med"].join(", ")}`);
3186
+ return;
3187
+ }
3188
+ assertItemMetadataCondition(false, "confidence must be a number or string");
3212
3189
  }
3213
- function trimStringOrUndefined(value) {
3214
- if (typeof value !== "string")
3215
- return void 0;
3216
- const trimmed = value.trim();
3217
- return trimmed.length > 0 ? trimmed : void 0;
3190
+ function assertSeverityItemMetadataField(record) {
3191
+ const severity = record.severity;
3192
+ if (severity === void 0) {
3193
+ return;
3194
+ }
3195
+ if (typeof severity !== "string") {
3196
+ validationError("severity must be a string");
3197
+ }
3198
+ const normalizedSeverity = severity.trim().toLowerCase();
3199
+ const isKnownSeverity = normalizedSeverity === "med" || ISSUE_SEVERITY_VALUES.includes(normalizedSeverity);
3200
+ assertItemMetadataCondition(isKnownSeverity, `severity value must be one of: ${[...ISSUE_SEVERITY_VALUES, "med"].join(", ")}`);
3218
3201
  }
3219
- function normalizePlanStepLinks(value) {
3220
- if (!Array.isArray(value))
3221
- return void 0;
3222
- const out = [];
3223
- for (const entry of value) {
3224
- if (entry === null || typeof entry !== "object")
3225
- continue;
3226
- const record = entry;
3227
- const id = trimStringOrUndefined(record.id);
3228
- const kind = trimStringOrUndefined(record.kind);
3229
- if (!id || !kind)
3230
- continue;
3231
- const link = { id, kind };
3232
- const note = trimStringOrUndefined(record.note);
3233
- if (note)
3234
- link.note = note;
3235
- if (record.required_before_step === true)
3236
- link.required_before_step = true;
3237
- out.push(link);
3202
+ function assertRegressionItemMetadataField(record) {
3203
+ if (record.regression !== void 0 && typeof record.regression !== "boolean") {
3204
+ validationError("regression must be a boolean");
3238
3205
  }
3239
- return out.length > 0 ? out : void 0;
3240
3206
  }
3241
- function normalizePlanStepFiles(value) {
3242
- if (!Array.isArray(value))
3243
- return void 0;
3244
- const out = [];
3245
- for (const entry of value) {
3246
- if (entry === null || typeof entry !== "object")
3247
- continue;
3248
- const record = entry;
3249
- const path6 = trimStringOrUndefined(record.path);
3250
- if (!path6)
3251
- continue;
3252
- const file = { path: normalizePathValue(path6) };
3253
- if (record.scope === "project" || record.scope === "global")
3254
- file.scope = record.scope;
3255
- const note = trimStringOrUndefined(record.note);
3256
- if (note)
3257
- file.note = note;
3258
- out.push(file);
3207
+ function assertReminderEntries(record) {
3208
+ const reminders = record.reminders;
3209
+ if (reminders === void 0) {
3210
+ return;
3211
+ }
3212
+ assertItemMetadataCondition(Array.isArray(reminders), "reminders must be an array");
3213
+ for (const reminder of reminders) {
3214
+ assertItemMetadataCondition(typeof reminder === "object" && reminder !== null && !Array.isArray(reminder), "reminders entries must be objects");
3215
+ const reminderRecord = reminder;
3216
+ assertItemMetadataCondition(typeof reminderRecord.at === "string", "reminder.at must be a string");
3217
+ assertItemMetadataCondition(isTimestampLiteral(reminderRecord.at), "reminder.at must be a valid ISO timestamp");
3218
+ assertItemMetadataCondition(typeof reminderRecord.text === "string", "reminder.text must be a string");
3219
+ assertItemMetadataCondition(reminderRecord.text.trim().length > 0, "reminder.text must not be empty");
3259
3220
  }
3260
- return out.length > 0 ? out : void 0;
3261
3221
  }
3262
- function normalizePlanStepTests(value) {
3263
- if (!Array.isArray(value))
3264
- return void 0;
3265
- const out = [];
3266
- for (const entry of value) {
3267
- if (entry === null || typeof entry !== "object")
3268
- continue;
3269
- const record = entry;
3270
- const command = trimStringOrUndefined(record.command);
3271
- const path6 = trimStringOrUndefined(record.path);
3272
- if (!command && !path6)
3273
- continue;
3274
- const test = {};
3275
- if (command)
3276
- test.command = command;
3277
- if (path6)
3278
- test.path = normalizePathValue(path6);
3279
- const note = trimStringOrUndefined(record.note);
3280
- if (note)
3281
- test.note = note;
3282
- out.push(test);
3222
+ function assertEventStringFields(eventRecord) {
3223
+ for (const stringField of [
3224
+ "title",
3225
+ "description",
3226
+ "location",
3227
+ "timezone"
3228
+ ]) {
3229
+ if (eventRecord[stringField] !== void 0) {
3230
+ assertItemMetadataCondition(typeof eventRecord[stringField] === "string", `event.${stringField} must be a string`);
3231
+ assertItemMetadataCondition(eventRecord[stringField].trim().length > 0, `event.${stringField} must not be empty`);
3232
+ }
3283
3233
  }
3284
- return out.length > 0 ? out : void 0;
3285
3234
  }
3286
- function normalizePlanStepDocs(value) {
3287
- if (!Array.isArray(value))
3288
- return void 0;
3289
- const out = [];
3290
- for (const entry of value) {
3291
- if (entry === null || typeof entry !== "object")
3292
- continue;
3293
- const record = entry;
3294
- const path6 = trimStringOrUndefined(record.path);
3295
- if (!path6)
3296
- continue;
3297
- const doc = { path: normalizePathValue(path6) };
3298
- if (record.scope === "project" || record.scope === "global")
3299
- doc.scope = record.scope;
3300
- const note = trimStringOrUndefined(record.note);
3301
- if (note)
3302
- doc.note = note;
3303
- out.push(doc);
3235
+ function assertEventRecurrence(eventRecord) {
3236
+ if (eventRecord.recurrence === void 0) {
3237
+ return;
3238
+ }
3239
+ assertValidRecurrenceRule(eventRecord.recurrence);
3240
+ if (eventRecord.recurrence.until !== void 0) {
3241
+ assertItemMetadataCondition(compareTimestampStrings(eventRecord.recurrence.until, eventRecord.start_at) >= 0, "event.recurrence.until must be at or after event.start_at");
3304
3242
  }
3305
- return out.length > 0 ? out : void 0;
3306
3243
  }
3307
- function normalizePlanStepEntry(entry) {
3308
- if (entry === null || typeof entry !== "object") {
3309
- return void 0;
3244
+ function assertCalendarEventEntry(event) {
3245
+ assertItemMetadataCondition(typeof event === "object" && event !== null && !Array.isArray(event), "events entries must be objects");
3246
+ const eventRecord = event;
3247
+ assertItemMetadataCondition(typeof eventRecord.start_at === "string", "event.start_at must be a string");
3248
+ assertItemMetadataCondition(isTimestampLiteral(eventRecord.start_at), "event.start_at must be a valid ISO timestamp");
3249
+ if (eventRecord.end_at !== void 0) {
3250
+ assertItemMetadataCondition(typeof eventRecord.end_at === "string", "event.end_at must be a string");
3251
+ assertItemMetadataCondition(isTimestampLiteral(eventRecord.end_at), "event.end_at must be a valid ISO timestamp");
3252
+ assertItemMetadataCondition(compareTimestampStrings(eventRecord.end_at, eventRecord.start_at) > 0, "event.end_at must be after event.start_at");
3310
3253
  }
3311
- const record = entry;
3312
- const id = trimStringOrUndefined(record.id);
3313
- const title = trimStringOrUndefined(record.title);
3314
- const statusRaw = trimStringOrUndefined(record.status);
3315
- const status = statusRaw && PLAN_STEP_STATUS_SET.has(statusRaw) ? statusRaw : void 0;
3316
- const order = coerceFiniteNumber(record.order) ?? Number.NaN;
3317
- const created_at = typeof record.created_at === "string" ? record.created_at : "";
3318
- const updated_at = typeof record.updated_at === "string" ? record.updated_at : "";
3319
- if (!id || !title || !status || !Number.isFinite(order) || !created_at || !updated_at) {
3320
- return void 0;
3254
+ assertEventStringFields(eventRecord);
3255
+ if (eventRecord.all_day !== void 0) {
3256
+ assertItemMetadataCondition(typeof eventRecord.all_day === "boolean", "event.all_day must be a boolean");
3321
3257
  }
3322
- const step = {
3323
- id,
3324
- order,
3325
- title,
3326
- status,
3327
- created_at,
3328
- updated_at
3329
- };
3330
- applyPlanStepOptionalFields(step, record);
3331
- return step;
3258
+ assertEventRecurrence(eventRecord);
3332
3259
  }
3333
- function applyPlanStepOptionalFields(step, record) {
3334
- const stringFields = [
3335
- ["body", "body"],
3336
- ["owner", "owner"],
3337
- ["evidence", "evidence"],
3338
- ["blocked_reason", "blocked_reason"],
3339
- ["superseded_by", "superseded_by"]
3340
- ];
3341
- for (const [target, source] of stringFields) {
3342
- const value = trimStringOrUndefined(record[source]);
3343
- if (value) {
3344
- step[target] = value;
3345
- }
3260
+ function assertCalendarEvents(record) {
3261
+ const events = record.events;
3262
+ if (events === void 0) {
3263
+ return;
3346
3264
  }
3347
- const completedAt = typeof record.completed_at === "string" ? record.completed_at : void 0;
3348
- if (completedAt && completedAt.length > 0) {
3349
- step.completed_at = completedAt;
3265
+ assertItemMetadataCondition(Array.isArray(events), "events must be an array");
3266
+ for (const event of events) {
3267
+ assertCalendarEventEntry(event);
3350
3268
  }
3351
- const collectionFields = [
3352
- ["linked_items", "linked_items", normalizePlanStepLinks],
3353
- ["files", "files", normalizePlanStepFiles],
3354
- ["tests", "tests", normalizePlanStepTests],
3355
- ["docs", "docs", normalizePlanStepDocs]
3356
- ];
3357
- for (const [target, source, normalize] of collectionFields) {
3358
- const value = normalize(record[source]);
3359
- if (value) {
3360
- step[target] = value;
3269
+ }
3270
+ function assertOptionalStringFields(record) {
3271
+ for (const fieldName of [
3272
+ "source_type",
3273
+ "source_owner",
3274
+ "design",
3275
+ "external_ref"
3276
+ ]) {
3277
+ const value = record[fieldName];
3278
+ if (value !== void 0) {
3279
+ assertItemMetadataCondition(typeof value === "string", `${fieldName} must be a string`);
3361
3280
  }
3362
3281
  }
3363
3282
  }
3364
- function normalizePlanSteps(value) {
3365
- if (!Array.isArray(value))
3366
- return void 0;
3367
- const out = value.flatMap((entry) => {
3368
- const step = normalizePlanStepEntry(entry);
3369
- return step ? [step] : [];
3370
- });
3371
- out.sort((left, right) => left.order - right.order);
3372
- return out.length > 0 ? out : void 0;
3373
- }
3374
- function normalizePlanDecisions(value) {
3375
- if (!Array.isArray(value))
3376
- return void 0;
3377
- const out = [];
3378
- for (const entry of value) {
3379
- if (entry === null || typeof entry !== "object")
3380
- continue;
3381
- const record = entry;
3382
- const ts = typeof record.ts === "string" ? record.ts : "";
3383
- const author = typeof record.author === "string" ? record.author : "";
3384
- const decision = trimStringOrUndefined(record.decision);
3385
- if (!ts || !author || !decision)
3386
- continue;
3387
- const item = { ts, author, decision };
3388
- const rationale = trimStringOrUndefined(record.rationale);
3389
- if (rationale)
3390
- item.rationale = rationale;
3391
- const evidence = trimStringOrUndefined(record.evidence);
3392
- if (evidence)
3393
- item.evidence = evidence;
3394
- const stepId = trimStringOrUndefined(record.step_id);
3395
- if (stepId)
3396
- item.step_id = stepId;
3397
- out.push(item);
3283
+ function assertTypeOptionsField(record) {
3284
+ const typeOptions = record.type_options;
3285
+ if (typeOptions === void 0) {
3286
+ return;
3398
3287
  }
3399
- return out.length > 0 ? out : void 0;
3400
- }
3401
- function normalizePlanDiscoveries(value) {
3402
- if (!Array.isArray(value))
3403
- return void 0;
3404
- const out = [];
3405
- for (const entry of value) {
3406
- if (entry === null || typeof entry !== "object")
3407
- continue;
3408
- const record = entry;
3409
- const ts = typeof record.ts === "string" ? record.ts : "";
3410
- const author = typeof record.author === "string" ? record.author : "";
3411
- const text = trimStringOrUndefined(record.text);
3412
- if (!ts || !author || !text)
3413
- continue;
3414
- const item = { ts, author, text };
3415
- const stepId = trimStringOrUndefined(record.step_id);
3416
- if (stepId)
3417
- item.step_id = stepId;
3418
- out.push(item);
3288
+ assertItemMetadataCondition(typeof typeOptions === "object" && typeOptions !== null && !Array.isArray(typeOptions), "type_options must be an object");
3289
+ for (const [optionKey, optionValue] of Object.entries(typeOptions)) {
3290
+ assertItemMetadataCondition(optionKey.trim().length > 0, "type_options keys must be non-empty");
3291
+ assertItemMetadataCondition(typeof optionValue === "string", "type_options values must be strings");
3292
+ const optionText = optionValue;
3293
+ assertItemMetadataCondition(optionText.trim().length > 0, "type_options values must be non-empty strings");
3419
3294
  }
3420
- return out.length > 0 ? out : void 0;
3421
3295
  }
3422
- function normalizePlanValidation(value) {
3423
- if (!Array.isArray(value))
3424
- return void 0;
3425
- const out = [];
3426
- for (const entry of value) {
3427
- if (entry === null || typeof entry !== "object")
3428
- continue;
3429
- const record = entry;
3430
- const text = trimStringOrUndefined(record.text);
3431
- if (!text)
3296
+ function coerceRuntimeItemMetadataFields(record, itemType, runtimeContext) {
3297
+ if (!runtimeContext?.fieldRegistry) {
3298
+ return;
3299
+ }
3300
+ for (const definition of runtimeContext.fieldRegistry.definitions) {
3301
+ const fieldValue = record[definition.metadata_key];
3302
+ if (fieldValue === void 0) {
3303
+ if (runtimeFieldRequiredForType(definition, itemType)) {
3304
+ validationError(`missing required schema field: ${definition.metadata_key}`);
3305
+ }
3432
3306
  continue;
3433
- const item = { text };
3434
- const command = trimStringOrUndefined(record.command);
3435
- if (command)
3436
- item.command = command;
3437
- const expected = trimStringOrUndefined(record.expected);
3438
- if (expected)
3439
- item.expected = expected;
3440
- out.push(item);
3307
+ }
3308
+ try {
3309
+ record[definition.metadata_key] = coerceRuntimeFieldValue(definition, fieldValue, `metadata field "${definition.metadata_key}"`);
3310
+ } catch (error) {
3311
+ validationError(String(error?.message).replace(/^Invalid\s+/u, ""));
3312
+ }
3441
3313
  }
3442
- return out.length > 0 ? out : void 0;
3443
3314
  }
3444
- function normalizeTypeOptions(values) {
3445
- if (!values) {
3446
- return void 0;
3315
+ function assertRuntimeUnknownItemMetadataFields(record, runtimeContext) {
3316
+ if (!runtimeContext || runtimeContext.unknownFieldPolicy === "allow") {
3317
+ return;
3447
3318
  }
3448
- const normalizedEntries = Object.entries(values).map(([key, value]) => [key.trim(), value.trim()]).filter(([key, value]) => key.length > 0 && value.length > 0).sort((left, right) => left[0].localeCompare(right[0]));
3449
- if (normalizedEntries.length === 0) {
3450
- return void 0;
3319
+ const knownKeys = buildKnownItemMetadataKeys(runtimeContext);
3320
+ const unknownKeys = Object.keys(record).filter((key) => !knownKeys.has(key)).sort((left, right) => left.localeCompare(right));
3321
+ if (unknownKeys.length === 0) {
3322
+ return;
3323
+ }
3324
+ if (runtimeContext.unknownFieldPolicy === "reject") {
3325
+ validationError(`unknown schema fields are not allowed: ${unknownKeys.join(", ")}`);
3326
+ } else {
3327
+ runtimeContext.onWarning?.(`item_unknown_schema_fields:${unknownKeys.join(",")}`);
3451
3328
  }
3452
- return Object.fromEntries(normalizedEntries);
3453
3329
  }
3454
- function normalizeBody(body) {
3455
- let start = 0;
3456
- while (start < body.length && body[start] === "\n") {
3457
- start += 1;
3330
+ function assertValidItemMetadata(itemMetadata, runtimeContext) {
3331
+ assertItemMetadataCondition(typeof itemMetadata === "object" && itemMetadata !== null && !Array.isArray(itemMetadata), "item metadata must be an object");
3332
+ const record = itemMetadata;
3333
+ const itemType = assertRequiredItemMetadataFields(record);
3334
+ assertStatusItemMetadataField(record, runtimeContext);
3335
+ assertPriorityAndTags(record);
3336
+ assertConfidenceItemMetadataField(record);
3337
+ assertSeverityItemMetadataField(record);
3338
+ assertRegressionItemMetadataField(record);
3339
+ assertTimestampField(record, "created_at");
3340
+ assertTimestampField(record, "updated_at");
3341
+ if (record.deadline !== void 0) {
3342
+ assertTimestampField(record, "deadline");
3458
3343
  }
3459
- return body.slice(start).trimEnd();
3344
+ assertReminderEntries(record);
3345
+ assertCalendarEvents(record);
3346
+ assertOptionalTimestampString(record, "closed_at", "closed_at");
3347
+ assertOptionalStringFields(record);
3348
+ assertTypeOptionsField(record);
3349
+ coerceRuntimeItemMetadataFields(record, itemType, runtimeContext);
3350
+ assertRuntimeUnknownItemMetadataFields(record, runtimeContext);
3460
3351
  }
3461
- function normalizeConfidenceValue(value) {
3462
- if (value === void 0) {
3352
+ function sortDependencies(values) {
3353
+ if (!values || values.length === 0)
3463
3354
  return void 0;
3464
- }
3465
- if (typeof value === "number") {
3466
- return value;
3467
- }
3468
- const normalized = value.trim().toLowerCase();
3469
- if (normalized === "med") {
3470
- return "medium";
3471
- }
3472
- if (CONFIDENCE_TEXT_VALUES.includes(normalized)) {
3473
- return normalized;
3474
- }
3475
- return void 0;
3355
+ return [...values].map((value) => ({
3356
+ id: value.id.trim().toLowerCase(),
3357
+ kind: value.kind,
3358
+ created_at: value.created_at,
3359
+ author: value.author?.trim() || void 0,
3360
+ source_kind: value.source_kind?.trim() || void 0
3361
+ })).sort((a, b) => {
3362
+ const byCreated = compareTimestampStrings(a.created_at, b.created_at);
3363
+ if (byCreated !== 0)
3364
+ return byCreated;
3365
+ const byId = a.id.localeCompare(b.id);
3366
+ if (byId !== 0)
3367
+ return byId;
3368
+ const byKind = a.kind.localeCompare(b.kind);
3369
+ if (byKind !== 0)
3370
+ return byKind;
3371
+ return (a.source_kind ?? "").localeCompare(b.source_kind ?? "");
3372
+ });
3476
3373
  }
3477
- function normalizeSeverityValue(value) {
3478
- if (value === void 0) {
3374
+ function sortLogValues(values) {
3375
+ if (!values || values.length === 0)
3479
3376
  return void 0;
3480
- }
3481
- const normalized = value.trim().toLowerCase();
3482
- if (normalized === "med") {
3483
- return "medium";
3484
- }
3485
- if (ISSUE_SEVERITY_VALUES.includes(normalized)) {
3486
- return normalized;
3487
- }
3488
- return void 0;
3377
+ return [...values].sort((a, b) => {
3378
+ const byCreated = compareTimestampStrings(a.created_at, b.created_at);
3379
+ if (byCreated !== 0)
3380
+ return byCreated;
3381
+ const byText = a.text.localeCompare(b.text);
3382
+ if (byText !== 0)
3383
+ return byText;
3384
+ return a.author.localeCompare(b.author);
3385
+ });
3489
3386
  }
3490
- function emptyStringToUndefined(value) {
3491
- return value || void 0;
3387
+ function sortReminders(values) {
3388
+ if (!values || values.length === 0)
3389
+ return void 0;
3390
+ const normalized = [...values].map((value) => ({
3391
+ at: value.at,
3392
+ text: value.text.trim()
3393
+ })).filter((value) => value.text.length > 0).sort((a, b) => {
3394
+ const byAt = compareTimestampStrings(a.at, b.at);
3395
+ if (byAt !== 0)
3396
+ return byAt;
3397
+ return a.text.localeCompare(b.text);
3398
+ });
3399
+ return normalized.length === 0 ? void 0 : normalized;
3492
3400
  }
3493
- function copyExtensionItemMetadataFields(normalized, source) {
3494
- const targetRecord = normalized;
3495
- const sourceRecord = source;
3496
- for (const [key, value] of Object.entries(sourceRecord)) {
3497
- if (isUnsafeObjectKey(key) || Object.prototype.hasOwnProperty.call(targetRecord, key) || value === void 0) {
3498
- continue;
3499
- }
3500
- targetRecord[key] = value;
3401
+ function normalizeRecurrenceRule(value) {
3402
+ if (!value) {
3403
+ return void 0;
3501
3404
  }
3502
- }
3503
- function coerceNormalizedRuntimeFields(normalized, runtimeContext) {
3504
- if (!runtimeContext?.fieldRegistry) {
3505
- return;
3405
+ const normalizedFrequency = value.freq.trim().toLowerCase();
3406
+ if (!RECURRENCE_FREQUENCY_VALUES.includes(normalizedFrequency)) {
3407
+ return void 0;
3506
3408
  }
3507
- const record = normalized;
3508
- for (const definition of runtimeContext.fieldRegistry.definitions) {
3509
- const currentValue = record[definition.metadata_key];
3510
- if (currentValue === void 0) {
3511
- continue;
3409
+ const byWeekday = Array.from(new Set((value.by_weekday ?? []).map((weekday) => weekday.trim().toLowerCase()).filter((weekday) => RECURRENCE_WEEKDAY_VALUES.includes(weekday)))).sort((a, b) => weekdayOrderIndex(a) - weekdayOrderIndex(b));
3410
+ const byMonthDay = Array.from(new Set((value.by_month_day ?? []).filter((day) => Number.isInteger(day) && day >= 1 && day <= 31).map((day) => day))).sort((a, b) => a - b);
3411
+ const exdates = Array.from(new Set((value.exdates ?? []).map((timestamp) => timestamp.trim()).filter((timestamp) => isTimestampLiteral(timestamp)))).sort((a, b) => compareTimestampStrings(a, b));
3412
+ const normalized = {
3413
+ freq: normalizedFrequency,
3414
+ interval: value.interval !== void 0 && value.interval > 1 ? value.interval : void 0,
3415
+ count: value.count,
3416
+ until: value.until?.trim() || void 0,
3417
+ by_weekday: byWeekday.length > 0 ? byWeekday : void 0,
3418
+ by_month_day: byMonthDay.length > 0 ? byMonthDay : void 0,
3419
+ exdates: exdates.length > 0 ? exdates : void 0
3420
+ };
3421
+ for (const [key, fieldValue] of Object.entries(normalized)) {
3422
+ if (fieldValue === void 0) {
3423
+ delete normalized[key];
3512
3424
  }
3513
- record[definition.metadata_key] = coerceRuntimeFieldValue(definition, currentValue, `metadata field "${definition.metadata_key}"`);
3514
3425
  }
3426
+ return normalized;
3515
3427
  }
3516
- function assertNormalizedUnknownFields(normalized, runtimeContext) {
3517
- if (!runtimeContext || runtimeContext.unknownFieldPolicy === "allow") {
3518
- return;
3519
- }
3520
- const knownKeys = buildKnownItemMetadataKeys(runtimeContext);
3521
- const record = normalized;
3522
- const unknownKeys = Object.keys(record).filter((key) => !knownKeys.has(key)).sort((left, right) => left.localeCompare(right));
3523
- if (unknownKeys.length > 0 && runtimeContext.unknownFieldPolicy === "reject") {
3524
- validationError(`unknown schema fields are not allowed: ${unknownKeys.join(", ")}`);
3525
- }
3526
- if (unknownKeys.length > 0) {
3527
- runtimeContext.onWarning?.(`item_unknown_schema_fields:${unknownKeys.join(",")}`);
3428
+ function sortEvents(values) {
3429
+ if (!Array.isArray(values) || values.length === 0) {
3430
+ return void 0;
3528
3431
  }
3529
- }
3530
- function normalizeItemMetadata(itemMetadata, options = {}) {
3531
- const runtimeContext = resolveRuntimeSchemaValidationContext(options);
3532
- const normalizedStatus = normalizeStatusInput(itemMetadata.status, runtimeContext?.statusRegistry) ?? itemMetadata.status;
3533
- const tags = Array.from(new Set(itemMetadata.tags.map((tag) => tag.trim().toLowerCase()).filter(Boolean))).sort((a, b) => a.localeCompare(b));
3534
- const normalized = {
3535
- id: itemMetadata.id,
3536
- title: itemMetadata.title,
3537
- description: itemMetadata.description,
3538
- type: itemMetadata.type,
3539
- pm_format_version: normalizeItemFormatVersion(itemMetadata.pm_format_version),
3540
- source_type: trimStringOrUndefined(itemMetadata.source_type),
3541
- type_options: normalizeTypeOptions(itemMetadata.type_options),
3542
- status: normalizedStatus,
3543
- priority: itemMetadata.priority,
3544
- tags,
3545
- created_at: itemMetadata.created_at,
3546
- updated_at: itemMetadata.updated_at,
3547
- dependencies: sortDependencies(itemMetadata.dependencies),
3548
- comments: sortLogValues(itemMetadata.comments),
3549
- notes: sortLogValues(itemMetadata.notes),
3550
- learnings: sortLogValues(itemMetadata.learnings),
3551
- files: normalizeFiles(itemMetadata.files),
3552
- tests: sortTests(itemMetadata.tests),
3553
- test_runs: normalizeTestRunSummaries(itemMetadata.test_runs),
3554
- docs: sortDocs(itemMetadata.docs),
3555
- deadline: emptyStringToUndefined(itemMetadata.deadline),
3556
- reminders: sortReminders(itemMetadata.reminders),
3557
- events: sortEvents(itemMetadata.events),
3558
- closed_at: emptyStringToUndefined(itemMetadata.closed_at),
3559
- assignee: trimStringOrUndefined(itemMetadata.assignee),
3560
- source_owner: trimStringOrUndefined(itemMetadata.source_owner),
3561
- author: emptyStringToUndefined(itemMetadata.author),
3562
- estimated_minutes: itemMetadata.estimated_minutes,
3563
- acceptance_criteria: itemMetadata.acceptance_criteria ?? void 0,
3564
- design: itemMetadata.design ?? void 0,
3565
- external_ref: itemMetadata.external_ref ?? void 0,
3566
- definition_of_ready: trimStringOrUndefined(itemMetadata.definition_of_ready),
3567
- order: itemMetadata.order,
3568
- goal: trimStringOrUndefined(itemMetadata.goal),
3569
- objective: trimStringOrUndefined(itemMetadata.objective),
3570
- value: trimStringOrUndefined(itemMetadata.value),
3571
- impact: trimStringOrUndefined(itemMetadata.impact),
3572
- outcome: trimStringOrUndefined(itemMetadata.outcome),
3573
- why_now: trimStringOrUndefined(itemMetadata.why_now),
3574
- parent: trimStringOrUndefined(itemMetadata.parent),
3575
- reviewer: trimStringOrUndefined(itemMetadata.reviewer),
3576
- risk: itemMetadata.risk ?? void 0,
3577
- confidence: normalizeConfidenceValue(itemMetadata.confidence),
3578
- sprint: trimStringOrUndefined(itemMetadata.sprint),
3579
- release: trimStringOrUndefined(itemMetadata.release),
3580
- blocked_by: trimStringOrUndefined(itemMetadata.blocked_by),
3581
- blocked_reason: trimStringOrUndefined(itemMetadata.blocked_reason),
3582
- unblock_note: trimStringOrUndefined(itemMetadata.unblock_note),
3583
- reporter: trimStringOrUndefined(itemMetadata.reporter),
3584
- severity: normalizeSeverityValue(itemMetadata.severity),
3585
- environment: trimStringOrUndefined(itemMetadata.environment),
3586
- repro_steps: trimStringOrUndefined(itemMetadata.repro_steps),
3587
- resolution: trimStringOrUndefined(itemMetadata.resolution),
3588
- expected_result: trimStringOrUndefined(itemMetadata.expected_result),
3589
- actual_result: trimStringOrUndefined(itemMetadata.actual_result),
3590
- affected_version: trimStringOrUndefined(itemMetadata.affected_version),
3591
- fixed_version: trimStringOrUndefined(itemMetadata.fixed_version),
3592
- component: trimStringOrUndefined(itemMetadata.component),
3593
- regression: itemMetadata.regression,
3594
- customer_impact: trimStringOrUndefined(itemMetadata.customer_impact),
3595
- close_reason: emptyStringToUndefined(itemMetadata.close_reason),
3596
- plan_mode: trimStringOrUndefined(itemMetadata.plan_mode),
3597
- plan_scope: trimStringOrUndefined(itemMetadata.plan_scope),
3598
- plan_harness: trimStringOrUndefined(itemMetadata.plan_harness),
3599
- plan_resume_context: trimStringOrUndefined(itemMetadata.plan_resume_context),
3600
- plan_steps: normalizePlanSteps(itemMetadata.plan_steps),
3601
- plan_decisions: normalizePlanDecisions(itemMetadata.plan_decisions),
3602
- plan_discoveries: normalizePlanDiscoveries(itemMetadata.plan_discoveries),
3603
- plan_validation: normalizePlanValidation(itemMetadata.plan_validation)
3432
+ const normalized = [...values].map(normalizeCalendarEvent).sort(compareCalendarEvents);
3433
+ return normalized;
3434
+ }
3435
+ function normalizeCalendarEvent(value) {
3436
+ const event = {
3437
+ start_at: value.start_at,
3438
+ end_at: value.end_at || void 0,
3439
+ title: value.title?.trim() || void 0,
3440
+ description: value.description?.trim() || void 0,
3441
+ location: value.location?.trim() || void 0,
3442
+ all_day: value.all_day,
3443
+ timezone: value.timezone?.trim() || void 0,
3444
+ recurrence: normalizeRecurrenceRule(value.recurrence)
3604
3445
  };
3605
- copyExtensionItemMetadataFields(normalized, itemMetadata);
3606
- coerceNormalizedRuntimeFields(normalized, runtimeContext);
3607
- assertNormalizedUnknownFields(normalized, runtimeContext);
3608
- deleteUndefinedFields(normalized);
3446
+ deleteUndefinedFields(event);
3447
+ return event;
3448
+ }
3449
+ function compareCalendarEvents(a, b) {
3450
+ return firstNonZeroComparison([
3451
+ compareTimestampStrings(a.start_at, b.start_at),
3452
+ (a.end_at ?? "").localeCompare(b.end_at ?? ""),
3453
+ (a.title ?? "").localeCompare(b.title ?? ""),
3454
+ Number(Boolean(a.all_day)) - Number(Boolean(b.all_day)),
3455
+ (a.timezone ?? "").localeCompare(b.timezone ?? ""),
3456
+ (a.location ?? "").localeCompare(b.location ?? ""),
3457
+ (a.description ?? "").localeCompare(b.description ?? ""),
3458
+ JSON.stringify(a.recurrence ?? {}).localeCompare(JSON.stringify(b.recurrence ?? {}))
3459
+ ]);
3460
+ }
3461
+ function normalizeFiles(values) {
3462
+ if (!values || values.length === 0)
3463
+ return void 0;
3464
+ return values.map((value) => ({
3465
+ path: normalizePathValue(value.path),
3466
+ scope: value.scope,
3467
+ note: value.note?.trim() || void 0
3468
+ }));
3469
+ }
3470
+ function normalizeTestRunSummaries(values) {
3471
+ if (!values || values.length === 0)
3472
+ return void 0;
3473
+ const normalized = values.map(normalizeTestRunSummary).filter((value) => value.run_id.length > 0 && value.started_at.length > 0 && value.finished_at.length > 0 && value.recorded_at.length > 0).sort((a, b) => firstNonZeroComparison([
3474
+ compareTimestampStrings(a.recorded_at, b.recorded_at),
3475
+ a.run_id.localeCompare(b.run_id),
3476
+ a.kind.localeCompare(b.kind)
3477
+ ]));
3478
+ return normalized.length > 0 ? normalized : void 0;
3479
+ }
3480
+ function normalizeNonNegativeInteger(value) {
3481
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : void 0;
3482
+ }
3483
+ function normalizePositiveInteger(value) {
3484
+ return typeof value === "number" && Number.isFinite(value) && value >= 1 ? Math.floor(value) : void 0;
3485
+ }
3486
+ function stringOrEmpty(value) {
3487
+ return typeof value === "string" ? value : "";
3488
+ }
3489
+ function normalizeTestRunSummary(value) {
3490
+ const runId = typeof value.run_id === "string" ? value.run_id.trim() : "";
3491
+ const kind = value.kind === "test" || value.kind === "test-all" ? value.kind : "test";
3492
+ const status = ITEM_TEST_RUN_STATUS_VALUES.has(value.status) ? value.status : "failed";
3493
+ const summary = {
3494
+ run_id: runId,
3495
+ kind,
3496
+ status,
3497
+ started_at: stringOrEmpty(value.started_at),
3498
+ finished_at: stringOrEmpty(value.finished_at),
3499
+ recorded_at: stringOrEmpty(value.recorded_at),
3500
+ attempt: normalizePositiveInteger(value.attempt),
3501
+ resumed_from: value.resumed_from?.trim() || void 0,
3502
+ passed: normalizeNonNegativeInteger(value.passed) ?? 0,
3503
+ failed: normalizeNonNegativeInteger(value.failed) ?? 0,
3504
+ skipped: normalizeNonNegativeInteger(value.skipped) ?? 0,
3505
+ items: normalizeNonNegativeInteger(value.items),
3506
+ linked_tests: normalizeNonNegativeInteger(value.linked_tests),
3507
+ fail_on_skipped_triggered: value.fail_on_skipped_triggered === true ? true : void 0
3508
+ };
3509
+ deleteUndefinedFields(summary);
3510
+ return summary;
3511
+ }
3512
+ function sortTests(values) {
3513
+ if (!Array.isArray(values) || values.length === 0)
3514
+ return void 0;
3515
+ return [...values].map(normalizeLinkedTest).sort(compareLinkedTests);
3516
+ }
3517
+ function normalizeTrimmedStringList(value) {
3518
+ if (!Array.isArray(value)) {
3519
+ return void 0;
3520
+ }
3521
+ const normalized = [
3522
+ ...new Set(value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter((entry) => entry.length > 0))
3523
+ ].sort((a, b) => a.localeCompare(b));
3524
+ return normalized.length > 0 ? normalized : void 0;
3525
+ }
3526
+ function isPlainObjectRecord(value) {
3527
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
3528
+ return false;
3529
+ }
3530
+ const prototype = Object.getPrototypeOf(value);
3531
+ return prototype === Object.prototype || prototype === null;
3532
+ }
3533
+ function isUnsafeObjectKey(key) {
3534
+ return key === "__proto__" || key === "constructor" || key === "prototype";
3535
+ }
3536
+ function normalizeStringRecord(value) {
3537
+ if (!isPlainObjectRecord(value)) {
3538
+ return void 0;
3539
+ }
3540
+ const entries = Object.entries(value).map(([key, recordValue]) => [key.trim(), String(recordValue).trim()]).filter(([key, recordValue]) => key.length > 0 && !isUnsafeObjectKey(key) && recordValue.length > 0).sort(([left], [right]) => left.localeCompare(right));
3541
+ return entries.length > 0 ? Object.fromEntries(entries) : void 0;
3542
+ }
3543
+ function normalizeNumericRecord(value) {
3544
+ if (!isPlainObjectRecord(value)) {
3545
+ return void 0;
3546
+ }
3547
+ const entries = Object.entries(value).map(([key, recordValue]) => [key.trim(), Number(recordValue)]).filter(([key, recordValue]) => key.length > 0 && !isUnsafeObjectKey(key) && Number.isFinite(recordValue)).sort(([left], [right]) => left.localeCompare(right));
3548
+ return entries.length > 0 ? Object.fromEntries(entries) : void 0;
3549
+ }
3550
+ function normalizeLinkedTestContextMode(value) {
3551
+ const normalized = value?.trim().toLowerCase();
3552
+ if (!normalized || !LINKED_TEST_PM_CONTEXT_MODE_VALUES.has(normalized)) {
3553
+ return void 0;
3554
+ }
3609
3555
  return normalized;
3610
3556
  }
3611
- function orderItemMetadata(itemMetadata) {
3612
- return orderObject(itemMetadata, ITEM_METADATA_KEY_ORDER);
3557
+ function normalizeLinkedTest(value) {
3558
+ const test = {
3559
+ command: value.command?.trim() || void 0,
3560
+ path: value.path ? normalizePathValue(value.path) : void 0,
3561
+ scope: value.scope,
3562
+ timeout_seconds: typeof value.timeout_seconds === "number" && Number.isFinite(value.timeout_seconds) && value.timeout_seconds > 0 ? value.timeout_seconds : void 0,
3563
+ pm_context_mode: normalizeLinkedTestContextMode(value.pm_context_mode),
3564
+ env_set: normalizeStringRecord(value.env_set),
3565
+ env_clear: normalizeTrimmedStringList(value.env_clear),
3566
+ shared_host_safe: value.shared_host_safe === true ? true : void 0,
3567
+ assert_stdout_contains: normalizeTrimmedStringList(value.assert_stdout_contains),
3568
+ assert_stdout_regex: normalizeTrimmedStringList(value.assert_stdout_regex),
3569
+ assert_stderr_contains: normalizeTrimmedStringList(value.assert_stderr_contains),
3570
+ assert_stderr_regex: normalizeTrimmedStringList(value.assert_stderr_regex),
3571
+ assert_stdout_min_lines: normalizeNonNegativeInteger(value.assert_stdout_min_lines),
3572
+ assert_json_field_equals: normalizeStringRecord(value.assert_json_field_equals),
3573
+ assert_json_field_gte: normalizeNumericRecord(value.assert_json_field_gte),
3574
+ note: value.note?.trim() || void 0
3575
+ };
3576
+ deleteUndefinedFields(test);
3577
+ return test;
3613
3578
  }
3614
- function findJsonObjectEnd(content) {
3615
- let depth = 0;
3616
- let inString = false;
3617
- let escaped = false;
3618
- for (let i = 0; i < content.length; i += 1) {
3619
- const char = content[i];
3620
- if (inString) {
3621
- if (escaped) {
3622
- escaped = false;
3623
- continue;
3624
- }
3625
- if (char === "\\") {
3626
- escaped = true;
3627
- continue;
3628
- }
3629
- if (char === '"') {
3630
- inString = false;
3631
- }
3579
+ function compareLinkedTests(a, b) {
3580
+ return firstNonZeroComparison([
3581
+ a.scope.localeCompare(b.scope),
3582
+ compareOptionalStrings(a.path, b.path),
3583
+ compareOptionalStrings(a.command, b.command),
3584
+ compareOptionalNumbers(a.timeout_seconds, b.timeout_seconds),
3585
+ compareOptionalStrings(a.pm_context_mode, b.pm_context_mode),
3586
+ Number(Boolean(a.shared_host_safe)) - Number(Boolean(b.shared_host_safe)),
3587
+ compareJsonValues(a.env_clear, b.env_clear, []),
3588
+ compareJsonValues(a.env_set, b.env_set, {}),
3589
+ compareJsonValues(a.assert_stdout_contains, b.assert_stdout_contains, []),
3590
+ compareJsonValues(a.assert_stdout_regex, b.assert_stdout_regex, []),
3591
+ compareJsonValues(a.assert_stderr_contains, b.assert_stderr_contains, []),
3592
+ compareJsonValues(a.assert_stderr_regex, b.assert_stderr_regex, []),
3593
+ compareOptionalNumbers(a.assert_stdout_min_lines, b.assert_stdout_min_lines),
3594
+ compareJsonValues(a.assert_json_field_equals, b.assert_json_field_equals, {}),
3595
+ compareJsonValues(a.assert_json_field_gte, b.assert_json_field_gte, {}),
3596
+ compareOptionalStrings(a.note, b.note)
3597
+ ]);
3598
+ }
3599
+ function compareOptionalStrings(left, right) {
3600
+ return (left ?? "").localeCompare(right ?? "");
3601
+ }
3602
+ function compareOptionalNumbers(left, right) {
3603
+ return (left ?? 0) - (right ?? 0);
3604
+ }
3605
+ function compareJsonValues(left, right, fallback) {
3606
+ return JSON.stringify(left ?? fallback).localeCompare(JSON.stringify(right ?? fallback));
3607
+ }
3608
+ function sortDocs(values) {
3609
+ if (!values || values.length === 0)
3610
+ return void 0;
3611
+ return [...values].map((value) => ({
3612
+ path: normalizePathValue(value.path),
3613
+ scope: value.scope,
3614
+ note: value.note?.trim() || void 0
3615
+ })).sort((a, b) => {
3616
+ const byScope = a.scope.localeCompare(b.scope);
3617
+ if (byScope !== 0)
3618
+ return byScope;
3619
+ const byPath = a.path.localeCompare(b.path);
3620
+ if (byPath !== 0)
3621
+ return byPath;
3622
+ return (a.note ?? "").localeCompare(b.note ?? "");
3623
+ });
3624
+ }
3625
+ function trimStringOrUndefined(value) {
3626
+ if (typeof value !== "string")
3627
+ return void 0;
3628
+ const trimmed = value.trim();
3629
+ return trimmed.length > 0 ? trimmed : void 0;
3630
+ }
3631
+ function normalizePlanStepLinks(value) {
3632
+ if (!Array.isArray(value))
3633
+ return void 0;
3634
+ const out = [];
3635
+ for (const entry of value) {
3636
+ if (entry === null || typeof entry !== "object")
3632
3637
  continue;
3633
- }
3634
- if (char === '"') {
3635
- inString = true;
3638
+ const record = entry;
3639
+ const id = trimStringOrUndefined(record.id);
3640
+ const kind = trimStringOrUndefined(record.kind);
3641
+ if (!id || !kind)
3636
3642
  continue;
3637
- }
3638
- if (char === "{") {
3639
- depth += 1;
3643
+ const link = { id, kind };
3644
+ const note = trimStringOrUndefined(record.note);
3645
+ if (note)
3646
+ link.note = note;
3647
+ if (record.required_before_step === true)
3648
+ link.required_before_step = true;
3649
+ out.push(link);
3650
+ }
3651
+ return out.length > 0 ? out : void 0;
3652
+ }
3653
+ function normalizePlanStepFiles(value) {
3654
+ if (!Array.isArray(value))
3655
+ return void 0;
3656
+ const out = [];
3657
+ for (const entry of value) {
3658
+ if (entry === null || typeof entry !== "object")
3640
3659
  continue;
3641
- }
3642
- if (char === "}") {
3643
- depth -= 1;
3644
- if (depth === 0) {
3645
- return i;
3646
- }
3647
- }
3660
+ const record = entry;
3661
+ const path6 = trimStringOrUndefined(record.path);
3662
+ if (!path6)
3663
+ continue;
3664
+ const file = { path: normalizePathValue(path6) };
3665
+ if (record.scope === "project" || record.scope === "global")
3666
+ file.scope = record.scope;
3667
+ const note = trimStringOrUndefined(record.note);
3668
+ if (note)
3669
+ file.note = note;
3670
+ out.push(file);
3671
+ }
3672
+ return out.length > 0 ? out : void 0;
3673
+ }
3674
+ function normalizePlanStepTests(value) {
3675
+ if (!Array.isArray(value))
3676
+ return void 0;
3677
+ const out = [];
3678
+ for (const entry of value) {
3679
+ if (entry === null || typeof entry !== "object")
3680
+ continue;
3681
+ const record = entry;
3682
+ const command = trimStringOrUndefined(record.command);
3683
+ const path6 = trimStringOrUndefined(record.path);
3684
+ if (!command && !path6)
3685
+ continue;
3686
+ const test = {};
3687
+ if (command)
3688
+ test.command = command;
3689
+ if (path6)
3690
+ test.path = normalizePathValue(path6);
3691
+ const note = trimStringOrUndefined(record.note);
3692
+ if (note)
3693
+ test.note = note;
3694
+ out.push(test);
3695
+ }
3696
+ return out.length > 0 ? out : void 0;
3697
+ }
3698
+ function normalizePlanStepDocs(value) {
3699
+ if (!Array.isArray(value))
3700
+ return void 0;
3701
+ const out = [];
3702
+ for (const entry of value) {
3703
+ if (entry === null || typeof entry !== "object")
3704
+ continue;
3705
+ const record = entry;
3706
+ const path6 = trimStringOrUndefined(record.path);
3707
+ if (!path6)
3708
+ continue;
3709
+ const doc = { path: normalizePathValue(path6) };
3710
+ if (record.scope === "project" || record.scope === "global")
3711
+ doc.scope = record.scope;
3712
+ const note = trimStringOrUndefined(record.note);
3713
+ if (note)
3714
+ doc.note = note;
3715
+ out.push(doc);
3716
+ }
3717
+ return out.length > 0 ? out : void 0;
3718
+ }
3719
+ function normalizePlanStepEntry(entry) {
3720
+ if (entry === null || typeof entry !== "object") {
3721
+ return void 0;
3722
+ }
3723
+ const record = entry;
3724
+ const id = trimStringOrUndefined(record.id);
3725
+ const title = trimStringOrUndefined(record.title);
3726
+ const statusRaw = trimStringOrUndefined(record.status);
3727
+ const status = statusRaw && PLAN_STEP_STATUS_SET.has(statusRaw) ? statusRaw : void 0;
3728
+ const order = coerceFiniteNumber(record.order) ?? Number.NaN;
3729
+ const created_at = typeof record.created_at === "string" ? record.created_at : "";
3730
+ const updated_at = typeof record.updated_at === "string" ? record.updated_at : "";
3731
+ if (!id || !title || !status || !Number.isFinite(order) || !created_at || !updated_at) {
3732
+ return void 0;
3648
3733
  }
3649
- return -1;
3734
+ const step = {
3735
+ id,
3736
+ order,
3737
+ title,
3738
+ status,
3739
+ created_at,
3740
+ updated_at
3741
+ };
3742
+ applyPlanStepOptionalFields(step, record);
3743
+ return step;
3650
3744
  }
3651
- function splitFrontMatter(content) {
3652
- if (!content.startsWith("{")) {
3653
- return { frontMatter: "", body: content };
3654
- }
3655
- const end = findJsonObjectEnd(content);
3656
- if (end < 0) {
3657
- return { frontMatter: "", body: content };
3745
+ function applyPlanStepOptionalFields(step, record) {
3746
+ const stringFields = [
3747
+ ["body", "body"],
3748
+ ["owner", "owner"],
3749
+ ["evidence", "evidence"],
3750
+ ["blocked_reason", "blocked_reason"],
3751
+ ["superseded_by", "superseded_by"]
3752
+ ];
3753
+ for (const [target, source] of stringFields) {
3754
+ const value = trimStringOrUndefined(record[source]);
3755
+ if (value) {
3756
+ step[target] = value;
3757
+ }
3658
3758
  }
3659
- const frontMatter = content.slice(0, end + 1);
3660
- const body = content.slice(end + 1).replace(/^\r?\n+/, "");
3661
- return { frontMatter, body };
3662
- }
3663
- function stripLeadingYamlDocument(content) {
3664
- const normalizedContent = content.charCodeAt(0) === 65279 ? content.slice(1) : content;
3665
- const opener = normalizedContent.match(/^[ \t]*---[ \t]*(?:\r?\n|$)/);
3666
- if (!opener) {
3667
- return { content: normalizedContent, stripped: false };
3759
+ const completedAt = typeof record.completed_at === "string" ? record.completed_at : void 0;
3760
+ if (completedAt && completedAt.length > 0) {
3761
+ step.completed_at = completedAt;
3668
3762
  }
3669
- let cursor = opener[0].length;
3670
- while (cursor < normalizedContent.length) {
3671
- const nextNewline = normalizedContent.indexOf("\n", cursor);
3672
- const lineEnd = nextNewline === -1 ? normalizedContent.length : nextNewline;
3673
- const line = normalizedContent.slice(cursor, lineEnd).replace(/\r$/, "");
3674
- const afterLine = nextNewline === -1 ? lineEnd : lineEnd + 1;
3675
- if (line.trim() === "---") {
3676
- return {
3677
- content: normalizedContent.slice(afterLine).replace(/^\s+/, ""),
3678
- stripped: true
3679
- };
3763
+ const collectionFields = [
3764
+ ["linked_items", "linked_items", normalizePlanStepLinks],
3765
+ ["files", "files", normalizePlanStepFiles],
3766
+ ["tests", "tests", normalizePlanStepTests],
3767
+ ["docs", "docs", normalizePlanStepDocs]
3768
+ ];
3769
+ for (const [target, source, normalize] of collectionFields) {
3770
+ const value = normalize(record[source]);
3771
+ if (value) {
3772
+ step[target] = value;
3680
3773
  }
3681
- cursor = afterLine;
3682
3774
  }
3683
- return { content: normalizedContent, stripped: false };
3684
3775
  }
3685
- function normalizeParsedItemMetadata(itemMetadata, options) {
3686
- return normalizeItemMetadata(itemMetadata, {
3687
- ...options,
3688
- onWarning: void 0
3776
+ function normalizePlanSteps(value) {
3777
+ if (!Array.isArray(value))
3778
+ return void 0;
3779
+ const out = value.flatMap((entry) => {
3780
+ const step = normalizePlanStepEntry(entry);
3781
+ return step ? [step] : [];
3689
3782
  });
3783
+ out.sort((left, right) => left.order - right.order);
3784
+ return out.length > 0 ? out : void 0;
3690
3785
  }
3691
- function parseJsonMarkdownItemDocument(content, runtimeContext, options = {}) {
3692
- const normalized = stripLeadingYamlDocument(content);
3693
- if (normalized.stripped) {
3694
- options.onWarning?.("json_markdown_leading_yaml_frontmatter_ignored");
3695
- }
3696
- const { frontMatter, body } = splitFrontMatter(normalized.content);
3697
- if (!frontMatter) {
3698
- const trimmed = content.trimStart();
3699
- if (trimmed.startsWith("{")) {
3700
- validationError("JSON front matter is not valid JSON");
3701
- }
3702
- validationError("missing JSON front matter");
3703
- }
3704
- let parsed;
3705
- try {
3706
- parsed = JSON.parse(frontMatter);
3707
- } catch {
3708
- validationError("JSON front matter is not valid JSON");
3786
+ function normalizePlanDecisions(value) {
3787
+ if (!Array.isArray(value))
3788
+ return void 0;
3789
+ const out = [];
3790
+ for (const entry of value) {
3791
+ if (entry === null || typeof entry !== "object")
3792
+ continue;
3793
+ const record = entry;
3794
+ const ts = typeof record.ts === "string" ? record.ts : "";
3795
+ const author = typeof record.author === "string" ? record.author : "";
3796
+ const decision = trimStringOrUndefined(record.decision);
3797
+ if (!ts || !author || !decision)
3798
+ continue;
3799
+ const item = { ts, author, decision };
3800
+ const rationale = trimStringOrUndefined(record.rationale);
3801
+ if (rationale)
3802
+ item.rationale = rationale;
3803
+ const evidence = trimStringOrUndefined(record.evidence);
3804
+ if (evidence)
3805
+ item.evidence = evidence;
3806
+ const stepId = trimStringOrUndefined(record.step_id);
3807
+ if (stepId)
3808
+ item.step_id = stepId;
3809
+ out.push(item);
3709
3810
  }
3710
- assertValidItemMetadata(parsed, runtimeContext);
3711
- return {
3712
- metadata: normalizeParsedItemMetadata(parsed, options),
3713
- body: normalizeBody(body)
3714
- };
3811
+ return out.length > 0 ? out : void 0;
3715
3812
  }
3716
- function parseToonItemDocument(content, runtimeContext, options = {}) {
3717
- let parsed;
3718
- try {
3719
- parsed = decodeToonItemContent(content).value;
3720
- } catch {
3721
- validationError("TOON item document is not valid TOON");
3722
- }
3723
- assertItemMetadataCondition(typeof parsed === "object" && parsed !== null && !Array.isArray(parsed), "TOON item document must be an object");
3724
- const record = parsed;
3725
- if (Object.prototype.hasOwnProperty.call(record, "front_matter")) {
3726
- assertValidItemMetadata(record.front_matter, runtimeContext);
3727
- assertItemMetadataCondition(record.body === void 0 || typeof record.body === "string", "TOON item document body must be a string");
3728
- return {
3729
- metadata: normalizeParsedItemMetadata(record.front_matter, options),
3730
- body: normalizeBody(typeof record.body === "string" ? record.body : "")
3731
- };
3813
+ function normalizePlanDiscoveries(value) {
3814
+ if (!Array.isArray(value))
3815
+ return void 0;
3816
+ const out = [];
3817
+ for (const entry of value) {
3818
+ if (entry === null || typeof entry !== "object")
3819
+ continue;
3820
+ const record = entry;
3821
+ const ts = typeof record.ts === "string" ? record.ts : "";
3822
+ const author = typeof record.author === "string" ? record.author : "";
3823
+ const text = trimStringOrUndefined(record.text);
3824
+ if (!ts || !author || !text)
3825
+ continue;
3826
+ const item = { ts, author, text };
3827
+ const stepId = trimStringOrUndefined(record.step_id);
3828
+ if (stepId)
3829
+ item.step_id = stepId;
3830
+ out.push(item);
3732
3831
  }
3733
- const { body, ...itemMetadataRecord } = record;
3734
- assertItemMetadataCondition(body === void 0 || typeof body === "string", "TOON item document body must be a string");
3735
- assertValidItemMetadata(itemMetadataRecord, runtimeContext);
3736
- return {
3737
- metadata: normalizeParsedItemMetadata(itemMetadataRecord, options),
3738
- body: normalizeBody(typeof body === "string" ? body : "")
3739
- };
3832
+ return out.length > 0 ? out : void 0;
3740
3833
  }
3741
- function serializeJsonMarkdownItemDocument(document, options = {}) {
3742
- const normalizedMetadata = normalizeItemMetadata(document.metadata, options);
3743
- const orderedMetadata = orderItemMetadata(normalizedMetadata);
3744
- const serializedMetadata = JSON.stringify(orderedMetadata, null, 2);
3745
- const normalizedBody = normalizeBody(document.body ?? "");
3746
- if (!normalizedBody) {
3747
- return `${serializedMetadata}
3748
- `;
3834
+ function normalizePlanValidation(value) {
3835
+ if (!Array.isArray(value))
3836
+ return void 0;
3837
+ const out = [];
3838
+ for (const entry of value) {
3839
+ if (entry === null || typeof entry !== "object")
3840
+ continue;
3841
+ const record = entry;
3842
+ const text = trimStringOrUndefined(record.text);
3843
+ if (!text)
3844
+ continue;
3845
+ const item = { text };
3846
+ const command = trimStringOrUndefined(record.command);
3847
+ if (command)
3848
+ item.command = command;
3849
+ const expected = trimStringOrUndefined(record.expected);
3850
+ if (expected)
3851
+ item.expected = expected;
3852
+ out.push(item);
3749
3853
  }
3750
- return `${serializedMetadata}
3751
-
3752
- ${normalizedBody}
3753
- `;
3754
- }
3755
- function serializeToonItemDocument(document, options = {}) {
3756
- const normalizedMetadata = normalizeItemMetadata(document.metadata, options);
3757
- const orderedMetadata = orderItemMetadata(normalizedMetadata);
3758
- const normalizedBody = normalizeBody(document.body ?? "");
3759
- return `${encodeToon({ ...orderedMetadata, body: normalizedBody })}
3760
- `;
3854
+ return out.length > 0 ? out : void 0;
3761
3855
  }
3762
- function parseItemDocument(content, options = {}) {
3763
- const conflictMarker = findFirstMergeConflictMarker(content);
3764
- if (conflictMarker) {
3765
- throw new PmCliError(`Merge conflict markers detected in item document at line ${conflictMarker.line} (${conflictMarker.marker}). Resolve <<<<<<< ======= >>>>>>> markers and retry.`, EXIT_CODE.GENERIC_FAILURE, {
3766
- code: "merge_conflict_markers_detected",
3767
- required: "Resolve merge-conflict markers in the item file before parsing or mutation commands.",
3768
- why: "Partially merged documents can corrupt item metadata and history integrity.",
3769
- examples: ["git status", "git add <resolved-file> && git commit"],
3770
- nextSteps: [
3771
- "Resolve conflicts, save the file, then rerun the pm command."
3772
- ]
3773
- });
3856
+ function normalizeTypeOptions(values) {
3857
+ if (!values) {
3858
+ return void 0;
3774
3859
  }
3775
- const format = options.format ?? "toon";
3776
- const runtimeContext = resolveRuntimeSchemaValidationContext(options);
3777
- return format === "toon" ? parseToonItemDocument(content, runtimeContext, options) : parseJsonMarkdownItemDocument(content, runtimeContext, options);
3778
- }
3779
- function serializeItemDocument(document, options = {}) {
3780
- const format = options.format ?? "toon";
3781
- return format === "toon" ? serializeToonItemDocument(document, options) : serializeJsonMarkdownItemDocument(document, options);
3782
- }
3783
- function canonicalDocument(document, options = {}) {
3784
- return {
3785
- metadata: normalizeItemMetadata(document.metadata, options),
3786
- body: normalizeBody(document.body ?? "")
3787
- };
3788
- }
3789
-
3790
- // dist/core/item/item-record.js
3791
- !(function() {
3792
- try {
3793
- var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
3794
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "30de0e7a-3307-5231-af8c-bae7a2b6374b");
3795
- } catch (e2) {
3860
+ const normalizedEntries = Object.entries(values).map(([key, value]) => [key.trim(), value.trim()]).filter(([key, value]) => key.length > 0 && value.length > 0).sort((left, right) => left[0].localeCompare(right[0]));
3861
+ if (normalizedEntries.length === 0) {
3862
+ return void 0;
3796
3863
  }
3797
- })();
3798
- function toItemRecord(item) {
3799
- return item;
3864
+ return Object.fromEntries(normalizedEntries);
3865
+ }
3866
+ function normalizeBody(body) {
3867
+ let start = 0;
3868
+ while (start < body.length && body[start] === "\n") {
3869
+ start += 1;
3870
+ }
3871
+ return body.slice(start).trimEnd();
3800
3872
  }
3801
-
3802
- // dist/core/history/history.js
3803
- import jsonPatch from "fast-json-patch";
3804
- !(function() {
3805
- try {
3806
- var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
3807
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "45cc07c9-b6f9-5851-9f98-4167976035b1");
3808
- } catch (e2) {
3873
+ function normalizeConfidenceValue(value) {
3874
+ if (value === void 0) {
3875
+ return void 0;
3809
3876
  }
3810
- })();
3811
- var EMPTY_LEGACY_HASH_DOCUMENT = {
3812
- front_matter: {},
3813
- body: ""
3814
- };
3815
- function decodeJsonPointer(path6) {
3816
- if (!path6 || path6 === "/") {
3817
- return [];
3877
+ if (typeof value === "number") {
3878
+ return value;
3818
3879
  }
3819
- if (!path6.startsWith("/")) {
3820
- return [];
3880
+ const normalized = value.trim().toLowerCase();
3881
+ if (normalized === "med") {
3882
+ return "medium";
3821
3883
  }
3822
- return path6.slice(1).split("/").map((segment) => segment.replaceAll("~1", "/").replaceAll("~0", "~"));
3884
+ if (CONFIDENCE_TEXT_VALUES.includes(normalized)) {
3885
+ return normalized;
3886
+ }
3887
+ return void 0;
3823
3888
  }
3824
- function isDefinedPointerPath(document, path6) {
3825
- const segments = decodeJsonPointer(path6);
3826
- if (segments.length === 0) {
3827
- return true;
3889
+ function normalizeSeverityValue(value) {
3890
+ if (value === void 0) {
3891
+ return void 0;
3828
3892
  }
3829
- let cursor = document;
3830
- for (const segment of segments) {
3831
- if (Array.isArray(cursor)) {
3832
- if (segment === "-" || !/^(0|[1-9]\d*)$/.test(segment)) {
3833
- return false;
3834
- }
3835
- const index = Number(segment);
3836
- if (!Number.isInteger(index) || index < 0 || index >= cursor.length) {
3837
- return false;
3838
- }
3839
- const next2 = cursor[index];
3840
- if (next2 === void 0) {
3841
- return false;
3842
- }
3843
- cursor = next2;
3893
+ const normalized = value.trim().toLowerCase();
3894
+ if (normalized === "med") {
3895
+ return "medium";
3896
+ }
3897
+ if (ISSUE_SEVERITY_VALUES.includes(normalized)) {
3898
+ return normalized;
3899
+ }
3900
+ return void 0;
3901
+ }
3902
+ function emptyStringToUndefined(value) {
3903
+ return value || void 0;
3904
+ }
3905
+ function copyExtensionItemMetadataFields(normalized, source) {
3906
+ const targetRecord = normalized;
3907
+ const sourceRecord = source;
3908
+ for (const [key, value] of Object.entries(sourceRecord)) {
3909
+ if (isUnsafeObjectKey(key) || Object.prototype.hasOwnProperty.call(targetRecord, key) || value === void 0) {
3844
3910
  continue;
3845
3911
  }
3846
- if (typeof cursor !== "object" || cursor === null) {
3847
- return false;
3848
- }
3849
- if (!Object.prototype.hasOwnProperty.call(cursor, segment)) {
3850
- return false;
3851
- }
3852
- const next = cursor[segment];
3853
- if (next === void 0) {
3854
- return false;
3855
- }
3856
- cursor = next;
3912
+ targetRecord[key] = value;
3857
3913
  }
3858
- return true;
3859
3914
  }
3860
- function normalizeHistoryPatchOps(beforeDocument, patch) {
3861
- const normalized = [];
3862
- let replayCursor = structuredClone(beforeDocument);
3863
- for (const operation of patch) {
3864
- const normalizedOperation = operation.op === "replace" && !isDefinedPointerPath(replayCursor, operation.path) ? { ...operation, op: "add" } : operation;
3865
- normalized.push(normalizedOperation);
3866
- replayCursor = jsonPatch.applyPatch(replayCursor, [normalizedOperation], true, true).newDocument;
3915
+ function coerceNormalizedRuntimeFields(normalized, runtimeContext) {
3916
+ if (!runtimeContext?.fieldRegistry) {
3917
+ return;
3867
3918
  }
3868
- return normalized;
3869
- }
3870
- function canonicalHashDocument(document) {
3871
- const hasMetadata = document.metadata && Object.keys(document.metadata).length > 0;
3872
- if (!hasMetadata) {
3873
- return {
3874
- front_matter: {},
3875
- body: document.body ?? ""
3876
- };
3919
+ const record = normalized;
3920
+ for (const definition of runtimeContext.fieldRegistry.definitions) {
3921
+ const currentValue = record[definition.metadata_key];
3922
+ if (currentValue === void 0) {
3923
+ continue;
3924
+ }
3925
+ record[definition.metadata_key] = coerceRuntimeFieldValue(definition, currentValue, `metadata field "${definition.metadata_key}"`);
3877
3926
  }
3878
- const canonical = canonicalDocument(document);
3879
- const orderedMetadata = orderObject(toItemRecord(canonical.metadata), ITEM_METADATA_KEY_ORDER);
3880
- return {
3881
- front_matter: orderedMetadata,
3882
- body: canonical.body
3883
- };
3884
3927
  }
3885
- function canonicalPatchDocument(document) {
3886
- const hasMetadata = document.metadata && Object.keys(document.metadata).length > 0;
3887
- if (!hasMetadata) {
3888
- return {
3889
- metadata: {},
3890
- body: document.body ?? ""
3891
- };
3928
+ function assertNormalizedUnknownFields(normalized, runtimeContext) {
3929
+ if (!runtimeContext || runtimeContext.unknownFieldPolicy === "allow") {
3930
+ return;
3931
+ }
3932
+ const knownKeys = buildKnownItemMetadataKeys(runtimeContext);
3933
+ const record = normalized;
3934
+ const unknownKeys = Object.keys(record).filter((key) => !knownKeys.has(key)).sort((left, right) => left.localeCompare(right));
3935
+ if (unknownKeys.length > 0 && runtimeContext.unknownFieldPolicy === "reject") {
3936
+ validationError(`unknown schema fields are not allowed: ${unknownKeys.join(", ")}`);
3937
+ }
3938
+ if (unknownKeys.length > 0) {
3939
+ runtimeContext.onWarning?.(`item_unknown_schema_fields:${unknownKeys.join(",")}`);
3892
3940
  }
3893
- const canonical = canonicalDocument(document);
3894
- const orderedMetadata = orderObject(toItemRecord(canonical.metadata), ITEM_METADATA_KEY_ORDER);
3895
- return {
3896
- metadata: orderedMetadata,
3897
- body: canonical.body
3898
- };
3899
- }
3900
- function hashDocument(document) {
3901
- return sha256Hex(stableStringify(canonicalHashDocument(document)));
3902
- }
3903
- function hashEmptyDocument() {
3904
- return sha256Hex(stableStringify(EMPTY_LEGACY_HASH_DOCUMENT));
3905
3941
  }
3906
- function createHistoryEntry(params) {
3907
- const beforeHashCanonical = canonicalHashDocument(params.before);
3908
- const afterHashCanonical = canonicalHashDocument(params.after);
3909
- const beforePatchCanonical = canonicalPatchDocument(params.before);
3910
- const afterPatchCanonical = canonicalPatchDocument(params.after);
3911
- const rawPatch = jsonPatch.compare(beforePatchCanonical, afterPatchCanonical);
3912
- const patch = normalizeHistoryPatchOps(beforePatchCanonical, rawPatch);
3913
- return {
3914
- ts: params.nowIso,
3915
- author: params.author,
3916
- op: params.op,
3917
- patch,
3918
- before_hash: sha256Hex(stableStringify(beforeHashCanonical)),
3919
- after_hash: sha256Hex(stableStringify(afterHashCanonical)),
3920
- message: params.message === void 0 ? void 0 : params.message
3942
+ function normalizeItemMetadata(itemMetadata, options = {}) {
3943
+ const runtimeContext = resolveRuntimeSchemaValidationContext(options);
3944
+ const normalizedStatus = normalizeStatusInput(itemMetadata.status, runtimeContext?.statusRegistry) ?? itemMetadata.status;
3945
+ const tags = Array.from(new Set(itemMetadata.tags.map((tag) => tag.trim().toLowerCase()).filter(Boolean))).sort((a, b) => a.localeCompare(b));
3946
+ const normalized = {
3947
+ id: itemMetadata.id,
3948
+ title: itemMetadata.title,
3949
+ description: itemMetadata.description,
3950
+ type: itemMetadata.type,
3951
+ pm_format_version: normalizeItemFormatVersion(itemMetadata.pm_format_version),
3952
+ source_type: trimStringOrUndefined(itemMetadata.source_type),
3953
+ type_options: normalizeTypeOptions(itemMetadata.type_options),
3954
+ status: normalizedStatus,
3955
+ priority: itemMetadata.priority,
3956
+ tags,
3957
+ created_at: itemMetadata.created_at,
3958
+ updated_at: itemMetadata.updated_at,
3959
+ dependencies: sortDependencies(itemMetadata.dependencies),
3960
+ comments: sortLogValues(itemMetadata.comments),
3961
+ notes: sortLogValues(itemMetadata.notes),
3962
+ learnings: sortLogValues(itemMetadata.learnings),
3963
+ files: normalizeFiles(itemMetadata.files),
3964
+ tests: sortTests(itemMetadata.tests),
3965
+ test_runs: normalizeTestRunSummaries(itemMetadata.test_runs),
3966
+ docs: sortDocs(itemMetadata.docs),
3967
+ deadline: emptyStringToUndefined(itemMetadata.deadline),
3968
+ reminders: sortReminders(itemMetadata.reminders),
3969
+ events: sortEvents(itemMetadata.events),
3970
+ closed_at: emptyStringToUndefined(itemMetadata.closed_at),
3971
+ assignee: trimStringOrUndefined(itemMetadata.assignee),
3972
+ source_owner: trimStringOrUndefined(itemMetadata.source_owner),
3973
+ author: emptyStringToUndefined(itemMetadata.author),
3974
+ estimated_minutes: itemMetadata.estimated_minutes,
3975
+ acceptance_criteria: itemMetadata.acceptance_criteria ?? void 0,
3976
+ design: itemMetadata.design ?? void 0,
3977
+ external_ref: itemMetadata.external_ref ?? void 0,
3978
+ definition_of_ready: trimStringOrUndefined(itemMetadata.definition_of_ready),
3979
+ order: itemMetadata.order,
3980
+ goal: trimStringOrUndefined(itemMetadata.goal),
3981
+ objective: trimStringOrUndefined(itemMetadata.objective),
3982
+ value: trimStringOrUndefined(itemMetadata.value),
3983
+ impact: trimStringOrUndefined(itemMetadata.impact),
3984
+ outcome: trimStringOrUndefined(itemMetadata.outcome),
3985
+ why_now: trimStringOrUndefined(itemMetadata.why_now),
3986
+ parent: trimStringOrUndefined(itemMetadata.parent),
3987
+ reviewer: trimStringOrUndefined(itemMetadata.reviewer),
3988
+ risk: itemMetadata.risk ?? void 0,
3989
+ confidence: normalizeConfidenceValue(itemMetadata.confidence),
3990
+ sprint: trimStringOrUndefined(itemMetadata.sprint),
3991
+ release: trimStringOrUndefined(itemMetadata.release),
3992
+ blocked_by: trimStringOrUndefined(itemMetadata.blocked_by),
3993
+ blocked_reason: trimStringOrUndefined(itemMetadata.blocked_reason),
3994
+ unblock_note: trimStringOrUndefined(itemMetadata.unblock_note),
3995
+ reporter: trimStringOrUndefined(itemMetadata.reporter),
3996
+ severity: normalizeSeverityValue(itemMetadata.severity),
3997
+ environment: trimStringOrUndefined(itemMetadata.environment),
3998
+ repro_steps: trimStringOrUndefined(itemMetadata.repro_steps),
3999
+ resolution: trimStringOrUndefined(itemMetadata.resolution),
4000
+ expected_result: trimStringOrUndefined(itemMetadata.expected_result),
4001
+ actual_result: trimStringOrUndefined(itemMetadata.actual_result),
4002
+ affected_version: trimStringOrUndefined(itemMetadata.affected_version),
4003
+ fixed_version: trimStringOrUndefined(itemMetadata.fixed_version),
4004
+ component: trimStringOrUndefined(itemMetadata.component),
4005
+ regression: itemMetadata.regression,
4006
+ customer_impact: trimStringOrUndefined(itemMetadata.customer_impact),
4007
+ close_reason: emptyStringToUndefined(itemMetadata.close_reason),
4008
+ plan_mode: trimStringOrUndefined(itemMetadata.plan_mode),
4009
+ plan_scope: trimStringOrUndefined(itemMetadata.plan_scope),
4010
+ plan_harness: trimStringOrUndefined(itemMetadata.plan_harness),
4011
+ plan_resume_context: trimStringOrUndefined(itemMetadata.plan_resume_context),
4012
+ plan_steps: normalizePlanSteps(itemMetadata.plan_steps),
4013
+ plan_decisions: normalizePlanDecisions(itemMetadata.plan_decisions),
4014
+ plan_discoveries: normalizePlanDiscoveries(itemMetadata.plan_discoveries),
4015
+ plan_validation: normalizePlanValidation(itemMetadata.plan_validation)
3921
4016
  };
4017
+ copyExtensionItemMetadataFields(normalized, itemMetadata);
4018
+ coerceNormalizedRuntimeFields(normalized, runtimeContext);
4019
+ assertNormalizedUnknownFields(normalized, runtimeContext);
4020
+ deleteUndefinedFields(normalized);
4021
+ return normalized;
3922
4022
  }
3923
- function isRecord(value) {
3924
- return typeof value === "object" && value !== null && !Array.isArray(value);
3925
- }
3926
- function fallbackHistoryTimestamp(entry) {
3927
- const ts = entry.ts.trim();
3928
- return ts.length > 0 ? ts : nowIso();
3929
- }
3930
- function withHistoryTimestamp(value, fallbackTs) {
3931
- const ts = value.ts;
3932
- if (typeof ts === "string" && ts.trim().length > 0) {
3933
- return value;
3934
- }
3935
- return { ...value, ts: fallbackTs };
4023
+ function orderItemMetadata(itemMetadata) {
4024
+ return orderObject(itemMetadata, ITEM_METADATA_KEY_ORDER);
3936
4025
  }
3937
- function serializeHistoryLine(value, fallbackEntry) {
3938
- const fallbackTs = fallbackHistoryTimestamp(fallbackEntry);
3939
- if (typeof value === "string") {
3940
- try {
3941
- const parsed = JSON.parse(value);
3942
- if (isRecord(parsed)) {
3943
- return JSON.stringify(withHistoryTimestamp(parsed, fallbackTs));
4026
+ function findJsonObjectEnd(content) {
4027
+ let depth = 0;
4028
+ let inString = false;
4029
+ let escaped = false;
4030
+ for (let i = 0; i < content.length; i += 1) {
4031
+ const char = content[i];
4032
+ if (inString) {
4033
+ if (escaped) {
4034
+ escaped = false;
4035
+ continue;
3944
4036
  }
3945
- } catch {
4037
+ if (char === "\\") {
4038
+ escaped = true;
4039
+ continue;
4040
+ }
4041
+ if (char === '"') {
4042
+ inString = false;
4043
+ }
4044
+ continue;
3946
4045
  }
3947
- return value;
3948
- }
3949
- if (isRecord(value)) {
3950
- return JSON.stringify(withHistoryTimestamp(value, fallbackTs));
3951
- }
3952
- return JSON.stringify(value);
3953
- }
3954
- async function appendHistoryEntry(historyPath, entry) {
3955
- const override = await runActiveServiceOverride("history_append", {
3956
- history_path: historyPath,
3957
- entry
3958
- });
3959
- if (override.handled) {
3960
- if (override.result === false) {
3961
- return;
4046
+ if (char === '"') {
4047
+ inString = true;
4048
+ continue;
3962
4049
  }
3963
- if (typeof override.result === "string") {
3964
- await appendLineAtomic(historyPath, serializeHistoryLine(override.result, entry));
3965
- return;
4050
+ if (char === "{") {
4051
+ depth += 1;
4052
+ continue;
3966
4053
  }
3967
- if (typeof override.result === "object" && override.result !== null) {
3968
- const record = override.result;
3969
- if (record.skip === true) {
3970
- return;
3971
- }
3972
- const nextHistoryPath = typeof record.history_path === "string" ? record.history_path : historyPath;
3973
- if (typeof record.line === "string") {
3974
- await appendLineAtomic(nextHistoryPath, serializeHistoryLine(record.line, entry));
3975
- return;
4054
+ if (char === "}") {
4055
+ depth -= 1;
4056
+ if (depth === 0) {
4057
+ return i;
3976
4058
  }
3977
- await appendLineAtomic(nextHistoryPath, serializeHistoryLine(record.entry ?? entry, entry));
3978
- return;
3979
4059
  }
3980
4060
  }
3981
- await appendLineAtomic(historyPath, serializeHistoryLine(entry, entry));
4061
+ return -1;
3982
4062
  }
3983
-
3984
- // dist/core/history/history-stream-policy.js
3985
- import fs from "node:fs/promises";
3986
- import path from "node:path";
3987
- !(function() {
3988
- try {
3989
- var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
3990
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "0e1bb27d-a1ac-57ae-b879-29318d827578");
3991
- } catch (e2) {
4063
+ function splitFrontMatter(content) {
4064
+ if (!content.startsWith("{")) {
4065
+ return { frontMatter: "", body: content };
3992
4066
  }
3993
- })();
3994
- function toSortedUniqueItemIds(itemIds) {
3995
- return [...new Set(itemIds.filter((value) => value.trim().length > 0))].sort((left, right) => left.localeCompare(right));
3996
- }
3997
- function strictMissingStreamError(itemId, commandLabel) {
3998
- return new PmCliError(`Missing history stream for ${itemId}. ${commandLabel} requires history streams when settings.history.missing_stream is strict_error.`, EXIT_CODE.NOT_FOUND);
4067
+ const end = findJsonObjectEnd(content);
4068
+ if (end < 0) {
4069
+ return { frontMatter: "", body: content };
4070
+ }
4071
+ const frontMatter = content.slice(0, end + 1);
4072
+ const body = content.slice(end + 1).replace(/^\r?\n+/, "");
4073
+ return { frontMatter, body };
3999
4074
  }
4000
- async function createStream(historyPath, commandLabel) {
4001
- await ensureDir(path.dirname(historyPath));
4002
- const handle = await fs.open(historyPath, "a");
4003
- await handle.close();
4004
- return runActiveOnWriteHooks({
4005
- path: historyPath,
4006
- scope: "project",
4007
- op: `${commandLabel}:history:auto_create`
4008
- });
4075
+ function stripLeadingYamlDocument(content) {
4076
+ const normalizedContent = content.charCodeAt(0) === 65279 ? content.slice(1) : content;
4077
+ const opener = normalizedContent.match(/^[ \t]*---[ \t]*(?:\r?\n|$)/);
4078
+ if (!opener) {
4079
+ return { content: normalizedContent, stripped: false };
4080
+ }
4081
+ let cursor = opener[0].length;
4082
+ while (cursor < normalizedContent.length) {
4083
+ const nextNewline = normalizedContent.indexOf("\n", cursor);
4084
+ const lineEnd = nextNewline === -1 ? normalizedContent.length : nextNewline;
4085
+ const line = normalizedContent.slice(cursor, lineEnd).replace(/\r$/, "");
4086
+ const afterLine = nextNewline === -1 ? lineEnd : lineEnd + 1;
4087
+ if (line.trim() === "---") {
4088
+ return {
4089
+ content: normalizedContent.slice(afterLine).replace(/^\s+/, ""),
4090
+ stripped: true
4091
+ };
4092
+ }
4093
+ cursor = afterLine;
4094
+ }
4095
+ return { content: normalizedContent, stripped: false };
4009
4096
  }
4010
- async function enforceHistoryStreamPolicyForItem(params) {
4011
- return enforceHistoryStreamPolicyForItems({
4012
- pmRoot: params.pmRoot,
4013
- settings: params.settings,
4014
- itemIds: [params.itemId],
4015
- commandLabel: params.commandLabel
4097
+ function normalizeParsedItemMetadata(itemMetadata, options) {
4098
+ return normalizeItemMetadata(itemMetadata, {
4099
+ ...options,
4100
+ onWarning: void 0
4016
4101
  });
4017
4102
  }
4018
- async function enforceHistoryStreamPolicyForItems(params) {
4019
- const ids = toSortedUniqueItemIds(params.itemIds);
4020
- const autoCreated = [];
4021
- const warnings = [];
4022
- for (const itemId of ids) {
4023
- const historyPath = getHistoryPath(params.pmRoot, itemId);
4024
- if (await pathExists(historyPath)) {
4025
- continue;
4026
- }
4027
- if (params.settings.history.missing_stream === "strict_error") {
4028
- throw strictMissingStreamError(itemId, params.commandLabel);
4103
+ function parseJsonMarkdownItemDocument(content, runtimeContext, options = {}) {
4104
+ const normalized = stripLeadingYamlDocument(content);
4105
+ if (normalized.stripped) {
4106
+ options.onWarning?.("json_markdown_leading_yaml_frontmatter_ignored");
4107
+ }
4108
+ const { frontMatter, body } = splitFrontMatter(normalized.content);
4109
+ if (!frontMatter) {
4110
+ const trimmed = content.trimStart();
4111
+ if (trimmed.startsWith("{")) {
4112
+ validationError("JSON front matter is not valid JSON");
4029
4113
  }
4030
- warnings.push(...await createStream(historyPath, params.commandLabel));
4031
- warnings.push(`history_stream_auto_created:${itemId}`);
4032
- autoCreated.push(itemId);
4114
+ validationError("missing JSON front matter");
4115
+ }
4116
+ let parsed;
4117
+ try {
4118
+ parsed = JSON.parse(frontMatter);
4119
+ } catch {
4120
+ validationError("JSON front matter is not valid JSON");
4033
4121
  }
4122
+ assertValidItemMetadata(parsed, runtimeContext);
4034
4123
  return {
4035
- auto_created_ids: autoCreated,
4036
- warnings
4124
+ metadata: normalizeParsedItemMetadata(parsed, options),
4125
+ body: normalizeBody(body)
4037
4126
  };
4038
4127
  }
4039
-
4040
- // dist/core/lock/lock.js
4041
- import fs2 from "node:fs/promises";
4042
- import path2 from "node:path";
4043
- import { randomUUID } from "node:crypto";
4044
- !(function() {
4045
- try {
4046
- var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
4047
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "d23246e1-c423-5100-bcde-8162e01587f0");
4048
- } catch (e2) {
4049
- }
4050
- })();
4051
- function parseLockInfo(raw) {
4128
+ function parseToonItemDocument(content, runtimeContext, options = {}) {
4052
4129
  let parsed;
4053
4130
  try {
4054
- parsed = JSON.parse(raw);
4131
+ parsed = decodeToonItemContent(content).value;
4055
4132
  } catch {
4056
- return {
4057
- info: null,
4058
- warnings: ["lock_info_invalid_json"]
4059
- };
4060
- }
4061
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
4062
- return {
4063
- info: null,
4064
- warnings: ["lock_info_invalid_shape"]
4065
- };
4133
+ validationError("TOON item document is not valid TOON");
4066
4134
  }
4067
- const candidate = parsed;
4068
- const id = candidate.id;
4069
- const pid = candidate.pid;
4070
- const owner = candidate.owner;
4071
- const createdAt = candidate.created_at;
4072
- const ttlSeconds = candidate.ttl_seconds;
4073
- if (typeof id !== "string" || typeof pid !== "number" || !Number.isFinite(pid) || typeof owner !== "string" || typeof createdAt !== "string" || typeof ttlSeconds !== "number" || !Number.isFinite(ttlSeconds)) {
4135
+ assertItemMetadataCondition(typeof parsed === "object" && parsed !== null && !Array.isArray(parsed), "TOON item document must be an object");
4136
+ const record = parsed;
4137
+ if (Object.prototype.hasOwnProperty.call(record, "front_matter")) {
4138
+ assertValidItemMetadata(record.front_matter, runtimeContext);
4139
+ assertItemMetadataCondition(record.body === void 0 || typeof record.body === "string", "TOON item document body must be a string");
4074
4140
  return {
4075
- info: null,
4076
- warnings: ["lock_info_invalid_shape"]
4141
+ metadata: normalizeParsedItemMetadata(record.front_matter, options),
4142
+ body: normalizeBody(typeof record.body === "string" ? record.body : "")
4077
4143
  };
4078
4144
  }
4145
+ const { body, ...itemMetadataRecord } = record;
4146
+ assertItemMetadataCondition(body === void 0 || typeof body === "string", "TOON item document body must be a string");
4147
+ assertValidItemMetadata(itemMetadataRecord, runtimeContext);
4079
4148
  return {
4080
- info: {
4081
- id,
4082
- pid,
4083
- owner,
4084
- created_at: createdAt,
4085
- ttl_seconds: ttlSeconds
4086
- },
4087
- warnings: []
4149
+ metadata: normalizeParsedItemMetadata(itemMetadataRecord, options),
4150
+ body: normalizeBody(typeof body === "string" ? body : "")
4088
4151
  };
4089
4152
  }
4090
- async function readLockInfo(lockPath) {
4091
- try {
4092
- const raw = await fs2.readFile(lockPath, "utf8");
4093
- await runActiveOnReadHooks({
4094
- path: lockPath,
4095
- scope: "project"
4153
+ function serializeJsonMarkdownItemDocument(document, options = {}) {
4154
+ const normalizedMetadata = normalizeItemMetadata(document.metadata, options);
4155
+ const orderedMetadata = orderItemMetadata(normalizedMetadata);
4156
+ const serializedMetadata = JSON.stringify(orderedMetadata, null, 2);
4157
+ const normalizedBody = normalizeBody(document.body ?? "");
4158
+ if (!normalizedBody) {
4159
+ return `${serializedMetadata}
4160
+ `;
4161
+ }
4162
+ return `${serializedMetadata}
4163
+
4164
+ ${normalizedBody}
4165
+ `;
4166
+ }
4167
+ function serializeToonItemDocument(document, options = {}) {
4168
+ const normalizedMetadata = normalizeItemMetadata(document.metadata, options);
4169
+ const orderedMetadata = orderItemMetadata(normalizedMetadata);
4170
+ const normalizedBody = normalizeBody(document.body ?? "");
4171
+ return `${encodeToon({ ...orderedMetadata, body: normalizedBody })}
4172
+ `;
4173
+ }
4174
+ function parseItemDocument(content, options = {}) {
4175
+ const conflictMarker = findFirstMergeConflictMarker(content);
4176
+ if (conflictMarker) {
4177
+ throw new PmCliError(`Merge conflict markers detected in item document at line ${conflictMarker.line} (${conflictMarker.marker}). Resolve <<<<<<< ======= >>>>>>> markers and retry.`, EXIT_CODE.GENERIC_FAILURE, {
4178
+ code: "merge_conflict_markers_detected",
4179
+ required: "Resolve merge-conflict markers in the item file before parsing or mutation commands.",
4180
+ why: "Partially merged documents can corrupt item metadata and history integrity.",
4181
+ examples: ["git status", "git add <resolved-file> && git commit"],
4182
+ nextSteps: [
4183
+ "Resolve conflicts, save the file, then rerun the pm command."
4184
+ ]
4096
4185
  });
4097
- return parseLockInfo(raw);
4098
- } catch (error) {
4099
- if (isErrno(error, "ENOENT")) {
4100
- return {
4101
- info: null,
4102
- warnings: []
4103
- };
4104
- }
4105
- return {
4106
- info: null,
4107
- warnings: ["lock_info_read_failed"]
4108
- };
4109
4186
  }
4187
+ const format = options.format ?? "toon";
4188
+ const runtimeContext = resolveRuntimeSchemaValidationContext(options);
4189
+ return format === "toon" ? parseToonItemDocument(content, runtimeContext, options) : parseJsonMarkdownItemDocument(content, runtimeContext, options);
4110
4190
  }
4111
- function isErrno(error, code) {
4112
- return typeof error === "object" && error !== null && "code" in error && error.code === code;
4113
- }
4114
- async function emitLockWriteHook(lockPath, op) {
4115
- await runActiveOnWriteHooks({
4116
- path: lockPath,
4117
- scope: "project",
4118
- op
4119
- });
4191
+ function serializeItemDocument(document, options = {}) {
4192
+ const format = options.format ?? "toon";
4193
+ return format === "toon" ? serializeToonItemDocument(document, options) : serializeJsonMarkdownItemDocument(document, options);
4120
4194
  }
4121
- function buildLockPayload(id, owner, ttlSeconds) {
4195
+ function canonicalDocument(document, options = {}) {
4122
4196
  return {
4123
- id,
4124
- pid: process.pid,
4125
- owner,
4126
- created_at: nowIso(),
4127
- ttl_seconds: ttlSeconds
4197
+ metadata: normalizeItemMetadata(document.metadata, options),
4198
+ body: normalizeBody(document.body ?? "")
4128
4199
  };
4129
4200
  }
4130
- async function createLockFile(lockPath, id, owner, ttlSeconds) {
4131
- await fs2.mkdir(path2.dirname(lockPath), { recursive: true });
4132
- const handle = await fs2.open(lockPath, "wx");
4201
+
4202
+ // dist/core/item/item-record.js
4203
+ !(function() {
4133
4204
  try {
4134
- await handle.writeFile(`${JSON.stringify(buildLockPayload(id, owner, ttlSeconds), null, 2)}
4135
- `, "utf8");
4136
- } finally {
4137
- await handle.close();
4205
+ var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
4206
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "30de0e7a-3307-5231-af8c-bae7a2b6374b");
4207
+ } catch (e2) {
4138
4208
  }
4139
- await emitLockWriteHook(lockPath, "lock:create");
4209
+ })();
4210
+ function toItemRecord(item) {
4211
+ return item;
4140
4212
  }
4141
- async function unlinkLockWithHook(lockPath, op) {
4213
+
4214
+ // dist/core/history/history.js
4215
+ import jsonPatch from "fast-json-patch";
4216
+ !(function() {
4142
4217
  try {
4143
- await fs2.unlink(lockPath);
4144
- await emitLockWriteHook(lockPath, op);
4145
- return true;
4146
- } catch {
4147
- return false;
4218
+ var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
4219
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "45cc07c9-b6f9-5851-9f98-4167976035b1");
4220
+ } catch (e2) {
4148
4221
  }
4149
- }
4150
- function isStaleLock(info, ttlSeconds) {
4151
- const createdAtMs = info?.created_at ? Date.parse(info.created_at) : Number.NaN;
4152
- const ageMs = Number.isFinite(createdAtMs) ? Date.now() - createdAtMs : Number.POSITIVE_INFINITY;
4153
- return ageMs > ttlSeconds * 1e3;
4154
- }
4155
- function lockOwnerSuffix(info) {
4156
- return info?.owner ? ` (owner ${info.owner})` : "";
4157
- }
4158
- var LOCK_WAIT_INITIAL_DELAY_MS = 25;
4159
- var LOCK_WAIT_MAX_DELAY_MS = 200;
4160
- var LOCK_CONFLICT_RETRY_HINT_MS = 250;
4161
- var MAX_STALE_LOCK_REMOVALS = 3;
4162
- var STALE_CLEANUP_GATE_SUFFIX = ".stale-cleanup";
4163
- var STALE_CLEANUP_GATE_OWNER_FILE = "owner.json";
4164
- var STALE_CLEANUP_GATE_STALE_MS = 1e4;
4165
- var STALE_CLEANUP_GATE_MAX_ACTIVE_MS = 5 * 6e4;
4166
- function parseNonNegativeIntegerWaitMs(value) {
4167
- if (typeof value === "string") {
4168
- const trimmed = value.trim();
4169
- if (!/^\d+$/.test(trimmed)) {
4170
- return void 0;
4171
- }
4172
- const parsed = Number(trimmed);
4173
- return Number.isSafeInteger(parsed) ? parsed : void 0;
4222
+ })();
4223
+ var EMPTY_LEGACY_HASH_DOCUMENT = {
4224
+ front_matter: {},
4225
+ body: ""
4226
+ };
4227
+ function decodeJsonPointer(path6) {
4228
+ if (!path6 || path6 === "/") {
4229
+ return [];
4174
4230
  }
4175
- if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
4176
- return Math.trunc(value);
4231
+ if (!path6.startsWith("/")) {
4232
+ return [];
4177
4233
  }
4178
- return void 0;
4234
+ return path6.slice(1).split("/").map((segment) => segment.replaceAll("~1", "/").replaceAll("~0", "~"));
4179
4235
  }
4180
- function resolveLockWaitMs(waitMs) {
4181
- const envRaw = process.env.PM_LOCK_WAIT_MS;
4182
- const envParsed = parseNonNegativeIntegerWaitMs(envRaw);
4183
- if (envParsed !== void 0) {
4184
- return envParsed;
4185
- }
4186
- const callerParsed = parseNonNegativeIntegerWaitMs(waitMs);
4187
- if (callerParsed !== void 0) {
4188
- return callerParsed;
4236
+ function isDefinedPointerPath(document, path6) {
4237
+ const segments = decodeJsonPointer(path6);
4238
+ if (segments.length === 0) {
4239
+ return true;
4189
4240
  }
4190
- return 0;
4191
- }
4192
- function sleepWithJitter(baseDelayMs) {
4193
- const jitteredMs = Math.max(1, Math.round(baseDelayMs * (0.5 + Math.random())));
4194
- return new Promise((resolve) => setTimeout(resolve, jitteredMs));
4195
- }
4196
- function buildLockConflictError(id, info, waitedMs) {
4197
- const waitedSuffix = waitedMs > 0 ? ` after waiting ${waitedMs}ms` : "";
4198
- return new PmCliError(`Item ${id} is locked${lockOwnerSuffix(info)}${waitedSuffix}`, EXIT_CODE.CONFLICT, {
4199
- code: "lock_conflict",
4200
- recovery: {
4201
- retry_after_ms: LOCK_CONFLICT_RETRY_HINT_MS
4241
+ let cursor = document;
4242
+ for (const segment of segments) {
4243
+ if (Array.isArray(cursor)) {
4244
+ if (segment === "-" || !/^(0|[1-9]\d*)$/.test(segment)) {
4245
+ return false;
4246
+ }
4247
+ const index = Number(segment);
4248
+ if (!Number.isInteger(index) || index < 0 || index >= cursor.length) {
4249
+ return false;
4250
+ }
4251
+ const next2 = cursor[index];
4252
+ if (next2 === void 0) {
4253
+ return false;
4254
+ }
4255
+ cursor = next2;
4256
+ continue;
4202
4257
  }
4203
- });
4204
- }
4205
- function resolveLockOverrideRelease(result) {
4206
- if (typeof result === "function") {
4207
- return result;
4208
- }
4209
- if (typeof result === "object" && result !== null && "release" in result) {
4210
- const release = result.release;
4211
- return typeof release === "function" ? release : null;
4258
+ if (typeof cursor !== "object" || cursor === null) {
4259
+ return false;
4260
+ }
4261
+ if (!Object.prototype.hasOwnProperty.call(cursor, segment)) {
4262
+ return false;
4263
+ }
4264
+ const next = cursor[segment];
4265
+ if (next === void 0) {
4266
+ return false;
4267
+ }
4268
+ cursor = next;
4212
4269
  }
4213
- return null;
4270
+ return true;
4214
4271
  }
4215
- function throwIfStaleLockNeedsForce(id, lockInfo, force, forceRequired) {
4216
- if (!force && forceRequired) {
4217
- const warningSuffix = lockInfo.warnings.length > 0 ? ` (${lockInfo.warnings.join(",")})` : "";
4218
- throw new PmCliError(`Item ${id} lock is stale${warningSuffix}; rerun with --force when supported for this command`, EXIT_CODE.CONFLICT);
4272
+ function normalizeHistoryPatchOps(beforeDocument, patch) {
4273
+ const normalized = [];
4274
+ let replayCursor = structuredClone(beforeDocument);
4275
+ for (const operation of patch) {
4276
+ const normalizedOperation = operation.op === "replace" && !isDefinedPointerPath(replayCursor, operation.path) ? { ...operation, op: "add" } : operation;
4277
+ normalized.push(normalizedOperation);
4278
+ replayCursor = jsonPatch.applyPatch(replayCursor, [normalizedOperation], true, true).newDocument;
4219
4279
  }
4280
+ return normalized;
4220
4281
  }
4221
- function parseStaleCleanupGateOwner(raw) {
4222
- let parsed;
4223
- try {
4224
- parsed = JSON.parse(raw);
4225
- } catch {
4226
- return null;
4227
- }
4228
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
4229
- return null;
4230
- }
4231
- const candidate = parsed;
4232
- const pid = candidate.pid;
4233
- const token = candidate.token;
4234
- if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || typeof token !== "string" || token.length === 0) {
4235
- return null;
4282
+ function canonicalHashDocument(document) {
4283
+ const hasMetadata = document.metadata && Object.keys(document.metadata).length > 0;
4284
+ if (!hasMetadata) {
4285
+ return {
4286
+ front_matter: {},
4287
+ body: document.body ?? ""
4288
+ };
4236
4289
  }
4237
- return { pid, token };
4290
+ const canonical = canonicalDocument(document);
4291
+ const orderedMetadata = orderObject(toItemRecord(canonical.metadata), ITEM_METADATA_KEY_ORDER);
4292
+ return {
4293
+ front_matter: orderedMetadata,
4294
+ body: canonical.body
4295
+ };
4238
4296
  }
4239
- async function readStaleCleanupGateOwner(gatePath) {
4240
- try {
4241
- return parseStaleCleanupGateOwner(await fs2.readFile(path2.join(gatePath, STALE_CLEANUP_GATE_OWNER_FILE), "utf8"));
4242
- } catch {
4243
- return null;
4297
+ function canonicalPatchDocument(document) {
4298
+ const hasMetadata = document.metadata && Object.keys(document.metadata).length > 0;
4299
+ if (!hasMetadata) {
4300
+ return {
4301
+ metadata: {},
4302
+ body: document.body ?? ""
4303
+ };
4244
4304
  }
4305
+ const canonical = canonicalDocument(document);
4306
+ const orderedMetadata = orderObject(toItemRecord(canonical.metadata), ITEM_METADATA_KEY_ORDER);
4307
+ return {
4308
+ metadata: orderedMetadata,
4309
+ body: canonical.body
4310
+ };
4245
4311
  }
4246
- function isProcessAlive(pid) {
4247
- try {
4248
- process.kill(pid, 0);
4249
- return true;
4250
- } catch (error) {
4251
- if (isErrno(error, "ESRCH")) {
4252
- return false;
4253
- }
4254
- return true;
4255
- }
4312
+ function hashDocument(document) {
4313
+ return sha256Hex(stableStringify(canonicalHashDocument(document)));
4314
+ }
4315
+ function hashEmptyDocument() {
4316
+ return sha256Hex(stableStringify(EMPTY_LEGACY_HASH_DOCUMENT));
4317
+ }
4318
+ function createHistoryEntry(params) {
4319
+ const beforeHashCanonical = canonicalHashDocument(params.before);
4320
+ const afterHashCanonical = canonicalHashDocument(params.after);
4321
+ const beforePatchCanonical = canonicalPatchDocument(params.before);
4322
+ const afterPatchCanonical = canonicalPatchDocument(params.after);
4323
+ const rawPatch = jsonPatch.compare(beforePatchCanonical, afterPatchCanonical);
4324
+ const patch = normalizeHistoryPatchOps(beforePatchCanonical, rawPatch);
4325
+ return {
4326
+ ts: params.nowIso,
4327
+ author: params.author,
4328
+ op: params.op,
4329
+ patch,
4330
+ before_hash: sha256Hex(stableStringify(beforeHashCanonical)),
4331
+ after_hash: sha256Hex(stableStringify(afterHashCanonical)),
4332
+ message: params.message === void 0 ? void 0 : params.message
4333
+ };
4256
4334
  }
4257
- async function removeStaleCleanupGateDirectory(gatePath) {
4258
- try {
4259
- await fs2.rm(gatePath, { recursive: true, force: true });
4260
- return true;
4261
- } catch {
4262
- return false;
4263
- }
4335
+ function isRecord(value) {
4336
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4264
4337
  }
4265
- async function releaseStaleCleanupGate(gatePath, token) {
4266
- const owner = await readStaleCleanupGateOwner(gatePath);
4267
- if (owner === null || owner.token !== token) {
4268
- return;
4269
- }
4270
- await removeStaleCleanupGateDirectory(gatePath);
4338
+ function fallbackHistoryTimestamp(entry) {
4339
+ const ts = entry.ts.trim();
4340
+ return ts.length > 0 ? ts : nowIso();
4271
4341
  }
4272
- async function tryCreateStaleCleanupGate(gatePath) {
4273
- try {
4274
- await fs2.mkdir(gatePath);
4275
- } catch (error) {
4276
- if (isErrno(error, "EEXIST")) {
4277
- return null;
4278
- }
4279
- return null;
4280
- }
4281
- const owner = { pid: process.pid, token: randomUUID() };
4282
- try {
4283
- await fs2.writeFile(path2.join(gatePath, STALE_CLEANUP_GATE_OWNER_FILE), `${JSON.stringify(owner)}
4284
- `, "utf8");
4285
- } catch {
4286
- await removeStaleCleanupGateDirectory(gatePath);
4287
- return null;
4342
+ function withHistoryTimestamp(value, fallbackTs) {
4343
+ const ts = value.ts;
4344
+ if (typeof ts === "string" && ts.trim().length > 0) {
4345
+ return value;
4288
4346
  }
4289
- return owner;
4347
+ return { ...value, ts: fallbackTs };
4290
4348
  }
4291
- async function removeExpiredStaleCleanupGate(gatePath) {
4292
- let gateAgeMs;
4293
- try {
4294
- const stats = await fs2.stat(gatePath);
4295
- gateAgeMs = Date.now() - stats.mtimeMs;
4296
- if (gateAgeMs <= STALE_CLEANUP_GATE_STALE_MS) {
4297
- return false;
4349
+ function serializeHistoryLine(value, fallbackEntry) {
4350
+ const fallbackTs = fallbackHistoryTimestamp(fallbackEntry);
4351
+ if (typeof value === "string") {
4352
+ try {
4353
+ const parsed = JSON.parse(value);
4354
+ if (isRecord(parsed)) {
4355
+ return JSON.stringify(withHistoryTimestamp(parsed, fallbackTs));
4356
+ }
4357
+ } catch {
4298
4358
  }
4299
- } catch (error) {
4300
- return isErrno(error, "ENOENT");
4301
- }
4302
- const owner = await readStaleCleanupGateOwner(gatePath);
4303
- if (owner !== null && isProcessAlive(owner.pid) && gateAgeMs <= STALE_CLEANUP_GATE_MAX_ACTIVE_MS) {
4304
- return false;
4305
- }
4306
- return removeStaleCleanupGateDirectory(gatePath);
4307
- }
4308
- async function acquireStaleCleanupGate(lockPath, _id) {
4309
- const gatePath = `${lockPath}${STALE_CLEANUP_GATE_SUFFIX}`;
4310
- const owner = await tryCreateStaleCleanupGate(gatePath);
4311
- if (owner !== null) {
4312
- return async () => releaseStaleCleanupGate(gatePath, owner.token);
4313
- }
4314
- if (!await removeExpiredStaleCleanupGate(gatePath)) {
4315
- return null;
4359
+ return value;
4316
4360
  }
4317
- const recoveredOwner = await tryCreateStaleCleanupGate(gatePath);
4318
- if (recoveredOwner === null) {
4319
- return null;
4361
+ if (isRecord(value)) {
4362
+ return JSON.stringify(withHistoryTimestamp(value, fallbackTs));
4320
4363
  }
4321
- return async () => releaseStaleCleanupGate(gatePath, recoveredOwner.token);
4364
+ return JSON.stringify(value);
4322
4365
  }
4323
- async function removeConfirmedStaleLock(params) {
4324
- const releaseCleanupGate = await acquireStaleCleanupGate(params.lockPath, params.id);
4325
- if (releaseCleanupGate === null) {
4326
- return {
4327
- lockInfo: params.fallbackLockInfo,
4328
- shouldRetryCreate: false,
4329
- staleRemovalCounted: false
4330
- };
4331
- }
4332
- try {
4333
- const currentLockInfo = await readLockInfo(params.lockPath);
4334
- if (currentLockInfo.info === null && currentLockInfo.warnings.length === 0) {
4335
- return {
4336
- lockInfo: currentLockInfo,
4337
- shouldRetryCreate: true,
4338
- staleRemovalCounted: false
4339
- };
4366
+ async function appendHistoryEntry(historyPath, entry) {
4367
+ const override = await runActiveServiceOverride("history_append", {
4368
+ history_path: historyPath,
4369
+ entry
4370
+ });
4371
+ if (override.handled) {
4372
+ if (override.result === false) {
4373
+ return;
4340
4374
  }
4341
- if (!isStaleLock(currentLockInfo.info, params.ttlSeconds)) {
4342
- return {
4343
- lockInfo: currentLockInfo,
4344
- shouldRetryCreate: false,
4345
- staleRemovalCounted: false
4346
- };
4375
+ if (typeof override.result === "string") {
4376
+ await appendLineAtomic(historyPath, serializeHistoryLine(override.result, entry));
4377
+ return;
4347
4378
  }
4348
- throwIfStaleLockNeedsForce(params.id, currentLockInfo, params.force, params.forceRequiredForStaleLock);
4349
- if (params.staleRemovals >= MAX_STALE_LOCK_REMOVALS) {
4350
- throw buildLockConflictError(params.id, currentLockInfo.info, Date.now() - params.startedAtMs);
4379
+ if (typeof override.result === "object" && override.result !== null) {
4380
+ const record = override.result;
4381
+ if (record.skip === true) {
4382
+ return;
4383
+ }
4384
+ const nextHistoryPath = typeof record.history_path === "string" ? record.history_path : historyPath;
4385
+ if (typeof record.line === "string") {
4386
+ await appendLineAtomic(nextHistoryPath, serializeHistoryLine(record.line, entry));
4387
+ return;
4388
+ }
4389
+ await appendLineAtomic(nextHistoryPath, serializeHistoryLine(record.entry ?? entry, entry));
4390
+ return;
4351
4391
  }
4352
- return {
4353
- lockInfo: currentLockInfo,
4354
- shouldRetryCreate: await unlinkLockWithHook(params.lockPath, "lock:stale_remove"),
4355
- staleRemovalCounted: true
4356
- };
4357
- } finally {
4358
- await releaseCleanupGate();
4359
4392
  }
4393
+ await appendLineAtomic(historyPath, serializeHistoryLine(entry, entry));
4360
4394
  }
4361
- async function acquireLock(pmRoot, id, ttlSeconds, owner, force = false, forceRequiredForStaleLock = true, waitMs) {
4362
- const lockOverride = await runActiveServiceOverride("lock_acquire", {
4363
- pm_root: pmRoot,
4364
- id,
4365
- ttl_seconds: ttlSeconds,
4366
- owner,
4367
- force,
4368
- force_required_for_stale_lock: forceRequiredForStaleLock
4395
+
4396
+ // dist/core/history/history-stream-policy.js
4397
+ import fs2 from "node:fs/promises";
4398
+ import path2 from "node:path";
4399
+ !(function() {
4400
+ try {
4401
+ var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
4402
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "0e1bb27d-a1ac-57ae-b879-29318d827578");
4403
+ } catch (e2) {
4404
+ }
4405
+ })();
4406
+ function toSortedUniqueItemIds(itemIds) {
4407
+ return [...new Set(itemIds.filter((value) => value.trim().length > 0))].sort((left, right) => left.localeCompare(right));
4408
+ }
4409
+ function strictMissingStreamError(itemId, commandLabel) {
4410
+ return new PmCliError(`Missing history stream for ${itemId}. ${commandLabel} requires history streams when settings.history.missing_stream is strict_error.`, EXIT_CODE.NOT_FOUND);
4411
+ }
4412
+ async function createStream(historyPath, commandLabel) {
4413
+ await ensureDir(path2.dirname(historyPath));
4414
+ const handle = await fs2.open(historyPath, "a");
4415
+ await handle.close();
4416
+ return runActiveOnWriteHooks({
4417
+ path: historyPath,
4418
+ scope: "project",
4419
+ op: `${commandLabel}:history:auto_create`
4369
4420
  });
4370
- if (lockOverride.handled) {
4371
- const release = resolveLockOverrideRelease(lockOverride.result);
4372
- if (release) {
4373
- return async () => {
4374
- await Promise.resolve(release());
4375
- await runActiveServiceOverride("lock_release", {
4376
- pm_root: pmRoot,
4377
- id,
4378
- owner
4379
- });
4380
- };
4421
+ }
4422
+ async function enforceHistoryStreamPolicyForItem(params) {
4423
+ return enforceHistoryStreamPolicyForItems({
4424
+ pmRoot: params.pmRoot,
4425
+ settings: params.settings,
4426
+ itemIds: [params.itemId],
4427
+ commandLabel: params.commandLabel
4428
+ });
4429
+ }
4430
+ async function enforceHistoryStreamPolicyForItems(params) {
4431
+ const ids = toSortedUniqueItemIds(params.itemIds);
4432
+ const autoCreated = [];
4433
+ const warnings = [];
4434
+ for (const itemId of ids) {
4435
+ const historyPath = getHistoryPath(params.pmRoot, itemId);
4436
+ if (await pathExists(historyPath)) {
4437
+ continue;
4381
4438
  }
4382
- }
4383
- const lockPath = getLockPath(pmRoot, id);
4384
- const waitBudgetMs = resolveLockWaitMs(waitMs);
4385
- const startedAtMs = Date.now();
4386
- let staleRemovals = 0;
4387
- let backoffMs = LOCK_WAIT_INITIAL_DELAY_MS;
4388
- for (; ; ) {
4389
- try {
4390
- await createLockFile(lockPath, id, owner, ttlSeconds);
4391
- return async () => {
4392
- await unlinkLockWithHook(lockPath, "lock:release");
4393
- await runActiveServiceOverride("lock_release", {
4394
- pm_root: pmRoot,
4395
- id,
4396
- owner
4397
- });
4398
- };
4399
- } catch (error) {
4400
- if (!isErrno(error, "EEXIST")) {
4401
- throw new PmCliError(`Failed to acquire lock for ${id}: ${toErrorMessage(error)}`, EXIT_CODE.GENERIC_FAILURE);
4402
- }
4403
- let lockInfo = await readLockInfo(lockPath);
4404
- if (isStaleLock(lockInfo.info, ttlSeconds)) {
4405
- const staleRemoval = await removeConfirmedStaleLock({
4406
- lockPath,
4407
- id,
4408
- ttlSeconds,
4409
- force,
4410
- forceRequiredForStaleLock,
4411
- staleRemovals,
4412
- waitBudgetMs,
4413
- startedAtMs,
4414
- fallbackLockInfo: lockInfo
4415
- });
4416
- lockInfo = staleRemoval.lockInfo;
4417
- if (staleRemoval.staleRemovalCounted) {
4418
- staleRemovals += 1;
4419
- }
4420
- if (staleRemoval.shouldRetryCreate) {
4421
- continue;
4422
- }
4423
- }
4424
- const elapsedMs = Date.now() - startedAtMs;
4425
- if (waitBudgetMs === 0 || elapsedMs >= waitBudgetMs) {
4426
- throw buildLockConflictError(id, lockInfo.info, waitBudgetMs === 0 ? 0 : elapsedMs);
4427
- }
4428
- await sleepWithJitter(Math.min(backoffMs, waitBudgetMs - elapsedMs));
4429
- backoffMs = Math.min(backoffMs * 2, LOCK_WAIT_MAX_DELAY_MS);
4439
+ if (params.settings.history.missing_stream === "strict_error") {
4440
+ throw strictMissingStreamError(itemId, params.commandLabel);
4430
4441
  }
4442
+ warnings.push(...await createStream(historyPath, params.commandLabel));
4443
+ warnings.push(`history_stream_auto_created:${itemId}`);
4444
+ autoCreated.push(itemId);
4431
4445
  }
4446
+ return {
4447
+ auto_created_ids: autoCreated,
4448
+ warnings
4449
+ };
4432
4450
  }
4433
4451
 
4434
4452
  // dist/core/item/id.js
@@ -5512,6 +5530,7 @@ async function deleteItem(params) {
5512
5530
  }
5513
5531
 
5514
5532
  export {
5533
+ createCoreCommandHookContext,
5515
5534
  createSerialQueue,
5516
5535
  setActiveExtensionHooks,
5517
5536
  setActiveExtensionCommands,
@@ -5553,6 +5572,7 @@ export {
5553
5572
  compareTimestampStrings,
5554
5573
  matchesTimestampFilters,
5555
5574
  resolveIsoOrRelative,
5575
+ acquireLock,
5556
5576
  readRuntimeFieldOptionValue,
5557
5577
  coerceRuntimeFieldValue,
5558
5578
  collectRuntimeCreateFieldValues,
@@ -5579,7 +5599,6 @@ export {
5579
5599
  appendHistoryEntry,
5580
5600
  enforceHistoryStreamPolicyForItem,
5581
5601
  enforceHistoryStreamPolicyForItems,
5582
- acquireLock,
5583
5602
  normalizePrefix,
5584
5603
  normalizeRawItemId,
5585
5604
  normalizeItemId,
@@ -5595,4 +5614,4 @@ export {
5595
5614
  mutateItem,
5596
5615
  deleteItem
5597
5616
  };
5598
- //# sourceMappingURL=chunk-QXYKH56X.js.map
5617
+ //# sourceMappingURL=chunk-T4BRCB6Z.js.map