@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,9 +1,10 @@
1
- import { r as listCustomerSlugs } from "./customer-dir-DIylZ8Q6.js";
1
+ import { i as listCustomerSlugs } from "./customer-dir-CkMMXhb0.js";
2
+ import { i as writeJsonFile } from "./json-store-WWsFzXub.js";
2
3
  import { n as getActor } from "./audit-log-DNMY9mUZ.js";
3
- import { t as withJsonFile } from "./file-lock-B_zi7NQl.js";
4
- import { l as runSimulation } from "./revenue-simulation-Bqf2DLVB.js";
5
- import { t as readPipeline } from "./pipeline-writer-BvVquKIe.js";
6
- import { o as guardIsoDate, t as callLlm } from "./llm-DvzZqva0.js";
4
+ import { t as withJsonFile } from "./file-lock-CcHotQkZ.js";
5
+ import { l as runSimulation } from "./revenue-simulation-D8f_YkUY.js";
6
+ import { t as readPipeline } from "./pipeline-writer-CIllfnZl.js";
7
+ import { o as guardIsoDate, t as callLlm } from "./llm-PZzgPphl.js";
7
8
  import path from "path";
8
9
  import fs from "fs";
9
10
  //#region src/core/goal-engine.ts
@@ -22,12 +23,10 @@ function readGoals(dataDir) {
22
23
  }
23
24
  }
24
25
  function writeGoals(dataDir, goals) {
25
- const p = goalsPath(dataDir);
26
- fs.mkdirSync(path.dirname(p), { recursive: true });
27
- fs.writeFileSync(p, JSON.stringify({
26
+ writeJsonFile(goalsPath(dataDir), {
28
27
  goals,
29
28
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
30
- }, null, 2), "utf-8");
29
+ });
31
30
  }
32
31
  function makeGoalId() {
33
32
  return `goal_${Date.now()}_${Math.random().toString(16).slice(2, 8)}`;
@@ -189,7 +188,7 @@ async function pursueGoal(dataDir, input, options = {}) {
189
188
  const today = options.today ?? (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
190
189
  const actor = options.actor ?? getActor();
191
190
  const simInput = await (options.buildInputFn ?? (async (dir, horizon, t) => {
192
- const { buildSimulationInput } = await import("./revenue-simulation-BJdRTEHc.js");
191
+ const { buildSimulationInput } = await import("./revenue-simulation-njJZlTqm.js");
193
192
  return buildSimulationInput(dir, horizon, t);
194
193
  }))(dataDir, "quarter", today);
195
194
  const currentP50 = runSimulation(simInput).p50;
@@ -292,4 +291,4 @@ async function syncGoalProgressFromPipeline(dataDir, _today) {
292
291
  //#endregion
293
292
  export { goalsPath as a, makeGoalId as c, pursueGoal as d, rankDealsByLeverage as f, writeGoals as g, updateGoalProgress as h, getActiveGoals as i, parseLlmDecomposition as l, syncGoalProgressFromPipeline as m, cancelGoal as n, inferGoalType as o, readGoals as p, decomposeGoalRuleBased as r, inferMetric as s, buildDecompositionPrompt as t, parseTargetFromDescription as u };
294
293
 
295
- //# sourceMappingURL=goal-engine-KpBftn4V.js.map
294
+ //# sourceMappingURL=goal-engine-BbroPhqm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"goal-engine-BbroPhqm.js","names":[],"sources":["../src/core/goal-engine.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport { runSimulation } from \"./revenue-simulation.js\";\nimport { callLlm } from \"./llm.js\";\nimport { getActor } from \"../fs/audit-log.js\";\nimport { withJsonFile } from \"./file-lock.js\";\nimport { guardIsoDate } from \"./input-guard.js\";\nimport type { DealSnapshot, SimulationInput } from \"./revenue-simulation.js\";\nimport { readPipeline } from \"../fs/pipeline-writer.js\";\nimport { listCustomerSlugs } from \"../fs/customer-dir.js\";\nimport { writeJsonFile } from \"../fs/json-store.js\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type GoalMetric = \"revenue\" | \"deals_closed\" | \"meetings_booked\" | \"pipeline_created\";\nexport type GoalType = \"revenue\" | \"pipeline\" | \"relationship\" | \"churn_prevention\";\nexport type GoalStatus = \"active\" | \"completed\" | \"cancelled\" | \"blocked\";\n\nexport interface GoalSubGoal {\n priority: number;\n action: string;\n slug: string;\n dealName?: string;\n why: string;\n nextStep: string;\n targetDelta: number;\n playbookName?: string;\n}\n\nexport interface GoalDecomposition {\n analysis: string;\n currentPipeline: number;\n gap: number;\n subGoals: GoalSubGoal[];\n probabilisticOutcome: string;\n decomposedAt: string;\n}\n\nexport interface Goal {\n id: string;\n description: string;\n type: GoalType;\n target: number;\n metric: GoalMetric;\n deadline: string;\n decomposition: GoalDecomposition;\n progress: number;\n status: GoalStatus;\n createdAt: string;\n updatedAt: string;\n actor: string;\n}\n\nexport type BuildInputFn = (\n dataDir: string,\n horizon: \"quarter\" | \"year\",\n today: string\n) => Promise<SimulationInput>;\n\n// ─── Persistence ──────────────────────────────────────────────────────────────\n\nexport function goalsPath(dataDir: string): string {\n return path.join(dataDir, \".agentic\", \"goals.json\");\n}\n\nexport function readGoals(dataDir: string): Goal[] {\n const p = goalsPath(dataDir);\n if (!fs.existsSync(p)) return [];\n try {\n const raw = JSON.parse(fs.readFileSync(p, \"utf-8\") as string) as unknown;\n if (Array.isArray(raw)) return raw as Goal[];\n return (raw as { goals?: Goal[] }).goals ?? [];\n } catch {\n return [];\n }\n}\n\nexport function writeGoals(dataDir: string, goals: Goal[]): void {\n writeJsonFile(goalsPath(dataDir), { goals, updatedAt: new Date().toISOString() });\n}\n\nexport function makeGoalId(): string {\n return `goal_${Date.now()}_${Math.random().toString(16).slice(2, 8)}`;\n}\n\n// ─── Parsing ──────────────────────────────────────────────────────────────────\n\nexport function parseTargetFromDescription(desc: string): number {\n // Try millions first: \"1.5M\", \"1.5 million\", \"$1.5M\"\n const millionMatch = desc.match(/[\\$€£]?\\s*(\\d+(?:\\.\\d+)?)\\s*(?:M\\b|million)/i);\n if (millionMatch) return Math.round(parseFloat(millionMatch[1]!) * 1_000_000);\n\n // Then thousands: \"500k\", \"€500k\"\n const kMatch = desc.match(/[\\$€£]?\\s*(\\d+(?:\\.\\d+)?)\\s*k\\b/i);\n if (kMatch) return Math.round(parseFloat(kMatch[1]!) * 1_000);\n\n // Then raw numbers with optional currency: \"€75000\"\n const rawMatch = desc.match(/[\\$€£]\\s*(\\d{4,}(?:[,.\\d]*\\d)?)/);\n if (rawMatch) return parseInt(rawMatch[1]!.replace(/[,. ]/g, \"\"), 10);\n\n return 0;\n}\n\nexport function inferGoalType(desc: string): GoalType {\n const lower = desc.toLowerCase();\n if (/churn|retain|renewal|renew/.test(lower)) return \"churn_prevention\";\n if (/meeting|call|book|relationship|contact/.test(lower)) return \"relationship\";\n if (/pipeline|prospect|lead|qualify/.test(lower)) return \"pipeline\";\n return \"revenue\";\n}\n\nexport function inferMetric(type: GoalType): GoalMetric {\n switch (type) {\n case \"pipeline\":\n return \"pipeline_created\";\n case \"relationship\":\n return \"meetings_booked\";\n case \"revenue\":\n return \"revenue\";\n case \"churn_prevention\":\n return \"revenue\";\n }\n}\n\n// ─── Rule-based decomposition ─────────────────────────────────────────────────\n\nexport function rankDealsByLeverage(deals: DealSnapshot[]): DealSnapshot[] {\n return deals\n .filter((d) => d.stage !== \"won\" && d.stage !== \"lost\")\n .sort((a, b) => {\n const leverageA = a.value * (a.probability / 100) * (a.healthScore / 100);\n const leverageB = b.value * (b.probability / 100) * (b.healthScore / 100);\n return leverageB - leverageA;\n });\n}\n\nfunction generateNextStep(deal: DealSnapshot): string {\n if (deal.healthScore < 40 && !deal.championPresent)\n return \"Re-engage urgently and identify a champion\";\n if (deal.healthScore < 60) return \"Schedule an urgent check-in call\";\n if (deal.daysSinceContact > 14) return \"Reach out — contact is overdue\";\n if (!deal.championPresent) return \"Identify a champion or economic buyer\";\n return \"Push to next pipeline stage\";\n}\n\nexport function decomposeGoalRuleBased(\n deals: DealSnapshot[],\n target: number,\n currentP50: number,\n today: string,\n playbookLookup?: (slug: string, deal: DealSnapshot) => string | undefined\n): GoalDecomposition {\n const gap = Math.max(0, target - currentP50);\n const decomposedAt = new Date(today + \"T00:00:00Z\").toISOString();\n\n if (gap === 0) {\n return {\n analysis: `Current pipeline (P50: €${currentP50.toLocaleString()}) already meets or exceeds the target of €${target.toLocaleString()}.`,\n currentPipeline: currentP50,\n gap: 0,\n subGoals: [],\n probabilisticOutcome: `Pipeline P50 (€${currentP50.toLocaleString()}) ≥ target (€${target.toLocaleString()}).`,\n decomposedAt,\n };\n }\n\n const ranked = rankDealsByLeverage(deals);\n\n if (ranked.length === 0) {\n return {\n analysis: `No active deals found. Gap to close: €${gap.toLocaleString()}. Focus on building pipeline.`,\n currentPipeline: currentP50,\n gap,\n subGoals: [\n {\n priority: 1,\n action: \"Build pipeline from scratch\",\n slug: \"_all\",\n why: `No active deals. Need €${gap.toLocaleString()} to reach target.`,\n nextStep:\n \"Use list_customers() to find prospects and log_interaction to initiate outreach\",\n targetDelta: target,\n },\n ],\n probabilisticOutcome: `Insufficient pipeline. Need €${gap.toLocaleString()} in new deals.`,\n decomposedAt,\n };\n }\n\n const subGoals: GoalSubGoal[] = [];\n let cumulative = 0;\n\n for (const deal of ranked.slice(0, 5)) {\n if (subGoals.length >= 5) break;\n const playbookName = playbookLookup?.(deal.slug, deal);\n const subGoal: GoalSubGoal = {\n priority: subGoals.length + 1,\n action: `Accelerate ${deal.slug}/${deal.name}`,\n slug: deal.slug,\n ...(deal.name ? { dealName: deal.name } : {}),\n why: `€${deal.value.toLocaleString()} deal in ${deal.stage} — health ${deal.healthScore}/100`,\n nextStep: generateNextStep(deal),\n targetDelta: deal.value,\n ...(playbookName ? { playbookName } : {}),\n };\n subGoals.push(subGoal);\n cumulative += deal.value;\n if (cumulative >= gap) break;\n }\n\n const projectedTotal = currentP50 + cumulative;\n return {\n analysis: `Current pipeline P50: €${currentP50.toLocaleString()}. Gap to target: €${gap.toLocaleString()}. Top ${subGoals.length} deal(s) identified.`,\n currentPipeline: currentP50,\n gap,\n subGoals,\n probabilisticOutcome: `If all recommended deals close: ~€${projectedTotal.toLocaleString()} (target: €${target.toLocaleString()}).`,\n decomposedAt,\n };\n}\n\n// ─── LLM path ─────────────────────────────────────────────────────────────────\n\nexport function buildDecompositionPrompt(\n description: string,\n target: number,\n deadline: string,\n currentP50: number,\n deals: DealSnapshot[],\n today: string\n): string {\n const gap = Math.max(0, target - currentP50);\n const dealLines = deals\n .filter((d) => d.stage !== \"won\" && d.stage !== \"lost\")\n .slice(0, 8)\n .map(\n (d, i) =>\n `${i + 1}. ${d.slug}/${d.name} — €${d.value.toLocaleString()}, stage: ${d.stage}, health: ${d.healthScore}/100, probability: ${d.probability}%${d.championPresent ? \", champion ✓\" : \"\"}`\n )\n .join(\"\\n\");\n\n return `You are a sales strategy AI helping decompose a revenue goal into actionable sub-goals.\n\nGoal: ${description}\nTarget: €${target.toLocaleString()}\nDeadline: ${deadline}\nCurrent date: ${today}\nCurrent weighted pipeline (P50): €${currentP50.toLocaleString()}\nGap to close: €${gap.toLocaleString()}\n\nActive deals (sorted by weighted value):\n${dealLines || \"(no active deals)\"}\n\nReturn JSON only (no markdown wrapper):\n{\n \"analysis\": \"<1-2 sentence summary of the situation>\",\n \"subGoals\": [\n {\n \"priority\": 1,\n \"action\": \"<what to do>\",\n \"slug\": \"<customer-slug>\",\n \"dealName\": \"<deal name>\",\n \"why\": \"<why this deal matters for the goal>\",\n \"nextStep\": \"<concrete next action with deadline>\",\n \"targetDelta\": <expected revenue contribution in euros>\n }\n ],\n \"probabilisticOutcome\": \"<P50 forecast summary after actions>\"\n}`;\n}\n\nexport function parseLlmDecomposition(\n response: string,\n fallback: GoalDecomposition\n): GoalDecomposition {\n try {\n const match = response.match(/\\{[\\s\\S]*\\}/);\n if (!match) return fallback;\n const parsed = JSON.parse(match[0]) as Partial<{\n analysis: string;\n subGoals: unknown[];\n probabilisticOutcome: string;\n }>;\n if (!parsed.analysis || !Array.isArray(parsed.subGoals)) return fallback;\n return {\n analysis: parsed.analysis,\n currentPipeline: fallback.currentPipeline,\n gap: fallback.gap,\n subGoals: (parsed.subGoals as Partial<GoalSubGoal>[]).map((s, i) => ({\n priority: s.priority ?? i + 1,\n action: s.action ?? \"\",\n slug: s.slug ?? \"_all\",\n ...(s.dealName ? { dealName: s.dealName } : {}),\n why: s.why ?? \"\",\n nextStep: s.nextStep ?? \"\",\n targetDelta: s.targetDelta ?? 0,\n ...(s.playbookName ? { playbookName: s.playbookName } : {}),\n })),\n probabilisticOutcome: parsed.probabilisticOutcome ?? fallback.probabilisticOutcome,\n decomposedAt: fallback.decomposedAt,\n };\n } catch {\n return fallback;\n }\n}\n\n// ─── pursueGoal ───────────────────────────────────────────────────────────────\n\nexport async function pursueGoal(\n dataDir: string,\n input: { description: string; deadline: string; context?: string },\n options: {\n llmFn?: (prompt: string) => Promise<string>;\n buildInputFn?: BuildInputFn;\n today?: string;\n actor?: string;\n } = {}\n): Promise<Goal> {\n guardIsoDate(input.deadline, \"deadline\");\n const today = options.today ?? new Date().toISOString().slice(0, 10);\n const actor = options.actor ?? getActor();\n\n const buildFn =\n options.buildInputFn ??\n ((async (dir, horizon, t) => {\n const { buildSimulationInput } = await import(\"./revenue-simulation.js\");\n return buildSimulationInput(dir, horizon, t);\n }) as BuildInputFn);\n\n const simInput = await buildFn(dataDir, \"quarter\", today);\n const simResult = runSimulation(simInput);\n const currentP50 = simResult.p50;\n const deals = simInput.deals;\n\n const target = parseTargetFromDescription(input.description);\n const type = inferGoalType(input.description);\n const metric = inferMetric(type);\n\n const ruleBasedDecomp = decomposeGoalRuleBased(deals, target, currentP50, today);\n\n let decomposition = ruleBasedDecomp;\n const llmFn = options.llmFn ?? callLlm;\n if (options.llmFn !== undefined) {\n const prompt = buildDecompositionPrompt(\n input.description,\n target,\n input.deadline,\n currentP50,\n deals,\n today\n );\n const response = await llmFn(prompt);\n decomposition = parseLlmDecomposition(response, ruleBasedDecomp);\n }\n\n const now = new Date().toISOString();\n const goal: Goal = {\n id: makeGoalId(),\n description: input.description,\n type,\n target,\n metric,\n deadline: input.deadline,\n decomposition,\n progress: 0,\n status: \"active\",\n createdAt: now,\n updatedAt: now,\n actor,\n };\n\n await withJsonFile<{ goals: Goal[]; updatedAt: string }>(goalsPath(dataDir), (current) => {\n const existing: Goal[] = Array.isArray(current?.goals) ? current.goals : [];\n return { goals: [...existing, goal], updatedAt: new Date().toISOString() };\n });\n return goal;\n}\n\n// ─── Goal management ──────────────────────────────────────────────────────────\n\nexport function getActiveGoals(dataDir: string): Goal[] {\n return readGoals(dataDir).filter((g) => g.status === \"active\");\n}\n\nexport async function updateGoalProgress(\n dataDir: string,\n goalId: string,\n progress: number\n): Promise<Goal | null> {\n let updated: Goal | null = null;\n await withJsonFile<{ goals: Goal[]; updatedAt: string }>(goalsPath(dataDir), (current) => {\n const goals: Goal[] = Array.isArray(current?.goals) ? [...current.goals] : [];\n const idx = goals.findIndex((g) => g.id === goalId);\n if (idx >= 0) {\n updated = { ...goals[idx]!, progress, updatedAt: new Date().toISOString() };\n goals[idx] = updated;\n }\n return { goals, updatedAt: new Date().toISOString() };\n });\n return updated;\n}\n\nexport async function cancelGoal(dataDir: string, goalId: string): Promise<Goal | null> {\n let cancelled: Goal | null = null;\n await withJsonFile<{ goals: Goal[]; updatedAt: string }>(goalsPath(dataDir), (current) => {\n const goals: Goal[] = Array.isArray(current?.goals) ? [...current.goals] : [];\n const idx = goals.findIndex((g) => g.id === goalId);\n if (idx >= 0) {\n cancelled = {\n ...goals[idx]!,\n status: \"cancelled\" as const,\n updatedAt: new Date().toISOString(),\n };\n goals[idx] = cancelled;\n }\n return { goals, updatedAt: new Date().toISOString() };\n });\n return cancelled;\n}\n\n// ─── Pipeline-driven progress sync ────────────────────────────────────────────\n\nexport interface SyncResult {\n updated: string[];\n skipped: number;\n}\n\nexport async function syncGoalProgressFromPipeline(\n dataDir: string,\n _today?: string\n): Promise<SyncResult> {\n const activeGoals = getActiveGoals(dataDir);\n const revenueGoals = activeGoals.filter((g) => g.metric === \"revenue\" && g.target > 0);\n\n if (revenueGoals.length === 0) return { updated: [], skipped: activeGoals.length };\n\n let totalWon = 0;\n for (const slug of listCustomerSlugs(dataDir)) {\n const deals = await readPipeline(dataDir, slug).catch(() => []);\n for (const deal of deals) {\n if (deal.stage === \"won\") totalWon += deal.value ?? 0;\n }\n }\n\n const updated: string[] = [];\n for (const goal of revenueGoals) {\n const progress = Math.min(100, Math.round((totalWon / goal.target) * 100));\n const result = await updateGoalProgress(dataDir, goal.id, progress);\n if (result) updated.push(goal.id);\n }\n\n return { updated, skipped: activeGoals.length - revenueGoals.length };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { g as writeGoals, m as syncGoalProgressFromPipeline, p as readGoals } from "./goal-engine-KpBftn4V.js";
1
+ import { g as writeGoals, m as syncGoalProgressFromPipeline, p as readGoals } from "./goal-engine-BbroPhqm.js";
2
2
  export { readGoals, syncGoalProgressFromPipeline, writeGoals };
@@ -1,5 +1,5 @@
1
- import { r as readInteractions, t as appendInteraction } from "./interactions-writer-SLHnoEeE.js";
2
- import { n as indexInLanceDB } from "./lancedb-rlvWoPwl.js";
1
+ import { i as readInteractions, n as appendInteraction } from "./interactions-writer-B8XAzdqR.js";
2
+ import { n as indexInLanceDB } from "./lancedb-CuHKNsNZ.js";
3
3
  import path from "path";
4
4
  import fs from "fs";
5
5
  //#region src/sync/google-drive-sync.ts
@@ -102,4 +102,4 @@ async function syncGoogleDriveFiles(opts) {
102
102
  //#endregion
103
103
  export { syncGoogleDriveFiles };
104
104
 
105
- //# sourceMappingURL=google-drive-sync-DEPcqFca.js.map
105
+ //# sourceMappingURL=google-drive-sync-B_I1d54Y.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"google-drive-sync-DEPcqFca.js","names":[],"sources":["../src/sync/google-drive-sync.ts"],"sourcesContent":["import { appendInteraction } from \"../fs/interactions-writer.js\";\nimport { indexInLanceDB } from \"../core/lancedb.js\";\nimport { readInteractions } from \"../fs/interactions-writer.js\";\nimport path from \"path\";\nimport fs from \"fs\";\n\nexport interface DriveFile {\n id: string;\n name: string;\n mimeType: string;\n webViewLink?: string;\n modifiedTime?: string;\n size?: string;\n}\n\nexport interface DriveFilesResponse {\n files: DriveFile[];\n nextPageToken?: string;\n}\n\nexport interface DriveSyncOptions {\n slug: string;\n dataDir: string;\n accessToken: string;\n customerName?: string; // If not provided, use slug\n maxFiles?: number;\n}\n\nexport interface DriveSyncResult {\n synced: number;\n skipped: number;\n errors: string[];\n}\n\nconst GOOGLE_DOC_MIME = \"application/vnd.google-apps.document\";\nconst DRIVE_API_BASE = \"https://www.googleapis.com/drive/v3\";\n\nexport async function syncGoogleDriveFiles(opts: DriveSyncOptions): Promise<DriveSyncResult> {\n const { slug, dataDir, accessToken } = opts;\n const searchName = opts.customerName ?? slug;\n const maxFiles = opts.maxFiles ?? 200;\n\n const result: DriveSyncResult = { synced: 0, skipped: 0, errors: [] };\n\n // Load existing interactions to detect already-synced files\n let existingInteractions = \"\";\n try {\n existingInteractions = await readInteractions(dataDir, slug);\n } catch {\n existingInteractions = \"\";\n }\n\n const encodedQuery = encodeURIComponent(\n `name contains \"${searchName}\" and mimeType!=\"application/vnd.google-apps.folder\"`\n );\n const fields = encodeURIComponent(\n \"files(id,name,mimeType,webViewLink,modifiedTime,size),nextPageToken\"\n );\n\n let pageToken: string | undefined;\n let totalFetched = 0;\n\n do {\n let url = `${DRIVE_API_BASE}/files?q=${encodedQuery}&fields=${fields}&pageSize=50`;\n if (pageToken) {\n url += `&pageToken=${encodeURIComponent(pageToken)}`;\n }\n\n let response: Response;\n try {\n response = await fetch(url, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n } catch (err) {\n result.errors.push(`Drive API request failed: ${(err as Error).message}`);\n break;\n }\n\n if (!response.ok) {\n result.errors.push(\n `Drive API error ${response.status}: ${await response.text().catch(() => \"unknown\")}`\n );\n break;\n }\n\n let data: DriveFilesResponse;\n try {\n data = (await response.json()) as DriveFilesResponse;\n } catch (err) {\n result.errors.push(`Failed to parse Drive API response: ${(err as Error).message}`);\n break;\n }\n\n const files = data.files ?? [];\n pageToken = data.nextPageToken;\n\n for (const file of files) {\n if (totalFetched >= maxFiles) break;\n totalFetched++;\n\n const sourceRef = `google://drive/${file.id}`;\n\n // Skip already-synced files\n if (existingInteractions.includes(sourceRef)) {\n result.skipped++;\n continue;\n }\n\n try {\n if (file.mimeType === GOOGLE_DOC_MIME) {\n // Export Google Doc as plain text\n const exportUrl = `${DRIVE_API_BASE}/files/${file.id}/export?mimeType=${encodeURIComponent(\"text/plain\")}`;\n const exportRes = await fetch(exportUrl, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n if (!exportRes.ok) {\n result.errors.push(`Failed to export doc '${file.name}': HTTP ${exportRes.status}`);\n continue;\n }\n\n const text = await exportRes.text();\n\n // Save to attachments directory\n const attachmentsDir = path.join(dataDir, \"customers\", slug, \"attachments\");\n fs.mkdirSync(attachmentsDir, { recursive: true });\n const safeFilename = file.name.replace(/[/\\\\?%*:|\"<>]/g, \"-\") + \".txt\";\n fs.writeFileSync(path.join(attachmentsDir, safeFilename), text, \"utf-8\");\n\n // Append interaction\n await appendInteraction(dataDir, slug, {\n date: file.modifiedTime\n ? file.modifiedTime.slice(0, 10)\n : new Date().toISOString().slice(0, 10),\n type: \"Note\",\n with: \"Google Drive\",\n summary: `Attachment: ${file.name}`,\n nextSteps: [],\n sourceRef,\n synced: new Date().toISOString(),\n });\n\n // Index in LanceDB\n const lanceOpts: { date?: string; type?: string } = { type: \"attachment\" };\n if (file.modifiedTime) lanceOpts.date = file.modifiedTime.slice(0, 10);\n await indexInLanceDB(dataDir, slug, text.slice(0, 2000), sourceRef, lanceOpts);\n } else {\n // Non-Doc file: record via appendInteraction (no binary download)\n await appendInteraction(dataDir, slug, {\n date: file.modifiedTime\n ? file.modifiedTime.slice(0, 10)\n : new Date().toISOString().slice(0, 10),\n type: \"Note\",\n with: \"Google Drive\",\n summary: `Attachment: ${file.name}${file.webViewLink ? ` — ${file.webViewLink}` : \"\"}`,\n nextSteps: [],\n sourceRef,\n synced: new Date().toISOString(),\n });\n }\n\n result.synced++;\n existingInteractions += sourceRef; // prevent double-sync within same run\n } catch (err) {\n result.errors.push(`Error processing '${file.name}': ${(err as Error).message}`);\n }\n }\n\n if (totalFetched >= maxFiles) break;\n } while (pageToken);\n\n return result;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"google-drive-sync-B_I1d54Y.js","names":[],"sources":["../src/sync/google-drive-sync.ts"],"sourcesContent":["import { appendInteraction } from \"../fs/interactions-writer.js\";\nimport { indexInLanceDB } from \"../core/lancedb.js\";\nimport { readInteractions } from \"../fs/interactions-writer.js\";\nimport path from \"path\";\nimport fs from \"fs\";\n\nexport interface DriveFile {\n id: string;\n name: string;\n mimeType: string;\n webViewLink?: string;\n modifiedTime?: string;\n size?: string;\n}\n\nexport interface DriveFilesResponse {\n files: DriveFile[];\n nextPageToken?: string;\n}\n\nexport interface DriveSyncOptions {\n slug: string;\n dataDir: string;\n accessToken: string;\n customerName?: string; // If not provided, use slug\n maxFiles?: number;\n}\n\nexport interface DriveSyncResult {\n synced: number;\n skipped: number;\n errors: string[];\n}\n\nconst GOOGLE_DOC_MIME = \"application/vnd.google-apps.document\";\nconst DRIVE_API_BASE = \"https://www.googleapis.com/drive/v3\";\n\nexport async function syncGoogleDriveFiles(opts: DriveSyncOptions): Promise<DriveSyncResult> {\n const { slug, dataDir, accessToken } = opts;\n const searchName = opts.customerName ?? slug;\n const maxFiles = opts.maxFiles ?? 200;\n\n const result: DriveSyncResult = { synced: 0, skipped: 0, errors: [] };\n\n // Load existing interactions to detect already-synced files\n let existingInteractions = \"\";\n try {\n existingInteractions = await readInteractions(dataDir, slug);\n } catch {\n existingInteractions = \"\";\n }\n\n const encodedQuery = encodeURIComponent(\n `name contains \"${searchName}\" and mimeType!=\"application/vnd.google-apps.folder\"`\n );\n const fields = encodeURIComponent(\n \"files(id,name,mimeType,webViewLink,modifiedTime,size),nextPageToken\"\n );\n\n let pageToken: string | undefined;\n let totalFetched = 0;\n\n do {\n let url = `${DRIVE_API_BASE}/files?q=${encodedQuery}&fields=${fields}&pageSize=50`;\n if (pageToken) {\n url += `&pageToken=${encodeURIComponent(pageToken)}`;\n }\n\n let response: Response;\n try {\n response = await fetch(url, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n } catch (err) {\n result.errors.push(`Drive API request failed: ${(err as Error).message}`);\n break;\n }\n\n if (!response.ok) {\n result.errors.push(\n `Drive API error ${response.status}: ${await response.text().catch(() => \"unknown\")}`\n );\n break;\n }\n\n let data: DriveFilesResponse;\n try {\n data = (await response.json()) as DriveFilesResponse;\n } catch (err) {\n result.errors.push(`Failed to parse Drive API response: ${(err as Error).message}`);\n break;\n }\n\n const files = data.files ?? [];\n pageToken = data.nextPageToken;\n\n for (const file of files) {\n if (totalFetched >= maxFiles) break;\n totalFetched++;\n\n const sourceRef = `google://drive/${file.id}`;\n\n // Skip already-synced files\n if (existingInteractions.includes(sourceRef)) {\n result.skipped++;\n continue;\n }\n\n try {\n if (file.mimeType === GOOGLE_DOC_MIME) {\n // Export Google Doc as plain text\n const exportUrl = `${DRIVE_API_BASE}/files/${file.id}/export?mimeType=${encodeURIComponent(\"text/plain\")}`;\n const exportRes = await fetch(exportUrl, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n if (!exportRes.ok) {\n result.errors.push(`Failed to export doc '${file.name}': HTTP ${exportRes.status}`);\n continue;\n }\n\n const text = await exportRes.text();\n\n // Save to attachments directory\n const attachmentsDir = path.join(dataDir, \"customers\", slug, \"attachments\");\n fs.mkdirSync(attachmentsDir, { recursive: true });\n const safeFilename = file.name.replace(/[/\\\\?%*:|\"<>]/g, \"-\") + \".txt\";\n fs.writeFileSync(path.join(attachmentsDir, safeFilename), text, \"utf-8\");\n\n // Append interaction\n await appendInteraction(dataDir, slug, {\n date: file.modifiedTime\n ? file.modifiedTime.slice(0, 10)\n : new Date().toISOString().slice(0, 10),\n type: \"Note\",\n with: \"Google Drive\",\n summary: `Attachment: ${file.name}`,\n nextSteps: [],\n sourceRef,\n synced: new Date().toISOString(),\n });\n\n // Index in LanceDB\n const lanceOpts: { date?: string; type?: string } = { type: \"attachment\" };\n if (file.modifiedTime) lanceOpts.date = file.modifiedTime.slice(0, 10);\n await indexInLanceDB(dataDir, slug, text.slice(0, 2000), sourceRef, lanceOpts);\n } else {\n // Non-Doc file: record via appendInteraction (no binary download)\n await appendInteraction(dataDir, slug, {\n date: file.modifiedTime\n ? file.modifiedTime.slice(0, 10)\n : new Date().toISOString().slice(0, 10),\n type: \"Note\",\n with: \"Google Drive\",\n summary: `Attachment: ${file.name}${file.webViewLink ? ` — ${file.webViewLink}` : \"\"}`,\n nextSteps: [],\n sourceRef,\n synced: new Date().toISOString(),\n });\n }\n\n result.synced++;\n existingInteractions += sourceRef; // prevent double-sync within same run\n } catch (err) {\n result.errors.push(`Error processing '${file.name}': ${(err as Error).message}`);\n }\n }\n\n if (totalFetched >= maxFiles) break;\n } while (pageToken);\n\n return result;\n}\n"],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ //#region src/sync/converters/html.ts
2
+ /**
3
+ * Convert an HTML fragment to Markdown using Turndown with the GitHub-flavored
4
+ * plugin (tables, strikethrough, task lists). Turndown and the plugin are
5
+ * loaded lazily so they stay out of the light default code path.
6
+ */
7
+ async function htmlToMarkdown(html) {
8
+ const TurndownService = (await import("turndown")).default;
9
+ const { gfm } = await import("@joplin/turndown-plugin-gfm");
10
+ const service = new TurndownService({
11
+ headingStyle: "atx",
12
+ codeBlockStyle: "fenced",
13
+ bulletListMarker: "-"
14
+ });
15
+ service.use(gfm);
16
+ return service.turndown(html).trim();
17
+ }
18
+ const htmlConverter = {
19
+ name: "html",
20
+ extensions: [
21
+ "html",
22
+ "htm",
23
+ "xhtml"
24
+ ],
25
+ mimeTypes: ["text/html", "application/xhtml+xml"],
26
+ async convert(buffer) {
27
+ return {
28
+ markdown: await htmlToMarkdown(buffer.toString("utf-8")),
29
+ meta: { format: "html" }
30
+ };
31
+ }
32
+ };
33
+ //#endregion
34
+ export { htmlToMarkdown as n, htmlConverter as t };
35
+
36
+ //# sourceMappingURL=html-BaeOCZKE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-BaeOCZKE.js","names":[],"sources":["../src/sync/converters/html.ts"],"sourcesContent":["// src/sync/converters/html.ts\nimport type { Converter, ConversionResult } from \"./types.js\";\n\n/**\n * Convert an HTML fragment to Markdown using Turndown with the GitHub-flavored\n * plugin (tables, strikethrough, task lists). Turndown and the plugin are\n * loaded lazily so they stay out of the light default code path.\n */\nexport async function htmlToMarkdown(html: string): Promise<string> {\n const TurndownService = (await import(\"turndown\")).default;\n const { gfm } = await import(\"@joplin/turndown-plugin-gfm\");\n const service = new TurndownService({\n headingStyle: \"atx\",\n codeBlockStyle: \"fenced\",\n bulletListMarker: \"-\",\n });\n service.use(gfm);\n return service.turndown(html).trim();\n}\n\nexport const htmlConverter: Converter = {\n name: \"html\",\n extensions: [\"html\", \"htm\", \"xhtml\"],\n mimeTypes: [\"text/html\", \"application/xhtml+xml\"],\n async convert(buffer: Buffer): Promise<ConversionResult> {\n const markdown = await htmlToMarkdown(buffer.toString(\"utf-8\"));\n return { markdown, meta: { format: \"html\" } };\n },\n};\n"],"mappings":";;;;;;AAQA,eAAsB,eAAe,MAA+B;CAClE,MAAM,mBAAmB,MAAM,OAAO,aAAa;CACnD,MAAM,EAAE,QAAQ,MAAM,OAAO;CAC7B,MAAM,UAAU,IAAI,gBAAgB;EAClC,cAAc;EACd,gBAAgB;EAChB,kBAAkB;CACpB,CAAC;CACD,QAAQ,IAAI,GAAG;CACf,OAAO,QAAQ,SAAS,IAAI,EAAE,KAAK;AACrC;AAEA,MAAa,gBAA2B;CACtC,MAAM;CACN,YAAY;EAAC;EAAQ;EAAO;CAAO;CACnC,WAAW,CAAC,aAAa,uBAAuB;CAChD,MAAM,QAAQ,QAA2C;EAEvD,OAAO;GAAE,UAAA,MADc,eAAe,OAAO,SAAS,OAAO,CAAC;GAC3C,MAAM,EAAE,QAAQ,OAAO;EAAE;CAC9C;AACF"}
@@ -0,0 +1,47 @@
1
+ //#region src/sync/converters/html.ts
2
+ /**
3
+ * Convert an HTML fragment to Markdown using Turndown with the GitHub-flavored
4
+ * plugin (tables, strikethrough, task lists). Turndown and the plugin are
5
+ * loaded lazily so they stay out of the light default code path.
6
+ */
7
+ async function htmlToMarkdown(html) {
8
+ const TurndownService = (await import("turndown")).default;
9
+ const { gfm } = await import("@joplin/turndown-plugin-gfm");
10
+ const service = new TurndownService({
11
+ headingStyle: "atx",
12
+ codeBlockStyle: "fenced",
13
+ bulletListMarker: "-"
14
+ });
15
+ service.use(gfm);
16
+ return service.turndown(html).trim();
17
+ }
18
+ const htmlConverter = {
19
+ name: "html",
20
+ extensions: [
21
+ "html",
22
+ "htm",
23
+ "xhtml"
24
+ ],
25
+ mimeTypes: ["text/html", "application/xhtml+xml"],
26
+ async convert(buffer) {
27
+ return {
28
+ markdown: await htmlToMarkdown(buffer.toString("utf-8")),
29
+ meta: { format: "html" }
30
+ };
31
+ }
32
+ };
33
+ //#endregion
34
+ Object.defineProperty(exports, "htmlConverter", {
35
+ enumerable: true,
36
+ get: function() {
37
+ return htmlConverter;
38
+ }
39
+ });
40
+ Object.defineProperty(exports, "htmlToMarkdown", {
41
+ enumerable: true,
42
+ get: function() {
43
+ return htmlToMarkdown;
44
+ }
45
+ });
46
+
47
+ //# sourceMappingURL=html-CmOku6jS.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-CmOku6jS.cjs","names":[],"sources":["../src/sync/converters/html.ts"],"sourcesContent":["// src/sync/converters/html.ts\nimport type { Converter, ConversionResult } from \"./types.js\";\n\n/**\n * Convert an HTML fragment to Markdown using Turndown with the GitHub-flavored\n * plugin (tables, strikethrough, task lists). Turndown and the plugin are\n * loaded lazily so they stay out of the light default code path.\n */\nexport async function htmlToMarkdown(html: string): Promise<string> {\n const TurndownService = (await import(\"turndown\")).default;\n const { gfm } = await import(\"@joplin/turndown-plugin-gfm\");\n const service = new TurndownService({\n headingStyle: \"atx\",\n codeBlockStyle: \"fenced\",\n bulletListMarker: \"-\",\n });\n service.use(gfm);\n return service.turndown(html).trim();\n}\n\nexport const htmlConverter: Converter = {\n name: \"html\",\n extensions: [\"html\", \"htm\", \"xhtml\"],\n mimeTypes: [\"text/html\", \"application/xhtml+xml\"],\n async convert(buffer: Buffer): Promise<ConversionResult> {\n const markdown = await htmlToMarkdown(buffer.toString(\"utf-8\"));\n return { markdown, meta: { format: \"html\" } };\n },\n};\n"],"mappings":";;;;;;AAQA,eAAsB,eAAe,MAA+B;CAClE,MAAM,mBAAmB,MAAM,OAAO,aAAa;CACnD,MAAM,EAAE,QAAQ,MAAM,OAAO;CAC7B,MAAM,UAAU,IAAI,gBAAgB;EAClC,cAAc;EACd,gBAAgB;EAChB,kBAAkB;CACpB,CAAC;CACD,QAAQ,IAAI,GAAG;CACf,OAAO,QAAQ,SAAS,IAAI,EAAE,KAAK;AACrC;AAEA,MAAa,gBAA2B;CACtC,MAAM;CACN,YAAY;EAAC;EAAQ;EAAO;CAAO;CACnC,WAAW,CAAC,aAAa,uBAAuB;CAChD,MAAM,QAAQ,QAA2C;EAEvD,OAAO;GAAE,UAAA,MADc,eAAe,OAAO,SAAS,OAAO,CAAC;GAC3C,MAAM,EAAE,QAAQ,OAAO;EAAE;CAC9C;AACF"}
@@ -1,5 +1,5 @@
1
- import { i as readMainFacts, r as listCustomerSlugs } from "./customer-dir-DIylZ8Q6.js";
2
- import { n as findDuplicateClusters, r as normalizeDomain } from "./identity-CI6olMNm.js";
1
+ import { a as readMainFacts, i as listCustomerSlugs } from "./customer-dir-CkMMXhb0.js";
2
+ import { n as findDuplicateClusters, r as normalizeDomain } from "./identity-_uZ3Lbr2.js";
3
3
  //#region src/core/hygiene.ts
4
4
  async function scanHygiene(dataDir) {
5
5
  const issues = [];
@@ -35,4 +35,4 @@ async function scanHygiene(dataDir) {
35
35
  //#endregion
36
36
  export { scanHygiene };
37
37
 
38
- //# sourceMappingURL=hygiene-DZqfYpFf.js.map
38
+ //# sourceMappingURL=hygiene-DzQPnc6P.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hygiene-DZqfYpFf.js","names":[],"sources":["../src/core/hygiene.ts"],"sourcesContent":["import { readMainFacts, listCustomerSlugs } from \"../fs/customer-dir.js\";\nimport { findDuplicateClusters, normalizeDomain } from \"./identity.js\";\n\n/**\n * Data-hygiene agent (domino D5 / C5): scans customers for quality issues\n * (missing contact info, malformed fields, duplicates) and suggests fixes.\n * Fixes are meant to be applied through the approval gate (D4) — clean data\n * lifts the quality of every downstream AI feature.\n */\nexport type HygieneIssueType = \"missing_contact\" | \"format_domain\" | \"format_email\" | \"duplicate\";\n\nexport interface HygieneIssue {\n type: HygieneIssueType;\n slug: string;\n field?: string;\n detail: string;\n suggestedFix?: string;\n}\n\nexport async function scanHygiene(dataDir: string): Promise<HygieneIssue[]> {\n const issues: HygieneIssue[] = [];\n\n for (const slug of listCustomerSlugs(dataDir)) {\n const facts = await readMainFacts(dataDir, slug).catch(() => null);\n if (!facts) continue;\n\n if (!facts.domain && !facts.email) {\n issues.push({ type: \"missing_contact\", slug, detail: \"No domain or email\" });\n }\n if (facts.domain && /^https?:\\/\\/|^www\\./i.test(facts.domain)) {\n issues.push({\n type: \"format_domain\",\n slug,\n field: \"domain\",\n detail: `Domain not normalized: ${facts.domain}`,\n suggestedFix: normalizeDomain(facts.domain),\n });\n }\n if (facts.email && !facts.email.includes(\"@\")) {\n issues.push({\n type: \"format_email\",\n slug,\n field: \"email\",\n detail: `Email missing '@': ${facts.email}`,\n });\n }\n }\n\n // Duplicate clusters (reuse identity resolution)\n for (const cluster of await findDuplicateClusters(dataDir)) {\n for (const slug of cluster.slugs) {\n issues.push({\n type: \"duplicate\",\n slug,\n detail: `Shares canonical domain '${cluster.key}' with: ${cluster.slugs\n .filter((s) => s !== slug)\n .join(\", \")}`,\n });\n }\n }\n\n return issues;\n}\n"],"mappings":";;;AAmBA,eAAsB,YAAY,SAA0C;CAC1E,MAAM,SAAyB,CAAC;CAEhC,KAAK,MAAM,QAAQ,kBAAkB,OAAO,GAAG;EAC7C,MAAM,QAAQ,MAAM,cAAc,SAAS,IAAI,EAAE,YAAY,IAAI;EACjE,IAAI,CAAC,OAAO;EAEZ,IAAI,CAAC,MAAM,UAAU,CAAC,MAAM,OAC1B,OAAO,KAAK;GAAE,MAAM;GAAmB;GAAM,QAAQ;EAAqB,CAAC;EAE7E,IAAI,MAAM,UAAU,uBAAuB,KAAK,MAAM,MAAM,GAC1D,OAAO,KAAK;GACV,MAAM;GACN;GACA,OAAO;GACP,QAAQ,0BAA0B,MAAM;GACxC,cAAc,gBAAgB,MAAM,MAAM;EAC5C,CAAC;EAEH,IAAI,MAAM,SAAS,CAAC,MAAM,MAAM,SAAS,GAAG,GAC1C,OAAO,KAAK;GACV,MAAM;GACN;GACA,OAAO;GACP,QAAQ,sBAAsB,MAAM;EACtC,CAAC;CAEL;CAGA,KAAK,MAAM,WAAW,MAAM,sBAAsB,OAAO,GACvD,KAAK,MAAM,QAAQ,QAAQ,OACzB,OAAO,KAAK;EACV,MAAM;EACN;EACA,QAAQ,4BAA4B,QAAQ,IAAI,UAAU,QAAQ,MAC/D,QAAQ,MAAM,MAAM,IAAI,EACxB,KAAK,IAAI;CACd,CAAC;CAIL,OAAO;AACT"}
1
+ {"version":3,"file":"hygiene-DzQPnc6P.js","names":[],"sources":["../src/core/hygiene.ts"],"sourcesContent":["import { readMainFacts, listCustomerSlugs } from \"../fs/customer-dir.js\";\nimport { findDuplicateClusters, normalizeDomain } from \"./identity.js\";\n\n/**\n * Data-hygiene agent (domino D5 / C5): scans customers for quality issues\n * (missing contact info, malformed fields, duplicates) and suggests fixes.\n * Fixes are meant to be applied through the approval gate (D4) — clean data\n * lifts the quality of every downstream AI feature.\n */\nexport type HygieneIssueType = \"missing_contact\" | \"format_domain\" | \"format_email\" | \"duplicate\";\n\nexport interface HygieneIssue {\n type: HygieneIssueType;\n slug: string;\n field?: string;\n detail: string;\n suggestedFix?: string;\n}\n\nexport async function scanHygiene(dataDir: string): Promise<HygieneIssue[]> {\n const issues: HygieneIssue[] = [];\n\n for (const slug of listCustomerSlugs(dataDir)) {\n const facts = await readMainFacts(dataDir, slug).catch(() => null);\n if (!facts) continue;\n\n if (!facts.domain && !facts.email) {\n issues.push({ type: \"missing_contact\", slug, detail: \"No domain or email\" });\n }\n if (facts.domain && /^https?:\\/\\/|^www\\./i.test(facts.domain)) {\n issues.push({\n type: \"format_domain\",\n slug,\n field: \"domain\",\n detail: `Domain not normalized: ${facts.domain}`,\n suggestedFix: normalizeDomain(facts.domain),\n });\n }\n if (facts.email && !facts.email.includes(\"@\")) {\n issues.push({\n type: \"format_email\",\n slug,\n field: \"email\",\n detail: `Email missing '@': ${facts.email}`,\n });\n }\n }\n\n // Duplicate clusters (reuse identity resolution)\n for (const cluster of await findDuplicateClusters(dataDir)) {\n for (const slug of cluster.slugs) {\n issues.push({\n type: \"duplicate\",\n slug,\n detail: `Shares canonical domain '${cluster.key}' with: ${cluster.slugs\n .filter((s) => s !== slug)\n .join(\", \")}`,\n });\n }\n }\n\n return issues;\n}\n"],"mappings":";;;AAmBA,eAAsB,YAAY,SAA0C;CAC1E,MAAM,SAAyB,CAAC;CAEhC,KAAK,MAAM,QAAQ,kBAAkB,OAAO,GAAG;EAC7C,MAAM,QAAQ,MAAM,cAAc,SAAS,IAAI,EAAE,YAAY,IAAI;EACjE,IAAI,CAAC,OAAO;EAEZ,IAAI,CAAC,MAAM,UAAU,CAAC,MAAM,OAC1B,OAAO,KAAK;GAAE,MAAM;GAAmB;GAAM,QAAQ;EAAqB,CAAC;EAE7E,IAAI,MAAM,UAAU,uBAAuB,KAAK,MAAM,MAAM,GAC1D,OAAO,KAAK;GACV,MAAM;GACN;GACA,OAAO;GACP,QAAQ,0BAA0B,MAAM;GACxC,cAAc,gBAAgB,MAAM,MAAM;EAC5C,CAAC;EAEH,IAAI,MAAM,SAAS,CAAC,MAAM,MAAM,SAAS,GAAG,GAC1C,OAAO,KAAK;GACV,MAAM;GACN;GACA,OAAO;GACP,QAAQ,sBAAsB,MAAM;EACtC,CAAC;CAEL;CAGA,KAAK,MAAM,WAAW,MAAM,sBAAsB,OAAO,GACvD,KAAK,MAAM,QAAQ,QAAQ,OACzB,OAAO,KAAK;EACV,MAAM;EACN;EACA,QAAQ,4BAA4B,QAAQ,IAAI,UAAU,QAAQ,MAC/D,QAAQ,MAAM,MAAM,IAAI,EACxB,KAAK,IAAI;CACd,CAAC;CAIL,OAAO;AACT"}
@@ -0,0 +1,2 @@
1
+ import { n as findDuplicateClusters } from "./identity-_uZ3Lbr2.js";
2
+ export { findDuplicateClusters };
@@ -1,4 +1,4 @@
1
- import { i as readMainFacts, r as listCustomerSlugs } from "./customer-dir-DIylZ8Q6.js";
1
+ import { a as readMainFacts, i as listCustomerSlugs } from "./customer-dir-CkMMXhb0.js";
2
2
  //#region src/core/identity.ts
3
3
  /**
4
4
  * Identity resolution (CDP v1, N4-3): deterministic deduplication of customers
@@ -38,4 +38,4 @@ async function findDuplicateClusters(dataDir) {
38
38
  //#endregion
39
39
  export { findDuplicateClusters as n, normalizeDomain as r, canonicalKey as t };
40
40
 
41
- //# sourceMappingURL=identity-CI6olMNm.js.map
41
+ //# sourceMappingURL=identity-_uZ3Lbr2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"identity-CI6olMNm.js","names":[],"sources":["../src/core/identity.ts"],"sourcesContent":["import { readMainFacts, listCustomerSlugs } from \"../fs/customer-dir.js\";\n\n/**\n * Identity resolution (CDP v1, N4-3): deterministic deduplication of customers\n * by a canonical key (normalized domain, falling back to email domain). Reports\n * clusters of likely-duplicate customers so they can be merged.\n */\nexport function normalizeDomain(value: string): string {\n let v = value.trim().toLowerCase();\n if (v.includes(\"@\")) v = v.split(\"@\").pop() ?? v; // email -> domain\n v = v.replace(/^https?:\\/\\//, \"\").replace(/^www\\./, \"\");\n v = v.replace(/\\/.*$/, \"\"); // drop path\n return v;\n}\n\nexport interface DuplicateCluster {\n key: string;\n slugs: string[];\n}\n\n/** Canonical key for a customer: normalized domain, else email domain, else \"\". */\nexport async function canonicalKey(dataDir: string, slug: string): Promise<string> {\n const facts = await readMainFacts(dataDir, slug).catch(() => null);\n if (!facts) return \"\";\n if (facts.domain) return normalizeDomain(facts.domain);\n if (facts.email) return normalizeDomain(facts.email);\n return \"\";\n}\n\n/** Group customers by canonical key; clusters with ≥2 members are duplicates. */\nexport async function findDuplicateClusters(dataDir: string): Promise<DuplicateCluster[]> {\n const byKey = new Map<string, string[]>();\n for (const slug of listCustomerSlugs(dataDir)) {\n const key = await canonicalKey(dataDir, slug);\n if (!key) continue;\n byKey.set(key, [...(byKey.get(key) ?? []), slug]);\n }\n const clusters: DuplicateCluster[] = [];\n for (const [key, slugs] of byKey) {\n if (slugs.length >= 2) clusters.push({ key, slugs });\n }\n return clusters;\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,gBAAgB,OAAuB;CACrD,IAAI,IAAI,MAAM,KAAK,EAAE,YAAY;CACjC,IAAI,EAAE,SAAS,GAAG,GAAG,IAAI,EAAE,MAAM,GAAG,EAAE,IAAI,KAAK;CAC/C,IAAI,EAAE,QAAQ,gBAAgB,EAAE,EAAE,QAAQ,UAAU,EAAE;CACtD,IAAI,EAAE,QAAQ,SAAS,EAAE;CACzB,OAAO;AACT;;AAQA,eAAsB,aAAa,SAAiB,MAA+B;CACjF,MAAM,QAAQ,MAAM,cAAc,SAAS,IAAI,EAAE,YAAY,IAAI;CACjE,IAAI,CAAC,OAAO,OAAO;CACnB,IAAI,MAAM,QAAQ,OAAO,gBAAgB,MAAM,MAAM;CACrD,IAAI,MAAM,OAAO,OAAO,gBAAgB,MAAM,KAAK;CACnD,OAAO;AACT;;AAGA,eAAsB,sBAAsB,SAA8C;CACxF,MAAM,wBAAQ,IAAI,IAAsB;CACxC,KAAK,MAAM,QAAQ,kBAAkB,OAAO,GAAG;EAC7C,MAAM,MAAM,MAAM,aAAa,SAAS,IAAI;EAC5C,IAAI,CAAC,KAAK;EACV,MAAM,IAAI,KAAK,CAAC,GAAI,MAAM,IAAI,GAAG,KAAK,CAAC,GAAI,IAAI,CAAC;CAClD;CACA,MAAM,WAA+B,CAAC;CACtC,KAAK,MAAM,CAAC,KAAK,UAAU,OACzB,IAAI,MAAM,UAAU,GAAG,SAAS,KAAK;EAAE;EAAK;CAAM,CAAC;CAErD,OAAO;AACT"}
1
+ {"version":3,"file":"identity-_uZ3Lbr2.js","names":[],"sources":["../src/core/identity.ts"],"sourcesContent":["import { readMainFacts, listCustomerSlugs } from \"../fs/customer-dir.js\";\n\n/**\n * Identity resolution (CDP v1, N4-3): deterministic deduplication of customers\n * by a canonical key (normalized domain, falling back to email domain). Reports\n * clusters of likely-duplicate customers so they can be merged.\n */\nexport function normalizeDomain(value: string): string {\n let v = value.trim().toLowerCase();\n if (v.includes(\"@\")) v = v.split(\"@\").pop() ?? v; // email -> domain\n v = v.replace(/^https?:\\/\\//, \"\").replace(/^www\\./, \"\");\n v = v.replace(/\\/.*$/, \"\"); // drop path\n return v;\n}\n\nexport interface DuplicateCluster {\n key: string;\n slugs: string[];\n}\n\n/** Canonical key for a customer: normalized domain, else email domain, else \"\". */\nexport async function canonicalKey(dataDir: string, slug: string): Promise<string> {\n const facts = await readMainFacts(dataDir, slug).catch(() => null);\n if (!facts) return \"\";\n if (facts.domain) return normalizeDomain(facts.domain);\n if (facts.email) return normalizeDomain(facts.email);\n return \"\";\n}\n\n/** Group customers by canonical key; clusters with ≥2 members are duplicates. */\nexport async function findDuplicateClusters(dataDir: string): Promise<DuplicateCluster[]> {\n const byKey = new Map<string, string[]>();\n for (const slug of listCustomerSlugs(dataDir)) {\n const key = await canonicalKey(dataDir, slug);\n if (!key) continue;\n byKey.set(key, [...(byKey.get(key) ?? []), slug]);\n }\n const clusters: DuplicateCluster[] = [];\n for (const [key, slugs] of byKey) {\n if (slugs.length >= 2) clusters.push({ key, slugs });\n }\n return clusters;\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,gBAAgB,OAAuB;CACrD,IAAI,IAAI,MAAM,KAAK,EAAE,YAAY;CACjC,IAAI,EAAE,SAAS,GAAG,GAAG,IAAI,EAAE,MAAM,GAAG,EAAE,IAAI,KAAK;CAC/C,IAAI,EAAE,QAAQ,gBAAgB,EAAE,EAAE,QAAQ,UAAU,EAAE;CACtD,IAAI,EAAE,QAAQ,SAAS,EAAE;CACzB,OAAO;AACT;;AAQA,eAAsB,aAAa,SAAiB,MAA+B;CACjF,MAAM,QAAQ,MAAM,cAAc,SAAS,IAAI,EAAE,YAAY,IAAI;CACjE,IAAI,CAAC,OAAO,OAAO;CACnB,IAAI,MAAM,QAAQ,OAAO,gBAAgB,MAAM,MAAM;CACrD,IAAI,MAAM,OAAO,OAAO,gBAAgB,MAAM,KAAK;CACnD,OAAO;AACT;;AAGA,eAAsB,sBAAsB,SAA8C;CACxF,MAAM,wBAAQ,IAAI,IAAsB;CACxC,KAAK,MAAM,QAAQ,kBAAkB,OAAO,GAAG;EAC7C,MAAM,MAAM,MAAM,aAAa,SAAS,IAAI;EAC5C,IAAI,CAAC,KAAK;EACV,MAAM,IAAI,KAAK,CAAC,GAAI,MAAM,IAAI,GAAG,KAAK,CAAC,GAAI,IAAI,CAAC;CAClD;CACA,MAAM,WAA+B,CAAC;CACtC,KAAK,MAAM,CAAC,KAAK,UAAU,OACzB,IAAI,MAAM,UAAU,GAAG,SAAS,KAAK;EAAE;EAAK;CAAM,CAAC;CAErD,OAAO;AACT"}
@@ -1,3 +1,7 @@
1
+ import { t as assertSafeSlug } from "./customer-dir-CkMMXhb0.js";
2
+ import { t as writeFileAtomic } from "./atomic-write-8yjqqLtS.js";
3
+ import { i as writeJsonFile, n as readJsonFile } from "./json-store-WWsFzXub.js";
4
+ import { t as escapeRegExp } from "./regex-Jt5DatPi.js";
1
5
  import path from "path";
2
6
  import fs from "fs";
3
7
  import { z } from "zod";
@@ -64,20 +68,15 @@ function contactsPath(dataDir, slug) {
64
68
  return path.join(dataDir, "customers", slug, "contacts.json");
65
69
  }
66
70
  function listContacts(dataDir, slug) {
67
- const p = contactsPath(dataDir, slug);
68
- if (!fs.existsSync(p)) return [];
69
- try {
70
- const raw = JSON.parse(fs.readFileSync(p, "utf-8"));
71
- if (!Array.isArray(raw)) return [];
72
- return raw.flatMap((item) => {
73
- const r = CustomerContactSchema.safeParse(item);
74
- return r.success ? [r.data] : [];
75
- });
76
- } catch {
77
- return [];
78
- }
71
+ const raw = readJsonFile(contactsPath(dataDir, slug), []);
72
+ if (!Array.isArray(raw)) return [];
73
+ return raw.flatMap((item) => {
74
+ const r = CustomerContactSchema.safeParse(item);
75
+ return r.success ? [r.data] : [];
76
+ });
79
77
  }
80
78
  function upsertContact(dataDir, slug, contact) {
79
+ assertSafeSlug(slug);
81
80
  const contacts = listContacts(dataDir, slug);
82
81
  const idx = contacts.findIndex((c) => c.email.toLowerCase() === contact.email.toLowerCase());
83
82
  if (idx >= 0) contacts[idx] = {
@@ -88,9 +87,7 @@ function upsertContact(dataDir, slug, contact) {
88
87
  if (contact.isPrimary) {
89
88
  for (const c of contacts) if (c.email.toLowerCase() !== contact.email.toLowerCase()) c.isPrimary = false;
90
89
  }
91
- const dir = path.dirname(contactsPath(dataDir, slug));
92
- fs.mkdirSync(dir, { recursive: true });
93
- fs.writeFileSync(contactsPath(dataDir, slug), JSON.stringify(contacts, null, 2), "utf-8");
90
+ writeJsonFile(contactsPath(dataDir, slug), contacts);
94
91
  }
95
92
  //#endregion
96
93
  //#region src/commands/import-hubspot.ts
@@ -195,7 +192,7 @@ function ensureCustomer(dataDir, name, domain, email, dryRun) {
195
192
  };
196
193
  fs.mkdirSync(customerDir, { recursive: true });
197
194
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
198
- const lines = [
195
+ writeFileAtomic(mainFactsPath, `${[
199
196
  "---",
200
197
  `name: ${name}`,
201
198
  domain ? `domain: ${domain}` : null,
@@ -207,11 +204,10 @@ function ensureCustomer(dataDir, name, domain, email, dryRun) {
207
204
  "tags: []",
208
205
  "currency: EUR",
209
206
  "---"
210
- ].filter(Boolean).join("\n");
211
- fs.writeFileSync(mainFactsPath, `${lines}\n\n# Customer: ${name}\n`, "utf-8");
212
- fs.writeFileSync(path.join(customerDir, "interactions.md"), `# Interactions — ${name}\n\n`, "utf-8");
213
- fs.writeFileSync(path.join(customerDir, "pipeline.md"), `# Pipeline — ${name}\n\n`, "utf-8");
214
- fs.writeFileSync(path.join(customerDir, "sources.json"), JSON.stringify({
207
+ ].filter(Boolean).join("\n")}\n\n# Customer: ${name}\n`);
208
+ writeFileAtomic(path.join(customerDir, "interactions.md"), `# Interactions — ${name}\n\n`);
209
+ writeFileAtomic(path.join(customerDir, "pipeline.md"), `# Pipeline — ${name}\n\n`);
210
+ writeJsonFile(path.join(customerDir, "sources.json"), {
215
211
  gmail: {
216
212
  query: domain ? `from:${domain} OR to:${domain}` : email ? `from:${email} OR to:${email}` : "",
217
213
  enabled: true
@@ -221,7 +217,7 @@ function ensureCustomer(dataDir, name, domain, email, dryRun) {
221
217
  extensions: [".txt", ".vtt"],
222
218
  enabled: false
223
219
  }
224
- }, null, 2), "utf-8");
220
+ });
225
221
  return {
226
222
  slug,
227
223
  created: true
@@ -231,18 +227,23 @@ function readMainFactsRaw(dataDir, slug) {
231
227
  const p = path.join(dataDir, "customers", slug, "main_facts.md");
232
228
  return fs.existsSync(p) ? fs.readFileSync(p, "utf-8") : "";
233
229
  }
234
- function updateMainFactsField(dataDir, slug, field, value) {
230
+ /** Patch several frontmatter fields in main_facts.md with a single read+write. */
231
+ function updateMainFactsFields(dataDir, slug, fields) {
232
+ const entries = Object.entries(fields).filter((e) => e[1] !== void 0 && e[1] !== "");
233
+ if (entries.length === 0) return;
235
234
  const p = path.join(dataDir, "customers", slug, "main_facts.md");
236
235
  if (!fs.existsSync(p)) return;
237
236
  let content = fs.readFileSync(p, "utf-8");
238
- const regex = new RegExp(`^${field}:.*$`, "m");
239
- if (regex.test(content)) content = content.replace(regex, `${field}: ${value}`);
240
- else {
241
- const firstDash = content.indexOf("---");
242
- const secondDash = content.indexOf("---", firstDash + 3);
243
- if (secondDash >= 0) content = content.slice(0, secondDash) + `${field}: ${value}\n` + content.slice(secondDash);
237
+ for (const [field, value] of entries) {
238
+ const regex = new RegExp(`^${escapeRegExp(field)}:.*$`, "m");
239
+ if (regex.test(content)) content = content.replace(regex, `${field}: ${value}`);
240
+ else {
241
+ const firstDash = content.indexOf("---");
242
+ const secondDash = content.indexOf("---", firstDash + 3);
243
+ if (secondDash >= 0) content = content.slice(0, secondDash) + `${field}: ${value}\n` + content.slice(secondDash);
244
+ }
244
245
  }
245
- fs.writeFileSync(p, content, "utf-8");
246
+ writeFileAtomic(p, content);
246
247
  }
247
248
  function saveCustomProperties(dataDir, slug, props) {
248
249
  if (Object.keys(props).length === 0) return;
@@ -253,15 +254,14 @@ function saveCustomProperties(dataDir, slug, props) {
253
254
  } catch {
254
255
  existing = {};
255
256
  }
256
- const merged = {
257
+ writeJsonFile(p, {
257
258
  source: "hubspot-import",
258
259
  importedAt: (/* @__PURE__ */ new Date()).toISOString(),
259
260
  properties: {
260
261
  ...existing["properties"] ?? {},
261
262
  ...props
262
263
  }
263
- };
264
- fs.writeFileSync(p, JSON.stringify(merged, null, 2), "utf-8");
264
+ });
265
265
  }
266
266
  function progressPath(dataDir) {
267
267
  return path.join(dataDir, ".agentic", "import-progress.json");
@@ -277,7 +277,7 @@ function readProgress(dataDir) {
277
277
  }
278
278
  function writeProgress(dataDir, progress) {
279
279
  fs.mkdirSync(path.dirname(progressPath(dataDir)), { recursive: true });
280
- fs.writeFileSync(progressPath(dataDir), JSON.stringify(progress, null, 2), "utf-8");
280
+ writeJsonFile(progressPath(dataDir), progress);
281
281
  }
282
282
  function clearProgress(dataDir) {
283
283
  const p = progressPath(dataDir);
@@ -387,16 +387,18 @@ async function runHubSpotCsvImport(exportDir, dataDir, opts = {}) {
387
387
  companySlugMap.set(name.toLowerCase(), slug);
388
388
  result.companiesProcessed++;
389
389
  if (!dryRun && created) {
390
+ const factsPatch = {};
390
391
  for (const [hsKey, dxKey] of Object.entries(COMPANY_FIELD_MAP)) {
391
392
  const val = row[hsKey] ?? "";
392
- if (val) updateMainFactsField(dataDir, slug, dxKey, val);
393
+ if (val) factsPatch[dxKey] = val;
393
394
  }
394
395
  const ownerEmail = row["hubspot_owner_email"] ?? row["HubSpot Owner Email"] ?? "";
395
396
  if (ownerEmail && ownerMap[ownerEmail]) {
396
- updateMainFactsField(dataDir, slug, "assigned_rep", ownerMap[ownerEmail]);
397
+ factsPatch["assigned_rep"] = ownerMap[ownerEmail];
397
398
  result.ownersResolved++;
398
399
  }
399
- if (hubspotId) updateMainFactsField(dataDir, slug, "hubspot_company_id", hubspotId);
400
+ if (hubspotId) factsPatch["hubspot_company_id"] = hubspotId;
401
+ updateMainFactsFields(dataDir, slug, factsPatch);
400
402
  const customProps = {};
401
403
  for (const [key, val] of Object.entries(row)) if (!KNOWN_COMPANY_COLUMNS.has(key) && val) customProps[key] = val;
402
404
  if (Object.keys(customProps).length > 0) {
@@ -465,14 +467,16 @@ async function runHubSpotCsvImport(exportDir, dataDir, opts = {}) {
465
467
  } catch {}
466
468
  }
467
469
  const existing = readMainFactsRaw(dataDir, slug);
468
- if (email && !existing.includes("email:")) updateMainFactsField(dataDir, slug, "email", email);
469
- if (phone && !existing.includes("phone:")) updateMainFactsField(dataDir, slug, "phone", phone);
470
- if (contactName && !existing.includes("primary_contact:")) updateMainFactsField(dataDir, slug, "primary_contact", contactName);
470
+ const factsPatch = {};
471
+ if (email && !existing.includes("email:")) factsPatch["email"] = email;
472
+ if (phone && !existing.includes("phone:")) factsPatch["phone"] = phone;
473
+ if (contactName && !existing.includes("primary_contact:")) factsPatch["primary_contact"] = contactName;
471
474
  const ownerEmail = row["contact_owner"] ?? row["Contact Owner"] ?? "";
472
475
  if (ownerEmail && ownerMap[ownerEmail] && !existing.includes("assigned_rep:")) {
473
- updateMainFactsField(dataDir, slug, "assigned_rep", ownerMap[ownerEmail]);
476
+ factsPatch["assigned_rep"] = ownerMap[ownerEmail];
474
477
  result.ownersResolved++;
475
478
  }
479
+ updateMainFactsFields(dataDir, slug, factsPatch);
476
480
  }
477
481
  if (email) emailSlugMap.set(email.toLowerCase(), slug);
478
482
  result.contactsImported++;
@@ -483,7 +487,7 @@ async function runHubSpotCsvImport(exportDir, dataDir, opts = {}) {
483
487
  }
484
488
  const dealsPath = path.join(exportDir, "deals.csv");
485
489
  if (fs.existsSync(dealsPath) && progress.phases.deals.status !== "done") if (!dryRun) {
486
- const { upsertDeal } = await import("./pipeline-writer-BqBrYrQc.js");
490
+ const { upsertDeal } = await import("./pipeline-writer-0LJ6Qkat.js");
487
491
  progress.phases.deals.status = "in-progress";
488
492
  writeProgress(dataDir, progress);
489
493
  for await (const row of streamCSV(dealsPath)) {
@@ -531,7 +535,8 @@ async function runHubSpotCsvImport(exportDir, dataDir, opts = {}) {
531
535
  }
532
536
  const engagementsPath = path.join(exportDir, "engagements.csv");
533
537
  if (fs.existsSync(engagementsPath) && progress.phases.engagements.status !== "done") if (!dryRun) {
534
- const { appendInteraction, readInteractions } = await import("./interactions-writer-dSPy1XfO.js");
538
+ const { appendInteraction, InteractionDedup } = await import("./interactions-writer-B2y-73lh.js");
539
+ const dedup = new InteractionDedup(dataDir);
535
540
  progress.phases.engagements.status = "in-progress";
536
541
  writeProgress(dataDir, progress);
537
542
  for await (const row of streamCSV(engagementsPath)) {
@@ -548,7 +553,7 @@ async function runHubSpotCsvImport(exportDir, dataDir, opts = {}) {
548
553
  if (!slug) continue;
549
554
  const sourceRef = `hubspot://engagement/${engId}`;
550
555
  try {
551
- if ((await readInteractions(dataDir, slug).catch(() => "")).includes(sourceRef)) continue;
556
+ if (await dedup.seen(slug, sourceRef)) continue;
552
557
  const date = coerceDate(timestamp);
553
558
  const type = TYPE_MAP[engType] ?? "Note";
554
559
  const summaryParts = [];
@@ -567,6 +572,7 @@ async function runHubSpotCsvImport(exportDir, dataDir, opts = {}) {
567
572
  sourceRef,
568
573
  synced: (/* @__PURE__ */ new Date()).toISOString()
569
574
  });
575
+ dedup.markAppended(slug, sourceRef);
570
576
  result.engagementsImported++;
571
577
  } catch (err) {
572
578
  result.errors.push(`Engagement ${engId}: ${err.message}`);
@@ -585,4 +591,4 @@ async function runHubSpotCsvImport(exportDir, dataDir, opts = {}) {
585
591
  //#endregion
586
592
  export { analyzeHubSpotExport, runHubSpotCsvImport };
587
593
 
588
- //# sourceMappingURL=import-hubspot-BaK71U_K.js.map
594
+ //# sourceMappingURL=import-hubspot-CTId9IGV.js.map