winclaw 2026.3.21 → 2026.3.22

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 (338) hide show
  1. package/dist/{accounts-CTJXIABG.js → accounts-8qwgz384.js} +1 -1
  2. package/dist/{accounts-CLKFSM00.js → accounts-BpS-Awr5.js} +1 -1
  3. package/dist/{accounts-cYG8442L.js → accounts-BrWJjaKS.js} +7 -7
  4. package/dist/{acp-cli-BbN2vTHD.js → acp-cli-BMM5ssNE.js} +8 -8
  5. package/dist/{agent-scope-D-i-vMLS.js → agent-scope-Dany4R2i.js} +17 -17
  6. package/dist/{agents-_gcdm-kb.js → agents-AMH_Bmb6.js} +14 -14
  7. package/dist/{agents.config-BkgsJJng.js → agents.config-6n_jmCMa.js} +2 -2
  8. package/dist/{api-key-rotation-D_JdsLIl.js → api-key-rotation-C9ywPLG3.js} +1 -1
  9. package/dist/{audio-preflight-CdgtLVh2.js → audio-preflight-D7UvXGlQ.js} +34 -34
  10. package/dist/{audio-preflight-CBWXmKyj.js → audio-preflight-DHeEYciJ.js} +4 -4
  11. package/dist/{audio-transcription-runner-DpvjaNmr.js → audio-transcription-runner-1-9PFrzh.js} +1 -1
  12. package/dist/{audio-transcription-runner-DGZYB2Wq.js → audio-transcription-runner-nnwJufig.js} +23 -23
  13. package/dist/{audit-DdcsBl_-.js → audit-DV_kf1sd.js} +29 -29
  14. package/dist/{auth-CU4HqNch.js → auth-Ahj-1B5R.js} +1 -1
  15. package/dist/{auth-choice-CtzD_rrW.js → auth-choice-NjkwJsBG.js} +13 -13
  16. package/dist/{auth-choice-i771W71t.js → auth-choice-dFTD1hLR.js} +11 -11
  17. package/dist/{auth-choice.apply-helpers-Bmj9LZnO.js → auth-choice.apply-helpers-ClzwLPaB.js} +1 -1
  18. package/dist/{auth-profiles-CmoHF97e.js → auth-profiles-DF0cLC20.js} +16 -16
  19. package/dist/{auth-token-C_S_Uszj.js → auth-token-BXCBtI3p.js} +1 -1
  20. package/dist/{banner-C-01b-if.js → banner-BB4DFL8E.js} +2 -2
  21. package/dist/{bonjour-discovery-BxCVyJLG.js → bonjour-discovery-BVSpbdjs.js} +1 -1
  22. package/dist/{browser-cli-Rt_P1-M1.js → browser-cli-DAcccrxR.js} +12 -12
  23. package/dist/build-info.json +2 -2
  24. package/dist/bundled/boot-md/handler.js +6 -6
  25. package/dist/bundled/session-memory/handler.js +6 -6
  26. package/dist/{call-BLyRfBMl.js → call-DEKH5GO9.js} +10 -10
  27. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  28. package/dist/{channel-account-context-B4ofKr9t.js → channel-account-context-D4Yftz20.js} +5 -5
  29. package/dist/{channel-activity-CPWF8YR5.js → channel-activity-D03SwGPA.js} +1 -1
  30. package/dist/{channel-options-it9Z3dNk.js → channel-options-C7dYNZsy.js} +3 -3
  31. package/dist/{channel-selection-5G2iw3CB.js → channel-selection-Bke39fer.js} +1 -1
  32. package/dist/{channel-web-CJ_jcZSw.js → channel-web-BOrAGcza.js} +17 -17
  33. package/dist/{channels-cli-miFqkj2-.js → channels-cli-4YLI7Ar_.js} +93 -93
  34. package/dist/{channels-status-issues-DpfEWI4l.js → channels-status-issues-wCgCdUDu.js} +1 -1
  35. package/dist/{chrome-RAfAR4xV.js → chrome-BDFA9lPV.js} +4 -4
  36. package/dist/{chrome-GsaZ074n.js → chrome-Cr8R7xl_.js} +8 -8
  37. package/dist/{clawbot-cli-HvFYYAc6.js → clawbot-cli-B96xAtzs.js} +11 -11
  38. package/dist/cli/daemon-cli.js +1 -1
  39. package/dist/cli-BozE7JCS.js +154 -0
  40. package/dist/{client-DCxDsURZ.js → client-jNFqrgw6.js} +2 -2
  41. package/dist/{command-registry-m8nfRV-J.js → command-registry-qDpes5Yr.js} +11 -11
  42. package/dist/{command-secret-targets-BfqkoJyp.js → command-secret-targets-Dd4qCPSg.js} +4 -4
  43. package/dist/{commands-4mnxaSoA.js → commands-DmBkhPD-.js} +1 -1
  44. package/dist/{commands-registry-h5KiQe_S.js → commands-registry-BB289Bg8.js} +3 -3
  45. package/dist/{completion-cli-B-8mTxbh.js → completion-cli-DzZieT3i.js} +13 -13
  46. package/dist/{config-cli-1ecjxVfC.js → config-cli-Dk1yc6M9.js} +7 -7
  47. package/dist/{config-guard-DlzKrdcR.js → config-guard-3fwTO4Mb.js} +3 -3
  48. package/dist/{config-validation-E-3Wz4C4.js → config-validation-5pIaju5U.js} +3 -3
  49. package/dist/{configure-B-tOY-wa.js → configure-CuqZCxTb.js} +17 -17
  50. package/dist/{control-ui-assets-B0DdamQU.js → control-ui-assets-5F0FEjfM.js} +1 -1
  51. package/dist/{cron-cli-DpVGzupl.js → cron-cli-BIa0VxDk.js} +11 -11
  52. package/dist/{daemon-cli-CqwUFobu.js → daemon-cli-BE11O7QX.js} +16 -16
  53. package/dist/{daemon-install-C029NlXk.js → daemon-install-DNhR8NtL.js} +4 -4
  54. package/dist/{daemon-install-helpers-D1YQ03lO.js → daemon-install-helpers-DWmF3oFP.js} +11 -11
  55. package/dist/{deliver-BX-UVg7x.js → deliver-CqiBzHnh.js} +7 -7
  56. package/dist/{deliver-CtyrAYix.js → deliver-r4_Yp7-C.js} +1 -1
  57. package/dist/{deliver-runtime-Bvh4te8E.js → deliver-runtime-CIXUsI5k.js} +3 -3
  58. package/dist/deliver-runtime-DJsAB9LW.js +57 -0
  59. package/dist/deps-send-discord.runtime-M8Cl0fms.js +32 -0
  60. package/dist/deps-send-imessage.runtime-Bing_Bvm.js +31 -0
  61. package/dist/deps-send-signal.runtime-CEnhoskG.js +30 -0
  62. package/dist/deps-send-slack.runtime-DeKWrOdA.js +28 -0
  63. package/dist/deps-send-telegram.runtime-K5LxxPog.js +34 -0
  64. package/dist/{deps-send-whatsapp.runtime-BJV7VcRP.js → deps-send-whatsapp.runtime-BXDQiU2D.js} +7 -7
  65. package/dist/deps-send-whatsapp.runtime-Cie2nrT8.js +115 -0
  66. package/dist/{devices-cli-Cpq_Gt1l.js → devices-cli-BJgUG9fc.js} +8 -8
  67. package/dist/{diagnostic-DIPYflOJ.js → diagnostic-BCcd-_zI.js} +1 -1
  68. package/dist/{diagnostics-KfpqzhsS.js → diagnostics-BDjbQJxP.js} +5 -5
  69. package/dist/{directory-cli-CPBPE8N1.js → directory-cli-CJ_l_BnF.js} +7 -7
  70. package/dist/{dns-cli-CI7HzCVI.js → dns-cli-CFau82Y7.js} +5 -5
  71. package/dist/{dock-ClcGZ0LV.js → dock-C-w5XvOS.js} +4 -4
  72. package/dist/{docs-cli-DkQBHXw-.js → docs-cli-BRob5CHm.js} +4 -4
  73. package/dist/{doctor-completion-DEdT-_9v.js → doctor-completion-DB39JNV7.js} +2 -2
  74. package/dist/{doctor-config-flow-D6rEqOwb.js → doctor-config-flow-BzYwmYwv.js} +15 -15
  75. package/dist/{enable-sRe0nI5a.js → enable-Qw-mz6ta.js} +1 -1
  76. package/dist/entry.js +2 -2
  77. package/dist/{exec-approvals-allowlist-B5ZdMbz6.js → exec-approvals-allowlist-BkdJCc3F.js} +1 -1
  78. package/dist/{exec-approvals-cli-BFxdGk9c.js → exec-approvals-cli-DsDGgzyV.js} +16 -16
  79. package/dist/{exec-safe-bin-runtime-policy-CB8atBLm.js → exec-safe-bin-runtime-policy-C5pAgyiz.js} +2 -2
  80. package/dist/{fetch-CdvuNDFE.js → fetch-BwrGQrFL.js} +3 -3
  81. package/dist/{fetch-guard-D-W6TRJN.js → fetch-guard-CHht1LfT.js} +1 -1
  82. package/dist/{plugin-sdk/fs-safe-DRACrdwg.js → fs-safe-B8J4dv27.js} +6 -6
  83. package/dist/{gateway-cli-C_4mlmOW.js → gateway-cli-BdyXCC2C.js} +154 -154
  84. package/dist/{gateway-rpc-Dg3CGljP.js → gateway-rpc-ICMh7-Qs.js} +1 -1
  85. package/dist/{health-C5a0wlfE.js → health-Boe965-L.js} +11 -11
  86. package/dist/{hooks-cli-C79J_WG7.js → hooks-cli-DI0sn396.js} +81 -81
  87. package/dist/{hooks-status-Cjg5SLpX.js → hooks-status-CQjtRM1s.js} +1 -1
  88. package/dist/{image-7s8Q2r40.js → image-DoOVDHql.js} +1 -1
  89. package/dist/{image-EjGWXbei.js → image-Dpt9TurJ.js} +5 -5
  90. package/dist/{image-ops-eFMqXMDE.js → image-ops-DWGnyTvC.js} +10 -10
  91. package/dist/image-runtime-HfAsK5X3.js +51 -0
  92. package/dist/{image-runtime-QNP_uABR.js → image-runtime-Wym8Keh3.js} +3 -3
  93. package/dist/{inspect-XmcWN97u.js → inspect-DbVcDDi7.js} +4 -4
  94. package/dist/{install-safe-path-DNotGe9T.js → install-safe-path-FR9r9Dmi.js} +25 -25
  95. package/dist/{installs-zKF10nZF.js → installs-7zsfIb7P.js} +9 -9
  96. package/dist/{ipv4-DIKCnoyz.js → ipv4-CfrDjvjo.js} +1 -1
  97. package/dist/{ir-CJPPU4LU.js → ir-B-FffSKU.js} +8 -8
  98. package/dist/{issue-format-DCF2SXK_.js → issue-format-NmLUfbBT.js} +1 -1
  99. package/dist/{json-files-kWpauJWO.js → json-files-D9ZHO8Ud.js} +8 -8
  100. package/dist/{lifecycle-core-BLhI5nRz.js → lifecycle-core-Di83_FGS.js} +5 -5
  101. package/dist/llm-slug-generator.js +6 -6
  102. package/dist/{login-D26qK4NQ.js → login-BrdFlfV0.js} +3 -3
  103. package/dist/{login-qr-CMgMlRCI.js → login-qr-Ci3FVgS9.js} +6 -6
  104. package/dist/{logs-cli-Cn7bGSc7.js → logs-cli-DUl4D14l.js} +9 -9
  105. package/dist/{manager-f6tniCBN.js → manager-2Wice7pq.js} +14 -14
  106. package/dist/manager-runtime-BrpO8pJp.js +22 -0
  107. package/dist/{manifest-registry-CI-UuKUO.js → manifest-registry-_liSV_Vx.js} +1 -1
  108. package/dist/{memory-cli-C2Yq9ryD.js → memory-cli-BgZK6A-T.js} +12 -12
  109. package/dist/{model-CXGHDOeN.js → model-C4J88Gi3.js} +2 -2
  110. package/dist/{model-catalog-08ftNXDk.js → model-catalog-BYxSwIkt.js} +3 -3
  111. package/dist/{model-picker-CTRi5Yhj.js → model-picker-DAr8DpKu.js} +4 -4
  112. package/dist/{models-Do96D4zT.js → models-DqwqcGxg.js} +17 -17
  113. package/dist/{models-cli-pblTciC_.js → models-cli-BFfUYhHp.js} +78 -78
  114. package/dist/{models-config-DYJ-p9kt.js → models-config-CJq2ywhf.js} +6 -6
  115. package/dist/{net-DQYHvbkN.js → net-C7TXXUto.js} +2 -2
  116. package/dist/{node-cli-CsQwAHzH.js → node-cli-DMpZsjse.js} +33 -33
  117. package/dist/{node-command-policy-BHdicfMO.js → node-command-policy-DGMJi4xw.js} +1 -1
  118. package/dist/{node-service-CLtiUeNO.js → node-service-L9-L8-7x.js} +1 -1
  119. package/dist/{nodes-cli-Dlilj-Pf.js → nodes-cli-BcyY77Cc.js} +16 -16
  120. package/dist/{nodes-screen-CL-8raxt.js → nodes-screen-B6QVlwKO.js} +7 -7
  121. package/dist/{npm-pack-install-DZvYhRnM.js → npm-pack-install-B3VCcNWC.js} +18 -18
  122. package/dist/{npm-resolution-DE7xcGkg.js → npm-resolution-0-Scs5nn.js} +4 -4
  123. package/dist/{onboard-CReGZ3G9.js → onboard-C9gtA3_b.js} +6 -6
  124. package/dist/{onboard-channels-ljMkIe7O.js → onboard-channels-NBqfiIc3.js} +21 -21
  125. package/dist/{onboard-custom-DoJDTzAW.js → onboard-custom-Cv61U_sa.js} +4 -4
  126. package/dist/{onboard-helpers-7lOdCHhD.js → onboard-helpers-Djj9SkyR.js} +10 -10
  127. package/dist/{onboard-hooks-BTD0YhRI.js → onboard-hooks-DRkLf5gL.js} +4 -4
  128. package/dist/{onboard-remote-Bj9uk3zW.js → onboard-remote-o8XtWCa_.js} +4 -4
  129. package/dist/{onboard-skills-1KAA9UrK.js → onboard-skills-TATKa-gc.js} +4 -4
  130. package/dist/{onboarding-CoH1hPY0.js → onboarding-C_LQ6doG.js} +14 -14
  131. package/dist/{onboarding.finalize-DzRWtkmA.js → onboarding.finalize-uHWzNBrm.js} +87 -87
  132. package/dist/{onboarding.gateway-config-s11ZLxLE.js → onboarding.gateway-config-ByvXJY2k.js} +18 -18
  133. package/dist/{onboarding.secret-input-D5VKqHdN.js → onboarding.secret-input-Cw4uIgyl.js} +1 -1
  134. package/dist/{openai-model-default-sYh2slgj.js → openai-model-default-Db9joqm4.js} +2 -2
  135. package/dist/{outbound-D0KF3CHY.js → outbound-DgsIsXfj.js} +3 -3
  136. package/dist/{outbound-attachment-CEC4H3tX.js → outbound-attachment-CjhkSZBR.js} +2 -2
  137. package/dist/{pairing-cli-4Nrc-V_v.js → pairing-cli-D0KKynjI.js} +8 -8
  138. package/dist/{pairing-labels-e3Pnen1C.js → pairing-labels-Ev8O2qBX.js} +1 -1
  139. package/dist/{pairing-store-Kslw_Wa0.js → pairing-store-CI0hWzZk.js} +3 -3
  140. package/dist/{plugin-sdk/path-alias-guards-CaCBZRHc.js → path-alias-guards-BoydiaPL.js} +1 -1
  141. package/dist/{path-safety-Cq9rwfZN.js → path-safety-CSCsbd-j.js} +1 -1
  142. package/dist/{paths-C5mR1YC-.js → paths-BVQ0udwc.js} +9 -9
  143. package/dist/{pi-embedded-DUO1eQ_J.js → pi-embedded-CD3oPGOP.js} +24 -24
  144. package/dist/{pi-embedded-helpers-BWpzwT6B.js → pi-embedded-helpers-Be8qWeKb.js} +6 -6
  145. package/dist/{pi-embedded-helpers-BMGRFCuV.js → pi-embedded-helpers-BthBxPYi.js} +3 -3
  146. package/dist/{pi-model-discovery-CibSv4gC.js → pi-model-discovery-CgxnCHvU.js} +1 -1
  147. package/dist/{pi-model-discovery-runtime-DhBE8w94.js → pi-model-discovery-runtime-CqYOz48r.js} +5 -5
  148. package/dist/{pi-tools.before-tool-call.runtime-D6h4CmLs.js → pi-tools.before-tool-call.runtime-CPnt06zM.js} +5 -5
  149. package/dist/{pi-tools.policy-BqpmC_c4.js → pi-tools.policy-DGbCC2Ji.js} +5 -5
  150. package/dist/{plugin-auto-enable-DnSZLbIH.js → plugin-auto-enable-Crpu18wt.js} +3 -3
  151. package/dist/{plugin-registry-DckyegZB.js → plugin-registry-Dbu4pN4B.js} +3 -3
  152. package/dist/plugin-sdk/imessage.js +2 -2
  153. package/dist/plugin-sdk/index.js +50 -50
  154. package/dist/plugin-sdk/mattermost.js +3 -3
  155. package/dist/plugin-sdk/signal.js +2 -2
  156. package/dist/plugin-sdk/telegram.js +2 -2
  157. package/dist/{plugins-C1OgLvb4.js → plugins-IFacUN_Q.js} +2 -2
  158. package/dist/{plugins-cli-C6Oo9R6E.js → plugins-cli-CCpaWcyg.js} +83 -83
  159. package/dist/{ports-CfOim1GC.js → ports-DqZBwUsy.js} +2 -2
  160. package/dist/{ports-Dw-3Gxsb.js → ports-FLn4cVl7.js} +1 -1
  161. package/dist/{probe-D3f6QMfy.js → probe-CHRXpP2F.js} +2 -2
  162. package/dist/{program-CEJ6CsoR.js → program-Br4Re78f.js} +81 -81
  163. package/dist/{prompt-select-styled-D-f3R2mt.js → prompt-select-styled-w-CGGgrT.js} +40 -40
  164. package/dist/{provider-auth-helpers-CN4iPBfs.js → provider-auth-helpers-BVCos07y.js} +5 -5
  165. package/dist/{proxy-env-B7GwrH5p.js → proxy-env-Bx8OhutV.js} +1 -1
  166. package/dist/{push-apns-BEZdCQsM.js → push-apns-Cdl2nskU.js} +5 -5
  167. package/dist/{pw-ai-Ckb-165q.js → pw-ai-BpQw305H.js} +18 -18
  168. package/dist/{pw-ai-D6e8FGb0.js → pw-ai-CJfoHUhH.js} +1 -1
  169. package/dist/{plugin-sdk/qmd-manager-JiY1T3wh.js → qmd-manager-COHJs6wn.js} +15 -11
  170. package/dist/{qr-cli-BI54tdt3.js → qr-cli-Bzo00_vR.js} +2 -2
  171. package/dist/{query-expansion-Cja4xprw.js → query-expansion-IQFdQdeu.js} +12 -12
  172. package/dist/{redact-snapshot-YrAxVxTI.js → redact-snapshot-Bfefch_D.js} +1 -1
  173. package/dist/{register.agent-BjxrirHi.js → register.agent-CVpohSrc.js} +94 -94
  174. package/dist/register.configure-CiIuig3f.js +162 -0
  175. package/dist/{register.maintenance-BfdiJ7KX.js → register.maintenance-CpVfbR8z.js} +95 -95
  176. package/dist/{register.message-BszoJEBm.js → register.message-CJErVRcL.js} +74 -74
  177. package/dist/{register.onboard-CbJU4Y-3.js → register.onboard-Cm5fn9dF.js} +18 -18
  178. package/dist/{register.setup-BTTBsCT0.js → register.setup-DIBDbMN8.js} +21 -21
  179. package/dist/{register.status-health-sessions-C3Ji8sqv.js → register.status-health-sessions-Bu3abDYw.js} +89 -89
  180. package/dist/{register.subclis-2iN-TxPh.js → register.subclis-DTiQUgvr.js} +31 -31
  181. package/dist/{rpc-4GcuaLHq.js → rpc-CkwrblZ9.js} +1 -1
  182. package/dist/{run-main-BEtPk_9z.js → run-main-4p7ridqP.js} +92 -92
  183. package/dist/{runtime-4RU4PT-H.js → runtime-C-9xWVep.js} +3 -3
  184. package/dist/{runtime-config-collectors-Ca2llf68.js → runtime-config-collectors-vw9ITu9W.js} +1 -1
  185. package/dist/{runtime-whatsapp-login.runtime-DOTrH3Wz.js → runtime-whatsapp-login.runtime-CrytFUOh.js} +7 -7
  186. package/dist/runtime-whatsapp-outbound.runtime-DOHkvY0R.js +28 -0
  187. package/dist/{sandbox-D19lOCVP.js → sandbox-CDjV0Crv.js} +18 -18
  188. package/dist/{sandbox-cli-DAZxiFQz.js → sandbox-cli-CyS9Kzp1.js} +25 -25
  189. package/dist/{secrets-cli-Bd2eDDOJ.js → secrets-cli-BPXW13bC.js} +11 -11
  190. package/dist/{security-cli-C6oO69to.js → security-cli-DfuX1PAw.js} +43 -43
  191. package/dist/{send-DR5zNR-6.js → send-BTQQeOIu.js} +6 -6
  192. package/dist/{send-3vnK2por.js → send-CFsJh6px.js} +11 -11
  193. package/dist/{send-DTvtOsK3.js → send-CM55Cnqy.js} +4 -4
  194. package/dist/{send-Bz5LPBFx.js → send-D7wKzeqg.js} +8 -8
  195. package/dist/{send-CEgqE2b1.js → send-DUJqLDEQ.js} +5 -5
  196. package/dist/{server-vPpafyBR.js → server-57rjxu9J.js} +20 -20
  197. package/dist/{server-context-FT_S05Zu.js → server-context-DdGwcBos.js} +12 -12
  198. package/dist/{server-lifecycle-YV61YmRr.js → server-lifecycle-TD7uRUJM.js} +2 -2
  199. package/dist/{server-middleware-BPI-0Duw.js → server-middleware-Dqzu_N47.js} +1 -1
  200. package/dist/{server-node-events-BozhXo6J.js → server-node-events-CstHr-4q.js} +74 -74
  201. package/dist/{service-Aratsspm.js → service-B45ntxm9.js} +15 -15
  202. package/dist/{session-C4iQQHfw.js → session-BO7rj_9P.js} +1 -1
  203. package/dist/{session-utils-CTpXGSxL.js → session-utils-DqzU9P2d.js} +6 -6
  204. package/dist/{sessions-CZvR93mC.js → sessions-BPbCt7hk.js} +4 -4
  205. package/dist/{sessions-Cvvux3S6.js → sessions-BUNwVEqF.js} +15 -15
  206. package/dist/{shared-ByZODVse.js → shared-CeHWQzSU.js} +3 -3
  207. package/dist/{shared-Cj-SPh02.js → shared-CpqkgNHp.js} +1 -1
  208. package/dist/{skill-commands-CzaT61kL.js → skill-commands-BlmjGaIe.js} +5 -5
  209. package/dist/{skill-scanner-DqqhF5of.js → skill-scanner-DOOfjrYo.js} +6 -6
  210. package/dist/{skills-BpN5EUZU.js → skills-CFYm0xdh.js} +3 -3
  211. package/dist/{skills-cli-Bk2WM5gn.js → skills-cli-Dmbm2-L8.js} +5 -5
  212. package/dist/{skills-install-0pjIZu1-.js → skills-install-DSB3T8VY.js} +6 -6
  213. package/dist/{skills-status-Bu28FGtt.js → skills-status-CmWpjTMz.js} +1 -1
  214. package/dist/{slash-commands.runtime-CU--cvcd.js → slash-commands.runtime-CTVGYo20.js} +11 -11
  215. package/dist/{slash-dispatch.runtime-DDLolsGY.js → slash-dispatch.runtime-CQmhrE1-.js} +6 -6
  216. package/dist/slash-dispatch.runtime-yKnwVCI5.js +110 -0
  217. package/dist/slash-skill-commands.runtime-BCG9eUm1.js +29 -0
  218. package/dist/{status-B5hylgEQ.js → status-DPFQHdBI.js} +28 -28
  219. package/dist/{status.update-CdaaXiD4.js → status.update-ZhDibzTU.js} +2 -2
  220. package/dist/{store-LSg8jeyh.js → store-Dgl-neCe.js} +5 -5
  221. package/dist/{subagent-registry-iD-ynHA9.js → subagent-registry-DPqc72Pw.js} +149 -149
  222. package/dist/{subagent-registry-runtime-DfMDVaOY.js → subagent-registry-runtime-BYxLgcCY.js} +6 -6
  223. package/dist/subagent-registry-runtime-DE-5902Y.js +110 -0
  224. package/dist/{system-cli-B8wmT3y0.js → system-cli-BiiO_z6k.js} +9 -9
  225. package/dist/{system-run-command-Ft0meR8i.js → system-run-command-CUMrwy8H.js} +1 -1
  226. package/dist/{systemd-CVY4-XuL.js → systemd-BNMfPHLS.js} +9 -9
  227. package/dist/{systemd-hints-GPX9Y1X7.js → systemd-hints-O9SJa5Ku.js} +6 -6
  228. package/dist/{systemd-linger-CyioH9ho.js → systemd-linger-CDgtOmPf.js} +1 -1
  229. package/dist/{tables-B6p8P9wY.js → tables-Bjpb4vEC.js} +1 -1
  230. package/dist/{tailnet-yScEfa2T.js → tailnet-C4yxhmDk.js} +1 -1
  231. package/dist/{plugin-sdk/target-errors-Hoj2qirZ.js → target-errors-Bd8kj4z9.js} +2 -2
  232. package/dist/{tool-images-Cp3hNFNZ.js → tool-images-DbchBdq5.js} +1 -1
  233. package/dist/{tui-BPqNtl51.js → tui-BVOPPCMP.js} +6 -6
  234. package/dist/{tui-cli-BZE2zssw.js → tui-cli-B2jmEXCo.js} +32 -32
  235. package/dist/{update-u6OtnABh.js → update-DF240Zd0.js} +3 -3
  236. package/dist/{update-cli-C1nysDmM.js → update-cli-PDG-KYWB.js} +105 -105
  237. package/dist/{update-runner-BpzbDTnQ.js → update-runner-BkpGT3AA.js} +16 -16
  238. package/dist/{web-CodV11ZY.js → web-0SOsmYmI.js} +6 -6
  239. package/dist/web-20qjCzeI.js +114 -0
  240. package/dist/{webhooks-cli-D4O_OfXU.js → webhooks-cli-N_vV0iXR.js} +6 -6
  241. package/dist/{whatsapp-actions-By2rV868.js → whatsapp-actions-X768ziyc.js} +17 -17
  242. package/dist/{winclaw-root-D0OUuGl7.js → winclaw-root-DEqOOeOw.js} +8 -8
  243. package/dist/{with-timeout-Cng0KnPd.js → with-timeout-DJb5ULbL.js} +3 -3
  244. package/dist/{workspace-vYy4qLQz.js → workspace-Cx-f7PO5.js} +1 -1
  245. package/dist/{workspace-dirs-C13vnqQQ.js → workspace-dirs-C5erYAob.js} +1 -1
  246. package/dist/{wsl-C9d12M7y.js → wsl-BisEqrSr.js} +2 -2
  247. package/package.json +1 -1
  248. package/dist/cli-Da0pNyXg.js +0 -154
  249. package/dist/deliver-runtime-Co5o7uv0.js +0 -57
  250. package/dist/deps-send-discord.runtime-D0BtA9iO.js +0 -32
  251. package/dist/deps-send-imessage.runtime-89fweiea.js +0 -31
  252. package/dist/deps-send-signal.runtime-BA3mNq_v.js +0 -30
  253. package/dist/deps-send-slack.runtime-DiA-Ieod.js +0 -28
  254. package/dist/deps-send-telegram.runtime-C9bLOnbt.js +0 -34
  255. package/dist/deps-send-whatsapp.runtime-Dflrvnq-.js +0 -115
  256. package/dist/fs-safe-Dha0DfFC.js +0 -352
  257. package/dist/image-runtime-CGAobfgI.js +0 -51
  258. package/dist/manager-runtime-BifbXCuI.js +0 -22
  259. package/dist/path-alias-guards-9OJ1UBCd.js +0 -43
  260. package/dist/plugin-sdk/accounts-B9lBByhz.js +0 -35
  261. package/dist/plugin-sdk/accounts-Bl6fp04N.js +0 -288
  262. package/dist/plugin-sdk/accounts-CQWq_42g.js +0 -46
  263. package/dist/plugin-sdk/active-listener-Dc-P7jeX.js +0 -50
  264. package/dist/plugin-sdk/api-key-rotation-DSOB99GV.js +0 -181
  265. package/dist/plugin-sdk/audio-preflight-DYTxAG0v.js +0 -69
  266. package/dist/plugin-sdk/audio-transcription-runner-Bndij5Q1.js +0 -2176
  267. package/dist/plugin-sdk/audit-membership-runtime-ZTTIhQhs.js +0 -58
  268. package/dist/plugin-sdk/channel-activity-ChRCQNSc.js +0 -94
  269. package/dist/plugin-sdk/channel-web-CfZNFYCV.js +0 -2256
  270. package/dist/plugin-sdk/chrome-DNpRdbZ1.js +0 -2415
  271. package/dist/plugin-sdk/commands-registry-Bq1HqcJU.js +0 -1125
  272. package/dist/plugin-sdk/config-Cyo0rHBx.js +0 -17959
  273. package/dist/plugin-sdk/deliver-mBruQPRt.js +0 -1719
  274. package/dist/plugin-sdk/deliver-runtime-ByVt0evu.js +0 -32
  275. package/dist/plugin-sdk/deps-send-discord.runtime-C2fc3t93.js +0 -23
  276. package/dist/plugin-sdk/deps-send-imessage.runtime-D4m7X6j4.js +0 -22
  277. package/dist/plugin-sdk/deps-send-signal.runtime-DwGJRjyX.js +0 -21
  278. package/dist/plugin-sdk/deps-send-slack.runtime-7J491hID.js +0 -19
  279. package/dist/plugin-sdk/deps-send-telegram.runtime-DAKGyd6b.js +0 -24
  280. package/dist/plugin-sdk/deps-send-whatsapp.runtime-BxQ5tZO2.js +0 -57
  281. package/dist/plugin-sdk/diagnostic-B3ZoSFoM.js +0 -319
  282. package/dist/plugin-sdk/errors-DdSHGcgi.js +0 -54
  283. package/dist/plugin-sdk/fetch-guard-Uhk4tySC.js +0 -156
  284. package/dist/plugin-sdk/image-CEBZ8sRh.js +0 -2314
  285. package/dist/plugin-sdk/image-ops-Dye2ozSZ.js +0 -584
  286. package/dist/plugin-sdk/image-runtime-CabQkSZn.js +0 -25
  287. package/dist/plugin-sdk/ir-CruONUHn.js +0 -1296
  288. package/dist/plugin-sdk/local-roots-BYSlR-at.js +0 -186
  289. package/dist/plugin-sdk/logger-C_vnHQg2.js +0 -1163
  290. package/dist/plugin-sdk/login-bdsdinOj.js +0 -57
  291. package/dist/plugin-sdk/login-qr-BYAvyop9.js +0 -320
  292. package/dist/plugin-sdk/manager-AOQxrU7P.js +0 -3929
  293. package/dist/plugin-sdk/manager-runtime-CijO5giX.js +0 -15
  294. package/dist/plugin-sdk/outbound-FdiP5J7H.js +0 -212
  295. package/dist/plugin-sdk/outbound-attachment-DZphVgq7.js +0 -19
  296. package/dist/plugin-sdk/paths-ICLB349I.js +0 -166
  297. package/dist/plugin-sdk/pi-embedded-helpers-tHjfJzH4.js +0 -9627
  298. package/dist/plugin-sdk/pi-model-discovery-DQV-B6bn.js +0 -134
  299. package/dist/plugin-sdk/pi-model-discovery-runtime-MJmZTIax.js +0 -8
  300. package/dist/plugin-sdk/pi-tools.before-tool-call.runtime-7DPjo7Ey.js +0 -354
  301. package/dist/plugin-sdk/plugins-BQHnLb2v.js +0 -864
  302. package/dist/plugin-sdk/proxy-fetch-BpMu-RpD.js +0 -38
  303. package/dist/plugin-sdk/pw-ai-DAMRoo8O.js +0 -1938
  304. package/dist/plugin-sdk/query-expansion-CuaTloKx.js +0 -1011
  305. package/dist/plugin-sdk/redact-BznLQ6I5.js +0 -319
  306. package/dist/plugin-sdk/reply-Cx_4UtvJ.js +0 -100211
  307. package/dist/plugin-sdk/resolve-outbound-target-BDjhohcf.js +0 -40
  308. package/dist/plugin-sdk/run-with-concurrency-BcPenaKJ.js +0 -1994
  309. package/dist/plugin-sdk/runtime-whatsapp-login.runtime-DqezqoLI.js +0 -10
  310. package/dist/plugin-sdk/runtime-whatsapp-outbound.runtime-Dgnv_x4o.js +0 -19
  311. package/dist/plugin-sdk/send-BWz-g7wE.js +0 -540
  312. package/dist/plugin-sdk/send-DB9pUM0k.js +0 -414
  313. package/dist/plugin-sdk/send-QPap4wBN.js +0 -503
  314. package/dist/plugin-sdk/send-gz4Lq5tL.js +0 -2587
  315. package/dist/plugin-sdk/send-tyEtWeMX.js +0 -3135
  316. package/dist/plugin-sdk/session-88GgvJcW.js +0 -169
  317. package/dist/plugin-sdk/skill-commands-ClwX3DoE.js +0 -353
  318. package/dist/plugin-sdk/skills-B2FPl9ca.js +0 -1428
  319. package/dist/plugin-sdk/slash-commands.runtime-CGAfyDkY.js +0 -13
  320. package/dist/plugin-sdk/slash-dispatch.runtime-DN7TWAWh.js +0 -52
  321. package/dist/plugin-sdk/slash-skill-commands.runtime-C4i9B-79.js +0 -16
  322. package/dist/plugin-sdk/ssrf-D3NQgatK.js +0 -202
  323. package/dist/plugin-sdk/store-CDmdRGxP.js +0 -81
  324. package/dist/plugin-sdk/subagent-registry-runtime-CprGCjIU.js +0 -52
  325. package/dist/plugin-sdk/tables-j2CMtAoX.js +0 -55
  326. package/dist/plugin-sdk/thinking-Dh6B0ZhB.js +0 -1206
  327. package/dist/plugin-sdk/tokens-PExiD061.js +0 -52
  328. package/dist/plugin-sdk/tool-images-D7ah30xm.js +0 -274
  329. package/dist/plugin-sdk/web-D9wJfMr_.js +0 -56
  330. package/dist/plugin-sdk/whatsapp-actions-BjarJorO.js +0 -80
  331. package/dist/qmd-manager-oU4X85hj.js +0 -1452
  332. package/dist/register.configure-MduIRRMt.js +0 -162
  333. package/dist/runtime-whatsapp-outbound.runtime-CNnM5MdE.js +0 -28
  334. package/dist/slash-dispatch.runtime-D5Cl7j1v.js +0 -110
  335. package/dist/slash-skill-commands.runtime-DnvHGcVS.js +0 -29
  336. package/dist/subagent-registry-runtime-LH0OBaWN.js +0 -110
  337. package/dist/target-errors-HJQQHC3B.js +0 -195
  338. package/dist/web-DxHq9RWt.js +0 -114
@@ -1,1452 +0,0 @@
1
- import { ot as resolveStateDir, s as createSubsystemLogger } from "./entry.js";
2
- import { u as resolveAgentWorkspaceDir } from "./agent-scope-D-i-vMLS.js";
3
- import { E as parseAgentSessionKey } from "./session-key-9-yI-GU_.js";
4
- import "./utils-hiIKrqOK.js";
5
- import "./winclaw-root-D0OUuGl7.js";
6
- import "./logger-BcqRk323.js";
7
- import "./exec-CaapFZaD.js";
8
- import "./path-alias-guards-9OJ1UBCd.js";
9
- import "./paths-ByCv35uy.js";
10
- import "./redact-D1OBirZT.js";
11
- import { l as writeFileWithinRoot } from "./fs-safe-Dha0DfFC.js";
12
- import { n as resolveWindowsSpawnProgram, t as materializeWindowsSpawnProgram } from "./windows-spawn-D0wwE7yg.js";
13
- import { _ as isFileMissingError, i as listSessionFilesForAgent, n as requireNodeSqlite, r as buildSessionEntry, t as extractKeywords, v as statRegularFile } from "./query-expansion-Cja4xprw.js";
14
- import { spawn } from "node:child_process";
15
- import os from "node:os";
16
- import path from "node:path";
17
- import fsPromises from "node:fs/promises";
18
- import readline from "node:readline";
19
-
20
- //#region src/memory/qmd-scope.ts
21
- function isQmdScopeAllowed(scope, sessionKey) {
22
- if (!scope) return true;
23
- const parsed = parseQmdSessionScope(sessionKey);
24
- const channel = parsed.channel;
25
- const chatType = parsed.chatType;
26
- const normalizedKey = parsed.normalizedKey ?? "";
27
- const rawKey = sessionKey?.trim().toLowerCase() ?? "";
28
- for (const rule of scope.rules ?? []) {
29
- if (!rule) continue;
30
- const match = rule.match ?? {};
31
- if (match.channel && match.channel !== channel) continue;
32
- if (match.chatType && match.chatType !== chatType) continue;
33
- const normalizedPrefix = match.keyPrefix?.trim().toLowerCase() || void 0;
34
- const rawPrefix = match.rawKeyPrefix?.trim().toLowerCase() || void 0;
35
- if (rawPrefix && !rawKey.startsWith(rawPrefix)) continue;
36
- if (normalizedPrefix) {
37
- if (normalizedPrefix.startsWith("agent:")) {
38
- if (!rawKey.startsWith(normalizedPrefix)) continue;
39
- } else if (!normalizedKey.startsWith(normalizedPrefix)) continue;
40
- }
41
- return rule.action === "allow";
42
- }
43
- return (scope.default ?? "allow") === "allow";
44
- }
45
- function deriveQmdScopeChannel(key) {
46
- return parseQmdSessionScope(key).channel;
47
- }
48
- function deriveQmdScopeChatType(key) {
49
- return parseQmdSessionScope(key).chatType;
50
- }
51
- function parseQmdSessionScope(key) {
52
- const normalized = normalizeQmdSessionKey(key);
53
- if (!normalized) return {};
54
- const parts = normalized.split(":").filter(Boolean);
55
- let chatType;
56
- if (parts.length >= 2 && (parts[1] === "group" || parts[1] === "channel" || parts[1] === "direct" || parts[1] === "dm")) {
57
- if (parts.includes("group")) chatType = "group";
58
- else if (parts.includes("channel")) chatType = "channel";
59
- return {
60
- normalizedKey: normalized,
61
- channel: parts[0]?.toLowerCase(),
62
- chatType: chatType ?? "direct"
63
- };
64
- }
65
- if (normalized.includes(":group:")) return {
66
- normalizedKey: normalized,
67
- chatType: "group"
68
- };
69
- if (normalized.includes(":channel:")) return {
70
- normalizedKey: normalized,
71
- chatType: "channel"
72
- };
73
- return {
74
- normalizedKey: normalized,
75
- chatType: "direct"
76
- };
77
- }
78
- function normalizeQmdSessionKey(key) {
79
- if (!key) return;
80
- const trimmed = key.trim();
81
- if (!trimmed) return;
82
- const normalized = (parseAgentSessionKey(trimmed)?.rest ?? trimmed).toLowerCase();
83
- if (normalized.startsWith("subagent:")) return;
84
- return normalized;
85
- }
86
-
87
- //#endregion
88
- //#region src/memory/qmd-query-parser.ts
89
- const log$1 = createSubsystemLogger("memory");
90
- function parseQmdQueryJson(stdout, stderr) {
91
- const trimmedStdout = stdout.trim();
92
- const trimmedStderr = stderr.trim();
93
- const stdoutIsMarker = trimmedStdout.length > 0 && isQmdNoResultsOutput(trimmedStdout);
94
- const stderrIsMarker = trimmedStderr.length > 0 && isQmdNoResultsOutput(trimmedStderr);
95
- if (stdoutIsMarker || !trimmedStdout && stderrIsMarker) return [];
96
- if (!trimmedStdout) {
97
- const message = `stdout empty${trimmedStderr ? ` (stderr: ${summarizeQmdStderr(trimmedStderr)})` : ""}`;
98
- log$1.warn(`qmd query returned invalid JSON: ${message}`);
99
- throw new Error(`qmd query returned invalid JSON: ${message}`);
100
- }
101
- try {
102
- const parsed = parseQmdQueryResultArray(trimmedStdout);
103
- if (parsed !== null) return parsed;
104
- const noisyPayload = extractFirstJsonArray(trimmedStdout);
105
- if (!noisyPayload) throw new Error("qmd query JSON response was not an array");
106
- const fallback = parseQmdQueryResultArray(noisyPayload);
107
- if (fallback !== null) return fallback;
108
- throw new Error("qmd query JSON response was not an array");
109
- } catch (err) {
110
- const message = err instanceof Error ? err.message : String(err);
111
- log$1.warn(`qmd query returned invalid JSON: ${message}`);
112
- throw new Error(`qmd query returned invalid JSON: ${message}`, { cause: err });
113
- }
114
- }
115
- function isQmdNoResultsOutput(raw) {
116
- return raw.split(/\r?\n/).map((line) => line.trim().toLowerCase().replace(/\s+/g, " ")).filter((line) => line.length > 0).some((line) => isQmdNoResultsLine(line));
117
- }
118
- function isQmdNoResultsLine(line) {
119
- if (line === "no results found" || line === "no results found.") return true;
120
- return /^(?:\[[^\]]+\]\s*)?(?:(?:warn(?:ing)?|info|error|qmd)\s*:\s*)+no results found\.?$/.test(line);
121
- }
122
- function summarizeQmdStderr(raw) {
123
- return raw.length <= 120 ? raw : `${raw.slice(0, 117)}...`;
124
- }
125
- function parseQmdQueryResultArray(raw) {
126
- try {
127
- const parsed = JSON.parse(raw);
128
- if (!Array.isArray(parsed)) return null;
129
- return parsed;
130
- } catch {
131
- return null;
132
- }
133
- }
134
- function extractFirstJsonArray(raw) {
135
- const start = raw.indexOf("[");
136
- if (start < 0) return null;
137
- let depth = 0;
138
- let inString = false;
139
- let escaped = false;
140
- for (let i = start; i < raw.length; i += 1) {
141
- const char = raw[i];
142
- if (char === void 0) break;
143
- if (inString) {
144
- if (escaped) {
145
- escaped = false;
146
- continue;
147
- }
148
- if (char === "\\") escaped = true;
149
- else if (char === "\"") inString = false;
150
- continue;
151
- }
152
- if (char === "\"") {
153
- inString = true;
154
- continue;
155
- }
156
- if (char === "[") depth += 1;
157
- else if (char === "]") {
158
- depth -= 1;
159
- if (depth === 0) return raw.slice(start, i + 1);
160
- }
161
- }
162
- return null;
163
- }
164
-
165
- //#endregion
166
- //#region src/memory/qmd-manager.ts
167
- const log = createSubsystemLogger("memory");
168
- const SNIPPET_HEADER_RE = /@@\s*-([0-9]+),([0-9]+)/;
169
- const SEARCH_PENDING_UPDATE_WAIT_MS = 500;
170
- const MAX_QMD_OUTPUT_CHARS = 2e5;
171
- const NUL_MARKER_RE = /(?:\^@|\\0|\\x00|\\u0000|null\s*byte|nul\s*byte)/i;
172
- const QMD_EMBED_BACKOFF_BASE_MS = 6e4;
173
- const QMD_EMBED_BACKOFF_MAX_MS = 3600 * 1e3;
174
- const HAN_SCRIPT_RE = /[\u3400-\u9fff]/u;
175
- const QMD_BM25_HAN_KEYWORD_LIMIT = 12;
176
- let qmdEmbedQueueTail = Promise.resolve();
177
- function resolveWindowsCommandShim(command) {
178
- if (process.platform !== "win32") return command;
179
- const trimmed = command.trim();
180
- if (!trimmed) return command;
181
- const ext = path.extname(trimmed).toLowerCase();
182
- if (ext === ".cmd" || ext === ".exe" || ext === ".bat") return command;
183
- const base = path.basename(trimmed).toLowerCase();
184
- if (base === "qmd" || base === "mcporter") return `${trimmed}.cmd`;
185
- return command;
186
- }
187
- function resolveSpawnInvocation(params) {
188
- return materializeWindowsSpawnProgram(resolveWindowsSpawnProgram({
189
- command: resolveWindowsCommandShim(params.command),
190
- platform: process.platform,
191
- env: params.env,
192
- execPath: process.execPath,
193
- packageName: params.packageName,
194
- allowShellFallback: true
195
- }), params.args);
196
- }
197
- function hasHanScript(value) {
198
- return HAN_SCRIPT_RE.test(value);
199
- }
200
- function normalizeHanBm25Query(query) {
201
- const trimmed = query.trim();
202
- if (!trimmed || !hasHanScript(trimmed)) return trimmed;
203
- const keywords = extractKeywords(trimmed);
204
- const normalizedKeywords = [];
205
- const seen = /* @__PURE__ */ new Set();
206
- for (const keyword of keywords) {
207
- const token = keyword.trim();
208
- if (!token || seen.has(token)) continue;
209
- const includesHan = hasHanScript(token);
210
- if (includesHan && Array.from(token).length < 2) continue;
211
- if (!includesHan && token.length < 2) continue;
212
- seen.add(token);
213
- normalizedKeywords.push(token);
214
- if (normalizedKeywords.length >= QMD_BM25_HAN_KEYWORD_LIMIT) break;
215
- }
216
- return normalizedKeywords.length > 0 ? normalizedKeywords.join(" ") : trimmed;
217
- }
218
- async function runWithQmdEmbedLock(task) {
219
- const previous = qmdEmbedQueueTail;
220
- let release;
221
- qmdEmbedQueueTail = new Promise((resolve) => {
222
- release = resolve;
223
- });
224
- await previous.catch(() => void 0);
225
- try {
226
- return await task();
227
- } finally {
228
- release?.();
229
- }
230
- }
231
- var QmdMemoryManager = class QmdMemoryManager {
232
- static async create(params) {
233
- const resolved = params.resolved.qmd;
234
- if (!resolved) return null;
235
- const manager = new QmdMemoryManager({
236
- cfg: params.cfg,
237
- agentId: params.agentId,
238
- resolved
239
- });
240
- await manager.initialize(params.mode ?? "full");
241
- return manager;
242
- }
243
- constructor(params) {
244
- this.collectionRoots = /* @__PURE__ */ new Map();
245
- this.sources = /* @__PURE__ */ new Set();
246
- this.docPathCache = /* @__PURE__ */ new Map();
247
- this.exportedSessionState = /* @__PURE__ */ new Map();
248
- this.maxQmdOutputChars = MAX_QMD_OUTPUT_CHARS;
249
- this.updateTimer = null;
250
- this.pendingUpdate = null;
251
- this.queuedForcedUpdate = null;
252
- this.queuedForcedRuns = 0;
253
- this.closed = false;
254
- this.db = null;
255
- this.lastUpdateAt = null;
256
- this.lastEmbedAt = null;
257
- this.embedBackoffUntil = null;
258
- this.embedFailureCount = 0;
259
- this.attemptedNullByteCollectionRepair = false;
260
- this.cfg = params.cfg;
261
- this.agentId = params.agentId;
262
- this.qmd = params.resolved;
263
- this.workspaceDir = resolveAgentWorkspaceDir(params.cfg, params.agentId);
264
- this.stateDir = resolveStateDir(process.env, os.homedir);
265
- this.agentStateDir = path.join(this.stateDir, "agents", this.agentId);
266
- this.qmdDir = path.join(this.agentStateDir, "qmd");
267
- this.xdgConfigHome = path.join(this.qmdDir, "xdg-config");
268
- this.xdgCacheHome = path.join(this.qmdDir, "xdg-cache");
269
- this.indexPath = path.join(this.xdgCacheHome, "qmd", "index.sqlite");
270
- this.env = {
271
- ...process.env,
272
- XDG_CONFIG_HOME: this.xdgConfigHome,
273
- QMD_CONFIG_DIR: this.xdgConfigHome,
274
- XDG_CACHE_HOME: this.xdgCacheHome,
275
- NO_COLOR: "1"
276
- };
277
- this.sessionExporter = this.qmd.sessions.enabled ? {
278
- dir: this.qmd.sessions.exportDir ?? path.join(this.qmdDir, "sessions"),
279
- retentionMs: this.qmd.sessions.retentionDays ? this.qmd.sessions.retentionDays * 24 * 60 * 60 * 1e3 : void 0,
280
- collectionName: this.pickSessionCollectionName()
281
- } : null;
282
- if (this.sessionExporter) this.qmd.collections = [...this.qmd.collections, {
283
- name: this.sessionExporter.collectionName,
284
- path: this.sessionExporter.dir,
285
- pattern: "**/*.md",
286
- kind: "sessions"
287
- }];
288
- this.managedCollectionNames = this.computeManagedCollectionNames();
289
- }
290
- async initialize(mode) {
291
- this.bootstrapCollections();
292
- if (mode === "status") return;
293
- await fsPromises.mkdir(this.xdgConfigHome, { recursive: true });
294
- await fsPromises.mkdir(this.xdgCacheHome, { recursive: true });
295
- await fsPromises.mkdir(path.dirname(this.indexPath), { recursive: true });
296
- if (this.sessionExporter) await fsPromises.mkdir(this.sessionExporter.dir, { recursive: true });
297
- await this.symlinkSharedModels();
298
- await this.ensureCollections();
299
- if (this.qmd.update.onBoot) {
300
- const bootRun = this.runUpdate("boot", true);
301
- if (this.qmd.update.waitForBootSync) await bootRun.catch((err) => {
302
- log.warn(`qmd boot update failed: ${String(err)}`);
303
- });
304
- else bootRun.catch((err) => {
305
- log.warn(`qmd boot update failed: ${String(err)}`);
306
- });
307
- }
308
- if (this.qmd.update.intervalMs > 0) this.updateTimer = setInterval(() => {
309
- this.runUpdate("interval").catch((err) => {
310
- log.warn(`qmd update failed (${String(err)})`);
311
- });
312
- }, this.qmd.update.intervalMs);
313
- }
314
- bootstrapCollections() {
315
- this.collectionRoots.clear();
316
- this.sources.clear();
317
- for (const collection of this.qmd.collections) {
318
- const kind = collection.kind === "sessions" ? "sessions" : "memory";
319
- this.collectionRoots.set(collection.name, {
320
- path: collection.path,
321
- kind
322
- });
323
- this.sources.add(kind);
324
- }
325
- }
326
- async ensureCollections() {
327
- const existing = /* @__PURE__ */ new Map();
328
- try {
329
- const result = await this.runQmd([
330
- "collection",
331
- "list",
332
- "--json"
333
- ], { timeoutMs: this.qmd.update.commandTimeoutMs });
334
- const parsed = this.parseListedCollections(result.stdout);
335
- for (const [name, details] of parsed) existing.set(name, details);
336
- } catch {}
337
- await this.migrateLegacyUnscopedCollections(existing);
338
- for (const collection of this.qmd.collections) {
339
- const listed = existing.get(collection.name);
340
- if (listed && !this.shouldRebindCollection(collection, listed)) continue;
341
- if (listed) try {
342
- await this.removeCollection(collection.name);
343
- } catch (err) {
344
- const message = err instanceof Error ? err.message : String(err);
345
- if (!this.isCollectionMissingError(message)) log.warn(`qmd collection remove failed for ${collection.name}: ${message}`);
346
- }
347
- try {
348
- await this.ensureCollectionPath(collection);
349
- await this.addCollection(collection.path, collection.name, collection.pattern);
350
- } catch (err) {
351
- const message = err instanceof Error ? err.message : String(err);
352
- if (this.isCollectionAlreadyExistsError(message)) continue;
353
- log.warn(`qmd collection add failed for ${collection.name}: ${message}`);
354
- }
355
- }
356
- }
357
- async migrateLegacyUnscopedCollections(existing) {
358
- for (const collection of this.qmd.collections) {
359
- if (existing.has(collection.name)) continue;
360
- const legacyName = this.deriveLegacyCollectionName(collection.name);
361
- if (!legacyName) continue;
362
- const listedLegacy = existing.get(legacyName);
363
- if (!listedLegacy) continue;
364
- if (!this.canMigrateLegacyCollection(collection, listedLegacy)) {
365
- log.debug(`qmd legacy collection migration skipped for ${legacyName} (path/pattern mismatch)`);
366
- continue;
367
- }
368
- try {
369
- await this.removeCollection(legacyName);
370
- existing.delete(legacyName);
371
- } catch (err) {
372
- const message = err instanceof Error ? err.message : String(err);
373
- if (!this.isCollectionMissingError(message)) log.warn(`qmd collection remove failed for ${legacyName}: ${message}`);
374
- }
375
- }
376
- }
377
- deriveLegacyCollectionName(scopedName) {
378
- const agentSuffix = `-${this.sanitizeCollectionNameSegment(this.agentId)}`;
379
- if (!scopedName.endsWith(agentSuffix)) return null;
380
- return scopedName.slice(0, -agentSuffix.length).trim() || null;
381
- }
382
- canMigrateLegacyCollection(collection, listedLegacy) {
383
- if (listedLegacy.path && !this.pathsMatch(listedLegacy.path, collection.path)) return false;
384
- if (typeof listedLegacy.pattern === "string" && listedLegacy.pattern !== collection.pattern) return false;
385
- return true;
386
- }
387
- async ensureCollectionPath(collection) {
388
- if (!this.isDirectoryGlobPattern(collection.pattern)) return;
389
- await fsPromises.mkdir(collection.path, { recursive: true });
390
- }
391
- isDirectoryGlobPattern(pattern) {
392
- return pattern.includes("*") || pattern.includes("?") || pattern.includes("[");
393
- }
394
- isCollectionAlreadyExistsError(message) {
395
- const lower = message.toLowerCase();
396
- return lower.includes("already exists") || lower.includes("exists");
397
- }
398
- isCollectionMissingError(message) {
399
- const lower = message.toLowerCase();
400
- return lower.includes("not found") || lower.includes("does not exist") || lower.includes("missing");
401
- }
402
- isMissingCollectionSearchError(err) {
403
- const message = err instanceof Error ? err.message : String(err);
404
- return this.isCollectionMissingError(message) && message.toLowerCase().includes("collection");
405
- }
406
- async tryRepairMissingCollectionSearch(err) {
407
- if (!this.isMissingCollectionSearchError(err)) return false;
408
- log.warn("qmd search failed because a managed collection is missing; repairing collections and retrying once");
409
- await this.ensureCollections();
410
- return true;
411
- }
412
- async addCollection(pathArg, name, pattern) {
413
- await this.runQmd([
414
- "collection",
415
- "add",
416
- pathArg,
417
- "--name",
418
- name,
419
- "--mask",
420
- pattern
421
- ], { timeoutMs: this.qmd.update.commandTimeoutMs });
422
- }
423
- async removeCollection(name) {
424
- await this.runQmd([
425
- "collection",
426
- "remove",
427
- name
428
- ], { timeoutMs: this.qmd.update.commandTimeoutMs });
429
- }
430
- parseListedCollections(output) {
431
- const listed = /* @__PURE__ */ new Map();
432
- const trimmed = output.trim();
433
- if (!trimmed) return listed;
434
- try {
435
- const parsed = JSON.parse(trimmed);
436
- if (Array.isArray(parsed)) {
437
- for (const entry of parsed) {
438
- if (typeof entry === "string") {
439
- listed.set(entry, {});
440
- continue;
441
- }
442
- if (!entry || typeof entry !== "object") continue;
443
- const name = entry.name;
444
- if (typeof name !== "string") continue;
445
- const listedPath = entry.path;
446
- const listedPattern = entry.pattern;
447
- const listedMask = entry.mask;
448
- listed.set(name, {
449
- path: typeof listedPath === "string" ? listedPath : void 0,
450
- pattern: typeof listedPattern === "string" ? listedPattern : typeof listedMask === "string" ? listedMask : void 0
451
- });
452
- }
453
- return listed;
454
- }
455
- } catch {}
456
- let currentName = null;
457
- for (const rawLine of output.split(/\r?\n/)) {
458
- const line = rawLine.trimEnd();
459
- if (!line.trim()) {
460
- currentName = null;
461
- continue;
462
- }
463
- const collectionLine = /^\s*([a-z0-9._-]+)\s+\(qmd:\/\/[^)]+\)\s*$/i.exec(line);
464
- if (collectionLine) {
465
- currentName = collectionLine[1];
466
- if (!listed.has(currentName)) listed.set(currentName, {});
467
- continue;
468
- }
469
- if (/^\s*collections\b/i.test(line)) continue;
470
- const bareNameLine = /^\s*([a-z0-9._-]+)\s*$/i.exec(line);
471
- if (bareNameLine && !line.includes(":")) {
472
- currentName = bareNameLine[1];
473
- if (!listed.has(currentName)) listed.set(currentName, {});
474
- continue;
475
- }
476
- if (!currentName) continue;
477
- const patternLine = /^\s*(?:pattern|mask)\s*:\s*(.+?)\s*$/i.exec(line);
478
- if (patternLine) {
479
- const existing = listed.get(currentName) ?? {};
480
- existing.pattern = patternLine[1].trim();
481
- listed.set(currentName, existing);
482
- continue;
483
- }
484
- const pathLine = /^\s*path\s*:\s*(.+?)\s*$/i.exec(line);
485
- if (pathLine) {
486
- const existing = listed.get(currentName) ?? {};
487
- existing.path = pathLine[1].trim();
488
- listed.set(currentName, existing);
489
- }
490
- }
491
- return listed;
492
- }
493
- shouldRebindCollection(collection, listed) {
494
- if (!listed.path) return true;
495
- if (!this.pathsMatch(listed.path, collection.path)) return true;
496
- if (typeof listed.pattern === "string" && listed.pattern !== collection.pattern) return true;
497
- return false;
498
- }
499
- pathsMatch(left, right) {
500
- const normalize = (value) => {
501
- const resolved = path.isAbsolute(value) ? path.resolve(value) : path.resolve(this.workspaceDir, value);
502
- const normalized = path.normalize(resolved);
503
- return process.platform === "win32" ? normalized.toLowerCase() : normalized;
504
- };
505
- return normalize(left) === normalize(right);
506
- }
507
- shouldRepairNullByteCollectionError(err) {
508
- const message = err instanceof Error ? err.message : String(err);
509
- const lower = message.toLowerCase();
510
- return (lower.includes("enotdir") || lower.includes("not a directory")) && NUL_MARKER_RE.test(message);
511
- }
512
- async tryRepairNullByteCollections(err, reason) {
513
- if (this.attemptedNullByteCollectionRepair) return false;
514
- if (!this.shouldRepairNullByteCollectionError(err)) return false;
515
- this.attemptedNullByteCollectionRepair = true;
516
- log.warn(`qmd update failed with suspected null-byte collection metadata (${reason}); rebuilding managed collections and retrying once`);
517
- for (const collection of this.qmd.collections) {
518
- try {
519
- await this.removeCollection(collection.name);
520
- } catch (removeErr) {
521
- const removeMessage = removeErr instanceof Error ? removeErr.message : String(removeErr);
522
- if (!this.isCollectionMissingError(removeMessage)) log.warn(`qmd collection remove failed for ${collection.name}: ${removeMessage}`);
523
- }
524
- try {
525
- await this.addCollection(collection.path, collection.name, collection.pattern);
526
- } catch (addErr) {
527
- const addMessage = addErr instanceof Error ? addErr.message : String(addErr);
528
- if (!this.isCollectionAlreadyExistsError(addMessage)) log.warn(`qmd collection add failed for ${collection.name}: ${addMessage}`);
529
- }
530
- }
531
- return true;
532
- }
533
- async search(query, opts) {
534
- if (!this.isScopeAllowed(opts?.sessionKey)) {
535
- this.logScopeDenied(opts?.sessionKey);
536
- return [];
537
- }
538
- const trimmed = query.trim();
539
- if (!trimmed) return [];
540
- await this.waitForPendingUpdateBeforeSearch();
541
- const limit = Math.min(this.qmd.limits.maxResults, opts?.maxResults ?? this.qmd.limits.maxResults);
542
- const collectionNames = this.listManagedCollectionNames();
543
- if (collectionNames.length === 0) {
544
- log.warn("qmd query skipped: no managed collections configured");
545
- return [];
546
- }
547
- const qmdSearchCommand = this.qmd.searchMode;
548
- const mcporterEnabled = this.qmd.mcporter.enabled;
549
- const runSearchAttempt = async (allowMissingCollectionRepair) => {
550
- try {
551
- if (mcporterEnabled) {
552
- const tool = qmdSearchCommand === "search" ? "search" : qmdSearchCommand === "vsearch" ? "vector_search" : "deep_search";
553
- const minScore = opts?.minScore ?? 0;
554
- if (collectionNames.length > 1) return await this.runMcporterAcrossCollections({
555
- tool,
556
- query: trimmed,
557
- limit,
558
- minScore,
559
- collectionNames
560
- });
561
- return await this.runQmdSearchViaMcporter({
562
- mcporter: this.qmd.mcporter,
563
- tool,
564
- query: trimmed,
565
- limit,
566
- minScore,
567
- collection: collectionNames[0],
568
- timeoutMs: this.qmd.limits.timeoutMs
569
- });
570
- }
571
- if (collectionNames.length > 1) return await this.runQueryAcrossCollections(trimmed, limit, collectionNames, qmdSearchCommand);
572
- const args = this.buildSearchArgs(qmdSearchCommand, trimmed, limit);
573
- args.push(...this.buildCollectionFilterArgs(collectionNames));
574
- const result = await this.runQmd(args, { timeoutMs: this.qmd.limits.timeoutMs });
575
- return parseQmdQueryJson(result.stdout, result.stderr);
576
- } catch (err) {
577
- if (allowMissingCollectionRepair && this.isMissingCollectionSearchError(err)) throw err;
578
- if (!mcporterEnabled && qmdSearchCommand !== "query" && this.isUnsupportedQmdOptionError(err)) {
579
- log.warn(`qmd ${qmdSearchCommand} does not support configured flags; retrying search with qmd query`);
580
- try {
581
- if (collectionNames.length > 1) return await this.runQueryAcrossCollections(trimmed, limit, collectionNames, "query");
582
- const fallbackArgs = this.buildSearchArgs("query", trimmed, limit);
583
- fallbackArgs.push(...this.buildCollectionFilterArgs(collectionNames));
584
- const fallback = await this.runQmd(fallbackArgs, { timeoutMs: this.qmd.limits.timeoutMs });
585
- return parseQmdQueryJson(fallback.stdout, fallback.stderr);
586
- } catch (fallbackErr) {
587
- log.warn(`qmd query fallback failed: ${String(fallbackErr)}`);
588
- throw fallbackErr instanceof Error ? fallbackErr : new Error(String(fallbackErr));
589
- }
590
- }
591
- const label = mcporterEnabled ? "mcporter/qmd" : `qmd ${qmdSearchCommand}`;
592
- log.warn(`${label} failed: ${String(err)}`);
593
- throw err instanceof Error ? err : new Error(String(err));
594
- }
595
- };
596
- let parsed;
597
- try {
598
- parsed = await runSearchAttempt(true);
599
- } catch (err) {
600
- if (!await this.tryRepairMissingCollectionSearch(err)) throw err instanceof Error ? err : new Error(String(err));
601
- parsed = await runSearchAttempt(false);
602
- }
603
- const results = [];
604
- for (const entry of parsed) {
605
- const doc = await this.resolveDocLocation(entry.docid, {
606
- preferredCollection: entry.collection,
607
- preferredFile: entry.file
608
- });
609
- if (!doc) continue;
610
- const snippet = entry.snippet?.slice(0, this.qmd.limits.maxSnippetChars) ?? "";
611
- const lines = this.extractSnippetLines(snippet);
612
- const score = typeof entry.score === "number" ? entry.score : 0;
613
- if (score < (opts?.minScore ?? 0)) continue;
614
- results.push({
615
- path: doc.rel,
616
- startLine: lines.startLine,
617
- endLine: lines.endLine,
618
- score,
619
- snippet,
620
- source: doc.source
621
- });
622
- }
623
- return this.clampResultsByInjectedChars(this.diversifyResultsBySource(results, limit));
624
- }
625
- async sync(params) {
626
- if (params?.progress) params.progress({
627
- completed: 0,
628
- total: 1,
629
- label: "Updating QMD index…"
630
- });
631
- await this.runUpdate(params?.reason ?? "manual", params?.force);
632
- if (params?.progress) params.progress({
633
- completed: 1,
634
- total: 1,
635
- label: "QMD index updated"
636
- });
637
- }
638
- async readFile(params) {
639
- const relPath = params.relPath?.trim();
640
- if (!relPath) throw new Error("path required");
641
- const absPath = this.resolveReadPath(relPath);
642
- if (!absPath.endsWith(".md")) throw new Error("path required");
643
- if ((await statRegularFile(absPath)).missing) return {
644
- text: "",
645
- path: relPath
646
- };
647
- if (params.from !== void 0 || params.lines !== void 0) {
648
- const partial = await this.readPartialText(absPath, params.from, params.lines);
649
- if (partial.missing) return {
650
- text: "",
651
- path: relPath
652
- };
653
- return {
654
- text: partial.text,
655
- path: relPath
656
- };
657
- }
658
- const full = await this.readFullText(absPath);
659
- if (full.missing) return {
660
- text: "",
661
- path: relPath
662
- };
663
- if (!params.from && !params.lines) return {
664
- text: full.text,
665
- path: relPath
666
- };
667
- const lines = full.text.split("\n");
668
- const start = Math.max(1, params.from ?? 1);
669
- const count = Math.max(1, params.lines ?? lines.length);
670
- return {
671
- text: lines.slice(start - 1, start - 1 + count).join("\n"),
672
- path: relPath
673
- };
674
- }
675
- status() {
676
- const counts = this.readCounts();
677
- return {
678
- backend: "qmd",
679
- provider: "qmd",
680
- model: "qmd",
681
- requestedProvider: "qmd",
682
- files: counts.totalDocuments,
683
- chunks: counts.totalDocuments,
684
- dirty: false,
685
- workspaceDir: this.workspaceDir,
686
- dbPath: this.indexPath,
687
- sources: Array.from(this.sources),
688
- sourceCounts: counts.sourceCounts,
689
- vector: {
690
- enabled: true,
691
- available: true
692
- },
693
- batch: {
694
- enabled: false,
695
- failures: 0,
696
- limit: 0,
697
- wait: false,
698
- concurrency: 0,
699
- pollIntervalMs: 0,
700
- timeoutMs: 0
701
- },
702
- custom: { qmd: {
703
- collections: this.qmd.collections.length,
704
- lastUpdateAt: this.lastUpdateAt
705
- } }
706
- };
707
- }
708
- async probeEmbeddingAvailability() {
709
- return { ok: true };
710
- }
711
- async probeVectorAvailability() {
712
- return true;
713
- }
714
- async close() {
715
- if (this.closed) return;
716
- this.closed = true;
717
- if (this.updateTimer) {
718
- clearInterval(this.updateTimer);
719
- this.updateTimer = null;
720
- }
721
- this.queuedForcedRuns = 0;
722
- await this.pendingUpdate?.catch(() => void 0);
723
- await this.queuedForcedUpdate?.catch(() => void 0);
724
- if (this.db) {
725
- this.db.close();
726
- this.db = null;
727
- }
728
- }
729
- async runUpdate(reason, force, opts) {
730
- if (this.closed) return;
731
- if (this.pendingUpdate) {
732
- if (force) return this.enqueueForcedUpdate(reason);
733
- return this.pendingUpdate;
734
- }
735
- if (this.queuedForcedUpdate && !opts?.fromForcedQueue) {
736
- if (force) return this.enqueueForcedUpdate(reason);
737
- return this.queuedForcedUpdate;
738
- }
739
- if (this.shouldSkipUpdate(force)) return;
740
- const run = async () => {
741
- if (this.sessionExporter) await this.exportSessions();
742
- await this.runQmdUpdateWithRetry(reason);
743
- if (this.shouldRunEmbed(force)) try {
744
- await runWithQmdEmbedLock(async () => {
745
- await this.runQmd(["embed"], {
746
- timeoutMs: this.qmd.update.embedTimeoutMs,
747
- discardOutput: true
748
- });
749
- });
750
- this.lastEmbedAt = Date.now();
751
- this.embedBackoffUntil = null;
752
- this.embedFailureCount = 0;
753
- } catch (err) {
754
- this.noteEmbedFailure(reason, err);
755
- }
756
- this.lastUpdateAt = Date.now();
757
- this.docPathCache.clear();
758
- };
759
- this.pendingUpdate = run().finally(() => {
760
- this.pendingUpdate = null;
761
- });
762
- await this.pendingUpdate;
763
- }
764
- async runQmdUpdateWithRetry(reason) {
765
- const maxAttempts = reason === "boot" || reason.startsWith("boot:") ? 3 : 1;
766
- for (let attempt = 1; attempt <= maxAttempts; attempt += 1) try {
767
- await this.runQmdUpdateOnce(reason);
768
- return;
769
- } catch (err) {
770
- if (attempt >= maxAttempts || !this.isRetryableUpdateError(err)) throw err;
771
- const delayMs = 500 * 2 ** (attempt - 1);
772
- log.warn(`qmd update retry ${attempt}/${maxAttempts - 1} after failure (${reason}): ${String(err)}`);
773
- await new Promise((resolve) => setTimeout(resolve, delayMs));
774
- }
775
- }
776
- async runQmdUpdateOnce(reason) {
777
- try {
778
- await this.runQmd(["update"], {
779
- timeoutMs: this.qmd.update.updateTimeoutMs,
780
- discardOutput: true
781
- });
782
- } catch (err) {
783
- if (!await this.tryRepairNullByteCollections(err, reason)) throw err;
784
- await this.runQmd(["update"], {
785
- timeoutMs: this.qmd.update.updateTimeoutMs,
786
- discardOutput: true
787
- });
788
- }
789
- }
790
- isRetryableUpdateError(err) {
791
- if (this.isSqliteBusyError(err)) return true;
792
- return (err instanceof Error ? err.message : String(err)).toLowerCase().includes("timed out");
793
- }
794
- shouldRunEmbed(force) {
795
- if (this.qmd.searchMode === "search") return false;
796
- const now = Date.now();
797
- if (this.embedBackoffUntil !== null && now < this.embedBackoffUntil) return false;
798
- const embedIntervalMs = this.qmd.update.embedIntervalMs;
799
- return Boolean(force) || this.lastEmbedAt === null || embedIntervalMs > 0 && now - this.lastEmbedAt > embedIntervalMs;
800
- }
801
- noteEmbedFailure(reason, err) {
802
- this.embedFailureCount += 1;
803
- const delayMs = Math.min(QMD_EMBED_BACKOFF_MAX_MS, QMD_EMBED_BACKOFF_BASE_MS * 2 ** Math.max(0, this.embedFailureCount - 1));
804
- this.embedBackoffUntil = Date.now() + delayMs;
805
- log.warn(`qmd embed failed (${reason}): ${String(err)}; backing off for ${Math.ceil(delayMs / 1e3)}s`);
806
- }
807
- enqueueForcedUpdate(reason) {
808
- this.queuedForcedRuns += 1;
809
- if (!this.queuedForcedUpdate) this.queuedForcedUpdate = this.drainForcedUpdates(reason).finally(() => {
810
- this.queuedForcedUpdate = null;
811
- });
812
- return this.queuedForcedUpdate;
813
- }
814
- async drainForcedUpdates(reason) {
815
- await this.pendingUpdate?.catch(() => void 0);
816
- while (!this.closed && this.queuedForcedRuns > 0) {
817
- this.queuedForcedRuns -= 1;
818
- await this.runUpdate(`${reason}:queued`, true, { fromForcedQueue: true });
819
- }
820
- }
821
- /**
822
- * Symlink the default QMD models directory into our custom XDG_CACHE_HOME so
823
- * that the pre-installed ML models (~/.cache/qmd/models/) are reused rather
824
- * than re-downloaded for every agent. If the default models directory does
825
- * not exist, or a models directory/symlink already exists in the target, this
826
- * is a no-op.
827
- */
828
- async symlinkSharedModels() {
829
- const defaultCacheHome = process.env.XDG_CACHE_HOME || (process.platform === "win32" ? process.env.LOCALAPPDATA : void 0) || path.join(os.homedir(), ".cache");
830
- const defaultModelsDir = path.join(defaultCacheHome, "qmd", "models");
831
- const targetModelsDir = path.join(this.xdgCacheHome, "qmd", "models");
832
- try {
833
- if (!(await fsPromises.stat(defaultModelsDir).catch((err) => {
834
- if (err.code === "ENOENT") return null;
835
- throw err;
836
- }))?.isDirectory()) return;
837
- try {
838
- await fsPromises.lstat(targetModelsDir);
839
- return;
840
- } catch {}
841
- try {
842
- await fsPromises.symlink(defaultModelsDir, targetModelsDir, "dir");
843
- } catch (symlinkErr) {
844
- const code = symlinkErr.code;
845
- if (process.platform === "win32" && (code === "EPERM" || code === "ENOTSUP")) await fsPromises.symlink(defaultModelsDir, targetModelsDir, "junction");
846
- else throw symlinkErr;
847
- }
848
- log.debug(`symlinked qmd models: ${defaultModelsDir} → ${targetModelsDir}`);
849
- } catch (err) {
850
- log.warn(`failed to symlink qmd models directory: ${String(err)}`);
851
- }
852
- }
853
- async runQmd(args, opts) {
854
- return await new Promise((resolve, reject) => {
855
- const spawnInvocation = resolveSpawnInvocation({
856
- command: this.qmd.command,
857
- args,
858
- env: this.env,
859
- packageName: "qmd"
860
- });
861
- const child = spawn(spawnInvocation.command, spawnInvocation.argv, {
862
- env: this.env,
863
- cwd: this.workspaceDir,
864
- shell: spawnInvocation.shell,
865
- windowsHide: spawnInvocation.windowsHide
866
- });
867
- let stdout = "";
868
- let stderr = "";
869
- let stdoutTruncated = false;
870
- let stderrTruncated = false;
871
- const discard = opts?.discardOutput === true;
872
- const timer = opts?.timeoutMs ? setTimeout(() => {
873
- child.kill("SIGKILL");
874
- reject(/* @__PURE__ */ new Error(`qmd ${args.join(" ")} timed out after ${opts.timeoutMs}ms`));
875
- }, opts.timeoutMs) : null;
876
- child.stdout.on("data", (data) => {
877
- if (discard) return;
878
- const next = appendOutputWithCap(stdout, data.toString("utf8"), this.maxQmdOutputChars);
879
- stdout = next.text;
880
- stdoutTruncated = stdoutTruncated || next.truncated;
881
- });
882
- child.stderr.on("data", (data) => {
883
- const next = appendOutputWithCap(stderr, data.toString("utf8"), this.maxQmdOutputChars);
884
- stderr = next.text;
885
- stderrTruncated = stderrTruncated || next.truncated;
886
- });
887
- child.on("error", (err) => {
888
- if (timer) clearTimeout(timer);
889
- reject(err);
890
- });
891
- child.on("close", (code) => {
892
- if (timer) clearTimeout(timer);
893
- if (!discard && (stdoutTruncated || stderrTruncated)) {
894
- reject(/* @__PURE__ */ new Error(`qmd ${args.join(" ")} produced too much output (limit ${this.maxQmdOutputChars} chars)`));
895
- return;
896
- }
897
- if (code === 0) resolve({
898
- stdout,
899
- stderr
900
- });
901
- else reject(/* @__PURE__ */ new Error(`qmd ${args.join(" ")} failed (code ${code}): ${stderr || stdout}`));
902
- });
903
- });
904
- }
905
- async ensureMcporterDaemonStarted(mcporter) {
906
- if (!mcporter.enabled) return;
907
- if (!mcporter.startDaemon) {
908
- const g = globalThis;
909
- if (!g.__winclawMcporterColdStartWarned) {
910
- g.__winclawMcporterColdStartWarned = true;
911
- log.warn("mcporter qmd bridge enabled but startDaemon=false; each query may cold-start QMD MCP. Consider setting memory.qmd.mcporter.startDaemon=true to keep it warm.");
912
- }
913
- return;
914
- }
915
- const g = globalThis;
916
- if (!g.__winclawMcporterDaemonStart) g.__winclawMcporterDaemonStart = (async () => {
917
- try {
918
- await this.runMcporter(["daemon", "start"], { timeoutMs: 1e4 });
919
- } catch (err) {
920
- log.warn(`mcporter daemon start failed: ${String(err)}`);
921
- delete g.__winclawMcporterDaemonStart;
922
- }
923
- })();
924
- await g.__winclawMcporterDaemonStart;
925
- }
926
- async runMcporter(args, opts) {
927
- return await new Promise((resolve, reject) => {
928
- const spawnInvocation = resolveSpawnInvocation({
929
- command: "mcporter",
930
- args,
931
- env: this.env,
932
- packageName: "mcporter"
933
- });
934
- const child = spawn(spawnInvocation.command, spawnInvocation.argv, {
935
- env: this.env,
936
- cwd: this.workspaceDir,
937
- shell: spawnInvocation.shell,
938
- windowsHide: spawnInvocation.windowsHide
939
- });
940
- let stdout = "";
941
- let stderr = "";
942
- let stdoutTruncated = false;
943
- let stderrTruncated = false;
944
- const timer = opts?.timeoutMs ? setTimeout(() => {
945
- child.kill("SIGKILL");
946
- reject(/* @__PURE__ */ new Error(`mcporter ${args.join(" ")} timed out after ${opts.timeoutMs}ms`));
947
- }, opts.timeoutMs) : null;
948
- child.stdout.on("data", (data) => {
949
- const next = appendOutputWithCap(stdout, data.toString("utf8"), this.maxQmdOutputChars);
950
- stdout = next.text;
951
- stdoutTruncated = stdoutTruncated || next.truncated;
952
- });
953
- child.stderr.on("data", (data) => {
954
- const next = appendOutputWithCap(stderr, data.toString("utf8"), this.maxQmdOutputChars);
955
- stderr = next.text;
956
- stderrTruncated = stderrTruncated || next.truncated;
957
- });
958
- child.on("error", (err) => {
959
- if (timer) clearTimeout(timer);
960
- reject(err);
961
- });
962
- child.on("close", (code) => {
963
- if (timer) clearTimeout(timer);
964
- if (stdoutTruncated || stderrTruncated) {
965
- reject(/* @__PURE__ */ new Error(`mcporter ${args.join(" ")} produced too much output (limit ${this.maxQmdOutputChars} chars)`));
966
- return;
967
- }
968
- if (code === 0) resolve({
969
- stdout,
970
- stderr
971
- });
972
- else reject(/* @__PURE__ */ new Error(`mcporter ${args.join(" ")} failed (code ${code}): ${stderr || stdout}`));
973
- });
974
- });
975
- }
976
- async runQmdSearchViaMcporter(params) {
977
- await this.ensureMcporterDaemonStarted(params.mcporter);
978
- const selector = `${params.mcporter.serverName}.${params.tool}`;
979
- const callArgs = {
980
- query: params.query,
981
- limit: params.limit,
982
- minScore: params.minScore
983
- };
984
- if (params.collection) callArgs.collection = params.collection;
985
- const result = await this.runMcporter([
986
- "call",
987
- selector,
988
- "--args",
989
- JSON.stringify(callArgs),
990
- "--output",
991
- "json",
992
- "--timeout",
993
- String(Math.max(0, params.timeoutMs))
994
- ], { timeoutMs: Math.max(params.timeoutMs + 2e3, 5e3) });
995
- const parsedUnknown = JSON.parse(result.stdout);
996
- const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
997
- const structured = isRecord(parsedUnknown) && isRecord(parsedUnknown.structuredContent) ? parsedUnknown.structuredContent : parsedUnknown;
998
- const results = isRecord(structured) && Array.isArray(structured.results) ? structured.results : Array.isArray(structured) ? structured : [];
999
- const out = [];
1000
- for (const item of results) {
1001
- if (!isRecord(item)) continue;
1002
- const docidRaw = item.docid;
1003
- const docid = typeof docidRaw === "string" ? docidRaw.replace(/^#/, "").trim() : "";
1004
- if (!docid) continue;
1005
- const scoreRaw = item.score;
1006
- const score = typeof scoreRaw === "number" ? scoreRaw : Number(scoreRaw);
1007
- const snippet = typeof item.snippet === "string" ? item.snippet : "";
1008
- out.push({
1009
- docid,
1010
- score: Number.isFinite(score) ? score : 0,
1011
- snippet
1012
- });
1013
- }
1014
- return out;
1015
- }
1016
- async readPartialText(absPath, from, lines) {
1017
- const start = Math.max(1, from ?? 1);
1018
- const count = Math.max(1, lines ?? Number.POSITIVE_INFINITY);
1019
- let handle;
1020
- try {
1021
- handle = await fsPromises.open(absPath);
1022
- } catch (err) {
1023
- if (isFileMissingError(err)) return { missing: true };
1024
- throw err;
1025
- }
1026
- const stream = handle.createReadStream({ encoding: "utf-8" });
1027
- const rl = readline.createInterface({
1028
- input: stream,
1029
- crlfDelay: Infinity
1030
- });
1031
- const selected = [];
1032
- let index = 0;
1033
- try {
1034
- for await (const line of rl) {
1035
- index += 1;
1036
- if (index < start) continue;
1037
- if (selected.length >= count) break;
1038
- selected.push(line);
1039
- }
1040
- } finally {
1041
- rl.close();
1042
- await handle.close();
1043
- }
1044
- return {
1045
- missing: false,
1046
- text: selected.slice(0, count).join("\n")
1047
- };
1048
- }
1049
- async readFullText(absPath) {
1050
- try {
1051
- return {
1052
- missing: false,
1053
- text: await fsPromises.readFile(absPath, "utf-8")
1054
- };
1055
- } catch (err) {
1056
- if (isFileMissingError(err)) return { missing: true };
1057
- throw err;
1058
- }
1059
- }
1060
- ensureDb() {
1061
- if (this.db) return this.db;
1062
- const { DatabaseSync } = requireNodeSqlite();
1063
- this.db = new DatabaseSync(this.indexPath, { readOnly: true });
1064
- this.db.exec("PRAGMA busy_timeout = 1");
1065
- return this.db;
1066
- }
1067
- async exportSessions() {
1068
- if (!this.sessionExporter) return;
1069
- const exportDir = this.sessionExporter.dir;
1070
- await fsPromises.mkdir(exportDir, { recursive: true });
1071
- const files = await listSessionFilesForAgent(this.agentId);
1072
- const keep = /* @__PURE__ */ new Set();
1073
- const tracked = /* @__PURE__ */ new Set();
1074
- const cutoff = this.sessionExporter.retentionMs ? Date.now() - this.sessionExporter.retentionMs : null;
1075
- for (const sessionFile of files) {
1076
- const entry = await buildSessionEntry(sessionFile);
1077
- if (!entry) continue;
1078
- if (cutoff && entry.mtimeMs < cutoff) continue;
1079
- const targetName = `${path.basename(sessionFile, ".jsonl")}.md`;
1080
- const target = path.join(exportDir, targetName);
1081
- tracked.add(sessionFile);
1082
- const state = this.exportedSessionState.get(sessionFile);
1083
- if (!state || state.hash !== entry.hash || state.mtimeMs !== entry.mtimeMs) await writeFileWithinRoot({
1084
- rootDir: exportDir,
1085
- relativePath: targetName,
1086
- data: this.renderSessionMarkdown(entry),
1087
- encoding: "utf-8"
1088
- });
1089
- this.exportedSessionState.set(sessionFile, {
1090
- hash: entry.hash,
1091
- mtimeMs: entry.mtimeMs,
1092
- target
1093
- });
1094
- keep.add(target);
1095
- }
1096
- const exported = await fsPromises.readdir(exportDir).catch(() => []);
1097
- for (const name of exported) {
1098
- if (!name.endsWith(".md")) continue;
1099
- const full = path.join(exportDir, name);
1100
- if (!keep.has(full)) await fsPromises.rm(full, { force: true });
1101
- }
1102
- for (const [sessionFile, state] of this.exportedSessionState) if (!tracked.has(sessionFile) || !state.target.startsWith(exportDir + path.sep)) this.exportedSessionState.delete(sessionFile);
1103
- }
1104
- renderSessionMarkdown(entry) {
1105
- return `${`# Session ${path.basename(entry.absPath, path.extname(entry.absPath))}`}\n\n${entry.content?.trim().length ? entry.content.trim() : "(empty)"}\n`;
1106
- }
1107
- pickSessionCollectionName() {
1108
- const existing = new Set(this.qmd.collections.map((collection) => collection.name));
1109
- const base = `sessions-${this.sanitizeCollectionNameSegment(this.agentId)}`;
1110
- if (!existing.has(base)) return base;
1111
- let counter = 2;
1112
- let candidate = `${base}-${counter}`;
1113
- while (existing.has(candidate)) {
1114
- counter += 1;
1115
- candidate = `${base}-${counter}`;
1116
- }
1117
- return candidate;
1118
- }
1119
- sanitizeCollectionNameSegment(input) {
1120
- return input.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "agent";
1121
- }
1122
- async resolveDocLocation(docid, hints) {
1123
- if (!docid) return null;
1124
- const normalized = docid.startsWith("#") ? docid.slice(1) : docid;
1125
- if (!normalized) return null;
1126
- const cacheKey = `${hints?.preferredCollection ?? "*"}:${normalized}`;
1127
- const cached = this.docPathCache.get(cacheKey);
1128
- if (cached) return cached;
1129
- const db = this.ensureDb();
1130
- let rows = [];
1131
- try {
1132
- rows = db.prepare("SELECT collection, path FROM documents WHERE hash = ? AND active = 1").all(normalized);
1133
- if (rows.length === 0) rows = db.prepare("SELECT collection, path FROM documents WHERE hash LIKE ? AND active = 1").all(`${normalized}%`);
1134
- } catch (err) {
1135
- if (this.isSqliteBusyError(err)) {
1136
- log.debug(`qmd index is busy while resolving doc path: ${String(err)}`);
1137
- throw this.createQmdBusyError(err);
1138
- }
1139
- throw err;
1140
- }
1141
- if (rows.length === 0) return null;
1142
- const location = this.pickDocLocation(rows, hints);
1143
- if (!location) return null;
1144
- this.docPathCache.set(cacheKey, location);
1145
- return location;
1146
- }
1147
- pickDocLocation(rows, hints) {
1148
- if (hints?.preferredCollection) for (const row of rows) {
1149
- if (row.collection !== hints.preferredCollection) continue;
1150
- const location = this.toDocLocation(row.collection, row.path);
1151
- if (location) return location;
1152
- }
1153
- if (hints?.preferredFile) {
1154
- const preferred = path.normalize(hints.preferredFile);
1155
- for (const row of rows) {
1156
- const rowPath = path.normalize(row.path);
1157
- if (rowPath !== preferred && !rowPath.endsWith(path.sep + preferred)) continue;
1158
- const location = this.toDocLocation(row.collection, row.path);
1159
- if (location) return location;
1160
- }
1161
- }
1162
- for (const row of rows) {
1163
- const location = this.toDocLocation(row.collection, row.path);
1164
- if (location) return location;
1165
- }
1166
- return null;
1167
- }
1168
- extractSnippetLines(snippet) {
1169
- const match = SNIPPET_HEADER_RE.exec(snippet);
1170
- if (match) {
1171
- const start = Number(match[1]);
1172
- const count = Number(match[2]);
1173
- if (Number.isFinite(start) && Number.isFinite(count)) return {
1174
- startLine: start,
1175
- endLine: start + count - 1
1176
- };
1177
- }
1178
- return {
1179
- startLine: 1,
1180
- endLine: snippet.split("\n").length
1181
- };
1182
- }
1183
- readCounts() {
1184
- try {
1185
- const rows = this.ensureDb().prepare("SELECT collection, COUNT(*) as c FROM documents WHERE active = 1 GROUP BY collection").all();
1186
- const bySource = /* @__PURE__ */ new Map();
1187
- for (const source of this.sources) bySource.set(source, {
1188
- files: 0,
1189
- chunks: 0
1190
- });
1191
- let total = 0;
1192
- for (const row of rows) {
1193
- const source = this.collectionRoots.get(row.collection)?.kind ?? "memory";
1194
- const entry = bySource.get(source) ?? {
1195
- files: 0,
1196
- chunks: 0
1197
- };
1198
- entry.files += row.c ?? 0;
1199
- entry.chunks += row.c ?? 0;
1200
- bySource.set(source, entry);
1201
- total += row.c ?? 0;
1202
- }
1203
- return {
1204
- totalDocuments: total,
1205
- sourceCounts: Array.from(bySource.entries()).map(([source, value]) => ({
1206
- source,
1207
- files: value.files,
1208
- chunks: value.chunks
1209
- }))
1210
- };
1211
- } catch (err) {
1212
- log.warn(`failed to read qmd index stats: ${String(err)}`);
1213
- return {
1214
- totalDocuments: 0,
1215
- sourceCounts: Array.from(this.sources).map((source) => ({
1216
- source,
1217
- files: 0,
1218
- chunks: 0
1219
- }))
1220
- };
1221
- }
1222
- }
1223
- logScopeDenied(sessionKey) {
1224
- const channel = deriveQmdScopeChannel(sessionKey) ?? "unknown";
1225
- const chatType = deriveQmdScopeChatType(sessionKey) ?? "unknown";
1226
- const key = sessionKey?.trim() || "<none>";
1227
- log.warn(`qmd search denied by scope (channel=${channel}, chatType=${chatType}, session=${key})`);
1228
- }
1229
- isScopeAllowed(sessionKey) {
1230
- return isQmdScopeAllowed(this.qmd.scope, sessionKey);
1231
- }
1232
- toDocLocation(collection, collectionRelativePath) {
1233
- const root = this.collectionRoots.get(collection);
1234
- if (!root) return null;
1235
- const normalizedRelative = collectionRelativePath.replace(/\\/g, "/");
1236
- const absPath = path.normalize(path.resolve(root.path, collectionRelativePath));
1237
- const relativeToWorkspace = path.relative(this.workspaceDir, absPath);
1238
- return {
1239
- rel: this.buildSearchPath(collection, normalizedRelative, relativeToWorkspace, absPath),
1240
- abs: absPath,
1241
- source: root.kind
1242
- };
1243
- }
1244
- buildSearchPath(collection, collectionRelativePath, relativeToWorkspace, absPath) {
1245
- if (this.isInsideWorkspace(relativeToWorkspace)) {
1246
- const normalized = relativeToWorkspace.replace(/\\/g, "/");
1247
- if (!normalized) return path.basename(absPath);
1248
- return normalized;
1249
- }
1250
- return `qmd/${collection}/${collectionRelativePath.replace(/^\/+/, "")}`;
1251
- }
1252
- isInsideWorkspace(relativePath) {
1253
- if (!relativePath) return true;
1254
- if (relativePath.startsWith("..")) return false;
1255
- if (relativePath.startsWith(`..${path.sep}`)) return false;
1256
- return !path.isAbsolute(relativePath);
1257
- }
1258
- resolveReadPath(relPath) {
1259
- if (relPath.startsWith("qmd/")) {
1260
- const [, collection, ...rest] = relPath.split("/");
1261
- if (!collection || rest.length === 0) throw new Error("invalid qmd path");
1262
- const root = this.collectionRoots.get(collection);
1263
- if (!root) throw new Error(`unknown qmd collection: ${collection}`);
1264
- const joined = rest.join("/");
1265
- const resolved = path.resolve(root.path, joined);
1266
- if (!this.isWithinRoot(root.path, resolved)) throw new Error("qmd path escapes collection");
1267
- return resolved;
1268
- }
1269
- const absPath = path.resolve(this.workspaceDir, relPath);
1270
- if (!this.isWithinWorkspace(absPath)) throw new Error("path escapes workspace");
1271
- return absPath;
1272
- }
1273
- isWithinWorkspace(absPath) {
1274
- const normalizedWorkspace = this.workspaceDir.endsWith(path.sep) ? this.workspaceDir : `${this.workspaceDir}${path.sep}`;
1275
- if (absPath === this.workspaceDir) return true;
1276
- return (absPath.endsWith(path.sep) ? absPath : `${absPath}${path.sep}`).startsWith(normalizedWorkspace);
1277
- }
1278
- isWithinRoot(root, candidate) {
1279
- const normalizedRoot = root.endsWith(path.sep) ? root : `${root}${path.sep}`;
1280
- if (candidate === root) return true;
1281
- return (candidate.endsWith(path.sep) ? candidate : `${candidate}${path.sep}`).startsWith(normalizedRoot);
1282
- }
1283
- clampResultsByInjectedChars(results) {
1284
- const budget = this.qmd.limits.maxInjectedChars;
1285
- if (!budget || budget <= 0) return results;
1286
- let remaining = budget;
1287
- const clamped = [];
1288
- for (const entry of results) {
1289
- if (remaining <= 0) break;
1290
- const snippet = entry.snippet ?? "";
1291
- if (snippet.length <= remaining) {
1292
- clamped.push(entry);
1293
- remaining -= snippet.length;
1294
- } else {
1295
- const trimmed = snippet.slice(0, Math.max(0, remaining));
1296
- clamped.push({
1297
- ...entry,
1298
- snippet: trimmed
1299
- });
1300
- break;
1301
- }
1302
- }
1303
- return clamped;
1304
- }
1305
- diversifyResultsBySource(results, limit) {
1306
- const target = Math.max(0, limit);
1307
- if (target <= 0) return [];
1308
- if (results.length <= 1) return results.slice(0, target);
1309
- const bySource = /* @__PURE__ */ new Map();
1310
- for (const entry of results) {
1311
- const list = bySource.get(entry.source) ?? [];
1312
- list.push(entry);
1313
- bySource.set(entry.source, list);
1314
- }
1315
- const hasSessions = bySource.has("sessions");
1316
- const hasMemory = bySource.has("memory");
1317
- if (!hasSessions || !hasMemory) return results.slice(0, target);
1318
- const sourceOrder = Array.from(bySource.entries()).toSorted((a, b) => (b[1][0]?.score ?? 0) - (a[1][0]?.score ?? 0)).map(([source]) => source);
1319
- const diversified = [];
1320
- while (diversified.length < target) {
1321
- let emitted = false;
1322
- for (const source of sourceOrder) {
1323
- const next = bySource.get(source)?.shift();
1324
- if (!next) continue;
1325
- diversified.push(next);
1326
- emitted = true;
1327
- if (diversified.length >= target) break;
1328
- }
1329
- if (!emitted) break;
1330
- }
1331
- return diversified;
1332
- }
1333
- shouldSkipUpdate(force) {
1334
- if (force) return false;
1335
- const debounceMs = this.qmd.update.debounceMs;
1336
- if (debounceMs <= 0) return false;
1337
- if (!this.lastUpdateAt) return false;
1338
- return Date.now() - this.lastUpdateAt < debounceMs;
1339
- }
1340
- isSqliteBusyError(err) {
1341
- const normalized = (err instanceof Error ? err.message : String(err)).toLowerCase();
1342
- return normalized.includes("sqlite_busy") || normalized.includes("database is locked");
1343
- }
1344
- isUnsupportedQmdOptionError(err) {
1345
- const normalized = (err instanceof Error ? err.message : String(err)).toLowerCase();
1346
- return normalized.includes("unknown flag") || normalized.includes("unknown option") || normalized.includes("unrecognized option") || normalized.includes("flag provided but not defined") || normalized.includes("unexpected argument");
1347
- }
1348
- createQmdBusyError(err) {
1349
- const message = err instanceof Error ? err.message : String(err);
1350
- return /* @__PURE__ */ new Error(`qmd index busy while reading results: ${message}`);
1351
- }
1352
- async waitForPendingUpdateBeforeSearch() {
1353
- const pending = this.pendingUpdate;
1354
- if (!pending) return;
1355
- await Promise.race([pending.catch(() => void 0), new Promise((resolve) => setTimeout(resolve, SEARCH_PENDING_UPDATE_WAIT_MS))]);
1356
- }
1357
- async runQueryAcrossCollections(query, limit, collectionNames, command) {
1358
- log.debug(`qmd ${command} multi-collection workaround active (${collectionNames.length} collections)`);
1359
- const bestByDocId = /* @__PURE__ */ new Map();
1360
- for (const collectionName of collectionNames) {
1361
- const args = this.buildSearchArgs(command, query, limit);
1362
- args.push("-c", collectionName);
1363
- const result = await this.runQmd(args, { timeoutMs: this.qmd.limits.timeoutMs });
1364
- const parsed = parseQmdQueryJson(result.stdout, result.stderr);
1365
- for (const entry of parsed) {
1366
- const normalizedDocId = typeof entry.docid === "string" && entry.docid.trim().length > 0 ? entry.docid : void 0;
1367
- if (!normalizedDocId) continue;
1368
- const withCollection = {
1369
- ...entry,
1370
- docid: normalizedDocId,
1371
- collection: entry.collection ?? collectionName
1372
- };
1373
- const prev = bestByDocId.get(normalizedDocId);
1374
- const prevScore = typeof prev?.score === "number" ? prev.score : Number.NEGATIVE_INFINITY;
1375
- const nextScore = typeof withCollection.score === "number" ? withCollection.score : Number.NEGATIVE_INFINITY;
1376
- if (!prev || nextScore > prevScore) bestByDocId.set(normalizedDocId, withCollection);
1377
- }
1378
- }
1379
- return [...bestByDocId.values()].toSorted((a, b) => (b.score ?? 0) - (a.score ?? 0));
1380
- }
1381
- async runMcporterAcrossCollections(params) {
1382
- const bestByDocId = /* @__PURE__ */ new Map();
1383
- for (const collectionName of params.collectionNames) {
1384
- const parsed = await this.runQmdSearchViaMcporter({
1385
- mcporter: this.qmd.mcporter,
1386
- tool: params.tool,
1387
- query: params.query,
1388
- limit: params.limit,
1389
- minScore: params.minScore,
1390
- collection: collectionName,
1391
- timeoutMs: this.qmd.limits.timeoutMs
1392
- });
1393
- for (const entry of parsed) {
1394
- if (typeof entry.docid !== "string" || !entry.docid.trim()) continue;
1395
- const prev = bestByDocId.get(entry.docid);
1396
- const prevScore = typeof prev?.score === "number" ? prev.score : Number.NEGATIVE_INFINITY;
1397
- const nextScore = typeof entry.score === "number" ? entry.score : Number.NEGATIVE_INFINITY;
1398
- if (!prev || nextScore > prevScore) bestByDocId.set(entry.docid, entry);
1399
- }
1400
- }
1401
- return [...bestByDocId.values()].toSorted((a, b) => (b.score ?? 0) - (a.score ?? 0));
1402
- }
1403
- listManagedCollectionNames() {
1404
- return this.managedCollectionNames;
1405
- }
1406
- computeManagedCollectionNames() {
1407
- const seen = /* @__PURE__ */ new Set();
1408
- const names = [];
1409
- for (const collection of this.qmd.collections) {
1410
- const name = collection.name?.trim();
1411
- if (!name || seen.has(name)) continue;
1412
- seen.add(name);
1413
- names.push(name);
1414
- }
1415
- return names;
1416
- }
1417
- buildCollectionFilterArgs(collectionNames) {
1418
- if (collectionNames.length === 0) return [];
1419
- return collectionNames.filter(Boolean).flatMap((name) => ["-c", name]);
1420
- }
1421
- buildSearchArgs(command, query, limit) {
1422
- const normalizedQuery = command === "search" ? normalizeHanBm25Query(query) : query;
1423
- if (command === "query") return [
1424
- "query",
1425
- normalizedQuery,
1426
- "--json",
1427
- "-n",
1428
- String(limit)
1429
- ];
1430
- return [
1431
- command,
1432
- normalizedQuery,
1433
- "--json",
1434
- "-n",
1435
- String(limit)
1436
- ];
1437
- }
1438
- };
1439
- function appendOutputWithCap(current, chunk, maxChars) {
1440
- const appended = current + chunk;
1441
- if (appended.length <= maxChars) return {
1442
- text: appended,
1443
- truncated: false
1444
- };
1445
- return {
1446
- text: appended.slice(-maxChars),
1447
- truncated: true
1448
- };
1449
- }
1450
-
1451
- //#endregion
1452
- export { QmdMemoryManager };