@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
@@ -4,7 +4,7 @@
4
4
  * Implements the pm search command surface and its agent-facing runtime behavior.
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]="0417fe76-c2a2-5a0a-82f3-0861f46175e9")}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]="fe9c6a3a-fb99-53ed-9a6c-8c32bb745364")}catch(e){}}();
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
10
  import { coerceNumberInRange, toNonEmptyStringOrUndefined } from "../../core/shared/primitives.js";
@@ -117,8 +117,6 @@ const LONG_QUERY_PHRASE_MULTIPLIER = 6;
117
117
  const ALL_TERMS_COVERAGE_BONUS = 40;
118
118
  const EXACT_ID_MATCH_SCORE = 1_000;
119
119
  const SHORT_ID_MATCH_SCORE = 900;
120
- const IMPLICIT_HYBRID_EMBEDDING_TIMEOUT_MS = 8_000;
121
- const IMPLICIT_HYBRID_VECTOR_TIMEOUT_MS = 8_000;
122
120
  // GH-157 matched-text highlighting (--highlight): markers wrapping each matching
123
121
  // token run, and the number of characters of surrounding context retained on
124
122
  // each side of the first match in a field. The «…» guillemets are single
@@ -195,20 +193,20 @@ function buildVerboseSearchFilters(params) {
195
193
  return {
196
194
  mode: effectiveMode,
197
195
  match_mode: matchMode,
198
- status: isStatusAllFilterInput(options.status) ? "all" : options.status ?? null,
199
- type: options.type ?? null,
200
- tag: options.tag ?? null,
201
- priority: options.priority ?? null,
202
- deadline_before: options.deadlineBefore ?? null,
203
- deadline_after: options.deadlineAfter ?? null,
204
- updated_after: options.updatedAfter ?? null,
205
- updated_before: options.updatedBefore ?? null,
206
- created_after: options.createdAfter ?? null,
207
- created_before: options.createdBefore ?? null,
208
- assignee: options.assignee ?? null,
209
- sprint: options.sprint ?? null,
210
- release: options.release ?? null,
211
- parent: options.parent ?? null,
196
+ status: isStatusAllFilterInput(options.status) ? "all" : valueOrNull(options.status),
197
+ type: valueOrNull(options.type),
198
+ tag: valueOrNull(options.tag),
199
+ priority: valueOrNull(options.priority),
200
+ deadline_before: valueOrNull(options.deadlineBefore),
201
+ deadline_after: valueOrNull(options.deadlineAfter),
202
+ updated_after: valueOrNull(options.updatedAfter),
203
+ updated_before: valueOrNull(options.updatedBefore),
204
+ created_after: valueOrNull(options.createdAfter),
205
+ created_before: valueOrNull(options.createdBefore),
206
+ assignee: valueOrNull(options.assignee),
207
+ sprint: valueOrNull(options.sprint),
208
+ release: valueOrNull(options.release),
209
+ parent: valueOrNull(options.parent),
212
210
  ...buildGovernanceMissingFilterEcho(options),
213
211
  ...buildContentFilterEcho(options),
214
212
  include_linked: includeLinked,
@@ -221,10 +219,13 @@ function buildVerboseSearchFilters(params) {
221
219
  rerank_enabled: rerank.enabled,
222
220
  rerank_model: rerank.model,
223
221
  rerank_top_k: rerank.top_k,
224
- limit: options.limit ?? null,
222
+ limit: valueOrNull(options.limit),
225
223
  runtime_filters: runtimeFieldFilters,
226
224
  };
227
225
  }
226
+ function valueOrNull(value) {
227
+ return value ?? null;
228
+ }
228
229
  /**
229
230
  * Aggregate the `code` strings found along an error's `cause` chain.
230
231
  *
@@ -269,16 +270,6 @@ export function classifyImplicitSemanticFallbackReason(error) {
269
270
  }
270
271
  return "error";
271
272
  }
272
- function buildImplicitSemanticFallbackWarning(error) {
273
- const reason = classifyImplicitSemanticFallbackReason(error);
274
- if (reason === "timeout") {
275
- return "search_implicit_semantic_fallback:timeout:using_keyword_mode";
276
- }
277
- if (reason === "connection") {
278
- return "search_implicit_semantic_fallback:connection:using_keyword_mode";
279
- }
280
- return "search_implicit_semantic_fallback:error:using_keyword_mode";
281
- }
282
273
  // Explicit --semantic/--hybrid searches must never hard-fail an agent when the
283
274
  // embedding/vector backend is unreachable or unconfigured: degrade to keyword
284
275
  // search and surface a machine-readable warning instead of an unknown_error.
@@ -437,7 +428,6 @@ export const _testOnlySearchCommand = {
437
428
  buildExplicitSemanticFallbackWarning,
438
429
  buildCompactSearchFilterSummary,
439
430
  buildHybridLexicalScore,
440
- buildImplicitSemanticFallbackWarning,
441
431
  buildRerankCorpus,
442
432
  buildSemanticHits,
443
433
  classifyImplicitSemanticFallbackReason,
@@ -643,6 +633,11 @@ function resolveSearchMetadataFilterSet(options, typeRegistry, statusFilter) {
643
633
  };
644
634
  }
645
635
  function matchesScalarSearchFilters(item, filters) {
636
+ return (matchesIdentitySearchFilters(item, filters) &&
637
+ matchesTimestampSearchFilters(item, filters) &&
638
+ matchesOwnerSearchFilters(item, filters));
639
+ }
640
+ function matchesIdentitySearchFilters(item, filters) {
646
641
  if (filters.statusSet && !filters.statusSet.has(item.status))
647
642
  return false;
648
643
  if (filters.typeFilter && item.type !== filters.typeFilter)
@@ -651,6 +646,9 @@ function matchesScalarSearchFilters(item, filters) {
651
646
  return false;
652
647
  if (filters.priorityFilter !== undefined && item.priority !== filters.priorityFilter)
653
648
  return false;
649
+ return true;
650
+ }
651
+ function matchesTimestampSearchFilters(item, filters) {
654
652
  if (filters.deadlineBefore && (!item.deadline || compareTimestampStrings(item.deadline, filters.deadlineBefore) > 0))
655
653
  return false;
656
654
  if (filters.deadlineAfter && (!item.deadline || compareTimestampStrings(item.deadline, filters.deadlineAfter) < 0))
@@ -663,6 +661,9 @@ function matchesScalarSearchFilters(item, filters) {
663
661
  return false;
664
662
  if (filters.createdBefore && compareTimestampStrings(item.created_at, filters.createdBefore) > 0)
665
663
  return false;
664
+ return true;
665
+ }
666
+ function matchesOwnerSearchFilters(item, filters) {
666
667
  if (filters.assigneeFilter !== undefined && item.assignee !== filters.assigneeFilter)
667
668
  return false;
668
669
  if (filters.sprintFilter !== undefined && item.sprint !== filters.sprintFilter)
@@ -919,28 +920,8 @@ function buildHitHighlights(document, matchedFields, tokens) {
919
920
  }
920
921
  return highlights;
921
922
  }
922
- function scoreDocument(document, tokens, normalizedQuery, linkedCorpus, tuning, idPrefix, applyCoverageBonus = false) {
923
- const item = document.metadata;
924
- const normalizedId = normalizeSearchPhrase(item.id);
925
- const normalizedIdPrefix = typeof idPrefix === "string" ? idPrefix.trim().toLowerCase() : "";
926
- const normalizedIdPrefixPhrase = normalizeSearchPhrase(normalizedIdPrefix);
927
- const normalizedShortId = normalizedIdPrefixPhrase.length > 0 && normalizedId.startsWith(normalizedIdPrefixPhrase)
928
- ? normalizedId.slice(normalizedIdPrefixPhrase.length).trim()
929
- : normalizedId;
930
- if (normalizedQuery === normalizedId || normalizedQuery === normalizedShortId) {
931
- return {
932
- item,
933
- score: normalizedQuery === normalizedId ? EXACT_ID_MATCH_SCORE : SHORT_ID_MATCH_SCORE,
934
- matched_fields: ["id"],
935
- matched_all_terms: true,
936
- exact_id_match: true,
937
- };
938
- }
939
- const titleTokenCounts = new Map();
940
- for (const token of tokenizeForExactTokenMatch(item.title)) {
941
- titleTokenCounts.set(token, (titleTokenCounts.get(token) ?? 0) + 1);
942
- }
943
- const searchableFields = [
923
+ function buildSearchableScoringFields(document, linkedCorpus, tuning) {
924
+ return [
944
925
  ...SEARCHABLE_FIELD_BUILDERS.map((builder) => ({
945
926
  name: builder.name,
946
927
  value: builder.value(document),
@@ -948,58 +929,90 @@ function scoreDocument(document, tokens, normalizedQuery, linkedCorpus, tuning,
948
929
  })),
949
930
  { name: "linked_content", value: linkedCorpus, weight: tuning.linked_content_weight },
950
931
  ];
951
- let score = 0;
952
- const matched = new Set();
953
- const matchedTokens = new Set();
932
+ }
933
+ function buildExactIdSearchHit(item, normalizedQuery, idPrefix) {
934
+ const normalizedId = normalizeSearchPhrase(item.id);
935
+ const normalizedIdPrefix = typeof idPrefix === "string" ? idPrefix.trim().toLowerCase() : "";
936
+ const normalizedIdPrefixPhrase = normalizeSearchPhrase(normalizedIdPrefix);
937
+ const normalizedShortId = normalizedIdPrefixPhrase.length > 0 && normalizedId.startsWith(normalizedIdPrefixPhrase)
938
+ ? normalizedId.slice(normalizedIdPrefixPhrase.length).trim()
939
+ : normalizedId;
940
+ if (normalizedQuery !== normalizedId && normalizedQuery !== normalizedShortId) {
941
+ return null;
942
+ }
943
+ return {
944
+ item,
945
+ score: normalizedQuery === normalizedId ? EXACT_ID_MATCH_SCORE : SHORT_ID_MATCH_SCORE,
946
+ matched_fields: ["id"],
947
+ matched_all_terms: true,
948
+ exact_id_match: true,
949
+ };
950
+ }
951
+ function scoreTokenMatches(tokens, titleTokenCounts, searchableFields, tuning, state) {
954
952
  for (const token of tokens) {
955
953
  const exactTitleMatches = titleTokenCounts.get(token) ?? 0;
956
954
  if (exactTitleMatches > 0) {
957
- score += exactTitleMatches * tuning.title_exact_bonus;
958
- matched.add("title");
959
- matchedTokens.add(token);
955
+ state.score += exactTitleMatches * tuning.title_exact_bonus;
956
+ state.matched.add("title");
957
+ state.matchedTokens.add(token);
960
958
  }
961
959
  for (const field of searchableFields) {
962
- const fieldValue = field.value.toLowerCase();
963
- const occurrences = countOccurrences(fieldValue, token);
960
+ const occurrences = countOccurrences(field.value.toLowerCase(), token);
964
961
  if (occurrences > 0) {
965
- score += occurrences * field.weight;
966
- matched.add(field.name);
967
- matchedTokens.add(token);
962
+ state.score += occurrences * field.weight;
963
+ state.matched.add(field.name);
964
+ state.matchedTokens.add(token);
968
965
  }
969
966
  }
970
967
  }
968
+ }
969
+ function scorePhraseMatches(item, normalizedQuery, searchableFields, state) {
970
+ const normalizedTitle = normalizeSearchPhrase(item.title);
971
+ if (normalizedTitle === normalizedQuery) {
972
+ state.score += LONG_QUERY_TITLE_EXACT_BONUS;
973
+ state.matched.add("title");
974
+ }
975
+ for (const field of searchableFields) {
976
+ const phraseOccurrences = countOccurrences(normalizeSearchPhrase(field.value), normalizedQuery);
977
+ if (phraseOccurrences > 0) {
978
+ state.score += phraseOccurrences * field.weight * LONG_QUERY_PHRASE_MULTIPLIER;
979
+ state.matched.add(field.name);
980
+ }
981
+ }
982
+ }
983
+ function scoreDocument(document, tokens, normalizedQuery, linkedCorpus, tuning, idPrefix, applyCoverageBonus = false) {
984
+ const item = document.metadata;
985
+ const exactIdHit = buildExactIdSearchHit(item, normalizedQuery, idPrefix);
986
+ if (exactIdHit) {
987
+ return exactIdHit;
988
+ }
989
+ const titleTokenCounts = new Map();
990
+ for (const token of tokenizeForExactTokenMatch(item.title)) {
991
+ titleTokenCounts.set(token, (titleTokenCounts.get(token) ?? 0) + 1);
992
+ }
993
+ const searchableFields = buildSearchableScoringFields(document, linkedCorpus, tuning);
994
+ const state = { score: 0, matched: new Set(), matchedTokens: new Set() };
995
+ scoreTokenMatches(tokens, titleTokenCounts, searchableFields, tuning, state);
971
996
  const distinctTokens = new Set(tokens);
972
997
  // matchedTokens only ever holds entries drawn from `tokens`, so it is always a
973
998
  // subset of distinctTokens — exact size equality means every distinct term matched.
974
- const matchedAllTerms = distinctTokens.size > 0 && matchedTokens.size === distinctTokens.size;
999
+ const matchedAllTerms = distinctTokens.size > 0 && state.matchedTokens.size === distinctTokens.size;
975
1000
  // GH-181 default-mode all-terms ranking bonus: only meaningful for multi-token
976
1001
  // queries where every distinct token matched somewhere.
977
1002
  if (applyCoverageBonus && distinctTokens.size > 1 && matchedAllTerms) {
978
- score += ALL_TERMS_COVERAGE_BONUS;
1003
+ state.score += ALL_TERMS_COVERAGE_BONUS;
979
1004
  }
980
1005
  const isLongPhraseQuery = tokens.length >= LONG_QUERY_TOKEN_THRESHOLD && normalizedQuery.includes(" ");
981
1006
  if (isLongPhraseQuery) {
982
- const normalizedTitle = normalizeSearchPhrase(item.title);
983
- if (normalizedTitle === normalizedQuery) {
984
- score += LONG_QUERY_TITLE_EXACT_BONUS;
985
- matched.add("title");
986
- }
987
- for (const field of searchableFields) {
988
- const normalizedField = normalizeSearchPhrase(field.value);
989
- const phraseOccurrences = countOccurrences(normalizedField, normalizedQuery);
990
- if (phraseOccurrences > 0) {
991
- score += phraseOccurrences * field.weight * LONG_QUERY_PHRASE_MULTIPLIER;
992
- matched.add(field.name);
993
- }
994
- }
1007
+ scorePhraseMatches(item, normalizedQuery, searchableFields, state);
995
1008
  }
996
- if (score <= 0) {
1009
+ if (state.score <= 0) {
997
1010
  return null;
998
1011
  }
999
1012
  return {
1000
1013
  item,
1001
- score,
1002
- matched_fields: [...matched].sort((a, b) => a.localeCompare(b)),
1014
+ score: state.score,
1015
+ matched_fields: [...state.matched].sort((a, b) => a.localeCompare(b)),
1003
1016
  matched_all_terms: matchedAllTerms,
1004
1017
  };
1005
1018
  }
@@ -1244,8 +1257,15 @@ function resolveExtensionVectorAdapter(settings) {
1244
1257
  if (typeof query !== "function") {
1245
1258
  return null;
1246
1259
  }
1260
+ const upsert = runtimeDefinition.upsert;
1261
+ const runtimeAdapterName = toOptionalNonEmptyString(runtimeDefinition.name) ??
1262
+ toOptionalNonEmptyString(resolved.definition.name) ??
1263
+ adapterName ??
1264
+ "extension";
1247
1265
  return {
1266
+ adapterName: runtimeAdapterName,
1248
1267
  query: query,
1268
+ ...(typeof upsert === "function" ? { upsert: upsert } : {}),
1249
1269
  };
1250
1270
  }
1251
1271
  /* c8 ignore stop */
@@ -1459,59 +1479,162 @@ function buildRerankCorpus(document) {
1459
1479
  }
1460
1480
  /* c8 ignore stop */
1461
1481
  /* c8 ignore start -- semantic expansion/rerank fallback matrices are covered by end-to-end semantic search tests */
1462
- async function computeSemanticOrHybridHits(context) {
1463
- const semanticLimit = context.limit ?? context.maxResults;
1464
- const embeddingOptions = context.embeddingTimeoutMs !== undefined ? { timeout_ms: context.embeddingTimeoutMs } : {};
1465
- const vectorQueryOptions = context.vectorQueryTimeoutMs !== undefined ? { timeout_ms: context.vectorQueryTimeoutMs } : {};
1466
- const queryTrimmed = context.query.trim();
1482
+ async function resolveExpandedSemanticQueries(context, queryTrimmed) {
1467
1483
  const baseExpandedQueries = context.queryExpansion.enabled
1468
1484
  ? buildDeterministicQueryExpansions(queryTrimmed, context.queryExpansion.max_queries)
1469
1485
  : [queryTrimmed];
1470
- let expandedQueries = baseExpandedQueries.length > 0 ? baseExpandedQueries : [queryTrimmed];
1471
- if (context.queryExpansion.enabled) {
1472
- if (context.queryExpansionExtension?.expand) {
1473
- try {
1474
- const rawExpansion = await Promise.resolve(context.queryExpansionExtension.expand({
1475
- query: queryTrimmed,
1476
- mode: context.requestedMode,
1477
- settings: context.settings,
1478
- }));
1479
- const extensionExpansion = normalizeQueryExpansionOutput(rawExpansion);
1480
- expandedQueries = mergeQueryExpansions(expandedQueries, extensionExpansion, context.queryExpansion.max_queries);
1481
- }
1482
- catch {
1483
- context.warnings.push(`search_query_expansion_provider_failed:${context.queryExpansionExtension.providerName}:using_builtin`);
1484
- }
1486
+ const expandedQueries = baseExpandedQueries.length > 0 ? baseExpandedQueries : [queryTrimmed];
1487
+ if (!context.queryExpansion.enabled) {
1488
+ return expandedQueries;
1489
+ }
1490
+ if (context.queryExpansionExtension?.expand) {
1491
+ try {
1492
+ const rawExpansion = await Promise.resolve(context.queryExpansionExtension.expand({
1493
+ query: queryTrimmed,
1494
+ mode: context.requestedMode,
1495
+ settings: context.settings,
1496
+ }));
1497
+ return mergeQueryExpansions(expandedQueries, normalizeQueryExpansionOutput(rawExpansion), context.queryExpansion.max_queries);
1485
1498
  }
1486
- else if (context.queryExpansion.provider &&
1487
- context.queryExpansion.provider !== "openai" &&
1488
- context.queryExpansion.provider !== "ollama") {
1489
- context.warnings.push(`search_query_expansion_provider_unavailable:${context.queryExpansion.provider}:using_builtin`);
1499
+ catch {
1500
+ context.warnings.push(`search_query_expansion_provider_failed:${context.queryExpansionExtension.providerName}:using_builtin`);
1501
+ return expandedQueries;
1490
1502
  }
1491
1503
  }
1492
- const queryVectors = await executeEmbeddingRequest(context.provider, expandedQueries, embeddingOptions);
1493
- const executeVectorQueryWithFallback = async (semanticVector) => {
1494
- if (context.extensionVectorAdapter?.query) {
1495
- try {
1496
- return await Promise.resolve(context.extensionVectorAdapter.query({
1497
- vector: semanticVector,
1498
- limit: semanticLimit,
1499
- settings: context.settings,
1500
- }));
1501
- }
1502
- catch (error) {
1503
- if (!context.vectorStore) {
1504
- throw new PmCliError(`Extension vector adapter query failed and no built-in fallback store is configured (${error instanceof Error ? error.message : String(error)})`, EXIT_CODE.GENERIC_FAILURE);
1505
- }
1506
- return await executeVectorQuery(context.vectorStore, semanticVector, semanticLimit, vectorQueryOptions);
1507
- }
1504
+ if (context.queryExpansion.provider &&
1505
+ context.queryExpansion.provider !== "openai" &&
1506
+ context.queryExpansion.provider !== "ollama") {
1507
+ context.warnings.push(`search_query_expansion_provider_unavailable:${context.queryExpansion.provider}:using_builtin`);
1508
+ }
1509
+ return expandedQueries;
1510
+ }
1511
+ async function executeSemanticVectorQuery(context, semanticVector, semanticLimit, vectorQueryOptions) {
1512
+ if (context.extensionVectorAdapter?.query) {
1513
+ try {
1514
+ return await Promise.resolve(context.extensionVectorAdapter.query({
1515
+ vector: semanticVector,
1516
+ limit: semanticLimit,
1517
+ settings: context.settings,
1518
+ }));
1508
1519
  }
1509
- if (context.vectorStore) {
1520
+ catch (error) {
1521
+ if (!context.vectorStore) {
1522
+ throw new PmCliError(`Extension vector adapter query failed and no built-in fallback store is configured (${error instanceof Error ? error.message : String(error)})`, EXIT_CODE.GENERIC_FAILURE);
1523
+ }
1524
+ context.warnings.push(`search_vector_adapter_failed:${context.extensionVectorAdapter.adapterName}:using_builtin`);
1510
1525
  return await executeVectorQuery(context.vectorStore, semanticVector, semanticLimit, vectorQueryOptions);
1511
1526
  }
1512
- throw new PmCliError("Semantic search requires either a configured vector store or an extension vector adapter query handler", EXIT_CODE.USAGE);
1513
- };
1514
- const queryVectorGroups = await Promise.all(queryVectors.map(async (semanticVector) => await executeVectorQueryWithFallback(semanticVector)));
1527
+ }
1528
+ if (context.vectorStore) {
1529
+ return await executeVectorQuery(context.vectorStore, semanticVector, semanticLimit, vectorQueryOptions);
1530
+ }
1531
+ throw new PmCliError("Semantic search requires either a configured vector store or an extension vector adapter query handler", EXIT_CODE.USAGE);
1532
+ }
1533
+ function buildRerankCandidateContexts(hybridHits, filteredById, topK) {
1534
+ const sortedForCandidates = [...hybridHits].sort((left, right) => {
1535
+ if (left.score !== right.score) {
1536
+ return right.score - left.score;
1537
+ }
1538
+ return left.item.id.localeCompare(right.item.id);
1539
+ });
1540
+ return sortedForCandidates
1541
+ .slice(0, topK)
1542
+ .map((hit) => {
1543
+ const document = filteredById.get(hit.item.id);
1544
+ return document ? { hit, text: buildRerankCorpus(document) } : null;
1545
+ })
1546
+ .filter((entry) => entry !== null);
1547
+ }
1548
+ async function resolveExtensionRerankScores(context, queryTrimmed, candidateContexts) {
1549
+ if (!context.rerankExtension?.rerank) {
1550
+ return null;
1551
+ }
1552
+ try {
1553
+ const rawRerank = await Promise.resolve(context.rerankExtension.rerank({
1554
+ query: queryTrimmed,
1555
+ mode: "hybrid",
1556
+ model: context.rerank.model,
1557
+ top_k: context.rerank.top_k,
1558
+ settings: context.settings,
1559
+ candidates: candidateContexts.map((entry) => ({
1560
+ id: entry.hit.item.id,
1561
+ text: entry.text,
1562
+ score: entry.hit.score,
1563
+ })),
1564
+ }));
1565
+ const normalizedRerank = normalizeRerankOutput(rawRerank);
1566
+ if (normalizedRerank.length > 0) {
1567
+ return new Map(normalizedRerank.map((entry) => [entry.id, entry.score]));
1568
+ }
1569
+ context.warnings.push(`search_rerank_provider_invalid_response:${context.rerankExtension.providerName}:using_builtin`);
1570
+ return null;
1571
+ }
1572
+ catch {
1573
+ context.warnings.push(`search_rerank_provider_failed:${context.rerankExtension.providerName}:using_builtin`);
1574
+ return null;
1575
+ }
1576
+ }
1577
+ async function resolveRerankScores(context, queryTrimmed, candidateContexts) {
1578
+ const extensionScores = await resolveExtensionRerankScores(context, queryTrimmed, candidateContexts);
1579
+ if (extensionScores) {
1580
+ return extensionScores;
1581
+ }
1582
+ const rerankCandidates = candidateContexts.map((entry) => ({
1583
+ id: entry.hit.item.id,
1584
+ text: entry.text,
1585
+ }));
1586
+ try {
1587
+ return await rerankCandidatesWithEmbeddings(context.provider, context.rerank.model, queryTrimmed, rerankCandidates, context.embeddingTimeoutMs);
1588
+ }
1589
+ catch {
1590
+ context.warnings.push("search_rerank_failed:using_hybrid_scores");
1591
+ return null;
1592
+ }
1593
+ }
1594
+ function applyRerankScores(hybridHits, rerankScores) {
1595
+ const rerankedIds = new Set(rerankScores.keys());
1596
+ const rerankedHits = hybridHits.map((hit) => {
1597
+ const rerankScore = rerankScores.get(hit.item.id);
1598
+ if (rerankScore === undefined) {
1599
+ return hit;
1600
+ }
1601
+ const matchedFields = new Set(hit.matched_fields);
1602
+ matchedFields.add("rerank");
1603
+ return {
1604
+ ...hit,
1605
+ score: rerankScore,
1606
+ matched_fields: [...matchedFields].sort((left, right) => left.localeCompare(right)),
1607
+ };
1608
+ });
1609
+ rerankedHits.sort((left, right) => {
1610
+ const leftWasReranked = rerankedIds.has(left.item.id);
1611
+ const rightWasReranked = rerankedIds.has(right.item.id);
1612
+ if (leftWasReranked !== rightWasReranked) {
1613
+ return leftWasReranked ? -1 : 1;
1614
+ }
1615
+ if (left.score !== right.score) {
1616
+ return right.score - left.score;
1617
+ }
1618
+ return left.item.id.localeCompare(right.item.id);
1619
+ });
1620
+ return rerankedHits;
1621
+ }
1622
+ async function applyHybridRerank(context, queryTrimmed, hybridHits, filteredById) {
1623
+ if (!context.rerank.enabled || hybridHits.length <= 1) {
1624
+ return hybridHits;
1625
+ }
1626
+ const candidateContexts = buildRerankCandidateContexts(hybridHits, filteredById, context.rerank.top_k);
1627
+ const rerankScores = await resolveRerankScores(context, queryTrimmed, candidateContexts);
1628
+ return rerankScores && rerankScores.size > 0 ? applyRerankScores(hybridHits, rerankScores) : hybridHits;
1629
+ }
1630
+ async function computeSemanticOrHybridHits(context) {
1631
+ const semanticLimit = context.limit ?? context.maxResults;
1632
+ const embeddingOptions = context.embeddingTimeoutMs !== undefined ? { timeout_ms: context.embeddingTimeoutMs } : {};
1633
+ const vectorQueryOptions = context.vectorQueryTimeoutMs !== undefined ? { timeout_ms: context.vectorQueryTimeoutMs } : {};
1634
+ const queryTrimmed = context.query.trim();
1635
+ const expandedQueries = await resolveExpandedSemanticQueries(context, queryTrimmed);
1636
+ const queryVectors = await executeEmbeddingRequest(context.provider, expandedQueries, embeddingOptions);
1637
+ const queryVectorGroups = await Promise.all(queryVectors.map(async (semanticVector) => await executeSemanticVectorQuery(context, semanticVector, semanticLimit, vectorQueryOptions)));
1515
1638
  const vectorHits = mergeVectorHitsById(queryVectorGroups);
1516
1639
  const filteredById = new Map(context.filteredDocuments.map((document) => [document.metadata.id, document]));
1517
1640
  const { semanticHits, semanticScores } = buildSemanticHits(vectorHits, filteredById);
@@ -1521,91 +1644,7 @@ async function computeSemanticOrHybridHits(context) {
1521
1644
  // semantic mode, where it otherwise carries no vector hit at all.
1522
1645
  return { hits: forceExactIdHitsToTop(semanticHits, context.keywordHits), vectorMatchCount };
1523
1646
  }
1524
- let hybridHits = combineHybridHits(filteredById, semanticScores, context.keywordHits, context.hybridSemanticWeight);
1525
- if (context.rerank.enabled && hybridHits.length > 1) {
1526
- const sortedForCandidates = [...hybridHits].sort((left, right) => {
1527
- if (left.score !== right.score) {
1528
- return right.score - left.score;
1529
- }
1530
- return left.item.id.localeCompare(right.item.id);
1531
- });
1532
- const candidateHits = sortedForCandidates.slice(0, context.rerank.top_k);
1533
- const candidateContexts = candidateHits
1534
- .map((hit) => {
1535
- const document = filteredById.get(hit.item.id);
1536
- if (!document) {
1537
- return null;
1538
- }
1539
- return { hit, text: buildRerankCorpus(document) };
1540
- })
1541
- .filter((entry) => entry !== null);
1542
- const rerankCandidates = candidateContexts.map((entry) => ({
1543
- id: entry.hit.item.id,
1544
- text: entry.text,
1545
- }));
1546
- let rerankScores = null;
1547
- if (context.rerankExtension?.rerank) {
1548
- try {
1549
- const rawRerank = await Promise.resolve(context.rerankExtension.rerank({
1550
- query: queryTrimmed,
1551
- mode: "hybrid",
1552
- model: context.rerank.model,
1553
- top_k: context.rerank.top_k,
1554
- settings: context.settings,
1555
- candidates: candidateContexts.map((entry) => ({
1556
- id: entry.hit.item.id,
1557
- text: entry.text,
1558
- score: entry.hit.score,
1559
- })),
1560
- }));
1561
- const normalizedRerank = normalizeRerankOutput(rawRerank);
1562
- if (normalizedRerank.length > 0) {
1563
- rerankScores = new Map(normalizedRerank.map((entry) => [entry.id, entry.score]));
1564
- }
1565
- else {
1566
- context.warnings.push(`search_rerank_provider_invalid_response:${context.rerankExtension.providerName}:using_builtin`);
1567
- }
1568
- }
1569
- catch {
1570
- context.warnings.push(`search_rerank_provider_failed:${context.rerankExtension.providerName}:using_builtin`);
1571
- }
1572
- }
1573
- if (!rerankScores) {
1574
- try {
1575
- rerankScores = await rerankCandidatesWithEmbeddings(context.provider, context.rerank.model, queryTrimmed, rerankCandidates, context.embeddingTimeoutMs);
1576
- }
1577
- catch {
1578
- context.warnings.push("search_rerank_failed:using_hybrid_scores");
1579
- }
1580
- }
1581
- if (rerankScores && rerankScores.size > 0) {
1582
- const rerankedIds = new Set(rerankScores.keys());
1583
- hybridHits = hybridHits.map((hit) => {
1584
- const rerankScore = rerankScores.get(hit.item.id);
1585
- if (rerankScore === undefined) {
1586
- return hit;
1587
- }
1588
- const matchedFields = new Set(hit.matched_fields);
1589
- matchedFields.add("rerank");
1590
- return {
1591
- ...hit,
1592
- score: rerankScore,
1593
- matched_fields: [...matchedFields].sort((left, right) => left.localeCompare(right)),
1594
- };
1595
- });
1596
- hybridHits.sort((left, right) => {
1597
- const leftWasReranked = rerankedIds.has(left.item.id);
1598
- const rightWasReranked = rerankedIds.has(right.item.id);
1599
- if (leftWasReranked !== rightWasReranked) {
1600
- return leftWasReranked ? -1 : 1;
1601
- }
1602
- if (left.score !== right.score) {
1603
- return right.score - left.score;
1604
- }
1605
- return left.item.id.localeCompare(right.item.id);
1606
- });
1607
- }
1608
- }
1647
+ const hybridHits = await applyHybridRerank(context, queryTrimmed, combineHybridHits(filteredById, semanticScores, context.keywordHits, context.hybridSemanticWeight), filteredById);
1609
1648
  return {
1610
1649
  // GH-281: applied LAST (after any rerank reordering) so an exact full-ID /
1611
1650
  // short-ID keyword match always ranks #1 in hybrid mode regardless of the
@@ -1725,14 +1764,15 @@ function projectSearchHits(hits, projection) {
1725
1764
  return projected;
1726
1765
  });
1727
1766
  }
1728
- /**
1729
- * Implements run search for the public runtime surface of this module.
1730
- */
1731
- export async function runSearch(rawQuery, rawOptions, global) {
1732
- // GH-157 inline query syntax: pull `field:value` filter tokens out of the raw
1733
- // query before any other parsing. Explicit flags win — an inline token only
1734
- // applies when its flag is unset, and a conflicting token surfaces as a
1735
- // warning. The residual keyword text drives tokenization/scoring as usual.
1767
+ function resolveQueryExpansionExtension(queryExpansion) {
1768
+ const provider = resolveExtensionSearchProviderByName(queryExpansion.provider ?? undefined);
1769
+ return provider?.queryExpansion ? { providerName: provider.providerName, expand: provider.queryExpansion } : null;
1770
+ }
1771
+ function resolveRerankExtension(settings) {
1772
+ const provider = resolveExtensionSearchProviderByName(toOptionalNonEmptyString(settings.search?.provider));
1773
+ return provider?.rerank ? { providerName: provider.providerName, rerank: provider.rerank } : null;
1774
+ }
1775
+ function prepareSearchInput(rawQuery, rawOptions) {
1736
1776
  const inlineWarnings = [];
1737
1777
  const inlineParse = parseInlineQueryFilters(rawQuery);
1738
1778
  const hasInlineFilters = Object.keys(inlineParse.inlineFilters).length > 0;
@@ -1746,372 +1786,391 @@ export async function runSearch(rawQuery, rawOptions, global) {
1746
1786
  }
1747
1787
  const query = hasInlineFilters ? inlineParse.residualQuery : rawQuery;
1748
1788
  const options = applyInlineQueryFilters(rawOptions, inlineParse.inlineFilters, inlineWarnings);
1749
- const highlight = options.highlight === true;
1750
- const includeLinked = parseIncludeLinked(options.includeLinked);
1751
- const titleExact = parseTitleExact(options.titleExact);
1752
- const phraseExact = parsePhraseExact(options.phraseExact);
1753
- const matchMode = parseMatchMode(typeof options.matchMode === "string" ? options.matchMode : undefined);
1754
- const minScoreOverride = parseMinScoreOverride(options.minScore);
1755
- const countOnly = options.count === true;
1756
- const tokens = parseTokens(query);
1757
- const normalizedQuery = normalizeSearchPhrase(query);
1758
- const limit = parseLimit(options.limit);
1759
- const projection = parseProjectionConfig(options);
1760
- const modeWasExplicit = typeof options.mode === "string" && options.mode.trim().length > 0;
1789
+ return {
1790
+ query,
1791
+ options,
1792
+ inlineWarnings,
1793
+ highlight: options.highlight === true,
1794
+ includeLinked: parseIncludeLinked(options.includeLinked),
1795
+ titleExact: parseTitleExact(options.titleExact),
1796
+ phraseExact: parsePhraseExact(options.phraseExact),
1797
+ matchMode: parseMatchMode(typeof options.matchMode === "string" ? options.matchMode : undefined),
1798
+ minScoreOverride: parseMinScoreOverride(options.minScore),
1799
+ countOnly: options.count === true,
1800
+ tokens: parseTokens(query),
1801
+ normalizedQuery: normalizeSearchPhrase(query),
1802
+ limit: parseLimit(options.limit),
1803
+ projection: parseProjectionConfig(options),
1804
+ modeWasExplicit: typeof options.mode === "string" && options.mode.trim().length > 0,
1805
+ };
1806
+ }
1807
+ async function resolveSearchRuntimeContext(prepared, global) {
1761
1808
  const pmRoot = resolvePmRoot(process.cwd(), global.path);
1762
1809
  if (!(await pathExists(getSettingsPath(pmRoot)))) {
1763
1810
  throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
1764
1811
  }
1765
1812
  const storedSettings = await readSettings(pmRoot);
1766
- const runtimeDefaultsResolution = resolveSettingsWithSemanticRuntimeDefaults(storedSettings);
1767
- const settings = runtimeDefaultsResolution.settings;
1813
+ const settings = resolveSettingsWithSemanticRuntimeDefaults(storedSettings).settings;
1768
1814
  const statusRegistry = resolveRuntimeStatusRegistry(settings.schema);
1769
1815
  const runtimeFieldRegistry = resolveRuntimeFieldRegistry(settings.schema);
1770
- validateSearchProjectionFields(projection, runtimeFieldRegistry);
1771
- const runtimeFieldFilters = collectRuntimeFilterValues(options, runtimeFieldRegistry, "search");
1772
- // `pm search --status` resolves strictly (a typo'd status surfaces a
1773
- // did-you-mean hint) so agents can scope retrieval to open work and drop
1774
- // closed-history noise without re-listing. Resolved before the corpus scan so
1775
- // an invalid value fails fast.
1776
- const statusFilter = parseStatusFilterCsv(typeof options.status === "string" ? options.status : undefined, statusRegistry, { strict: true });
1816
+ validateSearchProjectionFields(prepared.projection, runtimeFieldRegistry);
1817
+ const runtimeFieldFilters = collectRuntimeFilterValues(prepared.options, runtimeFieldRegistry, "search");
1777
1818
  const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
1778
- const maxResults = resolveSearchMaxResults(settings);
1779
- // pm-cstl: --min-score overrides the persistent search.score_threshold for this
1780
- // query only; the effective threshold is reflected in filters.score_threshold.
1781
- const scoreThreshold = minScoreOverride ?? resolveSearchScoreThreshold(settings);
1782
- const semanticWeightProvided = options.semanticWeight !== undefined;
1783
- const semanticWeightOverride = parseSemanticWeightOverride(options.semanticWeight);
1784
- const hybridSemanticWeight = semanticWeightOverride ?? resolveHybridSemanticWeight(settings);
1785
- const tuning = resolveSearchTuning(settings);
1786
1819
  const providerResolution = resolveEmbeddingProviders(settings);
1787
1820
  const vectorResolution = resolveVectorStores(settings);
1788
1821
  const extensionSearchProvider = resolveExtensionSearchProvider(settings);
1789
1822
  const extensionVectorAdapter = resolveExtensionVectorAdapter(settings);
1790
- // pm-75k9: offline BM25 lexical provider. When active, a semantic/hybrid query
1791
- // ranks the corpus locally with BM25 instead of requiring an embedding service
1792
- // + vector store — enabling dense-quality offline retrieval in air-gapped, CI,
1793
- // and zero-setup environments. Resolved here so the semantic block can branch.
1794
- const bm25Mode = resolveBuiltInBm25Mode({
1795
- configuredProvider: toOptionalNonEmptyString(settings.search?.provider),
1796
- hasEmbeddingProvider: providerResolution.active !== null,
1797
- hasExtensionSearchProvider: extensionSearchProvider !== null,
1798
- });
1823
+ const semanticWeightOverride = parseSemanticWeightOverride(prepared.options.semanticWeight);
1799
1824
  const queryExpansion = resolveQueryExpansionConfig(settings, providerResolution.active?.name ?? null);
1800
1825
  const rerank = resolveRerankConfig(settings, providerResolution.active?.model ?? toOptionalNonEmptyString(settings.search?.embedding_model) ?? "text-embedding-3-small");
1801
- const queryExpansionProvider = resolveExtensionSearchProviderByName(queryExpansion.provider ?? undefined);
1802
- const queryExpansionExtension = queryExpansionProvider?.queryExpansion
1803
- ? { providerName: queryExpansionProvider.providerName, expand: queryExpansionProvider.queryExpansion }
1804
- : null;
1805
- const rerankProvider = resolveExtensionSearchProviderByName(toOptionalNonEmptyString(settings.search?.provider));
1806
- const rerankExtension = rerankProvider?.rerank
1807
- ? { providerName: rerankProvider.providerName, rerank: rerankProvider.rerank }
1808
- : null;
1809
- let effectiveMode = parseMode(options.mode, {
1810
- hasProvider: providerResolution.active !== null || extensionSearchProvider !== null,
1811
- hasVectorStore: vectorResolution.active !== null || extensionVectorAdapter !== null,
1812
- });
1813
- const loadedDocuments = await loadDocuments(pmRoot, settings.item_format ?? "toon", typeRegistry.type_to_folder, settings.schema);
1814
- const warnings = loadedDocuments.warnings;
1815
- if (inlineWarnings.length > 0) {
1816
- warnings.push(...inlineWarnings);
1826
+ return {
1827
+ pmRoot,
1828
+ settings,
1829
+ statusRegistry,
1830
+ runtimeFieldRegistry,
1831
+ runtimeFieldFilters,
1832
+ typeRegistry,
1833
+ maxResults: resolveSearchMaxResults(settings),
1834
+ scoreThreshold: prepared.minScoreOverride ?? resolveSearchScoreThreshold(settings),
1835
+ semanticWeightProvided: prepared.options.semanticWeight !== undefined,
1836
+ semanticWeightOverride,
1837
+ hybridSemanticWeight: semanticWeightOverride ?? resolveHybridSemanticWeight(settings),
1838
+ tuning: resolveSearchTuning(settings),
1839
+ providerResolution,
1840
+ vectorResolution,
1841
+ extensionSearchProvider,
1842
+ extensionVectorAdapter,
1843
+ bm25Mode: resolveBuiltInBm25Mode({
1844
+ configuredProvider: toOptionalNonEmptyString(settings.search?.provider),
1845
+ hasEmbeddingProvider: providerResolution.active !== null,
1846
+ hasExtensionSearchProvider: extensionSearchProvider !== null,
1847
+ }),
1848
+ queryExpansion,
1849
+ queryExpansionExtension: resolveQueryExpansionExtension(queryExpansion),
1850
+ rerank,
1851
+ rerankExtension: resolveRerankExtension(settings),
1852
+ effectiveMode: parseMode(prepared.options.mode, {
1853
+ hasProvider: providerResolution.active !== null || extensionSearchProvider !== null,
1854
+ hasVectorStore: vectorResolution.active !== null || extensionVectorAdapter !== null,
1855
+ }),
1856
+ };
1857
+ }
1858
+ async function loadFilteredSearchCorpus(prepared, runtime) {
1859
+ const loadedDocuments = await loadDocuments(runtime.pmRoot, runtime.settings.item_format ?? "toon", runtime.typeRegistry.type_to_folder, runtime.settings.schema);
1860
+ const statusFilter = parseStatusFilterCsv(typeof prepared.options.status === "string" ? prepared.options.status : undefined, runtime.statusRegistry, { strict: true });
1861
+ const lifecycleClassifier = lifecycleClassifierFromStatusRegistry(runtime.statusRegistry);
1862
+ const metadataFilteredDocuments = applyFilters(loadedDocuments.documents, prepared.options, runtime.typeRegistry, runtime.runtimeFieldFilters, statusFilter, lifecycleClassifier);
1863
+ return {
1864
+ warnings: loadedDocuments.warnings,
1865
+ allDocuments: loadedDocuments.documents,
1866
+ filteredDocuments: applyExactQueryFilters(metadataFilteredDocuments, prepared.normalizedQuery, {
1867
+ titleExact: prepared.titleExact,
1868
+ phraseExact: prepared.phraseExact || prepared.matchMode === "exact",
1869
+ }),
1870
+ };
1871
+ }
1872
+ async function collectLinkedCorpusById(includeLinked, effectiveMode, filteredDocuments) {
1873
+ const linkedCorpusById = new Map();
1874
+ if (!includeLinked || (effectiveMode !== "keyword" && effectiveMode !== "hybrid")) {
1875
+ return linkedCorpusById;
1817
1876
  }
1818
- if (effectiveMode === "hybrid" && semanticWeightProvided && semanticWeightOverride === undefined) {
1819
- warnings.push("search_hybrid_semantic_weight_override_invalid:using_settings_default");
1877
+ const projectRoot = process.cwd();
1878
+ const linkedCorpusRoots = await resolveLinkedCorpusRoots(projectRoot, resolveGlobalPmRoot(projectRoot));
1879
+ const linkedCorpusEntries = await Promise.all(filteredDocuments.map(async (document) => [document.metadata.id, await loadLinkedCorpus(document, linkedCorpusRoots)]));
1880
+ for (const [id, corpus] of linkedCorpusEntries) {
1881
+ linkedCorpusById.set(id, corpus);
1882
+ }
1883
+ return linkedCorpusById;
1884
+ }
1885
+ async function computeKeywordSearchHits(prepared, runtime, filteredDocuments) {
1886
+ const linkedCorpusById = await collectLinkedCorpusById(prepared.includeLinked, runtime.effectiveMode, filteredDocuments);
1887
+ const applyCoverageBonus = prepared.matchMode === "or";
1888
+ return filteredDocuments
1889
+ .map((document) => buildHybridLexicalScore(document, prepared.tokens, prepared.normalizedQuery, prepared.includeLinked, linkedCorpusById, runtime.tuning, runtime.settings.id_prefix, applyCoverageBonus))
1890
+ .filter((entry) => entry !== null)
1891
+ .filter((entry) => prepared.matchMode !== "and" || entry.matched_all_terms === true);
1892
+ }
1893
+ function buildEmptySearchResultFromContext(response, countOnly) {
1894
+ return emptySearchResult(response.query, response.effectiveMode, response.matchMode, response.options, response.includeLinked, response.scoreThreshold, response.hybridSemanticWeight, response.queryExpansion, response.rerank, response.projection, response.warnings, response.runtimeFieldFilters, countOnly);
1895
+ }
1896
+ async function executeBuiltInBm25Search(prepared, runtime, filteredDocuments, keywordHits, warnings) {
1897
+ if (runtime.bm25Mode === null || runtime.effectiveMode === "keyword") {
1898
+ return null;
1820
1899
  }
1821
- const allDocuments = loadedDocuments.documents;
1822
- const lifecycleClassifier = lifecycleClassifierFromStatusRegistry(statusRegistry);
1823
- const metadataFilteredDocuments = applyFilters(allDocuments, options, typeRegistry, runtimeFieldFilters, statusFilter, lifecycleClassifier);
1824
- const filteredDocuments = applyExactQueryFilters(metadataFilteredDocuments, normalizedQuery, {
1825
- titleExact,
1826
- // --match-mode exact reuses the exact-phrase containment logic so the whole
1827
- // normalized query must appear as a contiguous phrase in some searchable field.
1828
- phraseExact: phraseExact || matchMode === "exact",
1900
+ const hits = computeBuiltInBm25Hits({
1901
+ requestedMode: runtime.effectiveMode,
1902
+ query: prepared.query,
1903
+ filteredDocuments,
1904
+ keywordHits,
1905
+ corpusFields: resolveSearchCorpusFields(runtime.settings),
1906
+ bm25Params: resolveBm25Params(runtime.settings),
1907
+ hybridSemanticWeight: runtime.hybridSemanticWeight,
1829
1908
  });
1830
- if (effectiveMode === "keyword" && (filteredDocuments.length === 0 || limit === 0)) {
1831
- return emptySearchResult(query, effectiveMode, matchMode, options, includeLinked, scoreThreshold, hybridSemanticWeight, queryExpansion, rerank, projection, warnings, runtimeFieldFilters, countOnly);
1909
+ if (runtime.bm25Mode === "auto-fallback") {
1910
+ warnings.push(`search_${runtime.effectiveMode}_offline_bm25:no_embedding_provider:using_lexical_bm25`);
1832
1911
  }
1833
- const projectRoot = process.cwd();
1834
- const globalRoot = resolveGlobalPmRoot(projectRoot);
1835
- const linkedCorpusById = new Map();
1836
- if (includeLinked && (effectiveMode === "keyword" || effectiveMode === "hybrid")) {
1837
- const linkedCorpusRoots = await resolveLinkedCorpusRoots(projectRoot, globalRoot);
1838
- const linkedCorpusEntries = await Promise.all(filteredDocuments.map(async (document) => [document.metadata.id, await loadLinkedCorpus(document, linkedCorpusRoots)]));
1839
- for (const [id, corpus] of linkedCorpusEntries) {
1840
- linkedCorpusById.set(id, corpus);
1912
+ return hits;
1913
+ }
1914
+ async function executeExtensionSearchProvider(prepared, runtime, filteredDocuments, filteredById) {
1915
+ if (!runtime.extensionSearchProvider) {
1916
+ return null;
1917
+ }
1918
+ const canUseBuiltInSemantic = runtime.providerResolution.active !== null &&
1919
+ (runtime.vectorResolution.active !== null || runtime.extensionVectorAdapter !== null);
1920
+ try {
1921
+ const providerResponse = await Promise.resolve(runtime.extensionSearchProvider.query({
1922
+ query: prepared.query,
1923
+ mode: runtime.effectiveMode,
1924
+ tokens: prepared.tokens,
1925
+ options: prepared.options,
1926
+ settings: runtime.settings,
1927
+ documents: filteredDocuments,
1928
+ }));
1929
+ return normalizeExtensionProviderHits(runtime.extensionSearchProvider.providerName, providerResponse, filteredById);
1930
+ }
1931
+ catch (error) {
1932
+ if (!canUseBuiltInSemantic) {
1933
+ throw new PmCliError(`Extension search provider "${runtime.extensionSearchProvider.providerName}" failed: ${error instanceof Error ? error.message : String(error)}`, EXIT_CODE.GENERIC_FAILURE);
1841
1934
  }
1935
+ return null;
1842
1936
  }
1843
- // GH-181: the all-terms coverage RANKING bonus only applies in default OR mode
1844
- // (no hard term filter) so multi-term queries prefer items covering all tokens.
1845
- // and/exact modes hard-filter instead, so the additive bonus would be redundant.
1846
- const applyCoverageBonus = matchMode === "or";
1847
- const keywordHits = filteredDocuments
1848
- .map((document) => buildHybridLexicalScore(document, tokens, normalizedQuery,
1849
- // Linked corpus is only collected into linkedCorpusById when the user
1850
- // passed --include-linked (and mode is keyword/hybrid), so pass the
1851
- // parsed flag directly rather than re-deriving it from the mode.
1852
- includeLinked, linkedCorpusById, tuning, settings.id_prefix, applyCoverageBonus))
1853
- .filter((entry) => entry !== null)
1854
- // --match-mode and: hard-filter to items where EVERY distinct query token
1855
- // matched some searchable field.
1856
- .filter((entry) => matchMode !== "and" || entry.matched_all_terms === true);
1937
+ }
1938
+ function maybeApplyNoVectorFallback(effectiveMode, semanticResult, keywordHits, warnings) {
1939
+ if (semanticResult.vectorMatchCount > 0) {
1940
+ return semanticResult.hits;
1941
+ }
1942
+ warnings.push(`search_${effectiveMode}_degraded:no_vector_matches:results_are_lexical`);
1943
+ return effectiveMode === "semantic" ? keywordHits : semanticResult.hits;
1944
+ }
1945
+ async function prepareBuiltInSemanticSearch(runtime, effectiveMode, filteredDocuments, warnings, modeWasExplicit) {
1946
+ const builtInSemanticWillRun = !runtime.extensionSearchProvider &&
1947
+ runtime.providerResolution.active !== null &&
1948
+ (runtime.vectorResolution.active !== null || runtime.extensionVectorAdapter !== null);
1949
+ if (modeWasExplicit && builtInSemanticWillRun) {
1950
+ await maybeEmitVectorIndexStaleWarning(runtime.pmRoot, filteredDocuments, warnings);
1951
+ }
1952
+ if (!runtime.extensionSearchProvider) {
1953
+ requireSemanticDependencies(effectiveMode, runtime.providerResolution, runtime.vectorResolution, runtime.extensionVectorAdapter !== null);
1954
+ }
1955
+ }
1956
+ async function executeSemanticSearch(input) {
1957
+ const { prepared, runtime, filteredDocuments, keywordHits, warnings, modeWasExplicit } = input;
1857
1958
  let hits = keywordHits;
1858
- // pm-75k9: offline BM25 path. Runs entirely in-process (no embedding service,
1859
- // vector store, or HTTP), so it sits OUTSIDE the semantic try/catch fallback
1860
- // block below it cannot fail on a backend error. Empty corpus / limit-0 are
1861
- // handled by the shared threshold+limit path that follows, so no early-return
1862
- // guard is needed here.
1863
- const useBuiltInBm25 = bm25Mode !== null && effectiveMode !== "keyword";
1864
- if (bm25Mode !== null && effectiveMode !== "keyword") {
1865
- hits = computeBuiltInBm25Hits({
1866
- requestedMode: effectiveMode,
1867
- query,
1868
- filteredDocuments,
1869
- keywordHits,
1870
- corpusFields: resolveSearchCorpusFields(settings),
1871
- bm25Params: resolveBm25Params(settings),
1872
- hybridSemanticWeight,
1873
- });
1874
- if (bm25Mode === "auto-fallback") {
1875
- warnings.push(`search_${effectiveMode}_offline_bm25:no_embedding_provider:using_lexical_bm25`);
1876
- }
1959
+ const bm25Hits = await executeBuiltInBm25Search(prepared, runtime, filteredDocuments, keywordHits, warnings);
1960
+ const semanticMode = runtime.effectiveMode;
1961
+ if (bm25Hits !== null || semanticMode === "keyword") {
1962
+ return { effectiveMode: runtime.effectiveMode, hits: bm25Hits ?? hits };
1877
1963
  }
1878
- /* c8 ignore start -- semantic/provider fallback + compact/count warning-shape permutations are covered by integration command-contract tests */
1879
- if (effectiveMode !== "keyword" && !useBuiltInBm25) {
1880
- // Surface vector-index staleness once per query so agents notice when a
1881
- // refresh is overdue. Only emitted when:
1882
- // (1) the user explicitly asked for semantic/hybrid mode (implicit
1883
- // upgrades fall back silently to keyword on any failure path below
1884
- // and shouldn't carry noise), AND
1885
- // (2) the BUILT-IN semantic path is what will run — an extension search
1886
- // provider has its own indexing lifecycle and the local ledger we
1887
- // read is irrelevant to it.
1888
- const builtInSemanticWillRun = !extensionSearchProvider &&
1889
- providerResolution.active !== null &&
1890
- (vectorResolution.active !== null || extensionVectorAdapter !== null);
1891
- if (modeWasExplicit && builtInSemanticWillRun) {
1892
- await maybeEmitVectorIndexStaleWarning(pmRoot, filteredDocuments, warnings);
1893
- }
1894
- try {
1895
- if (!extensionSearchProvider) {
1896
- requireSemanticDependencies(effectiveMode, providerResolution, vectorResolution, extensionVectorAdapter !== null);
1897
- }
1898
- if (filteredDocuments.length === 0 || limit === 0) {
1899
- return emptySearchResult(query, effectiveMode, matchMode, options, includeLinked, scoreThreshold, hybridSemanticWeight, queryExpansion, rerank, projection, warnings, runtimeFieldFilters, countOnly);
1900
- }
1901
- const filteredById = new Map(filteredDocuments.map((document) => [document.metadata.id, document]));
1902
- const canUseBuiltInSemantic = providerResolution.active !== null && (vectorResolution.active !== null || extensionVectorAdapter !== null);
1903
- if (extensionSearchProvider) {
1904
- try {
1905
- const providerResponse = await Promise.resolve(extensionSearchProvider.query({
1906
- query,
1907
- mode: effectiveMode,
1908
- tokens,
1909
- options,
1910
- settings,
1911
- documents: filteredDocuments,
1912
- }));
1913
- hits = normalizeExtensionProviderHits(extensionSearchProvider.providerName, providerResponse, filteredById);
1914
- }
1915
- catch (error) {
1916
- if (!canUseBuiltInSemantic) {
1917
- throw new PmCliError(`Extension search provider "${extensionSearchProvider.providerName}" failed: ${error instanceof Error ? error.message : String(error)}`, EXIT_CODE.GENERIC_FAILURE);
1918
- }
1919
- }
1920
- }
1921
- if (hits === keywordHits) {
1922
- const implicitHybridMode = !modeWasExplicit && effectiveMode === "hybrid";
1923
- const { provider, vectorStore } = requireSemanticDependencies(effectiveMode, providerResolution, vectorResolution, extensionVectorAdapter !== null);
1924
- const semanticResult = await computeSemanticOrHybridHits({
1925
- requestedMode: effectiveMode,
1926
- query,
1927
- filteredDocuments,
1928
- keywordHits,
1929
- hybridSemanticWeight,
1930
- limit,
1931
- maxResults,
1932
- provider,
1933
- vectorStore,
1934
- extensionVectorAdapter,
1935
- queryExpansion,
1936
- queryExpansionExtension,
1937
- rerank,
1938
- rerankExtension,
1939
- warnings,
1940
- settings,
1941
- /* c8 ignore next 5 -- reserved for future implicit-hybrid auto-mode; current parseMode defaults keyword when mode is omitted */
1942
- ...(implicitHybridMode
1943
- ? {
1944
- embeddingTimeoutMs: IMPLICIT_HYBRID_EMBEDDING_TIMEOUT_MS,
1945
- vectorQueryTimeoutMs: IMPLICIT_HYBRID_VECTOR_TIMEOUT_MS,
1946
- }
1947
- : {}),
1948
- });
1949
- hits = semanticResult.hits;
1950
- // The semantic/hybrid query ran without error, but vector ranking
1951
- // contributed no hits for this query/filter set. Pure semantic mode would
1952
- // otherwise return an empty set, so degrade to the locally computed
1953
- // keyword hits (hybrid already blends them in) and warn so agents do not
1954
- // mistake them for true vector ranking. The reported mode is left
1955
- // unchanged; the warning is the signal.
1956
- if (semanticResult.vectorMatchCount === 0) {
1957
- if (effectiveMode === "semantic") {
1958
- hits = keywordHits;
1959
- }
1960
- warnings.push(`search_${effectiveMode}_degraded:no_vector_matches:results_are_lexical`);
1961
- }
1962
- }
1963
- }
1964
- catch (error) {
1965
- // Any semantic/hybrid attempt that fails (backend down, timeout, or the
1966
- // project is not configured for semantic search) degrades to keyword mode
1967
- // so agents are never blocked. Keyword hits are always computed locally
1968
- // before this point, so the fallback is guaranteed to succeed.
1969
- const fallbackWarning = modeWasExplicit
1970
- ? buildExplicitSemanticFallbackWarning(effectiveMode, error)
1971
- /* c8 ignore next -- reserved for future implicit semantic/hybrid auto-mode fallback */
1972
- : buildImplicitSemanticFallbackWarning(error);
1973
- effectiveMode = "keyword";
1974
- hits = keywordHits;
1975
- warnings.push(fallbackWarning);
1964
+ try {
1965
+ await prepareBuiltInSemanticSearch(runtime, semanticMode, filteredDocuments, warnings, modeWasExplicit);
1966
+ if (filteredDocuments.length === 0 || prepared.limit === 0) {
1967
+ return { effectiveMode: runtime.effectiveMode, hits: [] };
1976
1968
  }
1977
- }
1978
- // GH-281: an exact full-ID / short-ID match is always retained regardless of
1979
- // the (possibly user-raised --min-score) threshold so the exact-target lookup
1980
- // is never silently dropped in any mode.
1981
- const thresholded = hits.filter((entry) => entry.exact_id_match === true || entry.score >= scoreThreshold);
1982
- const sorted = sortHits(thresholded, statusRegistry);
1983
- // total = matched hits after filters + threshold, BEFORE limit truncation.
1984
- const total = sorted.length;
1985
- // GH-181: keyword mode now also falls back to the configured max_results (50)
1986
- // default when --limit is omitted, so a broad query no longer returns ALL hits.
1987
- const resolvedLimit = limit ?? maxResults;
1988
- const limited = sorted.slice(0, resolvedLimit);
1989
- const projectionFields = projection.mode === "full" ? null : [...projection.fields];
1990
- const compactSummaryMode = projection.mode === "compact" && options.compact === true;
1991
- // --count: count-only response. Skips projecting/returning hit rows entirely so
1992
- // an agent asking "how many" pays minimal tokens. `count` carries the matched
1993
- // total (post-filter, post-threshold, pre-limit).
1994
- if (countOnly) {
1995
- if (compactSummaryMode) {
1996
- const compactFilters = buildCompactSearchFilterSummary({
1997
- mode: effectiveMode,
1998
- matchMode,
1999
- options,
2000
- includeLinked,
2001
- titleExact,
2002
- phraseExact,
2003
- scoreThreshold,
2004
- hybridSemanticWeight,
2005
- runtimeFieldFilters,
1969
+ const filteredById = new Map(filteredDocuments.map((document) => [document.metadata.id, document]));
1970
+ hits = await executeExtensionSearchProvider(prepared, runtime, filteredDocuments, filteredById) ?? hits;
1971
+ if (hits === keywordHits) {
1972
+ const { provider, vectorStore } = requireSemanticDependencies(semanticMode, runtime.providerResolution, runtime.vectorResolution, runtime.extensionVectorAdapter !== null);
1973
+ const semanticResult = await computeSemanticOrHybridHits({
1974
+ requestedMode: semanticMode,
1975
+ query: prepared.query,
1976
+ filteredDocuments,
1977
+ keywordHits,
1978
+ hybridSemanticWeight: runtime.hybridSemanticWeight,
1979
+ limit: prepared.limit,
1980
+ maxResults: runtime.maxResults,
1981
+ provider,
1982
+ vectorStore,
1983
+ extensionVectorAdapter: runtime.extensionVectorAdapter,
1984
+ queryExpansion: runtime.queryExpansion,
1985
+ queryExpansionExtension: runtime.queryExpansionExtension,
1986
+ rerank: runtime.rerank,
1987
+ rerankExtension: runtime.rerankExtension,
1988
+ warnings,
1989
+ settings: runtime.settings,
2006
1990
  });
2007
- return {
2008
- query: query.trim(),
2009
- mode: effectiveMode,
2010
- items: [],
2011
- count: total,
2012
- total,
2013
- count_only: true,
2014
- filters: compactFilters,
2015
- ...(warnings.length > 0 ? { warnings } : {}),
2016
- };
1991
+ hits = maybeApplyNoVectorFallback(semanticMode, semanticResult, keywordHits, warnings);
2017
1992
  }
2018
- return {
2019
- query: query.trim(),
2020
- mode: effectiveMode,
1993
+ return { effectiveMode: runtime.effectiveMode, hits };
1994
+ }
1995
+ catch (error) {
1996
+ warnings.push(buildExplicitSemanticFallbackWarning(runtime.effectiveMode, error));
1997
+ return { effectiveMode: "keyword", hits: keywordHits };
1998
+ }
1999
+ }
2000
+ function buildCountOnlySearchResult(response, total) {
2001
+ if (response.projection.mode === "compact" && response.options.compact === true) {
2002
+ return withSearchWarnings({
2003
+ query: response.query.trim(),
2004
+ mode: response.effectiveMode,
2021
2005
  items: [],
2022
2006
  count: total,
2023
2007
  total,
2024
2008
  count_only: true,
2025
- filters: buildVerboseSearchFilters({
2026
- effectiveMode,
2027
- matchMode,
2028
- options,
2029
- includeLinked,
2030
- titleExact,
2031
- phraseExact,
2032
- scoreThreshold,
2033
- hybridSemanticWeight,
2034
- queryExpansion,
2035
- rerank,
2036
- runtimeFieldFilters,
2009
+ filters: buildCompactSearchFilterSummary({
2010
+ mode: response.effectiveMode,
2011
+ matchMode: response.matchMode,
2012
+ options: response.options,
2013
+ includeLinked: response.includeLinked,
2014
+ titleExact: response.titleExact,
2015
+ phraseExact: response.phraseExact,
2016
+ scoreThreshold: response.scoreThreshold,
2017
+ hybridSemanticWeight: response.hybridSemanticWeight,
2018
+ runtimeFieldFilters: response.runtimeFieldFilters,
2037
2019
  }),
2038
- projection: {
2039
- mode: projection.mode,
2040
- fields: projectionFields,
2041
- },
2042
- now: nowIso(),
2043
- ...(warnings.length > 0 ? { warnings } : {}),
2044
- };
2020
+ }, response.warnings);
2045
2021
  }
2046
- // GH-157 --highlight: attach per-field matched-text snippets to the returned
2047
- // page of hits (only the post-limit slice pays the cost). In compact/fields
2048
- // projections we add "highlights" to the projected field set so the snippets
2049
- // are actually emitted; full mode already carries them on the hit.
2050
- let projectedHits = limited;
2051
- let effectiveProjection = projection;
2052
- if (highlight) {
2053
- const documentById = new Map(filteredDocuments.map((document) => [document.metadata.id, document]));
2054
- projectedHits = limited.map((hit) => ({
2055
- ...hit,
2056
- highlights: buildHitHighlights(documentById.get(hit.item.id), hit.matched_fields, tokens),
2057
- }));
2058
- if (projection.mode !== "full" && !projection.fields.includes("highlights")) {
2059
- effectiveProjection = { mode: projection.mode, fields: [...projection.fields, "highlights"] };
2060
- }
2022
+ const projectionFields = response.projection.mode === "full" ? null : [...response.projection.fields];
2023
+ return withSearchWarnings({
2024
+ query: response.query.trim(),
2025
+ mode: response.effectiveMode,
2026
+ items: [],
2027
+ count: total,
2028
+ total,
2029
+ count_only: true,
2030
+ filters: buildVerboseSearchFilters({
2031
+ effectiveMode: response.effectiveMode,
2032
+ matchMode: response.matchMode,
2033
+ options: response.options,
2034
+ includeLinked: response.includeLinked,
2035
+ titleExact: response.titleExact,
2036
+ phraseExact: response.phraseExact,
2037
+ scoreThreshold: response.scoreThreshold,
2038
+ hybridSemanticWeight: response.hybridSemanticWeight,
2039
+ queryExpansion: response.queryExpansion,
2040
+ rerank: response.rerank,
2041
+ runtimeFieldFilters: response.runtimeFieldFilters,
2042
+ }),
2043
+ projection: {
2044
+ mode: response.projection.mode,
2045
+ fields: projectionFields,
2046
+ },
2047
+ now: nowIso(),
2048
+ }, response.warnings);
2049
+ }
2050
+ function withSearchWarnings(result, warnings) {
2051
+ if (warnings.length === 0) {
2052
+ return result;
2061
2053
  }
2062
- const projectedItems = projectSearchHits(projectedHits, effectiveProjection);
2063
- const finalProjectionFields = effectiveProjection.mode === "full" ? null : [...effectiveProjection.fields];
2064
- // Surface the pre-limit total only when the limit actually dropped rows.
2065
- const truncationExtras = limited.length < total ? { total } : {};
2066
- if (compactSummaryMode) {
2067
- const compactFilters = buildCompactSearchFilterSummary({
2068
- mode: effectiveMode,
2069
- matchMode,
2070
- options,
2071
- includeLinked,
2072
- titleExact,
2073
- phraseExact,
2074
- scoreThreshold,
2075
- hybridSemanticWeight,
2076
- runtimeFieldFilters,
2077
- });
2078
- return {
2079
- query: query.trim(),
2080
- mode: effectiveMode,
2054
+ return { ...result, warnings };
2055
+ }
2056
+ function attachSearchHighlights(prepared, filteredDocuments, limited) {
2057
+ if (!prepared.highlight) {
2058
+ return { hits: limited, projection: prepared.projection };
2059
+ }
2060
+ const documentById = new Map(filteredDocuments.map((document) => [document.metadata.id, document]));
2061
+ const hits = limited.map((hit) => ({
2062
+ ...hit,
2063
+ highlights: buildHitHighlights(documentById.get(hit.item.id), hit.matched_fields, prepared.tokens),
2064
+ }));
2065
+ if (prepared.projection.mode === "full" || prepared.projection.fields.includes("highlights")) {
2066
+ return { hits, projection: prepared.projection };
2067
+ }
2068
+ return { hits, projection: { mode: prepared.projection.mode, fields: [...prepared.projection.fields, "highlights"] } };
2069
+ }
2070
+ function buildSearchResultForHits(response, projectedItems, total, limitedCount, effectiveProjection) {
2071
+ const truncationExtras = limitedCount < total ? { total } : {};
2072
+ if (response.projection.mode === "compact" && response.options.compact === true) {
2073
+ return withSearchWarnings({
2074
+ query: response.query.trim(),
2075
+ mode: response.effectiveMode,
2081
2076
  items: projectedItems,
2082
2077
  count: projectedItems.length,
2083
2078
  ...truncationExtras,
2084
- filters: compactFilters,
2085
- ...(warnings.length > 0 ? { warnings } : {}),
2086
- };
2079
+ filters: buildCompactSearchFilterSummary({
2080
+ mode: response.effectiveMode,
2081
+ matchMode: response.matchMode,
2082
+ options: response.options,
2083
+ includeLinked: response.includeLinked,
2084
+ titleExact: response.titleExact,
2085
+ phraseExact: response.phraseExact,
2086
+ scoreThreshold: response.scoreThreshold,
2087
+ hybridSemanticWeight: response.hybridSemanticWeight,
2088
+ runtimeFieldFilters: response.runtimeFieldFilters,
2089
+ }),
2090
+ }, response.warnings);
2087
2091
  }
2088
- /* c8 ignore stop */
2092
+ const finalProjectionFields = effectiveProjection.mode === "full" ? null : [...effectiveProjection.fields];
2089
2093
  return {
2090
- query: query.trim(),
2091
- mode: effectiveMode,
2094
+ query: response.query.trim(),
2095
+ mode: response.effectiveMode,
2092
2096
  items: projectedItems,
2093
2097
  count: projectedItems.length,
2094
2098
  ...truncationExtras,
2095
2099
  filters: buildVerboseSearchFilters({
2096
- effectiveMode,
2097
- matchMode,
2098
- options,
2099
- includeLinked,
2100
- titleExact,
2101
- phraseExact,
2102
- scoreThreshold,
2103
- hybridSemanticWeight,
2104
- queryExpansion,
2105
- rerank,
2106
- runtimeFieldFilters,
2100
+ effectiveMode: response.effectiveMode,
2101
+ matchMode: response.matchMode,
2102
+ options: response.options,
2103
+ includeLinked: response.includeLinked,
2104
+ titleExact: response.titleExact,
2105
+ phraseExact: response.phraseExact,
2106
+ scoreThreshold: response.scoreThreshold,
2107
+ hybridSemanticWeight: response.hybridSemanticWeight,
2108
+ queryExpansion: response.queryExpansion,
2109
+ rerank: response.rerank,
2110
+ runtimeFieldFilters: response.runtimeFieldFilters,
2107
2111
  }),
2108
2112
  projection: {
2109
2113
  mode: effectiveProjection.mode,
2110
2114
  fields: finalProjectionFields,
2111
2115
  },
2112
2116
  now: nowIso(),
2113
- ...(warnings.length > 0 ? { warnings } : {}),
2117
+ ...(response.warnings.length > 0 ? { warnings: response.warnings } : {}),
2114
2118
  };
2115
2119
  }
2120
+ /**
2121
+ * Implements run search for the public runtime surface of this module.
2122
+ */
2123
+ export async function runSearch(rawQuery, rawOptions, global) {
2124
+ const prepared = prepareSearchInput(rawQuery, rawOptions);
2125
+ const runtime = await resolveSearchRuntimeContext(prepared, global);
2126
+ const corpus = await loadFilteredSearchCorpus(prepared, runtime);
2127
+ const warnings = corpus.warnings;
2128
+ warnings.push(...prepared.inlineWarnings);
2129
+ if (runtime.effectiveMode === "hybrid" && runtime.semanticWeightProvided && runtime.semanticWeightOverride === undefined) {
2130
+ warnings.push("search_hybrid_semantic_weight_override_invalid:using_settings_default");
2131
+ }
2132
+ const responseBase = {
2133
+ query: prepared.query,
2134
+ matchMode: prepared.matchMode,
2135
+ options: prepared.options,
2136
+ includeLinked: prepared.includeLinked,
2137
+ titleExact: prepared.titleExact,
2138
+ phraseExact: prepared.phraseExact,
2139
+ scoreThreshold: runtime.scoreThreshold,
2140
+ hybridSemanticWeight: runtime.hybridSemanticWeight,
2141
+ queryExpansion: runtime.queryExpansion,
2142
+ rerank: runtime.rerank,
2143
+ projection: prepared.projection,
2144
+ warnings,
2145
+ runtimeFieldFilters: runtime.runtimeFieldFilters,
2146
+ };
2147
+ if (runtime.effectiveMode === "keyword" && (corpus.filteredDocuments.length === 0 || prepared.limit === 0)) {
2148
+ return buildEmptySearchResultFromContext({ ...responseBase, effectiveMode: runtime.effectiveMode }, prepared.countOnly);
2149
+ }
2150
+ const keywordHits = await computeKeywordSearchHits(prepared, runtime, corpus.filteredDocuments);
2151
+ const modeResult = await executeSemanticSearch({
2152
+ prepared,
2153
+ runtime,
2154
+ filteredDocuments: corpus.filteredDocuments,
2155
+ keywordHits,
2156
+ warnings,
2157
+ modeWasExplicit: prepared.modeWasExplicit,
2158
+ });
2159
+ if (modeResult.effectiveMode !== "keyword" && modeResult.hits.length === 0 && (corpus.filteredDocuments.length === 0 || prepared.limit === 0)) {
2160
+ return buildEmptySearchResultFromContext({ ...responseBase, effectiveMode: modeResult.effectiveMode }, prepared.countOnly);
2161
+ }
2162
+ const thresholded = modeResult.hits.filter((entry) => entry.exact_id_match === true || entry.score >= runtime.scoreThreshold);
2163
+ const sorted = sortHits(thresholded, runtime.statusRegistry);
2164
+ const total = sorted.length;
2165
+ const resolvedLimit = prepared.limit ?? runtime.maxResults;
2166
+ const limited = sorted.slice(0, resolvedLimit);
2167
+ const response = { ...responseBase, effectiveMode: modeResult.effectiveMode };
2168
+ if (prepared.countOnly) {
2169
+ return buildCountOnlySearchResult(response, total);
2170
+ }
2171
+ const { hits: projectedHits, projection: effectiveProjection } = attachSearchHighlights(prepared, corpus.filteredDocuments, limited);
2172
+ const projectedItems = projectSearchHits(projectedHits, effectiveProjection);
2173
+ return buildSearchResultForHits(response, projectedItems, total, limited.length, effectiveProjection);
2174
+ }
2116
2175
  //# sourceMappingURL=search.js.map
2117
- //# debugId=0417fe76-c2a2-5a0a-82f3-0861f46175e9
2176
+ //# debugId=fe9c6a3a-fb99-53ed-9a6c-8c32bb745364