@datasynx/agentic-crm 0.1.0 → 1.0.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 (286) hide show
  1. package/README.md +264 -670
  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-D8iYqDAr.js} +6 -6
  5. package/dist/{ask-CID3jnuL.js.map → ask-D8iYqDAr.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/auth-B5DcjJ_6.js +2 -0
  11. package/dist/{auth-DFWwWcYD.js → auth-DDXZTwS0.js} +4 -13
  12. package/dist/auth-DDXZTwS0.js.map +1 -0
  13. package/dist/{autofill-Di_-SP7t.js → autofill-B9VtlR2j.js} +2 -2
  14. package/dist/{autofill-Di_-SP7t.js.map → autofill-B9VtlR2j.js.map} +1 -1
  15. package/dist/{backup-CeMk9z86.js → backup-CTlIxUdO.js} +5 -7
  16. package/dist/backup-CTlIxUdO.js.map +1 -0
  17. package/dist/backup-LFnC09oV.js +2 -0
  18. package/dist/{churn-C28IgnAj.js → churn-DN9WDGNM.js} +3 -3
  19. package/dist/{churn-C28IgnAj.js.map → churn-DN9WDGNM.js.map} +1 -1
  20. package/dist/cli.js +282 -184
  21. package/dist/cli.js.map +1 -1
  22. package/dist/{compliance-CKSBoQUe.js → compliance-Bc12Hn9a.js} +3 -3
  23. package/dist/{compliance-CKSBoQUe.js.map → compliance-Bc12Hn9a.js.map} +1 -1
  24. package/dist/{compliance-CujOqAKk.js → compliance-TqYQXhBj.js} +1 -1
  25. package/dist/{compliance-B1kk5-YS.js → compliance-kq0xHRw3.js} +3 -3
  26. package/dist/{compliance-B1kk5-YS.js.map → compliance-kq0xHRw3.js.map} +1 -1
  27. package/dist/{compliance-B91zNvCR.cjs → compliance-pAj9FcGI.cjs} +3 -3
  28. package/dist/{compliance-B91zNvCR.cjs.map → compliance-pAj9FcGI.cjs.map} +1 -1
  29. package/dist/{context-builder-BzWAp3Zs.js → context-builder-7Uab5-G4.js} +3 -2
  30. package/dist/context-builder-7Uab5-G4.js.map +1 -0
  31. package/dist/context-builder-hmOPvgso.js +2 -0
  32. package/dist/{custom-fields-CzNeD3_v.js → custom-fields-BMyz5Ruh.js} +1 -1
  33. package/dist/{custom-fields-Pl2t9xzp.js → custom-fields-GzpOHW_2.js} +4 -13
  34. package/dist/custom-fields-GzpOHW_2.js.map +1 -0
  35. package/dist/{custom-objects-CIFrmQ2V.js → custom-objects-BNy-ayR-.js} +1 -1
  36. package/dist/{custom-objects-BHgn1GEX.js → custom-objects-CxW1gHwJ.js} +10 -25
  37. package/dist/custom-objects-CxW1gHwJ.js.map +1 -0
  38. package/dist/{customer-dir-DIylZ8Q6.js → customer-dir-CkMMXhb0.js} +9 -4
  39. package/dist/customer-dir-CkMMXhb0.js.map +1 -0
  40. package/dist/daemon/worker.js +66 -40
  41. package/dist/daemon/worker.js.map +1 -1
  42. package/dist/doctor-C14-vnJ1.js +103 -0
  43. package/dist/doctor-C14-vnJ1.js.map +1 -0
  44. package/dist/{enrichment-3XvgGDfB.js → enrichment-CDFdWmvD.js} +3 -3
  45. package/dist/{enrichment-3XvgGDfB.js.map → enrichment-CDFdWmvD.js.map} +1 -1
  46. package/dist/{file-lock-B_zi7NQl.js → file-lock-CcHotQkZ.js} +3 -4
  47. package/dist/file-lock-CcHotQkZ.js.map +1 -0
  48. package/dist/{gmail-sync-rQaVqKWd.js → gmail-sync-C-NmibzS.js} +13 -9
  49. package/dist/gmail-sync-C-NmibzS.js.map +1 -0
  50. package/dist/{gmail-sync-DIaxInDT.js → gmail-sync-DueE6tl5.js} +14 -10
  51. package/dist/gmail-sync-DueE6tl5.js.map +1 -0
  52. package/dist/{gmail-sync-hHm9gaWd.cjs → gmail-sync-GEy3oVvw.cjs} +13 -9
  53. package/dist/gmail-sync-GEy3oVvw.cjs.map +1 -0
  54. package/dist/{gmail-webhook-handler-DS7OlRPX.js → gmail-webhook-handler-B26COilD.js} +2 -2
  55. package/dist/{gmail-webhook-handler-e5Od25FX.js → gmail-webhook-handler-kGKpbY9h.js} +4 -4
  56. package/dist/{gmail-webhook-handler-e5Od25FX.js.map → gmail-webhook-handler-kGKpbY9h.js.map} +1 -1
  57. package/dist/{goal-engine-KpBftn4V.js → goal-engine-BbroPhqm.js} +10 -11
  58. package/dist/goal-engine-BbroPhqm.js.map +1 -0
  59. package/dist/{goal-engine-CUZSpERI.js → goal-engine-CfDAJTFt.js} +1 -1
  60. package/dist/{google-drive-sync-DEPcqFca.js → google-drive-sync-D1n7WKZn.js} +3 -3
  61. package/dist/{google-drive-sync-DEPcqFca.js.map → google-drive-sync-D1n7WKZn.js.map} +1 -1
  62. package/dist/{hygiene-DZqfYpFf.js → hygiene-DzQPnc6P.js} +3 -3
  63. package/dist/{hygiene-DZqfYpFf.js.map → hygiene-DzQPnc6P.js.map} +1 -1
  64. package/dist/identity-CB7j-Zr1.js +2 -0
  65. package/dist/{identity-CI6olMNm.js → identity-_uZ3Lbr2.js} +2 -2
  66. package/dist/{identity-CI6olMNm.js.map → identity-_uZ3Lbr2.js.map} +1 -1
  67. package/dist/{import-hubspot-BaK71U_K.js → import-hubspot-DB4n89jy.js} +51 -45
  68. package/dist/import-hubspot-DB4n89jy.js.map +1 -0
  69. package/dist/{index-V8BFaH-b.d.ts → index-B0IMMrp_.d.ts} +8 -4
  70. package/dist/{index-V8BFaH-b.d.ts.map → index-B0IMMrp_.d.ts.map} +1 -1
  71. package/dist/{index-YqwMd6aQ.d.cts → index-pY7tYXwH.d.cts} +8 -4
  72. package/dist/{index-YqwMd6aQ.d.cts.map → index-pY7tYXwH.d.cts.map} +1 -1
  73. package/dist/index.cjs +19 -21
  74. package/dist/index.cjs.map +1 -1
  75. package/dist/index.d.cts +8 -4
  76. package/dist/index.d.cts.map +1 -1
  77. package/dist/index.d.ts +8 -4
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +19 -21
  80. package/dist/index.js.map +1 -1
  81. package/dist/{interactions-writer-DO3KcSR3.js → interactions-writer-BZzUIgJd.js} +5 -2
  82. package/dist/interactions-writer-BZzUIgJd.js.map +1 -0
  83. package/dist/{interactions-writer-SLHnoEeE.js → interactions-writer-DbSyI2rt.js} +32 -3
  84. package/dist/interactions-writer-DbSyI2rt.js.map +1 -0
  85. package/dist/interactions-writer-RJB8SWf2.js +2 -0
  86. package/dist/{interactions-writer-CrPStUll.cjs → interactions-writer-a2yzBd7T.cjs} +5 -2
  87. package/dist/interactions-writer-a2yzBd7T.cjs.map +1 -0
  88. package/dist/json-store-WWsFzXub.js +43 -0
  89. package/dist/json-store-WWsFzXub.js.map +1 -0
  90. package/dist/{knowledge-base-D0Fh40kc.js → knowledge-base-DHNc4hVj.js} +43 -16
  91. package/dist/knowledge-base-DHNc4hVj.js.map +1 -0
  92. package/dist/{lancedb-CCBbpulq.js → lancedb-CswQEE5K.js} +1 -1
  93. package/dist/{lancedb-rlvWoPwl.js → lancedb-CuHKNsNZ.js} +4 -3
  94. package/dist/lancedb-CuHKNsNZ.js.map +1 -0
  95. package/dist/{lead-model-BCFzyktm.js → lead-model-CEmx7te7.js} +6 -14
  96. package/dist/lead-model-CEmx7te7.js.map +1 -0
  97. package/dist/{llm-Z8RIYkpF.js → llm-BnSUBisu.js} +2 -2
  98. package/dist/{llm-Z8RIYkpF.js.map → llm-BnSUBisu.js.map} +1 -1
  99. package/dist/{llm-iijeXmgq.cjs → llm-CXycmEl9.cjs} +2 -2
  100. package/dist/{llm-iijeXmgq.cjs.map → llm-CXycmEl9.cjs.map} +1 -1
  101. package/dist/{llm-DEjWcqmW.js → llm-DSX1-wFu.js} +1 -1
  102. package/dist/{llm-DvzZqva0.js → llm-PZzgPphl.js} +3 -3
  103. package/dist/{llm-DvzZqva0.js.map → llm-PZzgPphl.js.map} +1 -1
  104. package/dist/logger-BkInaGoV.cjs +167 -0
  105. package/dist/logger-BkInaGoV.cjs.map +1 -0
  106. package/dist/logger-Dyl4VcLO.js +147 -0
  107. package/dist/logger-Dyl4VcLO.js.map +1 -0
  108. package/dist/logger-UaF5p9d1.js +147 -0
  109. package/dist/logger-UaF5p9d1.js.map +1 -0
  110. package/dist/logger-vKQS34w9.js +2 -0
  111. package/dist/mcp-CdTJWTJf.d.cts.map +1 -1
  112. package/dist/mcp-CdTJWTJf.d.ts.map +1 -1
  113. package/dist/mcp.cjs +327 -303
  114. package/dist/mcp.cjs.map +1 -1
  115. package/dist/mcp.d.cts.map +1 -1
  116. package/dist/mcp.d.ts.map +1 -1
  117. package/dist/mcp.js +327 -303
  118. package/dist/mcp.js.map +1 -1
  119. package/dist/{memory-Cy6-Tbyl.js → memory-D8hmgD9d.js} +1 -1
  120. package/dist/{memory-Bb6ky3kb.js → memory-Dzr9dXSM.js} +4 -11
  121. package/dist/memory-Dzr9dXSM.js.map +1 -0
  122. package/dist/{microsoft-calendar-B6MMtUQK.js → microsoft-calendar-jIu9K5zX.js} +4 -4
  123. package/dist/{microsoft-calendar-B6MMtUQK.js.map → microsoft-calendar-jIu9K5zX.js.map} +1 -1
  124. package/dist/{microsoft-sync-CpZVoSuq.js → microsoft-sync-R_r8HL-B.js} +5 -5
  125. package/dist/{microsoft-sync-CpZVoSuq.js.map → microsoft-sync-R_r8HL-B.js.map} +1 -1
  126. package/dist/{nba-3wanmJ0U.js → nba-mTJ4yEqD.js} +3 -3
  127. package/dist/{nba-3wanmJ0U.js.map → nba-mTJ4yEqD.js.map} +1 -1
  128. package/dist/{notification-dispatcher-0vYNngWe.js → notification-dispatcher-inpKyuBz.js} +7 -3
  129. package/dist/notification-dispatcher-inpKyuBz.js.map +1 -0
  130. package/dist/{pipeline-writer-BqBrYrQc.js → pipeline-writer-0LJ6Qkat.js} +1 -1
  131. package/dist/{pipeline-writer-N2omexxp.cjs → pipeline-writer-B1tRAhuD.cjs} +11 -3
  132. package/dist/pipeline-writer-B1tRAhuD.cjs.map +1 -0
  133. package/dist/{pipeline-writer-BvVquKIe.js → pipeline-writer-CIllfnZl.js} +5 -3
  134. package/dist/pipeline-writer-CIllfnZl.js.map +1 -0
  135. package/dist/{pipeline-writer-eufx_0o1.js → pipeline-writer-rDj-ni6q.js} +6 -4
  136. package/dist/pipeline-writer-rDj-ni6q.js.map +1 -0
  137. package/dist/{proactive-agent-BgQXw3ac.js → proactive-agent-B7u3Bj_l.js} +6 -6
  138. package/dist/{proactive-agent-BgQXw3ac.js.map → proactive-agent-B7u3Bj_l.js.map} +1 -1
  139. package/dist/{proactive-worker-BrLHNhjH.js → proactive-worker-1zkm6aJD.js} +7 -8
  140. package/dist/proactive-worker-1zkm6aJD.js.map +1 -0
  141. package/dist/{push-manager-CowY-0IK.js → push-manager-BXM-IHfP.js} +1 -1
  142. package/dist/{push-manager-CdqIIkuh.js → push-manager-C0ECQgva.js} +4 -4
  143. package/dist/push-manager-C0ECQgva.js.map +1 -0
  144. package/dist/{quote-generator-OhSFsi3x.js → quote-generator-ByUyIYtw.js} +1 -1
  145. package/dist/{quote-generator-BfwENXzg.js → quote-generator-CTdR8eEI.js} +5 -5
  146. package/dist/quote-generator-CTdR8eEI.js.map +1 -0
  147. package/dist/rbac-DzbyFhVH.js +2 -0
  148. package/dist/{rbac-CTIktZaC.js → rbac-msmBc_tK.js} +19 -12
  149. package/dist/rbac-msmBc_tK.js.map +1 -0
  150. package/dist/regex-Jt5DatPi.js +13 -0
  151. package/dist/regex-Jt5DatPi.js.map +1 -0
  152. package/dist/{relationship-health-odxEoQdJ.js → relationship-health-ZZNXR1RZ.js} +8 -16
  153. package/dist/relationship-health-ZZNXR1RZ.js.map +1 -0
  154. package/dist/{revenue-simulation-Bqf2DLVB.js → revenue-simulation-D8f_YkUY.js} +9 -19
  155. package/dist/revenue-simulation-D8f_YkUY.js.map +1 -0
  156. package/dist/{revenue-simulation-BJdRTEHc.js → revenue-simulation-njJZlTqm.js} +1 -1
  157. package/dist/safe-path-mpp0dKtO.js +18 -0
  158. package/dist/safe-path-mpp0dKtO.js.map +1 -0
  159. package/dist/{segments-BqcD5HIl.js → segments-DI3LOQNe.js} +5 -14
  160. package/dist/segments-DI3LOQNe.js.map +1 -0
  161. package/dist/sequence-engine-C6nnewHX.js +2 -0
  162. package/dist/{sequence-engine-J1lTW_in.js → sequence-engine-DNTVLq7o.js} +15 -8
  163. package/dist/sequence-engine-DNTVLq7o.js.map +1 -0
  164. package/dist/{sequence-store-DaaWr0Os.js → sequence-store-CmYb6s0g.js} +6 -5
  165. package/dist/sequence-store-CmYb6s0g.js.map +1 -0
  166. package/dist/{server-Dyva03K8.js → server-DqSMYhSA.js} +278 -220
  167. package/dist/server-DqSMYhSA.js.map +1 -0
  168. package/dist/{session-D9ub6Wl1.js → session-B6XaP83h.js} +3 -3
  169. package/dist/session-B6XaP83h.js.map +1 -0
  170. package/dist/{session-B9AilxOE.js → session-BgGDyP2C.js} +3 -3
  171. package/dist/session-BgGDyP2C.js.map +1 -0
  172. package/dist/session-Bp4zTh4l.js +2 -0
  173. package/dist/{session-D0qFkBla.cjs → session-Mm7GQbSH.cjs} +3 -3
  174. package/dist/session-Mm7GQbSH.cjs.map +1 -0
  175. package/dist/{session-store-C8tEvMPw.js → session-store-DWxJ5Pof.js} +79 -17
  176. package/dist/session-store-DWxJ5Pof.js.map +1 -0
  177. package/dist/{session-store-B0QZE8Bx.cjs → session-store-yfwnj0OC.cjs} +126 -16
  178. package/dist/session-store-yfwnj0OC.cjs.map +1 -0
  179. package/dist/{sla-engine-5IhTsBUR.js → sla-engine-CP2KiKDS.js} +1 -1
  180. package/dist/{sla-engine-BqX-7u-7.js → sla-engine-O-A1ntu_.js} +2 -2
  181. package/dist/{sla-engine-BqX-7u-7.js.map → sla-engine-O-A1ntu_.js.map} +1 -1
  182. package/dist/{sop-Vp0UPWFW.js → sop-BV7ICAFR.js} +4 -11
  183. package/dist/sop-BV7ICAFR.js.map +1 -0
  184. package/dist/{sop-DkhVChGy.js → sop-D33qTHUb.js} +1 -1
  185. package/dist/survey-engine-DKctGcLQ.js +2 -0
  186. package/dist/{survey-engine-DBjCYqCv.js → survey-engine-DngXBv47.js} +5 -4
  187. package/dist/survey-engine-DngXBv47.js.map +1 -0
  188. package/dist/{sync-state-CwLSt_1m.js → sync-state-BaA8LbTI.js} +1 -1
  189. package/dist/{sync-state-ChaLbamC.js → sync-state-DMZgzpez.js} +4 -12
  190. package/dist/sync-state-DMZgzpez.js.map +1 -0
  191. package/dist/{ticket-writer-CjqKeIRD.js → ticket-writer-DsfpeLGZ.js} +1 -1
  192. package/dist/{ticket-writer-j2oX_Wal.js → ticket-writer-a9on36Wb.js} +12 -24
  193. package/dist/ticket-writer-a9on36Wb.js.map +1 -0
  194. package/dist/{tone-Bdm5uaht.js → tone-C7bqK69y.js} +5 -12
  195. package/dist/tone-C7bqK69y.js.map +1 -0
  196. package/dist/{tone-DRKlZgPr.cjs → tone-Cmc7O2Fx.cjs} +3 -9
  197. package/dist/tone-Cmc7O2Fx.cjs.map +1 -0
  198. package/dist/{tone-vNb2DAAD.js → tone-mXSftvTn.js} +3 -8
  199. package/dist/tone-mXSftvTn.js.map +1 -0
  200. package/dist/{transcript-watcher-CL2QUygI.js → transcript-watcher-0mh2ZhmH.js} +18 -11
  201. package/dist/transcript-watcher-0mh2ZhmH.js.map +1 -0
  202. package/dist/unmatched-transcripts-C92zAoM4.js +2 -0
  203. package/dist/unmatched-transcripts-DC-VQ9YS.js +16 -0
  204. package/dist/unmatched-transcripts-DC-VQ9YS.js.map +1 -0
  205. package/dist/update-deal-CWy1eLJI.js +2 -0
  206. package/dist/{update-deal-DKC79skb.js → update-deal-DSzr_Aau.js} +3 -3
  207. package/dist/{update-deal-DKC79skb.js.map → update-deal-DSzr_Aau.js.map} +1 -1
  208. package/dist/{usage-D0-TYJkw.js → usage-BVlFlKW_.js} +8 -6
  209. package/dist/usage-BVlFlKW_.js.map +1 -0
  210. package/dist/usage-CClTf5e6.cjs.map +1 -1
  211. package/dist/usage-D0u9a-lV.js.map +1 -1
  212. package/dist/{vault-DXCg29W-.js → vault-CfwZdNzC.js} +3 -4
  213. package/dist/vault-CfwZdNzC.js.map +1 -0
  214. package/dist/{vault-C1D3zScD.js → vault-DxKP4_R2.js} +1 -1
  215. package/dist/{webhooks-Xn6zO6kd.cjs → webhooks-CwW-3kvG.cjs} +5 -19
  216. package/dist/webhooks-CwW-3kvG.cjs.map +1 -0
  217. package/dist/{webhooks-7EpA05Qr.js → webhooks-DXr1IoKn.js} +8 -21
  218. package/dist/webhooks-DXr1IoKn.js.map +1 -0
  219. package/dist/{webhooks-BO2UAnmn.js → webhooks-sWZ8CJtR.js} +5 -18
  220. package/dist/webhooks-sWZ8CJtR.js.map +1 -0
  221. package/package.json +11 -2
  222. package/dist/approvals-DpjxGHFp.js.map +0 -1
  223. package/dist/auth-CyFuu9X_.js +0 -2
  224. package/dist/auth-DFWwWcYD.js.map +0 -1
  225. package/dist/backup-CeMk9z86.js.map +0 -1
  226. package/dist/backup-f_hC7rBV.js +0 -2
  227. package/dist/context-builder-BzWAp3Zs.js.map +0 -1
  228. package/dist/context-builder-DlrRcqmJ.js +0 -2
  229. package/dist/custom-fields-Pl2t9xzp.js.map +0 -1
  230. package/dist/custom-objects-BHgn1GEX.js.map +0 -1
  231. package/dist/customer-dir-DIylZ8Q6.js.map +0 -1
  232. package/dist/file-lock-B_zi7NQl.js.map +0 -1
  233. package/dist/gmail-sync-DIaxInDT.js.map +0 -1
  234. package/dist/gmail-sync-hHm9gaWd.cjs.map +0 -1
  235. package/dist/gmail-sync-rQaVqKWd.js.map +0 -1
  236. package/dist/goal-engine-KpBftn4V.js.map +0 -1
  237. package/dist/identity-gyfWdrcX.js +0 -2
  238. package/dist/import-hubspot-BaK71U_K.js.map +0 -1
  239. package/dist/interactions-writer-CrPStUll.cjs.map +0 -1
  240. package/dist/interactions-writer-DO3KcSR3.js.map +0 -1
  241. package/dist/interactions-writer-SLHnoEeE.js.map +0 -1
  242. package/dist/interactions-writer-dSPy1XfO.js +0 -2
  243. package/dist/knowledge-base-D0Fh40kc.js.map +0 -1
  244. package/dist/lancedb-rlvWoPwl.js.map +0 -1
  245. package/dist/lead-model-BCFzyktm.js.map +0 -1
  246. package/dist/memory-Bb6ky3kb.js.map +0 -1
  247. package/dist/notification-dispatcher-0vYNngWe.js.map +0 -1
  248. package/dist/pipeline-writer-BvVquKIe.js.map +0 -1
  249. package/dist/pipeline-writer-N2omexxp.cjs.map +0 -1
  250. package/dist/pipeline-writer-eufx_0o1.js.map +0 -1
  251. package/dist/proactive-worker-BrLHNhjH.js.map +0 -1
  252. package/dist/push-manager-CdqIIkuh.js.map +0 -1
  253. package/dist/quote-generator-BfwENXzg.js.map +0 -1
  254. package/dist/rbac-C7c8tcES.js +0 -2
  255. package/dist/rbac-CTIktZaC.js.map +0 -1
  256. package/dist/relationship-health-odxEoQdJ.js.map +0 -1
  257. package/dist/revenue-simulation-Bqf2DLVB.js.map +0 -1
  258. package/dist/segments-BqcD5HIl.js.map +0 -1
  259. package/dist/sequence-engine-CCTHEBgi.js +0 -2
  260. package/dist/sequence-engine-J1lTW_in.js.map +0 -1
  261. package/dist/sequence-store-DaaWr0Os.js.map +0 -1
  262. package/dist/server-Dyva03K8.js.map +0 -1
  263. package/dist/session-B9AilxOE.js.map +0 -1
  264. package/dist/session-D0qFkBla.cjs.map +0 -1
  265. package/dist/session-D9ub6Wl1.js.map +0 -1
  266. package/dist/session-mWHA71Lw.js +0 -2
  267. package/dist/session-store-B0QZE8Bx.cjs.map +0 -1
  268. package/dist/session-store-C8tEvMPw.js.map +0 -1
  269. package/dist/sop-Vp0UPWFW.js.map +0 -1
  270. package/dist/survey-engine-C06hcQt3.js +0 -2
  271. package/dist/survey-engine-DBjCYqCv.js.map +0 -1
  272. package/dist/sync-state-ChaLbamC.js.map +0 -1
  273. package/dist/ticket-writer-j2oX_Wal.js.map +0 -1
  274. package/dist/tone-Bdm5uaht.js.map +0 -1
  275. package/dist/tone-DRKlZgPr.cjs.map +0 -1
  276. package/dist/tone-vNb2DAAD.js.map +0 -1
  277. package/dist/transcript-watcher-CL2QUygI.js.map +0 -1
  278. package/dist/unmatched-transcripts-BsH5bhkU.js +0 -26
  279. package/dist/unmatched-transcripts-BsH5bhkU.js.map +0 -1
  280. package/dist/unmatched-transcripts-D0PrJ9iz.js +0 -2
  281. package/dist/update-deal-BNwPGaTV.js +0 -2
  282. package/dist/usage-D0-TYJkw.js.map +0 -1
  283. package/dist/vault-DXCg29W-.js.map +0 -1
  284. package/dist/webhooks-7EpA05Qr.js.map +0 -1
  285. package/dist/webhooks-BO2UAnmn.js.map +0 -1
  286. package/dist/webhooks-Xn6zO6kd.cjs.map +0 -1
package/dist/mcp.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { C as readMainFacts, S as listCustomerSlugs, a as enforceRbac, b as customerExists, c as filterAuditLog, d as writeAuditEntry, f as listBackupsInDir, i as canSeeCustomer, l as getActor, m as runBackup, n as getSession, p as readBackupLog, u as readAuditLog, w as writeMainFacts, x as ensureCustomerDir } from "./session-store-C8tEvMPw.js";
2
+ import { A as writeMainFacts, C as writeJsonArray, D as ensureCustomerDir, E as customerExists, M as isSafePathSegment, O as listCustomerSlugs, S as readJsonFile, T as assertSafeSlug, a as customerVisibility, d as readAuditLog, f as writeAuditEntry, h as runBackup, i as canSeeCustomer, j as assertSafePathSegment, k as readMainFacts, l as filterAuditLog, m as readBackupLog, n as getSession, o as enforceRbac, p as listBackupsInDir, u as getActor, w as writeJsonFile, x as readJsonArray } from "./session-store-DWxJ5Pof.js";
3
+ import { t as writeFileAtomic } from "./atomic-write-8yjqqLtS.js";
3
4
  import { t as withFileQueue } from "./write-queue-IbsAjUnh.js";
4
- import { n as formatInteractionEntry, t as appendInteraction } from "./interactions-writer-DO3KcSR3.js";
5
- import { n as readPipeline, r as upsertDeal } from "./pipeline-writer-eufx_0o1.js";
6
- import { i as guardIsoDate, t as callLlm } from "./llm-Z8RIYkpF.js";
5
+ import { n as formatInteractionEntry, t as appendInteraction } from "./interactions-writer-BZzUIgJd.js";
6
+ import { n as queryLogs, r as summarizeLogs, t as logger } from "./logger-UaF5p9d1.js";
7
+ import { i as upsertDeal, n as readPipeline, r as readPipelineSync } from "./pipeline-writer-rDj-ni6q.js";
8
+ import { i as guardIsoDate, t as callLlm } from "./llm-BnSUBisu.js";
7
9
  import path from "path";
8
10
  import fs from "fs";
9
11
  import matter from "gray-matter";
@@ -56,11 +58,10 @@ async function readSubscriptions(dataDir) {
56
58
  async function writeSubscriptions(dataDir, subs) {
57
59
  const filePath = subscriptionsPath(dataDir);
58
60
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
59
- const file = {
61
+ writeJsonFile(filePath, {
60
62
  subscriptions: subs,
61
63
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
62
- };
63
- fs.writeFileSync(filePath, JSON.stringify(file, null, 2), "utf-8");
64
+ });
64
65
  }
65
66
  function expiresAtForProvider(provider) {
66
67
  if (provider === "gmail") return new Date(Date.now() + 10080 * 60 * 1e3).toISOString();
@@ -91,23 +92,15 @@ function getSyncStatePath(dataDir) {
91
92
  return path.join(dataDir, ".agentic", "sync-state.json");
92
93
  }
93
94
  function readSyncState(dataDir) {
94
- const filePath = getSyncStatePath(dataDir);
95
- if (!fs.existsSync(filePath)) return {};
96
- try {
97
- return JSON.parse(fs.readFileSync(filePath, "utf-8"));
98
- } catch {
99
- return {};
100
- }
95
+ return readJsonFile(getSyncStatePath(dataDir), {});
101
96
  }
102
97
  function updateSlugSyncState(dataDir, slug, update) {
103
- const filePath = getSyncStatePath(dataDir);
104
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
105
98
  const state = readSyncState(dataDir);
106
99
  state[slug] = {
107
100
  ...state[slug],
108
101
  ...update
109
102
  };
110
- fs.writeFileSync(filePath, JSON.stringify(state, null, 2), "utf-8");
103
+ writeJsonFile(getSyncStatePath(dataDir), state);
111
104
  }
112
105
  function getLastGmailSync(dataDir, slug) {
113
106
  const ts = readSyncState(dataDir)[slug]?.lastGmailSync;
@@ -449,6 +442,7 @@ Config: \`.agentic/rbac.json\` | Actor: \`DXCRM_ACTOR\` env var
449
442
  | list_backups | List available backups with date, size, verification status, and customer count | any |
450
443
  | trigger_sync | Force immediate Gmail sync for one or all customers | rep+ |
451
444
  | get_audit_log | Read audit log — all write operations with actor, tool, customer | admin |
445
+ | get_logs | Query/aggregate the structured application log (level, component, errors) | admin |
452
446
  | define_custom_object | Define a runtime custom object type with typed fields (no migration) | admin |
453
447
  | create_record | Create a record of a custom object (validated against its schema) | rep+ |
454
448
  | list_records | List records of a custom object | any |
@@ -1323,6 +1317,16 @@ function registerGetActiveSession(server) {
1323
1317
  }, async () => handleGetActiveSession());
1324
1318
  }
1325
1319
  //#endregion
1320
+ //#region src/core/regex.ts
1321
+ /**
1322
+ * Escape a string so it can be embedded safely as a literal inside a `RegExp`.
1323
+ * Prevents both broken patterns and ReDoS/injection when interpolating
1324
+ * field names, section headers, or other dynamic values into a regex.
1325
+ */
1326
+ function escapeRegExp(value) {
1327
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1328
+ }
1329
+ //#endregion
1326
1330
  //#region src/core/context-builder.ts
1327
1331
  var context_builder_exports = /* @__PURE__ */ __exportAll({ buildContext: () => buildContext });
1328
1332
  const MAX_INTERACTIONS = 10;
@@ -1338,7 +1342,7 @@ function parsePipelineContent(filePath) {
1338
1342
  return fs.readFileSync(filePath, "utf-8").trim();
1339
1343
  }
1340
1344
  function extractSection(content, sectionName) {
1341
- const match = new RegExp(`## ${sectionName}([\\s\\S]*?)(?=^## |$)`, "m").exec(content);
1345
+ const match = new RegExp(`## ${escapeRegExp(sectionName)}([\\s\\S]*?)(?=^## |$)`, "m").exec(content);
1342
1346
  return match ? (match[1] ?? "").trim() : "";
1343
1347
  }
1344
1348
  async function buildContext(dataDir, slug) {
@@ -1415,7 +1419,7 @@ async function buildContext(dataDir, slug) {
1415
1419
  }
1416
1420
  //#endregion
1417
1421
  //#region src/mcp/tools/get-customer-context.ts
1418
- const DATA_DIR$51 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1422
+ const DATA_DIR$52 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1419
1423
  function triggerOnQuerySync(dataDir, slug) {
1420
1424
  const auth = getGmailAuth();
1421
1425
  if (!auth) return;
@@ -1428,7 +1432,7 @@ function triggerOnQuerySync(dataDir, slug) {
1428
1432
  const sources = JSON.parse(fs.readFileSync(sourcesPath, "utf-8"));
1429
1433
  if (!sources.gmail?.enabled || !sources.gmail.query) return;
1430
1434
  const query = sources.gmail.query;
1431
- import("./gmail-sync-rQaVqKWd.js").then(({ syncGmail }) => syncGmail({
1435
+ import("./gmail-sync-C-NmibzS.js").then(({ syncGmail }) => syncGmail({
1432
1436
  slug,
1433
1437
  dataDir,
1434
1438
  auth,
@@ -1436,7 +1440,7 @@ function triggerOnQuerySync(dataDir, slug) {
1436
1440
  }).then(() => updateSlugSyncState(dataDir, slug, { lastGmailSync: (/* @__PURE__ */ new Date()).toISOString() })).catch(() => {})).catch(() => {});
1437
1441
  } catch {}
1438
1442
  }
1439
- async function handleGetCustomerContext(input, dataDir = DATA_DIR$51) {
1443
+ async function handleGetCustomerContext(input, dataDir = DATA_DIR$52) {
1440
1444
  const targetSlug = input.slug ?? getSession()?.customerSlug;
1441
1445
  if (!targetSlug) return {
1442
1446
  content: [{
@@ -1552,7 +1556,7 @@ async function indexInLanceDB(dataDir, slug, text, sourceRef, meta) {
1552
1556
  }]);
1553
1557
  await table.mergeInsert("source_ref").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(data);
1554
1558
  } catch (err) {
1555
- process.stderr.write(`[lancedb] indexInLanceDB failed: ${err.message}\n`);
1559
+ logger.error("lancedb", "indexInLanceDB failed", { error: err.message });
1556
1560
  }
1557
1561
  }
1558
1562
  async function searchKnowledge(dataDir, slug, query, limit) {
@@ -1572,8 +1576,8 @@ async function searchKnowledge(dataDir, slug, query, limit) {
1572
1576
  }
1573
1577
  //#endregion
1574
1578
  //#region src/mcp/tools/search-customer-knowledge.ts
1575
- const DATA_DIR$50 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1576
- async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$50) {
1579
+ const DATA_DIR$51 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1580
+ async function handleSearchCustomerKnowledge(input, dataDir = DATA_DIR$51) {
1577
1581
  const limit = input.limit ?? 5;
1578
1582
  try {
1579
1583
  const results = await searchKnowledge(dataDir, input.slug, input.query, limit);
@@ -1621,14 +1625,14 @@ If no results: returns empty array with a helpful sync suggestion.`,
1621
1625
  }
1622
1626
  //#endregion
1623
1627
  //#region src/mcp/tools/list-customers.ts
1624
- const DATA_DIR$49 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1628
+ const DATA_DIR$50 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
1625
1629
  function extractLastInteractionDate(interactionsPath) {
1626
1630
  if (!fs.existsSync(interactionsPath)) return void 0;
1627
1631
  const content = fs.readFileSync(interactionsPath, "utf-8");
1628
1632
  const match = /^## (\d{4}-\d{2}-\d{2})/m.exec(content);
1629
1633
  return match ? match[1] : void 0;
1630
1634
  }
1631
- async function handleListCustomers(input, dataDir = DATA_DIR$49) {
1635
+ async function handleListCustomers(input, dataDir = DATA_DIR$50) {
1632
1636
  const customersDir = path.join(dataDir, "customers");
1633
1637
  const customers = [];
1634
1638
  if (!fs.existsSync(customersDir)) return { content: [{
@@ -1636,6 +1640,7 @@ async function handleListCustomers(input, dataDir = DATA_DIR$49) {
1636
1640
  text: JSON.stringify([], null, 2)
1637
1641
  }] };
1638
1642
  const entries = fs.readdirSync(customersDir);
1643
+ const canSee = customerVisibility(dataDir, process.env["DXCRM_ACTOR"] ?? "system");
1639
1644
  for (const entry of entries) {
1640
1645
  const customerDir = path.join(customersDir, entry);
1641
1646
  try {
@@ -1662,7 +1667,7 @@ async function handleListCustomers(input, dataDir = DATA_DIR$49) {
1662
1667
  const filterLower = input.filter.toLowerCase();
1663
1668
  if (!(name.toLowerCase().includes(filterLower) || entry.toLowerCase().includes(filterLower) || stage.toLowerCase().includes(filterLower))) continue;
1664
1669
  }
1665
- if (!canSeeCustomer(dataDir, process.env["DXCRM_ACTOR"] ?? "system", entry)) continue;
1670
+ if (!canSee(entry)) continue;
1666
1671
  customers.push(summary);
1667
1672
  } catch {
1668
1673
  continue;
@@ -1697,8 +1702,7 @@ async function withJsonFile(filePath, updater) {
1697
1702
  current = null;
1698
1703
  }
1699
1704
  const next = await updater(current);
1700
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
1701
- fs.writeFileSync(filePath, JSON.stringify(next, null, 2), "utf-8");
1705
+ writeFileAtomic(filePath, JSON.stringify(next, null, 2));
1702
1706
  return next;
1703
1707
  });
1704
1708
  }
@@ -1722,7 +1726,7 @@ function readGraph(dataDir, slug) {
1722
1726
  try {
1723
1727
  return JSON.parse(fs.readFileSync(p, "utf-8"));
1724
1728
  } catch {
1725
- process.stderr.write(`[graph] failed to parse ${p} — returning empty graph\n`);
1729
+ logger.warn("graph", "failed to parse graph file — returning empty graph", { path: p });
1726
1730
  return emptyGraph(slug);
1727
1731
  }
1728
1732
  }
@@ -1975,23 +1979,13 @@ function healthPath(dataDir, slug) {
1975
1979
  return path.join(dataDir, "customers", slug, "health.json");
1976
1980
  }
1977
1981
  function readHealth(dataDir, slug) {
1978
- const p = healthPath(dataDir, slug);
1979
- if (!fs.existsSync(p)) return null;
1980
- try {
1981
- return JSON.parse(fs.readFileSync(p, "utf-8"));
1982
- } catch {
1983
- return null;
1984
- }
1982
+ return readJsonFile(healthPath(dataDir, slug), null);
1985
1983
  }
1986
1984
  function writeHealth(dataDir, slug, health) {
1987
- const p = healthPath(dataDir, slug);
1988
- const dir = path.dirname(p);
1989
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
1990
- const updated = {
1985
+ writeJsonFile(healthPath(dataDir, slug), {
1991
1986
  ...health,
1992
1987
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1993
- };
1994
- fs.writeFileSync(p, JSON.stringify(updated, null, 2), "utf-8");
1988
+ });
1995
1989
  }
1996
1990
  function parseContactInteractions(content) {
1997
1991
  const blocks = content.split(/(?=^## \d{4}-\d{2}-\d{2})/m).filter((b) => b.trim().length > 0);
@@ -2151,8 +2145,8 @@ async function updateHealthFromInteraction(dataDir, slug) {
2151
2145
  }
2152
2146
  //#endregion
2153
2147
  //#region src/mcp/tools/log-interaction.ts
2154
- const DATA_DIR$48 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2155
- async function handleLogInteraction(input, dataDir = DATA_DIR$48) {
2148
+ const DATA_DIR$49 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2149
+ async function handleLogInteraction(input, dataDir = DATA_DIR$49) {
2156
2150
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
2157
2151
  const interactionDate = input.date ?? today;
2158
2152
  const sourceRef = input.source ?? `agent://log/${Date.now()}`;
@@ -2182,7 +2176,7 @@ async function handleLogInteraction(input, dataDir = DATA_DIR$48) {
2182
2176
  raw.data.last_touchpoint = interactionDate;
2183
2177
  let serialized = matter.stringify(raw.content, raw.data);
2184
2178
  serialized = serialized.replace(/^(last_touchpoint:\s*)['"](\d{4}-\d{2}-\d{2})['"]/m, "$1$2");
2185
- fs.writeFileSync(mainFactsPath, serialized, "utf-8");
2179
+ writeFileAtomic(mainFactsPath, serialized);
2186
2180
  } catch {}
2187
2181
  writeAuditEntry(dataDir, {
2188
2182
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -2261,8 +2255,8 @@ var update_deal_exports = /* @__PURE__ */ __exportAll({
2261
2255
  handleUpdateDeal: () => handleUpdateDeal,
2262
2256
  registerUpdateDeal: () => registerUpdateDeal
2263
2257
  });
2264
- const DATA_DIR$47 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2265
- async function handleUpdateDeal(input, dataDir = DATA_DIR$47) {
2258
+ const DATA_DIR$48 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2259
+ async function handleUpdateDeal(input, dataDir = DATA_DIR$48) {
2266
2260
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
2267
2261
  const deal = {
2268
2262
  name: input.dealName,
@@ -2345,12 +2339,12 @@ Returns: { success: boolean, deal: object }`,
2345
2339
  }
2346
2340
  //#endregion
2347
2341
  //#region src/mcp/tools/export-customer.ts
2348
- const DATA_DIR$46 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2342
+ const DATA_DIR$47 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2349
2343
  function countInteractions(content) {
2350
2344
  const matches = content.match(/^## \d{4}-\d{2}-\d{2}/gm);
2351
2345
  return matches ? matches.length : 0;
2352
2346
  }
2353
- async function handleExportCustomer(input, dataDir = DATA_DIR$46) {
2347
+ async function handleExportCustomer(input, dataDir = DATA_DIR$47) {
2354
2348
  enforceRbac(dataDir, "export_customer");
2355
2349
  const customerDir = path.join(dataDir, "customers", input.slug);
2356
2350
  if (!fs.existsSync(customerDir)) return {
@@ -2443,8 +2437,8 @@ Returns:
2443
2437
  }
2444
2438
  //#endregion
2445
2439
  //#region src/mcp/tools/update-customer-facts.ts
2446
- const DATA_DIR$45 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2447
- async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$45) {
2440
+ const DATA_DIR$46 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2441
+ async function handleUpdateCustomerFacts(input, dataDir = DATA_DIR$46) {
2448
2442
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2449
2443
  try {
2450
2444
  enforceRbac(dataDir, "update_customer_facts");
@@ -2594,10 +2588,36 @@ function scoreDeal(deal, signals) {
2594
2588
  warnings
2595
2589
  };
2596
2590
  }
2591
+ const MS_PER_DAY = 864e5;
2592
+ /**
2593
+ * Derive activity/close timing for a deal relative to `todayDate`. Centralizes
2594
+ * the day-diff math that deal-room and deal-agent each computed identically.
2595
+ * A blank/whitespace close_date yields `undefined` (not a NaN day count).
2596
+ */
2597
+ function deriveDealTiming(deal, todayDate) {
2598
+ const updatedDate = deal.updated ? new Date(deal.updated) : todayDate;
2599
+ const daysSinceLastActivity = Math.floor((todayDate.getTime() - updatedDate.getTime()) / MS_PER_DAY);
2600
+ const timing = {
2601
+ daysSinceLastActivity,
2602
+ daysInCurrentStage: daysSinceLastActivity
2603
+ };
2604
+ if (deal.close_date && deal.close_date.trim() !== "") timing.daysToClose = Math.floor((new Date(deal.close_date).getTime() - todayDate.getTime()) / MS_PER_DAY);
2605
+ return timing;
2606
+ }
2607
+ /** Score a deal using timing derived from `todayDate` plus the deal's probability. */
2608
+ function scoreDealForToday(deal, todayDate) {
2609
+ const timing = deriveDealTiming(deal, todayDate);
2610
+ return scoreDeal(deal, {
2611
+ daysSinceLastActivity: timing.daysSinceLastActivity,
2612
+ daysInCurrentStage: timing.daysInCurrentStage,
2613
+ ...timing.daysToClose !== void 0 ? { daysToClose: timing.daysToClose } : {},
2614
+ ...deal.probability !== void 0 ? { probability: deal.probability } : {}
2615
+ });
2616
+ }
2597
2617
  //#endregion
2598
2618
  //#region src/mcp/tools/get-deal-health.ts
2599
- const DATA_DIR$44 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2600
- async function handleGetDealHealth(input, dataDir = DATA_DIR$44) {
2619
+ const DATA_DIR$45 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2620
+ async function handleGetDealHealth(input, dataDir = DATA_DIR$45) {
2601
2621
  try {
2602
2622
  const deals = await readPipeline(dataDir, input.slug);
2603
2623
  const today = /* @__PURE__ */ new Date();
@@ -2646,28 +2666,13 @@ Returns: { slug, deals: [{ deal, stage, score, grade, signals, warnings }] }`,
2646
2666
  }
2647
2667
  //#endregion
2648
2668
  //#region src/mcp/tools/get-pipeline-forecast.ts
2649
- const DATA_DIR$43 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2650
- async function handleGetPipelineForecast(input, dataDir = DATA_DIR$43) {
2669
+ const DATA_DIR$44 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2670
+ async function handleGetPipelineForecast(input, dataDir = DATA_DIR$44) {
2651
2671
  try {
2652
- const customersDir = path.join(dataDir, "customers");
2653
- if (!fs.existsSync(customersDir)) return { content: [{
2654
- type: "text",
2655
- text: JSON.stringify({
2656
- deals: [],
2657
- totalWeightedValue: 0,
2658
- byStage: {}
2659
- }, null, 2)
2660
- }] };
2661
- const slugs = fs.readdirSync(customersDir).filter((d) => {
2662
- if (input.filter && !d.includes(input.filter)) return false;
2663
- return fs.statSync(path.join(customersDir, d)).isDirectory();
2664
- });
2672
+ const slugs = listCustomerSlugs(dataDir).filter((d) => !input.filter || d.includes(input.filter));
2665
2673
  const allDeals = [];
2666
2674
  for (const slug of slugs) {
2667
- const pipelinePath = path.join(customersDir, slug, "pipeline.md");
2668
- if (!fs.existsSync(pipelinePath)) continue;
2669
- const { readPipeline } = await import("./pipeline-writer-eufx_0o1.js").then((n) => n.t);
2670
- const deals = await readPipeline(dataDir, slug).catch(() => []);
2675
+ const deals = readPipelineSync(dataDir, slug);
2671
2676
  for (const deal of deals) {
2672
2677
  if (deal.stage === "won" || deal.stage === "lost") continue;
2673
2678
  const prob = deal.probability ?? 50;
@@ -2723,13 +2728,13 @@ Returns: { deals: [...], totalWeightedValue: number, byStage: { stage: { count,
2723
2728
  }
2724
2729
  //#endregion
2725
2730
  //#region src/mcp/tools/summarize-meeting.ts
2726
- const DATA_DIR$42 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2727
- async function handleSummarizeMeeting(input, dataDir = DATA_DIR$42) {
2731
+ const DATA_DIR$43 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2732
+ async function handleSummarizeMeeting(input, dataDir = DATA_DIR$43) {
2728
2733
  try {
2729
2734
  let summary = input.transcript.slice(0, 400);
2730
2735
  let nextSteps = [];
2731
2736
  try {
2732
- const { callLlm } = await import("./llm-Z8RIYkpF.js").then((n) => n.n);
2737
+ const { callLlm } = await import("./llm-BnSUBisu.js").then((n) => n.n);
2733
2738
  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": ["..."] }`);
2734
2739
  const parsed = JSON.parse(response);
2735
2740
  summary = parsed.summary ?? summary;
@@ -2843,18 +2848,12 @@ function stagesPath(dataDir) {
2843
2848
  return path.join(dataDir, ".agentic", "pipeline-stages.json");
2844
2849
  }
2845
2850
  function getPipelineStages(dataDir) {
2846
- const p = stagesPath(dataDir);
2847
- if (!fs.existsSync(p)) return DEFAULT_STAGES;
2848
- try {
2849
- return JSON.parse(fs.readFileSync(p, "utf-8"));
2850
- } catch {
2851
- return DEFAULT_STAGES;
2852
- }
2851
+ return readJsonFile(stagesPath(dataDir), DEFAULT_STAGES);
2853
2852
  }
2854
2853
  //#endregion
2855
2854
  //#region src/mcp/tools/get-pipeline-stages.ts
2856
- const DATA_DIR$41 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2857
- async function handleGetPipelineStages(_input, dataDir = DATA_DIR$41) {
2855
+ const DATA_DIR$42 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2856
+ async function handleGetPipelineStages(_input, dataDir = DATA_DIR$42) {
2858
2857
  const stages = getPipelineStages(dataDir);
2859
2858
  return { content: [{
2860
2859
  type: "text",
@@ -2872,21 +2871,18 @@ function registerGetPipelineStages(server) {
2872
2871
  //#region src/core/cross-customer.ts
2873
2872
  async function searchAcrossCustomers(dataDir, query, limit = 5, excludeSlug) {
2874
2873
  const slugs = listCustomerSlugs(dataDir).filter((d) => d !== excludeSlug);
2875
- const allResults = [];
2876
- for (const slug of slugs) {
2877
- const results = await searchKnowledge(dataDir, slug, query, 2);
2878
- for (const r of results) allResults.push({
2874
+ return (await Promise.all(slugs.map(async (slug) => {
2875
+ return (await searchKnowledge(dataDir, slug, query, 2)).map((r) => ({
2879
2876
  slug,
2880
2877
  relevantContent: r.content.slice(0, 200),
2881
2878
  score: r.score
2882
- });
2883
- }
2884
- return allResults.sort((a, b) => b.score - a.score).slice(0, limit);
2879
+ }));
2880
+ }))).flat().sort((a, b) => b.score - a.score).slice(0, limit);
2885
2881
  }
2886
2882
  //#endregion
2887
2883
  //#region src/mcp/tools/get-market-intelligence.ts
2888
- const DATA_DIR$40 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2889
- async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$40) {
2884
+ const DATA_DIR$41 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2885
+ async function handleGetMarketIntelligence(input, dataDir = DATA_DIR$41) {
2890
2886
  const excludeSlug = input.excludeCurrentCustomer ? input.slug : void 0;
2891
2887
  const all = listCustomerSlugs(dataDir);
2892
2888
  const totalCustomersSearched = excludeSlug ? all.filter((s) => s !== excludeSlug).length : all.length;
@@ -2917,7 +2913,7 @@ function registerGetMarketIntelligence(server) {
2917
2913
  }
2918
2914
  //#endregion
2919
2915
  //#region src/mcp/tools/get-relationship-graph.ts
2920
- const DATA_DIR$39 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2916
+ const DATA_DIR$40 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2921
2917
  function summarizeNode(n) {
2922
2918
  return {
2923
2919
  id: n.id,
@@ -2925,7 +2921,7 @@ function summarizeNode(n) {
2925
2921
  email: n.properties["email"]
2926
2922
  };
2927
2923
  }
2928
- async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$39) {
2924
+ async function handleGetRelationshipGraph(input, dataDir = DATA_DIR$40) {
2929
2925
  try {
2930
2926
  const graph = readGraph(dataDir, input.slug);
2931
2927
  const stakeholders = getStakeholders(graph);
@@ -2993,9 +2989,9 @@ Returns: {
2993
2989
  }
2994
2990
  //#endregion
2995
2991
  //#region src/mcp/tools/get-relationship-health.ts
2996
- const DATA_DIR$38 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2992
+ const DATA_DIR$39 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
2997
2993
  const MAX_HEALTH_AGE_MS = 3600 * 1e3;
2998
- async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$38) {
2994
+ async function handleGetRelationshipHealth(input, dataDir = DATA_DIR$39) {
2999
2995
  try {
3000
2996
  let health = readHealth(dataDir, input.slug);
3001
2997
  if (health === null || Date.now() - new Date(health.updatedAt).getTime() > MAX_HEALTH_AGE_MS) {
@@ -3075,8 +3071,7 @@ async function writePlaybook(dataDir, slug, playbook) {
3075
3071
  const filePath = path.join(dir, `${playbook.name}.md`);
3076
3072
  await withFileQueue(filePath, async () => {
3077
3073
  fs.mkdirSync(dir, { recursive: true });
3078
- const raw = matter.stringify(playbook.content, playbook.frontmatter);
3079
- fs.writeFileSync(filePath, raw, "utf-8");
3074
+ writeFileAtomic(filePath, matter.stringify(playbook.content, playbook.frontmatter));
3080
3075
  });
3081
3076
  }
3082
3077
  function toKebabCase(name) {
@@ -3278,11 +3273,10 @@ function writeAgentQueue(dataDir, slug, queue) {
3278
3273
  const p = agentQueuePath(dataDir, slug);
3279
3274
  const dir = path.dirname(p);
3280
3275
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
3281
- const updated = {
3276
+ writeJsonFile(p, {
3282
3277
  ...queue,
3283
3278
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3284
- };
3285
- fs.writeFileSync(p, JSON.stringify(updated, null, 2), "utf-8");
3279
+ });
3286
3280
  }
3287
3281
  function makeActionId() {
3288
3282
  return `da_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
@@ -3317,17 +3311,9 @@ async function observeDeal(dataDir, slug, dealName, today) {
3317
3311
  const deal = (await readPipeline(dataDir, slug).catch(() => [])).find((d) => d.name.toLowerCase() === dealName.toLowerCase());
3318
3312
  if (!deal) return null;
3319
3313
  const todayDate = new Date(today);
3320
- const updatedDate = deal.updated ? new Date(deal.updated) : todayDate;
3321
- const daysSinceLastActivity = Math.floor((todayDate.getTime() - updatedDate.getTime()) / 864e5);
3322
- const daysInCurrentStage = daysSinceLastActivity;
3323
- const daysToClose = deal.close_date && deal.close_date.trim() !== "" ? Math.floor((new Date(deal.close_date).getTime() - todayDate.getTime()) / 864e5) : void 0;
3324
- const dealHealthScore = scoreDeal(deal, {
3325
- daysSinceLastActivity,
3326
- daysInCurrentStage,
3327
- ...daysToClose !== void 0 ? { daysToClose } : {},
3328
- ...deal.probability !== void 0 ? { probability: deal.probability } : {}
3329
- });
3330
- const health = computeCustomerHealth(dataDir, slug, today);
3314
+ const { daysSinceLastActivity, daysInCurrentStage, daysToClose } = deriveDealTiming(deal, todayDate);
3315
+ const dealHealthScore = scoreDealForToday(deal, todayDate);
3316
+ const health = readHealth(dataDir, slug) ?? computeCustomerHealth(dataDir, slug, today);
3331
3317
  const atRiskContacts = health.contacts.filter((c) => c.riskFlags.length > 0).map((c) => c.email ?? c.contactId);
3332
3318
  const coldContacts = health.contacts.filter((c) => c.trend === "cold").map((c) => c.email ?? c.contactId);
3333
3319
  const stakeholders = getStakeholders(readGraph(dataDir, slug));
@@ -3555,7 +3541,7 @@ async function executeAction(action, dataDir) {
3555
3541
  if (!slug) return "skipped";
3556
3542
  switch (action.type) {
3557
3543
  case "log_interaction": {
3558
- const { appendInteraction } = await import("./interactions-writer-DO3KcSR3.js").then((n) => n.r);
3544
+ const { appendInteraction } = await import("./interactions-writer-BZzUIgJd.js").then((n) => n.r);
3559
3545
  await appendInteraction(dataDir, slug, {
3560
3546
  date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
3561
3547
  type: action.payload["type"] ?? "Note",
@@ -3568,7 +3554,7 @@ async function executeAction(action, dataDir) {
3568
3554
  return "executed";
3569
3555
  }
3570
3556
  case "schedule_meeting": {
3571
- const { appendInteraction } = await import("./interactions-writer-DO3KcSR3.js").then((n) => n.r);
3557
+ const { appendInteraction } = await import("./interactions-writer-BZzUIgJd.js").then((n) => n.r);
3572
3558
  await appendInteraction(dataDir, slug, {
3573
3559
  date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
3574
3560
  type: "Note",
@@ -3674,8 +3660,8 @@ async function runDealAgent(config, dataDir, llmFn = callLlm) {
3674
3660
  }
3675
3661
  //#endregion
3676
3662
  //#region src/mcp/tools/run-deal-agent.ts
3677
- const DATA_DIR$37 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3678
- async function handleRunDealAgent(input, dataDir = DATA_DIR$37) {
3663
+ const DATA_DIR$38 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3664
+ async function handleRunDealAgent(input, dataDir = DATA_DIR$38) {
3679
3665
  try {
3680
3666
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
3681
3667
  const result = await runDealAgent({
@@ -3742,8 +3728,8 @@ Returns: { assessment, riskLevel, plan[], actionsQueued[], actionsExecuted[], tr
3742
3728
  }
3743
3729
  //#endregion
3744
3730
  //#region src/mcp/tools/approve-agent-action.ts
3745
- const DATA_DIR$36 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3746
- async function handleApproveAgentAction(input, dataDir = DATA_DIR$36) {
3731
+ const DATA_DIR$37 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3732
+ async function handleApproveAgentAction(input, dataDir = DATA_DIR$37) {
3747
3733
  try {
3748
3734
  const queue = readAgentQueue(dataDir, input.slug);
3749
3735
  const idx = queue.pendingActions.findIndex((a) => a.actionId === input.actionId);
@@ -4003,8 +3989,8 @@ async function buildSimulationInput(dataDir, horizon, today, externalSignals = [
4003
3989
  }
4004
3990
  //#endregion
4005
3991
  //#region src/mcp/tools/simulate-revenue.ts
4006
- const DATA_DIR$35 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4007
- async function handleSimulateRevenue(input, dataDir = DATA_DIR$35) {
3992
+ const DATA_DIR$36 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
3993
+ async function handleSimulateRevenue(input, dataDir = DATA_DIR$36) {
4008
3994
  try {
4009
3995
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4010
3996
  const horizon = input.horizon ?? "quarter";
@@ -4062,8 +4048,8 @@ Returns: { forecast: { p10, p50, p90, expected, stdDev, atRiskRevenue, byCloseMo
4062
4048
  }
4063
4049
  //#endregion
4064
4050
  //#region src/mcp/tools/get-playbook.ts
4065
- const DATA_DIR$34 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4066
- async function handleGetPlaybook(input, dataDir = DATA_DIR$34) {
4051
+ const DATA_DIR$35 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4052
+ async function handleGetPlaybook(input, dataDir = DATA_DIR$35) {
4067
4053
  try {
4068
4054
  const playbooks = listPlaybooks(dataDir, input.slug);
4069
4055
  if (!(input.stage !== void 0 || input.value !== void 0 || input.healthScore !== void 0)) return { content: [{
@@ -4148,12 +4134,12 @@ Returns: { matches: [{ name, score, trigger, successRate, usedCount, content }],
4148
4134
  ...healthScore !== void 0 ? { healthScore } : {},
4149
4135
  ...daysSinceContact !== void 0 ? { daysSinceContact } : {},
4150
4136
  ...championPresent !== void 0 ? { championPresent } : {}
4151
- }, DATA_DIR$34));
4137
+ }, DATA_DIR$35));
4152
4138
  }
4153
4139
  //#endregion
4154
4140
  //#region src/mcp/tools/create-playbook.ts
4155
- const DATA_DIR$33 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4156
- async function handleCreatePlaybook(input, dataDir = DATA_DIR$33) {
4141
+ const DATA_DIR$34 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4142
+ async function handleCreatePlaybook(input, dataDir = DATA_DIR$34) {
4157
4143
  try {
4158
4144
  const name = toKebabCase(input.name);
4159
4145
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -4226,12 +4212,12 @@ Returns: { success: true, playbook: { name, trigger, successRate, path } }`,
4226
4212
  trigger,
4227
4213
  content,
4228
4214
  ...successRate !== void 0 ? { successRate } : {}
4229
- }, DATA_DIR$33));
4215
+ }, DATA_DIR$34));
4230
4216
  }
4231
4217
  //#endregion
4232
4218
  //#region src/mcp/tools/list-playbooks.ts
4233
- const DATA_DIR$32 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4234
- async function handleListPlaybooks(input, dataDir = DATA_DIR$32) {
4219
+ const DATA_DIR$33 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4220
+ async function handleListPlaybooks(input, dataDir = DATA_DIR$33) {
4235
4221
  try {
4236
4222
  const playbooks = listPlaybooks(dataDir, input.slug);
4237
4223
  return { content: [{
@@ -4270,12 +4256,12 @@ Args:
4270
4256
 
4271
4257
  Returns: { playbooks: [{ name, trigger, successRate, usedCount, lastUpdated }], count, slug }`,
4272
4258
  inputSchema: z.object({ slug: z.string().describe("Customer ID") })
4273
- }, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$32));
4259
+ }, async ({ slug }) => handleListPlaybooks({ slug }, DATA_DIR$33));
4274
4260
  }
4275
4261
  //#endregion
4276
4262
  //#region src/mcp/tools/distill-playbook.ts
4277
- const DATA_DIR$31 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4278
- async function handleDistillPlaybook(input, dataDir = DATA_DIR$31, llmFn = callLlm) {
4263
+ const DATA_DIR$32 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4264
+ async function handleDistillPlaybook(input, dataDir = DATA_DIR$32, llmFn = callLlm) {
4279
4265
  try {
4280
4266
  const result = await distillPlaybook(dataDir, input.slug, input.dealName, input.outcome, llmFn);
4281
4267
  if (!result.ok) {
@@ -4334,7 +4320,7 @@ Returns: { success: true, playbook: { name, trigger, successRate, path }, reason
4334
4320
  slug,
4335
4321
  dealName,
4336
4322
  outcome
4337
- }, DATA_DIR$31));
4323
+ }, DATA_DIR$32));
4338
4324
  }
4339
4325
  //#endregion
4340
4326
  //#region src/core/goal-engine.ts
@@ -4552,8 +4538,8 @@ function getActiveGoals(dataDir) {
4552
4538
  }
4553
4539
  //#endregion
4554
4540
  //#region src/mcp/tools/pursue-goal.ts
4555
- const DATA_DIR$30 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4556
- async function handlePursueGoal(input, dataDir = DATA_DIR$30, options = {}) {
4541
+ const DATA_DIR$31 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4542
+ async function handlePursueGoal(input, dataDir = DATA_DIR$31, options = {}) {
4557
4543
  try {
4558
4544
  enforceRbac(dataDir, "pursue_goal");
4559
4545
  const goal = await pursueGoal(dataDir, {
@@ -4616,12 +4602,12 @@ Returns: { goalId, description, target, deadline, decomposition: { analysis, cur
4616
4602
  goal,
4617
4603
  deadline,
4618
4604
  ...context !== void 0 ? { context } : {}
4619
- }, DATA_DIR$30));
4605
+ }, DATA_DIR$31));
4620
4606
  }
4621
4607
  //#endregion
4622
4608
  //#region src/mcp/tools/get-goal-status.ts
4623
- const DATA_DIR$29 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4624
- async function handleGetGoalStatus(input, dataDir = DATA_DIR$29) {
4609
+ const DATA_DIR$30 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4610
+ async function handleGetGoalStatus(input, dataDir = DATA_DIR$30) {
4625
4611
  try {
4626
4612
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4627
4613
  const allGoals = input.goalId ? readGoals(dataDir).filter((g) => g.id === input.goalId) : getActiveGoals(dataDir);
@@ -4680,17 +4666,17 @@ Args:
4680
4666
 
4681
4667
  Returns: { goals: [{ id, description, target, progress, status, deadline, daysRemaining, subGoals }], activeCount, completedCount }`,
4682
4668
  inputSchema: z.object({ goalId: z.string().optional().describe("Specific goal ID (omit for all active goals)") })
4683
- }, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$29));
4669
+ }, async ({ goalId }) => handleGetGoalStatus({ ...goalId !== void 0 ? { goalId } : {} }, DATA_DIR$30));
4684
4670
  }
4685
4671
  //#endregion
4686
4672
  //#region src/mcp/tools/register-push-subscription.ts
4687
- const DATA_DIR$28 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4673
+ const DATA_DIR$29 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4688
4674
  const VALID_PROVIDERS = [
4689
4675
  "gmail",
4690
4676
  "microsoft-graph",
4691
4677
  "slack"
4692
4678
  ];
4693
- async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$28) {
4679
+ async function handleRegisterPushSubscription(input, dataDir = DATA_DIR$29) {
4694
4680
  try {
4695
4681
  if (!VALID_PROVIDERS.includes(input.provider)) return { content: [{
4696
4682
  type: "text",
@@ -4776,12 +4762,12 @@ Returns: { subscriptionId, provider, slug, status, expiresAt, createdAt, warning
4776
4762
  ...microsoftResource !== void 0 ? { microsoftResource } : {},
4777
4763
  ...slackTeamId !== void 0 ? { slackTeamId } : {},
4778
4764
  ...slackChannelId !== void 0 ? { slackChannelId } : {}
4779
- }, DATA_DIR$28));
4765
+ }, DATA_DIR$29));
4780
4766
  }
4781
4767
  //#endregion
4782
4768
  //#region src/mcp/tools/get-push-status.ts
4783
- const DATA_DIR$27 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4784
- async function handleGetPushStatus(input, dataDir = DATA_DIR$27) {
4769
+ const DATA_DIR$28 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4770
+ async function handleGetPushStatus(input, dataDir = DATA_DIR$28) {
4785
4771
  try {
4786
4772
  let subs = await readSubscriptions(dataDir);
4787
4773
  if (input.slug) subs = subs.filter((s) => s.slug === input.slug);
@@ -4853,7 +4839,7 @@ Returns: { subscriptions: [{ id, provider, slug, status, expiresAt, expiresInHou
4853
4839
  }, async ({ slug, provider }) => handleGetPushStatus({
4854
4840
  ...slug !== void 0 ? { slug } : {},
4855
4841
  ...provider !== void 0 ? { provider } : {}
4856
- }, DATA_DIR$27));
4842
+ }, DATA_DIR$28));
4857
4843
  }
4858
4844
  //#endregion
4859
4845
  //#region src/core/org-intelligence.ts
@@ -4919,8 +4905,8 @@ function deriveRecommendation(people, missingRoles) {
4919
4905
  }
4920
4906
  //#endregion
4921
4907
  //#region src/mcp/tools/get-org-intelligence.ts
4922
- const DATA_DIR$26 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4923
- async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$26) {
4908
+ const DATA_DIR$27 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
4909
+ async function handleGetOrgIntelligence(input, dataDir = DATA_DIR$27) {
4924
4910
  try {
4925
4911
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4926
4912
  const map = buildStakeholderMap(dataDir, input.slug, today, input.dealName);
@@ -4971,15 +4957,7 @@ async function buildDealRoom(dataDir, slug, dealName, today) {
4971
4957
  });
4972
4958
  const todayDate = new Date(today);
4973
4959
  const dealHealth = pipelineDeals.filter((d) => d.stage !== "won" && d.stage !== "lost").map((deal) => {
4974
- const updatedDate = deal.updated ? new Date(deal.updated) : todayDate;
4975
- const daysSinceLastActivity = Math.floor((todayDate.getTime() - updatedDate.getTime()) / 864e5);
4976
- const daysToClose = deal.close_date ? Math.floor((new Date(deal.close_date).getTime() - todayDate.getTime()) / 864e5) : void 0;
4977
- const scored = scoreDeal(deal, {
4978
- daysSinceLastActivity,
4979
- daysInCurrentStage: daysSinceLastActivity,
4980
- ...daysToClose !== void 0 ? { daysToClose } : {},
4981
- ...deal.probability !== void 0 ? { probability: deal.probability } : {}
4982
- });
4960
+ const scored = scoreDealForToday(deal, todayDate);
4983
4961
  return {
4984
4962
  deal: deal.name,
4985
4963
  stage: deal.stage,
@@ -5061,8 +5039,8 @@ function buildExecutiveSummary(slug, dealName, stakeholders, overallHealth, sim,
5061
5039
  }
5062
5040
  //#endregion
5063
5041
  //#region src/mcp/tools/open-deal-room.ts
5064
- const DATA_DIR$25 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5065
- async function handleOpenDealRoom(input, dataDir = DATA_DIR$25) {
5042
+ const DATA_DIR$26 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5043
+ async function handleOpenDealRoom(input, dataDir = DATA_DIR$26) {
5066
5044
  try {
5067
5045
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
5068
5046
  const brief = await buildDealRoom(dataDir, input.slug, input.dealName, today);
@@ -5145,8 +5123,8 @@ async function buildDailyBriefing(dataDir, today) {
5145
5123
  }
5146
5124
  //#endregion
5147
5125
  //#region src/mcp/tools/get-proactive-briefing.ts
5148
- const DATA_DIR$24 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5149
- async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$24) {
5126
+ const DATA_DIR$25 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5127
+ async function handleGetProactiveBriefing(input, dataDir = DATA_DIR$25) {
5150
5128
  try {
5151
5129
  const briefing = await buildDailyBriefing(dataDir, input.date ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
5152
5130
  return { content: [{
@@ -5246,15 +5224,15 @@ function getTemplate(dataDir, id) {
5246
5224
  }
5247
5225
  //#endregion
5248
5226
  //#region src/mcp/tools/list-email-templates.ts
5249
- const DATA_DIR$23 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5250
- async function handleListEmailTemplates(input, dataDir = DATA_DIR$23) {
5227
+ const DATA_DIR$24 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5228
+ async function handleListEmailTemplates(input, dataDir = DATA_DIR$24) {
5251
5229
  const summary = listTemplates(dataDir, input.category ? { category: input.category } : {}).map(({ body: _body, ...meta }) => meta);
5252
5230
  return { content: [{
5253
5231
  type: "text",
5254
5232
  text: JSON.stringify(summary, null, 2)
5255
5233
  }] };
5256
5234
  }
5257
- function registerListEmailTemplates(server, dataDir = DATA_DIR$23) {
5235
+ function registerListEmailTemplates(server, dataDir = DATA_DIR$24) {
5258
5236
  server.registerTool("list_email_templates", {
5259
5237
  description: "List available email templates. Optionally filter by category (e.g. 'outreach', 'followup', 'support').",
5260
5238
  inputSchema: z.object({ category: z.string().optional().describe("Filter by category") })
@@ -5288,8 +5266,8 @@ async function buildVariablesFromCustomer(dataDir, slug) {
5288
5266
  }
5289
5267
  //#endregion
5290
5268
  //#region src/mcp/tools/get-email-template.ts
5291
- const DATA_DIR$22 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5292
- async function handleGetEmailTemplate(input, dataDir = DATA_DIR$22) {
5269
+ const DATA_DIR$23 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5270
+ async function handleGetEmailTemplate(input, dataDir = DATA_DIR$23) {
5293
5271
  const tmpl = getTemplate(dataDir, input.id);
5294
5272
  if (!tmpl) return { content: [{
5295
5273
  type: "text",
@@ -5305,7 +5283,7 @@ async function handleGetEmailTemplate(input, dataDir = DATA_DIR$22) {
5305
5283
  }, null, 2)
5306
5284
  }] };
5307
5285
  }
5308
- function registerGetEmailTemplate(server, dataDir = DATA_DIR$22) {
5286
+ function registerGetEmailTemplate(server, dataDir = DATA_DIR$23) {
5309
5287
  server.registerTool("get_email_template", {
5310
5288
  description: "Get a specific email template by ID, including its body and detected variables.",
5311
5289
  inputSchema: z.object({ id: z.string().describe("Template ID (e.g. 'enterprise-intro')") })
@@ -5313,8 +5291,8 @@ function registerGetEmailTemplate(server, dataDir = DATA_DIR$22) {
5313
5291
  }
5314
5292
  //#endregion
5315
5293
  //#region src/mcp/tools/draft-email.ts
5316
- const DATA_DIR$21 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5317
- async function handleDraftEmail(input, dataDir = DATA_DIR$21) {
5294
+ const DATA_DIR$22 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5295
+ async function handleDraftEmail(input, dataDir = DATA_DIR$22) {
5318
5296
  const tmpl = getTemplate(dataDir, input.templateId);
5319
5297
  if (!tmpl) return { content: [{
5320
5298
  type: "text",
@@ -5328,17 +5306,17 @@ async function handleDraftEmail(input, dataDir = DATA_DIR$21) {
5328
5306
  const interpolatedBody = interpolate(tmpl.body, vars);
5329
5307
  let effectiveTone = input.tone;
5330
5308
  if (!effectiveTone) {
5331
- const { resolveTone, toneInstruction } = await import("./tone-vNb2DAAD.js");
5309
+ const { resolveTone, toneInstruction } = await import("./tone-mXSftvTn.js");
5332
5310
  const instr = toneInstruction(resolveTone(dataDir, input.slug));
5333
5311
  if (instr) effectiveTone = instr;
5334
5312
  }
5335
5313
  let body = interpolatedBody;
5336
5314
  let polished = false;
5337
5315
  if (effectiveTone) try {
5338
- const { callLlm } = await import("./llm-Z8RIYkpF.js").then((n) => n.n);
5316
+ const { callLlm } = await import("./llm-BnSUBisu.js").then((n) => n.n);
5339
5317
  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}`);
5340
5318
  if (refined && refined.trim()) {
5341
- const { labelAiContent } = await import("./compliance-B1kk5-YS.js").then((n) => n.t);
5319
+ const { labelAiContent } = await import("./compliance-kq0xHRw3.js").then((n) => n.t);
5342
5320
  body = labelAiContent(refined.trim());
5343
5321
  polished = true;
5344
5322
  }
@@ -5358,7 +5336,7 @@ async function handleDraftEmail(input, dataDir = DATA_DIR$21) {
5358
5336
  }, null, 2)
5359
5337
  }] };
5360
5338
  }
5361
- function registerDraftEmail(server, dataDir = DATA_DIR$21) {
5339
+ function registerDraftEmail(server, dataDir = DATA_DIR$22) {
5362
5340
  server.registerTool("draft_email", {
5363
5341
  description: `Draft a personalized email for a customer using a stored template.
5364
5342
  Variables are auto-filled from the customer's main_facts.md. Override any variable manually.
@@ -5466,8 +5444,8 @@ async function updateEnrollment(dataDir, id, updates) {
5466
5444
  }
5467
5445
  //#endregion
5468
5446
  //#region src/mcp/tools/enroll-in-sequence.ts
5469
- const DATA_DIR$20 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5470
- async function handleEnrollInSequence(input, dataDir = DATA_DIR$20) {
5447
+ const DATA_DIR$21 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5448
+ async function handleEnrollInSequence(input, dataDir = DATA_DIR$21) {
5471
5449
  const sequence = getSequence(dataDir, input.sequenceId);
5472
5450
  if (!sequence) return { content: [{
5473
5451
  type: "text",
@@ -5499,7 +5477,7 @@ async function handleEnrollInSequence(input, dataDir = DATA_DIR$20) {
5499
5477
  })
5500
5478
  }] };
5501
5479
  }
5502
- function registerEnrollInSequence(server, dataDir = DATA_DIR$20) {
5480
+ function registerEnrollInSequence(server, dataDir = DATA_DIR$21) {
5503
5481
  server.registerTool("enroll_in_sequence", {
5504
5482
  description: `Enroll a contact in an email sequence. Validates that the sequence and its first template exist.
5505
5483
  Returns: { enrollmentId, sequenceName, totalSteps }`,
@@ -5516,8 +5494,8 @@ Returns: { enrollmentId, sequenceName, totalSteps }`,
5516
5494
  }
5517
5495
  //#endregion
5518
5496
  //#region src/mcp/tools/list-sequence-enrollments.ts
5519
- const DATA_DIR$19 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5520
- async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$19) {
5497
+ const DATA_DIR$20 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5498
+ async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$20) {
5521
5499
  let enrollments = readEnrollments(dataDir);
5522
5500
  if (input.slug !== void 0) enrollments = enrollments.filter((e) => e.slug === input.slug);
5523
5501
  if (input.status !== void 0) enrollments = enrollments.filter((e) => e.status === input.status);
@@ -5526,7 +5504,7 @@ async function handleListSequenceEnrollments(input, dataDir = DATA_DIR$19) {
5526
5504
  text: JSON.stringify({ enrollments }, null, 2)
5527
5505
  }] };
5528
5506
  }
5529
- function registerListSequenceEnrollments(server, dataDir = DATA_DIR$19) {
5507
+ function registerListSequenceEnrollments(server, dataDir = DATA_DIR$20) {
5530
5508
  server.registerTool("list_sequence_enrollments", {
5531
5509
  description: `List email sequence enrollments. Filter by customer slug or status.
5532
5510
  Returns: { enrollments: SequenceEnrollment[] }`,
@@ -5545,8 +5523,8 @@ Returns: { enrollments: SequenceEnrollment[] }`,
5545
5523
  }
5546
5524
  //#endregion
5547
5525
  //#region src/mcp/tools/unenroll-from-sequence.ts
5548
- const DATA_DIR$18 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5549
- async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$18) {
5526
+ const DATA_DIR$19 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5527
+ async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$19) {
5550
5528
  if (!await updateEnrollment(dataDir, input.enrollmentId, { status: "paused" })) return { content: [{
5551
5529
  type: "text",
5552
5530
  text: JSON.stringify({
@@ -5559,7 +5537,7 @@ async function handleUnenrollFromSequence(input, dataDir = DATA_DIR$18) {
5559
5537
  text: JSON.stringify({ success: true })
5560
5538
  }] };
5561
5539
  }
5562
- function registerUnenrollFromSequence(server, dataDir = DATA_DIR$18) {
5540
+ function registerUnenrollFromSequence(server, dataDir = DATA_DIR$19) {
5563
5541
  server.registerTool("unenroll_from_sequence", {
5564
5542
  description: `Unenroll (pause) a contact from an email sequence. Sets status to "paused" (soft delete).
5565
5543
  Returns: { success: boolean }`,
@@ -5568,8 +5546,8 @@ Returns: { success: boolean }`,
5568
5546
  }
5569
5547
  //#endregion
5570
5548
  //#region src/mcp/tools/list-sequences.ts
5571
- const DATA_DIR$17 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5572
- async function handleListSequences(_input, dataDir = DATA_DIR$17) {
5549
+ const DATA_DIR$18 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5550
+ async function handleListSequences(_input, dataDir = DATA_DIR$18) {
5573
5551
  const sequences = listSequences(dataDir);
5574
5552
  const enrollments = readEnrollments(dataDir);
5575
5553
  const result = sequences.map((seq) => ({
@@ -5583,7 +5561,7 @@ async function handleListSequences(_input, dataDir = DATA_DIR$17) {
5583
5561
  text: JSON.stringify({ sequences: result }, null, 2)
5584
5562
  }] };
5585
5563
  }
5586
- function registerListSequences(server, dataDir = DATA_DIR$17) {
5564
+ function registerListSequences(server, dataDir = DATA_DIR$18) {
5587
5565
  server.registerTool("list_sequences", {
5588
5566
  description: `List all email sequences with step count and enrollment count.
5589
5567
  Returns: { sequences: Array<{ id, name, stepCount, enrollmentCount }> }`,
@@ -5633,7 +5611,7 @@ function buildHtml(quote, config, customerName) {
5633
5611
  <p><strong>${config.companyName ?? ""}</strong><br>${config.companyAddress ?? ""}<br>${config.vatId ? `USt-IdNr.: ${config.vatId}` : ""}</p>
5634
5612
  <hr>
5635
5613
  <p><strong>An:</strong> ${customerName}</p>
5636
- <p><strong>Datum:</strong> ${quote.createdAt.slice(0, 10)} &nbsp;&nbsp; <strong>Gültig bis:</strong> ${quote.validUntil}</p>
5614
+ <p><strong>Date:</strong> ${quote.createdAt.slice(0, 10)} &nbsp;&nbsp; <strong>Valid until:</strong> ${quote.validUntil}</p>
5637
5615
  <h2>Leistungen</h2>
5638
5616
  <table>
5639
5617
  <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>
@@ -5712,15 +5690,14 @@ async function generateQuote(dataDir, input) {
5712
5690
  status: "draft",
5713
5691
  htmlPath
5714
5692
  };
5715
- fs.writeFileSync(path.join(dir, `${quoteNumber}.json`), JSON.stringify(quote, null, 2), "utf-8");
5716
- const html = buildHtml(quote, config, readCustomerName(dataDir, input.slug));
5717
- fs.writeFileSync(htmlPath, html, "utf-8");
5693
+ writeFileAtomic(path.join(dir, `${quoteNumber}.json`), JSON.stringify(quote, null, 2));
5694
+ writeFileAtomic(htmlPath, buildHtml(quote, config, readCustomerName(dataDir, input.slug)));
5718
5695
  return quote;
5719
5696
  }
5720
5697
  //#endregion
5721
5698
  //#region src/mcp/tools/generate-quote.ts
5722
- const DATA_DIR$16 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5723
- async function handleGenerateQuote(input, dataDir = DATA_DIR$16) {
5699
+ const DATA_DIR$17 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5700
+ async function handleGenerateQuote(input, dataDir = DATA_DIR$17) {
5724
5701
  try {
5725
5702
  const quote = await generateQuote(dataDir, input);
5726
5703
  return { content: [{
@@ -5744,7 +5721,7 @@ async function handleGenerateQuote(input, dataDir = DATA_DIR$16) {
5744
5721
  }] };
5745
5722
  }
5746
5723
  }
5747
- function registerGenerateQuote(server, dataDir = DATA_DIR$16) {
5724
+ function registerGenerateQuote(server, dataDir = DATA_DIR$17) {
5748
5725
  server.registerTool("generate_quote", {
5749
5726
  description: `Generate a professional HTML quote/offer for a customer deal.
5750
5727
  Calculates subtotal, VAT, and total. Saves JSON + HTML to .agentic/quotes/.
@@ -5772,8 +5749,8 @@ Returns: { quoteNumber, htmlPath, total, currency, validUntil }`,
5772
5749
  }
5773
5750
  //#endregion
5774
5751
  //#region src/mcp/tools/get-quote-status.ts
5775
- const DATA_DIR$15 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5776
- async function handleGetQuoteStatus(input, dataDir = DATA_DIR$15) {
5752
+ const DATA_DIR$16 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5753
+ async function handleGetQuoteStatus(input, dataDir = DATA_DIR$16) {
5777
5754
  if (input.quoteNumber) {
5778
5755
  const quote = readQuote(dataDir, input.quoteNumber);
5779
5756
  if (!quote) return { content: [{
@@ -5791,7 +5768,7 @@ async function handleGetQuoteStatus(input, dataDir = DATA_DIR$15) {
5791
5768
  text: JSON.stringify({ quotes }, null, 2)
5792
5769
  }] };
5793
5770
  }
5794
- function registerGetQuoteStatus(server, dataDir = DATA_DIR$15) {
5771
+ function registerGetQuoteStatus(server, dataDir = DATA_DIR$16) {
5795
5772
  server.registerTool("get_quote_status", {
5796
5773
  description: `Get quote status and details. Filter by quoteNumber (single quote) or slug (all quotes for a customer).
5797
5774
  Returns quote with status: draft | sent | viewed | accepted | declined`,
@@ -5806,7 +5783,7 @@ Returns quote with status: draft | sent | viewed | accepted | declined`,
5806
5783
  }
5807
5784
  //#endregion
5808
5785
  //#region src/mcp/tools/get-booking-link.ts
5809
- const DATA_DIR$14 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5786
+ const DATA_DIR$15 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
5810
5787
  function loadCalendlyConfig(dataDir) {
5811
5788
  const p = path.join(dataDir, ".agentic", "integrations", "calendly.yaml");
5812
5789
  if (!fs.existsSync(p)) return {};
@@ -5829,7 +5806,7 @@ function readCustomerFacts(dataDir, slug) {
5829
5806
  ...email ? { email } : {}
5830
5807
  };
5831
5808
  }
5832
- async function handleGetBookingLink(input, dataDir = DATA_DIR$14) {
5809
+ async function handleGetBookingLink(input, dataDir = DATA_DIR$15) {
5833
5810
  const config = loadCalendlyConfig(dataDir);
5834
5811
  const apiKey = config.apiKey ?? process.env["CALENDLY_API_KEY"] ?? "";
5835
5812
  if (!apiKey) return { content: [{
@@ -5857,7 +5834,7 @@ async function handleGetBookingLink(input, dataDir = DATA_DIR$14) {
5857
5834
  }] };
5858
5835
  }
5859
5836
  }
5860
- function registerGetBookingLink(server, dataDir = DATA_DIR$14) {
5837
+ function registerGetBookingLink(server, dataDir = DATA_DIR$15) {
5861
5838
  server.registerTool("get_booking_link", {
5862
5839
  description: `Get a Calendly booking link for a customer. Optionally pre-fills the customer's name/email.
5863
5840
  Requires CALENDLY_API_KEY env var or .agentic/integrations/calendly.yaml config.
@@ -5905,6 +5882,7 @@ const TICKET_HEADER = "# Tickets\n\n";
5905
5882
  const TABLE_HEADER = `| ID | Title | Status | Priority | Assignee | Created | SLA Due | Resolved |
5906
5883
  |----|-------|--------|----------|----------|---------|---------|---------|`;
5907
5884
  function ticketsPath(dataDir, slug) {
5885
+ assertSafeSlug(slug);
5908
5886
  return path.join(dataDir, "customers", slug, "tickets.md");
5909
5887
  }
5910
5888
  function escapeMd(s) {
@@ -5957,7 +5935,7 @@ async function upsertTicket(dataDir, slug, ticket) {
5957
5935
  const idx = existing.findIndex((t) => t.id === ticket.id);
5958
5936
  if (idx >= 0) existing[idx] = ticket;
5959
5937
  else existing.push(ticket);
5960
- fs.writeFileSync(p, serializeTickets(existing), "utf-8");
5938
+ writeFileAtomic(p, serializeTickets(existing));
5961
5939
  }
5962
5940
  function nextTicketId(tickets) {
5963
5941
  const nums = tickets.map((t) => parseInt(t.id.replace("T-", ""), 10)).filter((n) => !isNaN(n));
@@ -5965,28 +5943,13 @@ function nextTicketId(tickets) {
5965
5943
  return `T-${String(max + 1).padStart(3, "0")}`;
5966
5944
  }
5967
5945
  async function listAllTickets(dataDir, filter) {
5968
- const customersDir = path.join(dataDir, "customers");
5969
- if (!fs.existsSync(customersDir)) return [];
5970
- const slugs = filter?.slug ? [filter.slug] : fs.readdirSync(customersDir).filter((s) => {
5971
- try {
5972
- return fs.statSync(path.join(customersDir, s)).isDirectory();
5973
- } catch {
5974
- return false;
5975
- }
5976
- });
5977
- const results = [];
5978
- for (const slug of slugs) {
5979
- const tickets = await readTickets(dataDir, slug);
5980
- for (const ticket of tickets) {
5981
- if (filter?.status && ticket.status !== filter.status) continue;
5982
- if (filter?.priority && ticket.priority !== filter.priority) continue;
5983
- if (filter?.assignee && ticket.assignee !== filter.assignee) continue;
5984
- results.push({
5985
- slug,
5986
- ticket
5987
- });
5988
- }
5989
- }
5946
+ const slugs = filter?.slug ? [filter.slug] : listCustomerSlugs(dataDir);
5947
+ const results = (await Promise.all(slugs.map(async (slug) => {
5948
+ 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) => ({
5949
+ slug,
5950
+ ticket
5951
+ }));
5952
+ }))).flat();
5990
5953
  const priorityOrder = {
5991
5954
  urgent: 0,
5992
5955
  high: 1,
@@ -6041,8 +6004,8 @@ function calcSlaDue(createdDate, priority, rules) {
6041
6004
  }
6042
6005
  //#endregion
6043
6006
  //#region src/mcp/tools/create-ticket.ts
6044
- const DATA_DIR$13 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6045
- async function handleCreateTicket(input, dataDir = DATA_DIR$13) {
6007
+ const DATA_DIR$14 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6008
+ async function handleCreateTicket(input, dataDir = DATA_DIR$14) {
6046
6009
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
6047
6010
  const rules = loadSlaRules(dataDir);
6048
6011
  const priority = input.priority ?? "normal";
@@ -6064,7 +6027,7 @@ async function handleCreateTicket(input, dataDir = DATA_DIR$13) {
6064
6027
  text: JSON.stringify({ ticket }, null, 2)
6065
6028
  }] };
6066
6029
  }
6067
- function registerCreateTicket(server, dataDir = DATA_DIR$13) {
6030
+ function registerCreateTicket(server, dataDir = DATA_DIR$14) {
6068
6031
  server.registerTool("create_ticket", {
6069
6032
  description: `Create a support ticket for a customer. Auto-calculates SLA due date based on priority.
6070
6033
  Returns: { ticket } with id T-NNN, status=open, slaDue`,
@@ -6090,8 +6053,8 @@ Returns: { ticket } with id T-NNN, status=open, slaDue`,
6090
6053
  }
6091
6054
  //#endregion
6092
6055
  //#region src/mcp/tools/update-ticket.ts
6093
- const DATA_DIR$12 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6094
- async function handleUpdateTicket(input, dataDir = DATA_DIR$12) {
6056
+ const DATA_DIR$13 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6057
+ async function handleUpdateTicket(input, dataDir = DATA_DIR$13) {
6095
6058
  const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
6096
6059
  if (!ticket) return { content: [{
6097
6060
  type: "text",
@@ -6110,7 +6073,7 @@ async function handleUpdateTicket(input, dataDir = DATA_DIR$12) {
6110
6073
  text: JSON.stringify({ ticket: updated }, null, 2)
6111
6074
  }] };
6112
6075
  }
6113
- function registerUpdateTicket(server, dataDir = DATA_DIR$12) {
6076
+ function registerUpdateTicket(server, dataDir = DATA_DIR$13) {
6114
6077
  server.registerTool("update_ticket", {
6115
6078
  description: `Update a ticket's status or assignee. Setting status=resolved auto-sets resolved date.
6116
6079
  Returns: { ticket }`,
@@ -6135,8 +6098,8 @@ Returns: { ticket }`,
6135
6098
  }
6136
6099
  //#endregion
6137
6100
  //#region src/mcp/tools/list-tickets.ts
6138
- const DATA_DIR$11 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6139
- async function handleListTickets(input, dataDir = DATA_DIR$11) {
6101
+ const DATA_DIR$12 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6102
+ async function handleListTickets(input, dataDir = DATA_DIR$12) {
6140
6103
  const results = await listAllTickets(dataDir, {
6141
6104
  ...input.slug !== void 0 ? { slug: input.slug } : {},
6142
6105
  ...input.status !== void 0 ? { status: input.status } : {},
@@ -6148,7 +6111,7 @@ async function handleListTickets(input, dataDir = DATA_DIR$11) {
6148
6111
  text: JSON.stringify({ tickets: results }, null, 2)
6149
6112
  }] };
6150
6113
  }
6151
- function registerListTickets(server, dataDir = DATA_DIR$11) {
6114
+ function registerListTickets(server, dataDir = DATA_DIR$12) {
6152
6115
  server.registerTool("list_tickets", {
6153
6116
  description: `List support tickets. Filter by customer, status, priority, or assignee. Sorted by priority then date.
6154
6117
  Returns: { tickets: Array<{ slug, ticket }> }`,
@@ -6178,8 +6141,8 @@ Returns: { tickets: Array<{ slug, ticket }> }`,
6178
6141
  }
6179
6142
  //#endregion
6180
6143
  //#region src/mcp/tools/close-ticket.ts
6181
- const DATA_DIR$10 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6182
- async function handleCloseTicket(input, dataDir = DATA_DIR$10) {
6144
+ const DATA_DIR$11 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6145
+ async function handleCloseTicket(input, dataDir = DATA_DIR$11) {
6183
6146
  const ticket = (await readTickets(dataDir, input.slug)).find((t) => t.id === input.ticketId);
6184
6147
  if (!ticket) return { content: [{
6185
6148
  type: "text",
@@ -6206,7 +6169,7 @@ async function handleCloseTicket(input, dataDir = DATA_DIR$10) {
6206
6169
  text: JSON.stringify({ ticket: updated }, null, 2)
6207
6170
  }] };
6208
6171
  }
6209
- function registerCloseTicket(server, dataDir = DATA_DIR$10) {
6172
+ function registerCloseTicket(server, dataDir = DATA_DIR$11) {
6210
6173
  server.registerTool("close_ticket", {
6211
6174
  description: `Close a support ticket. Optionally logs the resolution as an interaction.
6212
6175
  Returns: { ticket } with status=closed`,
@@ -6316,7 +6279,7 @@ async function recordSurveyResponse(dataDir, token, score, comment) {
6316
6279
  const dir = responsesDir(dataDir, pending.surveyId);
6317
6280
  fs.mkdirSync(dir, { recursive: true });
6318
6281
  const filename = `${pending.slug}_${pending.contactEmail.replace("@", "_at_")}_${Date.now()}.json`;
6319
- fs.writeFileSync(path.join(dir, filename), JSON.stringify(response, null, 2), "utf-8");
6282
+ writeFileAtomic(path.join(dir, filename), JSON.stringify(response, null, 2));
6320
6283
  fs.unlinkSync(path.join(pendingDir, file));
6321
6284
  return response;
6322
6285
  } catch {
@@ -6356,12 +6319,12 @@ async function savePendingSurvey(dataDir, surveyId, slug, contactEmail, token) {
6356
6319
  contactEmail,
6357
6320
  sentAt: (/* @__PURE__ */ new Date()).toISOString()
6358
6321
  };
6359
- fs.writeFileSync(path.join(pendingDir, filename), JSON.stringify(pending, null, 2), "utf-8");
6322
+ writeFileAtomic(path.join(pendingDir, filename), JSON.stringify(pending, null, 2));
6360
6323
  }
6361
6324
  //#endregion
6362
6325
  //#region src/mcp/tools/send-nps-survey.ts
6363
- const DATA_DIR$9 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6364
- async function handleSendNpsSurvey(input, dataDir = DATA_DIR$9) {
6326
+ const DATA_DIR$10 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6327
+ async function handleSendNpsSurvey(input, dataDir = DATA_DIR$10) {
6365
6328
  const survey = getSurvey(dataDir, input.surveyId);
6366
6329
  if (!survey) return { content: [{
6367
6330
  type: "text",
@@ -6382,7 +6345,7 @@ async function handleSendNpsSurvey(input, dataDir = DATA_DIR$9) {
6382
6345
  }, null, 2)
6383
6346
  }] };
6384
6347
  }
6385
- function registerSendNpsSurvey(server, dataDir = DATA_DIR$9) {
6348
+ function registerSendNpsSurvey(server, dataDir = DATA_DIR$10) {
6386
6349
  server.registerTool("send_nps_survey", {
6387
6350
  description: `Generate an NPS/CSAT survey email for a customer contact. Returns subject, HTML body, and a token-based response URL.
6388
6351
  Does NOT send automatically — returns draft for review.
@@ -6402,8 +6365,8 @@ Returns: { token, subject, body, surveyUrl }`,
6402
6365
  }
6403
6366
  //#endregion
6404
6367
  //#region src/mcp/tools/get-survey-results.ts
6405
- const DATA_DIR$8 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6406
- async function handleGetSurveyResults(input, dataDir = DATA_DIR$8) {
6368
+ const DATA_DIR$9 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6369
+ async function handleGetSurveyResults(input, dataDir = DATA_DIR$9) {
6407
6370
  const responses = loadSurveyResponses(dataDir, input.surveyId, input.slug);
6408
6371
  const nps = calcNpsScore(responses);
6409
6372
  const promoters = responses.filter((r) => r.score >= 9).length;
@@ -6429,7 +6392,7 @@ async function handleGetSurveyResults(input, dataDir = DATA_DIR$8) {
6429
6392
  }, null, 2)
6430
6393
  }] };
6431
6394
  }
6432
- function registerGetSurveyResults(server, dataDir = DATA_DIR$8) {
6395
+ function registerGetSurveyResults(server, dataDir = DATA_DIR$9) {
6433
6396
  server.registerTool("get_survey_results", {
6434
6397
  description: `Get NPS/CSAT survey results with score breakdown. Calculates Net Promoter Score.
6435
6398
  Returns: { npsScore, totalResponses, promoters, passives, detractors, responses[] }`,
@@ -6459,18 +6422,21 @@ const KbArticleSchema = z.object({
6459
6422
  function kbDir(dataDir) {
6460
6423
  return path.join(dataDir, ".agentic", "knowledge-base");
6461
6424
  }
6462
- function listKbArticles(dataDir, opts) {
6463
- const dir = kbDir(dataDir);
6425
+ /** Category subdirectories of the knowledge base. */
6426
+ function kbCategories(dir) {
6464
6427
  if (!fs.existsSync(dir)) return [];
6465
- const results = [];
6466
- const categories = fs.readdirSync(dir).filter((f) => {
6428
+ return fs.readdirSync(dir).filter((f) => {
6467
6429
  try {
6468
6430
  return fs.statSync(path.join(dir, f)).isDirectory();
6469
6431
  } catch {
6470
6432
  return false;
6471
6433
  }
6472
6434
  });
6473
- for (const cat of categories) {
6435
+ }
6436
+ function listKbArticles(dataDir, opts) {
6437
+ const dir = kbDir(dataDir);
6438
+ const results = [];
6439
+ for (const cat of kbCategories(dir)) {
6474
6440
  const catDir = path.join(dir, cat);
6475
6441
  const files = fs.readdirSync(catDir).filter((f) => f.endsWith(".md"));
6476
6442
  for (const file of files) try {
@@ -6490,14 +6456,31 @@ function listKbArticles(dataDir, opts) {
6490
6456
  return results;
6491
6457
  }
6492
6458
  function getKbArticle(dataDir, id) {
6493
- return listKbArticles(dataDir).find((a) => a.id === id) ?? null;
6459
+ if (!isSafePathSegment(id)) return null;
6460
+ const dir = kbDir(dataDir);
6461
+ for (const cat of kbCategories(dir)) {
6462
+ const filePath = path.join(dir, cat, `${id}.md`);
6463
+ if (!fs.existsSync(filePath)) continue;
6464
+ try {
6465
+ const parsed = matter(fs.readFileSync(filePath, "utf-8"));
6466
+ const meta = KbArticleSchema.safeParse(parsed.data);
6467
+ if (!meta.success) return null;
6468
+ return {
6469
+ ...meta.data,
6470
+ body: parsed.content.trim()
6471
+ };
6472
+ } catch {
6473
+ return null;
6474
+ }
6475
+ }
6476
+ return null;
6494
6477
  }
6495
6478
  function writeKbArticle(dataDir, article) {
6496
- const dir = path.join(kbDir(dataDir), article.category);
6497
- fs.mkdirSync(dir, { recursive: true });
6479
+ assertSafePathSegment(article.category, "knowledge-base category");
6480
+ assertSafePathSegment(article.id, "knowledge-base article id");
6498
6481
  const { body, ...meta } = article;
6499
6482
  const content = matter.stringify(body, meta);
6500
- fs.writeFileSync(path.join(dir, `${article.id}.md`), content, "utf-8");
6483
+ writeFileAtomic(path.join(kbDir(dataDir), article.category, `${article.id}.md`), content);
6501
6484
  }
6502
6485
  function searchKbSimple(dataDir, query, opts) {
6503
6486
  const all = listKbArticles(dataDir, opts?.publicOnly ? { publicOnly: true } : {});
@@ -6510,8 +6493,8 @@ function getKbMetaForExport(article) {
6510
6493
  }
6511
6494
  //#endregion
6512
6495
  //#region src/mcp/tools/search-knowledge-base.ts
6513
- const DATA_DIR$7 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6514
- async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$7) {
6496
+ const DATA_DIR$8 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6497
+ async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$8) {
6515
6498
  const results = searchKbSimple(dataDir, input.query, { ...input.publicOnly ? { publicOnly: true } : {} });
6516
6499
  const limited = (input.category ? results.filter((a) => a.category === input.category) : results).slice(0, input.limit ?? 10);
6517
6500
  return { content: [{
@@ -6526,7 +6509,7 @@ async function handleSearchKnowledgeBase(input, dataDir = DATA_DIR$7) {
6526
6509
  }, null, 2)
6527
6510
  }] };
6528
6511
  }
6529
- function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$7) {
6512
+ function registerSearchKnowledgeBase(server, dataDir = DATA_DIR$8) {
6530
6513
  server.registerTool("search_knowledge_base", {
6531
6514
  description: `Search the knowledge base for articles. Text search on title, body, and tags.
6532
6515
  Returns: { count, articles[] } with excerpts`,
@@ -6545,8 +6528,8 @@ Returns: { count, articles[] } with excerpts`,
6545
6528
  }
6546
6529
  //#endregion
6547
6530
  //#region src/mcp/tools/create-kb-article.ts
6548
- const DATA_DIR$6 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6549
- async function handleCreateKbArticle(input, dataDir = DATA_DIR$6) {
6531
+ const DATA_DIR$7 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6532
+ async function handleCreateKbArticle(input, dataDir = DATA_DIR$7) {
6550
6533
  if (getKbArticle(dataDir, input.id)) return { content: [{
6551
6534
  type: "text",
6552
6535
  text: JSON.stringify({ error: `Article '${input.id}' already exists` })
@@ -6574,7 +6557,7 @@ async function handleCreateKbArticle(input, dataDir = DATA_DIR$6) {
6574
6557
  }, null, 2)
6575
6558
  }] };
6576
6559
  }
6577
- function registerCreateKbArticle(server, dataDir = DATA_DIR$6) {
6560
+ function registerCreateKbArticle(server, dataDir = DATA_DIR$7) {
6578
6561
  server.registerTool("create_kb_article", {
6579
6562
  description: `Create a new knowledge base article. Articles are stored as Markdown files in .agentic/knowledge-base/.
6580
6563
  Returns: { id, title, category, path }`,
@@ -6599,8 +6582,8 @@ Returns: { id, title, category, path }`,
6599
6582
  }
6600
6583
  //#endregion
6601
6584
  //#region src/mcp/tools/backup-now.ts
6602
- const DATA_DIR$5 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6603
- async function handleBackupNow(input, dataDir = DATA_DIR$5) {
6585
+ const DATA_DIR$6 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6586
+ async function handleBackupNow(input, dataDir = DATA_DIR$6) {
6604
6587
  const zipPath = path.join(dataDir, `dxcrm-backup-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19)}.zip`);
6605
6588
  const manifest = await runBackup(zipPath, dataDir, { ...input.remote ? { remote: input.remote } : {} }).catch(() => null);
6606
6589
  if (!manifest) return { content: [{
@@ -6637,8 +6620,8 @@ function registerBackupNow(server) {
6637
6620
  }
6638
6621
  //#endregion
6639
6622
  //#region src/mcp/tools/list-backups.ts
6640
- const DATA_DIR$4 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6641
- async function handleListBackups(input, dataDir = DATA_DIR$4) {
6623
+ const DATA_DIR$5 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6624
+ async function handleListBackups(input, dataDir = DATA_DIR$5) {
6642
6625
  const logEntries = readBackupLog(dataDir);
6643
6626
  const fileEntries = listBackupsInDir(dataDir);
6644
6627
  const entries = logEntries.length > 0 ? logEntries : fileEntries;
@@ -6672,8 +6655,8 @@ function registerListBackups(server) {
6672
6655
  }
6673
6656
  //#endregion
6674
6657
  //#region src/mcp/tools/trigger-sync.ts
6675
- const DATA_DIR$3 = process.cwd();
6676
- async function handleTriggerSync(input, dataDir = DATA_DIR$3) {
6658
+ const DATA_DIR$4 = process.cwd();
6659
+ async function handleTriggerSync(input, dataDir = DATA_DIR$4) {
6677
6660
  const auth = getGmailAuth();
6678
6661
  if (!auth) return { content: [{
6679
6662
  type: "text",
@@ -6708,7 +6691,7 @@ async function handleTriggerSync(input, dataDir = DATA_DIR$3) {
6708
6691
  try {
6709
6692
  const sources = JSON.parse(fs.readFileSync(sourcesPath, "utf-8"));
6710
6693
  if (!sources.gmail?.enabled || !sources.gmail.query) continue;
6711
- const { syncGmail } = await import("./gmail-sync-rQaVqKWd.js");
6694
+ const { syncGmail } = await import("./gmail-sync-C-NmibzS.js");
6712
6695
  const result = await syncGmail({
6713
6696
  slug,
6714
6697
  dataDir,
@@ -6767,8 +6750,8 @@ Returns: { success: boolean, synced: number, skipped: number, customers: [...],
6767
6750
  }
6768
6751
  //#endregion
6769
6752
  //#region src/mcp/tools/get-audit-log.ts
6770
- const DATA_DIR$2 = process.cwd();
6771
- async function handleGetAuditLog(input, dataDir = DATA_DIR$2) {
6753
+ const DATA_DIR$3 = process.cwd();
6754
+ async function handleGetAuditLog(input, dataDir = DATA_DIR$3) {
6772
6755
  const entries = readAuditLog(dataDir);
6773
6756
  const filterOpts = { limit: input.limit ?? 50 };
6774
6757
  if (input.slug !== void 0) filterOpts.slug = input.slug;
@@ -6809,6 +6792,69 @@ Returns: { total: number, returned: number, entries: [{timestamp, actor, tool, s
6809
6792
  });
6810
6793
  }
6811
6794
  //#endregion
6795
+ //#region src/mcp/tools/get-logs.ts
6796
+ const DATA_DIR$2 = process.env["DXCRM_DATA_DIR"] ?? process.cwd();
6797
+ async function handleGetLogs(input, dataDir = DATA_DIR$2) {
6798
+ const query = {
6799
+ ...input.level !== void 0 ? { level: input.level } : {},
6800
+ ...input.component !== void 0 ? { component: input.component } : {},
6801
+ ...input.since !== void 0 ? { since: input.since } : {},
6802
+ ...input.contains !== void 0 ? { contains: input.contains } : {},
6803
+ limit: input.limit ?? 100
6804
+ };
6805
+ const payload = input.summary ? summarizeLogs(dataDir, query) : (() => {
6806
+ const entries = queryLogs(dataDir, query);
6807
+ return {
6808
+ returned: entries.length,
6809
+ entries
6810
+ };
6811
+ })();
6812
+ return { content: [{
6813
+ type: "text",
6814
+ text: JSON.stringify(payload, null, 2)
6815
+ }] };
6816
+ }
6817
+ function registerGetLogs(server) {
6818
+ server.registerTool("get_logs", {
6819
+ title: "Get Logs",
6820
+ description: `Read and analyze the structured application log (.agentic/logs.ndjson).
6821
+ Use to answer "what went wrong recently?", "show errors from gmail sync", or "summarize today's activity".
6822
+
6823
+ Args:
6824
+ level: Minimum level to include — debug | info | warn | error (optional)
6825
+ component: Filter by component, e.g. "gmail-sync", "lancedb" (optional)
6826
+ since: ISO timestamp; only entries at or after it (optional)
6827
+ contains: Case-insensitive substring of the message (optional)
6828
+ limit: Max entries to return (default 100, most recent)
6829
+ summary: When true, return aggregated counts (by level + component) and recent errors instead of raw entries
6830
+
6831
+ Returns (entries): { returned: number, entries: [{ts, level, component, message, context?}] }
6832
+ Returns (summary): { total, byLevel, byComponent, firstTs, lastTs, recentErrors }`,
6833
+ inputSchema: z.object({
6834
+ level: z.enum([
6835
+ "debug",
6836
+ "info",
6837
+ "warn",
6838
+ "error"
6839
+ ]).optional().describe("Minimum level"),
6840
+ component: z.string().optional().describe("Filter by component"),
6841
+ since: z.string().optional().describe("ISO timestamp lower bound"),
6842
+ contains: z.string().optional().describe("Message substring filter"),
6843
+ limit: z.number().int().min(1).max(1e3).optional().describe("Max entries (default 100)"),
6844
+ summary: z.boolean().optional().describe("Return aggregated summary instead of entries")
6845
+ })
6846
+ }, async ({ level, component, since, contains, limit, summary }) => {
6847
+ const input = {};
6848
+ if (level !== void 0) input.level = level;
6849
+ if (component !== void 0) input.component = component;
6850
+ if (since !== void 0) input.since = since;
6851
+ if (contains !== void 0) input.contains = contains;
6852
+ if (limit !== void 0) input.limit = limit;
6853
+ if (summary !== void 0) input.summary = summary;
6854
+ return handleGetLogs(input);
6855
+ });
6856
+ }
6857
+ //#endregion
6812
6858
  //#region src/mcp/prompts.ts
6813
6859
  /**
6814
6860
  * CRM playbook prompts exposed via MCP `prompts/list` + `prompts/get`.
@@ -6890,7 +6936,7 @@ function registerResources(server, dataDir = DATA_DIR$1) {
6890
6936
  description: "Open and closed deals for a customer",
6891
6937
  mimeType: "application/json"
6892
6938
  }, async (uri, variables) => {
6893
- const { readPipeline } = await import("./pipeline-writer-eufx_0o1.js").then((n) => n.t);
6939
+ const { readPipeline } = await import("./pipeline-writer-rDj-ni6q.js").then((n) => n.t);
6894
6940
  const deals = await readPipeline(dataDir, String(variables["slug"]));
6895
6941
  return { contents: [{
6896
6942
  uri: uri.href,
@@ -6903,7 +6949,7 @@ function registerResources(server, dataDir = DATA_DIR$1) {
6903
6949
  description: "Newest-first interaction history for a customer",
6904
6950
  mimeType: "text/markdown"
6905
6951
  }, async (uri, variables) => {
6906
- const { readInteractions } = await import("./interactions-writer-DO3KcSR3.js").then((n) => n.r);
6952
+ const { readInteractions } = await import("./interactions-writer-BZzUIgJd.js").then((n) => n.r);
6907
6953
  const text = await readInteractions(dataDir, String(variables["slug"]));
6908
6954
  return { contents: [{
6909
6955
  uri: uri.href,
@@ -6962,46 +7008,30 @@ function objectsSchemaPath(dataDir) {
6962
7008
  return path.join(dataDir, ".agentic", "schema", "custom-objects.json");
6963
7009
  }
6964
7010
  function recordsPath(dataDir, name) {
7011
+ assertSafePathSegment(name, "custom object name");
6965
7012
  return path.join(dataDir, ".agentic", "objects", `${name}.json`);
6966
7013
  }
6967
7014
  function loadCustomObjects(dataDir) {
6968
- const p = objectsSchemaPath(dataDir);
6969
- if (!fs.existsSync(p)) return [];
6970
- try {
6971
- const data = JSON.parse(fs.readFileSync(p, "utf-8"));
6972
- return Array.isArray(data.objects) ? data.objects : [];
6973
- } catch {
6974
- return [];
6975
- }
7015
+ return readJsonArray(objectsSchemaPath(dataDir), "objects");
6976
7016
  }
6977
7017
  function getObjectDefinition(dataDir, name) {
6978
7018
  return loadCustomObjects(dataDir).find((o) => o.name === name);
6979
7019
  }
6980
7020
  /** Add or update (by name) a custom object definition. */
6981
7021
  function defineCustomObject(dataDir, def) {
7022
+ assertSafePathSegment(def.name, "custom object name");
6982
7023
  const objs = loadCustomObjects(dataDir);
6983
7024
  const idx = objs.findIndex((o) => o.name === def.name);
6984
7025
  if (idx >= 0) objs[idx] = def;
6985
7026
  else objs.push(def);
6986
- const p = objectsSchemaPath(dataDir);
6987
- fs.mkdirSync(path.dirname(p), { recursive: true });
6988
- fs.writeFileSync(p, JSON.stringify({ objects: objs }, null, 2), "utf-8");
7027
+ writeJsonArray(objectsSchemaPath(dataDir), "objects", objs);
6989
7028
  return objs;
6990
7029
  }
6991
7030
  function listRecords(dataDir, name) {
6992
- const p = recordsPath(dataDir, name);
6993
- if (!fs.existsSync(p)) return [];
6994
- try {
6995
- const data = JSON.parse(fs.readFileSync(p, "utf-8"));
6996
- return Array.isArray(data.records) ? data.records : [];
6997
- } catch {
6998
- return [];
6999
- }
7031
+ return readJsonArray(recordsPath(dataDir, name), "records");
7000
7032
  }
7001
7033
  function writeRecords(dataDir, name, records) {
7002
- const p = recordsPath(dataDir, name);
7003
- fs.mkdirSync(path.dirname(p), { recursive: true });
7004
- fs.writeFileSync(p, JSON.stringify({ records }, null, 2), "utf-8");
7034
+ writeJsonArray(recordsPath(dataDir, name), "records", records);
7005
7035
  }
7006
7036
  function createRecord(dataDir, name, values) {
7007
7037
  const def = getObjectDefinition(dataDir, name);
@@ -7059,7 +7089,7 @@ function handleCreateRecord(input, dataDir = DATA_DIR) {
7059
7089
  enforceRbac(dataDir, "create_record");
7060
7090
  const res = createRecord(dataDir, input.object, input.values);
7061
7091
  if (!res.ok) return json({ error: (res.errors ?? []).join("; ") });
7062
- import("./webhooks-BO2UAnmn.js").then(({ emitEvent }) => emitEvent(dataDir, "record.created", {
7092
+ import("./webhooks-sWZ8CJtR.js").then(({ emitEvent }) => emitEvent(dataDir, "record.created", {
7063
7093
  object: input.object,
7064
7094
  record: res.record
7065
7095
  }));
@@ -7121,14 +7151,7 @@ function hashToken(token) {
7121
7151
  return createHash("sha256").update(token).digest("hex");
7122
7152
  }
7123
7153
  function loadMcpTokens(dataDir) {
7124
- const p = tokensPath(dataDir);
7125
- if (!fs.existsSync(p)) return [];
7126
- try {
7127
- const data = JSON.parse(fs.readFileSync(p, "utf-8"));
7128
- return Array.isArray(data.tokens) ? data.tokens : [];
7129
- } catch {
7130
- return [];
7131
- }
7154
+ return readJsonArray(tokensPath(dataDir), "tokens");
7132
7155
  }
7133
7156
  /**
7134
7157
  * Whether the HTTP MCP endpoint must require a bearer token.
@@ -7247,6 +7270,7 @@ function createMcpServer() {
7247
7270
  registerListBackups(server);
7248
7271
  registerTriggerSync(server);
7249
7272
  registerGetAuditLog(server);
7273
+ registerGetLogs(server);
7250
7274
  registerCustomObjectTools(server);
7251
7275
  registerPrompts(server);
7252
7276
  registerResources(server);
@@ -7257,7 +7281,7 @@ async function startStdio() {
7257
7281
  const server = createMcpServer();
7258
7282
  const transport = new StdioServerTransport();
7259
7283
  await server.connect(transport);
7260
- console.error("DatasynxOpenCRM MCP Server running via stdio");
7284
+ logger.info("mcp-server", "running via stdio");
7261
7285
  }
7262
7286
  async function startHttp(port = 3847) {
7263
7287
  await initOAuthFromDisk(process.cwd());
@@ -7297,7 +7321,7 @@ async function startHttp(port = 3847) {
7297
7321
  });
7298
7322
  app.get("/sessions", async (_req, res) => {
7299
7323
  try {
7300
- const { readAllSessions } = await import("./session-D9ub6Wl1.js");
7324
+ const { readAllSessions } = await import("./session-B6XaP83h.js");
7301
7325
  const sessions = readAllSessions(dataDir);
7302
7326
  res.json({ sessions });
7303
7327
  } catch {
@@ -7431,15 +7455,15 @@ button{margin-top:12px;padding:12px 28px;background:#1a1a2e;color:#fff;border:no
7431
7455
  res.send(surveyThankYouPage(numScore, commentText));
7432
7456
  });
7433
7457
  app.listen(port, () => {
7434
- console.error(`DatasynxOpenCRM MCP Server running on http://0.0.0.0:${port}/mcp`);
7458
+ logger.info("mcp-server", "running over http", { url: `http://0.0.0.0:${port}/mcp` });
7435
7459
  });
7436
7460
  }
7437
7461
  if ((process.env["DXCRM_MCP_MODE"] ?? "stdio") === "http") startHttp(parseInt(process.env["DXCRM_MCP_PORT"] ?? "3847", 10)).catch((err) => {
7438
- console.error("MCP Server fatal error:", err.message);
7462
+ logger.error("mcp-server", "fatal error", { error: err.message });
7439
7463
  process.exit(1);
7440
7464
  });
7441
7465
  else startStdio().catch((err) => {
7442
- console.error("MCP Server fatal error:", err.message);
7466
+ logger.error("mcp-server", "fatal error", { error: err.message });
7443
7467
  process.exit(1);
7444
7468
  });
7445
7469
  //#endregion