@datasynx/agentic-crm 0.1.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. package/README.md +270 -669
  2. package/dist/{approvals-DpjxGHFp.js → approvals-CmDT2eUg.js} +7 -24
  3. package/dist/approvals-CmDT2eUg.js.map +1 -0
  4. package/dist/{ask-CID3jnuL.js → ask-CDysGnRg.js} +6 -6
  5. package/dist/{ask-CID3jnuL.js.map → ask-CDysGnRg.js.map} +1 -1
  6. package/dist/atomic-write-8yjqqLtS.js +29 -0
  7. package/dist/atomic-write-8yjqqLtS.js.map +1 -0
  8. package/dist/atomic-write-BYmF-ThH.cjs +37 -0
  9. package/dist/atomic-write-BYmF-ThH.cjs.map +1 -0
  10. package/dist/attachments-CX2GAtsw.cjs +517 -0
  11. package/dist/attachments-CX2GAtsw.cjs.map +1 -0
  12. package/dist/attachments-D207gXfN.js +514 -0
  13. package/dist/attachments-D207gXfN.js.map +1 -0
  14. package/dist/attachments-rLa96rOK.js +514 -0
  15. package/dist/attachments-rLa96rOK.js.map +1 -0
  16. package/dist/auth-B5DcjJ_6.js +2 -0
  17. package/dist/{auth-DFWwWcYD.js → auth-DDXZTwS0.js} +4 -13
  18. package/dist/auth-DDXZTwS0.js.map +1 -0
  19. package/dist/{autofill-Di_-SP7t.js → autofill-B9VtlR2j.js} +2 -2
  20. package/dist/{autofill-Di_-SP7t.js.map → autofill-B9VtlR2j.js.map} +1 -1
  21. package/dist/{backup-CeMk9z86.js → backup-CTlIxUdO.js} +5 -7
  22. package/dist/backup-CTlIxUdO.js.map +1 -0
  23. package/dist/backup-LFnC09oV.js +2 -0
  24. package/dist/chunk-BfDYWZQ8.cjs +32 -0
  25. package/dist/chunk-BfDYWZQ8.cjs.map +1 -0
  26. package/dist/chunk-BhUZmQg5.js +32 -0
  27. package/dist/chunk-BhUZmQg5.js.map +1 -0
  28. package/dist/chunk-ChC83jai.js +2 -0
  29. package/dist/chunk-e_w8qqtP.js +32 -0
  30. package/dist/chunk-e_w8qqtP.js.map +1 -0
  31. package/dist/{churn-C28IgnAj.js → churn-DN9WDGNM.js} +3 -3
  32. package/dist/{churn-C28IgnAj.js.map → churn-DN9WDGNM.js.map} +1 -1
  33. package/dist/cli.js +285 -186
  34. package/dist/cli.js.map +1 -1
  35. package/dist/{compliance-CKSBoQUe.js → compliance-Bc12Hn9a.js} +3 -3
  36. package/dist/{compliance-CKSBoQUe.js.map → compliance-Bc12Hn9a.js.map} +1 -1
  37. package/dist/{compliance-CujOqAKk.js → compliance-TqYQXhBj.js} +1 -1
  38. package/dist/{compliance-B1kk5-YS.js → compliance-kq0xHRw3.js} +3 -3
  39. package/dist/{compliance-B1kk5-YS.js.map → compliance-kq0xHRw3.js.map} +1 -1
  40. package/dist/{compliance-B91zNvCR.cjs → compliance-pAj9FcGI.cjs} +3 -3
  41. package/dist/{compliance-B91zNvCR.cjs.map → compliance-pAj9FcGI.cjs.map} +1 -1
  42. package/dist/{context-builder-BzWAp3Zs.js → context-builder-7Uab5-G4.js} +3 -2
  43. package/dist/context-builder-7Uab5-G4.js.map +1 -0
  44. package/dist/context-builder-hmOPvgso.js +2 -0
  45. package/dist/{custom-fields-CzNeD3_v.js → custom-fields-BMyz5Ruh.js} +1 -1
  46. package/dist/{custom-fields-Pl2t9xzp.js → custom-fields-GzpOHW_2.js} +4 -13
  47. package/dist/custom-fields-GzpOHW_2.js.map +1 -0
  48. package/dist/{custom-objects-CIFrmQ2V.js → custom-objects-BNy-ayR-.js} +1 -1
  49. package/dist/{custom-objects-BHgn1GEX.js → custom-objects-CxW1gHwJ.js} +10 -25
  50. package/dist/custom-objects-CxW1gHwJ.js.map +1 -0
  51. package/dist/{customer-dir-DIylZ8Q6.js → customer-dir-CkMMXhb0.js} +9 -4
  52. package/dist/customer-dir-CkMMXhb0.js.map +1 -0
  53. package/dist/daemon/worker.js +66 -40
  54. package/dist/daemon/worker.js.map +1 -1
  55. package/dist/doctor-C14-vnJ1.js +103 -0
  56. package/dist/doctor-C14-vnJ1.js.map +1 -0
  57. package/dist/email-body-BFSRa0AW.cjs +42 -0
  58. package/dist/email-body-BFSRa0AW.cjs.map +1 -0
  59. package/dist/email-body-BOd7U-D2.js +42 -0
  60. package/dist/email-body-BOd7U-D2.js.map +1 -0
  61. package/dist/{enrichment-3XvgGDfB.js → enrichment-CDFdWmvD.js} +3 -3
  62. package/dist/{enrichment-3XvgGDfB.js.map → enrichment-CDFdWmvD.js.map} +1 -1
  63. package/dist/{file-lock-B_zi7NQl.js → file-lock-CcHotQkZ.js} +3 -4
  64. package/dist/file-lock-CcHotQkZ.js.map +1 -0
  65. package/dist/{gmail-sync-DIaxInDT.js → gmail-sync-B4Iu3AQb.js} +56 -22
  66. package/dist/gmail-sync-B4Iu3AQb.js.map +1 -0
  67. package/dist/{gmail-sync-hHm9gaWd.cjs → gmail-sync-BpSVESSe.cjs} +55 -21
  68. package/dist/gmail-sync-BpSVESSe.cjs.map +1 -0
  69. package/dist/{gmail-sync-rQaVqKWd.js → gmail-sync-DIbrPnTK.js} +55 -21
  70. package/dist/gmail-sync-DIbrPnTK.js.map +1 -0
  71. package/dist/{gmail-webhook-handler-e5Od25FX.js → gmail-webhook-handler-BzOFbvgh.js} +4 -4
  72. package/dist/{gmail-webhook-handler-e5Od25FX.js.map → gmail-webhook-handler-BzOFbvgh.js.map} +1 -1
  73. package/dist/{gmail-webhook-handler-DS7OlRPX.js → gmail-webhook-handler-CvSDW_Js.js} +2 -2
  74. package/dist/{goal-engine-KpBftn4V.js → goal-engine-BbroPhqm.js} +10 -11
  75. package/dist/goal-engine-BbroPhqm.js.map +1 -0
  76. package/dist/{goal-engine-CUZSpERI.js → goal-engine-CfDAJTFt.js} +1 -1
  77. package/dist/{google-drive-sync-DEPcqFca.js → google-drive-sync-B_I1d54Y.js} +3 -3
  78. package/dist/{google-drive-sync-DEPcqFca.js.map → google-drive-sync-B_I1d54Y.js.map} +1 -1
  79. package/dist/html-BaeOCZKE.js +36 -0
  80. package/dist/html-BaeOCZKE.js.map +1 -0
  81. package/dist/html-CmOku6jS.cjs +47 -0
  82. package/dist/html-CmOku6jS.cjs.map +1 -0
  83. package/dist/{hygiene-DZqfYpFf.js → hygiene-DzQPnc6P.js} +3 -3
  84. package/dist/{hygiene-DZqfYpFf.js.map → hygiene-DzQPnc6P.js.map} +1 -1
  85. package/dist/identity-CB7j-Zr1.js +2 -0
  86. package/dist/{identity-CI6olMNm.js → identity-_uZ3Lbr2.js} +2 -2
  87. package/dist/{identity-CI6olMNm.js.map → identity-_uZ3Lbr2.js.map} +1 -1
  88. package/dist/{import-hubspot-BaK71U_K.js → import-hubspot-CTId9IGV.js} +51 -45
  89. package/dist/import-hubspot-CTId9IGV.js.map +1 -0
  90. package/dist/{index-YqwMd6aQ.d.cts → index-BAutNcAT.d.cts} +20 -12
  91. package/dist/index-BAutNcAT.d.cts.map +1 -0
  92. package/dist/{index-V8BFaH-b.d.ts → index-FzDsNSSb.d.ts} +12 -4
  93. package/dist/index-FzDsNSSb.d.ts.map +1 -0
  94. package/dist/index.cjs +19 -21
  95. package/dist/index.cjs.map +1 -1
  96. package/dist/index.d.cts +20 -12
  97. package/dist/index.d.cts.map +1 -1
  98. package/dist/index.d.ts +12 -4
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +19 -21
  101. package/dist/index.js.map +1 -1
  102. package/dist/interactions-writer-B2y-73lh.js +2 -0
  103. package/dist/{interactions-writer-SLHnoEeE.js → interactions-writer-B8XAzdqR.js} +34 -4
  104. package/dist/interactions-writer-B8XAzdqR.js.map +1 -0
  105. package/dist/{interactions-writer-CrPStUll.cjs → interactions-writer-BRJNrefF.cjs} +7 -3
  106. package/dist/interactions-writer-BRJNrefF.cjs.map +1 -0
  107. package/dist/{interactions-writer-DO3KcSR3.js → interactions-writer-ZQcpFOh9.js} +7 -3
  108. package/dist/interactions-writer-ZQcpFOh9.js.map +1 -0
  109. package/dist/json-store-WWsFzXub.js +43 -0
  110. package/dist/json-store-WWsFzXub.js.map +1 -0
  111. package/dist/{knowledge-base-D0Fh40kc.js → knowledge-base--063Kpa3.js} +51 -22
  112. package/dist/knowledge-base--063Kpa3.js.map +1 -0
  113. package/dist/{lancedb-CCBbpulq.js → lancedb-CswQEE5K.js} +1 -1
  114. package/dist/{lancedb-rlvWoPwl.js → lancedb-CuHKNsNZ.js} +4 -3
  115. package/dist/lancedb-CuHKNsNZ.js.map +1 -0
  116. package/dist/{lead-model-BCFzyktm.js → lead-model-CEmx7te7.js} +6 -14
  117. package/dist/lead-model-CEmx7te7.js.map +1 -0
  118. package/dist/{llm-Z8RIYkpF.js → llm-BnSUBisu.js} +2 -2
  119. package/dist/{llm-Z8RIYkpF.js.map → llm-BnSUBisu.js.map} +1 -1
  120. package/dist/{llm-iijeXmgq.cjs → llm-CXycmEl9.cjs} +2 -2
  121. package/dist/{llm-iijeXmgq.cjs.map → llm-CXycmEl9.cjs.map} +1 -1
  122. package/dist/{llm-DEjWcqmW.js → llm-DSX1-wFu.js} +1 -1
  123. package/dist/{llm-DvzZqva0.js → llm-PZzgPphl.js} +3 -3
  124. package/dist/{llm-DvzZqva0.js.map → llm-PZzgPphl.js.map} +1 -1
  125. package/dist/logger-BkInaGoV.cjs +167 -0
  126. package/dist/logger-BkInaGoV.cjs.map +1 -0
  127. package/dist/logger-Dyl4VcLO.js +147 -0
  128. package/dist/logger-Dyl4VcLO.js.map +1 -0
  129. package/dist/logger-UaF5p9d1.js +147 -0
  130. package/dist/logger-UaF5p9d1.js.map +1 -0
  131. package/dist/logger-vKQS34w9.js +2 -0
  132. package/dist/mcp-CdTJWTJf.d.cts.map +1 -1
  133. package/dist/mcp-CdTJWTJf.d.ts.map +1 -1
  134. package/dist/mcp.cjs +365 -319
  135. package/dist/mcp.cjs.map +1 -1
  136. package/dist/mcp.d.cts.map +1 -1
  137. package/dist/mcp.d.ts.map +1 -1
  138. package/dist/mcp.js +365 -319
  139. package/dist/mcp.js.map +1 -1
  140. package/dist/{memory-Cy6-Tbyl.js → memory-D8hmgD9d.js} +1 -1
  141. package/dist/{memory-Bb6ky3kb.js → memory-Dzr9dXSM.js} +4 -11
  142. package/dist/memory-Dzr9dXSM.js.map +1 -0
  143. package/dist/{microsoft-calendar-B6MMtUQK.js → microsoft-calendar-BgVR8GDv.js} +4 -4
  144. package/dist/{microsoft-calendar-B6MMtUQK.js.map → microsoft-calendar-BgVR8GDv.js.map} +1 -1
  145. package/dist/{microsoft-sync-CpZVoSuq.js → microsoft-sync-D30_XksI.js} +5 -5
  146. package/dist/{microsoft-sync-CpZVoSuq.js.map → microsoft-sync-D30_XksI.js.map} +1 -1
  147. package/dist/{nba-3wanmJ0U.js → nba-DwdfM93s.js} +3 -3
  148. package/dist/{nba-3wanmJ0U.js.map → nba-DwdfM93s.js.map} +1 -1
  149. package/dist/{notification-dispatcher-0vYNngWe.js → notification-dispatcher-inpKyuBz.js} +7 -3
  150. package/dist/notification-dispatcher-inpKyuBz.js.map +1 -0
  151. package/dist/{pipeline-writer-BqBrYrQc.js → pipeline-writer-0LJ6Qkat.js} +1 -1
  152. package/dist/{pipeline-writer-N2omexxp.cjs → pipeline-writer-B1tRAhuD.cjs} +11 -3
  153. package/dist/pipeline-writer-B1tRAhuD.cjs.map +1 -0
  154. package/dist/{pipeline-writer-BvVquKIe.js → pipeline-writer-CIllfnZl.js} +5 -3
  155. package/dist/pipeline-writer-CIllfnZl.js.map +1 -0
  156. package/dist/{pipeline-writer-eufx_0o1.js → pipeline-writer-rDj-ni6q.js} +6 -4
  157. package/dist/pipeline-writer-rDj-ni6q.js.map +1 -0
  158. package/dist/{proactive-agent-BgQXw3ac.js → proactive-agent-B7u3Bj_l.js} +6 -6
  159. package/dist/{proactive-agent-BgQXw3ac.js.map → proactive-agent-B7u3Bj_l.js.map} +1 -1
  160. package/dist/{proactive-worker-BrLHNhjH.js → proactive-worker-1zkm6aJD.js} +7 -8
  161. package/dist/proactive-worker-1zkm6aJD.js.map +1 -0
  162. package/dist/{push-manager-CowY-0IK.js → push-manager-BXM-IHfP.js} +1 -1
  163. package/dist/{push-manager-CdqIIkuh.js → push-manager-C0ECQgva.js} +4 -4
  164. package/dist/push-manager-C0ECQgva.js.map +1 -0
  165. package/dist/{quote-generator-OhSFsi3x.js → quote-generator-ByUyIYtw.js} +1 -1
  166. package/dist/{quote-generator-BfwENXzg.js → quote-generator-CTdR8eEI.js} +5 -5
  167. package/dist/quote-generator-CTdR8eEI.js.map +1 -0
  168. package/dist/rbac-DzbyFhVH.js +2 -0
  169. package/dist/{rbac-CTIktZaC.js → rbac-msmBc_tK.js} +19 -12
  170. package/dist/rbac-msmBc_tK.js.map +1 -0
  171. package/dist/regex-Jt5DatPi.js +13 -0
  172. package/dist/regex-Jt5DatPi.js.map +1 -0
  173. package/dist/{relationship-health-odxEoQdJ.js → relationship-health-ZZNXR1RZ.js} +8 -16
  174. package/dist/relationship-health-ZZNXR1RZ.js.map +1 -0
  175. package/dist/{revenue-simulation-Bqf2DLVB.js → revenue-simulation-D8f_YkUY.js} +9 -19
  176. package/dist/revenue-simulation-D8f_YkUY.js.map +1 -0
  177. package/dist/{revenue-simulation-BJdRTEHc.js → revenue-simulation-njJZlTqm.js} +1 -1
  178. package/dist/safe-path-mpp0dKtO.js +18 -0
  179. package/dist/safe-path-mpp0dKtO.js.map +1 -0
  180. package/dist/{segments-BqcD5HIl.js → segments-DI3LOQNe.js} +5 -14
  181. package/dist/segments-DI3LOQNe.js.map +1 -0
  182. package/dist/sequence-engine-C6nnewHX.js +2 -0
  183. package/dist/{sequence-engine-J1lTW_in.js → sequence-engine-DNTVLq7o.js} +15 -8
  184. package/dist/sequence-engine-DNTVLq7o.js.map +1 -0
  185. package/dist/{sequence-store-DaaWr0Os.js → sequence-store-CmYb6s0g.js} +6 -5
  186. package/dist/sequence-store-CmYb6s0g.js.map +1 -0
  187. package/dist/{server-Dyva03K8.js → server-DoRPPOeR.js} +308 -230
  188. package/dist/server-DoRPPOeR.js.map +1 -0
  189. package/dist/{session-D9ub6Wl1.js → session-B6XaP83h.js} +3 -3
  190. package/dist/session-B6XaP83h.js.map +1 -0
  191. package/dist/{session-B9AilxOE.js → session-BgGDyP2C.js} +3 -3
  192. package/dist/session-BgGDyP2C.js.map +1 -0
  193. package/dist/session-Bp4zTh4l.js +2 -0
  194. package/dist/{session-D0qFkBla.cjs → session-Mm7GQbSH.cjs} +3 -3
  195. package/dist/session-Mm7GQbSH.cjs.map +1 -0
  196. package/dist/{session-store-C8tEvMPw.js → session-store-DWxJ5Pof.js} +79 -17
  197. package/dist/session-store-DWxJ5Pof.js.map +1 -0
  198. package/dist/{session-store-B0QZE8Bx.cjs → session-store-yfwnj0OC.cjs} +126 -16
  199. package/dist/session-store-yfwnj0OC.cjs.map +1 -0
  200. package/dist/{sla-engine-5IhTsBUR.js → sla-engine-CP2KiKDS.js} +1 -1
  201. package/dist/{sla-engine-BqX-7u-7.js → sla-engine-O-A1ntu_.js} +2 -2
  202. package/dist/{sla-engine-BqX-7u-7.js.map → sla-engine-O-A1ntu_.js.map} +1 -1
  203. package/dist/{sop-Vp0UPWFW.js → sop-BV7ICAFR.js} +4 -11
  204. package/dist/sop-BV7ICAFR.js.map +1 -0
  205. package/dist/{sop-DkhVChGy.js → sop-D33qTHUb.js} +1 -1
  206. package/dist/survey-engine-DKctGcLQ.js +2 -0
  207. package/dist/{survey-engine-DBjCYqCv.js → survey-engine-DngXBv47.js} +5 -4
  208. package/dist/survey-engine-DngXBv47.js.map +1 -0
  209. package/dist/{sync-state-CwLSt_1m.js → sync-state-BaA8LbTI.js} +1 -1
  210. package/dist/{sync-state-ChaLbamC.js → sync-state-DMZgzpez.js} +4 -12
  211. package/dist/sync-state-DMZgzpez.js.map +1 -0
  212. package/dist/{ticket-writer-CjqKeIRD.js → ticket-writer-DsfpeLGZ.js} +1 -1
  213. package/dist/{ticket-writer-j2oX_Wal.js → ticket-writer-a9on36Wb.js} +12 -24
  214. package/dist/ticket-writer-a9on36Wb.js.map +1 -0
  215. package/dist/{tone-Bdm5uaht.js → tone-C7bqK69y.js} +5 -12
  216. package/dist/tone-C7bqK69y.js.map +1 -0
  217. package/dist/{tone-DRKlZgPr.cjs → tone-Cmc7O2Fx.cjs} +3 -9
  218. package/dist/tone-Cmc7O2Fx.cjs.map +1 -0
  219. package/dist/{tone-vNb2DAAD.js → tone-mXSftvTn.js} +3 -8
  220. package/dist/tone-mXSftvTn.js.map +1 -0
  221. package/dist/{transcript-watcher-CL2QUygI.js → transcript-watcher-BoClrJAz.js} +18 -11
  222. package/dist/transcript-watcher-BoClrJAz.js.map +1 -0
  223. package/dist/unmatched-transcripts-C92zAoM4.js +2 -0
  224. package/dist/unmatched-transcripts-DC-VQ9YS.js +16 -0
  225. package/dist/unmatched-transcripts-DC-VQ9YS.js.map +1 -0
  226. package/dist/update-deal-CWy1eLJI.js +2 -0
  227. package/dist/{update-deal-DKC79skb.js → update-deal-DSzr_Aau.js} +3 -3
  228. package/dist/{update-deal-DKC79skb.js.map → update-deal-DSzr_Aau.js.map} +1 -1
  229. package/dist/{usage-D0-TYJkw.js → usage-BVlFlKW_.js} +8 -6
  230. package/dist/usage-BVlFlKW_.js.map +1 -0
  231. package/dist/usage-CClTf5e6.cjs.map +1 -1
  232. package/dist/usage-D0u9a-lV.js.map +1 -1
  233. package/dist/{vault-DXCg29W-.js → vault-CfwZdNzC.js} +3 -4
  234. package/dist/vault-CfwZdNzC.js.map +1 -0
  235. package/dist/{vault-C1D3zScD.js → vault-DxKP4_R2.js} +1 -1
  236. package/dist/{webhooks-Xn6zO6kd.cjs → webhooks-CwW-3kvG.cjs} +5 -19
  237. package/dist/webhooks-CwW-3kvG.cjs.map +1 -0
  238. package/dist/{webhooks-7EpA05Qr.js → webhooks-DXr1IoKn.js} +8 -21
  239. package/dist/webhooks-DXr1IoKn.js.map +1 -0
  240. package/dist/{webhooks-BO2UAnmn.js → webhooks-sWZ8CJtR.js} +5 -18
  241. package/dist/webhooks-sWZ8CJtR.js.map +1 -0
  242. package/package.json +22 -2
  243. package/dist/approvals-DpjxGHFp.js.map +0 -1
  244. package/dist/auth-CyFuu9X_.js +0 -2
  245. package/dist/auth-DFWwWcYD.js.map +0 -1
  246. package/dist/backup-CeMk9z86.js.map +0 -1
  247. package/dist/backup-f_hC7rBV.js +0 -2
  248. package/dist/context-builder-BzWAp3Zs.js.map +0 -1
  249. package/dist/context-builder-DlrRcqmJ.js +0 -2
  250. package/dist/custom-fields-Pl2t9xzp.js.map +0 -1
  251. package/dist/custom-objects-BHgn1GEX.js.map +0 -1
  252. package/dist/customer-dir-DIylZ8Q6.js.map +0 -1
  253. package/dist/file-lock-B_zi7NQl.js.map +0 -1
  254. package/dist/gmail-sync-DIaxInDT.js.map +0 -1
  255. package/dist/gmail-sync-hHm9gaWd.cjs.map +0 -1
  256. package/dist/gmail-sync-rQaVqKWd.js.map +0 -1
  257. package/dist/goal-engine-KpBftn4V.js.map +0 -1
  258. package/dist/identity-gyfWdrcX.js +0 -2
  259. package/dist/import-hubspot-BaK71U_K.js.map +0 -1
  260. package/dist/index-V8BFaH-b.d.ts.map +0 -1
  261. package/dist/index-YqwMd6aQ.d.cts.map +0 -1
  262. package/dist/interactions-writer-CrPStUll.cjs.map +0 -1
  263. package/dist/interactions-writer-DO3KcSR3.js.map +0 -1
  264. package/dist/interactions-writer-SLHnoEeE.js.map +0 -1
  265. package/dist/interactions-writer-dSPy1XfO.js +0 -2
  266. package/dist/knowledge-base-D0Fh40kc.js.map +0 -1
  267. package/dist/lancedb-rlvWoPwl.js.map +0 -1
  268. package/dist/lead-model-BCFzyktm.js.map +0 -1
  269. package/dist/memory-Bb6ky3kb.js.map +0 -1
  270. package/dist/notification-dispatcher-0vYNngWe.js.map +0 -1
  271. package/dist/pipeline-writer-BvVquKIe.js.map +0 -1
  272. package/dist/pipeline-writer-N2omexxp.cjs.map +0 -1
  273. package/dist/pipeline-writer-eufx_0o1.js.map +0 -1
  274. package/dist/proactive-worker-BrLHNhjH.js.map +0 -1
  275. package/dist/push-manager-CdqIIkuh.js.map +0 -1
  276. package/dist/quote-generator-BfwENXzg.js.map +0 -1
  277. package/dist/rbac-C7c8tcES.js +0 -2
  278. package/dist/rbac-CTIktZaC.js.map +0 -1
  279. package/dist/relationship-health-odxEoQdJ.js.map +0 -1
  280. package/dist/revenue-simulation-Bqf2DLVB.js.map +0 -1
  281. package/dist/segments-BqcD5HIl.js.map +0 -1
  282. package/dist/sequence-engine-CCTHEBgi.js +0 -2
  283. package/dist/sequence-engine-J1lTW_in.js.map +0 -1
  284. package/dist/sequence-store-DaaWr0Os.js.map +0 -1
  285. package/dist/server-Dyva03K8.js.map +0 -1
  286. package/dist/session-B9AilxOE.js.map +0 -1
  287. package/dist/session-D0qFkBla.cjs.map +0 -1
  288. package/dist/session-D9ub6Wl1.js.map +0 -1
  289. package/dist/session-mWHA71Lw.js +0 -2
  290. package/dist/session-store-B0QZE8Bx.cjs.map +0 -1
  291. package/dist/session-store-C8tEvMPw.js.map +0 -1
  292. package/dist/sop-Vp0UPWFW.js.map +0 -1
  293. package/dist/survey-engine-C06hcQt3.js +0 -2
  294. package/dist/survey-engine-DBjCYqCv.js.map +0 -1
  295. package/dist/sync-state-ChaLbamC.js.map +0 -1
  296. package/dist/ticket-writer-j2oX_Wal.js.map +0 -1
  297. package/dist/tone-Bdm5uaht.js.map +0 -1
  298. package/dist/tone-DRKlZgPr.cjs.map +0 -1
  299. package/dist/tone-vNb2DAAD.js.map +0 -1
  300. package/dist/transcript-watcher-CL2QUygI.js.map +0 -1
  301. package/dist/unmatched-transcripts-BsH5bhkU.js +0 -26
  302. package/dist/unmatched-transcripts-BsH5bhkU.js.map +0 -1
  303. package/dist/unmatched-transcripts-D0PrJ9iz.js +0 -2
  304. package/dist/update-deal-BNwPGaTV.js +0 -2
  305. package/dist/usage-D0-TYJkw.js.map +0 -1
  306. package/dist/vault-DXCg29W-.js.map +0 -1
  307. package/dist/webhooks-7EpA05Qr.js.map +0 -1
  308. package/dist/webhooks-BO2UAnmn.js.map +0 -1
  309. package/dist/webhooks-Xn6zO6kd.cjs.map +0 -1
@@ -1,3 +1,5 @@
1
+ import { i as writeJsonFile } from "../json-store-WWsFzXub.js";
2
+ import { n as logger } from "../logger-Dyl4VcLO.js";
1
3
  import path from "path";
2
4
  import fs from "fs";
3
5
  import { CronJob } from "cron";
@@ -12,7 +14,7 @@ async function syncWithBackoff(fn, maxRetries = 3) {
12
14
  const msg = err.message;
13
15
  if (msg.includes("429") || msg.includes("rateLimitExceeded")) {
14
16
  const delay = Math.pow(2, attempt) * 2e3;
15
- process.stderr.write(`[daemon] Rate limit, retrying in ${delay}ms\n`);
17
+ logger.warn("daemon", "rate limit, retrying", { delayMs: delay });
16
18
  await new Promise((r) => setTimeout(r, delay));
17
19
  } else throw err;
18
20
  }
@@ -37,7 +39,7 @@ async function syncAllCustomers() {
37
39
  const credPath = path.join(DATA_DIR, ".agentic", "gmail-credentials.json");
38
40
  if (fs.existsSync(tokenPath) && fs.existsSync(credPath)) {
39
41
  const { getGmailAuth } = await import("../gmail-auth-OComS92L.js");
40
- const { syncGmail } = await import("../gmail-sync-DIaxInDT.js");
42
+ const { syncGmail } = await import("../gmail-sync-B4Iu3AQb.js");
41
43
  const auth = await getGmailAuth(credPath, tokenPath);
42
44
  await syncWithBackoff(async () => {
43
45
  const result = await syncGmail({
@@ -47,14 +49,20 @@ async function syncAllCustomers() {
47
49
  query: sources.gmail.query,
48
50
  since: /* @__PURE__ */ new Date(Date.now() - 1800 * 1e3)
49
51
  });
50
- if (result.synced > 0) process.stderr.write(`[daemon] ${slug}: synced ${result.synced} emails\n`);
51
- const { updateSlugSyncState } = await import("../sync-state-CwLSt_1m.js");
52
+ if (result.synced > 0) logger.info("daemon", "synced emails", {
53
+ slug,
54
+ synced: result.synced
55
+ });
56
+ const { updateSlugSyncState } = await import("../sync-state-BaA8LbTI.js");
52
57
  updateSlugSyncState(DATA_DIR, slug, { lastGmailSync: (/* @__PURE__ */ new Date()).toISOString() });
53
58
  });
54
59
  }
55
60
  }
56
61
  } catch (err) {
57
- process.stderr.write(`[daemon] Error syncing ${slug}: ${err.message}\n`);
62
+ logger.error("daemon", "error syncing customer", {
63
+ slug,
64
+ error: err.message
65
+ });
58
66
  }
59
67
  }
60
68
  }
@@ -64,17 +72,17 @@ async function startWatcher() {
64
72
  try {
65
73
  const sources = JSON.parse(fs.readFileSync(agenticSourcesPath, "utf-8"));
66
74
  if (sources.transcripts?.enabled && sources.transcripts.paths?.length) {
67
- const { watchTranscripts, processTranscriptFileAutoMatch } = await import("../transcript-watcher-CL2QUygI.js");
75
+ const { watchTranscripts, processTranscriptFileAutoMatch } = await import("../transcript-watcher-BoClrJAz.js");
68
76
  watchTranscripts({
69
77
  paths: sources.transcripts.paths,
70
78
  extensions: sources.transcripts.extensions ?? [".txt", ".vtt"],
71
79
  dataDir: DATA_DIR,
72
80
  onFile: (filePath) => processTranscriptFileAutoMatch(filePath, DATA_DIR)
73
81
  });
74
- process.stderr.write(`[daemon] Watching transcripts (LLM auto-match)\n`);
82
+ logger.info("daemon", "watching transcripts (LLM auto-match)");
75
83
  }
76
84
  } catch (err) {
77
- process.stderr.write(`[daemon] Watcher error: ${err.message}\n`);
85
+ logger.error("daemon", "watcher error", { error: err.message });
78
86
  }
79
87
  }
80
88
  async function checkAgentWakeTriggers() {
@@ -84,13 +92,13 @@ async function checkAgentWakeTriggers() {
84
92
  for (const file of files) try {
85
93
  const config = JSON.parse(fs.readFileSync(path.join(agentsDir, file), "utf-8"));
86
94
  if (!config.wakeOn.includes("email")) continue;
87
- const { getLastGmailSync } = await import("../sync-state-CwLSt_1m.js");
95
+ const { getLastGmailSync } = await import("../sync-state-BaA8LbTI.js");
88
96
  const lastSync = getLastGmailSync(DATA_DIR, config.slug);
89
97
  const lastWake = config.lastWake ? new Date(config.lastWake) : null;
90
98
  if (!lastSync) continue;
91
99
  if (lastWake && lastSync <= lastWake) continue;
92
- process.stderr.write(`[daemon] Wake trigger: ${config.slug}\n`);
93
- const { buildContext } = await import("../context-builder-DlrRcqmJ.js");
100
+ logger.info("daemon", "wake trigger", { slug: config.slug });
101
+ const { buildContext } = await import("../context-builder-hmOPvgso.js");
94
102
  const context = await buildContext(DATA_DIR, config.slug).catch(() => null);
95
103
  if (!context) continue;
96
104
  if (config.channel === "telegram" && process.env["TELEGRAM_BOT_TOKEN"] && (config.telegramChatId ?? process.env["TELEGRAM_CHAT_ID"])) {
@@ -119,88 +127,106 @@ async function checkAgentWakeTriggers() {
119
127
  req.write(body);
120
128
  req.end();
121
129
  });
122
- process.stderr.write(`[daemon] Telegram sent for ${config.slug}\n`);
130
+ logger.info("daemon", "telegram sent", { slug: config.slug });
123
131
  } catch (err) {
124
- process.stderr.write(`[daemon] Telegram failed: ${err.message}\n`);
132
+ logger.error("daemon", "telegram failed", { error: err.message });
125
133
  }
126
134
  }
127
135
  config.lastWake = (/* @__PURE__ */ new Date()).toISOString();
128
- fs.writeFileSync(path.join(agentsDir, file), JSON.stringify(config, null, 2), "utf-8");
136
+ writeJsonFile(path.join(agentsDir, file), config);
129
137
  } catch (err) {
130
- process.stderr.write(`[daemon] Agent check error ${file}: ${err.message}\n`);
138
+ logger.error("daemon", "agent check error", {
139
+ file,
140
+ error: err.message
141
+ });
131
142
  }
132
143
  }
133
144
  new CronJob(`*/${Math.max(1, parseInt(process.env["DXCRM_DAEMON_INTERVAL"] ?? "30", 10) || 30)} * * * *`, async () => {
134
145
  await syncAllCustomers();
135
146
  await checkAgentWakeTriggers().catch((err) => {
136
- process.stderr.write(`[daemon] Wake trigger check failed: ${err.message}\n`);
147
+ logger.error("daemon", "wake trigger check failed", { error: err.message });
137
148
  });
138
149
  }, null, true, void 0, null, false, void 0, false, true);
139
150
  new CronJob("*/60 * * * *", async () => {
140
151
  try {
141
- const { runScheduledBackupIfDue } = await import("../backup-f_hC7rBV.js");
152
+ const { runScheduledBackupIfDue } = await import("../backup-LFnC09oV.js");
142
153
  await runScheduledBackupIfDue(DATA_DIR);
143
154
  } catch (err) {
144
- process.stderr.write(`[daemon] Backup check error: ${err.message}\n`);
155
+ logger.error("daemon", "backup check error", { error: err.message });
145
156
  }
146
157
  }, null, true, void 0, null, false, void 0, false, true);
147
158
  new CronJob("0 6 * * *", async () => {
148
159
  try {
149
- const { renewExpiringSubscriptions } = await import("../push-manager-CowY-0IK.js");
150
- const { buildGmailRenewFn } = await import("../gmail-webhook-handler-DS7OlRPX.js");
160
+ const { renewExpiringSubscriptions } = await import("../push-manager-BXM-IHfP.js");
161
+ const { buildGmailRenewFn } = await import("../gmail-webhook-handler-CvSDW_Js.js");
151
162
  const tokenPath = path.join(DATA_DIR, ".agentic", "gmail-token.json");
152
163
  const credPath = path.join(DATA_DIR, ".agentic", "gmail-credentials.json");
153
- const { readSubscriptions } = await import("../push-manager-CowY-0IK.js");
164
+ const { readSubscriptions } = await import("../push-manager-BXM-IHfP.js");
154
165
  if ((await readSubscriptions(DATA_DIR)).filter((s) => s.provider === "gmail" && s.status === "active").length === 0) return;
155
166
  if (!fs.existsSync(tokenPath) || !fs.existsSync(credPath)) return;
156
167
  const { getGmailAuth } = await import("../gmail-auth-OComS92L.js");
157
168
  const result = await renewExpiringSubscriptions(DATA_DIR, buildGmailRenewFn((await getGmailAuth(credPath, tokenPath)).credentials?.access_token ?? "", ""), 24);
158
- if (result.renewed.length > 0) process.stderr.write(`[push] Renewed ${result.renewed.length} subscription(s)\n`);
159
- if (result.errors.length > 0) process.stderr.write(`[push] Renewal errors: ${result.errors.join(", ")}\n`);
169
+ if (result.renewed.length > 0) logger.info("push", "renewed subscriptions", { count: result.renewed.length });
170
+ if (result.errors.length > 0) logger.warn("push", "renewal errors", { errors: result.errors });
160
171
  } catch (err) {
161
- process.stderr.write(`[push] Renewal failed: ${err.message}\n`);
172
+ logger.error("push", "renewal failed", { error: err.message });
162
173
  }
163
174
  }, null, true, void 0, null, false, void 0, false, true);
164
175
  new CronJob("0 7 * * *", async () => {
165
176
  try {
166
- const { runDailyProactiveChecks } = await import("../proactive-worker-BrLHNhjH.js");
177
+ const { runDailyProactiveChecks } = await import("../proactive-worker-1zkm6aJD.js");
167
178
  const result = await runDailyProactiveChecks(DATA_DIR);
168
- process.stderr.write(`[proactive] Daily check: ${result.customersChecked} customers, ${result.tasksEnqueued} tasks enqueued\n`);
169
- if (result.errors.length > 0) process.stderr.write(`[proactive] Errors: ${result.errors.join(", ")}\n`);
170
- const { drainProactiveQueue } = await import("../notification-dispatcher-0vYNngWe.js");
179
+ logger.info("proactive", "daily check", {
180
+ customersChecked: result.customersChecked,
181
+ tasksEnqueued: result.tasksEnqueued
182
+ });
183
+ if (result.errors.length > 0) logger.warn("proactive", "errors during daily check", { errors: result.errors });
184
+ const { drainProactiveQueue } = await import("../notification-dispatcher-inpKyuBz.js");
171
185
  const drain = await drainProactiveQueue(DATA_DIR);
172
- process.stderr.write(`[proactive] Dispatched ${drain.sent} task(s), ${drain.failed} failed\n`);
173
- const { syncGoalProgressFromPipeline } = await import("../goal-engine-CUZSpERI.js");
186
+ logger.info("proactive", "dispatched tasks", {
187
+ sent: drain.sent,
188
+ failed: drain.failed
189
+ });
190
+ const { syncGoalProgressFromPipeline } = await import("../goal-engine-CfDAJTFt.js");
174
191
  const goalSync = await syncGoalProgressFromPipeline(DATA_DIR);
175
- if (goalSync.updated.length > 0) process.stderr.write(`[goals] Progress synced: ${goalSync.updated.join(", ")}\n`);
192
+ if (goalSync.updated.length > 0) logger.info("goals", "progress synced", { updated: goalSync.updated });
176
193
  } catch (err) {
177
- process.stderr.write(`[proactive] Daily check failed: ${err.message}\n`);
194
+ logger.error("proactive", "daily check failed", { error: err.message });
178
195
  }
179
196
  }, null, true, void 0, null, false, void 0, false, true);
180
197
  new CronJob("0 8 * * *", async () => {
181
198
  try {
182
- const { checkSlaBreaches } = await import("../sla-engine-5IhTsBUR.js");
199
+ const { checkSlaBreaches } = await import("../sla-engine-CP2KiKDS.js");
183
200
  const breaches = await checkSlaBreaches(DATA_DIR, (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
184
201
  if (breaches.length > 0) {
185
- process.stderr.write(`[tickets] ${breaches.length} SLA breach(es) found\n`);
186
- for (const { slug, ticket } of breaches) process.stderr.write(`[tickets] SLA breach: ${slug}/${ticket.id} "${ticket.title}" due ${ticket.slaDue}\n`);
202
+ logger.warn("tickets", "SLA breaches found", { count: breaches.length });
203
+ for (const { slug, ticket } of breaches) logger.warn("tickets", "SLA breach", {
204
+ slug,
205
+ ticketId: ticket.id,
206
+ title: ticket.title,
207
+ due: ticket.slaDue
208
+ });
187
209
  }
188
210
  } catch (err) {
189
- process.stderr.write(`[tickets] SLA check failed: ${err.message}\n`);
211
+ logger.error("tickets", "SLA check failed", { error: err.message });
190
212
  }
191
213
  }, null, true, void 0, null, false, void 0, false, true);
192
214
  new CronJob("0 */6 * * *", async () => {
193
215
  try {
194
- const { runSequenceCycle } = await import("../sequence-engine-CCTHEBgi.js");
216
+ const { runSequenceCycle } = await import("../sequence-engine-C6nnewHX.js");
195
217
  const result = await runSequenceCycle(DATA_DIR, (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
196
- process.stderr.write(`[sequences] ${result.sent} sent, ${result.completed} completed, ${result.errors.length} errors\n`);
218
+ logger.info("sequences", "cycle complete", {
219
+ sent: result.sent,
220
+ completed: result.completed,
221
+ errors: result.errors.length
222
+ });
197
223
  } catch (err) {
198
- process.stderr.write(`[sequences] cycle failed: ${err.message}\n`);
224
+ logger.error("sequences", "cycle failed", { error: err.message });
199
225
  }
200
226
  }, null, true, void 0, null, false, void 0, false, true);
201
227
  await startWatcher();
202
228
  if (process.send) process.send("ready");
203
- process.stderr.write("[daemon] DatasynxOpenCRM daemon started\n");
229
+ logger.info("daemon", "daemon started");
204
230
  //#endregion
205
231
  export {};
206
232
 
@@ -1 +1 @@
1
- {"version":3,"file":"worker.js","names":[],"sources":["../../src/daemon/worker.ts"],"sourcesContent":["// src/daemon/worker.ts\n// Standalone detached process — started by `dxcrm daemon start`\n// Handles background Gmail sync + transcript watching via cron\nimport { CronJob } from \"cron\";\nimport fs from \"fs\";\nimport path from \"path\";\n\nconst DATA_DIR = process.env[\"DXCRM_DATA_DIR\"] ?? process.cwd();\n\nconst MAX_CUSTOMERS_PER_CYCLE = 50;\n\nasync function syncWithBackoff(fn: () => Promise<void>, maxRetries = 3): Promise<void> {\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n try {\n await fn();\n return;\n } catch (err) {\n const msg = (err as Error).message;\n if (msg.includes(\"429\") || msg.includes(\"rateLimitExceeded\")) {\n const delay = Math.pow(2, attempt) * 2000; // 2s, 4s, 8s\n process.stderr.write(`[daemon] Rate limit, retrying in ${delay}ms\\n`);\n await new Promise((r) => setTimeout(r, delay));\n } else {\n throw err;\n }\n }\n }\n}\n\nasync function syncAllCustomers(): Promise<void> {\n const customersDir = path.join(DATA_DIR, \"customers\");\n if (!fs.existsSync(customersDir)) return;\n\n const slugs = fs.readdirSync(customersDir).filter((s) => {\n try {\n return fs.statSync(path.join(customersDir, s)).isDirectory();\n } catch {\n return false;\n }\n });\n\n const slugsToSync = slugs.slice(0, MAX_CUSTOMERS_PER_CYCLE);\n\n for (const slug of slugsToSync) {\n const sourcesPath = path.join(customersDir, slug, \"sources.json\");\n if (!fs.existsSync(sourcesPath)) continue;\n\n try {\n const sources = JSON.parse(fs.readFileSync(sourcesPath, \"utf-8\")) as {\n gmail?: { query?: string; enabled?: boolean };\n };\n\n if (sources.gmail?.enabled && sources.gmail.query) {\n // Gmail sync requires auth — skip if token not configured\n const tokenPath = path.join(DATA_DIR, \".agentic\", \"gmail-token.json\");\n const credPath = path.join(DATA_DIR, \".agentic\", \"gmail-credentials.json\");\n if (fs.existsSync(tokenPath) && fs.existsSync(credPath)) {\n const { getGmailAuth } = await import(\"../sync/gmail-auth.js\");\n const { syncGmail } = await import(\"../sync/gmail-sync.js\");\n const auth = await getGmailAuth(credPath, tokenPath);\n await syncWithBackoff(async () => {\n const result = await syncGmail({\n slug,\n dataDir: DATA_DIR,\n auth,\n query: sources.gmail!.query!,\n since: new Date(Date.now() - 30 * 60 * 1000), // last 30 min\n });\n if (result.synced > 0) {\n process.stderr.write(`[daemon] ${slug}: synced ${result.synced} emails\\n`);\n }\n // Update sync state after each successful customer sync\n const { updateSlugSyncState } = await import(\"../fs/sync-state.js\");\n updateSlugSyncState(DATA_DIR, slug, { lastGmailSync: new Date().toISOString() });\n });\n }\n }\n } catch (err) {\n process.stderr.write(`[daemon] Error syncing ${slug}: ${(err as Error).message}\\n`);\n }\n }\n}\n\n// Start transcript watcher\nasync function startWatcher(): Promise<void> {\n const agenticSourcesPath = path.join(DATA_DIR, \".agentic\", \"sources.json\");\n if (!fs.existsSync(agenticSourcesPath)) return;\n\n try {\n const sources = JSON.parse(fs.readFileSync(agenticSourcesPath, \"utf-8\")) as {\n transcripts?: { paths?: string[]; extensions?: string[]; enabled?: boolean };\n };\n\n if (sources.transcripts?.enabled && sources.transcripts.paths?.length) {\n const { watchTranscripts, processTranscriptFileAutoMatch } =\n await import(\"../sync/transcript-watcher.js\");\n watchTranscripts({\n paths: sources.transcripts.paths,\n extensions: sources.transcripts.extensions ?? [\".txt\", \".vtt\"],\n dataDir: DATA_DIR,\n onFile: (filePath) => processTranscriptFileAutoMatch(filePath, DATA_DIR),\n });\n process.stderr.write(`[daemon] Watching transcripts (LLM auto-match)\\n`);\n }\n } catch (err) {\n process.stderr.write(`[daemon] Watcher error: ${(err as Error).message}\\n`);\n }\n}\n\nasync function checkAgentWakeTriggers(): Promise<void> {\n const agentsDir = path.join(DATA_DIR, \".agentic\", \"agents\");\n if (!fs.existsSync(agentsDir)) return;\n\n const files = fs.readdirSync(agentsDir).filter((f) => f.endsWith(\".agent.json\"));\n\n for (const file of files) {\n try {\n const config = JSON.parse(fs.readFileSync(path.join(agentsDir, file), \"utf-8\") as string) as {\n slug: string;\n channel: string;\n wakeOn: string[];\n lastWake: string | null;\n telegramChatId?: string;\n };\n\n if (!config.wakeOn.includes(\"email\")) continue;\n\n const { getLastGmailSync } = await import(\"../fs/sync-state.js\");\n const lastSync = getLastGmailSync(DATA_DIR, config.slug);\n const lastWake = config.lastWake ? new Date(config.lastWake) : null;\n\n if (!lastSync) continue;\n if (lastWake && lastSync <= lastWake) continue;\n\n // New email since last wake — build context and send notification\n process.stderr.write(`[daemon] Wake trigger: ${config.slug}\\n`);\n\n const { buildContext } = await import(\"../core/context-builder.js\");\n const context = await buildContext(DATA_DIR, config.slug).catch(() => null);\n if (!context) continue;\n\n if (\n config.channel === \"telegram\" &&\n process.env[\"TELEGRAM_BOT_TOKEN\"] &&\n (config.telegramChatId ?? process.env[\"TELEGRAM_CHAT_ID\"])\n ) {\n const chatId = config.telegramChatId ?? process.env[\"TELEGRAM_CHAT_ID\"]!;\n const token = process.env[\"TELEGRAM_BOT_TOKEN\"];\n const message = `📬 New activity: *${config.slug}*\\n\\n${context.slice(0, 800)}`;\n\n try {\n const { default: https } = await import(\"https\");\n const body = JSON.stringify({ chat_id: chatId, text: message, parse_mode: \"Markdown\" });\n await new Promise<void>((resolve, reject) => {\n const req = https.request(\n `https://api.telegram.org/bot${token}/sendMessage`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(body),\n },\n },\n (res) => {\n res.resume();\n resolve();\n }\n );\n req.on(\"error\", reject);\n req.write(body);\n req.end();\n });\n process.stderr.write(`[daemon] Telegram sent for ${config.slug}\\n`);\n } catch (err) {\n process.stderr.write(`[daemon] Telegram failed: ${(err as Error).message}\\n`);\n }\n }\n\n // Update lastWake\n config.lastWake = new Date().toISOString();\n fs.writeFileSync(path.join(agentsDir, file), JSON.stringify(config, null, 2), \"utf-8\");\n } catch (err) {\n process.stderr.write(`[daemon] Agent check error ${file}: ${(err as Error).message}\\n`);\n }\n }\n}\n\n// Gmail sync — interval configurable via DXCRM_DAEMON_INTERVAL (minutes, default 30)\nconst daemonIntervalMin = Math.max(\n 1,\n parseInt(process.env[\"DXCRM_DAEMON_INTERVAL\"] ?? \"30\", 10) || 30\n);\nnew CronJob(\n `*/${daemonIntervalMin} * * * *`,\n async () => {\n await syncAllCustomers();\n await checkAgentWakeTriggers().catch((err: unknown) => {\n process.stderr.write(`[daemon] Wake trigger check failed: ${(err as Error).message}\\n`);\n });\n },\n null,\n true,\n undefined,\n null,\n false,\n undefined,\n false, // unrefTimeout — keep event loop alive\n true // waitForCompletion\n);\n\n// Scheduled backup check — hourly, runs backup if >1 day since last\nnew CronJob(\n \"*/60 * * * *\",\n async () => {\n try {\n const { runScheduledBackupIfDue } = await import(\"../commands/backup.js\");\n await runScheduledBackupIfDue(DATA_DIR);\n } catch (err) {\n process.stderr.write(`[daemon] Backup check error: ${(err as Error).message}\\n`);\n }\n },\n null,\n true,\n undefined,\n null,\n false,\n undefined,\n false, // unrefTimeout — keep event loop alive\n true // waitForCompletion\n);\n\n// Daily push subscription renewal at 06:00\nnew CronJob(\n \"0 6 * * *\",\n async () => {\n try {\n const { renewExpiringSubscriptions } = await import(\"../sync/push-manager.js\");\n const { buildGmailRenewFn } = await import(\"../sync/gmail-webhook-handler.js\");\n const tokenPath = path.join(DATA_DIR, \".agentic\", \"gmail-token.json\");\n const credPath = path.join(DATA_DIR, \".agentic\", \"gmail-credentials.json\");\n const { readSubscriptions } = await import(\"../sync/push-manager.js\");\n const subs = await readSubscriptions(DATA_DIR);\n const gmailSubs = subs.filter((s) => s.provider === \"gmail\" && s.status === \"active\");\n if (gmailSubs.length === 0) return;\n if (!fs.existsSync(tokenPath) || !fs.existsSync(credPath)) return;\n const { getGmailAuth } = await import(\"../sync/gmail-auth.js\");\n const auth = await getGmailAuth(credPath, tokenPath);\n const token = (auth.credentials?.access_token as string | undefined) ?? \"\";\n const result = await renewExpiringSubscriptions(DATA_DIR, buildGmailRenewFn(token, \"\"), 24);\n if (result.renewed.length > 0) {\n process.stderr.write(`[push] Renewed ${result.renewed.length} subscription(s)\\n`);\n }\n if (result.errors.length > 0) {\n process.stderr.write(`[push] Renewal errors: ${result.errors.join(\", \")}\\n`);\n }\n } catch (err) {\n process.stderr.write(`[push] Renewal failed: ${(err as Error).message}\\n`);\n }\n },\n null,\n true,\n undefined,\n null,\n false,\n undefined,\n false, // unrefTimeout — keep event loop alive\n true // waitForCompletion\n);\n\n// Daily proactive checks at 07:00 — relationship decay, deal risk, daily briefing\nnew CronJob(\n \"0 7 * * *\",\n async () => {\n try {\n const { runDailyProactiveChecks } = await import(\"../daemon/proactive-worker.js\");\n const result = await runDailyProactiveChecks(DATA_DIR);\n process.stderr.write(\n `[proactive] Daily check: ${result.customersChecked} customers, ${result.tasksEnqueued} tasks enqueued\\n`\n );\n if (result.errors.length > 0) {\n process.stderr.write(`[proactive] Errors: ${result.errors.join(\", \")}\\n`);\n }\n const { drainProactiveQueue } = await import(\"../core/notification-dispatcher.js\");\n const drain = await drainProactiveQueue(DATA_DIR);\n process.stderr.write(\n `[proactive] Dispatched ${drain.sent} task(s), ${drain.failed} failed\\n`\n );\n const { syncGoalProgressFromPipeline } = await import(\"../core/goal-engine.js\");\n const goalSync = await syncGoalProgressFromPipeline(DATA_DIR);\n if (goalSync.updated.length > 0) {\n process.stderr.write(`[goals] Progress synced: ${goalSync.updated.join(\", \")}\\n`);\n }\n } catch (err) {\n process.stderr.write(`[proactive] Daily check failed: ${(err as Error).message}\\n`);\n }\n },\n null,\n true,\n undefined,\n null,\n false,\n undefined,\n false, // unrefTimeout — keep event loop alive\n true // waitForCompletion\n);\n\n// SLA breach check — daily at 08:00\nnew CronJob(\n \"0 8 * * *\",\n async () => {\n try {\n const { checkSlaBreaches } = await import(\"../core/sla-engine.js\");\n const today = new Date().toISOString().slice(0, 10);\n const breaches = await checkSlaBreaches(DATA_DIR, today);\n if (breaches.length > 0) {\n process.stderr.write(`[tickets] ${breaches.length} SLA breach(es) found\\n`);\n for (const { slug, ticket } of breaches) {\n process.stderr.write(\n `[tickets] SLA breach: ${slug}/${ticket.id} \"${ticket.title}\" due ${ticket.slaDue}\\n`\n );\n }\n }\n } catch (err) {\n process.stderr.write(`[tickets] SLA check failed: ${(err as Error).message}\\n`);\n }\n },\n null,\n true,\n undefined,\n null,\n false,\n undefined,\n false, // unrefTimeout — keep event loop alive\n true // waitForCompletion\n);\n\n// Email sequence cycle — every 6 hours\nnew CronJob(\n \"0 */6 * * *\",\n async () => {\n try {\n const { runSequenceCycle } = await import(\"../core/sequence-engine.js\");\n const today = new Date().toISOString().slice(0, 10);\n const result = await runSequenceCycle(DATA_DIR, today);\n process.stderr.write(\n `[sequences] ${result.sent} sent, ${result.completed} completed, ${result.errors.length} errors\\n`\n );\n } catch (err) {\n process.stderr.write(`[sequences] cycle failed: ${(err as Error).message}\\n`);\n }\n },\n null,\n true,\n undefined,\n null,\n false,\n undefined,\n false, // unrefTimeout — keep event loop alive\n true // waitForCompletion\n);\n\nawait startWatcher();\n\n// Signal ready\nif (process.send) process.send(\"ready\");\nprocess.stderr.write(\"[daemon] DatasynxOpenCRM daemon started\\n\");\n"],"mappings":"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"}
1
+ {"version":3,"file":"worker.js","names":[],"sources":["../../src/daemon/worker.ts"],"sourcesContent":["// src/daemon/worker.ts\n// Standalone detached process — started by `dxcrm daemon start`\n// Handles background Gmail sync + transcript watching via cron\nimport { CronJob } from \"cron\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport { logger } from \"../core/logger.js\";\nimport { writeJsonFile } from \"../fs/json-store.js\";\n\nconst DATA_DIR = process.env[\"DXCRM_DATA_DIR\"] ?? process.cwd();\n\nconst MAX_CUSTOMERS_PER_CYCLE = 50;\n\nasync function syncWithBackoff(fn: () => Promise<void>, maxRetries = 3): Promise<void> {\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n try {\n await fn();\n return;\n } catch (err) {\n const msg = (err as Error).message;\n if (msg.includes(\"429\") || msg.includes(\"rateLimitExceeded\")) {\n const delay = Math.pow(2, attempt) * 2000; // 2s, 4s, 8s\n logger.warn(\"daemon\", \"rate limit, retrying\", { delayMs: delay });\n await new Promise((r) => setTimeout(r, delay));\n } else {\n throw err;\n }\n }\n }\n}\n\nasync function syncAllCustomers(): Promise<void> {\n const customersDir = path.join(DATA_DIR, \"customers\");\n if (!fs.existsSync(customersDir)) return;\n\n const slugs = fs.readdirSync(customersDir).filter((s) => {\n try {\n return fs.statSync(path.join(customersDir, s)).isDirectory();\n } catch {\n return false;\n }\n });\n\n const slugsToSync = slugs.slice(0, MAX_CUSTOMERS_PER_CYCLE);\n\n for (const slug of slugsToSync) {\n const sourcesPath = path.join(customersDir, slug, \"sources.json\");\n if (!fs.existsSync(sourcesPath)) continue;\n\n try {\n const sources = JSON.parse(fs.readFileSync(sourcesPath, \"utf-8\")) as {\n gmail?: { query?: string; enabled?: boolean };\n };\n\n if (sources.gmail?.enabled && sources.gmail.query) {\n // Gmail sync requires auth — skip if token not configured\n const tokenPath = path.join(DATA_DIR, \".agentic\", \"gmail-token.json\");\n const credPath = path.join(DATA_DIR, \".agentic\", \"gmail-credentials.json\");\n if (fs.existsSync(tokenPath) && fs.existsSync(credPath)) {\n const { getGmailAuth } = await import(\"../sync/gmail-auth.js\");\n const { syncGmail } = await import(\"../sync/gmail-sync.js\");\n const auth = await getGmailAuth(credPath, tokenPath);\n await syncWithBackoff(async () => {\n const result = await syncGmail({\n slug,\n dataDir: DATA_DIR,\n auth,\n query: sources.gmail!.query!,\n since: new Date(Date.now() - 30 * 60 * 1000), // last 30 min\n });\n if (result.synced > 0) {\n logger.info(\"daemon\", \"synced emails\", { slug, synced: result.synced });\n }\n // Update sync state after each successful customer sync\n const { updateSlugSyncState } = await import(\"../fs/sync-state.js\");\n updateSlugSyncState(DATA_DIR, slug, { lastGmailSync: new Date().toISOString() });\n });\n }\n }\n } catch (err) {\n logger.error(\"daemon\", \"error syncing customer\", { slug, error: (err as Error).message });\n }\n }\n}\n\n// Start transcript watcher\nasync function startWatcher(): Promise<void> {\n const agenticSourcesPath = path.join(DATA_DIR, \".agentic\", \"sources.json\");\n if (!fs.existsSync(agenticSourcesPath)) return;\n\n try {\n const sources = JSON.parse(fs.readFileSync(agenticSourcesPath, \"utf-8\")) as {\n transcripts?: { paths?: string[]; extensions?: string[]; enabled?: boolean };\n };\n\n if (sources.transcripts?.enabled && sources.transcripts.paths?.length) {\n const { watchTranscripts, processTranscriptFileAutoMatch } =\n await import(\"../sync/transcript-watcher.js\");\n watchTranscripts({\n paths: sources.transcripts.paths,\n extensions: sources.transcripts.extensions ?? [\".txt\", \".vtt\"],\n dataDir: DATA_DIR,\n onFile: (filePath) => processTranscriptFileAutoMatch(filePath, DATA_DIR),\n });\n logger.info(\"daemon\", \"watching transcripts (LLM auto-match)\");\n }\n } catch (err) {\n logger.error(\"daemon\", \"watcher error\", { error: (err as Error).message });\n }\n}\n\nasync function checkAgentWakeTriggers(): Promise<void> {\n const agentsDir = path.join(DATA_DIR, \".agentic\", \"agents\");\n if (!fs.existsSync(agentsDir)) return;\n\n const files = fs.readdirSync(agentsDir).filter((f) => f.endsWith(\".agent.json\"));\n\n for (const file of files) {\n try {\n const config = JSON.parse(fs.readFileSync(path.join(agentsDir, file), \"utf-8\") as string) as {\n slug: string;\n channel: string;\n wakeOn: string[];\n lastWake: string | null;\n telegramChatId?: string;\n };\n\n if (!config.wakeOn.includes(\"email\")) continue;\n\n const { getLastGmailSync } = await import(\"../fs/sync-state.js\");\n const lastSync = getLastGmailSync(DATA_DIR, config.slug);\n const lastWake = config.lastWake ? new Date(config.lastWake) : null;\n\n if (!lastSync) continue;\n if (lastWake && lastSync <= lastWake) continue;\n\n // New email since last wake — build context and send notification\n logger.info(\"daemon\", \"wake trigger\", { slug: config.slug });\n\n const { buildContext } = await import(\"../core/context-builder.js\");\n const context = await buildContext(DATA_DIR, config.slug).catch(() => null);\n if (!context) continue;\n\n if (\n config.channel === \"telegram\" &&\n process.env[\"TELEGRAM_BOT_TOKEN\"] &&\n (config.telegramChatId ?? process.env[\"TELEGRAM_CHAT_ID\"])\n ) {\n const chatId = config.telegramChatId ?? process.env[\"TELEGRAM_CHAT_ID\"]!;\n const token = process.env[\"TELEGRAM_BOT_TOKEN\"];\n const message = `📬 New activity: *${config.slug}*\\n\\n${context.slice(0, 800)}`;\n\n try {\n const { default: https } = await import(\"https\");\n const body = JSON.stringify({ chat_id: chatId, text: message, parse_mode: \"Markdown\" });\n await new Promise<void>((resolve, reject) => {\n const req = https.request(\n `https://api.telegram.org/bot${token}/sendMessage`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(body),\n },\n },\n (res) => {\n res.resume();\n resolve();\n }\n );\n req.on(\"error\", reject);\n req.write(body);\n req.end();\n });\n logger.info(\"daemon\", \"telegram sent\", { slug: config.slug });\n } catch (err) {\n logger.error(\"daemon\", \"telegram failed\", { error: (err as Error).message });\n }\n }\n\n // Update lastWake\n config.lastWake = new Date().toISOString();\n writeJsonFile(path.join(agentsDir, file), config);\n } catch (err) {\n logger.error(\"daemon\", \"agent check error\", { file, error: (err as Error).message });\n }\n }\n}\n\n// Gmail sync — interval configurable via DXCRM_DAEMON_INTERVAL (minutes, default 30)\nconst daemonIntervalMin = Math.max(\n 1,\n parseInt(process.env[\"DXCRM_DAEMON_INTERVAL\"] ?? \"30\", 10) || 30\n);\nnew CronJob(\n `*/${daemonIntervalMin} * * * *`,\n async () => {\n await syncAllCustomers();\n await checkAgentWakeTriggers().catch((err: unknown) => {\n logger.error(\"daemon\", \"wake trigger check failed\", { error: (err as Error).message });\n });\n },\n null,\n true,\n undefined,\n null,\n false,\n undefined,\n false, // unrefTimeout — keep event loop alive\n true // waitForCompletion\n);\n\n// Scheduled backup check — hourly, runs backup if >1 day since last\nnew CronJob(\n \"*/60 * * * *\",\n async () => {\n try {\n const { runScheduledBackupIfDue } = await import(\"../commands/backup.js\");\n await runScheduledBackupIfDue(DATA_DIR);\n } catch (err) {\n logger.error(\"daemon\", \"backup check error\", { error: (err as Error).message });\n }\n },\n null,\n true,\n undefined,\n null,\n false,\n undefined,\n false, // unrefTimeout — keep event loop alive\n true // waitForCompletion\n);\n\n// Daily push subscription renewal at 06:00\nnew CronJob(\n \"0 6 * * *\",\n async () => {\n try {\n const { renewExpiringSubscriptions } = await import(\"../sync/push-manager.js\");\n const { buildGmailRenewFn } = await import(\"../sync/gmail-webhook-handler.js\");\n const tokenPath = path.join(DATA_DIR, \".agentic\", \"gmail-token.json\");\n const credPath = path.join(DATA_DIR, \".agentic\", \"gmail-credentials.json\");\n const { readSubscriptions } = await import(\"../sync/push-manager.js\");\n const subs = await readSubscriptions(DATA_DIR);\n const gmailSubs = subs.filter((s) => s.provider === \"gmail\" && s.status === \"active\");\n if (gmailSubs.length === 0) return;\n if (!fs.existsSync(tokenPath) || !fs.existsSync(credPath)) return;\n const { getGmailAuth } = await import(\"../sync/gmail-auth.js\");\n const auth = await getGmailAuth(credPath, tokenPath);\n const token = (auth.credentials?.access_token as string | undefined) ?? \"\";\n const result = await renewExpiringSubscriptions(DATA_DIR, buildGmailRenewFn(token, \"\"), 24);\n if (result.renewed.length > 0) {\n logger.info(\"push\", \"renewed subscriptions\", { count: result.renewed.length });\n }\n if (result.errors.length > 0) {\n logger.warn(\"push\", \"renewal errors\", { errors: result.errors });\n }\n } catch (err) {\n logger.error(\"push\", \"renewal failed\", { error: (err as Error).message });\n }\n },\n null,\n true,\n undefined,\n null,\n false,\n undefined,\n false, // unrefTimeout — keep event loop alive\n true // waitForCompletion\n);\n\n// Daily proactive checks at 07:00 — relationship decay, deal risk, daily briefing\nnew CronJob(\n \"0 7 * * *\",\n async () => {\n try {\n const { runDailyProactiveChecks } = await import(\"../daemon/proactive-worker.js\");\n const result = await runDailyProactiveChecks(DATA_DIR);\n logger.info(\"proactive\", \"daily check\", {\n customersChecked: result.customersChecked,\n tasksEnqueued: result.tasksEnqueued,\n });\n if (result.errors.length > 0) {\n logger.warn(\"proactive\", \"errors during daily check\", { errors: result.errors });\n }\n const { drainProactiveQueue } = await import(\"../core/notification-dispatcher.js\");\n const drain = await drainProactiveQueue(DATA_DIR);\n logger.info(\"proactive\", \"dispatched tasks\", { sent: drain.sent, failed: drain.failed });\n const { syncGoalProgressFromPipeline } = await import(\"../core/goal-engine.js\");\n const goalSync = await syncGoalProgressFromPipeline(DATA_DIR);\n if (goalSync.updated.length > 0) {\n logger.info(\"goals\", \"progress synced\", { updated: goalSync.updated });\n }\n } catch (err) {\n logger.error(\"proactive\", \"daily check failed\", { error: (err as Error).message });\n }\n },\n null,\n true,\n undefined,\n null,\n false,\n undefined,\n false, // unrefTimeout — keep event loop alive\n true // waitForCompletion\n);\n\n// SLA breach check — daily at 08:00\nnew CronJob(\n \"0 8 * * *\",\n async () => {\n try {\n const { checkSlaBreaches } = await import(\"../core/sla-engine.js\");\n const today = new Date().toISOString().slice(0, 10);\n const breaches = await checkSlaBreaches(DATA_DIR, today);\n if (breaches.length > 0) {\n logger.warn(\"tickets\", \"SLA breaches found\", { count: breaches.length });\n for (const { slug, ticket } of breaches) {\n logger.warn(\"tickets\", \"SLA breach\", {\n slug,\n ticketId: ticket.id,\n title: ticket.title,\n due: ticket.slaDue,\n });\n }\n }\n } catch (err) {\n logger.error(\"tickets\", \"SLA check failed\", { error: (err as Error).message });\n }\n },\n null,\n true,\n undefined,\n null,\n false,\n undefined,\n false, // unrefTimeout — keep event loop alive\n true // waitForCompletion\n);\n\n// Email sequence cycle — every 6 hours\nnew CronJob(\n \"0 */6 * * *\",\n async () => {\n try {\n const { runSequenceCycle } = await import(\"../core/sequence-engine.js\");\n const today = new Date().toISOString().slice(0, 10);\n const result = await runSequenceCycle(DATA_DIR, today);\n logger.info(\"sequences\", \"cycle complete\", {\n sent: result.sent,\n completed: result.completed,\n errors: result.errors.length,\n });\n } catch (err) {\n logger.error(\"sequences\", \"cycle failed\", { error: (err as Error).message });\n }\n },\n null,\n true,\n undefined,\n null,\n false,\n undefined,\n false, // unrefTimeout — keep event loop alive\n true // waitForCompletion\n);\n\nawait startWatcher();\n\n// Signal ready\nif (process.send) process.send(\"ready\");\nlogger.info(\"daemon\", \"daemon started\");\n"],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ import { a as readMainFacts, i as listCustomerSlugs } from "./customer-dir-CkMMXhb0.js";
2
+ import { a as summarizeLogs } from "./logger-Dyl4VcLO.js";
3
+ import path from "path";
4
+ import fs from "fs";
5
+ //#region src/core/doctor.ts
6
+ /** Recursively collect files whose name matches the atomic-write temp pattern. */
7
+ function findOrphanedTempFiles(dir, depth = 0) {
8
+ if (depth > 3 || !fs.existsSync(dir)) return [];
9
+ const out = [];
10
+ let entries;
11
+ try {
12
+ entries = fs.readdirSync(dir);
13
+ } catch {
14
+ return [];
15
+ }
16
+ for (const entry of entries) {
17
+ const full = path.join(dir, entry);
18
+ let isDir = false;
19
+ try {
20
+ isDir = fs.statSync(full).isDirectory();
21
+ } catch {
22
+ continue;
23
+ }
24
+ if (isDir) out.push(...findOrphanedTempFiles(full, depth + 1));
25
+ else if (/\.\d+\.[0-9a-f]+\.tmp$/.test(entry)) out.push(full);
26
+ }
27
+ return out;
28
+ }
29
+ /** Delete orphaned atomic-write temp files; returns the paths removed. */
30
+ function cleanupTempFiles(dataDir) {
31
+ const temps = [...findOrphanedTempFiles(path.join(dataDir, ".agentic")), ...findOrphanedTempFiles(path.join(dataDir, "customers"))];
32
+ const removed = [];
33
+ for (const f of temps) try {
34
+ fs.rmSync(f, { force: true });
35
+ removed.push(f);
36
+ } catch {}
37
+ return removed;
38
+ }
39
+ async function runDiagnostics(dataDir) {
40
+ const checks = [];
41
+ const agenticDir = path.join(dataDir, ".agentic");
42
+ const customersDir = path.join(dataDir, "customers");
43
+ if (!fs.existsSync(agenticDir) && !fs.existsSync(customersDir)) checks.push({
44
+ name: "data directory",
45
+ status: "fail",
46
+ detail: `Neither .agentic/ nor customers/ found under ${dataDir} — run 'dxcrm init'`
47
+ });
48
+ else checks.push({
49
+ name: "data directory",
50
+ status: "ok",
51
+ detail: dataDir
52
+ });
53
+ const slugs = listCustomerSlugs(dataDir);
54
+ const invalid = [];
55
+ for (const slug of slugs) try {
56
+ await readMainFacts(dataDir, slug);
57
+ } catch {
58
+ invalid.push(slug);
59
+ }
60
+ checks.push({
61
+ name: "customer data",
62
+ status: invalid.length > 0 ? "fail" : "ok",
63
+ detail: invalid.length > 0 ? `${invalid.length} of ${slugs.length} invalid: ${invalid.slice(0, 5).join(", ")}` : `${slugs.length} customer(s) valid`
64
+ });
65
+ const temps = [...findOrphanedTempFiles(agenticDir), ...findOrphanedTempFiles(customersDir)];
66
+ checks.push({
67
+ name: "temp files",
68
+ status: temps.length > 0 ? "warn" : "ok",
69
+ detail: temps.length > 0 ? `${temps.length} orphaned temp file(s) from interrupted writes — safe to delete` : "no orphaned temp files"
70
+ });
71
+ const summary = summarizeLogs(dataDir);
72
+ const errorCount = summary.byLevel.error;
73
+ checks.push({
74
+ name: "logs",
75
+ status: errorCount > 0 ? "warn" : "ok",
76
+ detail: errorCount > 0 ? `${errorCount} error entr${errorCount === 1 ? "y" : "ies"} in the log (dxcrm logs --level error)` : `${summary.total} log entr${summary.total === 1 ? "y" : "ies"}, no errors`
77
+ });
78
+ const backupLogPath = path.join(agenticDir, "backup-log.json");
79
+ if (fs.existsSync(backupLogPath)) try {
80
+ const entries = JSON.parse(fs.readFileSync(backupLogPath, "utf-8"));
81
+ const last = entries[entries.length - 1]?.createdAt;
82
+ const ageDays = last ? Math.floor((Date.now() - new Date(last).getTime()) / 864e5) : Infinity;
83
+ checks.push({
84
+ name: "backups",
85
+ status: ageDays > 7 ? "warn" : "ok",
86
+ detail: last ? `last backup ${ageDays}d ago` : "no backups recorded"
87
+ });
88
+ } catch {
89
+ checks.push({
90
+ name: "backups",
91
+ status: "warn",
92
+ detail: "backup log unreadable"
93
+ });
94
+ }
95
+ return {
96
+ ok: !checks.some((c) => c.status === "fail"),
97
+ checks
98
+ };
99
+ }
100
+ //#endregion
101
+ export { cleanupTempFiles, runDiagnostics };
102
+
103
+ //# sourceMappingURL=doctor-C14-vnJ1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-C14-vnJ1.js","names":[],"sources":["../src/core/doctor.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport { listCustomerSlugs, readMainFacts } from \"../fs/customer-dir.js\";\nimport { summarizeLogs } from \"./logger.js\";\n\n/**\n * Self-diagnostic (`dxcrm doctor`). Ties together the integrity, observability\n * and validation work into a single operator-facing health check: is the data\n * directory sound, is customer data valid, are there orphaned atomic-write temp\n * files (a crash signature), recent log errors, or a stale backup?\n */\nexport type CheckStatus = \"ok\" | \"warn\" | \"fail\";\n\nexport interface DiagnosticCheck {\n name: string;\n status: CheckStatus;\n detail: string;\n}\n\nexport interface DiagnosticReport {\n ok: boolean; // false if any check failed\n checks: DiagnosticCheck[];\n}\n\n/** Recursively collect files whose name matches the atomic-write temp pattern. */\nfunction findOrphanedTempFiles(dir: string, depth = 0): string[] {\n if (depth > 3 || !fs.existsSync(dir)) return [];\n const out: string[] = [];\n let entries: string[];\n try {\n entries = fs.readdirSync(dir);\n } catch {\n return [];\n }\n for (const entry of entries) {\n const full = path.join(dir, entry);\n let isDir = false;\n try {\n isDir = fs.statSync(full).isDirectory();\n } catch {\n continue;\n }\n if (isDir) {\n out.push(...findOrphanedTempFiles(full, depth + 1));\n } else if (/\\.\\d+\\.[0-9a-f]+\\.tmp$/.test(entry)) {\n out.push(full);\n }\n }\n return out;\n}\n\n/** Delete orphaned atomic-write temp files; returns the paths removed. */\nexport function cleanupTempFiles(dataDir: string): string[] {\n const temps = [\n ...findOrphanedTempFiles(path.join(dataDir, \".agentic\")),\n ...findOrphanedTempFiles(path.join(dataDir, \"customers\")),\n ];\n const removed: string[] = [];\n for (const f of temps) {\n try {\n fs.rmSync(f, { force: true });\n removed.push(f);\n } catch {\n /* leave it; reported but not removable */\n }\n }\n return removed;\n}\n\nexport async function runDiagnostics(dataDir: string): Promise<DiagnosticReport> {\n const checks: DiagnosticCheck[] = [];\n\n // 1. Data directory structure\n const agenticDir = path.join(dataDir, \".agentic\");\n const customersDir = path.join(dataDir, \"customers\");\n if (!fs.existsSync(agenticDir) && !fs.existsSync(customersDir)) {\n checks.push({\n name: \"data directory\",\n status: \"fail\",\n detail: `Neither .agentic/ nor customers/ found under ${dataDir} — run 'dxcrm init'`,\n });\n } else {\n checks.push({\n name: \"data directory\",\n status: \"ok\",\n detail: dataDir,\n });\n }\n\n // 2. Customer data validity\n const slugs = listCustomerSlugs(dataDir);\n const invalid: string[] = [];\n for (const slug of slugs) {\n try {\n await readMainFacts(dataDir, slug);\n } catch {\n invalid.push(slug);\n }\n }\n checks.push({\n name: \"customer data\",\n status: invalid.length > 0 ? \"fail\" : \"ok\",\n detail:\n invalid.length > 0\n ? `${invalid.length} of ${slugs.length} invalid: ${invalid.slice(0, 5).join(\", \")}`\n : `${slugs.length} customer(s) valid`,\n });\n\n // 3. Orphaned atomic-write temp files (crash signature)\n const temps = [...findOrphanedTempFiles(agenticDir), ...findOrphanedTempFiles(customersDir)];\n checks.push({\n name: \"temp files\",\n status: temps.length > 0 ? \"warn\" : \"ok\",\n detail:\n temps.length > 0\n ? `${temps.length} orphaned temp file(s) from interrupted writes — safe to delete`\n : \"no orphaned temp files\",\n });\n\n // 4. Recent log errors\n const summary = summarizeLogs(dataDir);\n const errorCount = summary.byLevel.error;\n checks.push({\n name: \"logs\",\n status: errorCount > 0 ? \"warn\" : \"ok\",\n detail:\n errorCount > 0\n ? `${errorCount} error entr${errorCount === 1 ? \"y\" : \"ies\"} in the log (dxcrm logs --level error)`\n : `${summary.total} log entr${summary.total === 1 ? \"y\" : \"ies\"}, no errors`,\n });\n\n // 5. Backup freshness\n const backupLogPath = path.join(agenticDir, \"backup-log.json\");\n if (fs.existsSync(backupLogPath)) {\n try {\n const entries = JSON.parse(fs.readFileSync(backupLogPath, \"utf-8\") as string) as Array<{\n createdAt?: string;\n }>;\n const last = entries[entries.length - 1]?.createdAt;\n const ageDays = last\n ? Math.floor((Date.now() - new Date(last).getTime()) / 86_400_000)\n : Infinity;\n checks.push({\n name: \"backups\",\n status: ageDays > 7 ? \"warn\" : \"ok\",\n detail: last ? `last backup ${ageDays}d ago` : \"no backups recorded\",\n });\n } catch {\n checks.push({ name: \"backups\", status: \"warn\", detail: \"backup log unreadable\" });\n }\n }\n\n return { ok: !checks.some((c) => c.status === \"fail\"), checks };\n}\n"],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ const require_html = require("./html-CmOku6jS.cjs");
2
+ //#region src/sync/email-body.ts
3
+ /** Decode a Gmail part body (base64url) to a UTF-8 string. */
4
+ function decodeBody(data) {
5
+ if (!data) return "";
6
+ return Buffer.from(data, "base64url").toString("utf-8");
7
+ }
8
+ /**
9
+ * Recursively collect the text/plain and text/html bodies from a Gmail message
10
+ * payload. Attachment parts (those with a filename) are ignored — only inline
11
+ * body parts are considered. The first body of each type wins (the top-level
12
+ * alternative), so signatures appended in nested forwards don't clobber it.
13
+ */
14
+ function collectBodyParts(payload) {
15
+ const result = {};
16
+ const walk = (part) => {
17
+ if (!part) return;
18
+ const mime = part.mimeType ?? "";
19
+ if (!(Boolean(part.filename) || Boolean(part.body?.attachmentId)) && part.body?.data) {
20
+ if (mime === "text/plain" && result.plain === void 0) result.plain = decodeBody(part.body.data);
21
+ else if (mime === "text/html" && result.html === void 0) result.html = decodeBody(part.body.data);
22
+ }
23
+ for (const child of part.parts ?? []) walk(child);
24
+ };
25
+ walk(payload);
26
+ return result;
27
+ }
28
+ /**
29
+ * Extract the email body as Markdown: prefers the plain-text part verbatim,
30
+ * otherwise converts the HTML part via Turndown. Returns an empty string when
31
+ * the message carries no inline body (e.g. attachment-only messages).
32
+ */
33
+ async function extractEmailBodyMarkdown(payload) {
34
+ const { plain, html } = collectBodyParts(payload);
35
+ if (plain && plain.trim()) return plain.trim();
36
+ if (html && html.trim()) return (await require_html.htmlToMarkdown(html)).trim();
37
+ return "";
38
+ }
39
+ //#endregion
40
+ exports.extractEmailBodyMarkdown = extractEmailBodyMarkdown;
41
+
42
+ //# sourceMappingURL=email-body-BFSRa0AW.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-body-BFSRa0AW.cjs","names":["htmlToMarkdown"],"sources":["../src/sync/email-body.ts"],"sourcesContent":["// src/sync/email-body.ts\nimport type { gmail_v1 } from \"@googleapis/gmail\";\nimport { htmlToMarkdown } from \"./converters/html.js\";\n\nexport interface EmailBodyParts {\n plain?: string;\n html?: string;\n}\n\n/** Decode a Gmail part body (base64url) to a UTF-8 string. */\nfunction decodeBody(data: string | null | undefined): string {\n if (!data) return \"\";\n return Buffer.from(data, \"base64url\").toString(\"utf-8\");\n}\n\n/**\n * Recursively collect the text/plain and text/html bodies from a Gmail message\n * payload. Attachment parts (those with a filename) are ignored — only inline\n * body parts are considered. The first body of each type wins (the top-level\n * alternative), so signatures appended in nested forwards don't clobber it.\n */\nexport function collectBodyParts(\n payload: gmail_v1.Schema$MessagePart | undefined\n): EmailBodyParts {\n const result: EmailBodyParts = {};\n const walk = (part?: gmail_v1.Schema$MessagePart): void => {\n if (!part) return;\n const mime = part.mimeType ?? \"\";\n const isAttachment = Boolean(part.filename) || Boolean(part.body?.attachmentId);\n if (!isAttachment && part.body?.data) {\n if (mime === \"text/plain\" && result.plain === undefined) {\n result.plain = decodeBody(part.body.data);\n } else if (mime === \"text/html\" && result.html === undefined) {\n result.html = decodeBody(part.body.data);\n }\n }\n for (const child of part.parts ?? []) walk(child);\n };\n walk(payload);\n return result;\n}\n\n/**\n * Extract the email body as Markdown: prefers the plain-text part verbatim,\n * otherwise converts the HTML part via Turndown. Returns an empty string when\n * the message carries no inline body (e.g. attachment-only messages).\n */\nexport async function extractEmailBodyMarkdown(\n payload: gmail_v1.Schema$MessagePart | undefined\n): Promise<string> {\n const { plain, html } = collectBodyParts(payload);\n if (plain && plain.trim()) return plain.trim();\n if (html && html.trim()) return (await htmlToMarkdown(html)).trim();\n return \"\";\n}\n"],"mappings":";;;AAUA,SAAS,WAAW,MAAyC;CAC3D,IAAI,CAAC,MAAM,OAAO;CAClB,OAAO,OAAO,KAAK,MAAM,WAAW,EAAE,SAAS,OAAO;AACxD;;;;;;;AAQA,SAAgB,iBACd,SACgB;CAChB,MAAM,SAAyB,CAAC;CAChC,MAAM,QAAQ,SAA6C;EACzD,IAAI,CAAC,MAAM;EACX,MAAM,OAAO,KAAK,YAAY;EAE9B,IAAI,EADiB,QAAQ,KAAK,QAAQ,KAAK,QAAQ,KAAK,MAAM,YAAY,MACzD,KAAK,MAAM;OAC1B,SAAS,gBAAgB,OAAO,UAAU,KAAA,GAC5C,OAAO,QAAQ,WAAW,KAAK,KAAK,IAAI;QACnC,IAAI,SAAS,eAAe,OAAO,SAAS,KAAA,GACjD,OAAO,OAAO,WAAW,KAAK,KAAK,IAAI;EAAA;EAG3C,KAAK,MAAM,SAAS,KAAK,SAAS,CAAC,GAAG,KAAK,KAAK;CAClD;CACA,KAAK,OAAO;CACZ,OAAO;AACT;;;;;;AAOA,eAAsB,yBACpB,SACiB;CACjB,MAAM,EAAE,OAAO,SAAS,iBAAiB,OAAO;CAChD,IAAI,SAAS,MAAM,KAAK,GAAG,OAAO,MAAM,KAAK;CAC7C,IAAI,QAAQ,KAAK,KAAK,GAAG,QAAQ,MAAMA,aAAAA,eAAe,IAAI,GAAG,KAAK;CAClE,OAAO;AACT"}
@@ -0,0 +1,42 @@
1
+ import { n as htmlToMarkdown } from "./html-BaeOCZKE.js";
2
+ //#region src/sync/email-body.ts
3
+ /** Decode a Gmail part body (base64url) to a UTF-8 string. */
4
+ function decodeBody(data) {
5
+ if (!data) return "";
6
+ return Buffer.from(data, "base64url").toString("utf-8");
7
+ }
8
+ /**
9
+ * Recursively collect the text/plain and text/html bodies from a Gmail message
10
+ * payload. Attachment parts (those with a filename) are ignored — only inline
11
+ * body parts are considered. The first body of each type wins (the top-level
12
+ * alternative), so signatures appended in nested forwards don't clobber it.
13
+ */
14
+ function collectBodyParts(payload) {
15
+ const result = {};
16
+ const walk = (part) => {
17
+ if (!part) return;
18
+ const mime = part.mimeType ?? "";
19
+ if (!(Boolean(part.filename) || Boolean(part.body?.attachmentId)) && part.body?.data) {
20
+ if (mime === "text/plain" && result.plain === void 0) result.plain = decodeBody(part.body.data);
21
+ else if (mime === "text/html" && result.html === void 0) result.html = decodeBody(part.body.data);
22
+ }
23
+ for (const child of part.parts ?? []) walk(child);
24
+ };
25
+ walk(payload);
26
+ return result;
27
+ }
28
+ /**
29
+ * Extract the email body as Markdown: prefers the plain-text part verbatim,
30
+ * otherwise converts the HTML part via Turndown. Returns an empty string when
31
+ * the message carries no inline body (e.g. attachment-only messages).
32
+ */
33
+ async function extractEmailBodyMarkdown(payload) {
34
+ const { plain, html } = collectBodyParts(payload);
35
+ if (plain && plain.trim()) return plain.trim();
36
+ if (html && html.trim()) return (await htmlToMarkdown(html)).trim();
37
+ return "";
38
+ }
39
+ //#endregion
40
+ export { extractEmailBodyMarkdown };
41
+
42
+ //# sourceMappingURL=email-body-BOd7U-D2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email-body-BOd7U-D2.js","names":[],"sources":["../src/sync/email-body.ts"],"sourcesContent":["// src/sync/email-body.ts\nimport type { gmail_v1 } from \"@googleapis/gmail\";\nimport { htmlToMarkdown } from \"./converters/html.js\";\n\nexport interface EmailBodyParts {\n plain?: string;\n html?: string;\n}\n\n/** Decode a Gmail part body (base64url) to a UTF-8 string. */\nfunction decodeBody(data: string | null | undefined): string {\n if (!data) return \"\";\n return Buffer.from(data, \"base64url\").toString(\"utf-8\");\n}\n\n/**\n * Recursively collect the text/plain and text/html bodies from a Gmail message\n * payload. Attachment parts (those with a filename) are ignored — only inline\n * body parts are considered. The first body of each type wins (the top-level\n * alternative), so signatures appended in nested forwards don't clobber it.\n */\nexport function collectBodyParts(\n payload: gmail_v1.Schema$MessagePart | undefined\n): EmailBodyParts {\n const result: EmailBodyParts = {};\n const walk = (part?: gmail_v1.Schema$MessagePart): void => {\n if (!part) return;\n const mime = part.mimeType ?? \"\";\n const isAttachment = Boolean(part.filename) || Boolean(part.body?.attachmentId);\n if (!isAttachment && part.body?.data) {\n if (mime === \"text/plain\" && result.plain === undefined) {\n result.plain = decodeBody(part.body.data);\n } else if (mime === \"text/html\" && result.html === undefined) {\n result.html = decodeBody(part.body.data);\n }\n }\n for (const child of part.parts ?? []) walk(child);\n };\n walk(payload);\n return result;\n}\n\n/**\n * Extract the email body as Markdown: prefers the plain-text part verbatim,\n * otherwise converts the HTML part via Turndown. Returns an empty string when\n * the message carries no inline body (e.g. attachment-only messages).\n */\nexport async function extractEmailBodyMarkdown(\n payload: gmail_v1.Schema$MessagePart | undefined\n): Promise<string> {\n const { plain, html } = collectBodyParts(payload);\n if (plain && plain.trim()) return plain.trim();\n if (html && html.trim()) return (await htmlToMarkdown(html)).trim();\n return \"\";\n}\n"],"mappings":";;;AAUA,SAAS,WAAW,MAAyC;CAC3D,IAAI,CAAC,MAAM,OAAO;CAClB,OAAO,OAAO,KAAK,MAAM,WAAW,EAAE,SAAS,OAAO;AACxD;;;;;;;AAQA,SAAgB,iBACd,SACgB;CAChB,MAAM,SAAyB,CAAC;CAChC,MAAM,QAAQ,SAA6C;EACzD,IAAI,CAAC,MAAM;EACX,MAAM,OAAO,KAAK,YAAY;EAE9B,IAAI,EADiB,QAAQ,KAAK,QAAQ,KAAK,QAAQ,KAAK,MAAM,YAAY,MACzD,KAAK,MAAM;OAC1B,SAAS,gBAAgB,OAAO,UAAU,KAAA,GAC5C,OAAO,QAAQ,WAAW,KAAK,KAAK,IAAI;QACnC,IAAI,SAAS,eAAe,OAAO,SAAS,KAAA,GACjD,OAAO,OAAO,WAAW,KAAK,KAAK,IAAI;EAAA;EAG3C,KAAK,MAAM,SAAS,KAAK,SAAS,CAAC,GAAG,KAAK,KAAK;CAClD;CACA,KAAK,OAAO;CACZ,OAAO;AACT;;;;;;AAOA,eAAsB,yBACpB,SACiB;CACjB,MAAM,EAAE,OAAO,SAAS,iBAAiB,OAAO;CAChD,IAAI,SAAS,MAAM,KAAK,GAAG,OAAO,MAAM,KAAK;CAC7C,IAAI,QAAQ,KAAK,KAAK,GAAG,QAAQ,MAAM,eAAe,IAAI,GAAG,KAAK;CAClE,OAAO;AACT"}
@@ -1,5 +1,5 @@
1
- import { a as writeMainFacts, i as readMainFacts } from "./customer-dir-DIylZ8Q6.js";
2
- import { t as getSecret } from "./vault-DXCg29W-.js";
1
+ import { a as readMainFacts, o as writeMainFacts } from "./customer-dir-CkMMXhb0.js";
2
+ import { t as getSecret } from "./vault-CfwZdNzC.js";
3
3
  //#region src/core/enrichment.ts
4
4
  const ENRICHABLE = [
5
5
  "domain",
@@ -100,4 +100,4 @@ async function enrichCustomer(dataDir, slug, opts = {}) {
100
100
  //#endregion
101
101
  export { enrichCustomer };
102
102
 
103
- //# sourceMappingURL=enrichment-3XvgGDfB.js.map
103
+ //# sourceMappingURL=enrichment-CDFdWmvD.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"enrichment-3XvgGDfB.js","names":["vaultGetSecret"],"sources":["../src/core/enrichment.ts"],"sourcesContent":["import { readMainFacts, writeMainFacts } from \"../fs/customer-dir.js\";\nimport { getSecret as vaultGetSecret } from \"./vault.js\";\n\n/**\n * Enrichment layer (domino D15 / C6): a pluggable, vault-backed way to fill in\n * missing customer facts (domain, industry, contact info). The package ships an\n * offline built-in (derive domain from an email) and a provider interface so\n * external data providers can be added as plugins. Provider API keys come from\n * the D12 vault via the context — never from the markdown. Enrichment only fills\n * gaps; it never overwrites human-entered facts.\n */\nexport interface EnrichmentData {\n domain?: string;\n email?: string;\n phone?: string;\n industry?: string;\n}\n\nexport interface EnrichmentContext {\n /** Look up a provider credential from the local vault (or env). */\n getSecret(name: string): string | undefined;\n}\n\nexport interface EnrichmentInput extends EnrichmentData {\n name: string;\n}\n\nexport interface EnrichmentProvider {\n name: string;\n enrich(input: EnrichmentInput, ctx: EnrichmentContext): Promise<EnrichmentData> | EnrichmentData;\n}\n\nconst ENRICHABLE: Array<keyof EnrichmentData> = [\"domain\", \"email\", \"phone\", \"industry\"];\n\nfunction isEmpty(v: unknown): boolean {\n return v === undefined || v === null || (typeof v === \"string\" && v.trim() === \"\");\n}\n\n/** Merge additions into base, only filling fields that are currently empty. */\nexport function mergeEnrichment(base: EnrichmentData, additions: EnrichmentData): EnrichmentData {\n const out: EnrichmentData = { ...base };\n for (const key of ENRICHABLE) {\n const incoming = additions[key];\n if (isEmpty(out[key]) && incoming !== undefined && incoming.trim() !== \"\") out[key] = incoming;\n }\n return out;\n}\n\n/** Built-in, offline provider: derive a company domain from a contact email. */\nexport const domainFromEmailProvider: EnrichmentProvider = {\n name: \"domain-from-email\",\n enrich(input) {\n const email = input.email ?? \"\";\n const at = email.indexOf(\"@\");\n if (at > 0 && at < email.length - 1) {\n const domain = email\n .slice(at + 1)\n .trim()\n .toLowerCase();\n if (domain) return { domain };\n }\n return {};\n },\n};\n\nexport const DEFAULT_PROVIDERS: EnrichmentProvider[] = [domainFromEmailProvider];\n\n/** Run providers in order, merging their output into the input (gaps only). */\nexport async function runEnrichment(\n input: EnrichmentInput,\n providers: EnrichmentProvider[],\n ctx: EnrichmentContext\n): Promise<EnrichmentData> {\n let data: EnrichmentData = {\n ...(input.domain !== undefined ? { domain: input.domain } : {}),\n ...(input.email !== undefined ? { email: input.email } : {}),\n ...(input.phone !== undefined ? { phone: input.phone } : {}),\n ...(input.industry !== undefined ? { industry: input.industry } : {}),\n };\n for (const provider of providers) {\n const additions = await provider.enrich({ ...data, name: input.name }, ctx);\n data = mergeEnrichment(data, additions);\n }\n return data;\n}\n\nexport interface EnrichResult {\n /** Fields newly added by enrichment (i.e. previously empty). */\n applied: EnrichmentData;\n /** The full merged enrichment data. */\n merged: EnrichmentData;\n written: boolean;\n}\n\nfunction vaultContext(dataDir: string): EnrichmentContext {\n const key = process.env[\"DXCRM_VAULT_KEY\"];\n if (!key) return { getSecret: (n) => process.env[n] };\n return {\n getSecret(name: string) {\n try {\n return vaultGetSecret(dataDir, key, name) ?? process.env[name];\n } catch {\n return process.env[name];\n }\n },\n };\n}\n\n/**\n * Enrich one customer: read main_facts, run providers, and (optionally) write\n * the newly-filled fields back. Existing human-entered facts are preserved.\n */\nexport async function enrichCustomer(\n dataDir: string,\n slug: string,\n opts: { providers?: EnrichmentProvider[]; write?: boolean; ctx?: EnrichmentContext } = {}\n): Promise<EnrichResult> {\n const facts = await readMainFacts(dataDir, slug);\n const providers = opts.providers ?? DEFAULT_PROVIDERS;\n const ctx = opts.ctx ?? vaultContext(dataDir);\n\n const before: EnrichmentData = {\n ...(facts.domain !== undefined ? { domain: facts.domain } : {}),\n ...(facts.email !== undefined ? { email: facts.email } : {}),\n ...(facts.phone !== undefined ? { phone: facts.phone } : {}),\n ...(facts.industry !== undefined ? { industry: facts.industry } : {}),\n };\n const merged = await runEnrichment({ name: facts.name, ...before }, providers, ctx);\n\n const applied: EnrichmentData = {};\n for (const key of ENRICHABLE) {\n const value = merged[key];\n if (isEmpty(before[key]) && value !== undefined && value.trim() !== \"\") applied[key] = value;\n }\n\n let written = false;\n if (opts.write && Object.keys(applied).length > 0) {\n await writeMainFacts(dataDir, slug, {\n ...facts,\n ...applied,\n updated: new Date().toISOString().slice(0, 10),\n });\n written = true;\n }\n\n return { applied, merged, written };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"enrichment-CDFdWmvD.js","names":["vaultGetSecret"],"sources":["../src/core/enrichment.ts"],"sourcesContent":["import { readMainFacts, writeMainFacts } from \"../fs/customer-dir.js\";\nimport { getSecret as vaultGetSecret } from \"./vault.js\";\n\n/**\n * Enrichment layer (domino D15 / C6): a pluggable, vault-backed way to fill in\n * missing customer facts (domain, industry, contact info). The package ships an\n * offline built-in (derive domain from an email) and a provider interface so\n * external data providers can be added as plugins. Provider API keys come from\n * the D12 vault via the context — never from the markdown. Enrichment only fills\n * gaps; it never overwrites human-entered facts.\n */\nexport interface EnrichmentData {\n domain?: string;\n email?: string;\n phone?: string;\n industry?: string;\n}\n\nexport interface EnrichmentContext {\n /** Look up a provider credential from the local vault (or env). */\n getSecret(name: string): string | undefined;\n}\n\nexport interface EnrichmentInput extends EnrichmentData {\n name: string;\n}\n\nexport interface EnrichmentProvider {\n name: string;\n enrich(input: EnrichmentInput, ctx: EnrichmentContext): Promise<EnrichmentData> | EnrichmentData;\n}\n\nconst ENRICHABLE: Array<keyof EnrichmentData> = [\"domain\", \"email\", \"phone\", \"industry\"];\n\nfunction isEmpty(v: unknown): boolean {\n return v === undefined || v === null || (typeof v === \"string\" && v.trim() === \"\");\n}\n\n/** Merge additions into base, only filling fields that are currently empty. */\nexport function mergeEnrichment(base: EnrichmentData, additions: EnrichmentData): EnrichmentData {\n const out: EnrichmentData = { ...base };\n for (const key of ENRICHABLE) {\n const incoming = additions[key];\n if (isEmpty(out[key]) && incoming !== undefined && incoming.trim() !== \"\") out[key] = incoming;\n }\n return out;\n}\n\n/** Built-in, offline provider: derive a company domain from a contact email. */\nexport const domainFromEmailProvider: EnrichmentProvider = {\n name: \"domain-from-email\",\n enrich(input) {\n const email = input.email ?? \"\";\n const at = email.indexOf(\"@\");\n if (at > 0 && at < email.length - 1) {\n const domain = email\n .slice(at + 1)\n .trim()\n .toLowerCase();\n if (domain) return { domain };\n }\n return {};\n },\n};\n\nexport const DEFAULT_PROVIDERS: EnrichmentProvider[] = [domainFromEmailProvider];\n\n/** Run providers in order, merging their output into the input (gaps only). */\nexport async function runEnrichment(\n input: EnrichmentInput,\n providers: EnrichmentProvider[],\n ctx: EnrichmentContext\n): Promise<EnrichmentData> {\n let data: EnrichmentData = {\n ...(input.domain !== undefined ? { domain: input.domain } : {}),\n ...(input.email !== undefined ? { email: input.email } : {}),\n ...(input.phone !== undefined ? { phone: input.phone } : {}),\n ...(input.industry !== undefined ? { industry: input.industry } : {}),\n };\n for (const provider of providers) {\n const additions = await provider.enrich({ ...data, name: input.name }, ctx);\n data = mergeEnrichment(data, additions);\n }\n return data;\n}\n\nexport interface EnrichResult {\n /** Fields newly added by enrichment (i.e. previously empty). */\n applied: EnrichmentData;\n /** The full merged enrichment data. */\n merged: EnrichmentData;\n written: boolean;\n}\n\nfunction vaultContext(dataDir: string): EnrichmentContext {\n const key = process.env[\"DXCRM_VAULT_KEY\"];\n if (!key) return { getSecret: (n) => process.env[n] };\n return {\n getSecret(name: string) {\n try {\n return vaultGetSecret(dataDir, key, name) ?? process.env[name];\n } catch {\n return process.env[name];\n }\n },\n };\n}\n\n/**\n * Enrich one customer: read main_facts, run providers, and (optionally) write\n * the newly-filled fields back. Existing human-entered facts are preserved.\n */\nexport async function enrichCustomer(\n dataDir: string,\n slug: string,\n opts: { providers?: EnrichmentProvider[]; write?: boolean; ctx?: EnrichmentContext } = {}\n): Promise<EnrichResult> {\n const facts = await readMainFacts(dataDir, slug);\n const providers = opts.providers ?? DEFAULT_PROVIDERS;\n const ctx = opts.ctx ?? vaultContext(dataDir);\n\n const before: EnrichmentData = {\n ...(facts.domain !== undefined ? { domain: facts.domain } : {}),\n ...(facts.email !== undefined ? { email: facts.email } : {}),\n ...(facts.phone !== undefined ? { phone: facts.phone } : {}),\n ...(facts.industry !== undefined ? { industry: facts.industry } : {}),\n };\n const merged = await runEnrichment({ name: facts.name, ...before }, providers, ctx);\n\n const applied: EnrichmentData = {};\n for (const key of ENRICHABLE) {\n const value = merged[key];\n if (isEmpty(before[key]) && value !== undefined && value.trim() !== \"\") applied[key] = value;\n }\n\n let written = false;\n if (opts.write && Object.keys(applied).length > 0) {\n await writeMainFacts(dataDir, slug, {\n ...facts,\n ...applied,\n updated: new Date().toISOString().slice(0, 10),\n });\n written = true;\n }\n\n return { applied, merged, written };\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
+ import { t as writeFileAtomic } from "./atomic-write-8yjqqLtS.js";
1
2
  import { t as withFileQueue } from "./write-queue-IbsAjUnh.js";
2
- import path from "path";
3
3
  import fs from "fs";
4
4
  //#region src/core/file-lock.ts
5
5
  async function withJsonFile(filePath, updater) {
@@ -11,12 +11,11 @@ async function withJsonFile(filePath, updater) {
11
11
  current = null;
12
12
  }
13
13
  const next = await updater(current);
14
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
15
- fs.writeFileSync(filePath, JSON.stringify(next, null, 2), "utf-8");
14
+ writeFileAtomic(filePath, JSON.stringify(next, null, 2));
16
15
  return next;
17
16
  });
18
17
  }
19
18
  //#endregion
20
19
  export { withJsonFile as t };
21
20
 
22
- //# sourceMappingURL=file-lock-B_zi7NQl.js.map
21
+ //# sourceMappingURL=file-lock-CcHotQkZ.js.map