@unbrained/pm-cli 2026.6.30 → 2026.7.2

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 (628) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +26 -0
  3. package/dist/cli/bootstrap-args.js +89 -79
  4. package/dist/cli/bootstrap-args.js.map +1 -1
  5. package/dist/cli/commander-usage.d.ts +2 -0
  6. package/dist/cli/commander-usage.js +58 -47
  7. package/dist/cli/commander-usage.js.map +1 -1
  8. package/dist/cli/commands/aggregate.js +102 -79
  9. package/dist/cli/commands/aggregate.js.map +1 -1
  10. package/dist/cli/commands/calendar.js +339 -303
  11. package/dist/cli/commands/calendar.js.map +1 -1
  12. package/dist/cli/commands/close-many.js +89 -68
  13. package/dist/cli/commands/close-many.js.map +1 -1
  14. package/dist/cli/commands/close.js +157 -129
  15. package/dist/cli/commands/close.js.map +1 -1
  16. package/dist/cli/commands/comments-audit.js +50 -42
  17. package/dist/cli/commands/comments-audit.js.map +1 -1
  18. package/dist/cli/commands/config.d.ts +2 -0
  19. package/dist/cli/commands/config.js +443 -879
  20. package/dist/cli/commands/config.js.map +1 -1
  21. package/dist/cli/commands/context.js +365 -287
  22. package/dist/cli/commands/context.js.map +1 -1
  23. package/dist/cli/commands/contracts.js +352 -238
  24. package/dist/cli/commands/contracts.js.map +1 -1
  25. package/dist/cli/commands/create.js +483 -434
  26. package/dist/cli/commands/create.js.map +1 -1
  27. package/dist/cli/commands/dedupe-audit.js +46 -39
  28. package/dist/cli/commands/dedupe-audit.js.map +1 -1
  29. package/dist/cli/commands/dedupe-merge.js +88 -69
  30. package/dist/cli/commands/dedupe-merge.js.map +1 -1
  31. package/dist/cli/commands/extension/bundled-catalog.js +59 -46
  32. package/dist/cli/commands/extension/bundled-catalog.js.map +1 -1
  33. package/dist/cli/commands/extension/doctor.js +129 -78
  34. package/dist/cli/commands/extension/doctor.js.map +1 -1
  35. package/dist/cli/commands/extension/managed-state.js +101 -57
  36. package/dist/cli/commands/extension/managed-state.js.map +1 -1
  37. package/dist/cli/commands/extension/scaffold.d.ts +7 -0
  38. package/dist/cli/commands/extension/scaffold.js +214 -186
  39. package/dist/cli/commands/extension/scaffold.js.map +1 -1
  40. package/dist/cli/commands/extension.d.ts +6 -1
  41. package/dist/cli/commands/extension.js +1034 -902
  42. package/dist/cli/commands/extension.js.map +1 -1
  43. package/dist/cli/commands/get.js +114 -81
  44. package/dist/cli/commands/get.js.map +1 -1
  45. package/dist/cli/commands/health.d.ts +17 -0
  46. package/dist/cli/commands/health.js +446 -307
  47. package/dist/cli/commands/health.js.map +1 -1
  48. package/dist/cli/commands/history-compact.js +209 -140
  49. package/dist/cli/commands/history-compact.js.map +1 -1
  50. package/dist/cli/commands/history-redact.js +162 -119
  51. package/dist/cli/commands/history-redact.js.map +1 -1
  52. package/dist/cli/commands/history-repair.js +120 -85
  53. package/dist/cli/commands/history-repair.js.map +1 -1
  54. package/dist/cli/commands/init.d.ts +8 -2
  55. package/dist/cli/commands/init.js +263 -162
  56. package/dist/cli/commands/init.js.map +1 -1
  57. package/dist/cli/commands/list-filter-shared.js +55 -48
  58. package/dist/cli/commands/list-filter-shared.js.map +1 -1
  59. package/dist/cli/commands/list.js +152 -102
  60. package/dist/cli/commands/list.js.map +1 -1
  61. package/dist/cli/commands/next.js +49 -32
  62. package/dist/cli/commands/next.js.map +1 -1
  63. package/dist/cli/commands/plan.js +373 -298
  64. package/dist/cli/commands/plan.js.map +1 -1
  65. package/dist/cli/commands/recurrence-parsers.js +43 -25
  66. package/dist/cli/commands/recurrence-parsers.js.map +1 -1
  67. package/dist/cli/commands/reindex.d.ts +21 -5
  68. package/dist/cli/commands/reindex.js +345 -205
  69. package/dist/cli/commands/reindex.js.map +1 -1
  70. package/dist/cli/commands/restore.d.ts +8 -7
  71. package/dist/cli/commands/restore.js +105 -69
  72. package/dist/cli/commands/restore.js.map +1 -1
  73. package/dist/cli/commands/schema.js +33 -30
  74. package/dist/cli/commands/schema.js.map +1 -1
  75. package/dist/cli/commands/search.d.ts +10 -2
  76. package/dist/cli/commands/search.js +595 -536
  77. package/dist/cli/commands/search.js.map +1 -1
  78. package/dist/cli/commands/telemetry.js +98 -87
  79. package/dist/cli/commands/telemetry.js.map +1 -1
  80. package/dist/cli/commands/test-all.js +237 -168
  81. package/dist/cli/commands/test-all.js.map +1 -1
  82. package/dist/cli/commands/test.d.ts +6 -5
  83. package/dist/cli/commands/test.js +530 -464
  84. package/dist/cli/commands/test.js.map +1 -1
  85. package/dist/cli/commands/update-many.js +57 -42
  86. package/dist/cli/commands/update-many.js.map +1 -1
  87. package/dist/cli/commands/update.d.ts +1 -1
  88. package/dist/cli/commands/update.js +764 -747
  89. package/dist/cli/commands/update.js.map +1 -1
  90. package/dist/cli/commands/validate.d.ts +18 -1
  91. package/dist/cli/commands/validate.js +466 -343
  92. package/dist/cli/commands/validate.js.map +1 -1
  93. package/dist/cli/error-guidance.js +399 -357
  94. package/dist/cli/error-guidance.js.map +1 -1
  95. package/dist/cli/extension-command-options.js +48 -21
  96. package/dist/cli/extension-command-options.js.map +1 -1
  97. package/dist/cli/main.d.ts +47 -0
  98. package/dist/cli/main.js +428 -341
  99. package/dist/cli/main.js.map +1 -1
  100. package/dist/cli/migration-gates.js +22 -45
  101. package/dist/cli/migration-gates.js.map +1 -1
  102. package/dist/cli/register-list-query.js +94 -105
  103. package/dist/cli/register-list-query.js.map +1 -1
  104. package/dist/cli/register-mutation.js +400 -416
  105. package/dist/cli/register-mutation.js.map +1 -1
  106. package/dist/cli/register-operations.js +86 -66
  107. package/dist/cli/register-operations.js.map +1 -1
  108. package/dist/cli/register-setup.js +120 -101
  109. package/dist/cli/register-setup.js.map +1 -1
  110. package/dist/cli/registration-helpers.js +117 -122
  111. package/dist/cli/registration-helpers.js.map +1 -1
  112. package/dist/cli-bundle/chunks/{activity-MVSEND6D.js → activity-CUC4JY3U.js} +9 -9
  113. package/dist/cli-bundle/chunks/activity-WEIEMM73.js +16 -0
  114. package/dist/cli-bundle/chunks/{aggregate-MOC4TR2G.js → aggregate-DKUTRY6R.js} +109 -85
  115. package/dist/cli-bundle/chunks/aggregate-DKUTRY6R.js.map +1 -0
  116. package/dist/cli-bundle/chunks/{aggregate-XJHLZQ5X.js → aggregate-SW5PNGCS.js} +108 -84
  117. package/dist/cli-bundle/chunks/{aggregate-XJHLZQ5X.js.map → aggregate-SW5PNGCS.js.map} +2 -2
  118. package/dist/cli-bundle/chunks/{append-KDHT4GHI.js → append-H32VOR2Y.js} +6 -6
  119. package/dist/cli-bundle/chunks/{append-LEDBAM3K.js → append-UBM632FK.js} +6 -6
  120. package/dist/cli-bundle/chunks/{chunk-Z55WX4IQ.js → chunk-2227673O.js} +158 -114
  121. package/dist/cli-bundle/chunks/chunk-2227673O.js.map +1 -0
  122. package/dist/cli-bundle/chunks/{chunk-SJZTPVFT.js → chunk-2ASNV4DH.js} +4 -4
  123. package/dist/cli-bundle/chunks/{chunk-JVQ7UOYC.js → chunk-2CHRYUXL.js} +2 -2
  124. package/dist/cli-bundle/chunks/{chunk-QE5UFCCO.js → chunk-2KWL5NPW.js} +42 -27
  125. package/dist/cli-bundle/chunks/chunk-2KWL5NPW.js.map +1 -0
  126. package/dist/cli-bundle/chunks/{chunk-ZEATCVAC.js → chunk-36UGKF4O.js} +21 -29
  127. package/dist/cli-bundle/chunks/chunk-36UGKF4O.js.map +7 -0
  128. package/dist/cli-bundle/chunks/{chunk-JZG5ADVE.js → chunk-3AZUFQK6.js} +1103 -963
  129. package/dist/cli-bundle/chunks/chunk-3AZUFQK6.js.map +1 -0
  130. package/dist/cli-bundle/chunks/{chunk-DRPF274X.js → chunk-3LCUASYG.js} +2 -2
  131. package/dist/cli-bundle/chunks/{chunk-JJ4SG243.js → chunk-3Q2HBMTI.js} +2 -2
  132. package/dist/cli-bundle/chunks/chunk-4BU75MF4.js +87 -0
  133. package/dist/cli-bundle/chunks/chunk-4BU75MF4.js.map +7 -0
  134. package/dist/cli-bundle/chunks/{chunk-GF7EAR22.js → chunk-4NUOWFBT.js} +109 -72
  135. package/dist/cli-bundle/chunks/chunk-4NUOWFBT.js.map +7 -0
  136. package/dist/cli-bundle/chunks/{chunk-TQ6E76BE.js → chunk-55XRYWEG.js} +6 -6
  137. package/dist/cli-bundle/chunks/{chunk-5IRVSKPS.js → chunk-5GVTFFTC.js} +150 -224
  138. package/dist/cli-bundle/chunks/chunk-5GVTFFTC.js.map +1 -0
  139. package/dist/cli-bundle/chunks/{chunk-CHRNYKNI.js → chunk-5PGBHRY3.js} +41 -26
  140. package/dist/cli-bundle/chunks/chunk-5PGBHRY3.js.map +7 -0
  141. package/dist/cli-bundle/chunks/{chunk-53ARXF2O.js → chunk-66Z3X7ZG.js} +261 -161
  142. package/dist/cli-bundle/chunks/chunk-66Z3X7ZG.js.map +7 -0
  143. package/dist/cli-bundle/chunks/{chunk-A3UNLXNJ.js → chunk-6ITZLD4T.js} +738 -688
  144. package/dist/cli-bundle/chunks/chunk-6ITZLD4T.js.map +7 -0
  145. package/dist/cli-bundle/chunks/{chunk-JTRKME24.js → chunk-6YCYF2AI.js} +262 -162
  146. package/dist/cli-bundle/chunks/chunk-6YCYF2AI.js.map +1 -0
  147. package/dist/cli-bundle/chunks/{chunk-RM6MHL6A.js → chunk-6ZMBJRDJ.js} +580 -467
  148. package/dist/cli-bundle/chunks/chunk-6ZMBJRDJ.js.map +7 -0
  149. package/dist/cli-bundle/chunks/{chunk-RPRW26NG.js → chunk-7MYWF4ZX.js} +110 -73
  150. package/dist/cli-bundle/chunks/chunk-7MYWF4ZX.js.map +1 -0
  151. package/dist/cli-bundle/chunks/{chunk-SNUK7H5J.js → chunk-7NSPKJUS.js} +716 -606
  152. package/dist/cli-bundle/chunks/chunk-7NSPKJUS.js.map +7 -0
  153. package/dist/cli-bundle/chunks/{chunk-KYDYQMNW.js → chunk-7TH5NMVB.js} +95 -53
  154. package/dist/cli-bundle/chunks/chunk-7TH5NMVB.js.map +7 -0
  155. package/dist/cli-bundle/chunks/{chunk-VD3LKZFX.js → chunk-7W4H4K26.js} +739 -689
  156. package/dist/cli-bundle/chunks/chunk-7W4H4K26.js.map +1 -0
  157. package/dist/cli-bundle/chunks/{chunk-IBU2LLWM.js → chunk-A6VOGKBA.js} +6 -6
  158. package/dist/cli-bundle/chunks/{chunk-MLHX6DN5.js → chunk-AIAIXG7I.js} +2 -2
  159. package/dist/cli-bundle/chunks/{chunk-NIBP3I7A.js → chunk-AJEBCRIY.js} +128 -126
  160. package/dist/cli-bundle/chunks/chunk-AJEBCRIY.js.map +1 -0
  161. package/dist/cli-bundle/chunks/{chunk-VZDBVEZR.js → chunk-B4O5S7I3.js} +79 -57
  162. package/dist/cli-bundle/chunks/{chunk-VZDBVEZR.js.map → chunk-B4O5S7I3.js.map} +2 -2
  163. package/dist/cli-bundle/chunks/{chunk-5ABGFWR4.js → chunk-BTX5MIQF.js} +2 -2
  164. package/dist/cli-bundle/chunks/chunk-BVZZN2LH.js +809 -0
  165. package/dist/cli-bundle/chunks/chunk-BVZZN2LH.js.map +7 -0
  166. package/dist/cli-bundle/chunks/{chunk-3JWQCLR5.js → chunk-CYBDUHNO.js} +3 -3
  167. package/dist/cli-bundle/chunks/{chunk-WFJZDUM7.js → chunk-CZPVDLD2.js} +4 -4
  168. package/dist/cli-bundle/chunks/{chunk-FDEVKXC4.js → chunk-EMPGXBUF.js} +22 -30
  169. package/dist/cli-bundle/chunks/chunk-EMPGXBUF.js.map +1 -0
  170. package/dist/cli-bundle/chunks/{chunk-HUYYMTGW.js → chunk-EUKTMRN3.js} +2 -2
  171. package/dist/cli-bundle/chunks/{chunk-EVWYAG46.js → chunk-FFOQHGNH.js} +6 -6
  172. package/dist/cli-bundle/chunks/{chunk-IF4ERU6A.js → chunk-GFMSLORL.js} +6 -6
  173. package/dist/cli-bundle/chunks/{chunk-IZQOJR2B.js → chunk-GRRG3MCT.js} +198 -189
  174. package/dist/cli-bundle/chunks/chunk-GRRG3MCT.js.map +7 -0
  175. package/dist/cli-bundle/chunks/{chunk-IDYCAK35.js → chunk-H4GRLYJS.js} +3 -3
  176. package/dist/cli-bundle/chunks/{chunk-VMY7MZEM.js → chunk-HQTPRV4D.js} +6 -6
  177. package/dist/cli-bundle/chunks/{chunk-CY5IJMUM.js → chunk-I66WE2HE.js} +712 -602
  178. package/dist/cli-bundle/chunks/chunk-I66WE2HE.js.map +1 -0
  179. package/dist/cli-bundle/chunks/{chunk-ZFIEEDTJ.js → chunk-IEEJQCZ4.js} +509 -363
  180. package/dist/cli-bundle/chunks/chunk-IEEJQCZ4.js.map +7 -0
  181. package/dist/cli-bundle/chunks/{chunk-DU66JUGT.js → chunk-IG5JYZGU.js} +488 -420
  182. package/dist/cli-bundle/chunks/chunk-IG5JYZGU.js.map +7 -0
  183. package/dist/cli-bundle/chunks/{chunk-7L6TXOOC.js → chunk-JMK5GCK2.js} +2 -2
  184. package/dist/cli-bundle/chunks/{chunk-LBH7UYKY.js → chunk-JXAUVO6X.js} +258 -169
  185. package/dist/cli-bundle/chunks/{chunk-LBH7UYKY.js.map → chunk-JXAUVO6X.js.map} +2 -2
  186. package/dist/cli-bundle/chunks/{chunk-KRASIL6M.js → chunk-K2VYLVX4.js} +2 -2
  187. package/dist/cli-bundle/chunks/{chunk-4YIMPANT.js → chunk-KCO2EAN5.js} +3 -3
  188. package/dist/cli-bundle/chunks/{chunk-T7ZMQI4J.js → chunk-KIYCOJ63.js} +198 -189
  189. package/dist/cli-bundle/chunks/chunk-KIYCOJ63.js.map +1 -0
  190. package/dist/cli-bundle/chunks/{chunk-D6USKAMA.js → chunk-KLXF7NCC.js} +2 -2
  191. package/dist/cli-bundle/chunks/{chunk-V3KLX7U7.js → chunk-KN3URLKS.js} +510 -364
  192. package/dist/cli-bundle/chunks/chunk-KN3URLKS.js.map +1 -0
  193. package/dist/cli-bundle/chunks/{chunk-OB3RJV5F.js → chunk-LRKMWUUV.js} +2 -2
  194. package/dist/cli-bundle/chunks/{chunk-74PUWBGN.js → chunk-LTRAF2D7.js} +3 -3
  195. package/dist/cli-bundle/chunks/{chunk-5T6WPLRO.js → chunk-MNBPX5JS.js} +394 -354
  196. package/dist/cli-bundle/chunks/chunk-MNBPX5JS.js.map +7 -0
  197. package/dist/cli-bundle/chunks/{chunk-4TXTVZL3.js → chunk-MRD4T5LF.js} +2 -2
  198. package/dist/cli-bundle/chunks/{chunk-E2Q2ULMR.js → chunk-N2JSWVWG.js} +4 -4
  199. package/dist/cli-bundle/chunks/{chunk-7WDETKGP.js → chunk-N3QCJS4M.js} +1105 -965
  200. package/dist/cli-bundle/chunks/chunk-N3QCJS4M.js.map +7 -0
  201. package/dist/cli-bundle/chunks/{chunk-KGQ3W65B.js → chunk-NRZS637N.js} +258 -169
  202. package/dist/cli-bundle/chunks/chunk-NRZS637N.js.map +1 -0
  203. package/dist/cli-bundle/chunks/chunk-OTUJZKGI.js +799 -0
  204. package/dist/cli-bundle/chunks/chunk-OTUJZKGI.js.map +1 -0
  205. package/dist/cli-bundle/chunks/{chunk-ZIE6WXJ2.js → chunk-Q6K2OACU.js} +153 -90
  206. package/dist/cli-bundle/chunks/chunk-Q6K2OACU.js.map +1 -0
  207. package/dist/cli-bundle/chunks/{chunk-K46GQ265.js → chunk-Q6NXOHS6.js} +489 -421
  208. package/dist/cli-bundle/chunks/chunk-Q6NXOHS6.js.map +1 -0
  209. package/dist/cli-bundle/chunks/{chunk-7RIJGN4R.js → chunk-QH3FSKRJ.js} +2 -2
  210. package/dist/cli-bundle/chunks/{chunk-UB3V5WUI.js → chunk-RM37OPYK.js} +394 -354
  211. package/dist/cli-bundle/chunks/chunk-RM37OPYK.js.map +1 -0
  212. package/dist/cli-bundle/chunks/{chunk-OUQ5JEFM.js → chunk-S62UANU7.js} +3 -3
  213. package/dist/cli-bundle/chunks/{chunk-NO6Y6FB2.js → chunk-SPM2XLWI.js} +37 -28
  214. package/dist/cli-bundle/chunks/chunk-SPM2XLWI.js.map +7 -0
  215. package/dist/cli-bundle/chunks/{chunk-DORJSBGJ.js → chunk-SYNKD3ZG.js} +127 -125
  216. package/dist/cli-bundle/chunks/chunk-SYNKD3ZG.js.map +7 -0
  217. package/dist/cli-bundle/chunks/{chunk-6YRAMXRS.js → chunk-SYVUU7EK.js} +581 -468
  218. package/dist/cli-bundle/chunks/chunk-SYVUU7EK.js.map +1 -0
  219. package/dist/cli-bundle/chunks/{chunk-D5LYZVGB.js → chunk-TPOFWBMY.js} +95 -53
  220. package/dist/cli-bundle/chunks/chunk-TPOFWBMY.js.map +1 -0
  221. package/dist/cli-bundle/chunks/{chunk-IHXXUIXS.js → chunk-TTHCEV5Q.js} +92 -77
  222. package/dist/cli-bundle/chunks/chunk-TTHCEV5Q.js.map +1 -0
  223. package/dist/cli-bundle/chunks/{chunk-DLDCPF5X.js → chunk-U2BEEM2X.js} +3 -3
  224. package/dist/cli-bundle/chunks/{chunk-Z5BM2FKQ.js → chunk-UGLU6Q2I.js} +91 -76
  225. package/dist/cli-bundle/chunks/chunk-UGLU6Q2I.js.map +7 -0
  226. package/dist/cli-bundle/chunks/{chunk-73PTKMAE.js → chunk-UT73HUPC.js} +3 -3
  227. package/dist/cli-bundle/chunks/{chunk-F7G53BOA.js → chunk-UTSH5GWX.js} +4 -4
  228. package/dist/cli-bundle/chunks/{chunk-AWN4PPH5.js → chunk-UWKEJMZU.js} +157 -113
  229. package/dist/cli-bundle/chunks/chunk-UWKEJMZU.js.map +7 -0
  230. package/dist/cli-bundle/chunks/chunk-VY3VQ22F.js +84 -0
  231. package/dist/cli-bundle/chunks/chunk-VY3VQ22F.js.map +1 -0
  232. package/dist/cli-bundle/chunks/{chunk-KTMMTOIP.js → chunk-W47SML5B.js} +152 -89
  233. package/dist/cli-bundle/chunks/chunk-W47SML5B.js.map +7 -0
  234. package/dist/cli-bundle/chunks/{chunk-UFKNF23C.js → chunk-WJAMWAHZ.js} +157 -118
  235. package/dist/cli-bundle/chunks/chunk-WJAMWAHZ.js.map +7 -0
  236. package/dist/cli-bundle/chunks/{chunk-HIBK6H4S.js → chunk-XCHUVHKU.js} +685 -544
  237. package/dist/cli-bundle/chunks/chunk-XCHUVHKU.js.map +1 -0
  238. package/dist/cli-bundle/chunks/{chunk-DJDXAU74.js → chunk-XEWQKDYZ.js} +685 -544
  239. package/dist/cli-bundle/chunks/chunk-XEWQKDYZ.js.map +7 -0
  240. package/dist/cli-bundle/chunks/{chunk-BOWQWXLI.js → chunk-XTHQWXVC.js} +158 -119
  241. package/dist/cli-bundle/chunks/chunk-XTHQWXVC.js.map +1 -0
  242. package/dist/cli-bundle/chunks/{chunk-6T5ZIWBS.js → chunk-XWGEMNBR.js} +150 -224
  243. package/dist/cli-bundle/chunks/chunk-XWGEMNBR.js.map +7 -0
  244. package/dist/cli-bundle/chunks/{chunk-JIP67N2K.js → chunk-Y4NRKBFW.js} +3 -3
  245. package/dist/cli-bundle/chunks/{chunk-WTRUDJ3R.js → chunk-YLZZ6T54.js} +38 -29
  246. package/dist/cli-bundle/chunks/chunk-YLZZ6T54.js.map +1 -0
  247. package/dist/cli-bundle/chunks/{chunk-FBZ5XAAF.js → chunk-YPKFV2JR.js} +6 -6
  248. package/dist/cli-bundle/chunks/{chunk-OKQ22KTH.js → chunk-Z4DGFQDH.js} +80 -58
  249. package/dist/cli-bundle/chunks/{chunk-OKQ22KTH.js.map → chunk-Z4DGFQDH.js.map} +1 -1
  250. package/dist/cli-bundle/chunks/{chunk-BN3CWK6G.js → chunk-ZNHEYCDD.js} +2 -2
  251. package/dist/cli-bundle/chunks/{chunk-YEDFE4DC.js → chunk-ZNT7KEWE.js} +2 -2
  252. package/dist/cli-bundle/chunks/{claim-HMCLSLUE.js → claim-SENTPZBN.js} +8 -8
  253. package/dist/cli-bundle/chunks/{claim-6NINZYB3.js → claim-Z7MEQCBT.js} +8 -8
  254. package/dist/cli-bundle/chunks/{close-OP3LK7Z2.js → close-424MX4CU.js} +7 -7
  255. package/dist/cli-bundle/chunks/close-YCWQQPDS.js +14 -0
  256. package/dist/cli-bundle/chunks/{close-many-CXJBOWWY.js → close-many-2IV4J2TR.js} +103 -82
  257. package/dist/cli-bundle/chunks/close-many-2IV4J2TR.js.map +1 -0
  258. package/dist/cli-bundle/chunks/{close-many-BFMP6HHK.js → close-many-SWY34BII.js} +102 -81
  259. package/dist/cli-bundle/chunks/close-many-SWY34BII.js.map +7 -0
  260. package/dist/cli-bundle/chunks/{comments-ETHABIY6.js → comments-4FGNTSNV.js} +8 -8
  261. package/dist/cli-bundle/chunks/{comments-MU2WMBUY.js → comments-7YS5MY5X.js} +8 -8
  262. package/dist/cli-bundle/chunks/config-BZJKK7FZ.js +1062 -0
  263. package/dist/cli-bundle/chunks/config-BZJKK7FZ.js.map +1 -0
  264. package/dist/cli-bundle/chunks/config-G74GISC4.js +1072 -0
  265. package/dist/cli-bundle/chunks/config-G74GISC4.js.map +7 -0
  266. package/dist/cli-bundle/chunks/{context-7ZEZV3BV.js → context-LHVKJSPJ.js} +12 -12
  267. package/dist/cli-bundle/chunks/{context-XDI4DKKT.js → context-ZQY54JNS.js} +12 -12
  268. package/dist/cli-bundle/chunks/{contracts-SMOAN5NF.js → contracts-CP2EZJC7.js} +320 -199
  269. package/dist/cli-bundle/chunks/contracts-CP2EZJC7.js.map +7 -0
  270. package/dist/cli-bundle/chunks/{contracts-KP4QAGVW.js → contracts-FIZLMP7O.js} +321 -200
  271. package/dist/cli-bundle/chunks/contracts-FIZLMP7O.js.map +1 -0
  272. package/dist/cli-bundle/chunks/{copy-JJ3KOQW2.js → copy-GYNQQPW2.js} +5 -5
  273. package/dist/cli-bundle/chunks/{copy-CWM6SBY6.js → copy-TLW7JTQT.js} +5 -5
  274. package/dist/cli-bundle/chunks/{create-J5Q2ELZT.js → create-VSKYSOCD.js} +12 -12
  275. package/dist/cli-bundle/chunks/create-XTMAPS7I.js +28 -0
  276. package/dist/cli-bundle/chunks/{delete-2GZLQEUQ.js → delete-4W5JYCEG.js} +5 -5
  277. package/dist/cli-bundle/chunks/{delete-OOQS4KVD.js → delete-ANTOTI2I.js} +5 -5
  278. package/dist/cli-bundle/chunks/{deps-IF4IGL4R.js → deps-HPPE6MJN.js} +5 -5
  279. package/dist/cli-bundle/chunks/{deps-ZVGGCRR6.js → deps-ZQZN54EZ.js} +5 -5
  280. package/dist/cli-bundle/chunks/{docs-NFTBCQQC.js → docs-RPOVFMP3.js} +7 -7
  281. package/dist/cli-bundle/chunks/{docs-2TIFR62T.js → docs-XJNYBJGE.js} +7 -7
  282. package/dist/cli-bundle/chunks/{eval-2F6EH4XN.js → eval-DM6JBZTS.js} +10 -10
  283. package/dist/cli-bundle/chunks/{eval-PFKXQR3B.js → eval-RFBI5FGS.js} +10 -10
  284. package/dist/cli-bundle/chunks/{extension-GMVOIP4O.js → extension-B3YY4WY5.js} +11 -10
  285. package/dist/cli-bundle/chunks/{extension-3LRYX7SW.js → extension-TTSEFQTS.js} +11 -10
  286. package/dist/cli-bundle/chunks/{files-DF3HO6XK.js → files-5D65CHGE.js} +7 -7
  287. package/dist/cli-bundle/chunks/{files-T5ODMETM.js → files-GPIG77EN.js} +7 -7
  288. package/dist/cli-bundle/chunks/{focus-MY5ARIEK.js → focus-C3PEJV2C.js} +6 -6
  289. package/dist/cli-bundle/chunks/{focus-DLXKK4AH.js → focus-ZHN7WIGX.js} +6 -6
  290. package/dist/cli-bundle/chunks/{gc-MDGRR2SU.js → gc-D4JQ6OWN.js} +3 -3
  291. package/dist/cli-bundle/chunks/{gc-FULIVYR4.js → gc-VZIXDL32.js} +3 -3
  292. package/dist/cli-bundle/chunks/{get-VYPIICPC.js → get-GIBRUUOP.js} +121 -81
  293. package/dist/cli-bundle/chunks/get-GIBRUUOP.js.map +1 -0
  294. package/dist/cli-bundle/chunks/{get-AWK324RS.js → get-IOVAN6RU.js} +120 -80
  295. package/dist/cli-bundle/chunks/get-IOVAN6RU.js.map +7 -0
  296. package/dist/cli-bundle/chunks/{health-Q66C43GN.js → health-L2U3AFKV.js} +437 -264
  297. package/dist/cli-bundle/chunks/health-L2U3AFKV.js.map +1 -0
  298. package/dist/cli-bundle/chunks/{health-FBCVZGSX.js → health-MM7AWXYF.js} +436 -263
  299. package/dist/cli-bundle/chunks/health-MM7AWXYF.js.map +7 -0
  300. package/dist/cli-bundle/chunks/history-DD7L7BNL.js +18 -0
  301. package/dist/cli-bundle/chunks/{history-X4OSES6K.js → history-IL7XCEX2.js} +8 -8
  302. package/dist/cli-bundle/chunks/{history-compact-2GHT32UX.js → history-compact-HALOTOU7.js} +214 -135
  303. package/dist/cli-bundle/chunks/history-compact-HALOTOU7.js.map +1 -0
  304. package/dist/cli-bundle/chunks/{history-compact-WLCQEKXS.js → history-compact-MV25P7DM.js} +213 -134
  305. package/dist/cli-bundle/chunks/history-compact-MV25P7DM.js.map +7 -0
  306. package/dist/cli-bundle/chunks/history-redact-IX4YEWMY.js +19 -0
  307. package/dist/cli-bundle/chunks/{history-redact-45YW65BK.js → history-redact-VYCWQFK7.js} +9 -9
  308. package/dist/cli-bundle/chunks/{history-repair-FY75IC26.js → history-repair-44MODPQF.js} +124 -84
  309. package/dist/cli-bundle/chunks/history-repair-44MODPQF.js.map +1 -0
  310. package/dist/cli-bundle/chunks/{history-repair-GABSDSVD.js → history-repair-CPNAOCNF.js} +123 -83
  311. package/dist/cli-bundle/chunks/history-repair-CPNAOCNF.js.map +7 -0
  312. package/dist/cli-bundle/chunks/{init-KO7CGIRQ.js → init-F27NHENZ.js} +12 -11
  313. package/dist/cli-bundle/chunks/init-HHVQQP6C.js +22 -0
  314. package/dist/cli-bundle/chunks/{learnings-LHZT5BHW.js → learnings-HJVDQIGY.js} +8 -8
  315. package/dist/cli-bundle/chunks/{learnings-3F7YLI45.js → learnings-XSFSUUWK.js} +8 -8
  316. package/dist/cli-bundle/chunks/{list-Y6AU5BJS.js → list-HPMEKCAA.js} +8 -8
  317. package/dist/cli-bundle/chunks/{list-ROT7JF62.js → list-VMPWTURB.js} +8 -8
  318. package/dist/cli-bundle/chunks/{next-66BJB4N2.js → next-ETXF2ZCN.js} +59 -37
  319. package/dist/cli-bundle/chunks/next-ETXF2ZCN.js.map +7 -0
  320. package/dist/cli-bundle/chunks/{next-N5MWJTBY.js → next-QM6YJIIS.js} +60 -38
  321. package/dist/cli-bundle/chunks/next-QM6YJIIS.js.map +1 -0
  322. package/dist/cli-bundle/chunks/{notes-FW6YFLND.js → notes-GDZIKGR6.js} +8 -8
  323. package/dist/cli-bundle/chunks/{notes-EVJZ3VAB.js → notes-WDDBPC4D.js} +8 -8
  324. package/dist/cli-bundle/chunks/{plan-ZHKZ7JVF.js → plan-BGDR73Z6.js} +373 -279
  325. package/dist/cli-bundle/chunks/plan-BGDR73Z6.js.map +1 -0
  326. package/dist/cli-bundle/chunks/{plan-DQ7G4EDC.js → plan-C5IMM335.js} +372 -278
  327. package/dist/cli-bundle/chunks/plan-C5IMM335.js.map +7 -0
  328. package/dist/cli-bundle/chunks/{profile-CHAW6SEA.js → profile-CCOKZ2IQ.js} +9 -9
  329. package/dist/cli-bundle/chunks/{profile-UPZGCDOG.js → profile-HUCENIEQ.js} +9 -9
  330. package/dist/cli-bundle/chunks/{register-list-query-Y2VRHPCL.js → register-list-query-ROSNIL52.js} +80 -83
  331. package/dist/cli-bundle/chunks/register-list-query-ROSNIL52.js.map +1 -0
  332. package/dist/cli-bundle/chunks/{register-list-query-KY6Z6WV7.js → register-list-query-XN4ZRHSV.js} +79 -82
  333. package/dist/cli-bundle/chunks/register-list-query-XN4ZRHSV.js.map +7 -0
  334. package/dist/cli-bundle/chunks/{register-mutation-PCARIGZS.js → register-mutation-CFSB2MS3.js} +406 -385
  335. package/dist/cli-bundle/chunks/register-mutation-CFSB2MS3.js.map +1 -0
  336. package/dist/cli-bundle/chunks/{register-mutation-N6AYSKPM.js → register-mutation-KRLAHEL2.js} +405 -384
  337. package/dist/cli-bundle/chunks/register-mutation-KRLAHEL2.js.map +7 -0
  338. package/dist/cli-bundle/chunks/{register-operations-L6CYTOIH.js → register-operations-4PASGJDB.js} +112 -93
  339. package/dist/cli-bundle/chunks/register-operations-4PASGJDB.js.map +7 -0
  340. package/dist/cli-bundle/chunks/{register-operations-YAT6FUUB.js → register-operations-MBN4KGUM.js} +113 -94
  341. package/dist/cli-bundle/chunks/register-operations-MBN4KGUM.js.map +1 -0
  342. package/dist/cli-bundle/chunks/{register-setup-N7UGXYJC.js → register-setup-VIAWYFP5.js} +129 -104
  343. package/dist/cli-bundle/chunks/register-setup-VIAWYFP5.js.map +1 -0
  344. package/dist/cli-bundle/chunks/{register-setup-MPANILQF.js → register-setup-ZCGKHDKL.js} +128 -103
  345. package/dist/cli-bundle/chunks/register-setup-ZCGKHDKL.js.map +7 -0
  346. package/dist/cli-bundle/chunks/{restore-DKMCLPI5.js → restore-4CBWUMCX.js} +9 -9
  347. package/dist/cli-bundle/chunks/restore-5UEAGG3W.js +17 -0
  348. package/dist/cli-bundle/chunks/{scheduling-shortcuts-3F4QUEDH.js → scheduling-shortcuts-6VFKNKCM.js} +12 -12
  349. package/dist/cli-bundle/chunks/{scheduling-shortcuts-BNZLQK36.js → scheduling-shortcuts-ERHCVTEM.js} +12 -12
  350. package/dist/cli-bundle/chunks/{schema-OLT6LVKH.js → schema-TDGK6N3I.js} +7 -7
  351. package/dist/cli-bundle/chunks/{schema-XJXKJQF5.js → schema-UE5KKAUX.js} +7 -7
  352. package/dist/cli-bundle/chunks/{search-KP6H7COV.js → search-FP7MEU4S.js} +10 -10
  353. package/dist/cli-bundle/chunks/{search-CX5UMV4H.js → search-K4CFLQ5S.js} +10 -10
  354. package/dist/cli-bundle/chunks/{stats-QZUG6MX5.js → stats-NJJCALEZ.js} +6 -6
  355. package/dist/cli-bundle/chunks/{stats-7XW4OEMK.js → stats-XT6QRKQY.js} +6 -6
  356. package/dist/cli-bundle/chunks/{telemetry-DIFPXCAT.js → telemetry-5SQ5UDXC.js} +84 -70
  357. package/dist/cli-bundle/chunks/telemetry-5SQ5UDXC.js.map +7 -0
  358. package/dist/cli-bundle/chunks/{telemetry-WTYFUPRL.js → telemetry-HVXFZA2U.js} +85 -71
  359. package/dist/cli-bundle/chunks/telemetry-HVXFZA2U.js.map +1 -0
  360. package/dist/cli-bundle/chunks/{test-QNDXZQCW.js → test-UFSJ5YIO.js} +15 -14
  361. package/dist/cli-bundle/chunks/{test-HU2BS7EY.js → test-YCDAUBWF.js} +15 -14
  362. package/dist/cli-bundle/chunks/test-all-2BWKY3GQ.js +427 -0
  363. package/dist/cli-bundle/chunks/test-all-2BWKY3GQ.js.map +1 -0
  364. package/dist/cli-bundle/chunks/test-all-PM7UYN42.js +430 -0
  365. package/dist/cli-bundle/chunks/test-all-PM7UYN42.js.map +7 -0
  366. package/dist/cli-bundle/chunks/{test-runs-CA6K32RD.js → test-runs-FK5E75AA.js} +185 -147
  367. package/dist/cli-bundle/chunks/test-runs-FK5E75AA.js.map +1 -0
  368. package/dist/cli-bundle/chunks/{test-runs-LANLLPVO.js → test-runs-H4TGWGRN.js} +184 -146
  369. package/dist/cli-bundle/chunks/test-runs-H4TGWGRN.js.map +7 -0
  370. package/dist/cli-bundle/chunks/update-MTCFES6X.js +24 -0
  371. package/dist/cli-bundle/chunks/{update-DJKWLBWJ.js → update-Y5WQVT5O.js} +15 -15
  372. package/dist/cli-bundle/chunks/{update-many-LU3SCNK5.js → update-many-6YAYYRLE.js} +83 -68
  373. package/dist/cli-bundle/chunks/{update-many-LU3SCNK5.js.map → update-many-6YAYYRLE.js.map} +2 -2
  374. package/dist/cli-bundle/chunks/{update-many-VW5DGF3S.js → update-many-JTKKSA7Y.js} +84 -69
  375. package/dist/cli-bundle/chunks/{update-many-VW5DGF3S.js.map → update-many-JTKKSA7Y.js.map} +1 -1
  376. package/dist/cli-bundle/chunks/{upgrade-ICXY244R.js → upgrade-DTAHZ236.js} +11 -10
  377. package/dist/cli-bundle/chunks/{upgrade-ICXY244R.js.map → upgrade-DTAHZ236.js.map} +1 -1
  378. package/dist/cli-bundle/chunks/{upgrade-77FRUAXN.js → upgrade-JUDU7YL4.js} +13 -12
  379. package/dist/cli-bundle/chunks/{upgrade-77FRUAXN.js.map → upgrade-JUDU7YL4.js.map} +1 -1
  380. package/dist/cli-bundle/chunks/{validate-2G566PKQ.js → validate-732RWS5W.js} +440 -319
  381. package/dist/cli-bundle/chunks/validate-732RWS5W.js.map +7 -0
  382. package/dist/cli-bundle/chunks/{validate-BDPVXHHH.js → validate-W7H5TEDC.js} +441 -320
  383. package/dist/cli-bundle/chunks/validate-W7H5TEDC.js.map +1 -0
  384. package/dist/cli-bundle/main.js +986 -1500
  385. package/dist/cli-bundle/main.js.map +4 -4
  386. package/dist/core/config/nested-settings.js +89 -67
  387. package/dist/core/config/nested-settings.js.map +1 -1
  388. package/dist/core/extensions/activation-summary-markdown.js +23 -12
  389. package/dist/core/extensions/activation-summary-markdown.js.map +1 -1
  390. package/dist/core/extensions/extension-policy.d.ts +18 -3
  391. package/dist/core/extensions/extension-policy.js +116 -106
  392. package/dist/core/extensions/extension-policy.js.map +1 -1
  393. package/dist/core/extensions/loader.js +310 -232
  394. package/dist/core/extensions/loader.js.map +1 -1
  395. package/dist/core/governance/metadata-coverage.js +20 -28
  396. package/dist/core/governance/metadata-coverage.js.map +1 -1
  397. package/dist/core/history/drift-scan.js +93 -81
  398. package/dist/core/history/drift-scan.js.map +1 -1
  399. package/dist/core/item/item-format.js +523 -410
  400. package/dist/core/item/item-format.js.map +1 -1
  401. package/dist/core/item/item-type-definition.js +14 -14
  402. package/dist/core/item/item-type-definition.js.map +1 -1
  403. package/dist/core/item/type-registry.js +87 -82
  404. package/dist/core/item/type-registry.js.map +1 -1
  405. package/dist/core/output/mutation-projection.js +42 -26
  406. package/dist/core/output/mutation-projection.js.map +1 -1
  407. package/dist/core/schema/runtime-schema.js +34 -28
  408. package/dist/core/schema/runtime-schema.js.map +1 -1
  409. package/dist/core/search/semantic-defaults.js +64 -37
  410. package/dist/core/search/semantic-defaults.js.map +1 -1
  411. package/dist/core/search/vector-stores.js +32 -17
  412. package/dist/core/search/vector-stores.js.map +1 -1
  413. package/dist/core/sentry/helpers.js +31 -28
  414. package/dist/core/sentry/helpers.js.map +1 -1
  415. package/dist/core/sentry/instrument.js +54 -43
  416. package/dist/core/sentry/instrument.js.map +1 -1
  417. package/dist/core/store/front-matter-cache.js +239 -153
  418. package/dist/core/store/front-matter-cache.js.map +1 -1
  419. package/dist/core/store/item-store.js +33 -26
  420. package/dist/core/store/item-store.js.map +1 -1
  421. package/dist/core/store/settings.js +247 -203
  422. package/dist/core/store/settings.js.map +1 -1
  423. package/dist/core/test/background-runs.js +189 -160
  424. package/dist/core/test/background-runs.js.map +1 -1
  425. package/dist/mcp/server.js +387 -367
  426. package/dist/mcp/server.js.map +1 -1
  427. package/dist/sdk/cli-contracts/flag-contracts.js +111 -180
  428. package/dist/sdk/cli-contracts/flag-contracts.js.map +1 -1
  429. package/dist/sdk/cli-contracts/tool-schema.js +76 -45
  430. package/dist/sdk/cli-contracts/tool-schema.js.map +1 -1
  431. package/dist/sdk/compose.d.ts +4 -1
  432. package/dist/sdk/compose.js +181 -115
  433. package/dist/sdk/compose.js.map +1 -1
  434. package/docs/RELEASING.md +2 -3
  435. package/package.json +2 -2
  436. package/packages/pm-beads/extensions/beads/runtime.ts +240 -167
  437. package/packages/pm-guide-shell/extensions/guide-shell/runtime.ts +65 -58
  438. package/packages/pm-todos/extensions/todos/runtime.ts +65 -42
  439. package/dist/cli-bundle/chunks/activity-EJBMXUBH.js +0 -16
  440. package/dist/cli-bundle/chunks/aggregate-MOC4TR2G.js.map +0 -1
  441. package/dist/cli-bundle/chunks/chunk-53ARXF2O.js.map +0 -7
  442. package/dist/cli-bundle/chunks/chunk-5IRVSKPS.js.map +0 -1
  443. package/dist/cli-bundle/chunks/chunk-5T6WPLRO.js.map +0 -7
  444. package/dist/cli-bundle/chunks/chunk-6T5ZIWBS.js.map +0 -7
  445. package/dist/cli-bundle/chunks/chunk-6YRAMXRS.js.map +0 -1
  446. package/dist/cli-bundle/chunks/chunk-7WDETKGP.js.map +0 -7
  447. package/dist/cli-bundle/chunks/chunk-A3UNLXNJ.js.map +0 -7
  448. package/dist/cli-bundle/chunks/chunk-AWN4PPH5.js.map +0 -7
  449. package/dist/cli-bundle/chunks/chunk-BOWQWXLI.js.map +0 -1
  450. package/dist/cli-bundle/chunks/chunk-C2KCIZKZ.js +0 -115
  451. package/dist/cli-bundle/chunks/chunk-C2KCIZKZ.js.map +0 -1
  452. package/dist/cli-bundle/chunks/chunk-CHRNYKNI.js.map +0 -7
  453. package/dist/cli-bundle/chunks/chunk-CY5IJMUM.js.map +0 -1
  454. package/dist/cli-bundle/chunks/chunk-D5LYZVGB.js.map +0 -1
  455. package/dist/cli-bundle/chunks/chunk-DJDXAU74.js.map +0 -7
  456. package/dist/cli-bundle/chunks/chunk-DORJSBGJ.js.map +0 -7
  457. package/dist/cli-bundle/chunks/chunk-DU66JUGT.js.map +0 -7
  458. package/dist/cli-bundle/chunks/chunk-F6VH3LFC.js +0 -118
  459. package/dist/cli-bundle/chunks/chunk-F6VH3LFC.js.map +0 -7
  460. package/dist/cli-bundle/chunks/chunk-FDEVKXC4.js.map +0 -1
  461. package/dist/cli-bundle/chunks/chunk-GF7EAR22.js.map +0 -7
  462. package/dist/cli-bundle/chunks/chunk-HIBK6H4S.js.map +0 -1
  463. package/dist/cli-bundle/chunks/chunk-IHXXUIXS.js.map +0 -1
  464. package/dist/cli-bundle/chunks/chunk-ISEKN64V.js +0 -35
  465. package/dist/cli-bundle/chunks/chunk-ISEKN64V.js.map +0 -7
  466. package/dist/cli-bundle/chunks/chunk-IZQOJR2B.js.map +0 -7
  467. package/dist/cli-bundle/chunks/chunk-JTRKME24.js.map +0 -1
  468. package/dist/cli-bundle/chunks/chunk-JZG5ADVE.js.map +0 -1
  469. package/dist/cli-bundle/chunks/chunk-K46GQ265.js.map +0 -1
  470. package/dist/cli-bundle/chunks/chunk-KGQ3W65B.js.map +0 -1
  471. package/dist/cli-bundle/chunks/chunk-KTMMTOIP.js.map +0 -7
  472. package/dist/cli-bundle/chunks/chunk-KYDYQMNW.js.map +0 -7
  473. package/dist/cli-bundle/chunks/chunk-NIBP3I7A.js.map +0 -1
  474. package/dist/cli-bundle/chunks/chunk-NO6Y6FB2.js.map +0 -7
  475. package/dist/cli-bundle/chunks/chunk-QE5UFCCO.js.map +0 -1
  476. package/dist/cli-bundle/chunks/chunk-RM6MHL6A.js.map +0 -7
  477. package/dist/cli-bundle/chunks/chunk-RPRW26NG.js.map +0 -1
  478. package/dist/cli-bundle/chunks/chunk-SNUK7H5J.js.map +0 -7
  479. package/dist/cli-bundle/chunks/chunk-T7ZMQI4J.js.map +0 -1
  480. package/dist/cli-bundle/chunks/chunk-UB3V5WUI.js.map +0 -1
  481. package/dist/cli-bundle/chunks/chunk-UFKNF23C.js.map +0 -7
  482. package/dist/cli-bundle/chunks/chunk-V3KLX7U7.js.map +0 -1
  483. package/dist/cli-bundle/chunks/chunk-VD3LKZFX.js.map +0 -1
  484. package/dist/cli-bundle/chunks/chunk-W2VMLL5S.js +0 -32
  485. package/dist/cli-bundle/chunks/chunk-W2VMLL5S.js.map +0 -1
  486. package/dist/cli-bundle/chunks/chunk-WTRUDJ3R.js.map +0 -1
  487. package/dist/cli-bundle/chunks/chunk-Z55WX4IQ.js.map +0 -1
  488. package/dist/cli-bundle/chunks/chunk-Z5BM2FKQ.js.map +0 -7
  489. package/dist/cli-bundle/chunks/chunk-ZEATCVAC.js.map +0 -7
  490. package/dist/cli-bundle/chunks/chunk-ZFIEEDTJ.js.map +0 -7
  491. package/dist/cli-bundle/chunks/chunk-ZIE6WXJ2.js.map +0 -1
  492. package/dist/cli-bundle/chunks/close-37KEHLYM.js +0 -14
  493. package/dist/cli-bundle/chunks/close-many-BFMP6HHK.js.map +0 -7
  494. package/dist/cli-bundle/chunks/close-many-CXJBOWWY.js.map +0 -1
  495. package/dist/cli-bundle/chunks/config-FIXJZEQK.js +0 -1541
  496. package/dist/cli-bundle/chunks/config-FIXJZEQK.js.map +0 -7
  497. package/dist/cli-bundle/chunks/config-X3ZVCUUG.js +0 -1531
  498. package/dist/cli-bundle/chunks/config-X3ZVCUUG.js.map +0 -1
  499. package/dist/cli-bundle/chunks/contracts-KP4QAGVW.js.map +0 -1
  500. package/dist/cli-bundle/chunks/contracts-SMOAN5NF.js.map +0 -7
  501. package/dist/cli-bundle/chunks/create-DFMNBKBS.js +0 -28
  502. package/dist/cli-bundle/chunks/get-AWK324RS.js.map +0 -7
  503. package/dist/cli-bundle/chunks/get-VYPIICPC.js.map +0 -1
  504. package/dist/cli-bundle/chunks/health-FBCVZGSX.js.map +0 -7
  505. package/dist/cli-bundle/chunks/health-Q66C43GN.js.map +0 -1
  506. package/dist/cli-bundle/chunks/history-5XUSLAJA.js +0 -18
  507. package/dist/cli-bundle/chunks/history-compact-2GHT32UX.js.map +0 -1
  508. package/dist/cli-bundle/chunks/history-compact-WLCQEKXS.js.map +0 -7
  509. package/dist/cli-bundle/chunks/history-redact-BVHWDXPR.js +0 -19
  510. package/dist/cli-bundle/chunks/history-repair-FY75IC26.js.map +0 -1
  511. package/dist/cli-bundle/chunks/history-repair-GABSDSVD.js.map +0 -7
  512. package/dist/cli-bundle/chunks/init-TRYJELH4.js +0 -21
  513. package/dist/cli-bundle/chunks/next-66BJB4N2.js.map +0 -7
  514. package/dist/cli-bundle/chunks/next-N5MWJTBY.js.map +0 -1
  515. package/dist/cli-bundle/chunks/plan-DQ7G4EDC.js.map +0 -7
  516. package/dist/cli-bundle/chunks/plan-ZHKZ7JVF.js.map +0 -1
  517. package/dist/cli-bundle/chunks/register-list-query-KY6Z6WV7.js.map +0 -7
  518. package/dist/cli-bundle/chunks/register-list-query-Y2VRHPCL.js.map +0 -1
  519. package/dist/cli-bundle/chunks/register-mutation-N6AYSKPM.js.map +0 -7
  520. package/dist/cli-bundle/chunks/register-mutation-PCARIGZS.js.map +0 -1
  521. package/dist/cli-bundle/chunks/register-operations-L6CYTOIH.js.map +0 -7
  522. package/dist/cli-bundle/chunks/register-operations-YAT6FUUB.js.map +0 -1
  523. package/dist/cli-bundle/chunks/register-setup-MPANILQF.js.map +0 -7
  524. package/dist/cli-bundle/chunks/register-setup-N7UGXYJC.js.map +0 -1
  525. package/dist/cli-bundle/chunks/restore-IRAKSWIW.js +0 -17
  526. package/dist/cli-bundle/chunks/telemetry-DIFPXCAT.js.map +0 -7
  527. package/dist/cli-bundle/chunks/telemetry-WTYFUPRL.js.map +0 -1
  528. package/dist/cli-bundle/chunks/test-all-PZTBLLQ6.js +0 -360
  529. package/dist/cli-bundle/chunks/test-all-PZTBLLQ6.js.map +0 -7
  530. package/dist/cli-bundle/chunks/test-all-XLPI4USF.js +0 -357
  531. package/dist/cli-bundle/chunks/test-all-XLPI4USF.js.map +0 -1
  532. package/dist/cli-bundle/chunks/test-runs-CA6K32RD.js.map +0 -1
  533. package/dist/cli-bundle/chunks/test-runs-LANLLPVO.js.map +0 -7
  534. package/dist/cli-bundle/chunks/update-UXDLTEOZ.js +0 -24
  535. package/dist/cli-bundle/chunks/validate-2G566PKQ.js.map +0 -7
  536. package/dist/cli-bundle/chunks/validate-BDPVXHHH.js.map +0 -1
  537. /package/dist/cli-bundle/chunks/{activity-MVSEND6D.js.map → activity-CUC4JY3U.js.map} +0 -0
  538. /package/dist/cli-bundle/chunks/{activity-EJBMXUBH.js.map → activity-WEIEMM73.js.map} +0 -0
  539. /package/dist/cli-bundle/chunks/{append-KDHT4GHI.js.map → append-H32VOR2Y.js.map} +0 -0
  540. /package/dist/cli-bundle/chunks/{append-LEDBAM3K.js.map → append-UBM632FK.js.map} +0 -0
  541. /package/dist/cli-bundle/chunks/{chunk-SJZTPVFT.js.map → chunk-2ASNV4DH.js.map} +0 -0
  542. /package/dist/cli-bundle/chunks/{chunk-JVQ7UOYC.js.map → chunk-2CHRYUXL.js.map} +0 -0
  543. /package/dist/cli-bundle/chunks/{chunk-DRPF274X.js.map → chunk-3LCUASYG.js.map} +0 -0
  544. /package/dist/cli-bundle/chunks/{chunk-JJ4SG243.js.map → chunk-3Q2HBMTI.js.map} +0 -0
  545. /package/dist/cli-bundle/chunks/{chunk-TQ6E76BE.js.map → chunk-55XRYWEG.js.map} +0 -0
  546. /package/dist/cli-bundle/chunks/{chunk-IBU2LLWM.js.map → chunk-A6VOGKBA.js.map} +0 -0
  547. /package/dist/cli-bundle/chunks/{chunk-MLHX6DN5.js.map → chunk-AIAIXG7I.js.map} +0 -0
  548. /package/dist/cli-bundle/chunks/{chunk-5ABGFWR4.js.map → chunk-BTX5MIQF.js.map} +0 -0
  549. /package/dist/cli-bundle/chunks/{chunk-3JWQCLR5.js.map → chunk-CYBDUHNO.js.map} +0 -0
  550. /package/dist/cli-bundle/chunks/{chunk-WFJZDUM7.js.map → chunk-CZPVDLD2.js.map} +0 -0
  551. /package/dist/cli-bundle/chunks/{chunk-HUYYMTGW.js.map → chunk-EUKTMRN3.js.map} +0 -0
  552. /package/dist/cli-bundle/chunks/{chunk-EVWYAG46.js.map → chunk-FFOQHGNH.js.map} +0 -0
  553. /package/dist/cli-bundle/chunks/{chunk-IF4ERU6A.js.map → chunk-GFMSLORL.js.map} +0 -0
  554. /package/dist/cli-bundle/chunks/{chunk-IDYCAK35.js.map → chunk-H4GRLYJS.js.map} +0 -0
  555. /package/dist/cli-bundle/chunks/{chunk-VMY7MZEM.js.map → chunk-HQTPRV4D.js.map} +0 -0
  556. /package/dist/cli-bundle/chunks/{chunk-7L6TXOOC.js.map → chunk-JMK5GCK2.js.map} +0 -0
  557. /package/dist/cli-bundle/chunks/{chunk-KRASIL6M.js.map → chunk-K2VYLVX4.js.map} +0 -0
  558. /package/dist/cli-bundle/chunks/{chunk-4YIMPANT.js.map → chunk-KCO2EAN5.js.map} +0 -0
  559. /package/dist/cli-bundle/chunks/{chunk-D6USKAMA.js.map → chunk-KLXF7NCC.js.map} +0 -0
  560. /package/dist/cli-bundle/chunks/{chunk-OB3RJV5F.js.map → chunk-LRKMWUUV.js.map} +0 -0
  561. /package/dist/cli-bundle/chunks/{chunk-74PUWBGN.js.map → chunk-LTRAF2D7.js.map} +0 -0
  562. /package/dist/cli-bundle/chunks/{chunk-4TXTVZL3.js.map → chunk-MRD4T5LF.js.map} +0 -0
  563. /package/dist/cli-bundle/chunks/{chunk-E2Q2ULMR.js.map → chunk-N2JSWVWG.js.map} +0 -0
  564. /package/dist/cli-bundle/chunks/{chunk-7RIJGN4R.js.map → chunk-QH3FSKRJ.js.map} +0 -0
  565. /package/dist/cli-bundle/chunks/{chunk-OUQ5JEFM.js.map → chunk-S62UANU7.js.map} +0 -0
  566. /package/dist/cli-bundle/chunks/{chunk-DLDCPF5X.js.map → chunk-U2BEEM2X.js.map} +0 -0
  567. /package/dist/cli-bundle/chunks/{chunk-73PTKMAE.js.map → chunk-UT73HUPC.js.map} +0 -0
  568. /package/dist/cli-bundle/chunks/{chunk-F7G53BOA.js.map → chunk-UTSH5GWX.js.map} +0 -0
  569. /package/dist/cli-bundle/chunks/{chunk-JIP67N2K.js.map → chunk-Y4NRKBFW.js.map} +0 -0
  570. /package/dist/cli-bundle/chunks/{chunk-FBZ5XAAF.js.map → chunk-YPKFV2JR.js.map} +0 -0
  571. /package/dist/cli-bundle/chunks/{chunk-BN3CWK6G.js.map → chunk-ZNHEYCDD.js.map} +0 -0
  572. /package/dist/cli-bundle/chunks/{chunk-YEDFE4DC.js.map → chunk-ZNT7KEWE.js.map} +0 -0
  573. /package/dist/cli-bundle/chunks/{claim-HMCLSLUE.js.map → claim-SENTPZBN.js.map} +0 -0
  574. /package/dist/cli-bundle/chunks/{claim-6NINZYB3.js.map → claim-Z7MEQCBT.js.map} +0 -0
  575. /package/dist/cli-bundle/chunks/{close-OP3LK7Z2.js.map → close-424MX4CU.js.map} +0 -0
  576. /package/dist/cli-bundle/chunks/{close-37KEHLYM.js.map → close-YCWQQPDS.js.map} +0 -0
  577. /package/dist/cli-bundle/chunks/{comments-ETHABIY6.js.map → comments-4FGNTSNV.js.map} +0 -0
  578. /package/dist/cli-bundle/chunks/{comments-MU2WMBUY.js.map → comments-7YS5MY5X.js.map} +0 -0
  579. /package/dist/cli-bundle/chunks/{context-7ZEZV3BV.js.map → context-LHVKJSPJ.js.map} +0 -0
  580. /package/dist/cli-bundle/chunks/{context-XDI4DKKT.js.map → context-ZQY54JNS.js.map} +0 -0
  581. /package/dist/cli-bundle/chunks/{copy-JJ3KOQW2.js.map → copy-GYNQQPW2.js.map} +0 -0
  582. /package/dist/cli-bundle/chunks/{copy-CWM6SBY6.js.map → copy-TLW7JTQT.js.map} +0 -0
  583. /package/dist/cli-bundle/chunks/{create-J5Q2ELZT.js.map → create-VSKYSOCD.js.map} +0 -0
  584. /package/dist/cli-bundle/chunks/{create-DFMNBKBS.js.map → create-XTMAPS7I.js.map} +0 -0
  585. /package/dist/cli-bundle/chunks/{delete-2GZLQEUQ.js.map → delete-4W5JYCEG.js.map} +0 -0
  586. /package/dist/cli-bundle/chunks/{delete-OOQS4KVD.js.map → delete-ANTOTI2I.js.map} +0 -0
  587. /package/dist/cli-bundle/chunks/{deps-IF4IGL4R.js.map → deps-HPPE6MJN.js.map} +0 -0
  588. /package/dist/cli-bundle/chunks/{deps-ZVGGCRR6.js.map → deps-ZQZN54EZ.js.map} +0 -0
  589. /package/dist/cli-bundle/chunks/{docs-NFTBCQQC.js.map → docs-RPOVFMP3.js.map} +0 -0
  590. /package/dist/cli-bundle/chunks/{docs-2TIFR62T.js.map → docs-XJNYBJGE.js.map} +0 -0
  591. /package/dist/cli-bundle/chunks/{eval-2F6EH4XN.js.map → eval-DM6JBZTS.js.map} +0 -0
  592. /package/dist/cli-bundle/chunks/{eval-PFKXQR3B.js.map → eval-RFBI5FGS.js.map} +0 -0
  593. /package/dist/cli-bundle/chunks/{extension-GMVOIP4O.js.map → extension-B3YY4WY5.js.map} +0 -0
  594. /package/dist/cli-bundle/chunks/{extension-3LRYX7SW.js.map → extension-TTSEFQTS.js.map} +0 -0
  595. /package/dist/cli-bundle/chunks/{files-DF3HO6XK.js.map → files-5D65CHGE.js.map} +0 -0
  596. /package/dist/cli-bundle/chunks/{files-T5ODMETM.js.map → files-GPIG77EN.js.map} +0 -0
  597. /package/dist/cli-bundle/chunks/{focus-MY5ARIEK.js.map → focus-C3PEJV2C.js.map} +0 -0
  598. /package/dist/cli-bundle/chunks/{focus-DLXKK4AH.js.map → focus-ZHN7WIGX.js.map} +0 -0
  599. /package/dist/cli-bundle/chunks/{gc-MDGRR2SU.js.map → gc-D4JQ6OWN.js.map} +0 -0
  600. /package/dist/cli-bundle/chunks/{gc-FULIVYR4.js.map → gc-VZIXDL32.js.map} +0 -0
  601. /package/dist/cli-bundle/chunks/{history-5XUSLAJA.js.map → history-DD7L7BNL.js.map} +0 -0
  602. /package/dist/cli-bundle/chunks/{history-X4OSES6K.js.map → history-IL7XCEX2.js.map} +0 -0
  603. /package/dist/cli-bundle/chunks/{history-redact-BVHWDXPR.js.map → history-redact-IX4YEWMY.js.map} +0 -0
  604. /package/dist/cli-bundle/chunks/{history-redact-45YW65BK.js.map → history-redact-VYCWQFK7.js.map} +0 -0
  605. /package/dist/cli-bundle/chunks/{init-KO7CGIRQ.js.map → init-F27NHENZ.js.map} +0 -0
  606. /package/dist/cli-bundle/chunks/{init-TRYJELH4.js.map → init-HHVQQP6C.js.map} +0 -0
  607. /package/dist/cli-bundle/chunks/{learnings-LHZT5BHW.js.map → learnings-HJVDQIGY.js.map} +0 -0
  608. /package/dist/cli-bundle/chunks/{learnings-3F7YLI45.js.map → learnings-XSFSUUWK.js.map} +0 -0
  609. /package/dist/cli-bundle/chunks/{list-Y6AU5BJS.js.map → list-HPMEKCAA.js.map} +0 -0
  610. /package/dist/cli-bundle/chunks/{list-ROT7JF62.js.map → list-VMPWTURB.js.map} +0 -0
  611. /package/dist/cli-bundle/chunks/{notes-FW6YFLND.js.map → notes-GDZIKGR6.js.map} +0 -0
  612. /package/dist/cli-bundle/chunks/{notes-EVJZ3VAB.js.map → notes-WDDBPC4D.js.map} +0 -0
  613. /package/dist/cli-bundle/chunks/{profile-CHAW6SEA.js.map → profile-CCOKZ2IQ.js.map} +0 -0
  614. /package/dist/cli-bundle/chunks/{profile-UPZGCDOG.js.map → profile-HUCENIEQ.js.map} +0 -0
  615. /package/dist/cli-bundle/chunks/{restore-DKMCLPI5.js.map → restore-4CBWUMCX.js.map} +0 -0
  616. /package/dist/cli-bundle/chunks/{restore-IRAKSWIW.js.map → restore-5UEAGG3W.js.map} +0 -0
  617. /package/dist/cli-bundle/chunks/{scheduling-shortcuts-3F4QUEDH.js.map → scheduling-shortcuts-6VFKNKCM.js.map} +0 -0
  618. /package/dist/cli-bundle/chunks/{scheduling-shortcuts-BNZLQK36.js.map → scheduling-shortcuts-ERHCVTEM.js.map} +0 -0
  619. /package/dist/cli-bundle/chunks/{schema-OLT6LVKH.js.map → schema-TDGK6N3I.js.map} +0 -0
  620. /package/dist/cli-bundle/chunks/{schema-XJXKJQF5.js.map → schema-UE5KKAUX.js.map} +0 -0
  621. /package/dist/cli-bundle/chunks/{search-KP6H7COV.js.map → search-FP7MEU4S.js.map} +0 -0
  622. /package/dist/cli-bundle/chunks/{search-CX5UMV4H.js.map → search-K4CFLQ5S.js.map} +0 -0
  623. /package/dist/cli-bundle/chunks/{stats-QZUG6MX5.js.map → stats-NJJCALEZ.js.map} +0 -0
  624. /package/dist/cli-bundle/chunks/{stats-7XW4OEMK.js.map → stats-XT6QRKQY.js.map} +0 -0
  625. /package/dist/cli-bundle/chunks/{test-QNDXZQCW.js.map → test-UFSJ5YIO.js.map} +0 -0
  626. /package/dist/cli-bundle/chunks/{test-HU2BS7EY.js.map → test-YCDAUBWF.js.map} +0 -0
  627. /package/dist/cli-bundle/chunks/{update-UXDLTEOZ.js.map → update-MTCFES6X.js.map} +0 -0
  628. /package/dist/cli-bundle/chunks/{update-DJKWLBWJ.js.map → update-Y5WQVT5O.js.map} +0 -0
@@ -13,7 +13,7 @@
13
13
  * pure logic here stays trivially testable with a fake classifier.
14
14
  */
15
15
 
16
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="dc9b8793-1f34-54b7-a0fc-073e48f11646")}catch(e){}}();
16
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="f14cd0bc-bf31-5676-8e21-345fb9ecdd0d")}catch(e){}}();
17
17
  import { toNonEmptyStringOrUndefined } from "../shared/primitives.js";
18
18
  /** Stable rendering order for lifecycle buckets. */
19
19
  export const LIFECYCLE_BUCKET_ORDER = [
@@ -125,6 +125,22 @@ export function hasMissingMetadataFilter(filters) {
125
125
  filters.releaseMissing ||
126
126
  filters.metadataMissing);
127
127
  }
128
+ function itemMatchesSpecificMetadataFilters(item, filters, classifier) {
129
+ const checks = [
130
+ [filters.acMissing, isAcMissing(item)],
131
+ [filters.estimatesMissing, isEstimateMissing(item)],
132
+ [filters.resolutionMissing, isResolutionMissing(item, classifier)],
133
+ [filters.reviewerMissing, isReviewerMissing(item)],
134
+ [filters.riskMissing, isRiskMissing(item)],
135
+ [filters.confidenceMissing, isConfidenceMissing(item)],
136
+ [filters.sprintMissing, isSprintMissing(item)],
137
+ [filters.releaseMissing, isReleaseMissing(item)],
138
+ ];
139
+ return checks.every(([requested, matched]) => requested !== true || matched);
140
+ }
141
+ function itemMatchesCoreMetadataMissingUnion(item, classifier) {
142
+ return isAcMissing(item) || isEstimateMissing(item) || isResolutionMissing(item, classifier);
143
+ }
128
144
  /**
129
145
  * Does a single item satisfy the requested missing-metadata filters?
130
146
  *
@@ -140,36 +156,12 @@ export function itemMatchesMissingMetadata(item, filters, classifier) {
140
156
  if (!hasMissingMetadataFilter(filters)) {
141
157
  return true;
142
158
  }
143
- if (filters.acMissing && !isAcMissing(item)) {
144
- return false;
145
- }
146
- if (filters.estimatesMissing && !isEstimateMissing(item)) {
147
- return false;
148
- }
149
- if (filters.resolutionMissing && !isResolutionMissing(item, classifier)) {
150
- return false;
151
- }
152
- if (filters.reviewerMissing && !isReviewerMissing(item)) {
159
+ if (!itemMatchesSpecificMetadataFilters(item, filters, classifier)) {
153
160
  return false;
154
161
  }
155
- if (filters.riskMissing && !isRiskMissing(item)) {
162
+ if (filters.metadataMissing && !itemMatchesCoreMetadataMissingUnion(item, classifier)) {
156
163
  return false;
157
164
  }
158
- if (filters.confidenceMissing && !isConfidenceMissing(item)) {
159
- return false;
160
- }
161
- if (filters.sprintMissing && !isSprintMissing(item)) {
162
- return false;
163
- }
164
- if (filters.releaseMissing && !isReleaseMissing(item)) {
165
- return false;
166
- }
167
- if (filters.metadataMissing) {
168
- const anyMissing = isAcMissing(item) || isEstimateMissing(item) || isResolutionMissing(item, classifier);
169
- if (!anyMissing) {
170
- return false;
171
- }
172
- }
173
165
  return true;
174
166
  }
175
167
  /** Filter a list of items by the requested missing-metadata predicates. */
@@ -359,4 +351,4 @@ export function computeLifecycleDistribution(items, classifier) {
359
351
  return buckets;
360
352
  }
361
353
  //# sourceMappingURL=metadata-coverage.js.map
362
- //# debugId=dc9b8793-1f34-54b7-a0fc-073e48f11646
354
+ //# debugId=f14cd0bc-bf31-5676-8e21-345fb9ecdd0d
@@ -1 +1 @@
1
- {"version":3,"file":"metadata-coverage.js","sources":["core/governance/metadata-coverage.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Metadata governance & coverage observability primitives.\n *\n * One dependency-light module that powers the whole metadata-governance\n * surface: missing-field selection (pm list / pm update-many), coverage\n * percentages (pm stats --metadata-coverage / pm validate), and grouped\n * lifecycle breakdowns (pm stats --by-assignee/--by-tag/--by-priority,\n * pm aggregate explicit labels).\n *\n * The module is pure: it performs no IO and imports no heavy runtime\n * dependencies. Lifecycle semantics are injected via a {@link LifecycleClassifier}\n * so callers map their runtime status registry to lifecycle buckets while the\n * pure logic here stays trivially testable with a fake classifier.\n */\n\nimport { toNonEmptyStringOrUndefined } from \"../shared/primitives.js\";\n\n/** Minimal structural shape this module needs from an item's front matter. */\nexport interface CoverageItem {\n type: string;\n status: string;\n assignee?: string;\n tags?: string[];\n parent?: string;\n priority?: number;\n acceptance_criteria?: string;\n estimated_minutes?: number;\n resolution?: string;\n reviewer?: string;\n risk?: string;\n /** Confidence is a string-like enum or a numeric score depending on workspace. */\n confidence?: string | number;\n sprint?: string;\n release?: string;\n [key: string]: unknown;\n}\n\n/** Lifecycle buckets used by grouped breakdowns and distributions. */\nexport type LifecycleBucket =\n | \"open\"\n | \"in_progress\"\n | \"blocked\"\n | \"draft\"\n | \"closed\"\n | \"canceled\"\n | \"other\";\n\n/** Stable rendering order for lifecycle buckets. */\nexport const LIFECYCLE_BUCKET_ORDER: readonly LifecycleBucket[] = [\n \"open\",\n \"in_progress\",\n \"blocked\",\n \"draft\",\n \"closed\",\n \"canceled\",\n \"other\",\n] as const;\n\n/**\n * Classifies a raw status string into a lifecycle bucket and reports whether a\n * status is terminal (closed/canceled). Callers build this from their resolved\n * runtime status registry via {@link lifecycleClassifierFromStatusRegistry}.\n */\nexport interface LifecycleClassifier {\n classify(status: string): LifecycleBucket;\n isTerminal(status: string): boolean;\n}\n\n/** The subset of a resolved runtime status registry this module consumes. */\nexport interface StatusRegistryLike {\n alias_to_id: Map<string, string>;\n terminal_statuses: Set<string>;\n terminal_canceled_statuses: Set<string>;\n blocked_statuses: Set<string>;\n draft_statuses: Set<string>;\n active_statuses: Set<string>;\n open_status: string;\n}\n\nfunction normalizeStatus(status: string, registry: StatusRegistryLike): string {\n const trimmed = status.trim().toLowerCase();\n return registry.alias_to_id.get(trimmed) ?? trimmed;\n}\n\n/**\n * Adapt a resolved runtime status registry into a {@link LifecycleClassifier}.\n *\n * Precedence is deliberate and disjoint: canceled → closed → blocked → draft →\n * open → in_progress (active but not the default open status) → other.\n */\nexport function lifecycleClassifierFromStatusRegistry(registry: StatusRegistryLike): LifecycleClassifier {\n return {\n isTerminal(status: string): boolean {\n return registry.terminal_statuses.has(normalizeStatus(status, registry));\n },\n classify(status: string): LifecycleBucket {\n const id = normalizeStatus(status, registry);\n if (registry.terminal_canceled_statuses.has(id)) {\n return \"canceled\";\n }\n if (registry.terminal_statuses.has(id)) {\n return \"closed\";\n }\n if (registry.blocked_statuses.has(id)) {\n return \"blocked\";\n }\n if (registry.draft_statuses.has(id)) {\n return \"draft\";\n }\n if (id === registry.open_status) {\n return \"open\";\n }\n if (registry.active_statuses.has(id)) {\n return \"in_progress\";\n }\n return \"other\";\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Missing-metadata predicates\n// ---------------------------------------------------------------------------\n\n/** True when an item has no non-empty acceptance_criteria. */\nexport function isAcMissing(item: CoverageItem): boolean {\n return toNonEmptyStringOrUndefined(item.acceptance_criteria) === undefined;\n}\n\n/** True when an item has no finite estimated_minutes. */\nexport function isEstimateMissing(item: CoverageItem): boolean {\n return !Number.isFinite(item.estimated_minutes);\n}\n\n/**\n * True when a terminal (closed/canceled) item has no non-empty resolution.\n * Resolution is only expected on terminal items, so open items are never\n * considered \"resolution-missing\".\n */\nexport function isResolutionMissing(item: CoverageItem, classifier: LifecycleClassifier): boolean {\n if (!classifier.isTerminal(item.status)) {\n return false;\n }\n return toNonEmptyStringOrUndefined(item.resolution) === undefined;\n}\n\n/** True when an item has no non-empty reviewer. */\nexport function isReviewerMissing(item: CoverageItem): boolean {\n return toNonEmptyStringOrUndefined(item.reviewer) === undefined;\n}\n\n/** True when an item has no non-empty risk level. */\nexport function isRiskMissing(item: CoverageItem): boolean {\n return toNonEmptyStringOrUndefined(item.risk) === undefined;\n}\n\n/**\n * True when an item has no confidence value. Confidence is a string-like enum\n * or a numeric score depending on workspace, so a finite number counts as\n * present and only blank/absent values are treated as missing.\n */\nexport function isConfidenceMissing(item: CoverageItem): boolean {\n if (typeof item.confidence === \"number\") {\n return !Number.isFinite(item.confidence);\n }\n return toNonEmptyStringOrUndefined(item.confidence) === undefined;\n}\n\n/** True when an item has no non-empty sprint. */\nexport function isSprintMissing(item: CoverageItem): boolean {\n return toNonEmptyStringOrUndefined(item.sprint) === undefined;\n}\n\n/** True when an item has no non-empty release. */\nexport function isReleaseMissing(item: CoverageItem): boolean {\n return toNonEmptyStringOrUndefined(item.release) === undefined;\n}\n\n/** Selection flags for {@link filterMissingMetadata}. */\nexport interface MissingMetadataFilters {\n acMissing?: boolean;\n estimatesMissing?: boolean;\n resolutionMissing?: boolean;\n reviewerMissing?: boolean;\n riskMissing?: boolean;\n confidenceMissing?: boolean;\n sprintMissing?: boolean;\n releaseMissing?: boolean;\n /** Match items missing ANY of the tracked metadata fields (union). */\n metadataMissing?: boolean;\n}\n\n/** True when any missing-metadata filter is requested. */\nexport function hasMissingMetadataFilter(filters: MissingMetadataFilters): boolean {\n return Boolean(\n filters.acMissing ||\n filters.estimatesMissing ||\n filters.resolutionMissing ||\n filters.reviewerMissing ||\n filters.riskMissing ||\n filters.confidenceMissing ||\n filters.sprintMissing ||\n filters.releaseMissing ||\n filters.metadataMissing,\n );\n}\n\n/**\n * Does a single item satisfy the requested missing-metadata filters?\n *\n * Specific flags (acMissing/estimatesMissing/resolutionMissing plus the\n * governance flags reviewerMissing/riskMissing/confidenceMissing/sprintMissing/\n * releaseMissing) are ANDed together so callers can narrow precisely.\n * `metadataMissing` is ORed in as a union shortcut for \"missing any of the\n * core tracked fields\" (acceptance_criteria/estimated_minutes/resolution); it\n * deliberately excludes the governance fields so the long-standing flag keeps\n * its original meaning. When no filter is requested the item passes.\n */\nexport function itemMatchesMissingMetadata(\n item: CoverageItem,\n filters: MissingMetadataFilters,\n classifier: LifecycleClassifier,\n): boolean {\n if (!hasMissingMetadataFilter(filters)) {\n return true;\n }\n if (filters.acMissing && !isAcMissing(item)) {\n return false;\n }\n if (filters.estimatesMissing && !isEstimateMissing(item)) {\n return false;\n }\n if (filters.resolutionMissing && !isResolutionMissing(item, classifier)) {\n return false;\n }\n if (filters.reviewerMissing && !isReviewerMissing(item)) {\n return false;\n }\n if (filters.riskMissing && !isRiskMissing(item)) {\n return false;\n }\n if (filters.confidenceMissing && !isConfidenceMissing(item)) {\n return false;\n }\n if (filters.sprintMissing && !isSprintMissing(item)) {\n return false;\n }\n if (filters.releaseMissing && !isReleaseMissing(item)) {\n return false;\n }\n if (filters.metadataMissing) {\n const anyMissing =\n isAcMissing(item) || isEstimateMissing(item) || isResolutionMissing(item, classifier);\n if (!anyMissing) {\n return false;\n }\n }\n return true;\n}\n\n/** Filter a list of items by the requested missing-metadata predicates. */\nexport function filterMissingMetadata<T extends CoverageItem>(\n items: readonly T[],\n filters: MissingMetadataFilters,\n classifier: LifecycleClassifier,\n): T[] {\n if (!hasMissingMetadataFilter(filters)) {\n return [...items];\n }\n return items.filter((item) => itemMatchesMissingMetadata(item, filters, classifier));\n}\n\n// ---------------------------------------------------------------------------\n// Metadata coverage percentages\n// ---------------------------------------------------------------------------\n\n/** Coverage-tracked metadata fields. */\nexport type CoverageField =\n | \"acceptance_criteria\"\n | \"estimated_minutes\"\n | \"resolution\"\n | \"tags\"\n | \"parent\";\n\n/** Stable ordering of coverage fields for rendering. */\nexport const COVERAGE_FIELD_ORDER: readonly CoverageField[] = [\n \"acceptance_criteria\",\n \"estimated_minutes\",\n \"resolution\",\n \"tags\",\n \"parent\",\n] as const;\n\n/** Coverage of a single field: present vs applicable, with a rounded percent. */\nexport interface FieldCoverage {\n present: number;\n /** Items for which the field is expected (all items, except resolution = terminal only). */\n applicable: number;\n /** present/applicable * 100, rounded to one decimal; 100 when applicable is 0. */\n percent: number;\n}\n\n/**\n * Documents the metadata coverage report payload exchanged by command, SDK, and package integrations.\n */\nexport interface MetadataCoverageReport {\n overall: Record<CoverageField, FieldCoverage>;\n by_type: Record<string, Record<CoverageField, FieldCoverage>>;\n}\n\nfunction isFieldPresent(item: CoverageItem, field: CoverageField): boolean {\n switch (field) {\n case \"acceptance_criteria\":\n return !isAcMissing(item);\n case \"estimated_minutes\":\n return !isEstimateMissing(item);\n case \"resolution\":\n return toNonEmptyStringOrUndefined(item.resolution) !== undefined;\n case \"tags\":\n return Array.isArray(item.tags) && item.tags.length > 0;\n default:\n return toNonEmptyStringOrUndefined(item.parent) !== undefined;\n }\n}\n\n/** Whether a field applies to a given item (resolution only applies to terminal items). */\nfunction isFieldApplicable(item: CoverageItem, field: CoverageField, classifier: LifecycleClassifier): boolean {\n if (field === \"resolution\") {\n return classifier.isTerminal(item.status);\n }\n return true;\n}\n\nfunction roundPercent(present: number, applicable: number): number {\n if (applicable === 0) {\n return 100;\n }\n return Math.round((present / applicable) * 1000) / 10;\n}\n\nfunction emptyFieldCoverage(): Record<CoverageField, FieldCoverage> {\n const record = {} as Record<CoverageField, FieldCoverage>;\n for (const field of COVERAGE_FIELD_ORDER) {\n record[field] = { present: 0, applicable: 0, percent: 100 };\n }\n return record;\n}\n\nfunction accumulateCoverage(\n target: Record<CoverageField, FieldCoverage>,\n item: CoverageItem,\n classifier: LifecycleClassifier,\n): void {\n for (const field of COVERAGE_FIELD_ORDER) {\n if (!isFieldApplicable(item, field, classifier)) {\n continue;\n }\n const entry = target[field];\n entry.applicable += 1;\n if (isFieldPresent(item, field)) {\n entry.present += 1;\n }\n }\n}\n\nfunction finalizePercentages(record: Record<CoverageField, FieldCoverage>): void {\n for (const field of COVERAGE_FIELD_ORDER) {\n const entry = record[field];\n entry.percent = roundPercent(entry.present, entry.applicable);\n }\n}\n\n/**\n * Compute metadata coverage overall and per item type. For each tracked field\n * we report present/applicable counts and a rounded percentage. Resolution is\n * scoped to terminal items (its only applicable population).\n */\nexport function computeMetadataCoverage(\n items: readonly CoverageItem[],\n classifier: LifecycleClassifier,\n): MetadataCoverageReport {\n const overall = emptyFieldCoverage();\n const byType: Record<string, Record<CoverageField, FieldCoverage>> = {};\n for (const item of items) {\n accumulateCoverage(overall, item, classifier);\n const typeRecord = byType[item.type] ?? (byType[item.type] = emptyFieldCoverage());\n accumulateCoverage(typeRecord, item, classifier);\n }\n finalizePercentages(overall);\n for (const typeRecord of Object.values(byType)) {\n finalizePercentages(typeRecord);\n }\n return { overall, by_type: byType };\n}\n\n// ---------------------------------------------------------------------------\n// Grouped lifecycle breakdowns\n// ---------------------------------------------------------------------------\n\n/** Dimensions a breakdown can group by. */\nexport type GroupDimension = \"assignee\" | \"priority\" | \"tag\" | \"parent\" | \"type\" | \"status\";\n\n/** Explicit labels for empty/blank group keys, by dimension. */\nconst EMPTY_GROUP_LABELS: Record<GroupDimension, string> = {\n assignee: \"(unassigned)\",\n priority: \"(no priority)\",\n tag: \"(untagged)\",\n parent: \"(unparented)\",\n type: \"(untyped)\",\n status: \"(no status)\",\n};\n\n/** Explicit label for an empty/blank group value for a given dimension. */\nexport function emptyGroupLabel(dimension: GroupDimension): string {\n return EMPTY_GROUP_LABELS[dimension];\n}\n\n/**\n * Documents the group row payload exchanged by command, SDK, and package integrations.\n */\nexport interface GroupRow {\n /** Display label; explicit \"(unassigned)\"-style label for blank keys. */\n label: string;\n /** Stable structured key (null for the empty/blank group). */\n key: string | null;\n buckets: Record<LifecycleBucket, number>;\n total: number;\n}\n\n/**\n * Documents the grouped breakdown payload exchanged by command, SDK, and package integrations.\n */\nexport interface GroupedBreakdown {\n dimension: GroupDimension;\n rows: GroupRow[];\n /** Distinct items observed (an item can contribute to multiple tag rows). */\n total_items: number;\n}\n\n/**\n * Documents the group options payload exchanged by command, SDK, and package integrations.\n */\nexport interface GroupOptions {\n /** For dimension=\"tag\": only consider tags starting with this prefix. */\n tagPrefix?: string;\n}\n\nfunction emptyBuckets(): Record<LifecycleBucket, number> {\n return {\n open: 0,\n in_progress: 0,\n blocked: 0,\n draft: 0,\n closed: 0,\n canceled: 0,\n other: 0,\n };\n}\n\n/**\n * Resolve the group keys an item belongs to for a dimension. Most dimensions\n * yield exactly one key (possibly null for blank); tag yields one key per\n * matching tag (or [null] when none match), so an item can span multiple rows.\n */\nfunction groupKeysForItem(item: CoverageItem, dimension: GroupDimension, options: GroupOptions): (string | null)[] {\n switch (dimension) {\n case \"assignee\":\n return [toNonEmptyStringOrUndefined(item.assignee) ?? null];\n case \"parent\":\n return [toNonEmptyStringOrUndefined(item.parent) ?? null];\n case \"type\":\n return [toNonEmptyStringOrUndefined(item.type) ?? null];\n case \"status\":\n return [toNonEmptyStringOrUndefined(item.status) ?? null];\n case \"priority\":\n return [typeof item.priority === \"number\" ? `P${item.priority}` : null];\n default: {\n const prefix = options.tagPrefix?.trim();\n const tags = Array.isArray(item.tags) ? item.tags : [];\n const matching = tags.filter(\n (tag) => typeof tag === \"string\" && tag.length > 0 && (!prefix || tag.startsWith(prefix)),\n );\n return matching.length > 0 ? matching : [null];\n }\n }\n}\n\n/**\n * Group items by a dimension into lifecycle-bucketed rows. Blank keys render\n * with an explicit \"(unassigned)\"-style label. Rows are sorted by total\n * descending, then label ascending, with the empty group sorted last on ties.\n */\nexport function groupItemsByDimension(\n items: readonly CoverageItem[],\n dimension: GroupDimension,\n classifier: LifecycleClassifier,\n options: GroupOptions = {},\n): GroupedBreakdown {\n const rows = new Map<string, GroupRow>();\n let totalItems = 0;\n for (const item of items) {\n totalItems += 1;\n const bucket = classifier.classify(item.status);\n for (const key of groupKeysForItem(item, dimension, options)) {\n const mapKey = key ?? \"\u0000empty\";\n let row = rows.get(mapKey);\n if (!row) {\n row = {\n label: key ?? emptyGroupLabel(dimension),\n key,\n buckets: emptyBuckets(),\n total: 0,\n };\n rows.set(mapKey, row);\n }\n row.buckets[bucket] += 1;\n row.total += 1;\n }\n }\n const sorted = [...rows.values()].sort((left, right) => {\n if (right.total !== left.total) {\n return right.total - left.total;\n }\n // All blank-key items collapse into a single row per dimension, so at most\n // one row has key === null; it sorts last on ties.\n if (left.key === null) {\n return 1;\n }\n if (right.key === null) {\n return -1;\n }\n return left.label.localeCompare(right.label);\n });\n return { dimension, rows: sorted, total_items: totalItems };\n}\n\n/** Lifecycle-bucket distribution across all items (for stats lifecycle section). */\nexport function computeLifecycleDistribution(\n items: readonly CoverageItem[],\n classifier: LifecycleClassifier,\n): Record<LifecycleBucket, number> {\n const buckets = emptyBuckets();\n for (const item of items) {\n buckets[classifier.classify(item.status)] += 1;\n }\n return buckets;\n}\n"],"names":[],"mappings":"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","debugId":"dc9b8793-1f34-54b7-a0fc-073e48f11646"}
1
+ {"version":3,"file":"metadata-coverage.js","sources":["core/governance/metadata-coverage.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Metadata governance & coverage observability primitives.\n *\n * One dependency-light module that powers the whole metadata-governance\n * surface: missing-field selection (pm list / pm update-many), coverage\n * percentages (pm stats --metadata-coverage / pm validate), and grouped\n * lifecycle breakdowns (pm stats --by-assignee/--by-tag/--by-priority,\n * pm aggregate explicit labels).\n *\n * The module is pure: it performs no IO and imports no heavy runtime\n * dependencies. Lifecycle semantics are injected via a {@link LifecycleClassifier}\n * so callers map their runtime status registry to lifecycle buckets while the\n * pure logic here stays trivially testable with a fake classifier.\n */\n\nimport { toNonEmptyStringOrUndefined } from \"../shared/primitives.js\";\n\n/** Minimal structural shape this module needs from an item's front matter. */\nexport interface CoverageItem {\n type: string;\n status: string;\n assignee?: string;\n tags?: string[];\n parent?: string;\n priority?: number;\n acceptance_criteria?: string;\n estimated_minutes?: number;\n resolution?: string;\n reviewer?: string;\n risk?: string;\n /** Confidence is a string-like enum or a numeric score depending on workspace. */\n confidence?: string | number;\n sprint?: string;\n release?: string;\n [key: string]: unknown;\n}\n\n/** Lifecycle buckets used by grouped breakdowns and distributions. */\nexport type LifecycleBucket =\n | \"open\"\n | \"in_progress\"\n | \"blocked\"\n | \"draft\"\n | \"closed\"\n | \"canceled\"\n | \"other\";\n\n/** Stable rendering order for lifecycle buckets. */\nexport const LIFECYCLE_BUCKET_ORDER: readonly LifecycleBucket[] = [\n \"open\",\n \"in_progress\",\n \"blocked\",\n \"draft\",\n \"closed\",\n \"canceled\",\n \"other\",\n] as const;\n\n/**\n * Classifies a raw status string into a lifecycle bucket and reports whether a\n * status is terminal (closed/canceled). Callers build this from their resolved\n * runtime status registry via {@link lifecycleClassifierFromStatusRegistry}.\n */\nexport interface LifecycleClassifier {\n classify(status: string): LifecycleBucket;\n isTerminal(status: string): boolean;\n}\n\n/** The subset of a resolved runtime status registry this module consumes. */\nexport interface StatusRegistryLike {\n alias_to_id: Map<string, string>;\n terminal_statuses: Set<string>;\n terminal_canceled_statuses: Set<string>;\n blocked_statuses: Set<string>;\n draft_statuses: Set<string>;\n active_statuses: Set<string>;\n open_status: string;\n}\n\nfunction normalizeStatus(status: string, registry: StatusRegistryLike): string {\n const trimmed = status.trim().toLowerCase();\n return registry.alias_to_id.get(trimmed) ?? trimmed;\n}\n\n/**\n * Adapt a resolved runtime status registry into a {@link LifecycleClassifier}.\n *\n * Precedence is deliberate and disjoint: canceled → closed → blocked → draft →\n * open → in_progress (active but not the default open status) → other.\n */\nexport function lifecycleClassifierFromStatusRegistry(registry: StatusRegistryLike): LifecycleClassifier {\n return {\n isTerminal(status: string): boolean {\n return registry.terminal_statuses.has(normalizeStatus(status, registry));\n },\n classify(status: string): LifecycleBucket {\n const id = normalizeStatus(status, registry);\n if (registry.terminal_canceled_statuses.has(id)) {\n return \"canceled\";\n }\n if (registry.terminal_statuses.has(id)) {\n return \"closed\";\n }\n if (registry.blocked_statuses.has(id)) {\n return \"blocked\";\n }\n if (registry.draft_statuses.has(id)) {\n return \"draft\";\n }\n if (id === registry.open_status) {\n return \"open\";\n }\n if (registry.active_statuses.has(id)) {\n return \"in_progress\";\n }\n return \"other\";\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Missing-metadata predicates\n// ---------------------------------------------------------------------------\n\n/** True when an item has no non-empty acceptance_criteria. */\nexport function isAcMissing(item: CoverageItem): boolean {\n return toNonEmptyStringOrUndefined(item.acceptance_criteria) === undefined;\n}\n\n/** True when an item has no finite estimated_minutes. */\nexport function isEstimateMissing(item: CoverageItem): boolean {\n return !Number.isFinite(item.estimated_minutes);\n}\n\n/**\n * True when a terminal (closed/canceled) item has no non-empty resolution.\n * Resolution is only expected on terminal items, so open items are never\n * considered \"resolution-missing\".\n */\nexport function isResolutionMissing(item: CoverageItem, classifier: LifecycleClassifier): boolean {\n if (!classifier.isTerminal(item.status)) {\n return false;\n }\n return toNonEmptyStringOrUndefined(item.resolution) === undefined;\n}\n\n/** True when an item has no non-empty reviewer. */\nexport function isReviewerMissing(item: CoverageItem): boolean {\n return toNonEmptyStringOrUndefined(item.reviewer) === undefined;\n}\n\n/** True when an item has no non-empty risk level. */\nexport function isRiskMissing(item: CoverageItem): boolean {\n return toNonEmptyStringOrUndefined(item.risk) === undefined;\n}\n\n/**\n * True when an item has no confidence value. Confidence is a string-like enum\n * or a numeric score depending on workspace, so a finite number counts as\n * present and only blank/absent values are treated as missing.\n */\nexport function isConfidenceMissing(item: CoverageItem): boolean {\n if (typeof item.confidence === \"number\") {\n return !Number.isFinite(item.confidence);\n }\n return toNonEmptyStringOrUndefined(item.confidence) === undefined;\n}\n\n/** True when an item has no non-empty sprint. */\nexport function isSprintMissing(item: CoverageItem): boolean {\n return toNonEmptyStringOrUndefined(item.sprint) === undefined;\n}\n\n/** True when an item has no non-empty release. */\nexport function isReleaseMissing(item: CoverageItem): boolean {\n return toNonEmptyStringOrUndefined(item.release) === undefined;\n}\n\n/** Selection flags for {@link filterMissingMetadata}. */\nexport interface MissingMetadataFilters {\n acMissing?: boolean;\n estimatesMissing?: boolean;\n resolutionMissing?: boolean;\n reviewerMissing?: boolean;\n riskMissing?: boolean;\n confidenceMissing?: boolean;\n sprintMissing?: boolean;\n releaseMissing?: boolean;\n /** Match items missing ANY of the tracked metadata fields (union). */\n metadataMissing?: boolean;\n}\n\n/** True when any missing-metadata filter is requested. */\nexport function hasMissingMetadataFilter(filters: MissingMetadataFilters): boolean {\n return Boolean(\n filters.acMissing ||\n filters.estimatesMissing ||\n filters.resolutionMissing ||\n filters.reviewerMissing ||\n filters.riskMissing ||\n filters.confidenceMissing ||\n filters.sprintMissing ||\n filters.releaseMissing ||\n filters.metadataMissing,\n );\n}\n\nfunction itemMatchesSpecificMetadataFilters(\n item: CoverageItem,\n filters: MissingMetadataFilters,\n classifier: LifecycleClassifier,\n): boolean {\n const checks: Array<[boolean | undefined, boolean]> = [\n [filters.acMissing, isAcMissing(item)],\n [filters.estimatesMissing, isEstimateMissing(item)],\n [filters.resolutionMissing, isResolutionMissing(item, classifier)],\n [filters.reviewerMissing, isReviewerMissing(item)],\n [filters.riskMissing, isRiskMissing(item)],\n [filters.confidenceMissing, isConfidenceMissing(item)],\n [filters.sprintMissing, isSprintMissing(item)],\n [filters.releaseMissing, isReleaseMissing(item)],\n ];\n return checks.every(([requested, matched]) => requested !== true || matched);\n}\n\nfunction itemMatchesCoreMetadataMissingUnion(item: CoverageItem, classifier: LifecycleClassifier): boolean {\n return isAcMissing(item) || isEstimateMissing(item) || isResolutionMissing(item, classifier);\n}\n\n/**\n * Does a single item satisfy the requested missing-metadata filters?\n *\n * Specific flags (acMissing/estimatesMissing/resolutionMissing plus the\n * governance flags reviewerMissing/riskMissing/confidenceMissing/sprintMissing/\n * releaseMissing) are ANDed together so callers can narrow precisely.\n * `metadataMissing` is ORed in as a union shortcut for \"missing any of the\n * core tracked fields\" (acceptance_criteria/estimated_minutes/resolution); it\n * deliberately excludes the governance fields so the long-standing flag keeps\n * its original meaning. When no filter is requested the item passes.\n */\nexport function itemMatchesMissingMetadata(\n item: CoverageItem,\n filters: MissingMetadataFilters,\n classifier: LifecycleClassifier,\n): boolean {\n if (!hasMissingMetadataFilter(filters)) {\n return true;\n }\n if (!itemMatchesSpecificMetadataFilters(item, filters, classifier)) {\n return false;\n }\n if (filters.metadataMissing && !itemMatchesCoreMetadataMissingUnion(item, classifier)) {\n return false;\n }\n return true;\n}\n\n/** Filter a list of items by the requested missing-metadata predicates. */\nexport function filterMissingMetadata<T extends CoverageItem>(\n items: readonly T[],\n filters: MissingMetadataFilters,\n classifier: LifecycleClassifier,\n): T[] {\n if (!hasMissingMetadataFilter(filters)) {\n return [...items];\n }\n return items.filter((item) => itemMatchesMissingMetadata(item, filters, classifier));\n}\n\n// ---------------------------------------------------------------------------\n// Metadata coverage percentages\n// ---------------------------------------------------------------------------\n\n/** Coverage-tracked metadata fields. */\nexport type CoverageField =\n | \"acceptance_criteria\"\n | \"estimated_minutes\"\n | \"resolution\"\n | \"tags\"\n | \"parent\";\n\n/** Stable ordering of coverage fields for rendering. */\nexport const COVERAGE_FIELD_ORDER: readonly CoverageField[] = [\n \"acceptance_criteria\",\n \"estimated_minutes\",\n \"resolution\",\n \"tags\",\n \"parent\",\n] as const;\n\n/** Coverage of a single field: present vs applicable, with a rounded percent. */\nexport interface FieldCoverage {\n present: number;\n /** Items for which the field is expected (all items, except resolution = terminal only). */\n applicable: number;\n /** present/applicable * 100, rounded to one decimal; 100 when applicable is 0. */\n percent: number;\n}\n\n/**\n * Documents the metadata coverage report payload exchanged by command, SDK, and package integrations.\n */\nexport interface MetadataCoverageReport {\n overall: Record<CoverageField, FieldCoverage>;\n by_type: Record<string, Record<CoverageField, FieldCoverage>>;\n}\n\nfunction isFieldPresent(item: CoverageItem, field: CoverageField): boolean {\n switch (field) {\n case \"acceptance_criteria\":\n return !isAcMissing(item);\n case \"estimated_minutes\":\n return !isEstimateMissing(item);\n case \"resolution\":\n return toNonEmptyStringOrUndefined(item.resolution) !== undefined;\n case \"tags\":\n return Array.isArray(item.tags) && item.tags.length > 0;\n default:\n return toNonEmptyStringOrUndefined(item.parent) !== undefined;\n }\n}\n\n/** Whether a field applies to a given item (resolution only applies to terminal items). */\nfunction isFieldApplicable(item: CoverageItem, field: CoverageField, classifier: LifecycleClassifier): boolean {\n if (field === \"resolution\") {\n return classifier.isTerminal(item.status);\n }\n return true;\n}\n\nfunction roundPercent(present: number, applicable: number): number {\n if (applicable === 0) {\n return 100;\n }\n return Math.round((present / applicable) * 1000) / 10;\n}\n\nfunction emptyFieldCoverage(): Record<CoverageField, FieldCoverage> {\n const record = {} as Record<CoverageField, FieldCoverage>;\n for (const field of COVERAGE_FIELD_ORDER) {\n record[field] = { present: 0, applicable: 0, percent: 100 };\n }\n return record;\n}\n\nfunction accumulateCoverage(\n target: Record<CoverageField, FieldCoverage>,\n item: CoverageItem,\n classifier: LifecycleClassifier,\n): void {\n for (const field of COVERAGE_FIELD_ORDER) {\n if (!isFieldApplicable(item, field, classifier)) {\n continue;\n }\n const entry = target[field];\n entry.applicable += 1;\n if (isFieldPresent(item, field)) {\n entry.present += 1;\n }\n }\n}\n\nfunction finalizePercentages(record: Record<CoverageField, FieldCoverage>): void {\n for (const field of COVERAGE_FIELD_ORDER) {\n const entry = record[field];\n entry.percent = roundPercent(entry.present, entry.applicable);\n }\n}\n\n/**\n * Compute metadata coverage overall and per item type. For each tracked field\n * we report present/applicable counts and a rounded percentage. Resolution is\n * scoped to terminal items (its only applicable population).\n */\nexport function computeMetadataCoverage(\n items: readonly CoverageItem[],\n classifier: LifecycleClassifier,\n): MetadataCoverageReport {\n const overall = emptyFieldCoverage();\n const byType: Record<string, Record<CoverageField, FieldCoverage>> = {};\n for (const item of items) {\n accumulateCoverage(overall, item, classifier);\n const typeRecord = byType[item.type] ?? (byType[item.type] = emptyFieldCoverage());\n accumulateCoverage(typeRecord, item, classifier);\n }\n finalizePercentages(overall);\n for (const typeRecord of Object.values(byType)) {\n finalizePercentages(typeRecord);\n }\n return { overall, by_type: byType };\n}\n\n// ---------------------------------------------------------------------------\n// Grouped lifecycle breakdowns\n// ---------------------------------------------------------------------------\n\n/** Dimensions a breakdown can group by. */\nexport type GroupDimension = \"assignee\" | \"priority\" | \"tag\" | \"parent\" | \"type\" | \"status\";\n\n/** Explicit labels for empty/blank group keys, by dimension. */\nconst EMPTY_GROUP_LABELS: Record<GroupDimension, string> = {\n assignee: \"(unassigned)\",\n priority: \"(no priority)\",\n tag: \"(untagged)\",\n parent: \"(unparented)\",\n type: \"(untyped)\",\n status: \"(no status)\",\n};\n\n/** Explicit label for an empty/blank group value for a given dimension. */\nexport function emptyGroupLabel(dimension: GroupDimension): string {\n return EMPTY_GROUP_LABELS[dimension];\n}\n\n/**\n * Documents the group row payload exchanged by command, SDK, and package integrations.\n */\nexport interface GroupRow {\n /** Display label; explicit \"(unassigned)\"-style label for blank keys. */\n label: string;\n /** Stable structured key (null for the empty/blank group). */\n key: string | null;\n buckets: Record<LifecycleBucket, number>;\n total: number;\n}\n\n/**\n * Documents the grouped breakdown payload exchanged by command, SDK, and package integrations.\n */\nexport interface GroupedBreakdown {\n dimension: GroupDimension;\n rows: GroupRow[];\n /** Distinct items observed (an item can contribute to multiple tag rows). */\n total_items: number;\n}\n\n/**\n * Documents the group options payload exchanged by command, SDK, and package integrations.\n */\nexport interface GroupOptions {\n /** For dimension=\"tag\": only consider tags starting with this prefix. */\n tagPrefix?: string;\n}\n\nfunction emptyBuckets(): Record<LifecycleBucket, number> {\n return {\n open: 0,\n in_progress: 0,\n blocked: 0,\n draft: 0,\n closed: 0,\n canceled: 0,\n other: 0,\n };\n}\n\n/**\n * Resolve the group keys an item belongs to for a dimension. Most dimensions\n * yield exactly one key (possibly null for blank); tag yields one key per\n * matching tag (or [null] when none match), so an item can span multiple rows.\n */\nfunction groupKeysForItem(item: CoverageItem, dimension: GroupDimension, options: GroupOptions): (string | null)[] {\n switch (dimension) {\n case \"assignee\":\n return [toNonEmptyStringOrUndefined(item.assignee) ?? null];\n case \"parent\":\n return [toNonEmptyStringOrUndefined(item.parent) ?? null];\n case \"type\":\n return [toNonEmptyStringOrUndefined(item.type) ?? null];\n case \"status\":\n return [toNonEmptyStringOrUndefined(item.status) ?? null];\n case \"priority\":\n return [typeof item.priority === \"number\" ? `P${item.priority}` : null];\n default: {\n const prefix = options.tagPrefix?.trim();\n const tags = Array.isArray(item.tags) ? item.tags : [];\n const matching = tags.filter(\n (tag) => typeof tag === \"string\" && tag.length > 0 && (!prefix || tag.startsWith(prefix)),\n );\n return matching.length > 0 ? matching : [null];\n }\n }\n}\n\n/**\n * Group items by a dimension into lifecycle-bucketed rows. Blank keys render\n * with an explicit \"(unassigned)\"-style label. Rows are sorted by total\n * descending, then label ascending, with the empty group sorted last on ties.\n */\nexport function groupItemsByDimension(\n items: readonly CoverageItem[],\n dimension: GroupDimension,\n classifier: LifecycleClassifier,\n options: GroupOptions = {},\n): GroupedBreakdown {\n const rows = new Map<string, GroupRow>();\n let totalItems = 0;\n for (const item of items) {\n totalItems += 1;\n const bucket = classifier.classify(item.status);\n for (const key of groupKeysForItem(item, dimension, options)) {\n const mapKey = key ?? \"\u0000empty\";\n let row = rows.get(mapKey);\n if (!row) {\n row = {\n label: key ?? emptyGroupLabel(dimension),\n key,\n buckets: emptyBuckets(),\n total: 0,\n };\n rows.set(mapKey, row);\n }\n row.buckets[bucket] += 1;\n row.total += 1;\n }\n }\n const sorted = [...rows.values()].sort((left, right) => {\n if (right.total !== left.total) {\n return right.total - left.total;\n }\n // All blank-key items collapse into a single row per dimension, so at most\n // one row has key === null; it sorts last on ties.\n if (left.key === null) {\n return 1;\n }\n if (right.key === null) {\n return -1;\n }\n return left.label.localeCompare(right.label);\n });\n return { dimension, rows: sorted, total_items: totalItems };\n}\n\n/** Lifecycle-bucket distribution across all items (for stats lifecycle section). */\nexport function computeLifecycleDistribution(\n items: readonly CoverageItem[],\n classifier: LifecycleClassifier,\n): Record<LifecycleBucket, number> {\n const buckets = emptyBuckets();\n for (const item of items) {\n buckets[classifier.classify(item.status)] += 1;\n }\n return buckets;\n}\n"],"names":[],"mappings":"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","debugId":"f14cd0bc-bf31-5676-8e21-345fb9ecdd0d"}
@@ -4,7 +4,7 @@
4
4
  * Implements append-only history and replay behavior for Drift Scan.
5
5
  */
6
6
 
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a928aad0-855f-5c7f-aa00-77d698ddca80")}catch(e){}}();
7
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="91c6995a-7219-5402-b2d4-e50227bf0149")}catch(e){}}();
8
8
  import fs from "fs/promises";
9
9
  import { createHash } from "node:crypto";
10
10
  import path from "node:path";
@@ -75,6 +75,62 @@ async function verifyHistoryStream(historyPath) {
75
75
  contentHash,
76
76
  };
77
77
  }
78
+ function cacheMetadataMatches(cached, stat) {
79
+ return cached !== undefined && cached.mtime_ms === stat.mtimeMs && cached.ctime_ms === stat.ctimeMs && cached.size === stat.size;
80
+ }
81
+ async function loadFreshStreamVerification(itemId, historyPath, accumulator) {
82
+ try {
83
+ const loaded = await verifyHistoryStream(historyPath);
84
+ if (!loaded) {
85
+ accumulator.missingStreams.push(itemId);
86
+ return null;
87
+ }
88
+ return loaded;
89
+ }
90
+ catch {
91
+ accumulator.unreadableStreams.push(itemId);
92
+ return null;
93
+ }
94
+ }
95
+ async function resolveStreamVerification(params) {
96
+ const cachedContentHash = typeof params.cached?.content_hash === "string" && params.cached.content_hash.length > 0
97
+ ? params.cached.content_hash
98
+ : undefined;
99
+ const canUseCache = cacheMetadataMatches(params.cached, params.stat) && cachedContentHash !== undefined && params.cached !== undefined;
100
+ if (!canUseCache || !params.cached) {
101
+ return {
102
+ verification: await loadFreshStreamVerification(params.itemId, params.historyPath, params.accumulator),
103
+ cacheDirty: true,
104
+ };
105
+ }
106
+ let currentContentHash;
107
+ if (params.verifyCacheHitByContent) {
108
+ try {
109
+ currentContentHash = await readHistoryContentHash(params.historyPath);
110
+ }
111
+ catch {
112
+ params.accumulator.unreadableStreams.push(params.itemId);
113
+ return { verification: null, cacheDirty: false };
114
+ }
115
+ }
116
+ else {
117
+ currentContentHash = cachedContentHash;
118
+ }
119
+ if (!params.verifyCacheHitByContent || currentContentHash === cachedContentHash) {
120
+ return {
121
+ verification: {
122
+ latestAfterHash: params.cached.latest_after_hash,
123
+ chainOk: params.cached.chain_ok,
124
+ contentHash: currentContentHash,
125
+ },
126
+ cacheDirty: false,
127
+ };
128
+ }
129
+ return {
130
+ verification: await loadFreshStreamVerification(params.itemId, params.historyPath, params.accumulator),
131
+ cacheDirty: true,
132
+ };
133
+ }
78
134
  /**
79
135
  * Scan every item's history stream for drift (missing/unreadable streams, broken
80
136
  * hash chains, and item/history hash mismatches).
@@ -86,10 +142,12 @@ async function verifyHistoryStream(historyPath) {
86
142
  * trusting the stat tuple and skip rereading unchanged streams.
87
143
  */
88
144
  export async function scanHistoryDrift(pmRoot, items, options = {}) {
89
- const missingStreams = [];
90
- const unreadableStreams = [];
91
- const hashMismatches = [];
92
- const chainMismatches = [];
145
+ const accumulator = {
146
+ missingStreams: [],
147
+ unreadableStreams: [],
148
+ hashMismatches: [],
149
+ chainMismatches: [],
150
+ };
93
151
  const cache = await loadDriftCache(pmRoot);
94
152
  const previousEntries = cache?.entries ?? {};
95
153
  const nextEntries = {};
@@ -105,97 +163,44 @@ export async function scanHistoryDrift(pmRoot, items, options = {}) {
105
163
  }
106
164
  catch (error) {
107
165
  if (isErrno(error, "ENOENT")) {
108
- missingStreams.push(item.id);
166
+ accumulator.missingStreams.push(item.id);
109
167
  }
110
168
  else {
111
- unreadableStreams.push(item.id);
169
+ accumulator.unreadableStreams.push(item.id);
112
170
  }
113
171
  continue;
114
172
  }
115
- const loadStreamVerification = async () => {
116
- try {
117
- return await verifyHistoryStream(historyPath);
118
- }
119
- catch {
120
- return "unreadable";
121
- }
122
- };
123
- const loadFreshVerification = async () => {
124
- const loaded = await loadStreamVerification();
125
- if (loaded === "unreadable") {
126
- unreadableStreams.push(item.id);
127
- return null;
128
- }
129
- if (!loaded) {
130
- missingStreams.push(item.id);
131
- return null;
132
- }
133
- return loaded;
134
- };
135
173
  const cached = previousEntries[item.id];
136
- let verification;
137
- const metadataMatchesCache = cached !== undefined &&
138
- cached.mtime_ms === stat.mtimeMs &&
139
- cached.ctime_ms === stat.ctimeMs &&
140
- cached.size === stat.size;
141
- const cachedContentHash = typeof cached?.content_hash === "string" && cached.content_hash.length > 0 ? cached.content_hash : undefined;
142
- const canUseCache = metadataMatchesCache && cachedContentHash !== undefined;
143
- if (canUseCache && cached) {
144
- let currentContentHash;
145
- if (verifyCacheHitByContent) {
146
- try {
147
- currentContentHash = await readHistoryContentHash(historyPath);
148
- }
149
- catch {
150
- unreadableStreams.push(item.id);
151
- continue;
152
- }
153
- }
154
- else {
155
- currentContentHash = cachedContentHash;
156
- }
157
- if (!verifyCacheHitByContent || currentContentHash === cachedContentHash) {
158
- verification = {
159
- latestAfterHash: cached.latest_after_hash,
160
- chainOk: cached.chain_ok,
161
- contentHash: currentContentHash,
162
- };
163
- }
164
- else {
165
- cacheDirty = true;
166
- const refreshed = await loadFreshVerification();
167
- if (!refreshed) {
168
- continue;
169
- }
170
- verification = refreshed;
171
- }
172
- }
173
- else {
174
- cacheDirty = true;
175
- const refreshed = await loadFreshVerification();
176
- if (!refreshed) {
177
- continue;
178
- }
179
- verification = refreshed;
174
+ const resolved = await resolveStreamVerification({
175
+ itemId: item.id,
176
+ historyPath,
177
+ stat,
178
+ cached,
179
+ verifyCacheHitByContent,
180
+ accumulator,
181
+ });
182
+ cacheDirty ||= resolved.cacheDirty;
183
+ if (!resolved.verification) {
184
+ continue;
180
185
  }
181
- if (!verification.chainOk) {
182
- chainMismatches.push(item.id);
186
+ if (!resolved.verification.chainOk) {
187
+ accumulator.chainMismatches.push(item.id);
183
188
  }
184
189
  nextEntries[item.id] = {
185
190
  mtime_ms: stat.mtimeMs,
186
191
  ctime_ms: stat.ctimeMs,
187
192
  size: stat.size,
188
- content_hash: verification.contentHash,
189
- latest_after_hash: verification.latestAfterHash,
190
- chain_ok: verification.chainOk,
193
+ content_hash: resolved.verification.contentHash,
194
+ latest_after_hash: resolved.verification.latestAfterHash,
195
+ chain_ok: resolved.verification.chainOk,
191
196
  };
192
197
  const { body, ...frontMatter } = item;
193
198
  const currentHash = hashDocument({
194
199
  metadata: frontMatter,
195
200
  body,
196
201
  });
197
- if (currentHash !== verification.latestAfterHash) {
198
- hashMismatches.push(item.id);
202
+ if (currentHash !== resolved.verification.latestAfterHash) {
203
+ accumulator.hashMismatches.push(item.id);
199
204
  }
200
205
  }
201
206
  if (cacheDirty || Object.keys(previousEntries).length !== Object.keys(nextEntries).length) {
@@ -208,8 +213,15 @@ export async function scanHistoryDrift(pmRoot, items, options = {}) {
208
213
  // Best-effort cache write: a failed persist must never fail a health scan.
209
214
  }
210
215
  }
211
- const driftedItems = [...new Set([...missingStreams, ...unreadableStreams, ...hashMismatches, ...chainMismatches])].sort((a, b) => a.localeCompare(b));
212
- return { missingStreams, unreadableStreams, hashMismatches, chainMismatches, driftedItems };
216
+ const driftedItems = [
217
+ ...new Set([
218
+ ...accumulator.missingStreams,
219
+ ...accumulator.unreadableStreams,
220
+ ...accumulator.hashMismatches,
221
+ ...accumulator.chainMismatches,
222
+ ]),
223
+ ].sort((a, b) => a.localeCompare(b));
224
+ return { ...accumulator, driftedItems };
213
225
  }
214
226
  //# sourceMappingURL=drift-scan.js.map
215
- //# debugId=a928aad0-855f-5c7f-aa00-77d698ddca80
227
+ //# debugId=91c6995a-7219-5402-b2d4-e50227bf0149
@@ -1 +1 @@
1
- {"version":3,"file":"drift-scan.js","sources":["core/history/drift-scan.ts"],"sourceRoot":"/","sourcesContent":["/**\n * @module core/history/drift-scan\n *\n * Implements append-only history and replay behavior for Drift Scan.\n */\nimport fs from \"fs/promises\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport { getHistoryPath } from \"../store/paths.js\";\nimport { writeFileAtomic } from \"../fs/fs-utils.js\";\nimport { hashDocument } from \"./history.js\";\nimport { verifyHistoryChain } from \"./replay.js\";\nimport type { HistoryEntry, ItemMetadata } from \"../../types/index.js\";\n\n/**\n * Documents the drift scan result payload exchanged by command, SDK, and package integrations.\n */\nexport interface DriftScanResult {\n missingStreams: string[];\n unreadableStreams: string[];\n hashMismatches: string[];\n chainMismatches: string[];\n driftedItems: string[];\n}\n\nconst DRIFT_CACHE_VERSION = 3;\nconst DRIFT_CACHE_FILENAME = \"history-drift-cache.json\";\n\n/**\n * Controls how cached history stream verification is trusted when the file stat\n * tuple still matches a previous scan.\n */\nexport type DriftCacheHitVerification = \"content_hash\" | \"metadata\";\n\n/**\n * Documents the history drift scan options shared by health, validate, and\n * repair callers.\n */\nexport interface DriftScanOptions {\n cacheHitVerification?: DriftCacheHitVerification;\n}\n\ninterface DriftCacheEntry {\n mtime_ms: number;\n ctime_ms: number;\n size: number;\n content_hash: string;\n latest_after_hash: string;\n chain_ok: boolean;\n}\n\ninterface DriftCacheEnvelope {\n version: number;\n entries: Record<string, DriftCacheEntry>;\n}\n\nfunction getDriftCachePath(pmRoot: string): string {\n return path.join(pmRoot, \"runtime\", DRIFT_CACHE_FILENAME);\n}\n\nasync function loadDriftCache(pmRoot: string): Promise<DriftCacheEnvelope | null> {\n try {\n const raw = await fs.readFile(getDriftCachePath(pmRoot), \"utf8\");\n const parsed = JSON.parse(raw) as DriftCacheEnvelope;\n if (parsed.version !== DRIFT_CACHE_VERSION || typeof parsed.entries !== \"object\" || parsed.entries === null) {\n return null;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\nfunction isErrno(error: unknown, code: string): boolean {\n return typeof error === \"object\" && error !== null && \"code\" in error && (error as { code?: string }).code === code;\n}\n\ninterface StreamVerification {\n latestAfterHash: string;\n chainOk: boolean;\n contentHash: string;\n}\n\nfunction hashContent(raw: string): string {\n return createHash(\"sha256\").update(raw).digest(\"hex\");\n}\n\nasync function readHistoryContentHash(historyPath: string): Promise<string> {\n const raw = await fs.readFile(historyPath, \"utf8\");\n return hashContent(raw);\n}\n\n/**\n * Read and fully verify one history stream's hash chain. Returns null for an\n * empty/missing stream (caller records it as a missing stream).\n */\nasync function verifyHistoryStream(historyPath: string): Promise<StreamVerification | null> {\n const raw = await fs.readFile(historyPath, \"utf8\");\n const contentHash = hashContent(raw);\n if (raw.trim().length === 0) {\n return null;\n }\n const entries: HistoryEntry[] = [];\n let latestAfterHash: string | null = null;\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (trimmed.length === 0) {\n continue;\n }\n const parsed = JSON.parse(trimmed) as HistoryEntry;\n if (typeof parsed.after_hash !== \"string\" || parsed.after_hash.trim().length === 0) {\n throw new Error(\"missing after_hash\");\n }\n entries.push(parsed);\n latestAfterHash = parsed.after_hash;\n }\n /* c8 ignore start -- defensive guard for future history schema changes. */\n if (!latestAfterHash) {\n return null;\n }\n /* c8 ignore stop */\n return {\n latestAfterHash,\n chainOk: verifyHistoryChain(entries).ok,\n contentHash,\n };\n}\n\n/**\n * Scan every item's history stream for drift (missing/unreadable streams, broken\n * hash chains, and item/history hash mismatches).\n *\n * Full chain re-verification of a large history tree is the dominant cost of\n * `pm health`. We cache the per-stream verification keyed by the history file's\n * mtime/ctime/size plus content hash. Strict callers keep recomputing the\n * content hash on metadata hits; latency-sensitive health checks can opt into\n * trusting the stat tuple and skip rereading unchanged streams.\n */\nexport async function scanHistoryDrift(\n pmRoot: string,\n items: Array<ItemMetadata & { body: string }>,\n options: DriftScanOptions = {},\n): Promise<DriftScanResult> {\n const missingStreams: string[] = [];\n const unreadableStreams: string[] = [];\n const hashMismatches: string[] = [];\n const chainMismatches: string[] = [];\n\n const cache = await loadDriftCache(pmRoot);\n const previousEntries: Record<string, DriftCacheEntry> = cache?.entries ?? {};\n const nextEntries: Record<string, DriftCacheEntry> = {};\n let cacheDirty = false;\n // Metadata mode does not open a stat-matched stream, so unreadable-after-stat\n // failures are intentionally deferred to strict validate/history-repair scans.\n const verifyCacheHitByContent = options.cacheHitVerification !== \"metadata\";\n\n for (const item of items) {\n const historyPath = getHistoryPath(pmRoot, item.id);\n\n let stat: Awaited<ReturnType<typeof fs.stat>>;\n try {\n stat = await fs.stat(historyPath);\n } catch (error: unknown) {\n if (isErrno(error, \"ENOENT\")) {\n missingStreams.push(item.id);\n } else {\n unreadableStreams.push(item.id);\n }\n continue;\n }\n\n const loadStreamVerification = async (): Promise<StreamVerification | null | \"unreadable\"> => {\n try {\n return await verifyHistoryStream(historyPath);\n } catch {\n return \"unreadable\";\n }\n };\n\n const loadFreshVerification = async (): Promise<StreamVerification | null> => {\n const loaded = await loadStreamVerification();\n if (loaded === \"unreadable\") {\n unreadableStreams.push(item.id);\n return null;\n }\n if (!loaded) {\n missingStreams.push(item.id);\n return null;\n }\n return loaded;\n };\n\n const cached = previousEntries[item.id];\n let verification: StreamVerification;\n const metadataMatchesCache =\n cached !== undefined &&\n cached.mtime_ms === stat.mtimeMs &&\n cached.ctime_ms === stat.ctimeMs &&\n cached.size === stat.size;\n const cachedContentHash =\n typeof cached?.content_hash === \"string\" && cached.content_hash.length > 0 ? cached.content_hash : undefined;\n const canUseCache = metadataMatchesCache && cachedContentHash !== undefined;\n if (canUseCache && cached) {\n let currentContentHash: string;\n if (verifyCacheHitByContent) {\n try {\n currentContentHash = await readHistoryContentHash(historyPath);\n } catch {\n unreadableStreams.push(item.id);\n continue;\n }\n } else {\n currentContentHash = cachedContentHash;\n }\n if (!verifyCacheHitByContent || currentContentHash === cachedContentHash) {\n verification = {\n latestAfterHash: cached.latest_after_hash,\n chainOk: cached.chain_ok,\n contentHash: currentContentHash,\n };\n } else {\n cacheDirty = true;\n const refreshed = await loadFreshVerification();\n if (!refreshed) {\n continue;\n }\n verification = refreshed;\n }\n } else {\n cacheDirty = true;\n const refreshed = await loadFreshVerification();\n if (!refreshed) {\n continue;\n }\n verification = refreshed;\n }\n\n if (!verification.chainOk) {\n chainMismatches.push(item.id);\n }\n nextEntries[item.id] = {\n mtime_ms: stat.mtimeMs,\n ctime_ms: stat.ctimeMs,\n size: stat.size,\n content_hash: verification.contentHash,\n latest_after_hash: verification.latestAfterHash,\n chain_ok: verification.chainOk,\n };\n\n const { body, ...frontMatter } = item;\n const currentHash = hashDocument({\n metadata: frontMatter as ItemMetadata,\n body,\n });\n if (currentHash !== verification.latestAfterHash) {\n hashMismatches.push(item.id);\n }\n }\n\n if (cacheDirty || Object.keys(previousEntries).length !== Object.keys(nextEntries).length) {\n const cachePath = getDriftCachePath(pmRoot);\n try {\n await fs.mkdir(path.dirname(cachePath), { recursive: true });\n await writeFileAtomic(cachePath, JSON.stringify({ version: DRIFT_CACHE_VERSION, entries: nextEntries }));\n } catch {\n // Best-effort cache write: a failed persist must never fail a health scan.\n }\n }\n\n const driftedItems = [...new Set([...missingStreams, ...unreadableStreams, ...hashMismatches, ...chainMismatches])].sort((a, b) =>\n a.localeCompare(b),\n );\n return { missingStreams, unreadableStreams, hashMismatches, chainMismatches, driftedItems };\n}\n"],"names":[],"mappings":"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","debugId":"a928aad0-855f-5c7f-aa00-77d698ddca80"}
1
+ {"version":3,"file":"drift-scan.js","sources":["core/history/drift-scan.ts"],"sourceRoot":"/","sourcesContent":["/**\n * @module core/history/drift-scan\n *\n * Implements append-only history and replay behavior for Drift Scan.\n */\nimport fs from \"fs/promises\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport { getHistoryPath } from \"../store/paths.js\";\nimport { writeFileAtomic } from \"../fs/fs-utils.js\";\nimport { hashDocument } from \"./history.js\";\nimport { verifyHistoryChain } from \"./replay.js\";\nimport type { HistoryEntry, ItemMetadata } from \"../../types/index.js\";\n\n/**\n * Documents the drift scan result payload exchanged by command, SDK, and package integrations.\n */\nexport interface DriftScanResult {\n missingStreams: string[];\n unreadableStreams: string[];\n hashMismatches: string[];\n chainMismatches: string[];\n driftedItems: string[];\n}\n\nconst DRIFT_CACHE_VERSION = 3;\nconst DRIFT_CACHE_FILENAME = \"history-drift-cache.json\";\n\n/**\n * Controls how cached history stream verification is trusted when the file stat\n * tuple still matches a previous scan.\n */\nexport type DriftCacheHitVerification = \"content_hash\" | \"metadata\";\n\n/**\n * Documents the history drift scan options shared by health, validate, and\n * repair callers.\n */\nexport interface DriftScanOptions {\n cacheHitVerification?: DriftCacheHitVerification;\n}\n\ninterface DriftCacheEntry {\n mtime_ms: number;\n ctime_ms: number;\n size: number;\n content_hash: string;\n latest_after_hash: string;\n chain_ok: boolean;\n}\n\ninterface DriftCacheEnvelope {\n version: number;\n entries: Record<string, DriftCacheEntry>;\n}\n\nfunction getDriftCachePath(pmRoot: string): string {\n return path.join(pmRoot, \"runtime\", DRIFT_CACHE_FILENAME);\n}\n\nasync function loadDriftCache(pmRoot: string): Promise<DriftCacheEnvelope | null> {\n try {\n const raw = await fs.readFile(getDriftCachePath(pmRoot), \"utf8\");\n const parsed = JSON.parse(raw) as DriftCacheEnvelope;\n if (parsed.version !== DRIFT_CACHE_VERSION || typeof parsed.entries !== \"object\" || parsed.entries === null) {\n return null;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\nfunction isErrno(error: unknown, code: string): boolean {\n return typeof error === \"object\" && error !== null && \"code\" in error && (error as { code?: string }).code === code;\n}\n\ninterface StreamVerification {\n latestAfterHash: string;\n chainOk: boolean;\n contentHash: string;\n}\n\ninterface DriftScanAccumulator {\n missingStreams: string[];\n unreadableStreams: string[];\n hashMismatches: string[];\n chainMismatches: string[];\n}\n\nfunction hashContent(raw: string): string {\n return createHash(\"sha256\").update(raw).digest(\"hex\");\n}\n\nasync function readHistoryContentHash(historyPath: string): Promise<string> {\n const raw = await fs.readFile(historyPath, \"utf8\");\n return hashContent(raw);\n}\n\n/**\n * Read and fully verify one history stream's hash chain. Returns null for an\n * empty/missing stream (caller records it as a missing stream).\n */\nasync function verifyHistoryStream(historyPath: string): Promise<StreamVerification | null> {\n const raw = await fs.readFile(historyPath, \"utf8\");\n const contentHash = hashContent(raw);\n if (raw.trim().length === 0) {\n return null;\n }\n const entries: HistoryEntry[] = [];\n let latestAfterHash: string | null = null;\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (trimmed.length === 0) {\n continue;\n }\n const parsed = JSON.parse(trimmed) as HistoryEntry;\n if (typeof parsed.after_hash !== \"string\" || parsed.after_hash.trim().length === 0) {\n throw new Error(\"missing after_hash\");\n }\n entries.push(parsed);\n latestAfterHash = parsed.after_hash;\n }\n /* c8 ignore start -- defensive guard for future history schema changes. */\n if (!latestAfterHash) {\n return null;\n }\n /* c8 ignore stop */\n return {\n latestAfterHash,\n chainOk: verifyHistoryChain(entries).ok,\n contentHash,\n };\n}\n\nfunction cacheMetadataMatches(cached: DriftCacheEntry | undefined, stat: Awaited<ReturnType<typeof fs.stat>>): boolean {\n return cached !== undefined && cached.mtime_ms === stat.mtimeMs && cached.ctime_ms === stat.ctimeMs && cached.size === stat.size;\n}\n\nasync function loadFreshStreamVerification(\n itemId: string,\n historyPath: string,\n accumulator: DriftScanAccumulator,\n): Promise<StreamVerification | null> {\n try {\n const loaded = await verifyHistoryStream(historyPath);\n if (!loaded) {\n accumulator.missingStreams.push(itemId);\n return null;\n }\n return loaded;\n } catch {\n accumulator.unreadableStreams.push(itemId);\n return null;\n }\n}\n\nasync function resolveStreamVerification(params: {\n itemId: string;\n historyPath: string;\n stat: Awaited<ReturnType<typeof fs.stat>>;\n cached: DriftCacheEntry | undefined;\n verifyCacheHitByContent: boolean;\n accumulator: DriftScanAccumulator;\n}): Promise<{ verification: StreamVerification | null; cacheDirty: boolean }> {\n const cachedContentHash =\n typeof params.cached?.content_hash === \"string\" && params.cached.content_hash.length > 0\n ? params.cached.content_hash\n : undefined;\n const canUseCache = cacheMetadataMatches(params.cached, params.stat) && cachedContentHash !== undefined && params.cached !== undefined;\n if (!canUseCache || !params.cached) {\n return {\n verification: await loadFreshStreamVerification(params.itemId, params.historyPath, params.accumulator),\n cacheDirty: true,\n };\n }\n let currentContentHash: string;\n if (params.verifyCacheHitByContent) {\n try {\n currentContentHash = await readHistoryContentHash(params.historyPath);\n } catch {\n params.accumulator.unreadableStreams.push(params.itemId);\n return { verification: null, cacheDirty: false };\n }\n } else {\n currentContentHash = cachedContentHash;\n }\n if (!params.verifyCacheHitByContent || currentContentHash === cachedContentHash) {\n return {\n verification: {\n latestAfterHash: params.cached.latest_after_hash,\n chainOk: params.cached.chain_ok,\n contentHash: currentContentHash,\n },\n cacheDirty: false,\n };\n }\n return {\n verification: await loadFreshStreamVerification(params.itemId, params.historyPath, params.accumulator),\n cacheDirty: true,\n };\n}\n\n/**\n * Scan every item's history stream for drift (missing/unreadable streams, broken\n * hash chains, and item/history hash mismatches).\n *\n * Full chain re-verification of a large history tree is the dominant cost of\n * `pm health`. We cache the per-stream verification keyed by the history file's\n * mtime/ctime/size plus content hash. Strict callers keep recomputing the\n * content hash on metadata hits; latency-sensitive health checks can opt into\n * trusting the stat tuple and skip rereading unchanged streams.\n */\nexport async function scanHistoryDrift(\n pmRoot: string,\n items: Array<ItemMetadata & { body: string }>,\n options: DriftScanOptions = {},\n): Promise<DriftScanResult> {\n const accumulator: DriftScanAccumulator = {\n missingStreams: [],\n unreadableStreams: [],\n hashMismatches: [],\n chainMismatches: [],\n };\n\n const cache = await loadDriftCache(pmRoot);\n const previousEntries: Record<string, DriftCacheEntry> = cache?.entries ?? {};\n const nextEntries: Record<string, DriftCacheEntry> = {};\n let cacheDirty = false;\n // Metadata mode does not open a stat-matched stream, so unreadable-after-stat\n // failures are intentionally deferred to strict validate/history-repair scans.\n const verifyCacheHitByContent = options.cacheHitVerification !== \"metadata\";\n\n for (const item of items) {\n const historyPath = getHistoryPath(pmRoot, item.id);\n\n let stat: Awaited<ReturnType<typeof fs.stat>>;\n try {\n stat = await fs.stat(historyPath);\n } catch (error: unknown) {\n if (isErrno(error, \"ENOENT\")) {\n accumulator.missingStreams.push(item.id);\n } else {\n accumulator.unreadableStreams.push(item.id);\n }\n continue;\n }\n\n const cached = previousEntries[item.id];\n const resolved = await resolveStreamVerification({\n itemId: item.id,\n historyPath,\n stat,\n cached,\n verifyCacheHitByContent,\n accumulator,\n });\n cacheDirty ||= resolved.cacheDirty;\n if (!resolved.verification) {\n continue;\n }\n\n if (!resolved.verification.chainOk) {\n accumulator.chainMismatches.push(item.id);\n }\n nextEntries[item.id] = {\n mtime_ms: stat.mtimeMs,\n ctime_ms: stat.ctimeMs,\n size: stat.size,\n content_hash: resolved.verification.contentHash,\n latest_after_hash: resolved.verification.latestAfterHash,\n chain_ok: resolved.verification.chainOk,\n };\n\n const { body, ...frontMatter } = item;\n const currentHash = hashDocument({\n metadata: frontMatter as ItemMetadata,\n body,\n });\n if (currentHash !== resolved.verification.latestAfterHash) {\n accumulator.hashMismatches.push(item.id);\n }\n }\n\n if (cacheDirty || Object.keys(previousEntries).length !== Object.keys(nextEntries).length) {\n const cachePath = getDriftCachePath(pmRoot);\n try {\n await fs.mkdir(path.dirname(cachePath), { recursive: true });\n await writeFileAtomic(cachePath, JSON.stringify({ version: DRIFT_CACHE_VERSION, entries: nextEntries }));\n } catch {\n // Best-effort cache write: a failed persist must never fail a health scan.\n }\n }\n\n const driftedItems = [\n ...new Set([\n ...accumulator.missingStreams,\n ...accumulator.unreadableStreams,\n ...accumulator.hashMismatches,\n ...accumulator.chainMismatches,\n ]),\n ].sort((a, b) => a.localeCompare(b));\n return { ...accumulator, driftedItems };\n}\n"],"names":[],"mappings":"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","debugId":"91c6995a-7219-5402-b2d4-e50227bf0149"}