@datasynx/agentic-crm 0.1.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. package/README.md +270 -669
  2. package/dist/{approvals-DpjxGHFp.js → approvals-CmDT2eUg.js} +7 -24
  3. package/dist/approvals-CmDT2eUg.js.map +1 -0
  4. package/dist/{ask-CID3jnuL.js → ask-CDysGnRg.js} +6 -6
  5. package/dist/{ask-CID3jnuL.js.map → ask-CDysGnRg.js.map} +1 -1
  6. package/dist/atomic-write-8yjqqLtS.js +29 -0
  7. package/dist/atomic-write-8yjqqLtS.js.map +1 -0
  8. package/dist/atomic-write-BYmF-ThH.cjs +37 -0
  9. package/dist/atomic-write-BYmF-ThH.cjs.map +1 -0
  10. package/dist/attachments-CX2GAtsw.cjs +517 -0
  11. package/dist/attachments-CX2GAtsw.cjs.map +1 -0
  12. package/dist/attachments-D207gXfN.js +514 -0
  13. package/dist/attachments-D207gXfN.js.map +1 -0
  14. package/dist/attachments-rLa96rOK.js +514 -0
  15. package/dist/attachments-rLa96rOK.js.map +1 -0
  16. package/dist/auth-B5DcjJ_6.js +2 -0
  17. package/dist/{auth-DFWwWcYD.js → auth-DDXZTwS0.js} +4 -13
  18. package/dist/auth-DDXZTwS0.js.map +1 -0
  19. package/dist/{autofill-Di_-SP7t.js → autofill-B9VtlR2j.js} +2 -2
  20. package/dist/{autofill-Di_-SP7t.js.map → autofill-B9VtlR2j.js.map} +1 -1
  21. package/dist/{backup-CeMk9z86.js → backup-CTlIxUdO.js} +5 -7
  22. package/dist/backup-CTlIxUdO.js.map +1 -0
  23. package/dist/backup-LFnC09oV.js +2 -0
  24. package/dist/chunk-BfDYWZQ8.cjs +32 -0
  25. package/dist/chunk-BfDYWZQ8.cjs.map +1 -0
  26. package/dist/chunk-BhUZmQg5.js +32 -0
  27. package/dist/chunk-BhUZmQg5.js.map +1 -0
  28. package/dist/chunk-ChC83jai.js +2 -0
  29. package/dist/chunk-e_w8qqtP.js +32 -0
  30. package/dist/chunk-e_w8qqtP.js.map +1 -0
  31. package/dist/{churn-C28IgnAj.js → churn-DN9WDGNM.js} +3 -3
  32. package/dist/{churn-C28IgnAj.js.map → churn-DN9WDGNM.js.map} +1 -1
  33. package/dist/cli.js +285 -186
  34. package/dist/cli.js.map +1 -1
  35. package/dist/{compliance-CKSBoQUe.js → compliance-Bc12Hn9a.js} +3 -3
  36. package/dist/{compliance-CKSBoQUe.js.map → compliance-Bc12Hn9a.js.map} +1 -1
  37. package/dist/{compliance-CujOqAKk.js → compliance-TqYQXhBj.js} +1 -1
  38. package/dist/{compliance-B1kk5-YS.js → compliance-kq0xHRw3.js} +3 -3
  39. package/dist/{compliance-B1kk5-YS.js.map → compliance-kq0xHRw3.js.map} +1 -1
  40. package/dist/{compliance-B91zNvCR.cjs → compliance-pAj9FcGI.cjs} +3 -3
  41. package/dist/{compliance-B91zNvCR.cjs.map → compliance-pAj9FcGI.cjs.map} +1 -1
  42. package/dist/{context-builder-BzWAp3Zs.js → context-builder-7Uab5-G4.js} +3 -2
  43. package/dist/context-builder-7Uab5-G4.js.map +1 -0
  44. package/dist/context-builder-hmOPvgso.js +2 -0
  45. package/dist/{custom-fields-CzNeD3_v.js → custom-fields-BMyz5Ruh.js} +1 -1
  46. package/dist/{custom-fields-Pl2t9xzp.js → custom-fields-GzpOHW_2.js} +4 -13
  47. package/dist/custom-fields-GzpOHW_2.js.map +1 -0
  48. package/dist/{custom-objects-CIFrmQ2V.js → custom-objects-BNy-ayR-.js} +1 -1
  49. package/dist/{custom-objects-BHgn1GEX.js → custom-objects-CxW1gHwJ.js} +10 -25
  50. package/dist/custom-objects-CxW1gHwJ.js.map +1 -0
  51. package/dist/{customer-dir-DIylZ8Q6.js → customer-dir-CkMMXhb0.js} +9 -4
  52. package/dist/customer-dir-CkMMXhb0.js.map +1 -0
  53. package/dist/daemon/worker.js +66 -40
  54. package/dist/daemon/worker.js.map +1 -1
  55. package/dist/doctor-C14-vnJ1.js +103 -0
  56. package/dist/doctor-C14-vnJ1.js.map +1 -0
  57. package/dist/email-body-BFSRa0AW.cjs +42 -0
  58. package/dist/email-body-BFSRa0AW.cjs.map +1 -0
  59. package/dist/email-body-BOd7U-D2.js +42 -0
  60. package/dist/email-body-BOd7U-D2.js.map +1 -0
  61. package/dist/{enrichment-3XvgGDfB.js → enrichment-CDFdWmvD.js} +3 -3
  62. package/dist/{enrichment-3XvgGDfB.js.map → enrichment-CDFdWmvD.js.map} +1 -1
  63. package/dist/{file-lock-B_zi7NQl.js → file-lock-CcHotQkZ.js} +3 -4
  64. package/dist/file-lock-CcHotQkZ.js.map +1 -0
  65. package/dist/{gmail-sync-DIaxInDT.js → gmail-sync-B4Iu3AQb.js} +56 -22
  66. package/dist/gmail-sync-B4Iu3AQb.js.map +1 -0
  67. package/dist/{gmail-sync-hHm9gaWd.cjs → gmail-sync-BpSVESSe.cjs} +55 -21
  68. package/dist/gmail-sync-BpSVESSe.cjs.map +1 -0
  69. package/dist/{gmail-sync-rQaVqKWd.js → gmail-sync-DIbrPnTK.js} +55 -21
  70. package/dist/gmail-sync-DIbrPnTK.js.map +1 -0
  71. package/dist/{gmail-webhook-handler-e5Od25FX.js → gmail-webhook-handler-BzOFbvgh.js} +4 -4
  72. package/dist/{gmail-webhook-handler-e5Od25FX.js.map → gmail-webhook-handler-BzOFbvgh.js.map} +1 -1
  73. package/dist/{gmail-webhook-handler-DS7OlRPX.js → gmail-webhook-handler-CvSDW_Js.js} +2 -2
  74. package/dist/{goal-engine-KpBftn4V.js → goal-engine-BbroPhqm.js} +10 -11
  75. package/dist/goal-engine-BbroPhqm.js.map +1 -0
  76. package/dist/{goal-engine-CUZSpERI.js → goal-engine-CfDAJTFt.js} +1 -1
  77. package/dist/{google-drive-sync-DEPcqFca.js → google-drive-sync-B_I1d54Y.js} +3 -3
  78. package/dist/{google-drive-sync-DEPcqFca.js.map → google-drive-sync-B_I1d54Y.js.map} +1 -1
  79. package/dist/html-BaeOCZKE.js +36 -0
  80. package/dist/html-BaeOCZKE.js.map +1 -0
  81. package/dist/html-CmOku6jS.cjs +47 -0
  82. package/dist/html-CmOku6jS.cjs.map +1 -0
  83. package/dist/{hygiene-DZqfYpFf.js → hygiene-DzQPnc6P.js} +3 -3
  84. package/dist/{hygiene-DZqfYpFf.js.map → hygiene-DzQPnc6P.js.map} +1 -1
  85. package/dist/identity-CB7j-Zr1.js +2 -0
  86. package/dist/{identity-CI6olMNm.js → identity-_uZ3Lbr2.js} +2 -2
  87. package/dist/{identity-CI6olMNm.js.map → identity-_uZ3Lbr2.js.map} +1 -1
  88. package/dist/{import-hubspot-BaK71U_K.js → import-hubspot-CTId9IGV.js} +51 -45
  89. package/dist/import-hubspot-CTId9IGV.js.map +1 -0
  90. package/dist/{index-YqwMd6aQ.d.cts → index-BAutNcAT.d.cts} +20 -12
  91. package/dist/index-BAutNcAT.d.cts.map +1 -0
  92. package/dist/{index-V8BFaH-b.d.ts → index-FzDsNSSb.d.ts} +12 -4
  93. package/dist/index-FzDsNSSb.d.ts.map +1 -0
  94. package/dist/index.cjs +19 -21
  95. package/dist/index.cjs.map +1 -1
  96. package/dist/index.d.cts +20 -12
  97. package/dist/index.d.cts.map +1 -1
  98. package/dist/index.d.ts +12 -4
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +19 -21
  101. package/dist/index.js.map +1 -1
  102. package/dist/interactions-writer-B2y-73lh.js +2 -0
  103. package/dist/{interactions-writer-SLHnoEeE.js → interactions-writer-B8XAzdqR.js} +34 -4
  104. package/dist/interactions-writer-B8XAzdqR.js.map +1 -0
  105. package/dist/{interactions-writer-CrPStUll.cjs → interactions-writer-BRJNrefF.cjs} +7 -3
  106. package/dist/interactions-writer-BRJNrefF.cjs.map +1 -0
  107. package/dist/{interactions-writer-DO3KcSR3.js → interactions-writer-ZQcpFOh9.js} +7 -3
  108. package/dist/interactions-writer-ZQcpFOh9.js.map +1 -0
  109. package/dist/json-store-WWsFzXub.js +43 -0
  110. package/dist/json-store-WWsFzXub.js.map +1 -0
  111. package/dist/{knowledge-base-D0Fh40kc.js → knowledge-base--063Kpa3.js} +51 -22
  112. package/dist/knowledge-base--063Kpa3.js.map +1 -0
  113. package/dist/{lancedb-CCBbpulq.js → lancedb-CswQEE5K.js} +1 -1
  114. package/dist/{lancedb-rlvWoPwl.js → lancedb-CuHKNsNZ.js} +4 -3
  115. package/dist/lancedb-CuHKNsNZ.js.map +1 -0
  116. package/dist/{lead-model-BCFzyktm.js → lead-model-CEmx7te7.js} +6 -14
  117. package/dist/lead-model-CEmx7te7.js.map +1 -0
  118. package/dist/{llm-Z8RIYkpF.js → llm-BnSUBisu.js} +2 -2
  119. package/dist/{llm-Z8RIYkpF.js.map → llm-BnSUBisu.js.map} +1 -1
  120. package/dist/{llm-iijeXmgq.cjs → llm-CXycmEl9.cjs} +2 -2
  121. package/dist/{llm-iijeXmgq.cjs.map → llm-CXycmEl9.cjs.map} +1 -1
  122. package/dist/{llm-DEjWcqmW.js → llm-DSX1-wFu.js} +1 -1
  123. package/dist/{llm-DvzZqva0.js → llm-PZzgPphl.js} +3 -3
  124. package/dist/{llm-DvzZqva0.js.map → llm-PZzgPphl.js.map} +1 -1
  125. package/dist/logger-BkInaGoV.cjs +167 -0
  126. package/dist/logger-BkInaGoV.cjs.map +1 -0
  127. package/dist/logger-Dyl4VcLO.js +147 -0
  128. package/dist/logger-Dyl4VcLO.js.map +1 -0
  129. package/dist/logger-UaF5p9d1.js +147 -0
  130. package/dist/logger-UaF5p9d1.js.map +1 -0
  131. package/dist/logger-vKQS34w9.js +2 -0
  132. package/dist/mcp-CdTJWTJf.d.cts.map +1 -1
  133. package/dist/mcp-CdTJWTJf.d.ts.map +1 -1
  134. package/dist/mcp.cjs +365 -319
  135. package/dist/mcp.cjs.map +1 -1
  136. package/dist/mcp.d.cts.map +1 -1
  137. package/dist/mcp.d.ts.map +1 -1
  138. package/dist/mcp.js +365 -319
  139. package/dist/mcp.js.map +1 -1
  140. package/dist/{memory-Cy6-Tbyl.js → memory-D8hmgD9d.js} +1 -1
  141. package/dist/{memory-Bb6ky3kb.js → memory-Dzr9dXSM.js} +4 -11
  142. package/dist/memory-Dzr9dXSM.js.map +1 -0
  143. package/dist/{microsoft-calendar-B6MMtUQK.js → microsoft-calendar-BgVR8GDv.js} +4 -4
  144. package/dist/{microsoft-calendar-B6MMtUQK.js.map → microsoft-calendar-BgVR8GDv.js.map} +1 -1
  145. package/dist/{microsoft-sync-CpZVoSuq.js → microsoft-sync-D30_XksI.js} +5 -5
  146. package/dist/{microsoft-sync-CpZVoSuq.js.map → microsoft-sync-D30_XksI.js.map} +1 -1
  147. package/dist/{nba-3wanmJ0U.js → nba-DwdfM93s.js} +3 -3
  148. package/dist/{nba-3wanmJ0U.js.map → nba-DwdfM93s.js.map} +1 -1
  149. package/dist/{notification-dispatcher-0vYNngWe.js → notification-dispatcher-inpKyuBz.js} +7 -3
  150. package/dist/notification-dispatcher-inpKyuBz.js.map +1 -0
  151. package/dist/{pipeline-writer-BqBrYrQc.js → pipeline-writer-0LJ6Qkat.js} +1 -1
  152. package/dist/{pipeline-writer-N2omexxp.cjs → pipeline-writer-B1tRAhuD.cjs} +11 -3
  153. package/dist/pipeline-writer-B1tRAhuD.cjs.map +1 -0
  154. package/dist/{pipeline-writer-BvVquKIe.js → pipeline-writer-CIllfnZl.js} +5 -3
  155. package/dist/pipeline-writer-CIllfnZl.js.map +1 -0
  156. package/dist/{pipeline-writer-eufx_0o1.js → pipeline-writer-rDj-ni6q.js} +6 -4
  157. package/dist/pipeline-writer-rDj-ni6q.js.map +1 -0
  158. package/dist/{proactive-agent-BgQXw3ac.js → proactive-agent-B7u3Bj_l.js} +6 -6
  159. package/dist/{proactive-agent-BgQXw3ac.js.map → proactive-agent-B7u3Bj_l.js.map} +1 -1
  160. package/dist/{proactive-worker-BrLHNhjH.js → proactive-worker-1zkm6aJD.js} +7 -8
  161. package/dist/proactive-worker-1zkm6aJD.js.map +1 -0
  162. package/dist/{push-manager-CowY-0IK.js → push-manager-BXM-IHfP.js} +1 -1
  163. package/dist/{push-manager-CdqIIkuh.js → push-manager-C0ECQgva.js} +4 -4
  164. package/dist/push-manager-C0ECQgva.js.map +1 -0
  165. package/dist/{quote-generator-OhSFsi3x.js → quote-generator-ByUyIYtw.js} +1 -1
  166. package/dist/{quote-generator-BfwENXzg.js → quote-generator-CTdR8eEI.js} +5 -5
  167. package/dist/quote-generator-CTdR8eEI.js.map +1 -0
  168. package/dist/rbac-DzbyFhVH.js +2 -0
  169. package/dist/{rbac-CTIktZaC.js → rbac-msmBc_tK.js} +19 -12
  170. package/dist/rbac-msmBc_tK.js.map +1 -0
  171. package/dist/regex-Jt5DatPi.js +13 -0
  172. package/dist/regex-Jt5DatPi.js.map +1 -0
  173. package/dist/{relationship-health-odxEoQdJ.js → relationship-health-ZZNXR1RZ.js} +8 -16
  174. package/dist/relationship-health-ZZNXR1RZ.js.map +1 -0
  175. package/dist/{revenue-simulation-Bqf2DLVB.js → revenue-simulation-D8f_YkUY.js} +9 -19
  176. package/dist/revenue-simulation-D8f_YkUY.js.map +1 -0
  177. package/dist/{revenue-simulation-BJdRTEHc.js → revenue-simulation-njJZlTqm.js} +1 -1
  178. package/dist/safe-path-mpp0dKtO.js +18 -0
  179. package/dist/safe-path-mpp0dKtO.js.map +1 -0
  180. package/dist/{segments-BqcD5HIl.js → segments-DI3LOQNe.js} +5 -14
  181. package/dist/segments-DI3LOQNe.js.map +1 -0
  182. package/dist/sequence-engine-C6nnewHX.js +2 -0
  183. package/dist/{sequence-engine-J1lTW_in.js → sequence-engine-DNTVLq7o.js} +15 -8
  184. package/dist/sequence-engine-DNTVLq7o.js.map +1 -0
  185. package/dist/{sequence-store-DaaWr0Os.js → sequence-store-CmYb6s0g.js} +6 -5
  186. package/dist/sequence-store-CmYb6s0g.js.map +1 -0
  187. package/dist/{server-Dyva03K8.js → server-DoRPPOeR.js} +308 -230
  188. package/dist/server-DoRPPOeR.js.map +1 -0
  189. package/dist/{session-D9ub6Wl1.js → session-B6XaP83h.js} +3 -3
  190. package/dist/session-B6XaP83h.js.map +1 -0
  191. package/dist/{session-B9AilxOE.js → session-BgGDyP2C.js} +3 -3
  192. package/dist/session-BgGDyP2C.js.map +1 -0
  193. package/dist/session-Bp4zTh4l.js +2 -0
  194. package/dist/{session-D0qFkBla.cjs → session-Mm7GQbSH.cjs} +3 -3
  195. package/dist/session-Mm7GQbSH.cjs.map +1 -0
  196. package/dist/{session-store-C8tEvMPw.js → session-store-DWxJ5Pof.js} +79 -17
  197. package/dist/session-store-DWxJ5Pof.js.map +1 -0
  198. package/dist/{session-store-B0QZE8Bx.cjs → session-store-yfwnj0OC.cjs} +126 -16
  199. package/dist/session-store-yfwnj0OC.cjs.map +1 -0
  200. package/dist/{sla-engine-5IhTsBUR.js → sla-engine-CP2KiKDS.js} +1 -1
  201. package/dist/{sla-engine-BqX-7u-7.js → sla-engine-O-A1ntu_.js} +2 -2
  202. package/dist/{sla-engine-BqX-7u-7.js.map → sla-engine-O-A1ntu_.js.map} +1 -1
  203. package/dist/{sop-Vp0UPWFW.js → sop-BV7ICAFR.js} +4 -11
  204. package/dist/sop-BV7ICAFR.js.map +1 -0
  205. package/dist/{sop-DkhVChGy.js → sop-D33qTHUb.js} +1 -1
  206. package/dist/survey-engine-DKctGcLQ.js +2 -0
  207. package/dist/{survey-engine-DBjCYqCv.js → survey-engine-DngXBv47.js} +5 -4
  208. package/dist/survey-engine-DngXBv47.js.map +1 -0
  209. package/dist/{sync-state-CwLSt_1m.js → sync-state-BaA8LbTI.js} +1 -1
  210. package/dist/{sync-state-ChaLbamC.js → sync-state-DMZgzpez.js} +4 -12
  211. package/dist/sync-state-DMZgzpez.js.map +1 -0
  212. package/dist/{ticket-writer-CjqKeIRD.js → ticket-writer-DsfpeLGZ.js} +1 -1
  213. package/dist/{ticket-writer-j2oX_Wal.js → ticket-writer-a9on36Wb.js} +12 -24
  214. package/dist/ticket-writer-a9on36Wb.js.map +1 -0
  215. package/dist/{tone-Bdm5uaht.js → tone-C7bqK69y.js} +5 -12
  216. package/dist/tone-C7bqK69y.js.map +1 -0
  217. package/dist/{tone-DRKlZgPr.cjs → tone-Cmc7O2Fx.cjs} +3 -9
  218. package/dist/tone-Cmc7O2Fx.cjs.map +1 -0
  219. package/dist/{tone-vNb2DAAD.js → tone-mXSftvTn.js} +3 -8
  220. package/dist/tone-mXSftvTn.js.map +1 -0
  221. package/dist/{transcript-watcher-CL2QUygI.js → transcript-watcher-BoClrJAz.js} +18 -11
  222. package/dist/transcript-watcher-BoClrJAz.js.map +1 -0
  223. package/dist/unmatched-transcripts-C92zAoM4.js +2 -0
  224. package/dist/unmatched-transcripts-DC-VQ9YS.js +16 -0
  225. package/dist/unmatched-transcripts-DC-VQ9YS.js.map +1 -0
  226. package/dist/update-deal-CWy1eLJI.js +2 -0
  227. package/dist/{update-deal-DKC79skb.js → update-deal-DSzr_Aau.js} +3 -3
  228. package/dist/{update-deal-DKC79skb.js.map → update-deal-DSzr_Aau.js.map} +1 -1
  229. package/dist/{usage-D0-TYJkw.js → usage-BVlFlKW_.js} +8 -6
  230. package/dist/usage-BVlFlKW_.js.map +1 -0
  231. package/dist/usage-CClTf5e6.cjs.map +1 -1
  232. package/dist/usage-D0u9a-lV.js.map +1 -1
  233. package/dist/{vault-DXCg29W-.js → vault-CfwZdNzC.js} +3 -4
  234. package/dist/vault-CfwZdNzC.js.map +1 -0
  235. package/dist/{vault-C1D3zScD.js → vault-DxKP4_R2.js} +1 -1
  236. package/dist/{webhooks-Xn6zO6kd.cjs → webhooks-CwW-3kvG.cjs} +5 -19
  237. package/dist/webhooks-CwW-3kvG.cjs.map +1 -0
  238. package/dist/{webhooks-7EpA05Qr.js → webhooks-DXr1IoKn.js} +8 -21
  239. package/dist/webhooks-DXr1IoKn.js.map +1 -0
  240. package/dist/{webhooks-BO2UAnmn.js → webhooks-sWZ8CJtR.js} +5 -18
  241. package/dist/webhooks-sWZ8CJtR.js.map +1 -0
  242. package/package.json +22 -2
  243. package/dist/approvals-DpjxGHFp.js.map +0 -1
  244. package/dist/auth-CyFuu9X_.js +0 -2
  245. package/dist/auth-DFWwWcYD.js.map +0 -1
  246. package/dist/backup-CeMk9z86.js.map +0 -1
  247. package/dist/backup-f_hC7rBV.js +0 -2
  248. package/dist/context-builder-BzWAp3Zs.js.map +0 -1
  249. package/dist/context-builder-DlrRcqmJ.js +0 -2
  250. package/dist/custom-fields-Pl2t9xzp.js.map +0 -1
  251. package/dist/custom-objects-BHgn1GEX.js.map +0 -1
  252. package/dist/customer-dir-DIylZ8Q6.js.map +0 -1
  253. package/dist/file-lock-B_zi7NQl.js.map +0 -1
  254. package/dist/gmail-sync-DIaxInDT.js.map +0 -1
  255. package/dist/gmail-sync-hHm9gaWd.cjs.map +0 -1
  256. package/dist/gmail-sync-rQaVqKWd.js.map +0 -1
  257. package/dist/goal-engine-KpBftn4V.js.map +0 -1
  258. package/dist/identity-gyfWdrcX.js +0 -2
  259. package/dist/import-hubspot-BaK71U_K.js.map +0 -1
  260. package/dist/index-V8BFaH-b.d.ts.map +0 -1
  261. package/dist/index-YqwMd6aQ.d.cts.map +0 -1
  262. package/dist/interactions-writer-CrPStUll.cjs.map +0 -1
  263. package/dist/interactions-writer-DO3KcSR3.js.map +0 -1
  264. package/dist/interactions-writer-SLHnoEeE.js.map +0 -1
  265. package/dist/interactions-writer-dSPy1XfO.js +0 -2
  266. package/dist/knowledge-base-D0Fh40kc.js.map +0 -1
  267. package/dist/lancedb-rlvWoPwl.js.map +0 -1
  268. package/dist/lead-model-BCFzyktm.js.map +0 -1
  269. package/dist/memory-Bb6ky3kb.js.map +0 -1
  270. package/dist/notification-dispatcher-0vYNngWe.js.map +0 -1
  271. package/dist/pipeline-writer-BvVquKIe.js.map +0 -1
  272. package/dist/pipeline-writer-N2omexxp.cjs.map +0 -1
  273. package/dist/pipeline-writer-eufx_0o1.js.map +0 -1
  274. package/dist/proactive-worker-BrLHNhjH.js.map +0 -1
  275. package/dist/push-manager-CdqIIkuh.js.map +0 -1
  276. package/dist/quote-generator-BfwENXzg.js.map +0 -1
  277. package/dist/rbac-C7c8tcES.js +0 -2
  278. package/dist/rbac-CTIktZaC.js.map +0 -1
  279. package/dist/relationship-health-odxEoQdJ.js.map +0 -1
  280. package/dist/revenue-simulation-Bqf2DLVB.js.map +0 -1
  281. package/dist/segments-BqcD5HIl.js.map +0 -1
  282. package/dist/sequence-engine-CCTHEBgi.js +0 -2
  283. package/dist/sequence-engine-J1lTW_in.js.map +0 -1
  284. package/dist/sequence-store-DaaWr0Os.js.map +0 -1
  285. package/dist/server-Dyva03K8.js.map +0 -1
  286. package/dist/session-B9AilxOE.js.map +0 -1
  287. package/dist/session-D0qFkBla.cjs.map +0 -1
  288. package/dist/session-D9ub6Wl1.js.map +0 -1
  289. package/dist/session-mWHA71Lw.js +0 -2
  290. package/dist/session-store-B0QZE8Bx.cjs.map +0 -1
  291. package/dist/session-store-C8tEvMPw.js.map +0 -1
  292. package/dist/sop-Vp0UPWFW.js.map +0 -1
  293. package/dist/survey-engine-C06hcQt3.js +0 -2
  294. package/dist/survey-engine-DBjCYqCv.js.map +0 -1
  295. package/dist/sync-state-ChaLbamC.js.map +0 -1
  296. package/dist/ticket-writer-j2oX_Wal.js.map +0 -1
  297. package/dist/tone-Bdm5uaht.js.map +0 -1
  298. package/dist/tone-DRKlZgPr.cjs.map +0 -1
  299. package/dist/tone-vNb2DAAD.js.map +0 -1
  300. package/dist/transcript-watcher-CL2QUygI.js.map +0 -1
  301. package/dist/unmatched-transcripts-BsH5bhkU.js +0 -26
  302. package/dist/unmatched-transcripts-BsH5bhkU.js.map +0 -1
  303. package/dist/unmatched-transcripts-D0PrJ9iz.js +0 -2
  304. package/dist/update-deal-BNwPGaTV.js +0 -2
  305. package/dist/usage-D0-TYJkw.js.map +0 -1
  306. package/dist/vault-DXCg29W-.js.map +0 -1
  307. package/dist/webhooks-7EpA05Qr.js.map +0 -1
  308. package/dist/webhooks-BO2UAnmn.js.map +0 -1
  309. package/dist/webhooks-Xn6zO6kd.cjs.map +0 -1
package/dist/mcp.cjs CHANGED
@@ -1,10 +1,12 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("./chunk-DakpK96I.cjs");
3
- const require_session_store = require("./session-store-B0QZE8Bx.cjs");
3
+ const require_session_store = require("./session-store-yfwnj0OC.cjs");
4
+ const require_atomic_write = require("./atomic-write-BYmF-ThH.cjs");
4
5
  const require_write_queue = require("./write-queue-BDolUxfs.cjs");
5
- const require_interactions_writer = require("./interactions-writer-CrPStUll.cjs");
6
- const require_pipeline_writer = require("./pipeline-writer-N2omexxp.cjs");
7
- const require_llm = require("./llm-iijeXmgq.cjs");
6
+ const require_interactions_writer = require("./interactions-writer-BRJNrefF.cjs");
7
+ const require_logger = require("./logger-BkInaGoV.cjs");
8
+ const require_pipeline_writer = require("./pipeline-writer-B1tRAhuD.cjs");
9
+ const require_llm = require("./llm-CXycmEl9.cjs");
8
10
  let path = require("path");
9
11
  path = require_chunk.__toESM(path, 1);
10
12
  let fs = require("fs");
@@ -63,11 +65,10 @@ async function readSubscriptions(dataDir) {
63
65
  async function writeSubscriptions(dataDir, subs) {
64
66
  const filePath = subscriptionsPath(dataDir);
65
67
  fs.default.mkdirSync(path.default.dirname(filePath), { recursive: true });
66
- const file = {
68
+ require_session_store.writeJsonFile(filePath, {
67
69
  subscriptions: subs,
68
70
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
69
- };
70
- fs.default.writeFileSync(filePath, JSON.stringify(file, null, 2), "utf-8");
71
+ });
71
72
  }
72
73
  function expiresAtForProvider(provider) {
73
74
  if (provider === "gmail") return new Date(Date.now() + 10080 * 60 * 1e3).toISOString();
@@ -98,23 +99,15 @@ function getSyncStatePath(dataDir) {
98
99
  return path.default.join(dataDir, ".agentic", "sync-state.json");
99
100
  }
100
101
  function readSyncState(dataDir) {
101
- const filePath = getSyncStatePath(dataDir);
102
- if (!fs.default.existsSync(filePath)) return {};
103
- try {
104
- return JSON.parse(fs.default.readFileSync(filePath, "utf-8"));
105
- } catch {
106
- return {};
107
- }
102
+ return require_session_store.readJsonFile(getSyncStatePath(dataDir), {});
108
103
  }
109
104
  function updateSlugSyncState(dataDir, slug, update) {
110
- const filePath = getSyncStatePath(dataDir);
111
- fs.default.mkdirSync(path.default.dirname(filePath), { recursive: true });
112
105
  const state = readSyncState(dataDir);
113
106
  state[slug] = {
114
107
  ...state[slug],
115
108
  ...update
116
109
  };
117
- fs.default.writeFileSync(filePath, JSON.stringify(state, null, 2), "utf-8");
110
+ require_session_store.writeJsonFile(getSyncStatePath(dataDir), state);
118
111
  }
119
112
  function getLastGmailSync(dataDir, slug) {
120
113
  const ts = readSyncState(dataDir)[slug]?.lastGmailSync;
@@ -412,7 +405,7 @@ Config: \`.agentic/rbac.json\` | Actor: \`DXCRM_ACTOR\` env var
412
405
  | log_interaction | Write a new interaction entry (call, email, meeting, note) — immediately searchable | rep+ |
413
406
  | update_deal | Create or update a deal in pipeline.md — upserts by deal name | rep+ |
414
407
  | update_customer_facts | Update fields in customer profile (domain, contact, stage, tags) | admin |
415
- | export_customer | Export all customer data as JSON or Markdown | admin |
408
+ | export_customer | Export all customer data (incl. attachment contents) as JSON or Markdown | admin |
416
409
  | get_deal_health | Score deal health 0–100 (A–F grade) based on activity, velocity, close date, probability | any |
417
410
  | get_pipeline_forecast | Aggregate weighted pipeline revenue across all customers grouped by stage | any |
418
411
  | get_pipeline_stages | List all configured pipeline stages (defaults: lead, qualified, proposal, negotiation, won, lost) | any |
@@ -456,6 +449,7 @@ Config: \`.agentic/rbac.json\` | Actor: \`DXCRM_ACTOR\` env var
456
449
  | list_backups | List available backups with date, size, verification status, and customer count | any |
457
450
  | trigger_sync | Force immediate Gmail sync for one or all customers | rep+ |
458
451
  | get_audit_log | Read audit log — all write operations with actor, tool, customer | admin |
452
+ | get_logs | Query/aggregate the structured application log (level, component, errors) | admin |
459
453
  | define_custom_object | Define a runtime custom object type with typed fields (no migration) | admin |
460
454
  | create_record | Create a record of a custom object (validated against its schema) | rep+ |
461
455
  | list_records | List records of a custom object | any |
@@ -545,12 +539,14 @@ RBAC: admin
545
539
  - Input: slug (required) + any combination of the optional fields
546
540
  - Returns: { success: boolean, facts: object }
547
541
 
548
- ### export_customer({ slug, format? })
549
- Export all customer data (main_facts + interactions count + pipeline + attachments list).
542
+ ### export_customer({ slug, format?, includeAttachmentContent? })
543
+ Export all customer data (main_facts + interactions + pipeline + attachments).
544
+ Set includeAttachmentContent to inline every attachment's converted Markdown —
545
+ a single sendable bundle of all conversations and documents for the customer.
550
546
  RBAC: admin
551
- - Input: { slug: string, format?: "json" | "markdown" (default "json") }
552
- - Returns (JSON): { slug, exportedAt, mainFacts, interactionsCount, pipeline, attachments }
553
- - Returns (Markdown): Formatted document with all sections
547
+ - Input: { slug: string, format?: "json" | "markdown" (default "json"), includeAttachmentContent?: boolean (default false) }
548
+ - Returns (JSON): { slug, exportedAt, mainFacts, interactionsCount, pipeline, attachments[, attachmentContents] }
549
+ - Returns (Markdown): Formatted document with all sections (and attachment contents when requested)
554
550
 
555
551
  ### get_deal_health({ slug })
556
552
  Score the health of all deals for a customer based on activity recency, stage velocity,
@@ -1330,6 +1326,16 @@ function registerGetActiveSession(server) {
1330
1326
  }, async () => handleGetActiveSession());
1331
1327
  }
1332
1328
  //#endregion
1329
+ //#region src/core/regex.ts
1330
+ /**
1331
+ * Escape a string so it can be embedded safely as a literal inside a `RegExp`.
1332
+ * Prevents both broken patterns and ReDoS/injection when interpolating
1333
+ * field names, section headers, or other dynamic values into a regex.
1334
+ */
1335
+ function escapeRegExp(value) {
1336
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1337
+ }
1338
+ //#endregion
1333
1339
  //#region src/core/context-builder.ts
1334
1340
  var context_builder_exports = /* @__PURE__ */ require_chunk.__exportAll({ buildContext: () => buildContext });
1335
1341
  const MAX_INTERACTIONS = 10;
@@ -1345,7 +1351,7 @@ function parsePipelineContent(filePath) {
1345
1351
  return fs.default.readFileSync(filePath, "utf-8").trim();
1346
1352
  }
1347
1353
  function extractSection(content, sectionName) {
1348
- const match = new RegExp(`## ${sectionName}([\\s\\S]*?)(?=^## |$)`, "m").exec(content);
1354
+ const match = new RegExp(`## ${escapeRegExp(sectionName)}([\\s\\S]*?)(?=^## |$)`, "m").exec(content);
1349
1355
  return match ? (match[1] ?? "").trim() : "";
1350
1356
  }
1351
1357
  async function buildContext(dataDir, slug) {
@@ -1422,7 +1428,7 @@ async function buildContext(dataDir, slug) {
1422
1428
  }
1423
1429
  //#endregion
1424
1430
  //#region src/mcp/tools/get-customer-context.ts
1425
- const DATA_DIR$51 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1431
+ const DATA_DIR$52 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1426
1432
  function triggerOnQuerySync(dataDir, slug) {
1427
1433
  const auth = getGmailAuth();
1428
1434
  if (!auth) return;
@@ -1435,7 +1441,7 @@ function triggerOnQuerySync(dataDir, slug) {
1435
1441
  const sources = JSON.parse(fs.default.readFileSync(sourcesPath, "utf-8"));
1436
1442
  if (!sources.gmail?.enabled || !sources.gmail.query) return;
1437
1443
  const query = sources.gmail.query;
1438
- Promise.resolve().then(() => require("./gmail-sync-hHm9gaWd.cjs")).then(({ syncGmail }) => syncGmail({
1444
+ Promise.resolve().then(() => require("./gmail-sync-BpSVESSe.cjs")).then(({ syncGmail }) => syncGmail({
1439
1445
  slug,
1440
1446
  dataDir,
1441
1447
  auth,
@@ -1443,7 +1449,7 @@ function triggerOnQuerySync(dataDir, slug) {
1443
1449
  }).then(() => updateSlugSyncState(dataDir, slug, { lastGmailSync: (/* @__PURE__ */ new Date()).toISOString() })).catch(() => {})).catch(() => {});
1444
1450
  } catch {}
1445
1451
  }
1446
- async function handleGetCustomerContext(input, dataDir = DATA_DIR$51) {
1452
+ async function handleGetCustomerContext(input, dataDir = DATA_DIR$52) {
1447
1453
  const targetSlug = input.slug ?? require_session_store.getSession()?.customerSlug;
1448
1454
  if (!targetSlug) return {
1449
1455
  content: [{
@@ -1559,7 +1565,7 @@ async function indexInLanceDB(dataDir, slug, text, sourceRef, meta) {
1559
1565
  }]);
1560
1566
  await table.mergeInsert("source_ref").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(data);
1561
1567
  } catch (err) {
1562
- process.stderr.write(`[lancedb] indexInLanceDB failed: ${err.message}\n`);
1568
+ require_logger.logger.error("lancedb", "indexInLanceDB failed", { error: err.message });
1563
1569
  }
1564
1570
  }
1565
1571
  async function searchKnowledge(dataDir, slug, query, limit) {
@@ -1579,8 +1585,8 @@ async function searchKnowledge(dataDir, slug, query, limit) {
1579
1585
  }
1580
1586
  //#endregion
1581
1587
  //#region src/mcp/tools/search-customer-knowledge.ts
1582
- const DATA_DIR$50 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1583
- async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$50) {
1588
+ const DATA_DIR$51 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1589
+ async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$51) {
1584
1590
  const limit = input.limit ?? 5;
1585
1591
  try {
1586
1592
  const results = await searchKnowledge(dataDir, input.slug, input.query, limit);
@@ -1628,14 +1634,14 @@ If no results: returns empty array with a helpful sync suggestion.`,
1628
1634
  }
1629
1635
  //#endregion
1630
1636
  //#region src/mcp/tools/list-customers.ts
1631
- const DATA_DIR$49 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1637
+ const DATA_DIR$50 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1632
1638
  function extractLastInteractionDate(interactionsPath) {
1633
1639
  if (!fs.default.existsSync(interactionsPath)) return void 0;
1634
1640
  const content = fs.default.readFileSync(interactionsPath, "utf-8");
1635
1641
  const match = /^## (\d{4}-\d{2}-\d{2})/m.exec(content);
1636
1642
  return match ? match[1] : void 0;
1637
1643
  }
1638
- async function handleListCustomers(input, dataDir = DATA_DIR$49) {
1644
+ async function handleListCustomers(input, dataDir = DATA_DIR$50) {
1639
1645
  const customersDir = path.default.join(dataDir, "customers");
1640
1646
  const customers = [];
1641
1647
  if (!fs.default.existsSync(customersDir)) return { content: [{
@@ -1643,6 +1649,7 @@ async function handleListCustomers(input, dataDir = DATA_DIR$49) {
1643
1649
  text: JSON.stringify([], null, 2)
1644
1650
  }] };
1645
1651
  const entries = fs.default.readdirSync(customersDir);
1652
+ const canSee = require_session_store.customerVisibility(dataDir, process.env["DXCRM_ACTOR"] ?? "system");
1646
1653
  for (const entry of entries) {
1647
1654
  const customerDir = path.default.join(customersDir, entry);
1648
1655
  try {
@@ -1669,7 +1676,7 @@ async function handleListCustomers(input, dataDir = DATA_DIR$49) {
1669
1676
  const filterLower = input.filter.toLowerCase();
1670
1677
  if (!(name.toLowerCase().includes(filterLower) || entry.toLowerCase().includes(filterLower) || stage.toLowerCase().includes(filterLower))) continue;
1671
1678
  }
1672
- if (!require_session_store.canSeeCustomer(dataDir, process.env["DXCRM_ACTOR"] ?? "system", entry)) continue;
1679
+ if (!canSee(entry)) continue;
1673
1680
  customers.push(summary);
1674
1681
  } catch {
1675
1682
  continue;
@@ -1704,8 +1711,7 @@ async function withJsonFile(filePath, updater) {
1704
1711
  current = null;
1705
1712
  }
1706
1713
  const next = await updater(current);
1707
- fs.default.mkdirSync(path.default.dirname(filePath), { recursive: true });
1708
- fs.default.writeFileSync(filePath, JSON.stringify(next, null, 2), "utf-8");
1714
+ require_atomic_write.writeFileAtomic(filePath, JSON.stringify(next, null, 2));
1709
1715
  return next;
1710
1716
  });
1711
1717
  }
@@ -1729,7 +1735,7 @@ function readGraph(dataDir, slug) {
1729
1735
  try {
1730
1736
  return JSON.parse(fs.default.readFileSync(p, "utf-8"));
1731
1737
  } catch {
1732
- process.stderr.write(`[graph] failed to parse ${p} — returning empty graph\n`);
1738
+ require_logger.logger.warn("graph", "failed to parse graph file — returning empty graph", { path: p });
1733
1739
  return emptyGraph(slug);
1734
1740
  }
1735
1741
  }
@@ -1982,23 +1988,13 @@ function healthPath(dataDir, slug) {
1982
1988
  return path.default.join(dataDir, "customers", slug, "health.json");
1983
1989
  }
1984
1990
  function readHealth(dataDir, slug) {
1985
- const p = healthPath(dataDir, slug);
1986
- if (!fs.default.existsSync(p)) return null;
1987
- try {
1988
- return JSON.parse(fs.default.readFileSync(p, "utf-8"));
1989
- } catch {
1990
- return null;
1991
- }
1991
+ return require_session_store.readJsonFile(healthPath(dataDir, slug), null);
1992
1992
  }
1993
1993
  function writeHealth(dataDir, slug, health) {
1994
- const p = healthPath(dataDir, slug);
1995
- const dir = path.default.dirname(p);
1996
- if (!fs.default.existsSync(dir)) fs.default.mkdirSync(dir, { recursive: true });
1997
- const updated = {
1994
+ require_session_store.writeJsonFile(healthPath(dataDir, slug), {
1998
1995
  ...health,
1999
1996
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2000
- };
2001
- fs.default.writeFileSync(p, JSON.stringify(updated, null, 2), "utf-8");
1997
+ });
2002
1998
  }
2003
1999
  function parseContactInteractions(content) {
2004
2000
  const blocks = content.split(/(?=^## \d{4}-\d{2}-\d{2})/m).filter((b) => b.trim().length > 0);
@@ -2158,8 +2154,8 @@ async function updateHealthFromInteraction(dataDir, slug) {
2158
2154
  }
2159
2155
  //#endregion
2160
2156
  //#region src/mcp/tools/log-interaction.ts
2161
- const DATA_DIR$48 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2162
- async function handleLogInteraction(input, dataDir = DATA_DIR$48) {
2157
+ const DATA_DIR$49 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2158
+ async function handleLogInteraction(input, dataDir = DATA_DIR$49) {
2163
2159
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
2164
2160
  const interactionDate = input.date ?? today;
2165
2161
  const sourceRef = input.source ?? `agent://log/${Date.now()}`;
@@ -2189,7 +2185,7 @@ async function handleLogInteraction(input, dataDir = DATA_DIR$48) {
2189
2185
  raw.data.last_touchpoint = interactionDate;
2190
2186
  let serialized = gray_matter.default.stringify(raw.content, raw.data);
2191
2187
  serialized = serialized.replace(/^(last_touchpoint:\s*)['"](\d{4}-\d{2}-\d{2})['"]/m, "$1$2");
2192
- fs.default.writeFileSync(mainFactsPath, serialized, "utf-8");
2188
+ require_atomic_write.writeFileAtomic(mainFactsPath, serialized);
2193
2189
  } catch {}
2194
2190
  require_session_store.writeAuditEntry(dataDir, {
2195
2191
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -2268,8 +2264,8 @@ var update_deal_exports = /* @__PURE__ */ require_chunk.__exportAll({
2268
2264
  handleUpdateDeal: () => handleUpdateDeal,
2269
2265
  registerUpdateDeal: () => registerUpdateDeal
2270
2266
  });
2271
- const DATA_DIR$47 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2272
- async function handleUpdateDeal(input, dataDir = DATA_DIR$47) {
2267
+ const DATA_DIR$48 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2268
+ async function handleUpdateDeal(input, dataDir = DATA_DIR$48) {
2273
2269
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
2274
2270
  const deal = {
2275
2271
  name: input.dealName,
@@ -2352,12 +2348,12 @@ Returns: { success: boolean, deal: object }`,
2352
2348
  }
2353
2349
  //#endregion
2354
2350
  //#region src/mcp/tools/export-customer.ts
2355
- const DATA_DIR$46 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2351
+ const DATA_DIR$47 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2356
2352
  function countInteractions(content) {
2357
2353
  const matches = content.match(/^## \d{4}-\d{2}-\d{2}/gm);
2358
2354
  return matches ? matches.length : 0;
2359
2355
  }
2360
- async function handleExportCustomer(input, dataDir = DATA_DIR$46) {
2356
+ async function handleExportCustomer(input, dataDir = DATA_DIR$47) {
2361
2357
  require_session_store.enforceRbac(dataDir, "export_customer");
2362
2358
  const customerDir = path.default.join(dataDir, "customers", input.slug);
2363
2359
  if (!fs.default.existsSync(customerDir)) return {
@@ -2384,14 +2380,27 @@ async function handleExportCustomer(input, dataDir = DATA_DIR$46) {
2384
2380
  interactionsCount = countInteractions(interactionsContent);
2385
2381
  }
2386
2382
  const pipeline = await require_pipeline_writer.readPipeline(dataDir, input.slug);
2383
+ const includeAttachmentContent = input.includeAttachmentContent ?? false;
2387
2384
  const attachmentsDir = path.default.join(customerDir, "attachments");
2388
2385
  const attachments = [];
2386
+ const attachmentContents = {};
2389
2387
  if (fs.default.existsSync(attachmentsDir)) try {
2390
2388
  const files = fs.default.readdirSync(attachmentsDir);
2391
2389
  for (const f of files) try {
2392
- if (fs.default.statSync(path.default.join(attachmentsDir, f)).isFile()) attachments.push(f);
2390
+ if (!fs.default.statSync(path.default.join(attachmentsDir, f)).isFile()) continue;
2391
+ attachments.push(f);
2392
+ if (includeAttachmentContent && f.endsWith(".md")) attachmentContents[f] = fs.default.readFileSync(path.default.join(attachmentsDir, f), "utf-8");
2393
2393
  } catch {}
2394
2394
  } catch {}
2395
+ const attachmentContentSection = () => {
2396
+ const entries = Object.entries(attachmentContents);
2397
+ if (!includeAttachmentContent || entries.length === 0) return [];
2398
+ return [
2399
+ "",
2400
+ `## Attachment Contents (${entries.length})`,
2401
+ ...entries.map(([name, content]) => `\n### ${name}\n\n${content.trim()}`)
2402
+ ];
2403
+ };
2395
2404
  if (format === "markdown") return { content: [{
2396
2405
  type: "text",
2397
2406
  text: [
@@ -2410,7 +2419,8 @@ async function handleExportCustomer(input, dataDir = DATA_DIR$46) {
2410
2419
  pipeline.length > 0 ? pipeline.map((d) => `- **${d.name}** · ${d.stage}${d.value !== void 0 ? ` · €${d.value}` : ""}${d.close_date ? ` · close: ${d.close_date}` : ""}`).join("\n") : "(no deals)",
2411
2420
  "",
2412
2421
  `## Attachments (${attachments.length})`,
2413
- attachments.length > 0 ? attachments.map((f) => `- ${f}`).join("\n") : "(none)"
2422
+ attachments.length > 0 ? attachments.map((f) => `- ${f}`).join("\n") : "(none)",
2423
+ ...attachmentContentSection()
2414
2424
  ].join("\n")
2415
2425
  }] };
2416
2426
  const exported = {
@@ -2419,7 +2429,8 @@ async function handleExportCustomer(input, dataDir = DATA_DIR$46) {
2419
2429
  mainFacts,
2420
2430
  interactionsCount,
2421
2431
  pipeline,
2422
- attachments
2432
+ attachments,
2433
+ ...includeAttachmentContent ? { attachmentContents } : {}
2423
2434
  };
2424
2435
  return { content: [{
2425
2436
  type: "text",
@@ -2429,29 +2440,34 @@ async function handleExportCustomer(input, dataDir = DATA_DIR$46) {
2429
2440
  function registerExportCustomer(server) {
2430
2441
  server.registerTool("export_customer", {
2431
2442
  title: "Export Customer",
2432
- description: `Export all customer data (main_facts + interactions count + pipeline deals).
2433
- Useful for reporting, audits, or creating backups.
2443
+ description: `Export all customer data (main_facts + interactions + pipeline deals + attachments).
2444
+ Useful for reporting, audits, handoffs, or creating a complete sendable bundle
2445
+ of every conversation and document for a customer.
2434
2446
 
2435
2447
  Args:
2436
2448
  slug: Customer ID (e.g. "acme-corp")
2437
2449
  format: Output format — "json" (default) or "markdown"
2450
+ includeAttachmentContent: Inline the converted Markdown of every attachment
2451
+ (default false). Use this to produce a single self-contained bundle.
2438
2452
 
2439
2453
  Returns:
2440
- JSON: { slug, exportedAt, mainFacts, interactionsCount, pipeline }
2441
- Markdown: Formatted document with all sections`,
2454
+ JSON: { slug, exportedAt, mainFacts, interactionsCount, pipeline, attachments[, attachmentContents] }
2455
+ Markdown: Formatted document with all sections (and attachment contents when requested)`,
2442
2456
  inputSchema: zod.z.object({
2443
2457
  slug: zod.z.string().describe("Customer slug (e.g. 'acme-corp')"),
2444
- format: zod.z.enum(["json", "markdown"]).optional().describe("Output format: 'json' (default) or 'markdown'")
2458
+ format: zod.z.enum(["json", "markdown"]).optional().describe("Output format: 'json' (default) or 'markdown'"),
2459
+ includeAttachmentContent: zod.z.boolean().optional().describe("Inline converted attachment Markdown into the export (default false)")
2445
2460
  })
2446
- }, async ({ slug, format }) => handleExportCustomer({
2461
+ }, async ({ slug, format, includeAttachmentContent }) => handleExportCustomer({
2447
2462
  slug,
2448
- ...format !== void 0 ? { format } : {}
2463
+ ...format !== void 0 ? { format } : {},
2464
+ ...includeAttachmentContent !== void 0 ? { includeAttachmentContent } : {}
2449
2465
  }));
2450
2466
  }
2451
2467
  //#endregion
2452
2468
  //#region src/mcp/tools/update-customer-facts.ts
2453
- const DATA_DIR$45 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2454
- async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$45) {
2469
+ const DATA_DIR$46 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2470
+ async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$46) {
2455
2471
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2456
2472
  try {
2457
2473
  require_session_store.enforceRbac(dataDir, "update_customer_facts");
@@ -2601,10 +2617,36 @@ function scoreDeal(deal, signals) {
2601
2617
  warnings
2602
2618
  };
2603
2619
  }
2620
+ const MS_PER_DAY = 864e5;
2621
+ /**
2622
+ * Derive activity/close timing for a deal relative to `todayDate`. Centralizes
2623
+ * the day-diff math that deal-room and deal-agent each computed identically.
2624
+ * A blank/whitespace close_date yields `undefined` (not a NaN day count).
2625
+ */
2626
+ function deriveDealTiming(deal, todayDate) {
2627
+ const updatedDate = deal.updated ? new Date(deal.updated) : todayDate;
2628
+ const daysSinceLastActivity = Math.floor((todayDate.getTime() - updatedDate.getTime()) / MS_PER_DAY);
2629
+ const timing = {
2630
+ daysSinceLastActivity,
2631
+ daysInCurrentStage: daysSinceLastActivity
2632
+ };
2633
+ if (deal.close_date && deal.close_date.trim() !== "") timing.daysToClose = Math.floor((new Date(deal.close_date).getTime() - todayDate.getTime()) / MS_PER_DAY);
2634
+ return timing;
2635
+ }
2636
+ /** Score a deal using timing derived from `todayDate` plus the deal's probability. */
2637
+ function scoreDealForToday(deal, todayDate) {
2638
+ const timing = deriveDealTiming(deal, todayDate);
2639
+ return scoreDeal(deal, {
2640
+ daysSinceLastActivity: timing.daysSinceLastActivity,
2641
+ daysInCurrentStage: timing.daysInCurrentStage,
2642
+ ...timing.daysToClose !== void 0 ? { daysToClose: timing.daysToClose } : {},
2643
+ ...deal.probability !== void 0 ? { probability: deal.probability } : {}
2644
+ });
2645
+ }
2604
2646
  //#endregion
2605
2647
  //#region src/mcp/tools/get-deal-health.ts
2606
- const DATA_DIR$44 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2607
- async function handleGetDealHealth(input, dataDir = DATA_DIR$44) {
2648
+ const DATA_DIR$45 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2649
+ async function handleGetDealHealth(input, dataDir = DATA_DIR$45) {
2608
2650
  try {
2609
2651
  const deals = await require_pipeline_writer.readPipeline(dataDir, input.slug);
2610
2652
  const today = /* @__PURE__ */ new Date();
@@ -2653,28 +2695,13 @@ Returns: { slug, deals: [{ deal, stage, score, grade, signals, warnings }] }`,
2653
2695
  }
2654
2696
  //#endregion
2655
2697
  //#region src/mcp/tools/get-pipeline-forecast.ts
2656
- const DATA_DIR$43 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2657
- async function handleGetPipelineForecast(input, dataDir = DATA_DIR$43) {
2698
+ const DATA_DIR$44 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2699
+ async function handleGetPipelineForecast(input, dataDir = DATA_DIR$44) {
2658
2700
  try {
2659
- const customersDir = path.default.join(dataDir, "customers");
2660
- if (!fs.default.existsSync(customersDir)) return { content: [{
2661
- type: "text",
2662
- text: JSON.stringify({
2663
- deals: [],
2664
- totalWeightedValue: 0,
2665
- byStage: {}
2666
- }, null, 2)
2667
- }] };
2668
- const slugs = fs.default.readdirSync(customersDir).filter((d) => {
2669
- if (input.filter && !d.includes(input.filter)) return false;
2670
- return fs.default.statSync(path.default.join(customersDir, d)).isDirectory();
2671
- });
2701
+ const slugs = require_session_store.listCustomerSlugs(dataDir).filter((d) => !input.filter || d.includes(input.filter));
2672
2702
  const allDeals = [];
2673
2703
  for (const slug of slugs) {
2674
- const pipelinePath = path.default.join(customersDir, slug, "pipeline.md");
2675
- if (!fs.default.existsSync(pipelinePath)) continue;
2676
- const { readPipeline } = await Promise.resolve().then(() => require("./pipeline-writer-N2omexxp.cjs")).then((n) => n.pipeline_writer_exports);
2677
- const deals = await readPipeline(dataDir, slug).catch(() => []);
2704
+ const deals = require_pipeline_writer.readPipelineSync(dataDir, slug);
2678
2705
  for (const deal of deals) {
2679
2706
  if (deal.stage === "won" || deal.stage === "lost") continue;
2680
2707
  const prob = deal.probability ?? 50;
@@ -2730,13 +2757,13 @@ Returns: { deals: [...], totalWeightedValue: number, byStage: { stage: { count,
2730
2757
  }
2731
2758
  //#endregion
2732
2759
  //#region src/mcp/tools/summarize-meeting.ts
2733
- const DATA_DIR$42 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2734
- async function handleSummarizeMeeting(input, dataDir = DATA_DIR$42) {
2760
+ const DATA_DIR$43 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2761
+ async function handleSummarizeMeeting(input, dataDir = DATA_DIR$43) {
2735
2762
  try {
2736
2763
  let summary = input.transcript.slice(0, 400);
2737
2764
  let nextSteps = [];
2738
2765
  try {
2739
- const { callLlm } = await Promise.resolve().then(() => require("./llm-iijeXmgq.cjs")).then((n) => n.llm_exports);
2766
+ const { callLlm } = await Promise.resolve().then(() => require("./llm-CXycmEl9.cjs")).then((n) => n.llm_exports);
2740
2767
  const response = await callLlm(`Summarize this meeting transcript in 3-5 sentences and extract action items.\n\nTranscript:\n${input.transcript.slice(0, 3e3)}\n\nRespond as JSON: { "summary": "...", "nextSteps": ["..."] }`);
2741
2768
  const parsed = JSON.parse(response);
2742
2769
  summary = parsed.summary ?? summary;
@@ -2850,18 +2877,12 @@ function stagesPath(dataDir) {
2850
2877
  return path.default.join(dataDir, ".agentic", "pipeline-stages.json");
2851
2878
  }
2852
2879
  function getPipelineStages(dataDir) {
2853
- const p = stagesPath(dataDir);
2854
- if (!fs.default.existsSync(p)) return DEFAULT_STAGES;
2855
- try {
2856
- return JSON.parse(fs.default.readFileSync(p, "utf-8"));
2857
- } catch {
2858
- return DEFAULT_STAGES;
2859
- }
2880
+ return require_session_store.readJsonFile(stagesPath(dataDir), DEFAULT_STAGES);
2860
2881
  }
2861
2882
  //#endregion
2862
2883
  //#region src/mcp/tools/get-pipeline-stages.ts
2863
- const DATA_DIR$41 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2864
- async function handleGetPipelineStages(_input, dataDir = DATA_DIR$41) {
2884
+ const DATA_DIR$42 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2885
+ async function handleGetPipelineStages(_input, dataDir = DATA_DIR$42) {
2865
2886
  const stages = getPipelineStages(dataDir);
2866
2887
  return { content: [{
2867
2888
  type: "text",
@@ -2879,21 +2900,18 @@ function registerGetPipelineStages(server) {
2879
2900
  //#region src/core/cross-customer.ts
2880
2901
  async function searchAcrossCustomers(dataDir, query, limit = 5, excludeSlug) {
2881
2902
  const slugs = require_session_store.listCustomerSlugs(dataDir).filter((d) => d !== excludeSlug);
2882
- const allResults = [];
2883
- for (const slug of slugs) {
2884
- const results = await searchKnowledge(dataDir, slug, query, 2);
2885
- for (const r of results) allResults.push({
2903
+ return (await Promise.all(slugs.map(async (slug) => {
2904
+ return (await searchKnowledge(dataDir, slug, query, 2)).map((r) => ({
2886
2905
  slug,
2887
2906
  relevantContent: r.content.slice(0, 200),
2888
2907
  score: r.score
2889
- });
2890
- }
2891
- return allResults.sort((a, b) => b.score - a.score).slice(0, limit);
2908
+ }));
2909
+ }))).flat().sort((a, b) => b.score - a.score).slice(0, limit);
2892
2910
  }
2893
2911
  //#endregion
2894
2912
  //#region src/mcp/tools/get-market-intelligence.ts
2895
- const DATA_DIR$40 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2896
- async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$40) {
2913
+ const DATA_DIR$41 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2914
+ async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$41) {
2897
2915
  const excludeSlug = input.excludeCurrentCustomer ? input.slug : void 0;
2898
2916
  const all = require_session_store.listCustomerSlugs(dataDir);
2899
2917
  const totalCustomersSearched = excludeSlug ? all.filter((s) => s !== excludeSlug).length : all.length;
@@ -2924,7 +2942,7 @@ function registerGetMarketIntelligence(server) {
2924
2942
  }
2925
2943
  //#endregion
2926
2944
  //#region src/mcp/tools/get-relationship-graph.ts
2927
- const DATA_DIR$39 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2945
+ const DATA_DIR$40 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2928
2946
  function summarizeNode(n) {
2929
2947
  return {
2930
2948
  id: n.id,
@@ -2932,7 +2950,7 @@ function summarizeNode(n) {
2932
2950
  email: n.properties["email"]
2933
2951
  };
2934
2952
  }
2935
- async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$39) {
2953
+ async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$40) {
2936
2954
  try {
2937
2955
  const graph = readGraph(dataDir, input.slug);
2938
2956
  const stakeholders = getStakeholders(graph);
@@ -3000,9 +3018,9 @@ Returns: {
3000
3018
  }
3001
3019
  //#endregion
3002
3020
  //#region src/mcp/tools/get-relationship-health.ts
3003
- const DATA_DIR$38 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3021
+ const DATA_DIR$39 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3004
3022
  const MAX_HEALTH_AGE_MS = 3600 * 1e3;
3005
- async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$38) {
3023
+ async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$39) {
3006
3024
  try {
3007
3025
  let health = readHealth(dataDir, input.slug);
3008
3026
  if (health === null || Date.now() - new Date(health.updatedAt).getTime() > MAX_HEALTH_AGE_MS) {
@@ -3082,8 +3100,7 @@ async function writePlaybook(dataDir, slug, playbook) {
3082
3100
  const filePath = path.default.join(dir, `${playbook.name}.md`);
3083
3101
  await require_write_queue.withFileQueue(filePath, async () => {
3084
3102
  fs.default.mkdirSync(dir, { recursive: true });
3085
- const raw = gray_matter.default.stringify(playbook.content, playbook.frontmatter);
3086
- fs.default.writeFileSync(filePath, raw, "utf-8");
3103
+ require_atomic_write.writeFileAtomic(filePath, gray_matter.default.stringify(playbook.content, playbook.frontmatter));
3087
3104
  });
3088
3105
  }
3089
3106
  function toKebabCase(name) {
@@ -3285,11 +3302,10 @@ function writeAgentQueue(dataDir, slug, queue) {
3285
3302
  const p = agentQueuePath(dataDir, slug);
3286
3303
  const dir = path.default.dirname(p);
3287
3304
  if (!fs.default.existsSync(dir)) fs.default.mkdirSync(dir, { recursive: true });
3288
- const updated = {
3305
+ require_session_store.writeJsonFile(p, {
3289
3306
  ...queue,
3290
3307
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3291
- };
3292
- fs.default.writeFileSync(p, JSON.stringify(updated, null, 2), "utf-8");
3308
+ });
3293
3309
  }
3294
3310
  function makeActionId() {
3295
3311
  return `da_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
@@ -3324,17 +3340,9 @@ async function observeDeal(dataDir, slug, dealName, today) {
3324
3340
  const deal = (await require_pipeline_writer.readPipeline(dataDir, slug).catch(() => [])).find((d) => d.name.toLowerCase() === dealName.toLowerCase());
3325
3341
  if (!deal) return null;
3326
3342
  const todayDate = new Date(today);
3327
- const updatedDate = deal.updated ? new Date(deal.updated) : todayDate;
3328
- const daysSinceLastActivity = Math.floor((todayDate.getTime() - updatedDate.getTime()) / 864e5);
3329
- const daysInCurrentStage = daysSinceLastActivity;
3330
- const daysToClose = deal.close_date && deal.close_date.trim() !== "" ? Math.floor((new Date(deal.close_date).getTime() - todayDate.getTime()) / 864e5) : void 0;
3331
- const dealHealthScore = scoreDeal(deal, {
3332
- daysSinceLastActivity,
3333
- daysInCurrentStage,
3334
- ...daysToClose !== void 0 ? { daysToClose } : {},
3335
- ...deal.probability !== void 0 ? { probability: deal.probability } : {}
3336
- });
3337
- const health = computeCustomerHealth(dataDir, slug, today);
3343
+ const { daysSinceLastActivity, daysInCurrentStage, daysToClose } = deriveDealTiming(deal, todayDate);
3344
+ const dealHealthScore = scoreDealForToday(deal, todayDate);
3345
+ const health = readHealth(dataDir, slug) ?? computeCustomerHealth(dataDir, slug, today);
3338
3346
  const atRiskContacts = health.contacts.filter((c) => c.riskFlags.length > 0).map((c) => c.email ?? c.contactId);
3339
3347
  const coldContacts = health.contacts.filter((c) => c.trend === "cold").map((c) => c.email ?? c.contactId);
3340
3348
  const stakeholders = getStakeholders(readGraph(dataDir, slug));
@@ -3562,7 +3570,7 @@ async function executeAction(action, dataDir) {
3562
3570
  if (!slug) return "skipped";
3563
3571
  switch (action.type) {
3564
3572
  case "log_interaction": {
3565
- const { appendInteraction } = await Promise.resolve().then(() => require("./interactions-writer-CrPStUll.cjs")).then((n) => n.interactions_writer_exports);
3573
+ const { appendInteraction } = await Promise.resolve().then(() => require("./interactions-writer-BRJNrefF.cjs")).then((n) => n.interactions_writer_exports);
3566
3574
  await appendInteraction(dataDir, slug, {
3567
3575
  date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
3568
3576
  type: action.payload["type"] ?? "Note",
@@ -3575,7 +3583,7 @@ async function executeAction(action, dataDir) {
3575
3583
  return "executed";
3576
3584
  }
3577
3585
  case "schedule_meeting": {
3578
- const { appendInteraction } = await Promise.resolve().then(() => require("./interactions-writer-CrPStUll.cjs")).then((n) => n.interactions_writer_exports);
3586
+ const { appendInteraction } = await Promise.resolve().then(() => require("./interactions-writer-BRJNrefF.cjs")).then((n) => n.interactions_writer_exports);
3579
3587
  await appendInteraction(dataDir, slug, {
3580
3588
  date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
3581
3589
  type: "Note",
@@ -3681,8 +3689,8 @@ async function runDealAgent(config, dataDir, llmFn = require_llm.callLlm) {
3681
3689
  }
3682
3690
  //#endregion
3683
3691
  //#region src/mcp/tools/run-deal-agent.ts
3684
- const DATA_DIR$37 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3685
- async function handleRunDealAgent(input, dataDir = DATA_DIR$37) {
3692
+ const DATA_DIR$38 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3693
+ async function handleRunDealAgent(input, dataDir = DATA_DIR$38) {
3686
3694
  try {
3687
3695
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
3688
3696
  const result = await runDealAgent({
@@ -3749,8 +3757,8 @@ Returns: { assessment, riskLevel, plan[], actionsQueued[], actionsExecuted[], tr
3749
3757
  }
3750
3758
  //#endregion
3751
3759
  //#region src/mcp/tools/approve-agent-action.ts
3752
- const DATA_DIR$36 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3753
- async function handleApproveAgentAction(input, dataDir = DATA_DIR$36) {
3760
+ const DATA_DIR$37 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3761
+ async function handleApproveAgentAction(input, dataDir = DATA_DIR$37) {
3754
3762
  try {
3755
3763
  const queue = readAgentQueue(dataDir, input.slug);
3756
3764
  const idx = queue.pendingActions.findIndex((a) => a.actionId === input.actionId);
@@ -4010,8 +4018,8 @@ async function buildSimulationInput(dataDir, horizon, today, externalSignals = [
4010
4018
  }
4011
4019
  //#endregion
4012
4020
  //#region src/mcp/tools/simulate-revenue.ts
4013
- const DATA_DIR$35 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4014
- async function handleSimulateRevenue(input, dataDir = DATA_DIR$35) {
4021
+ const DATA_DIR$36 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4022
+ async function handleSimulateRevenue(input, dataDir = DATA_DIR$36) {
4015
4023
  try {
4016
4024
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4017
4025
  const horizon = input.horizon ?? "quarter";
@@ -4069,8 +4077,8 @@ Returns: { forecast: { p10, p50, p90, expected, stdDev, atRiskRevenue, byCloseMo
4069
4077
  }
4070
4078
  //#endregion
4071
4079
  //#region src/mcp/tools/get-playbook.ts
4072
- const DATA_DIR$34 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4073
- async function handleGetPlaybook(input, dataDir = DATA_DIR$34) {
4080
+ const DATA_DIR$35 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4081
+ async function handleGetPlaybook(input, dataDir = DATA_DIR$35) {
4074
4082
  try {
4075
4083
  const playbooks = listPlaybooks(dataDir, input.slug);
4076
4084
  if (!(input.stage !== void 0 || input.value !== void 0 || input.healthScore !== void 0)) return { content: [{
@@ -4155,12 +4163,12 @@ Returns: { matches: [{ name, score, trigger, successRate, usedCount, content }],
4155
4163
  ...healthScore !== void 0 ? { healthScore } : {},
4156
4164
  ...daysSinceContact !== void 0 ? { daysSinceContact } : {},
4157
4165
  ...championPresent !== void 0 ? { championPresent } : {}
4158
- }, DATA_DIR$34));
4166
+ }, DATA_DIR$35));
4159
4167
  }
4160
4168
  //#endregion
4161
4169
  //#region src/mcp/tools/create-playbook.ts
4162
- const DATA_DIR$33 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4163
- async function handleCreatePlaybook(input, dataDir = DATA_DIR$33) {
4170
+ const DATA_DIR$34 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4171
+ async function handleCreatePlaybook(input, dataDir = DATA_DIR$34) {
4164
4172
  try {
4165
4173
  const name = toKebabCase(input.name);
4166
4174
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -4233,12 +4241,12 @@ Returns: { success: true, playbook: { name, trigger, successRate, path } }`,
4233
4241
  trigger,
4234
4242
  content,
4235
4243
  ...successRate !== void 0 ? { successRate } : {}
4236
- }, DATA_DIR$33));
4244
+ }, DATA_DIR$34));
4237
4245
  }
4238
4246
  //#endregion
4239
4247
  //#region src/mcp/tools/list-playbooks.ts
4240
- const DATA_DIR$32 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4241
- async function handleListPlaybooks(input, dataDir = DATA_DIR$32) {
4248
+ const DATA_DIR$33 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4249
+ async function handleListPlaybooks(input, dataDir = DATA_DIR$33) {
4242
4250
  try {
4243
4251
  const playbooks = listPlaybooks(dataDir, input.slug);
4244
4252
  return { content: [{
@@ -4277,12 +4285,12 @@ Args:
4277
4285
 
4278
4286
  Returns: { playbooks: [{ name, trigger, successRate, usedCount, lastUpdated }], count, slug }`,
4279
4287
  inputSchema: zod.z.object({ slug: zod.z.string().describe("Customer ID") })
4280
- }, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$32));
4288
+ }, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$33));
4281
4289
  }
4282
4290
  //#endregion
4283
4291
  //#region src/mcp/tools/distill-playbook.ts
4284
- const DATA_DIR$31 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4285
- async function handleDistillPlaybook(input, dataDir = DATA_DIR$31, llmFn = require_llm.callLlm) {
4292
+ const DATA_DIR$32 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4293
+ async function handleDistillPlaybook(input, dataDir = DATA_DIR$32, llmFn = require_llm.callLlm) {
4286
4294
  try {
4287
4295
  const result = await distillPlaybook(dataDir, input.slug, input.dealName, input.outcome, llmFn);
4288
4296
  if (!result.ok) {
@@ -4341,7 +4349,7 @@ Returns: { success: true, playbook: { name, trigger, successRate, path }, reason
4341
4349
  slug,
4342
4350
  dealName,
4343
4351
  outcome
4344
- }, DATA_DIR$31));
4352
+ }, DATA_DIR$32));
4345
4353
  }
4346
4354
  //#endregion
4347
4355
  //#region src/core/goal-engine.ts
@@ -4559,8 +4567,8 @@ function getActiveGoals(dataDir) {
4559
4567
  }
4560
4568
  //#endregion
4561
4569
  //#region src/mcp/tools/pursue-goal.ts
4562
- const DATA_DIR$30 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4563
- async function handlePursueGoal(input, dataDir = DATA_DIR$30, options = {}) {
4570
+ const DATA_DIR$31 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4571
+ async function handlePursueGoal(input, dataDir = DATA_DIR$31, options = {}) {
4564
4572
  try {
4565
4573
  require_session_store.enforceRbac(dataDir, "pursue_goal");
4566
4574
  const goal = await pursueGoal(dataDir, {
@@ -4623,12 +4631,12 @@ Returns: { goalId, description, target, deadline, decomposition: { analysis, cur
4623
4631
  goal,
4624
4632
  deadline,
4625
4633
  ...context !== void 0 ? { context } : {}
4626
- }, DATA_DIR$30));
4634
+ }, DATA_DIR$31));
4627
4635
  }
4628
4636
  //#endregion
4629
4637
  //#region src/mcp/tools/get-goal-status.ts
4630
- const DATA_DIR$29 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4631
- async function handleGetGoalStatus(input, dataDir = DATA_DIR$29) {
4638
+ const DATA_DIR$30 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4639
+ async function handleGetGoalStatus(input, dataDir = DATA_DIR$30) {
4632
4640
  try {
4633
4641
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4634
4642
  const allGoals = input.goalId ? readGoals(dataDir).filter((g) => g.id === input.goalId) : getActiveGoals(dataDir);
@@ -4687,17 +4695,17 @@ Args:
4687
4695
 
4688
4696
  Returns: { goals: [{ id, description, target, progress, status, deadline, daysRemaining, subGoals }], activeCount, completedCount }`,
4689
4697
  inputSchema: zod.z.object({ goalId: zod.z.string().optional().describe("Specific goal ID (omit for all active goals)") })
4690
- }, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$29));
4698
+ }, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$30));
4691
4699
  }
4692
4700
  //#endregion
4693
4701
  //#region src/mcp/tools/register-push-subscription.ts
4694
- const DATA_DIR$28 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4702
+ const DATA_DIR$29 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4695
4703
  const VALID_PROVIDERS = [
4696
4704
  "gmail",
4697
4705
  "microsoft-graph",
4698
4706
  "slack"
4699
4707
  ];
4700
- async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$28) {
4708
+ async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$29) {
4701
4709
  try {
4702
4710
  if (!VALID_PROVIDERS.includes(input.provider)) return { content: [{
4703
4711
  type: "text",
@@ -4783,12 +4791,12 @@ Returns: { subscriptionId, provider, slug, status, expiresAt, createdAt, warning
4783
4791
  ...microsoftResource !== void 0 ? { microsoftResource } : {},
4784
4792
  ...slackTeamId !== void 0 ? { slackTeamId } : {},
4785
4793
  ...slackChannelId !== void 0 ? { slackChannelId } : {}
4786
- }, DATA_DIR$28));
4794
+ }, DATA_DIR$29));
4787
4795
  }
4788
4796
  //#endregion
4789
4797
  //#region src/mcp/tools/get-push-status.ts
4790
- const DATA_DIR$27 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4791
- async function handleGetPushStatus(input, dataDir = DATA_DIR$27) {
4798
+ const DATA_DIR$28 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4799
+ async function handleGetPushStatus(input, dataDir = DATA_DIR$28) {
4792
4800
  try {
4793
4801
  let subs = await readSubscriptions(dataDir);
4794
4802
  if (input.slug) subs = subs.filter((s) => s.slug === input.slug);
@@ -4860,7 +4868,7 @@ Returns: { subscriptions: [{ id, provider, slug, status, expiresAt, expiresInHou
4860
4868
  }, async ({ slug, provider }) => handleGetPushStatus({
4861
4869
  ...slug !== void 0 ? { slug } : {},
4862
4870
  ...provider !== void 0 ? { provider } : {}
4863
- }, DATA_DIR$27));
4871
+ }, DATA_DIR$28));
4864
4872
  }
4865
4873
  //#endregion
4866
4874
  //#region src/core/org-intelligence.ts
@@ -4926,8 +4934,8 @@ function deriveRecommendation(people, missingRoles) {
4926
4934
  }
4927
4935
  //#endregion
4928
4936
  //#region src/mcp/tools/get-org-intelligence.ts
4929
- const DATA_DIR$26 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4930
- async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$26) {
4937
+ const DATA_DIR$27 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4938
+ async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$27) {
4931
4939
  try {
4932
4940
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4933
4941
  const map = buildStakeholderMap(dataDir, input.slug, today, input.dealName);
@@ -4978,15 +4986,7 @@ async function buildDealRoom(dataDir, slug, dealName, today) {
4978
4986
  });
4979
4987
  const todayDate = new Date(today);
4980
4988
  const dealHealth = pipelineDeals.filter((d) => d.stage !== "won" && d.stage !== "lost").map((deal) => {
4981
- const updatedDate = deal.updated ? new Date(deal.updated) : todayDate;
4982
- const daysSinceLastActivity = Math.floor((todayDate.getTime() - updatedDate.getTime()) / 864e5);
4983
- const daysToClose = deal.close_date ? Math.floor((new Date(deal.close_date).getTime() - todayDate.getTime()) / 864e5) : void 0;
4984
- const scored = scoreDeal(deal, {
4985
- daysSinceLastActivity,
4986
- daysInCurrentStage: daysSinceLastActivity,
4987
- ...daysToClose !== void 0 ? { daysToClose } : {},
4988
- ...deal.probability !== void 0 ? { probability: deal.probability } : {}
4989
- });
4989
+ const scored = scoreDealForToday(deal, todayDate);
4990
4990
  return {
4991
4991
  deal: deal.name,
4992
4992
  stage: deal.stage,
@@ -5068,8 +5068,8 @@ function buildExecutiveSummary(slug, dealName, stakeholders, overallHealth, sim,
5068
5068
  }
5069
5069
  //#endregion
5070
5070
  //#region src/mcp/tools/open-deal-room.ts
5071
- const DATA_DIR$25 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5072
- async function handleOpenDealRoom(input, dataDir = DATA_DIR$25) {
5071
+ const DATA_DIR$26 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5072
+ async function handleOpenDealRoom(input, dataDir = DATA_DIR$26) {
5073
5073
  try {
5074
5074
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
5075
5075
  const brief = await buildDealRoom(dataDir, input.slug, input.dealName, today);
@@ -5152,8 +5152,8 @@ async function buildDailyBriefing(dataDir, today) {
5152
5152
  }
5153
5153
  //#endregion
5154
5154
  //#region src/mcp/tools/get-proactive-briefing.ts
5155
- const DATA_DIR$24 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5156
- async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$24) {
5155
+ const DATA_DIR$25 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5156
+ async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$25) {
5157
5157
  try {
5158
5158
  const briefing = await buildDailyBriefing(dataDir, input.date ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
5159
5159
  return { content: [{
@@ -5253,15 +5253,15 @@ function getTemplate(dataDir, id) {
5253
5253
  }
5254
5254
  //#endregion
5255
5255
  //#region src/mcp/tools/list-email-templates.ts
5256
- const DATA_DIR$23 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5257
- async function handleListEmailTemplates(input, dataDir = DATA_DIR$23) {
5256
+ const DATA_DIR$24 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5257
+ async function handleListEmailTemplates(input, dataDir = DATA_DIR$24) {
5258
5258
  const summary = listTemplates(dataDir, input.category ? { category: input.category } : {}).map(({ body: _body, ...meta }) => meta);
5259
5259
  return { content: [{
5260
5260
  type: "text",
5261
5261
  text: JSON.stringify(summary, null, 2)
5262
5262
  }] };
5263
5263
  }
5264
- function registerListEmailTemplates(server, dataDir = DATA_DIR$23) {
5264
+ function registerListEmailTemplates(server, dataDir = DATA_DIR$24) {
5265
5265
  server.registerTool("list_email_templates", {
5266
5266
  description: "List available email templates. Optionally filter by category (e.g. 'outreach', 'followup', 'support').",
5267
5267
  inputSchema: zod.z.object({ category: zod.z.string().optional().describe("Filter by category") })
@@ -5295,8 +5295,8 @@ async function buildVariablesFromCustomer(dataDir, slug) {
5295
5295
  }
5296
5296
  //#endregion
5297
5297
  //#region src/mcp/tools/get-email-template.ts
5298
- const DATA_DIR$22 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5299
- async function handleGetEmailTemplate(input, dataDir = DATA_DIR$22) {
5298
+ const DATA_DIR$23 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5299
+ async function handleGetEmailTemplate(input, dataDir = DATA_DIR$23) {
5300
5300
  const tmpl = getTemplate(dataDir, input.id);
5301
5301
  if (!tmpl) return { content: [{
5302
5302
  type: "text",
@@ -5312,7 +5312,7 @@ async function handleGetEmailTemplate(input, dataDir = DATA_DIR$22) {
5312
5312
  }, null, 2)
5313
5313
  }] };
5314
5314
  }
5315
- function registerGetEmailTemplate(server, dataDir = DATA_DIR$22) {
5315
+ function registerGetEmailTemplate(server, dataDir = DATA_DIR$23) {
5316
5316
  server.registerTool("get_email_template", {
5317
5317
  description: "Get a specific email template by ID, including its body and detected variables.",
5318
5318
  inputSchema: zod.z.object({ id: zod.z.string().describe("Template ID (e.g. 'enterprise-intro')") })
@@ -5320,8 +5320,8 @@ function registerGetEmailTemplate(server, dataDir = DATA_DIR$22) {
5320
5320
  }
5321
5321
  //#endregion
5322
5322
  //#region src/mcp/tools/draft-email.ts
5323
- const DATA_DIR$21 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5324
- async function handleDraftEmail(input, dataDir = DATA_DIR$21) {
5323
+ const DATA_DIR$22 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5324
+ async function handleDraftEmail(input, dataDir = DATA_DIR$22) {
5325
5325
  const tmpl = getTemplate(dataDir, input.templateId);
5326
5326
  if (!tmpl) return { content: [{
5327
5327
  type: "text",
@@ -5335,17 +5335,17 @@ async function handleDraftEmail(input, dataDir = DATA_DIR$21) {
5335
5335
  const interpolatedBody = interpolate(tmpl.body, vars);
5336
5336
  let effectiveTone = input.tone;
5337
5337
  if (!effectiveTone) {
5338
- const { resolveTone, toneInstruction } = await Promise.resolve().then(() => require("./tone-DRKlZgPr.cjs"));
5338
+ const { resolveTone, toneInstruction } = await Promise.resolve().then(() => require("./tone-Cmc7O2Fx.cjs"));
5339
5339
  const instr = toneInstruction(resolveTone(dataDir, input.slug));
5340
5340
  if (instr) effectiveTone = instr;
5341
5341
  }
5342
5342
  let body = interpolatedBody;
5343
5343
  let polished = false;
5344
5344
  if (effectiveTone) try {
5345
- const { callLlm } = await Promise.resolve().then(() => require("./llm-iijeXmgq.cjs")).then((n) => n.llm_exports);
5345
+ const { callLlm } = await Promise.resolve().then(() => require("./llm-CXycmEl9.cjs")).then((n) => n.llm_exports);
5346
5346
  const refined = await callLlm(`Rewrite the following email in a ${effectiveTone} tone. Keep the same language, preserve all names and facts, and do not invent details. Return ONLY the rewritten email body, no preamble.\n\n---\n${interpolatedBody}`);
5347
5347
  if (refined && refined.trim()) {
5348
- const { labelAiContent } = await Promise.resolve().then(() => require("./compliance-B91zNvCR.cjs")).then((n) => n.compliance_exports);
5348
+ const { labelAiContent } = await Promise.resolve().then(() => require("./compliance-pAj9FcGI.cjs")).then((n) => n.compliance_exports);
5349
5349
  body = labelAiContent(refined.trim());
5350
5350
  polished = true;
5351
5351
  }
@@ -5365,7 +5365,7 @@ async function handleDraftEmail(input, dataDir = DATA_DIR$21) {
5365
5365
  }, null, 2)
5366
5366
  }] };
5367
5367
  }
5368
- function registerDraftEmail(server, dataDir = DATA_DIR$21) {
5368
+ function registerDraftEmail(server, dataDir = DATA_DIR$22) {
5369
5369
  server.registerTool("draft_email", {
5370
5370
  description: `Draft a personalized email for a customer using a stored template.
5371
5371
  Variables are auto-filled from the customer's main_facts.md. Override any variable manually.
@@ -5473,8 +5473,8 @@ async function updateEnrollment(dataDir, id, updates) {
5473
5473
  }
5474
5474
  //#endregion
5475
5475
  //#region src/mcp/tools/enroll-in-sequence.ts
5476
- const DATA_DIR$20 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5477
- async function handleEnrollInSequence(input, dataDir = DATA_DIR$20) {
5476
+ const DATA_DIR$21 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5477
+ async function handleEnrollInSequence(input, dataDir = DATA_DIR$21) {
5478
5478
  const sequence = getSequence(dataDir, input.sequenceId);
5479
5479
  if (!sequence) return { content: [{
5480
5480
  type: "text",
@@ -5506,7 +5506,7 @@ async function handleEnrollInSequence(input, dataDir = DATA_DIR$20) {
5506
5506
  })
5507
5507
  }] };
5508
5508
  }
5509
- function registerEnrollInSequence(server, dataDir = DATA_DIR$20) {
5509
+ function registerEnrollInSequence(server, dataDir = DATA_DIR$21) {
5510
5510
  server.registerTool("enroll_in_sequence", {
5511
5511
  description: `Enroll a contact in an email sequence. Validates that the sequence and its first template exist.
5512
5512
  Returns: { enrollmentId, sequenceName, totalSteps }`,
@@ -5523,8 +5523,8 @@ Returns: { enrollmentId, sequenceName, totalSteps }`,
5523
5523
  }
5524
5524
  //#endregion
5525
5525
  //#region src/mcp/tools/list-sequence-enrollments.ts
5526
- const DATA_DIR$19 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5527
- async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$19) {
5526
+ const DATA_DIR$20 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5527
+ async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$20) {
5528
5528
  let enrollments = readEnrollments(dataDir);
5529
5529
  if (input.slug !== void 0) enrollments = enrollments.filter((e) => e.slug === input.slug);
5530
5530
  if (input.status !== void 0) enrollments = enrollments.filter((e) => e.status === input.status);
@@ -5533,7 +5533,7 @@ async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$19) {
5533
5533
  text: JSON.stringify({ enrollments }, null, 2)
5534
5534
  }] };
5535
5535
  }
5536
- function registerListSequenceEnrollments(server, dataDir = DATA_DIR$19) {
5536
+ function registerListSequenceEnrollments(server, dataDir = DATA_DIR$20) {
5537
5537
  server.registerTool("list_sequence_enrollments", {
5538
5538
  description: `List email sequence enrollments. Filter by customer slug or status.
5539
5539
  Returns: { enrollments: SequenceEnrollment[] }`,
@@ -5552,8 +5552,8 @@ Returns: { enrollments: SequenceEnrollment[] }`,
5552
5552
  }
5553
5553
  //#endregion
5554
5554
  //#region src/mcp/tools/unenroll-from-sequence.ts
5555
- const DATA_DIR$18 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5556
- async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$18) {
5555
+ const DATA_DIR$19 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5556
+ async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$19) {
5557
5557
  if (!await updateEnrollment(dataDir, input.enrollmentId, { status: "paused" })) return { content: [{
5558
5558
  type: "text",
5559
5559
  text: JSON.stringify({
@@ -5566,7 +5566,7 @@ async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$18) {
5566
5566
  text: JSON.stringify({ success: true })
5567
5567
  }] };
5568
5568
  }
5569
- function registerUnenrollFromSequence(server, dataDir = DATA_DIR$18) {
5569
+ function registerUnenrollFromSequence(server, dataDir = DATA_DIR$19) {
5570
5570
  server.registerTool("unenroll_from_sequence", {
5571
5571
  description: `Unenroll (pause) a contact from an email sequence. Sets status to "paused" (soft delete).
5572
5572
  Returns: { success: boolean }`,
@@ -5575,8 +5575,8 @@ Returns: { success: boolean }`,
5575
5575
  }
5576
5576
  //#endregion
5577
5577
  //#region src/mcp/tools/list-sequences.ts
5578
- const DATA_DIR$17 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5579
- async function handleListSequences(_input, dataDir = DATA_DIR$17) {
5578
+ const DATA_DIR$18 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5579
+ async function handleListSequences(_input, dataDir = DATA_DIR$18) {
5580
5580
  const sequences = listSequences(dataDir);
5581
5581
  const enrollments = readEnrollments(dataDir);
5582
5582
  const result = sequences.map((seq) => ({
@@ -5590,7 +5590,7 @@ async function handleListSequences(_input, dataDir = DATA_DIR$17) {
5590
5590
  text: JSON.stringify({ sequences: result }, null, 2)
5591
5591
  }] };
5592
5592
  }
5593
- function registerListSequences(server, dataDir = DATA_DIR$17) {
5593
+ function registerListSequences(server, dataDir = DATA_DIR$18) {
5594
5594
  server.registerTool("list_sequences", {
5595
5595
  description: `List all email sequences with step count and enrollment count.
5596
5596
  Returns: { sequences: Array<{ id, name, stepCount, enrollmentCount }> }`,
@@ -5640,7 +5640,7 @@ function buildHtml(quote, config, customerName) {
5640
5640
  <p><strong>${config.companyName ?? ""}</strong><br>${config.companyAddress ?? ""}<br>${config.vatId ? `USt-IdNr.: ${config.vatId}` : ""}</p>
5641
5641
  <hr>
5642
5642
  <p><strong>An:</strong> ${customerName}</p>
5643
- <p><strong>Datum:</strong> ${quote.createdAt.slice(0, 10)} &nbsp;&nbsp; <strong>Gültig bis:</strong> ${quote.validUntil}</p>
5643
+ <p><strong>Date:</strong> ${quote.createdAt.slice(0, 10)} &nbsp;&nbsp; <strong>Valid until:</strong> ${quote.validUntil}</p>
5644
5644
  <h2>Leistungen</h2>
5645
5645
  <table>
5646
5646
  <thead><tr><th>Beschreibung</th><th style="text-align:right">Menge</th><th style="text-align:right">Einzelpreis</th><th style="text-align:right">Gesamt</th></tr></thead>
@@ -5719,15 +5719,14 @@ async function generateQuote(dataDir, input) {
5719
5719
  status: "draft",
5720
5720
  htmlPath
5721
5721
  };
5722
- fs.default.writeFileSync(path.default.join(dir, `${quoteNumber}.json`), JSON.stringify(quote, null, 2), "utf-8");
5723
- const html = buildHtml(quote, config, readCustomerName(dataDir, input.slug));
5724
- fs.default.writeFileSync(htmlPath, html, "utf-8");
5722
+ require_atomic_write.writeFileAtomic(path.default.join(dir, `${quoteNumber}.json`), JSON.stringify(quote, null, 2));
5723
+ require_atomic_write.writeFileAtomic(htmlPath, buildHtml(quote, config, readCustomerName(dataDir, input.slug)));
5725
5724
  return quote;
5726
5725
  }
5727
5726
  //#endregion
5728
5727
  //#region src/mcp/tools/generate-quote.ts
5729
- const DATA_DIR$16 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5730
- async function handleGenerateQuote(input, dataDir = DATA_DIR$16) {
5728
+ const DATA_DIR$17 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5729
+ async function handleGenerateQuote(input, dataDir = DATA_DIR$17) {
5731
5730
  try {
5732
5731
  const quote = await generateQuote(dataDir, input);
5733
5732
  return { content: [{
@@ -5751,7 +5750,7 @@ async function handleGenerateQuote(input, dataDir = DATA_DIR$16) {
5751
5750
  }] };
5752
5751
  }
5753
5752
  }
5754
- function registerGenerateQuote(server, dataDir = DATA_DIR$16) {
5753
+ function registerGenerateQuote(server, dataDir = DATA_DIR$17) {
5755
5754
  server.registerTool("generate_quote", {
5756
5755
  description: `Generate a professional HTML quote/offer for a customer deal.
5757
5756
  Calculates subtotal, VAT, and total. Saves JSON + HTML to .agentic/quotes/.
@@ -5779,8 +5778,8 @@ Returns: { quoteNumber, htmlPath, total, currency, validUntil }`,
5779
5778
  }
5780
5779
  //#endregion
5781
5780
  //#region src/mcp/tools/get-quote-status.ts
5782
- const DATA_DIR$15 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5783
- async function handleGetQuoteStatus(input, dataDir = DATA_DIR$15) {
5781
+ const DATA_DIR$16 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5782
+ async function handleGetQuoteStatus(input, dataDir = DATA_DIR$16) {
5784
5783
  if (input.quoteNumber) {
5785
5784
  const quote = readQuote(dataDir, input.quoteNumber);
5786
5785
  if (!quote) return { content: [{
@@ -5798,7 +5797,7 @@ async function handleGetQuoteStatus(input, dataDir = DATA_DIR$15) {
5798
5797
  text: JSON.stringify({ quotes }, null, 2)
5799
5798
  }] };
5800
5799
  }
5801
- function registerGetQuoteStatus(server, dataDir = DATA_DIR$15) {
5800
+ function registerGetQuoteStatus(server, dataDir = DATA_DIR$16) {
5802
5801
  server.registerTool("get_quote_status", {
5803
5802
  description: `Get quote status and details. Filter by quoteNumber (single quote) or slug (all quotes for a customer).
5804
5803
  Returns quote with status: draft | sent | viewed | accepted | declined`,
@@ -5813,7 +5812,7 @@ Returns quote with status: draft | sent | viewed | accepted | declined`,
5813
5812
  }
5814
5813
  //#endregion
5815
5814
  //#region src/mcp/tools/get-booking-link.ts
5816
- const DATA_DIR$14 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5815
+ const DATA_DIR$15 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5817
5816
  function loadCalendlyConfig(dataDir) {
5818
5817
  const p = path.default.join(dataDir, ".agentic", "integrations", "calendly.yaml");
5819
5818
  if (!fs.default.existsSync(p)) return {};
@@ -5836,7 +5835,7 @@ function readCustomerFacts(dataDir, slug) {
5836
5835
  ...email ? { email } : {}
5837
5836
  };
5838
5837
  }
5839
- async function handleGetBookingLink(input, dataDir = DATA_DIR$14) {
5838
+ async function handleGetBookingLink(input, dataDir = DATA_DIR$15) {
5840
5839
  const config = loadCalendlyConfig(dataDir);
5841
5840
  const apiKey = config.apiKey ?? process.env["CALENDLY_API_KEY"] ?? "";
5842
5841
  if (!apiKey) return { content: [{
@@ -5864,7 +5863,7 @@ async function handleGetBookingLink(input, dataDir = DATA_DIR$14) {
5864
5863
  }] };
5865
5864
  }
5866
5865
  }
5867
- function registerGetBookingLink(server, dataDir = DATA_DIR$14) {
5866
+ function registerGetBookingLink(server, dataDir = DATA_DIR$15) {
5868
5867
  server.registerTool("get_booking_link", {
5869
5868
  description: `Get a Calendly booking link for a customer. Optionally pre-fills the customer's name/email.
5870
5869
  Requires CALENDLY_API_KEY env var or .agentic/integrations/calendly.yaml config.
@@ -5912,6 +5911,7 @@ const TICKET_HEADER = "# Tickets\n\n";
5912
5911
  const TABLE_HEADER = `| ID | Title | Status | Priority | Assignee | Created | SLA Due | Resolved |
5913
5912
  |----|-------|--------|----------|----------|---------|---------|---------|`;
5914
5913
  function ticketsPath(dataDir, slug) {
5914
+ require_session_store.assertSafeSlug(slug);
5915
5915
  return path.default.join(dataDir, "customers", slug, "tickets.md");
5916
5916
  }
5917
5917
  function escapeMd(s) {
@@ -5964,7 +5964,7 @@ async function upsertTicket(dataDir, slug, ticket) {
5964
5964
  const idx = existing.findIndex((t) => t.id === ticket.id);
5965
5965
  if (idx >= 0) existing[idx] = ticket;
5966
5966
  else existing.push(ticket);
5967
- fs.default.writeFileSync(p, serializeTickets(existing), "utf-8");
5967
+ require_atomic_write.writeFileAtomic(p, serializeTickets(existing));
5968
5968
  }
5969
5969
  function nextTicketId(tickets) {
5970
5970
  const nums = tickets.map((t) => parseInt(t.id.replace("T-", ""), 10)).filter((n) => !isNaN(n));
@@ -5972,28 +5972,13 @@ function nextTicketId(tickets) {
5972
5972
  return `T-${String(max + 1).padStart(3, "0")}`;
5973
5973
  }
5974
5974
  async function listAllTickets(dataDir, filter) {
5975
- const customersDir = path.default.join(dataDir, "customers");
5976
- if (!fs.default.existsSync(customersDir)) return [];
5977
- const slugs = filter?.slug ? [filter.slug] : fs.default.readdirSync(customersDir).filter((s) => {
5978
- try {
5979
- return fs.default.statSync(path.default.join(customersDir, s)).isDirectory();
5980
- } catch {
5981
- return false;
5982
- }
5983
- });
5984
- const results = [];
5985
- for (const slug of slugs) {
5986
- const tickets = await readTickets(dataDir, slug);
5987
- for (const ticket of tickets) {
5988
- if (filter?.status && ticket.status !== filter.status) continue;
5989
- if (filter?.priority && ticket.priority !== filter.priority) continue;
5990
- if (filter?.assignee && ticket.assignee !== filter.assignee) continue;
5991
- results.push({
5992
- slug,
5993
- ticket
5994
- });
5995
- }
5996
- }
5975
+ const slugs = filter?.slug ? [filter.slug] : require_session_store.listCustomerSlugs(dataDir);
5976
+ const results = (await Promise.all(slugs.map(async (slug) => {
5977
+ return (await readTickets(dataDir, slug)).filter((ticket) => (!filter?.status || ticket.status === filter.status) && (!filter?.priority || ticket.priority === filter.priority) && (!filter?.assignee || ticket.assignee === filter.assignee)).map((ticket) => ({
5978
+ slug,
5979
+ ticket
5980
+ }));
5981
+ }))).flat();
5997
5982
  const priorityOrder = {
5998
5983
  urgent: 0,
5999
5984
  high: 1,
@@ -6048,8 +6033,8 @@ function calcSlaDue(createdDate, priority, rules) {
6048
6033
  }
6049
6034
  //#endregion
6050
6035
  //#region src/mcp/tools/create-ticket.ts
6051
- const DATA_DIR$13 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6052
- async function handleCreateTicket(input, dataDir = DATA_DIR$13) {
6036
+ const DATA_DIR$14 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6037
+ async function handleCreateTicket(input, dataDir = DATA_DIR$14) {
6053
6038
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
6054
6039
  const rules = loadSlaRules(dataDir);
6055
6040
  const priority = input.priority ?? "normal";
@@ -6071,7 +6056,7 @@ async function handleCreateTicket(input, dataDir = DATA_DIR$13) {
6071
6056
  text: JSON.stringify({ ticket }, null, 2)
6072
6057
  }] };
6073
6058
  }
6074
- function registerCreateTicket(server, dataDir = DATA_DIR$13) {
6059
+ function registerCreateTicket(server, dataDir = DATA_DIR$14) {
6075
6060
  server.registerTool("create_ticket", {
6076
6061
  description: `Create a support ticket for a customer. Auto-calculates SLA due date based on priority.
6077
6062
  Returns: { ticket } with id T-NNN, status=open, slaDue`,
@@ -6097,8 +6082,8 @@ Returns: { ticket } with id T-NNN, status=open, slaDue`,
6097
6082
  }
6098
6083
  //#endregion
6099
6084
  //#region src/mcp/tools/update-ticket.ts
6100
- const DATA_DIR$12 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6101
- async function handleUpdateTicket(input, dataDir = DATA_DIR$12) {
6085
+ const DATA_DIR$13 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6086
+ async function handleUpdateTicket(input, dataDir = DATA_DIR$13) {
6102
6087
  const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
6103
6088
  if (!ticket) return { content: [{
6104
6089
  type: "text",
@@ -6117,7 +6102,7 @@ async function handleUpdateTicket(input, dataDir = DATA_DIR$12) {
6117
6102
  text: JSON.stringify({ ticket: updated }, null, 2)
6118
6103
  }] };
6119
6104
  }
6120
- function registerUpdateTicket(server, dataDir = DATA_DIR$12) {
6105
+ function registerUpdateTicket(server, dataDir = DATA_DIR$13) {
6121
6106
  server.registerTool("update_ticket", {
6122
6107
  description: `Update a ticket's status or assignee. Setting status=resolved auto-sets resolved date.
6123
6108
  Returns: { ticket }`,
@@ -6142,8 +6127,8 @@ Returns: { ticket }`,
6142
6127
  }
6143
6128
  //#endregion
6144
6129
  //#region src/mcp/tools/list-tickets.ts
6145
- const DATA_DIR$11 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6146
- async function handleListTickets(input, dataDir = DATA_DIR$11) {
6130
+ const DATA_DIR$12 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6131
+ async function handleListTickets(input, dataDir = DATA_DIR$12) {
6147
6132
  const results = await listAllTickets(dataDir, {
6148
6133
  ...input.slug !== void 0 ? { slug: input.slug } : {},
6149
6134
  ...input.status !== void 0 ? { status: input.status } : {},
@@ -6155,7 +6140,7 @@ async function handleListTickets(input, dataDir = DATA_DIR$11) {
6155
6140
  text: JSON.stringify({ tickets: results }, null, 2)
6156
6141
  }] };
6157
6142
  }
6158
- function registerListTickets(server, dataDir = DATA_DIR$11) {
6143
+ function registerListTickets(server, dataDir = DATA_DIR$12) {
6159
6144
  server.registerTool("list_tickets", {
6160
6145
  description: `List support tickets. Filter by customer, status, priority, or assignee. Sorted by priority then date.
6161
6146
  Returns: { tickets: Array<{ slug, ticket }> }`,
@@ -6185,8 +6170,8 @@ Returns: { tickets: Array<{ slug, ticket }> }`,
6185
6170
  }
6186
6171
  //#endregion
6187
6172
  //#region src/mcp/tools/close-ticket.ts
6188
- const DATA_DIR$10 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6189
- async function handleCloseTicket(input, dataDir = DATA_DIR$10) {
6173
+ const DATA_DIR$11 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6174
+ async function handleCloseTicket(input, dataDir = DATA_DIR$11) {
6190
6175
  const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
6191
6176
  if (!ticket) return { content: [{
6192
6177
  type: "text",
@@ -6213,7 +6198,7 @@ async function handleCloseTicket(input, dataDir = DATA_DIR$10) {
6213
6198
  text: JSON.stringify({ ticket: updated }, null, 2)
6214
6199
  }] };
6215
6200
  }
6216
- function registerCloseTicket(server, dataDir = DATA_DIR$10) {
6201
+ function registerCloseTicket(server, dataDir = DATA_DIR$11) {
6217
6202
  server.registerTool("close_ticket", {
6218
6203
  description: `Close a support ticket. Optionally logs the resolution as an interaction.
6219
6204
  Returns: { ticket } with status=closed`,
@@ -6323,7 +6308,7 @@ async function recordSurveyResponse(dataDir, token, score, comment) {
6323
6308
  const dir = responsesDir(dataDir, pending.surveyId);
6324
6309
  fs.default.mkdirSync(dir, { recursive: true });
6325
6310
  const filename = `${pending.slug}_${pending.contactEmail.replace("@", "_at_")}_${Date.now()}.json`;
6326
- fs.default.writeFileSync(path.default.join(dir, filename), JSON.stringify(response, null, 2), "utf-8");
6311
+ require_atomic_write.writeFileAtomic(path.default.join(dir, filename), JSON.stringify(response, null, 2));
6327
6312
  fs.default.unlinkSync(path.default.join(pendingDir, file));
6328
6313
  return response;
6329
6314
  } catch {
@@ -6363,12 +6348,12 @@ async function savePendingSurvey(dataDir, surveyId, slug, contactEmail, token) {
6363
6348
  contactEmail,
6364
6349
  sentAt: (/* @__PURE__ */ new Date()).toISOString()
6365
6350
  };
6366
- fs.default.writeFileSync(path.default.join(pendingDir, filename), JSON.stringify(pending, null, 2), "utf-8");
6351
+ require_atomic_write.writeFileAtomic(path.default.join(pendingDir, filename), JSON.stringify(pending, null, 2));
6367
6352
  }
6368
6353
  //#endregion
6369
6354
  //#region src/mcp/tools/send-nps-survey.ts
6370
- const DATA_DIR$9 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6371
- async function handleSendNpsSurvey(input, dataDir = DATA_DIR$9) {
6355
+ const DATA_DIR$10 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6356
+ async function handleSendNpsSurvey(input, dataDir = DATA_DIR$10) {
6372
6357
  const survey = getSurvey(dataDir, input.surveyId);
6373
6358
  if (!survey) return { content: [{
6374
6359
  type: "text",
@@ -6389,7 +6374,7 @@ async function handleSendNpsSurvey(input, dataDir = DATA_DIR$9) {
6389
6374
  }, null, 2)
6390
6375
  }] };
6391
6376
  }
6392
- function registerSendNpsSurvey(server, dataDir = DATA_DIR$9) {
6377
+ function registerSendNpsSurvey(server, dataDir = DATA_DIR$10) {
6393
6378
  server.registerTool("send_nps_survey", {
6394
6379
  description: `Generate an NPS/CSAT survey email for a customer contact. Returns subject, HTML body, and a token-based response URL.
6395
6380
  Does NOT send automatically — returns draft for review.
@@ -6409,8 +6394,8 @@ Returns: { token, subject, body, surveyUrl }`,
6409
6394
  }
6410
6395
  //#endregion
6411
6396
  //#region src/mcp/tools/get-survey-results.ts
6412
- const DATA_DIR$8 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6413
- async function handleGetSurveyResults(input, dataDir = DATA_DIR$8) {
6397
+ const DATA_DIR$9 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6398
+ async function handleGetSurveyResults(input, dataDir = DATA_DIR$9) {
6414
6399
  const responses = loadSurveyResponses(dataDir, input.surveyId, input.slug);
6415
6400
  const nps = calcNpsScore(responses);
6416
6401
  const promoters = responses.filter((r) => r.score >= 9).length;
@@ -6436,7 +6421,7 @@ async function handleGetSurveyResults(input, dataDir = DATA_DIR$8) {
6436
6421
  }, null, 2)
6437
6422
  }] };
6438
6423
  }
6439
- function registerGetSurveyResults(server, dataDir = DATA_DIR$8) {
6424
+ function registerGetSurveyResults(server, dataDir = DATA_DIR$9) {
6440
6425
  server.registerTool("get_survey_results", {
6441
6426
  description: `Get NPS/CSAT survey results with score breakdown. Calculates Net Promoter Score.
6442
6427
  Returns: { npsScore, totalResponses, promoters, passives, detractors, responses[] }`,
@@ -6466,18 +6451,21 @@ const KbArticleSchema = zod.z.object({
6466
6451
  function kbDir(dataDir) {
6467
6452
  return path.default.join(dataDir, ".agentic", "knowledge-base");
6468
6453
  }
6469
- function listKbArticles(dataDir, opts) {
6470
- const dir = kbDir(dataDir);
6454
+ /** Category subdirectories of the knowledge base. */
6455
+ function kbCategories(dir) {
6471
6456
  if (!fs.default.existsSync(dir)) return [];
6472
- const results = [];
6473
- const categories = fs.default.readdirSync(dir).filter((f) => {
6457
+ return fs.default.readdirSync(dir).filter((f) => {
6474
6458
  try {
6475
6459
  return fs.default.statSync(path.default.join(dir, f)).isDirectory();
6476
6460
  } catch {
6477
6461
  return false;
6478
6462
  }
6479
6463
  });
6480
- for (const cat of categories) {
6464
+ }
6465
+ function listKbArticles(dataDir, opts) {
6466
+ const dir = kbDir(dataDir);
6467
+ const results = [];
6468
+ for (const cat of kbCategories(dir)) {
6481
6469
  const catDir = path.default.join(dir, cat);
6482
6470
  const files = fs.default.readdirSync(catDir).filter((f) => f.endsWith(".md"));
6483
6471
  for (const file of files) try {
@@ -6497,14 +6485,31 @@ function listKbArticles(dataDir, opts) {
6497
6485
  return results;
6498
6486
  }
6499
6487
  function getKbArticle(dataDir, id) {
6500
- return listKbArticles(dataDir).find((a) => a.id === id) ?? null;
6488
+ if (!require_session_store.isSafePathSegment(id)) return null;
6489
+ const dir = kbDir(dataDir);
6490
+ for (const cat of kbCategories(dir)) {
6491
+ const filePath = path.default.join(dir, cat, `${id}.md`);
6492
+ if (!fs.default.existsSync(filePath)) continue;
6493
+ try {
6494
+ const parsed = (0, gray_matter.default)(fs.default.readFileSync(filePath, "utf-8"));
6495
+ const meta = KbArticleSchema.safeParse(parsed.data);
6496
+ if (!meta.success) return null;
6497
+ return {
6498
+ ...meta.data,
6499
+ body: parsed.content.trim()
6500
+ };
6501
+ } catch {
6502
+ return null;
6503
+ }
6504
+ }
6505
+ return null;
6501
6506
  }
6502
6507
  function writeKbArticle(dataDir, article) {
6503
- const dir = path.default.join(kbDir(dataDir), article.category);
6504
- fs.default.mkdirSync(dir, { recursive: true });
6508
+ require_session_store.assertSafePathSegment(article.category, "knowledge-base category");
6509
+ require_session_store.assertSafePathSegment(article.id, "knowledge-base article id");
6505
6510
  const { body, ...meta } = article;
6506
6511
  const content = gray_matter.default.stringify(body, meta);
6507
- fs.default.writeFileSync(path.default.join(dir, `${article.id}.md`), content, "utf-8");
6512
+ require_atomic_write.writeFileAtomic(path.default.join(kbDir(dataDir), article.category, `${article.id}.md`), content);
6508
6513
  }
6509
6514
  function searchKbSimple(dataDir, query, opts) {
6510
6515
  const all = listKbArticles(dataDir, opts?.publicOnly ? { publicOnly: true } : {});
@@ -6517,8 +6522,8 @@ function getKbMetaForExport(article) {
6517
6522
  }
6518
6523
  //#endregion
6519
6524
  //#region src/mcp/tools/search-knowledge-base.ts
6520
- const DATA_DIR$7 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6521
- async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$7) {
6525
+ const DATA_DIR$8 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6526
+ async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$8) {
6522
6527
  const results = searchKbSimple(dataDir, input.query, { ...input.publicOnly ? { publicOnly: true } : {} });
6523
6528
  const limited = (input.category ? results.filter((a) => a.category === input.category) : results).slice(0, input.limit ?? 10);
6524
6529
  return { content: [{
@@ -6533,7 +6538,7 @@ async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$7) {
6533
6538
  }, null, 2)
6534
6539
  }] };
6535
6540
  }
6536
- function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$7) {
6541
+ function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$8) {
6537
6542
  server.registerTool("search_knowledge_base", {
6538
6543
  description: `Search the knowledge base for articles. Text search on title, body, and tags.
6539
6544
  Returns: { count, articles[] } with excerpts`,
@@ -6552,8 +6557,8 @@ Returns: { count, articles[] } with excerpts`,
6552
6557
  }
6553
6558
  //#endregion
6554
6559
  //#region src/mcp/tools/create-kb-article.ts
6555
- const DATA_DIR$6 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6556
- async function handleCreateKbArticle(input, dataDir = DATA_DIR$6) {
6560
+ const DATA_DIR$7 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6561
+ async function handleCreateKbArticle(input, dataDir = DATA_DIR$7) {
6557
6562
  if (getKbArticle(dataDir, input.id)) return { content: [{
6558
6563
  type: "text",
6559
6564
  text: JSON.stringify({ error: `Article '${input.id}' already exists` })
@@ -6581,7 +6586,7 @@ async function handleCreateKbArticle(input, dataDir = DATA_DIR$6) {
6581
6586
  }, null, 2)
6582
6587
  }] };
6583
6588
  }
6584
- function registerCreateKbArticle(server, dataDir = DATA_DIR$6) {
6589
+ function registerCreateKbArticle(server, dataDir = DATA_DIR$7) {
6585
6590
  server.registerTool("create_kb_article", {
6586
6591
  description: `Create a new knowledge base article. Articles are stored as Markdown files in .agentic/knowledge-base/.
6587
6592
  Returns: { id, title, category, path }`,
@@ -6606,8 +6611,8 @@ Returns: { id, title, category, path }`,
6606
6611
  }
6607
6612
  //#endregion
6608
6613
  //#region src/mcp/tools/backup-now.ts
6609
- const DATA_DIR$5 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6610
- async function handleBackupNow(input, dataDir = DATA_DIR$5) {
6614
+ const DATA_DIR$6 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6615
+ async function handleBackupNow(input, dataDir = DATA_DIR$6) {
6611
6616
  const zipPath = path.default.join(dataDir, `dxcrm-backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19)}.zip`);
6612
6617
  const manifest = await require_session_store.runBackup(zipPath, dataDir, { ...input.remote ? { remote: input.remote } : {} }).catch(() => null);
6613
6618
  if (!manifest) return { content: [{
@@ -6644,8 +6649,8 @@ function registerBackupNow(server) {
6644
6649
  }
6645
6650
  //#endregion
6646
6651
  //#region src/mcp/tools/list-backups.ts
6647
- const DATA_DIR$4 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6648
- async function handleListBackups(input, dataDir = DATA_DIR$4) {
6652
+ const DATA_DIR$5 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6653
+ async function handleListBackups(input, dataDir = DATA_DIR$5) {
6649
6654
  const logEntries = require_session_store.readBackupLog(dataDir);
6650
6655
  const fileEntries = require_session_store.listBackupsInDir(dataDir);
6651
6656
  const entries = logEntries.length > 0 ? logEntries : fileEntries;
@@ -6679,8 +6684,8 @@ function registerListBackups(server) {
6679
6684
  }
6680
6685
  //#endregion
6681
6686
  //#region src/mcp/tools/trigger-sync.ts
6682
- const DATA_DIR$3 = process.cwd();
6683
- async function handleTriggerSync(input, dataDir = DATA_DIR$3) {
6687
+ const DATA_DIR$4 = process.cwd();
6688
+ async function handleTriggerSync(input, dataDir = DATA_DIR$4) {
6684
6689
  const auth = getGmailAuth();
6685
6690
  if (!auth) return { content: [{
6686
6691
  type: "text",
@@ -6715,7 +6720,7 @@ async function handleTriggerSync(input, dataDir = DATA_DIR$3) {
6715
6720
  try {
6716
6721
  const sources = JSON.parse(fs.default.readFileSync(sourcesPath, "utf-8"));
6717
6722
  if (!sources.gmail?.enabled || !sources.gmail.query) continue;
6718
- const { syncGmail } = await Promise.resolve().then(() => require("./gmail-sync-hHm9gaWd.cjs"));
6723
+ const { syncGmail } = await Promise.resolve().then(() => require("./gmail-sync-BpSVESSe.cjs"));
6719
6724
  const result = await syncGmail({
6720
6725
  slug,
6721
6726
  dataDir,
@@ -6774,8 +6779,8 @@ Returns: { success: boolean, synced: number, skipped: number, customers: [...],
6774
6779
  }
6775
6780
  //#endregion
6776
6781
  //#region src/mcp/tools/get-audit-log.ts
6777
- const DATA_DIR$2 = process.cwd();
6778
- async function handleGetAuditLog(input, dataDir = DATA_DIR$2) {
6782
+ const DATA_DIR$3 = process.cwd();
6783
+ async function handleGetAuditLog(input, dataDir = DATA_DIR$3) {
6779
6784
  const entries = require_session_store.readAuditLog(dataDir);
6780
6785
  const filterOpts = { limit: input.limit ?? 50 };
6781
6786
  if (input.slug !== void 0) filterOpts.slug = input.slug;
@@ -6816,6 +6821,69 @@ Returns: { total: number, returned: number, entries: [{timestamp, actor, tool, s
6816
6821
  });
6817
6822
  }
6818
6823
  //#endregion
6824
+ //#region src/mcp/tools/get-logs.ts
6825
+ const DATA_DIR$2 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6826
+ async function handleGetLogs(input, dataDir = DATA_DIR$2) {
6827
+ const query = {
6828
+ ...input.level !== void 0 ? { level: input.level } : {},
6829
+ ...input.component !== void 0 ? { component: input.component } : {},
6830
+ ...input.since !== void 0 ? { since: input.since } : {},
6831
+ ...input.contains !== void 0 ? { contains: input.contains } : {},
6832
+ limit: input.limit ?? 100
6833
+ };
6834
+ const payload = input.summary ? require_logger.summarizeLogs(dataDir, query) : (() => {
6835
+ const entries = require_logger.queryLogs(dataDir, query);
6836
+ return {
6837
+ returned: entries.length,
6838
+ entries
6839
+ };
6840
+ })();
6841
+ return { content: [{
6842
+ type: "text",
6843
+ text: JSON.stringify(payload, null, 2)
6844
+ }] };
6845
+ }
6846
+ function registerGetLogs(server) {
6847
+ server.registerTool("get_logs", {
6848
+ title: "Get Logs",
6849
+ description: `Read and analyze the structured application log (.agentic/logs.ndjson).
6850
+ Use to answer "what went wrong recently?", "show errors from gmail sync", or "summarize today's activity".
6851
+
6852
+ Args:
6853
+ level: Minimum level to include — debug | info | warn | error (optional)
6854
+ component: Filter by component, e.g. "gmail-sync", "lancedb" (optional)
6855
+ since: ISO timestamp; only entries at or after it (optional)
6856
+ contains: Case-insensitive substring of the message (optional)
6857
+ limit: Max entries to return (default 100, most recent)
6858
+ summary: When true, return aggregated counts (by level + component) and recent errors instead of raw entries
6859
+
6860
+ Returns (entries): { returned: number, entries: [{ts, level, component, message, context?}] }
6861
+ Returns (summary): { total, byLevel, byComponent, firstTs, lastTs, recentErrors }`,
6862
+ inputSchema: zod.z.object({
6863
+ level: zod.z.enum([
6864
+ "debug",
6865
+ "info",
6866
+ "warn",
6867
+ "error"
6868
+ ]).optional().describe("Minimum level"),
6869
+ component: zod.z.string().optional().describe("Filter by component"),
6870
+ since: zod.z.string().optional().describe("ISO timestamp lower bound"),
6871
+ contains: zod.z.string().optional().describe("Message substring filter"),
6872
+ limit: zod.z.number().int().min(1).max(1e3).optional().describe("Max entries (default 100)"),
6873
+ summary: zod.z.boolean().optional().describe("Return aggregated summary instead of entries")
6874
+ })
6875
+ }, async ({ level, component, since, contains, limit, summary }) => {
6876
+ const input = {};
6877
+ if (level !== void 0) input.level = level;
6878
+ if (component !== void 0) input.component = component;
6879
+ if (since !== void 0) input.since = since;
6880
+ if (contains !== void 0) input.contains = contains;
6881
+ if (limit !== void 0) input.limit = limit;
6882
+ if (summary !== void 0) input.summary = summary;
6883
+ return handleGetLogs(input);
6884
+ });
6885
+ }
6886
+ //#endregion
6819
6887
  //#region src/mcp/prompts.ts
6820
6888
  /**
6821
6889
  * CRM playbook prompts exposed via MCP `prompts/list` + `prompts/get`.
@@ -6897,7 +6965,7 @@ function registerResources(server, dataDir = DATA_DIR$1) {
6897
6965
  description: "Open and closed deals for a customer",
6898
6966
  mimeType: "application/json"
6899
6967
  }, async (uri, variables) => {
6900
- const { readPipeline } = await Promise.resolve().then(() => require("./pipeline-writer-N2omexxp.cjs")).then((n) => n.pipeline_writer_exports);
6968
+ const { readPipeline } = await Promise.resolve().then(() => require("./pipeline-writer-B1tRAhuD.cjs")).then((n) => n.pipeline_writer_exports);
6901
6969
  const deals = await readPipeline(dataDir, String(variables["slug"]));
6902
6970
  return { contents: [{
6903
6971
  uri: uri.href,
@@ -6910,7 +6978,7 @@ function registerResources(server, dataDir = DATA_DIR$1) {
6910
6978
  description: "Newest-first interaction history for a customer",
6911
6979
  mimeType: "text/markdown"
6912
6980
  }, async (uri, variables) => {
6913
- const { readInteractions } = await Promise.resolve().then(() => require("./interactions-writer-CrPStUll.cjs")).then((n) => n.interactions_writer_exports);
6981
+ const { readInteractions } = await Promise.resolve().then(() => require("./interactions-writer-BRJNrefF.cjs")).then((n) => n.interactions_writer_exports);
6914
6982
  const text = await readInteractions(dataDir, String(variables["slug"]));
6915
6983
  return { contents: [{
6916
6984
  uri: uri.href,
@@ -6969,46 +7037,30 @@ function objectsSchemaPath(dataDir) {
6969
7037
  return path.default.join(dataDir, ".agentic", "schema", "custom-objects.json");
6970
7038
  }
6971
7039
  function recordsPath(dataDir, name) {
7040
+ require_session_store.assertSafePathSegment(name, "custom object name");
6972
7041
  return path.default.join(dataDir, ".agentic", "objects", `${name}.json`);
6973
7042
  }
6974
7043
  function loadCustomObjects(dataDir) {
6975
- const p = objectsSchemaPath(dataDir);
6976
- if (!fs.default.existsSync(p)) return [];
6977
- try {
6978
- const data = JSON.parse(fs.default.readFileSync(p, "utf-8"));
6979
- return Array.isArray(data.objects) ? data.objects : [];
6980
- } catch {
6981
- return [];
6982
- }
7044
+ return require_session_store.readJsonArray(objectsSchemaPath(dataDir), "objects");
6983
7045
  }
6984
7046
  function getObjectDefinition(dataDir, name) {
6985
7047
  return loadCustomObjects(dataDir).find((o) => o.name === name);
6986
7048
  }
6987
7049
  /** Add or update (by name) a custom object definition. */
6988
7050
  function defineCustomObject(dataDir, def) {
7051
+ require_session_store.assertSafePathSegment(def.name, "custom object name");
6989
7052
  const objs = loadCustomObjects(dataDir);
6990
7053
  const idx = objs.findIndex((o) => o.name === def.name);
6991
7054
  if (idx >= 0) objs[idx] = def;
6992
7055
  else objs.push(def);
6993
- const p = objectsSchemaPath(dataDir);
6994
- fs.default.mkdirSync(path.default.dirname(p), { recursive: true });
6995
- fs.default.writeFileSync(p, JSON.stringify({ objects: objs }, null, 2), "utf-8");
7056
+ require_session_store.writeJsonArray(objectsSchemaPath(dataDir), "objects", objs);
6996
7057
  return objs;
6997
7058
  }
6998
7059
  function listRecords(dataDir, name) {
6999
- const p = recordsPath(dataDir, name);
7000
- if (!fs.default.existsSync(p)) return [];
7001
- try {
7002
- const data = JSON.parse(fs.default.readFileSync(p, "utf-8"));
7003
- return Array.isArray(data.records) ? data.records : [];
7004
- } catch {
7005
- return [];
7006
- }
7060
+ return require_session_store.readJsonArray(recordsPath(dataDir, name), "records");
7007
7061
  }
7008
7062
  function writeRecords(dataDir, name, records) {
7009
- const p = recordsPath(dataDir, name);
7010
- fs.default.mkdirSync(path.default.dirname(p), { recursive: true });
7011
- fs.default.writeFileSync(p, JSON.stringify({ records }, null, 2), "utf-8");
7063
+ require_session_store.writeJsonArray(recordsPath(dataDir, name), "records", records);
7012
7064
  }
7013
7065
  function createRecord(dataDir, name, values) {
7014
7066
  const def = getObjectDefinition(dataDir, name);
@@ -7066,7 +7118,7 @@ function handleCreateRecord(input, dataDir = DATA_DIR) {
7066
7118
  require_session_store.enforceRbac(dataDir, "create_record");
7067
7119
  const res = createRecord(dataDir, input.object, input.values);
7068
7120
  if (!res.ok) return json({ error: (res.errors ?? []).join("; ") });
7069
- Promise.resolve().then(() => require("./webhooks-Xn6zO6kd.cjs")).then(({ emitEvent }) => emitEvent(dataDir, "record.created", {
7121
+ Promise.resolve().then(() => require("./webhooks-CwW-3kvG.cjs")).then(({ emitEvent }) => emitEvent(dataDir, "record.created", {
7070
7122
  object: input.object,
7071
7123
  record: res.record
7072
7124
  }));
@@ -7128,14 +7180,7 @@ function hashToken(token) {
7128
7180
  return (0, crypto.createHash)("sha256").update(token).digest("hex");
7129
7181
  }
7130
7182
  function loadMcpTokens(dataDir) {
7131
- const p = tokensPath(dataDir);
7132
- if (!fs.default.existsSync(p)) return [];
7133
- try {
7134
- const data = JSON.parse(fs.default.readFileSync(p, "utf-8"));
7135
- return Array.isArray(data.tokens) ? data.tokens : [];
7136
- } catch {
7137
- return [];
7138
- }
7183
+ return require_session_store.readJsonArray(tokensPath(dataDir), "tokens");
7139
7184
  }
7140
7185
  /**
7141
7186
  * Whether the HTTP MCP endpoint must require a bearer token.
@@ -7254,6 +7299,7 @@ function createMcpServer() {
7254
7299
  registerListBackups(server);
7255
7300
  registerTriggerSync(server);
7256
7301
  registerGetAuditLog(server);
7302
+ registerGetLogs(server);
7257
7303
  registerCustomObjectTools(server);
7258
7304
  registerPrompts(server);
7259
7305
  registerResources(server);
@@ -7264,7 +7310,7 @@ async function startStdio() {
7264
7310
  const server = createMcpServer();
7265
7311
  const transport = new _modelcontextprotocol_sdk_server_stdio_js.StdioServerTransport();
7266
7312
  await server.connect(transport);
7267
- console.error("DatasynxOpenCRM MCP Server running via stdio");
7313
+ require_logger.logger.info("mcp-server", "running via stdio");
7268
7314
  }
7269
7315
  async function startHttp(port = 3847) {
7270
7316
  await initOAuthFromDisk(process.cwd());
@@ -7304,7 +7350,7 @@ async function startHttp(port = 3847) {
7304
7350
  });
7305
7351
  app.get("/sessions", async (_req, res) => {
7306
7352
  try {
7307
- const { readAllSessions } = await Promise.resolve().then(() => require("./session-D0qFkBla.cjs"));
7353
+ const { readAllSessions } = await Promise.resolve().then(() => require("./session-Mm7GQbSH.cjs"));
7308
7354
  const sessions = readAllSessions(dataDir);
7309
7355
  res.json({ sessions });
7310
7356
  } catch {
@@ -7438,15 +7484,15 @@ button{margin-top:12px;padding:12px 28px;background:#1a1a2e;color:#fff;border:no
7438
7484
  res.send(surveyThankYouPage(numScore, commentText));
7439
7485
  });
7440
7486
  app.listen(port, () => {
7441
- console.error(`DatasynxOpenCRM MCP Server running on http://0.0.0.0:${port}/mcp`);
7487
+ require_logger.logger.info("mcp-server", "running over http", { url: `http://0.0.0.0:${port}/mcp` });
7442
7488
  });
7443
7489
  }
7444
7490
  if ((process.env["DXCRM_MCP_MODE"] ?? "stdio") === "http") startHttp(parseInt(process.env["DXCRM_MCP_PORT"] ?? "3847", 10)).catch((err) => {
7445
- console.error("MCP Server fatal error:", err.message);
7491
+ require_logger.logger.error("mcp-server", "fatal error", { error: err.message });
7446
7492
  process.exit(1);
7447
7493
  });
7448
7494
  else startStdio().catch((err) => {
7449
- console.error("MCP Server fatal error:", err.message);
7495
+ require_logger.logger.error("mcp-server", "fatal error", { error: err.message });
7450
7496
  process.exit(1);
7451
7497
  });
7452
7498
  //#endregion