@datasynx/agentic-crm 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (286) hide show
  1. package/README.md +264 -670
  2. package/dist/{approvals-DpjxGHFp.js → approvals-CmDT2eUg.js} +7 -24
  3. package/dist/approvals-CmDT2eUg.js.map +1 -0
  4. package/dist/{ask-CID3jnuL.js → ask-D8iYqDAr.js} +6 -6
  5. package/dist/{ask-CID3jnuL.js.map → ask-D8iYqDAr.js.map} +1 -1
  6. package/dist/atomic-write-8yjqqLtS.js +29 -0
  7. package/dist/atomic-write-8yjqqLtS.js.map +1 -0
  8. package/dist/atomic-write-BYmF-ThH.cjs +37 -0
  9. package/dist/atomic-write-BYmF-ThH.cjs.map +1 -0
  10. package/dist/auth-B5DcjJ_6.js +2 -0
  11. package/dist/{auth-DFWwWcYD.js → auth-DDXZTwS0.js} +4 -13
  12. package/dist/auth-DDXZTwS0.js.map +1 -0
  13. package/dist/{autofill-Di_-SP7t.js → autofill-B9VtlR2j.js} +2 -2
  14. package/dist/{autofill-Di_-SP7t.js.map → autofill-B9VtlR2j.js.map} +1 -1
  15. package/dist/{backup-CeMk9z86.js → backup-CTlIxUdO.js} +5 -7
  16. package/dist/backup-CTlIxUdO.js.map +1 -0
  17. package/dist/backup-LFnC09oV.js +2 -0
  18. package/dist/{churn-C28IgnAj.js → churn-DN9WDGNM.js} +3 -3
  19. package/dist/{churn-C28IgnAj.js.map → churn-DN9WDGNM.js.map} +1 -1
  20. package/dist/cli.js +282 -184
  21. package/dist/cli.js.map +1 -1
  22. package/dist/{compliance-CKSBoQUe.js → compliance-Bc12Hn9a.js} +3 -3
  23. package/dist/{compliance-CKSBoQUe.js.map → compliance-Bc12Hn9a.js.map} +1 -1
  24. package/dist/{compliance-CujOqAKk.js → compliance-TqYQXhBj.js} +1 -1
  25. package/dist/{compliance-B1kk5-YS.js → compliance-kq0xHRw3.js} +3 -3
  26. package/dist/{compliance-B1kk5-YS.js.map → compliance-kq0xHRw3.js.map} +1 -1
  27. package/dist/{compliance-B91zNvCR.cjs → compliance-pAj9FcGI.cjs} +3 -3
  28. package/dist/{compliance-B91zNvCR.cjs.map → compliance-pAj9FcGI.cjs.map} +1 -1
  29. package/dist/{context-builder-BzWAp3Zs.js → context-builder-7Uab5-G4.js} +3 -2
  30. package/dist/context-builder-7Uab5-G4.js.map +1 -0
  31. package/dist/context-builder-hmOPvgso.js +2 -0
  32. package/dist/{custom-fields-CzNeD3_v.js → custom-fields-BMyz5Ruh.js} +1 -1
  33. package/dist/{custom-fields-Pl2t9xzp.js → custom-fields-GzpOHW_2.js} +4 -13
  34. package/dist/custom-fields-GzpOHW_2.js.map +1 -0
  35. package/dist/{custom-objects-CIFrmQ2V.js → custom-objects-BNy-ayR-.js} +1 -1
  36. package/dist/{custom-objects-BHgn1GEX.js → custom-objects-CxW1gHwJ.js} +10 -25
  37. package/dist/custom-objects-CxW1gHwJ.js.map +1 -0
  38. package/dist/{customer-dir-DIylZ8Q6.js → customer-dir-CkMMXhb0.js} +9 -4
  39. package/dist/customer-dir-CkMMXhb0.js.map +1 -0
  40. package/dist/daemon/worker.js +66 -40
  41. package/dist/daemon/worker.js.map +1 -1
  42. package/dist/doctor-C14-vnJ1.js +103 -0
  43. package/dist/doctor-C14-vnJ1.js.map +1 -0
  44. package/dist/{enrichment-3XvgGDfB.js → enrichment-CDFdWmvD.js} +3 -3
  45. package/dist/{enrichment-3XvgGDfB.js.map → enrichment-CDFdWmvD.js.map} +1 -1
  46. package/dist/{file-lock-B_zi7NQl.js → file-lock-CcHotQkZ.js} +3 -4
  47. package/dist/file-lock-CcHotQkZ.js.map +1 -0
  48. package/dist/{gmail-sync-rQaVqKWd.js → gmail-sync-C-NmibzS.js} +13 -9
  49. package/dist/gmail-sync-C-NmibzS.js.map +1 -0
  50. package/dist/{gmail-sync-DIaxInDT.js → gmail-sync-DueE6tl5.js} +14 -10
  51. package/dist/gmail-sync-DueE6tl5.js.map +1 -0
  52. package/dist/{gmail-sync-hHm9gaWd.cjs → gmail-sync-GEy3oVvw.cjs} +13 -9
  53. package/dist/gmail-sync-GEy3oVvw.cjs.map +1 -0
  54. package/dist/{gmail-webhook-handler-DS7OlRPX.js → gmail-webhook-handler-B26COilD.js} +2 -2
  55. package/dist/{gmail-webhook-handler-e5Od25FX.js → gmail-webhook-handler-kGKpbY9h.js} +4 -4
  56. package/dist/{gmail-webhook-handler-e5Od25FX.js.map → gmail-webhook-handler-kGKpbY9h.js.map} +1 -1
  57. package/dist/{goal-engine-KpBftn4V.js → goal-engine-BbroPhqm.js} +10 -11
  58. package/dist/goal-engine-BbroPhqm.js.map +1 -0
  59. package/dist/{goal-engine-CUZSpERI.js → goal-engine-CfDAJTFt.js} +1 -1
  60. package/dist/{google-drive-sync-DEPcqFca.js → google-drive-sync-D1n7WKZn.js} +3 -3
  61. package/dist/{google-drive-sync-DEPcqFca.js.map → google-drive-sync-D1n7WKZn.js.map} +1 -1
  62. package/dist/{hygiene-DZqfYpFf.js → hygiene-DzQPnc6P.js} +3 -3
  63. package/dist/{hygiene-DZqfYpFf.js.map → hygiene-DzQPnc6P.js.map} +1 -1
  64. package/dist/identity-CB7j-Zr1.js +2 -0
  65. package/dist/{identity-CI6olMNm.js → identity-_uZ3Lbr2.js} +2 -2
  66. package/dist/{identity-CI6olMNm.js.map → identity-_uZ3Lbr2.js.map} +1 -1
  67. package/dist/{import-hubspot-BaK71U_K.js → import-hubspot-DB4n89jy.js} +51 -45
  68. package/dist/import-hubspot-DB4n89jy.js.map +1 -0
  69. package/dist/{index-V8BFaH-b.d.ts → index-B0IMMrp_.d.ts} +8 -4
  70. package/dist/{index-V8BFaH-b.d.ts.map → index-B0IMMrp_.d.ts.map} +1 -1
  71. package/dist/{index-YqwMd6aQ.d.cts → index-pY7tYXwH.d.cts} +8 -4
  72. package/dist/{index-YqwMd6aQ.d.cts.map → index-pY7tYXwH.d.cts.map} +1 -1
  73. package/dist/index.cjs +19 -21
  74. package/dist/index.cjs.map +1 -1
  75. package/dist/index.d.cts +8 -4
  76. package/dist/index.d.cts.map +1 -1
  77. package/dist/index.d.ts +8 -4
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +19 -21
  80. package/dist/index.js.map +1 -1
  81. package/dist/{interactions-writer-DO3KcSR3.js → interactions-writer-BZzUIgJd.js} +5 -2
  82. package/dist/interactions-writer-BZzUIgJd.js.map +1 -0
  83. package/dist/{interactions-writer-SLHnoEeE.js → interactions-writer-DbSyI2rt.js} +32 -3
  84. package/dist/interactions-writer-DbSyI2rt.js.map +1 -0
  85. package/dist/interactions-writer-RJB8SWf2.js +2 -0
  86. package/dist/{interactions-writer-CrPStUll.cjs → interactions-writer-a2yzBd7T.cjs} +5 -2
  87. package/dist/interactions-writer-a2yzBd7T.cjs.map +1 -0
  88. package/dist/json-store-WWsFzXub.js +43 -0
  89. package/dist/json-store-WWsFzXub.js.map +1 -0
  90. package/dist/{knowledge-base-D0Fh40kc.js → knowledge-base-DHNc4hVj.js} +43 -16
  91. package/dist/knowledge-base-DHNc4hVj.js.map +1 -0
  92. package/dist/{lancedb-CCBbpulq.js → lancedb-CswQEE5K.js} +1 -1
  93. package/dist/{lancedb-rlvWoPwl.js → lancedb-CuHKNsNZ.js} +4 -3
  94. package/dist/lancedb-CuHKNsNZ.js.map +1 -0
  95. package/dist/{lead-model-BCFzyktm.js → lead-model-CEmx7te7.js} +6 -14
  96. package/dist/lead-model-CEmx7te7.js.map +1 -0
  97. package/dist/{llm-Z8RIYkpF.js → llm-BnSUBisu.js} +2 -2
  98. package/dist/{llm-Z8RIYkpF.js.map → llm-BnSUBisu.js.map} +1 -1
  99. package/dist/{llm-iijeXmgq.cjs → llm-CXycmEl9.cjs} +2 -2
  100. package/dist/{llm-iijeXmgq.cjs.map → llm-CXycmEl9.cjs.map} +1 -1
  101. package/dist/{llm-DEjWcqmW.js → llm-DSX1-wFu.js} +1 -1
  102. package/dist/{llm-DvzZqva0.js → llm-PZzgPphl.js} +3 -3
  103. package/dist/{llm-DvzZqva0.js.map → llm-PZzgPphl.js.map} +1 -1
  104. package/dist/logger-BkInaGoV.cjs +167 -0
  105. package/dist/logger-BkInaGoV.cjs.map +1 -0
  106. package/dist/logger-Dyl4VcLO.js +147 -0
  107. package/dist/logger-Dyl4VcLO.js.map +1 -0
  108. package/dist/logger-UaF5p9d1.js +147 -0
  109. package/dist/logger-UaF5p9d1.js.map +1 -0
  110. package/dist/logger-vKQS34w9.js +2 -0
  111. package/dist/mcp-CdTJWTJf.d.cts.map +1 -1
  112. package/dist/mcp-CdTJWTJf.d.ts.map +1 -1
  113. package/dist/mcp.cjs +327 -303
  114. package/dist/mcp.cjs.map +1 -1
  115. package/dist/mcp.d.cts.map +1 -1
  116. package/dist/mcp.d.ts.map +1 -1
  117. package/dist/mcp.js +327 -303
  118. package/dist/mcp.js.map +1 -1
  119. package/dist/{memory-Cy6-Tbyl.js → memory-D8hmgD9d.js} +1 -1
  120. package/dist/{memory-Bb6ky3kb.js → memory-Dzr9dXSM.js} +4 -11
  121. package/dist/memory-Dzr9dXSM.js.map +1 -0
  122. package/dist/{microsoft-calendar-B6MMtUQK.js → microsoft-calendar-jIu9K5zX.js} +4 -4
  123. package/dist/{microsoft-calendar-B6MMtUQK.js.map → microsoft-calendar-jIu9K5zX.js.map} +1 -1
  124. package/dist/{microsoft-sync-CpZVoSuq.js → microsoft-sync-R_r8HL-B.js} +5 -5
  125. package/dist/{microsoft-sync-CpZVoSuq.js.map → microsoft-sync-R_r8HL-B.js.map} +1 -1
  126. package/dist/{nba-3wanmJ0U.js → nba-mTJ4yEqD.js} +3 -3
  127. package/dist/{nba-3wanmJ0U.js.map → nba-mTJ4yEqD.js.map} +1 -1
  128. package/dist/{notification-dispatcher-0vYNngWe.js → notification-dispatcher-inpKyuBz.js} +7 -3
  129. package/dist/notification-dispatcher-inpKyuBz.js.map +1 -0
  130. package/dist/{pipeline-writer-BqBrYrQc.js → pipeline-writer-0LJ6Qkat.js} +1 -1
  131. package/dist/{pipeline-writer-N2omexxp.cjs → pipeline-writer-B1tRAhuD.cjs} +11 -3
  132. package/dist/pipeline-writer-B1tRAhuD.cjs.map +1 -0
  133. package/dist/{pipeline-writer-BvVquKIe.js → pipeline-writer-CIllfnZl.js} +5 -3
  134. package/dist/pipeline-writer-CIllfnZl.js.map +1 -0
  135. package/dist/{pipeline-writer-eufx_0o1.js → pipeline-writer-rDj-ni6q.js} +6 -4
  136. package/dist/pipeline-writer-rDj-ni6q.js.map +1 -0
  137. package/dist/{proactive-agent-BgQXw3ac.js → proactive-agent-B7u3Bj_l.js} +6 -6
  138. package/dist/{proactive-agent-BgQXw3ac.js.map → proactive-agent-B7u3Bj_l.js.map} +1 -1
  139. package/dist/{proactive-worker-BrLHNhjH.js → proactive-worker-1zkm6aJD.js} +7 -8
  140. package/dist/proactive-worker-1zkm6aJD.js.map +1 -0
  141. package/dist/{push-manager-CowY-0IK.js → push-manager-BXM-IHfP.js} +1 -1
  142. package/dist/{push-manager-CdqIIkuh.js → push-manager-C0ECQgva.js} +4 -4
  143. package/dist/push-manager-C0ECQgva.js.map +1 -0
  144. package/dist/{quote-generator-OhSFsi3x.js → quote-generator-ByUyIYtw.js} +1 -1
  145. package/dist/{quote-generator-BfwENXzg.js → quote-generator-CTdR8eEI.js} +5 -5
  146. package/dist/quote-generator-CTdR8eEI.js.map +1 -0
  147. package/dist/rbac-DzbyFhVH.js +2 -0
  148. package/dist/{rbac-CTIktZaC.js → rbac-msmBc_tK.js} +19 -12
  149. package/dist/rbac-msmBc_tK.js.map +1 -0
  150. package/dist/regex-Jt5DatPi.js +13 -0
  151. package/dist/regex-Jt5DatPi.js.map +1 -0
  152. package/dist/{relationship-health-odxEoQdJ.js → relationship-health-ZZNXR1RZ.js} +8 -16
  153. package/dist/relationship-health-ZZNXR1RZ.js.map +1 -0
  154. package/dist/{revenue-simulation-Bqf2DLVB.js → revenue-simulation-D8f_YkUY.js} +9 -19
  155. package/dist/revenue-simulation-D8f_YkUY.js.map +1 -0
  156. package/dist/{revenue-simulation-BJdRTEHc.js → revenue-simulation-njJZlTqm.js} +1 -1
  157. package/dist/safe-path-mpp0dKtO.js +18 -0
  158. package/dist/safe-path-mpp0dKtO.js.map +1 -0
  159. package/dist/{segments-BqcD5HIl.js → segments-DI3LOQNe.js} +5 -14
  160. package/dist/segments-DI3LOQNe.js.map +1 -0
  161. package/dist/sequence-engine-C6nnewHX.js +2 -0
  162. package/dist/{sequence-engine-J1lTW_in.js → sequence-engine-DNTVLq7o.js} +15 -8
  163. package/dist/sequence-engine-DNTVLq7o.js.map +1 -0
  164. package/dist/{sequence-store-DaaWr0Os.js → sequence-store-CmYb6s0g.js} +6 -5
  165. package/dist/sequence-store-CmYb6s0g.js.map +1 -0
  166. package/dist/{server-Dyva03K8.js → server-DqSMYhSA.js} +278 -220
  167. package/dist/server-DqSMYhSA.js.map +1 -0
  168. package/dist/{session-D9ub6Wl1.js → session-B6XaP83h.js} +3 -3
  169. package/dist/session-B6XaP83h.js.map +1 -0
  170. package/dist/{session-B9AilxOE.js → session-BgGDyP2C.js} +3 -3
  171. package/dist/session-BgGDyP2C.js.map +1 -0
  172. package/dist/session-Bp4zTh4l.js +2 -0
  173. package/dist/{session-D0qFkBla.cjs → session-Mm7GQbSH.cjs} +3 -3
  174. package/dist/session-Mm7GQbSH.cjs.map +1 -0
  175. package/dist/{session-store-C8tEvMPw.js → session-store-DWxJ5Pof.js} +79 -17
  176. package/dist/session-store-DWxJ5Pof.js.map +1 -0
  177. package/dist/{session-store-B0QZE8Bx.cjs → session-store-yfwnj0OC.cjs} +126 -16
  178. package/dist/session-store-yfwnj0OC.cjs.map +1 -0
  179. package/dist/{sla-engine-5IhTsBUR.js → sla-engine-CP2KiKDS.js} +1 -1
  180. package/dist/{sla-engine-BqX-7u-7.js → sla-engine-O-A1ntu_.js} +2 -2
  181. package/dist/{sla-engine-BqX-7u-7.js.map → sla-engine-O-A1ntu_.js.map} +1 -1
  182. package/dist/{sop-Vp0UPWFW.js → sop-BV7ICAFR.js} +4 -11
  183. package/dist/sop-BV7ICAFR.js.map +1 -0
  184. package/dist/{sop-DkhVChGy.js → sop-D33qTHUb.js} +1 -1
  185. package/dist/survey-engine-DKctGcLQ.js +2 -0
  186. package/dist/{survey-engine-DBjCYqCv.js → survey-engine-DngXBv47.js} +5 -4
  187. package/dist/survey-engine-DngXBv47.js.map +1 -0
  188. package/dist/{sync-state-CwLSt_1m.js → sync-state-BaA8LbTI.js} +1 -1
  189. package/dist/{sync-state-ChaLbamC.js → sync-state-DMZgzpez.js} +4 -12
  190. package/dist/sync-state-DMZgzpez.js.map +1 -0
  191. package/dist/{ticket-writer-CjqKeIRD.js → ticket-writer-DsfpeLGZ.js} +1 -1
  192. package/dist/{ticket-writer-j2oX_Wal.js → ticket-writer-a9on36Wb.js} +12 -24
  193. package/dist/ticket-writer-a9on36Wb.js.map +1 -0
  194. package/dist/{tone-Bdm5uaht.js → tone-C7bqK69y.js} +5 -12
  195. package/dist/tone-C7bqK69y.js.map +1 -0
  196. package/dist/{tone-DRKlZgPr.cjs → tone-Cmc7O2Fx.cjs} +3 -9
  197. package/dist/tone-Cmc7O2Fx.cjs.map +1 -0
  198. package/dist/{tone-vNb2DAAD.js → tone-mXSftvTn.js} +3 -8
  199. package/dist/tone-mXSftvTn.js.map +1 -0
  200. package/dist/{transcript-watcher-CL2QUygI.js → transcript-watcher-0mh2ZhmH.js} +18 -11
  201. package/dist/transcript-watcher-0mh2ZhmH.js.map +1 -0
  202. package/dist/unmatched-transcripts-C92zAoM4.js +2 -0
  203. package/dist/unmatched-transcripts-DC-VQ9YS.js +16 -0
  204. package/dist/unmatched-transcripts-DC-VQ9YS.js.map +1 -0
  205. package/dist/update-deal-CWy1eLJI.js +2 -0
  206. package/dist/{update-deal-DKC79skb.js → update-deal-DSzr_Aau.js} +3 -3
  207. package/dist/{update-deal-DKC79skb.js.map → update-deal-DSzr_Aau.js.map} +1 -1
  208. package/dist/{usage-D0-TYJkw.js → usage-BVlFlKW_.js} +8 -6
  209. package/dist/usage-BVlFlKW_.js.map +1 -0
  210. package/dist/usage-CClTf5e6.cjs.map +1 -1
  211. package/dist/usage-D0u9a-lV.js.map +1 -1
  212. package/dist/{vault-DXCg29W-.js → vault-CfwZdNzC.js} +3 -4
  213. package/dist/vault-CfwZdNzC.js.map +1 -0
  214. package/dist/{vault-C1D3zScD.js → vault-DxKP4_R2.js} +1 -1
  215. package/dist/{webhooks-Xn6zO6kd.cjs → webhooks-CwW-3kvG.cjs} +5 -19
  216. package/dist/webhooks-CwW-3kvG.cjs.map +1 -0
  217. package/dist/{webhooks-7EpA05Qr.js → webhooks-DXr1IoKn.js} +8 -21
  218. package/dist/webhooks-DXr1IoKn.js.map +1 -0
  219. package/dist/{webhooks-BO2UAnmn.js → webhooks-sWZ8CJtR.js} +5 -18
  220. package/dist/webhooks-sWZ8CJtR.js.map +1 -0
  221. package/package.json +11 -2
  222. package/dist/approvals-DpjxGHFp.js.map +0 -1
  223. package/dist/auth-CyFuu9X_.js +0 -2
  224. package/dist/auth-DFWwWcYD.js.map +0 -1
  225. package/dist/backup-CeMk9z86.js.map +0 -1
  226. package/dist/backup-f_hC7rBV.js +0 -2
  227. package/dist/context-builder-BzWAp3Zs.js.map +0 -1
  228. package/dist/context-builder-DlrRcqmJ.js +0 -2
  229. package/dist/custom-fields-Pl2t9xzp.js.map +0 -1
  230. package/dist/custom-objects-BHgn1GEX.js.map +0 -1
  231. package/dist/customer-dir-DIylZ8Q6.js.map +0 -1
  232. package/dist/file-lock-B_zi7NQl.js.map +0 -1
  233. package/dist/gmail-sync-DIaxInDT.js.map +0 -1
  234. package/dist/gmail-sync-hHm9gaWd.cjs.map +0 -1
  235. package/dist/gmail-sync-rQaVqKWd.js.map +0 -1
  236. package/dist/goal-engine-KpBftn4V.js.map +0 -1
  237. package/dist/identity-gyfWdrcX.js +0 -2
  238. package/dist/import-hubspot-BaK71U_K.js.map +0 -1
  239. package/dist/interactions-writer-CrPStUll.cjs.map +0 -1
  240. package/dist/interactions-writer-DO3KcSR3.js.map +0 -1
  241. package/dist/interactions-writer-SLHnoEeE.js.map +0 -1
  242. package/dist/interactions-writer-dSPy1XfO.js +0 -2
  243. package/dist/knowledge-base-D0Fh40kc.js.map +0 -1
  244. package/dist/lancedb-rlvWoPwl.js.map +0 -1
  245. package/dist/lead-model-BCFzyktm.js.map +0 -1
  246. package/dist/memory-Bb6ky3kb.js.map +0 -1
  247. package/dist/notification-dispatcher-0vYNngWe.js.map +0 -1
  248. package/dist/pipeline-writer-BvVquKIe.js.map +0 -1
  249. package/dist/pipeline-writer-N2omexxp.cjs.map +0 -1
  250. package/dist/pipeline-writer-eufx_0o1.js.map +0 -1
  251. package/dist/proactive-worker-BrLHNhjH.js.map +0 -1
  252. package/dist/push-manager-CdqIIkuh.js.map +0 -1
  253. package/dist/quote-generator-BfwENXzg.js.map +0 -1
  254. package/dist/rbac-C7c8tcES.js +0 -2
  255. package/dist/rbac-CTIktZaC.js.map +0 -1
  256. package/dist/relationship-health-odxEoQdJ.js.map +0 -1
  257. package/dist/revenue-simulation-Bqf2DLVB.js.map +0 -1
  258. package/dist/segments-BqcD5HIl.js.map +0 -1
  259. package/dist/sequence-engine-CCTHEBgi.js +0 -2
  260. package/dist/sequence-engine-J1lTW_in.js.map +0 -1
  261. package/dist/sequence-store-DaaWr0Os.js.map +0 -1
  262. package/dist/server-Dyva03K8.js.map +0 -1
  263. package/dist/session-B9AilxOE.js.map +0 -1
  264. package/dist/session-D0qFkBla.cjs.map +0 -1
  265. package/dist/session-D9ub6Wl1.js.map +0 -1
  266. package/dist/session-mWHA71Lw.js +0 -2
  267. package/dist/session-store-B0QZE8Bx.cjs.map +0 -1
  268. package/dist/session-store-C8tEvMPw.js.map +0 -1
  269. package/dist/sop-Vp0UPWFW.js.map +0 -1
  270. package/dist/survey-engine-C06hcQt3.js +0 -2
  271. package/dist/survey-engine-DBjCYqCv.js.map +0 -1
  272. package/dist/sync-state-ChaLbamC.js.map +0 -1
  273. package/dist/ticket-writer-j2oX_Wal.js.map +0 -1
  274. package/dist/tone-Bdm5uaht.js.map +0 -1
  275. package/dist/tone-DRKlZgPr.cjs.map +0 -1
  276. package/dist/tone-vNb2DAAD.js.map +0 -1
  277. package/dist/transcript-watcher-CL2QUygI.js.map +0 -1
  278. package/dist/unmatched-transcripts-BsH5bhkU.js +0 -26
  279. package/dist/unmatched-transcripts-BsH5bhkU.js.map +0 -1
  280. package/dist/unmatched-transcripts-D0PrJ9iz.js +0 -2
  281. package/dist/update-deal-BNwPGaTV.js +0 -2
  282. package/dist/usage-D0-TYJkw.js.map +0 -1
  283. package/dist/vault-DXCg29W-.js.map +0 -1
  284. package/dist/webhooks-7EpA05Qr.js.map +0 -1
  285. package/dist/webhooks-BO2UAnmn.js.map +0 -1
  286. package/dist/webhooks-Xn6zO6kd.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["ensureCustomerDir","writeMainFacts","Command","success","bold","error","filterAuditLog","readAuditLog","Command","matter","warning","listCustomerSlugs","error","info","success","Command"],"sources":["../src/commands/create.ts","../src/commands/audit.ts","../src/commands/validate.ts","../src/version.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport slugify from \"slug\";\nimport { ensureCustomerDir, writeMainFacts } from \"../fs/customer-dir.js\";\nimport { success, error, bold } from \"../ui/colors.js\";\n\nexport async function createCustomer(opts: {\n name: string;\n domain?: string;\n email?: string;\n dataDir?: string;\n}): Promise<{ id: string; dir: string }> {\n const id = slugify(opts.name, { lower: true });\n const dataDir = opts.dataDir ?? process.env[\"DXCRM_DATA_DIR\"] ?? process.cwd();\n await ensureCustomerDir(dataDir, id);\n const dir = path.join(dataDir, \"customers\", id);\n\n // Write main_facts.md\n const today = new Date().toISOString().slice(0, 10);\n await writeMainFacts(dataDir, id, {\n name: opts.name,\n domain: opts.domain,\n email: opts.email,\n relationship_stage: \"prospect\",\n tags: [],\n currency: \"EUR\",\n created: today,\n updated: today,\n });\n\n // Create interactions.md\n const interactionsPath = path.join(dir, \"interactions.md\");\n if (!fs.existsSync(interactionsPath)) {\n fs.writeFileSync(interactionsPath, `# Interactions — ${opts.name}\\n\\n`);\n }\n\n // Create pipeline.md\n const pipelinePath = path.join(dir, \"pipeline.md\");\n if (!fs.existsSync(pipelinePath)) {\n fs.writeFileSync(\n pipelinePath,\n `# Pipeline — ${opts.name}\\n\\n| Deal | Stage | Value | Currency | Probability | Close Date | Updated | Notes |\\n|---|---|---|---|---|---|---|---|\\n`\n );\n }\n\n // Create sources.json\n const sourcesPath = path.join(dir, \"sources.json\");\n if (!fs.existsSync(sourcesPath)) {\n const gmailQuery = opts.domain\n ? `from:${opts.domain} OR to:${opts.domain}`\n : opts.email\n ? `from:${opts.email} OR to:${opts.email}`\n : \"\";\n const sources = {\n gmail: {\n type: \"gmail\",\n query: gmailQuery,\n enabled: true,\n },\n version: 1,\n created: new Date().toISOString(),\n };\n fs.writeFileSync(sourcesPath, JSON.stringify(sources, null, 2));\n }\n\n return { id, dir };\n}\n\nexport const createCommand = new Command(\"create\")\n .argument(\"<name>\", \"Customer name\")\n .option(\"--domain <domain>\", \"Primary domain (for Gmail sync)\")\n .option(\"--email <email>\", \"Primary contact email\")\n .action(async (name: string, opts: { domain?: string; email?: string }) => {\n try {\n const { id, dir } = await createCustomer({ name, ...opts });\n console.log(success(`✓ Created customer: ${bold(id)}`));\n console.log(` Dir: ${dir}`);\n console.log(` Files: main_facts.md, interactions.md, pipeline.md, sources.json`);\n } catch (err) {\n console.error(error(`✗ ${(err as Error).message}`));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport { readAuditLog, filterAuditLog } from \"../fs/audit-log.js\";\n\nconst SEP = \"─\".repeat(70);\n\nexport async function runAudit(\n opts: {\n slug?: string;\n actor?: string;\n limit?: number;\n tail?: boolean;\n },\n dataDir?: string\n): Promise<void> {\n const dir = dataDir ?? process.cwd();\n const limit = opts.limit ?? 20;\n\n const allEntries = readAuditLog(dir);\n const entries = filterAuditLog(allEntries, {\n ...(opts.slug !== undefined ? { slug: opts.slug } : {}),\n ...(opts.actor !== undefined ? { actor: opts.actor } : {}),\n limit,\n });\n\n console.log(SEP);\n console.log(\" DatasynxOpenCRM — Audit Trail\");\n\n if (opts.slug) console.log(` Customer: ${opts.slug}`);\n if (opts.actor) console.log(` Actor: ${opts.actor}`);\n\n console.log(SEP);\n\n if (entries.length === 0) {\n console.log(\" No audit entries found.\");\n console.log(SEP);\n return;\n }\n\n for (const entry of entries) {\n console.log(\n ` ${entry.timestamp} ${entry.actor.padEnd(12)} ${entry.tool.padEnd(20)} ${entry.slug.padEnd(20)} ${entry.summary}`\n );\n }\n\n console.log(SEP);\n console.log(` ${entries.length} entr${entries.length === 1 ? \"y\" : \"ies\"} shown`);\n console.log(SEP);\n}\n\nexport const auditCommand = new Command(\"audit\")\n .description(\"Show CRM audit trail — who changed what and when\")\n .option(\"--slug <slug>\", \"Filter by customer slug\")\n .option(\"--actor <actor>\", \"Filter by actor\")\n .option(\"--limit <n>\", \"Number of entries to show (default: 20)\", parseInt)\n .option(\"--tail\", \"Show all new entries (simplified: shows current entries)\")\n .action((opts: { slug?: string; actor?: string; limit?: number; tail?: boolean }) =>\n runAudit(opts, process.env[\"DXCRM_DATA_DIR\"])\n );\n","import { Command } from \"commander\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport { MainFactsSchema } from \"../schemas/main-facts.js\";\nimport { listCustomerSlugs } from \"../fs/customer-dir.js\";\nimport matter from \"gray-matter\";\nimport { success, error, warning, info } from \"../ui/colors.js\";\n\nconst RECOVERABLE_DEFAULTS: Record<string, unknown> = {\n tags: [],\n currency: \"EUR\",\n};\n\nexport function applyFix(\n factsPath: string,\n content: string,\n data: Record<string, unknown>\n): { fixed: string[]; content: string } | null {\n const fixed: string[] = [];\n const patched = { ...data };\n\n for (const [field, defaultValue] of Object.entries(RECOVERABLE_DEFAULTS)) {\n if (patched[field] === undefined || patched[field] === null) {\n patched[field] = defaultValue;\n fixed.push(`${field} → ${JSON.stringify(defaultValue)}`);\n }\n }\n\n if (patched[\"updated\"] === undefined && patched[\"created\"]) {\n patched[\"updated\"] = patched[\"created\"];\n fixed.push(`updated → ${String(patched[\"created\"])}`);\n }\n\n if (fixed.length === 0) return null;\n\n const parsed = matter(content);\n const newContent = matter.stringify(parsed.content, patched);\n fs.writeFileSync(factsPath, newContent);\n return { fixed, content: newContent };\n}\n\nexport async function runValidate(opts: { fix?: boolean }, dataDir: string): Promise<void> {\n const customersDir = path.join(dataDir, \"customers\");\n\n if (!fs.existsSync(customersDir)) {\n console.log(warning(\"⚠ No customers directory found.\"));\n return;\n }\n\n const slugs = listCustomerSlugs(dataDir);\n\n let errorCount = 0;\n let fixedCount = 0;\n\n for (const slug of slugs) {\n const factsPath = path.join(customersDir, slug, \"main_facts.md\");\n const interactionsPath = path.join(customersDir, slug, \"interactions.md\");\n\n if (!fs.existsSync(factsPath)) {\n console.log(error(`✗ ${slug}: missing main_facts.md`));\n errorCount++;\n continue;\n }\n\n try {\n let content = fs.readFileSync(factsPath, \"utf-8\") as string;\n const { data } = matter(content);\n\n if (opts.fix) {\n const result = applyFix(factsPath, content, data as Record<string, unknown>);\n if (result) {\n content = result.content;\n fixedCount++;\n console.log(info(`⚙ ${slug}: fixed ${result.fixed.join(\", \")}`));\n }\n }\n\n const { data: refetchedData } = matter(content);\n MainFactsSchema.parse(refetchedData);\n\n if (!fs.existsSync(interactionsPath)) {\n console.log(warning(`⚠ ${slug}: missing interactions.md`));\n } else {\n console.log(success(`✓ ${slug}`));\n }\n } catch (err) {\n console.log(error(`✗ ${slug}: ${(err as Error).message}`));\n errorCount++;\n }\n }\n\n if (opts.fix && fixedCount > 0) {\n console.log(info(`\\n⚙ Fixed ${fixedCount} customer(s).`));\n }\n\n if (errorCount > 0) {\n console.error(error(`\\n${errorCount} error(s) found.`));\n process.exit(1);\n } else {\n console.log(success(\"\\n✓ All customers valid.\"));\n }\n}\n\nexport const validateCommand = new Command(\"validate\")\n .option(\"--fix\", \"Auto-fix recoverable issues\")\n .action(async (opts: { fix?: boolean }) => {\n await runValidate(opts, process.env[\"DXCRM_DATA_DIR\"] ?? process.cwd());\n });\n","export const VERSION = \"0.1.0\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["ensureCustomerDir","writeMainFacts","Command","success","bold","error","filterAuditLog","readAuditLog","Command","matter","warning","listCustomerSlugs","error","info","success","Command"],"sources":["../src/commands/create.ts","../src/commands/audit.ts","../src/commands/validate.ts","../src/version.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport slugify from \"slug\";\nimport { ensureCustomerDir, writeMainFacts } from \"../fs/customer-dir.js\";\nimport { writeFileAtomic } from \"../fs/atomic-write.js\";\nimport { writeJsonFile } from \"../fs/json-store.js\";\nimport { success, error, bold } from \"../ui/colors.js\";\n\nexport async function createCustomer(opts: {\n name: string;\n domain?: string;\n email?: string;\n dataDir?: string;\n}): Promise<{ id: string; dir: string }> {\n const id = slugify(opts.name, { lower: true });\n const dataDir = opts.dataDir ?? process.env[\"DXCRM_DATA_DIR\"] ?? process.cwd();\n await ensureCustomerDir(dataDir, id);\n const dir = path.join(dataDir, \"customers\", id);\n\n // Write main_facts.md\n const today = new Date().toISOString().slice(0, 10);\n await writeMainFacts(dataDir, id, {\n name: opts.name,\n domain: opts.domain,\n email: opts.email,\n relationship_stage: \"prospect\",\n tags: [],\n currency: \"EUR\",\n created: today,\n updated: today,\n });\n\n // Create interactions.md\n const interactionsPath = path.join(dir, \"interactions.md\");\n if (!fs.existsSync(interactionsPath)) {\n writeFileAtomic(interactionsPath, `# Interactions — ${opts.name}\\n\\n`);\n }\n\n // Create pipeline.md\n const pipelinePath = path.join(dir, \"pipeline.md\");\n if (!fs.existsSync(pipelinePath)) {\n writeFileAtomic(\n pipelinePath,\n `# Pipeline — ${opts.name}\\n\\n| Deal | Stage | Value | Currency | Probability | Close Date | Updated | Notes |\\n|---|---|---|---|---|---|---|---|\\n`\n );\n }\n\n // Create sources.json\n const sourcesPath = path.join(dir, \"sources.json\");\n if (!fs.existsSync(sourcesPath)) {\n const gmailQuery = opts.domain\n ? `from:${opts.domain} OR to:${opts.domain}`\n : opts.email\n ? `from:${opts.email} OR to:${opts.email}`\n : \"\";\n const sources = {\n gmail: {\n type: \"gmail\",\n query: gmailQuery,\n enabled: true,\n },\n version: 1,\n created: new Date().toISOString(),\n };\n writeJsonFile(sourcesPath, sources);\n }\n\n return { id, dir };\n}\n\nexport const createCommand = new Command(\"create\")\n .description(\"Create a new customer\")\n .argument(\"<name>\", \"Customer name\")\n .option(\"--domain <domain>\", \"Primary domain (for Gmail sync)\")\n .option(\"--email <email>\", \"Primary contact email\")\n .action(async (name: string, opts: { domain?: string; email?: string }) => {\n try {\n const { id, dir } = await createCustomer({ name, ...opts });\n console.log(success(`✓ Created customer: ${bold(id)}`));\n console.log(` Dir: ${dir}`);\n console.log(` Files: main_facts.md, interactions.md, pipeline.md, sources.json`);\n } catch (err) {\n console.error(error(`✗ ${(err as Error).message}`));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport { readAuditLog, filterAuditLog } from \"../fs/audit-log.js\";\n\nconst SEP = \"─\".repeat(70);\n\nexport async function runAudit(\n opts: {\n slug?: string;\n actor?: string;\n limit?: number;\n tail?: boolean;\n },\n dataDir?: string\n): Promise<void> {\n const dir = dataDir ?? process.cwd();\n const limit = opts.limit ?? 20;\n\n const allEntries = readAuditLog(dir);\n const entries = filterAuditLog(allEntries, {\n ...(opts.slug !== undefined ? { slug: opts.slug } : {}),\n ...(opts.actor !== undefined ? { actor: opts.actor } : {}),\n limit,\n });\n\n console.log(SEP);\n console.log(\" DatasynxOpenCRM — Audit Trail\");\n\n if (opts.slug) console.log(` Customer: ${opts.slug}`);\n if (opts.actor) console.log(` Actor: ${opts.actor}`);\n\n console.log(SEP);\n\n if (entries.length === 0) {\n console.log(\" No audit entries found.\");\n console.log(SEP);\n return;\n }\n\n for (const entry of entries) {\n console.log(\n ` ${entry.timestamp} ${entry.actor.padEnd(12)} ${entry.tool.padEnd(20)} ${entry.slug.padEnd(20)} ${entry.summary}`\n );\n }\n\n console.log(SEP);\n console.log(` ${entries.length} entr${entries.length === 1 ? \"y\" : \"ies\"} shown`);\n console.log(SEP);\n}\n\nexport const auditCommand = new Command(\"audit\")\n .description(\"Show CRM audit trail — who changed what and when\")\n .option(\"--slug <slug>\", \"Filter by customer slug\")\n .option(\"--actor <actor>\", \"Filter by actor\")\n .option(\"--limit <n>\", \"Number of entries to show (default: 20)\", parseInt)\n .option(\"--tail\", \"Show all new entries (simplified: shows current entries)\")\n .action((opts: { slug?: string; actor?: string; limit?: number; tail?: boolean }) =>\n runAudit(opts, process.env[\"DXCRM_DATA_DIR\"])\n );\n","import { Command } from \"commander\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport { MainFactsSchema } from \"../schemas/main-facts.js\";\nimport { listCustomerSlugs } from \"../fs/customer-dir.js\";\nimport matter from \"gray-matter\";\nimport { success, error, warning, info } from \"../ui/colors.js\";\n\nconst RECOVERABLE_DEFAULTS: Record<string, unknown> = {\n tags: [],\n currency: \"EUR\",\n};\n\nexport function applyFix(\n factsPath: string,\n content: string,\n data: Record<string, unknown>\n): { fixed: string[]; content: string } | null {\n const fixed: string[] = [];\n const patched = { ...data };\n\n for (const [field, defaultValue] of Object.entries(RECOVERABLE_DEFAULTS)) {\n if (patched[field] === undefined || patched[field] === null) {\n patched[field] = defaultValue;\n fixed.push(`${field} → ${JSON.stringify(defaultValue)}`);\n }\n }\n\n if (patched[\"updated\"] === undefined && patched[\"created\"]) {\n patched[\"updated\"] = patched[\"created\"];\n fixed.push(`updated → ${String(patched[\"created\"])}`);\n }\n\n if (fixed.length === 0) return null;\n\n const parsed = matter(content);\n const newContent = matter.stringify(parsed.content, patched);\n fs.writeFileSync(factsPath, newContent);\n return { fixed, content: newContent };\n}\n\nexport async function runValidate(opts: { fix?: boolean }, dataDir: string): Promise<void> {\n const customersDir = path.join(dataDir, \"customers\");\n\n if (!fs.existsSync(customersDir)) {\n console.log(warning(\"⚠ No customers directory found.\"));\n return;\n }\n\n const slugs = listCustomerSlugs(dataDir);\n\n let errorCount = 0;\n let fixedCount = 0;\n\n for (const slug of slugs) {\n const factsPath = path.join(customersDir, slug, \"main_facts.md\");\n const interactionsPath = path.join(customersDir, slug, \"interactions.md\");\n\n if (!fs.existsSync(factsPath)) {\n console.log(error(`✗ ${slug}: missing main_facts.md`));\n errorCount++;\n continue;\n }\n\n try {\n let content = fs.readFileSync(factsPath, \"utf-8\") as string;\n let parsed = matter(content);\n\n if (opts.fix) {\n const result = applyFix(factsPath, content, parsed.data as Record<string, unknown>);\n if (result) {\n content = result.content;\n parsed = matter(content); // only re-parse when a fix actually rewrote content\n fixedCount++;\n console.log(info(`⚙ ${slug}: fixed ${result.fixed.join(\", \")}`));\n }\n }\n\n MainFactsSchema.parse(parsed.data);\n\n if (!fs.existsSync(interactionsPath)) {\n console.log(warning(`⚠ ${slug}: missing interactions.md`));\n } else {\n console.log(success(`✓ ${slug}`));\n }\n } catch (err) {\n console.log(error(`✗ ${slug}: ${(err as Error).message}`));\n errorCount++;\n }\n }\n\n if (opts.fix && fixedCount > 0) {\n console.log(info(`\\n⚙ Fixed ${fixedCount} customer(s).`));\n }\n\n if (errorCount > 0) {\n console.error(error(`\\n${errorCount} error(s) found.`));\n process.exit(1);\n } else {\n console.log(success(\"\\n✓ All customers valid.\"));\n }\n}\n\nexport const validateCommand = new Command(\"validate\")\n .description(\"Validate all customer data against schemas\")\n .option(\"--fix\", \"Auto-fix recoverable issues\")\n .action(async (opts: { fix?: boolean }) => {\n await runValidate(opts, process.env[\"DXCRM_DATA_DIR\"] ?? process.cwd());\n });\n","export const VERSION = \"0.1.0\";\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -138,8 +138,8 @@ declare const InteractionEntrySchema: z.ZodObject<{
138
138
  sourceRef: z.ZodString;
139
139
  synced: z.ZodString;
140
140
  }, "strip", z.ZodTypeAny, {
141
- date: string;
142
141
  type: "Email" | "Call" | "Meeting" | "Note" | "Demo" | "Proposal" | "Contract" | "Other";
142
+ date: string;
143
143
  with: string;
144
144
  summary: string;
145
145
  nextSteps: string[];
@@ -148,8 +148,8 @@ declare const InteractionEntrySchema: z.ZodObject<{
148
148
  direction?: "inbound" | "outbound" | undefined;
149
149
  subject?: string | undefined;
150
150
  }, {
151
- date: string;
152
151
  type: "Email" | "Call" | "Meeting" | "Note" | "Demo" | "Proposal" | "Contract" | "Other";
152
+ date: string;
153
153
  with: string;
154
154
  summary: string;
155
155
  sourceRef: string;
@@ -515,7 +515,11 @@ interface RbacConfig {
515
515
  declare function getRbacConfig(dataDir: string): RbacConfig;
516
516
  declare function getRole(dataDir: string, actor: string): Role;
517
517
  declare function canSeeCustomer(dataDir: string, actor: string, slug: string): boolean;
518
- /** Load the field-level ACL (field → allowed roles) from rbac.json. */
518
+ /**
519
+ * Build a once-loaded predicate for which customers `actor` may see. Equivalent
520
+ * to calling canSeeCustomer per slug, but reads/parses rbac.json a single time
521
+ * (and uses O(1) Set membership) — for hot loops like list_customers.
522
+ */
519
523
  //#endregion
520
524
  //#region src/core/session-store.d.ts
521
525
  interface Session {
@@ -535,4 +539,4 @@ declare const VERSION = "0.1.0";
535
539
 
536
540
  //#endregion
537
541
  export { type GlobalSources, type InteractionEntry, type KbArticle, type MainFacts, type PipelineDeal, type QuoteLineItem, type Quote as QuoteRecord, type SurveyDefinition, type SurveyResponse, type TicketPriority, type Ticket as TicketRecord, type TicketStatus, VERSION, canSeeCustomer, clearSession, createCustomer, customerExists, filterAuditLog, getRbacConfig, getRole, getSession, readAuditLog, readMainFacts, runAudit, runBackup, runValidate, setSession };
538
- //# sourceMappingURL=index-YqwMd6aQ.d.cts.map
542
+ //# sourceMappingURL=index-pY7tYXwH.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-YqwMd6aQ.d.cts","names":[],"sources":["../src/schemas/sources.ts","../src/schemas/main-facts.ts","../src/schemas/interaction.ts","../src/schemas/pipeline.ts","../src/schemas/ticket.ts","../src/schemas/quote.ts","../src/schemas/kb-article.ts","../src/schemas/survey.ts","../src/commands/create.ts","../src/commands/backup.ts","../src/commands/audit.ts","../src/commands/validate.ts","../src/fs/customer-dir.ts","../src/fs/audit-log.ts","../src/core/rbac.ts","../src/core/session-store.ts","../src/version.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index-pY7tYXwH.d.cts","names":[],"sources":["../src/schemas/sources.ts","../src/schemas/main-facts.ts","../src/schemas/interaction.ts","../src/schemas/pipeline.ts","../src/schemas/ticket.ts","../src/schemas/quote.ts","../src/schemas/kb-article.ts","../src/schemas/survey.ts","../src/commands/create.ts","../src/commands/backup.ts","../src/commands/audit.ts","../src/commands/validate.ts","../src/fs/customer-dir.ts","../src/fs/audit-log.ts","../src/core/rbac.ts","../src/core/session-store.ts","../src/version.ts"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -139,8 +139,8 @@ declare const InteractionEntrySchema: z.ZodObject<{
139
139
  sourceRef: z.ZodString;
140
140
  synced: z.ZodString;
141
141
  }, "strip", z.ZodTypeAny, {
142
- type: "Email" | "Call" | "Meeting" | "Note" | "Demo" | "Proposal" | "Contract" | "Other";
143
142
  date: string;
143
+ type: "Email" | "Call" | "Meeting" | "Note" | "Demo" | "Proposal" | "Contract" | "Other";
144
144
  with: string;
145
145
  summary: string;
146
146
  nextSteps: string[];
@@ -149,8 +149,8 @@ declare const InteractionEntrySchema: z.ZodObject<{
149
149
  direction?: "inbound" | "outbound" | undefined;
150
150
  subject?: string | undefined;
151
151
  }, {
152
- type: "Email" | "Call" | "Meeting" | "Note" | "Demo" | "Proposal" | "Contract" | "Other";
153
152
  date: string;
153
+ type: "Email" | "Call" | "Meeting" | "Note" | "Demo" | "Proposal" | "Contract" | "Other";
154
154
  with: string;
155
155
  summary: string;
156
156
  sourceRef: string;
@@ -516,7 +516,11 @@ interface RbacConfig {
516
516
  declare function getRbacConfig(dataDir: string): RbacConfig;
517
517
  declare function getRole(dataDir: string, actor: string): Role;
518
518
  declare function canSeeCustomer(dataDir: string, actor: string, slug: string): boolean;
519
- /** Load the field-level ACL (field → allowed roles) from rbac.json. */
519
+ /**
520
+ * Build a once-loaded predicate for which customers `actor` may see. Equivalent
521
+ * to calling canSeeCustomer per slug, but reads/parses rbac.json a single time
522
+ * (and uses O(1) Set membership) — for hot loops like list_customers.
523
+ */
520
524
  //#endregion
521
525
  //#region src/core/session-store.d.ts
522
526
  interface Session {
@@ -536,4 +540,4 @@ declare const VERSION = "0.1.0";
536
540
 
537
541
  //#endregion
538
542
  export { type GlobalSources, type InteractionEntry, type KbArticle, type MainFacts, type PipelineDeal, type QuoteLineItem, type Quote as QuoteRecord, type SurveyDefinition, type SurveyResponse, type TicketPriority, type Ticket as TicketRecord, type TicketStatus, VERSION, canSeeCustomer, clearSession, createCustomer, customerExists, filterAuditLog, getRbacConfig, getRole, getSession, readAuditLog, readMainFacts, runAudit, runBackup, runValidate, setSession };
539
- //# sourceMappingURL=index-V8BFaH-b.d.ts.map
543
+ //# sourceMappingURL=index-B0IMMrp_.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-V8BFaH-b.d.ts","names":[],"sources":["../src/schemas/sources.ts","../src/schemas/main-facts.ts","../src/schemas/interaction.ts","../src/schemas/pipeline.ts","../src/schemas/ticket.ts","../src/schemas/quote.ts","../src/schemas/kb-article.ts","../src/schemas/survey.ts","../src/commands/create.ts","../src/commands/backup.ts","../src/commands/audit.ts","../src/commands/validate.ts","../src/fs/customer-dir.ts","../src/fs/audit-log.ts","../src/core/rbac.ts","../src/core/session-store.ts","../src/version.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index-B0IMMrp_.d.ts","names":[],"sources":["../src/schemas/sources.ts","../src/schemas/main-facts.ts","../src/schemas/interaction.ts","../src/schemas/pipeline.ts","../src/schemas/ticket.ts","../src/schemas/quote.ts","../src/schemas/kb-article.ts","../src/schemas/survey.ts","../src/commands/create.ts","../src/commands/backup.ts","../src/commands/audit.ts","../src/commands/validate.ts","../src/fs/customer-dir.ts","../src/fs/audit-log.ts","../src/core/rbac.ts","../src/core/session-store.ts","../src/version.ts"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
- import { C as readMainFacts, S as listCustomerSlugs, T as MainFactsSchema, _ as info, b as customerExists, c as filterAuditLog, g as error, h as bold, i as canSeeCustomer, m as runBackup, n as getSession, o as getRbacConfig, r as setSession, s as getRole, t as clearSession, u as readAuditLog, v as success, w as writeMainFacts, x as ensureCustomerDir, y as warning } from "./session-store-C8tEvMPw.js";
1
+ import { A as writeMainFacts, D as ensureCustomerDir, E as customerExists, N as MainFactsSchema, O as listCustomerSlugs, _ as error, b as warning, c as getRole, d as readAuditLog, g as bold, h as runBackup, i as canSeeCustomer, k as readMainFacts, l as filterAuditLog, n as getSession, r as setSession, s as getRbacConfig, t as clearSession, v as info, w as writeJsonFile, y as success } from "./session-store-DWxJ5Pof.js";
2
+ import { t as writeFileAtomic } from "./atomic-write-8yjqqLtS.js";
2
3
  import { Command } from "commander";
3
4
  import path from "path";
4
5
  import fs from "fs";
@@ -22,28 +23,25 @@ async function createCustomer(opts) {
22
23
  updated: today
23
24
  });
24
25
  const interactionsPath = path.join(dir, "interactions.md");
25
- if (!fs.existsSync(interactionsPath)) fs.writeFileSync(interactionsPath, `# Interactions — ${opts.name}\n\n`);
26
+ if (!fs.existsSync(interactionsPath)) writeFileAtomic(interactionsPath, `# Interactions — ${opts.name}\n\n`);
26
27
  const pipelinePath = path.join(dir, "pipeline.md");
27
- if (!fs.existsSync(pipelinePath)) fs.writeFileSync(pipelinePath, `# Pipeline — ${opts.name}\n\n| Deal | Stage | Value | Currency | Probability | Close Date | Updated | Notes |\n|---|---|---|---|---|---|---|---|\n`);
28
+ if (!fs.existsSync(pipelinePath)) writeFileAtomic(pipelinePath, `# Pipeline — ${opts.name}\n\n| Deal | Stage | Value | Currency | Probability | Close Date | Updated | Notes |\n|---|---|---|---|---|---|---|---|\n`);
28
29
  const sourcesPath = path.join(dir, "sources.json");
29
- if (!fs.existsSync(sourcesPath)) {
30
- const sources = {
31
- gmail: {
32
- type: "gmail",
33
- query: opts.domain ? `from:${opts.domain} OR to:${opts.domain}` : opts.email ? `from:${opts.email} OR to:${opts.email}` : "",
34
- enabled: true
35
- },
36
- version: 1,
37
- created: (/* @__PURE__ */ new Date()).toISOString()
38
- };
39
- fs.writeFileSync(sourcesPath, JSON.stringify(sources, null, 2));
40
- }
30
+ if (!fs.existsSync(sourcesPath)) writeJsonFile(sourcesPath, {
31
+ gmail: {
32
+ type: "gmail",
33
+ query: opts.domain ? `from:${opts.domain} OR to:${opts.domain}` : opts.email ? `from:${opts.email} OR to:${opts.email}` : "",
34
+ enabled: true
35
+ },
36
+ version: 1,
37
+ created: (/* @__PURE__ */ new Date()).toISOString()
38
+ });
41
39
  return {
42
40
  id,
43
41
  dir
44
42
  };
45
43
  }
46
- new Command("create").argument("<name>", "Customer name").option("--domain <domain>", "Primary domain (for Gmail sync)").option("--email <email>", "Primary contact email").action(async (name, opts) => {
44
+ new Command("create").description("Create a new customer").argument("<name>", "Customer name").option("--domain <domain>", "Primary domain (for Gmail sync)").option("--email <email>", "Primary contact email").action(async (name, opts) => {
47
45
  try {
48
46
  const { id, dir } = await createCustomer({
49
47
  name,
@@ -129,17 +127,17 @@ async function runValidate(opts, dataDir) {
129
127
  }
130
128
  try {
131
129
  let content = fs.readFileSync(factsPath, "utf-8");
132
- const { data } = matter(content);
130
+ let parsed = matter(content);
133
131
  if (opts.fix) {
134
- const result = applyFix(factsPath, content, data);
132
+ const result = applyFix(factsPath, content, parsed.data);
135
133
  if (result) {
136
134
  content = result.content;
135
+ parsed = matter(content);
137
136
  fixedCount++;
138
137
  console.log(info(`⚙ ${slug}: fixed ${result.fixed.join(", ")}`));
139
138
  }
140
139
  }
141
- const { data: refetchedData } = matter(content);
142
- MainFactsSchema.parse(refetchedData);
140
+ MainFactsSchema.parse(parsed.data);
143
141
  if (!fs.existsSync(interactionsPath)) console.log(warning(`⚠ ${slug}: missing interactions.md`));
144
142
  else console.log(success(`✓ ${slug}`));
145
143
  } catch (err) {
@@ -153,7 +151,7 @@ async function runValidate(opts, dataDir) {
153
151
  process.exit(1);
154
152
  } else console.log(success("\n✓ All customers valid."));
155
153
  }
156
- new Command("validate").option("--fix", "Auto-fix recoverable issues").action(async (opts) => {
154
+ new Command("validate").description("Validate all customer data against schemas").option("--fix", "Auto-fix recoverable issues").action(async (opts) => {
157
155
  await runValidate(opts, process.env["DXCRM_DATA_DIR"] ?? process.cwd());
158
156
  });
159
157
  //#endregion
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/commands/create.ts","../src/commands/audit.ts","../src/commands/validate.ts","../src/version.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport slugify from \"slug\";\nimport { ensureCustomerDir, writeMainFacts } from \"../fs/customer-dir.js\";\nimport { success, error, bold } from \"../ui/colors.js\";\n\nexport async function createCustomer(opts: {\n name: string;\n domain?: string;\n email?: string;\n dataDir?: string;\n}): Promise<{ id: string; dir: string }> {\n const id = slugify(opts.name, { lower: true });\n const dataDir = opts.dataDir ?? process.env[\"DXCRM_DATA_DIR\"] ?? process.cwd();\n await ensureCustomerDir(dataDir, id);\n const dir = path.join(dataDir, \"customers\", id);\n\n // Write main_facts.md\n const today = new Date().toISOString().slice(0, 10);\n await writeMainFacts(dataDir, id, {\n name: opts.name,\n domain: opts.domain,\n email: opts.email,\n relationship_stage: \"prospect\",\n tags: [],\n currency: \"EUR\",\n created: today,\n updated: today,\n });\n\n // Create interactions.md\n const interactionsPath = path.join(dir, \"interactions.md\");\n if (!fs.existsSync(interactionsPath)) {\n fs.writeFileSync(interactionsPath, `# Interactions — ${opts.name}\\n\\n`);\n }\n\n // Create pipeline.md\n const pipelinePath = path.join(dir, \"pipeline.md\");\n if (!fs.existsSync(pipelinePath)) {\n fs.writeFileSync(\n pipelinePath,\n `# Pipeline — ${opts.name}\\n\\n| Deal | Stage | Value | Currency | Probability | Close Date | Updated | Notes |\\n|---|---|---|---|---|---|---|---|\\n`\n );\n }\n\n // Create sources.json\n const sourcesPath = path.join(dir, \"sources.json\");\n if (!fs.existsSync(sourcesPath)) {\n const gmailQuery = opts.domain\n ? `from:${opts.domain} OR to:${opts.domain}`\n : opts.email\n ? `from:${opts.email} OR to:${opts.email}`\n : \"\";\n const sources = {\n gmail: {\n type: \"gmail\",\n query: gmailQuery,\n enabled: true,\n },\n version: 1,\n created: new Date().toISOString(),\n };\n fs.writeFileSync(sourcesPath, JSON.stringify(sources, null, 2));\n }\n\n return { id, dir };\n}\n\nexport const createCommand = new Command(\"create\")\n .argument(\"<name>\", \"Customer name\")\n .option(\"--domain <domain>\", \"Primary domain (for Gmail sync)\")\n .option(\"--email <email>\", \"Primary contact email\")\n .action(async (name: string, opts: { domain?: string; email?: string }) => {\n try {\n const { id, dir } = await createCustomer({ name, ...opts });\n console.log(success(`✓ Created customer: ${bold(id)}`));\n console.log(` Dir: ${dir}`);\n console.log(` Files: main_facts.md, interactions.md, pipeline.md, sources.json`);\n } catch (err) {\n console.error(error(`✗ ${(err as Error).message}`));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport { readAuditLog, filterAuditLog } from \"../fs/audit-log.js\";\n\nconst SEP = \"─\".repeat(70);\n\nexport async function runAudit(\n opts: {\n slug?: string;\n actor?: string;\n limit?: number;\n tail?: boolean;\n },\n dataDir?: string\n): Promise<void> {\n const dir = dataDir ?? process.cwd();\n const limit = opts.limit ?? 20;\n\n const allEntries = readAuditLog(dir);\n const entries = filterAuditLog(allEntries, {\n ...(opts.slug !== undefined ? { slug: opts.slug } : {}),\n ...(opts.actor !== undefined ? { actor: opts.actor } : {}),\n limit,\n });\n\n console.log(SEP);\n console.log(\" DatasynxOpenCRM — Audit Trail\");\n\n if (opts.slug) console.log(` Customer: ${opts.slug}`);\n if (opts.actor) console.log(` Actor: ${opts.actor}`);\n\n console.log(SEP);\n\n if (entries.length === 0) {\n console.log(\" No audit entries found.\");\n console.log(SEP);\n return;\n }\n\n for (const entry of entries) {\n console.log(\n ` ${entry.timestamp} ${entry.actor.padEnd(12)} ${entry.tool.padEnd(20)} ${entry.slug.padEnd(20)} ${entry.summary}`\n );\n }\n\n console.log(SEP);\n console.log(` ${entries.length} entr${entries.length === 1 ? \"y\" : \"ies\"} shown`);\n console.log(SEP);\n}\n\nexport const auditCommand = new Command(\"audit\")\n .description(\"Show CRM audit trail — who changed what and when\")\n .option(\"--slug <slug>\", \"Filter by customer slug\")\n .option(\"--actor <actor>\", \"Filter by actor\")\n .option(\"--limit <n>\", \"Number of entries to show (default: 20)\", parseInt)\n .option(\"--tail\", \"Show all new entries (simplified: shows current entries)\")\n .action((opts: { slug?: string; actor?: string; limit?: number; tail?: boolean }) =>\n runAudit(opts, process.env[\"DXCRM_DATA_DIR\"])\n );\n","import { Command } from \"commander\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport { MainFactsSchema } from \"../schemas/main-facts.js\";\nimport { listCustomerSlugs } from \"../fs/customer-dir.js\";\nimport matter from \"gray-matter\";\nimport { success, error, warning, info } from \"../ui/colors.js\";\n\nconst RECOVERABLE_DEFAULTS: Record<string, unknown> = {\n tags: [],\n currency: \"EUR\",\n};\n\nexport function applyFix(\n factsPath: string,\n content: string,\n data: Record<string, unknown>\n): { fixed: string[]; content: string } | null {\n const fixed: string[] = [];\n const patched = { ...data };\n\n for (const [field, defaultValue] of Object.entries(RECOVERABLE_DEFAULTS)) {\n if (patched[field] === undefined || patched[field] === null) {\n patched[field] = defaultValue;\n fixed.push(`${field} → ${JSON.stringify(defaultValue)}`);\n }\n }\n\n if (patched[\"updated\"] === undefined && patched[\"created\"]) {\n patched[\"updated\"] = patched[\"created\"];\n fixed.push(`updated → ${String(patched[\"created\"])}`);\n }\n\n if (fixed.length === 0) return null;\n\n const parsed = matter(content);\n const newContent = matter.stringify(parsed.content, patched);\n fs.writeFileSync(factsPath, newContent);\n return { fixed, content: newContent };\n}\n\nexport async function runValidate(opts: { fix?: boolean }, dataDir: string): Promise<void> {\n const customersDir = path.join(dataDir, \"customers\");\n\n if (!fs.existsSync(customersDir)) {\n console.log(warning(\"⚠ No customers directory found.\"));\n return;\n }\n\n const slugs = listCustomerSlugs(dataDir);\n\n let errorCount = 0;\n let fixedCount = 0;\n\n for (const slug of slugs) {\n const factsPath = path.join(customersDir, slug, \"main_facts.md\");\n const interactionsPath = path.join(customersDir, slug, \"interactions.md\");\n\n if (!fs.existsSync(factsPath)) {\n console.log(error(`✗ ${slug}: missing main_facts.md`));\n errorCount++;\n continue;\n }\n\n try {\n let content = fs.readFileSync(factsPath, \"utf-8\") as string;\n const { data } = matter(content);\n\n if (opts.fix) {\n const result = applyFix(factsPath, content, data as Record<string, unknown>);\n if (result) {\n content = result.content;\n fixedCount++;\n console.log(info(`⚙ ${slug}: fixed ${result.fixed.join(\", \")}`));\n }\n }\n\n const { data: refetchedData } = matter(content);\n MainFactsSchema.parse(refetchedData);\n\n if (!fs.existsSync(interactionsPath)) {\n console.log(warning(`⚠ ${slug}: missing interactions.md`));\n } else {\n console.log(success(`✓ ${slug}`));\n }\n } catch (err) {\n console.log(error(`✗ ${slug}: ${(err as Error).message}`));\n errorCount++;\n }\n }\n\n if (opts.fix && fixedCount > 0) {\n console.log(info(`\\n⚙ Fixed ${fixedCount} customer(s).`));\n }\n\n if (errorCount > 0) {\n console.error(error(`\\n${errorCount} error(s) found.`));\n process.exit(1);\n } else {\n console.log(success(\"\\n✓ All customers valid.\"));\n }\n}\n\nexport const validateCommand = new Command(\"validate\")\n .option(\"--fix\", \"Auto-fix recoverable issues\")\n .action(async (opts: { fix?: boolean }) => {\n await runValidate(opts, process.env[\"DXCRM_DATA_DIR\"] ?? process.cwd());\n });\n","export const VERSION = \"0.1.0\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/commands/create.ts","../src/commands/audit.ts","../src/commands/validate.ts","../src/version.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport slugify from \"slug\";\nimport { ensureCustomerDir, writeMainFacts } from \"../fs/customer-dir.js\";\nimport { writeFileAtomic } from \"../fs/atomic-write.js\";\nimport { writeJsonFile } from \"../fs/json-store.js\";\nimport { success, error, bold } from \"../ui/colors.js\";\n\nexport async function createCustomer(opts: {\n name: string;\n domain?: string;\n email?: string;\n dataDir?: string;\n}): Promise<{ id: string; dir: string }> {\n const id = slugify(opts.name, { lower: true });\n const dataDir = opts.dataDir ?? process.env[\"DXCRM_DATA_DIR\"] ?? process.cwd();\n await ensureCustomerDir(dataDir, id);\n const dir = path.join(dataDir, \"customers\", id);\n\n // Write main_facts.md\n const today = new Date().toISOString().slice(0, 10);\n await writeMainFacts(dataDir, id, {\n name: opts.name,\n domain: opts.domain,\n email: opts.email,\n relationship_stage: \"prospect\",\n tags: [],\n currency: \"EUR\",\n created: today,\n updated: today,\n });\n\n // Create interactions.md\n const interactionsPath = path.join(dir, \"interactions.md\");\n if (!fs.existsSync(interactionsPath)) {\n writeFileAtomic(interactionsPath, `# Interactions — ${opts.name}\\n\\n`);\n }\n\n // Create pipeline.md\n const pipelinePath = path.join(dir, \"pipeline.md\");\n if (!fs.existsSync(pipelinePath)) {\n writeFileAtomic(\n pipelinePath,\n `# Pipeline — ${opts.name}\\n\\n| Deal | Stage | Value | Currency | Probability | Close Date | Updated | Notes |\\n|---|---|---|---|---|---|---|---|\\n`\n );\n }\n\n // Create sources.json\n const sourcesPath = path.join(dir, \"sources.json\");\n if (!fs.existsSync(sourcesPath)) {\n const gmailQuery = opts.domain\n ? `from:${opts.domain} OR to:${opts.domain}`\n : opts.email\n ? `from:${opts.email} OR to:${opts.email}`\n : \"\";\n const sources = {\n gmail: {\n type: \"gmail\",\n query: gmailQuery,\n enabled: true,\n },\n version: 1,\n created: new Date().toISOString(),\n };\n writeJsonFile(sourcesPath, sources);\n }\n\n return { id, dir };\n}\n\nexport const createCommand = new Command(\"create\")\n .description(\"Create a new customer\")\n .argument(\"<name>\", \"Customer name\")\n .option(\"--domain <domain>\", \"Primary domain (for Gmail sync)\")\n .option(\"--email <email>\", \"Primary contact email\")\n .action(async (name: string, opts: { domain?: string; email?: string }) => {\n try {\n const { id, dir } = await createCustomer({ name, ...opts });\n console.log(success(`✓ Created customer: ${bold(id)}`));\n console.log(` Dir: ${dir}`);\n console.log(` Files: main_facts.md, interactions.md, pipeline.md, sources.json`);\n } catch (err) {\n console.error(error(`✗ ${(err as Error).message}`));\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\nimport { readAuditLog, filterAuditLog } from \"../fs/audit-log.js\";\n\nconst SEP = \"─\".repeat(70);\n\nexport async function runAudit(\n opts: {\n slug?: string;\n actor?: string;\n limit?: number;\n tail?: boolean;\n },\n dataDir?: string\n): Promise<void> {\n const dir = dataDir ?? process.cwd();\n const limit = opts.limit ?? 20;\n\n const allEntries = readAuditLog(dir);\n const entries = filterAuditLog(allEntries, {\n ...(opts.slug !== undefined ? { slug: opts.slug } : {}),\n ...(opts.actor !== undefined ? { actor: opts.actor } : {}),\n limit,\n });\n\n console.log(SEP);\n console.log(\" DatasynxOpenCRM — Audit Trail\");\n\n if (opts.slug) console.log(` Customer: ${opts.slug}`);\n if (opts.actor) console.log(` Actor: ${opts.actor}`);\n\n console.log(SEP);\n\n if (entries.length === 0) {\n console.log(\" No audit entries found.\");\n console.log(SEP);\n return;\n }\n\n for (const entry of entries) {\n console.log(\n ` ${entry.timestamp} ${entry.actor.padEnd(12)} ${entry.tool.padEnd(20)} ${entry.slug.padEnd(20)} ${entry.summary}`\n );\n }\n\n console.log(SEP);\n console.log(` ${entries.length} entr${entries.length === 1 ? \"y\" : \"ies\"} shown`);\n console.log(SEP);\n}\n\nexport const auditCommand = new Command(\"audit\")\n .description(\"Show CRM audit trail — who changed what and when\")\n .option(\"--slug <slug>\", \"Filter by customer slug\")\n .option(\"--actor <actor>\", \"Filter by actor\")\n .option(\"--limit <n>\", \"Number of entries to show (default: 20)\", parseInt)\n .option(\"--tail\", \"Show all new entries (simplified: shows current entries)\")\n .action((opts: { slug?: string; actor?: string; limit?: number; tail?: boolean }) =>\n runAudit(opts, process.env[\"DXCRM_DATA_DIR\"])\n );\n","import { Command } from \"commander\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport { MainFactsSchema } from \"../schemas/main-facts.js\";\nimport { listCustomerSlugs } from \"../fs/customer-dir.js\";\nimport matter from \"gray-matter\";\nimport { success, error, warning, info } from \"../ui/colors.js\";\n\nconst RECOVERABLE_DEFAULTS: Record<string, unknown> = {\n tags: [],\n currency: \"EUR\",\n};\n\nexport function applyFix(\n factsPath: string,\n content: string,\n data: Record<string, unknown>\n): { fixed: string[]; content: string } | null {\n const fixed: string[] = [];\n const patched = { ...data };\n\n for (const [field, defaultValue] of Object.entries(RECOVERABLE_DEFAULTS)) {\n if (patched[field] === undefined || patched[field] === null) {\n patched[field] = defaultValue;\n fixed.push(`${field} → ${JSON.stringify(defaultValue)}`);\n }\n }\n\n if (patched[\"updated\"] === undefined && patched[\"created\"]) {\n patched[\"updated\"] = patched[\"created\"];\n fixed.push(`updated → ${String(patched[\"created\"])}`);\n }\n\n if (fixed.length === 0) return null;\n\n const parsed = matter(content);\n const newContent = matter.stringify(parsed.content, patched);\n fs.writeFileSync(factsPath, newContent);\n return { fixed, content: newContent };\n}\n\nexport async function runValidate(opts: { fix?: boolean }, dataDir: string): Promise<void> {\n const customersDir = path.join(dataDir, \"customers\");\n\n if (!fs.existsSync(customersDir)) {\n console.log(warning(\"⚠ No customers directory found.\"));\n return;\n }\n\n const slugs = listCustomerSlugs(dataDir);\n\n let errorCount = 0;\n let fixedCount = 0;\n\n for (const slug of slugs) {\n const factsPath = path.join(customersDir, slug, \"main_facts.md\");\n const interactionsPath = path.join(customersDir, slug, \"interactions.md\");\n\n if (!fs.existsSync(factsPath)) {\n console.log(error(`✗ ${slug}: missing main_facts.md`));\n errorCount++;\n continue;\n }\n\n try {\n let content = fs.readFileSync(factsPath, \"utf-8\") as string;\n let parsed = matter(content);\n\n if (opts.fix) {\n const result = applyFix(factsPath, content, parsed.data as Record<string, unknown>);\n if (result) {\n content = result.content;\n parsed = matter(content); // only re-parse when a fix actually rewrote content\n fixedCount++;\n console.log(info(`⚙ ${slug}: fixed ${result.fixed.join(\", \")}`));\n }\n }\n\n MainFactsSchema.parse(parsed.data);\n\n if (!fs.existsSync(interactionsPath)) {\n console.log(warning(`⚠ ${slug}: missing interactions.md`));\n } else {\n console.log(success(`✓ ${slug}`));\n }\n } catch (err) {\n console.log(error(`✗ ${slug}: ${(err as Error).message}`));\n errorCount++;\n }\n }\n\n if (opts.fix && fixedCount > 0) {\n console.log(info(`\\n⚙ Fixed ${fixedCount} customer(s).`));\n }\n\n if (errorCount > 0) {\n console.error(error(`\\n${errorCount} error(s) found.`));\n process.exit(1);\n } else {\n console.log(success(\"\\n✓ All customers valid.\"));\n }\n}\n\nexport const validateCommand = new Command(\"validate\")\n .description(\"Validate all customer data against schemas\")\n .option(\"--fix\", \"Auto-fix recoverable issues\")\n .action(async (opts: { fix?: boolean }) => {\n await runValidate(opts, process.env[\"DXCRM_DATA_DIR\"] ?? process.cwd());\n });\n","export const VERSION = \"0.1.0\";\n"],"mappings":"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"}
@@ -1,4 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
+ import { T as assertSafeSlug } from "./session-store-DWxJ5Pof.js";
3
+ import { t as writeFileAtomic } from "./atomic-write-8yjqqLtS.js";
2
4
  import { t as withFileQueue } from "./write-queue-IbsAjUnh.js";
3
5
  import path from "path";
4
6
  import fs from "fs";
@@ -29,6 +31,7 @@ async function readInteractions(dataDir, slug) {
29
31
  return fs.readFileSync(filePath, "utf-8");
30
32
  }
31
33
  async function appendInteraction(dataDir, slug, entry) {
34
+ assertSafeSlug(slug);
32
35
  const filePath = path.join(dataDir, "customers", slug, "interactions.md");
33
36
  return withFileQueue(filePath, async () => {
34
37
  const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf-8") : "";
@@ -43,10 +46,10 @@ async function appendInteraction(dataDir, slug, entry) {
43
46
  newContent = header + formatted + "\n" + body;
44
47
  } else newContent = existing + "\n" + formatted;
45
48
  }
46
- fs.writeFileSync(filePath, newContent, "utf-8");
49
+ writeFileAtomic(filePath, newContent);
47
50
  });
48
51
  }
49
52
  //#endregion
50
53
  export { readInteractions as i, formatInteractionEntry as n, interactions_writer_exports as r, appendInteraction as t };
51
54
 
52
- //# sourceMappingURL=interactions-writer-DO3KcSR3.js.map
55
+ //# sourceMappingURL=interactions-writer-BZzUIgJd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactions-writer-BZzUIgJd.js","names":[],"sources":["../src/fs/interactions-writer.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport type { InteractionEntry } from \"../schemas/interaction.js\";\nimport { withFileQueue } from \"./write-queue.js\";\nimport { writeFileAtomic } from \"./atomic-write.js\";\nimport { assertSafeSlug } from \"./customer-dir.js\";\n\nconst INTERACTION_SEPARATOR = \"---\";\n\nexport function formatInteractionEntry(entry: InteractionEntry): string {\n const header = `## ${entry.date} · ${entry.type}${entry.direction ? ` · ${entry.direction}` : \"\"}`;\n const withLabel = entry.type === \"Email\" ? \"Subject\" : \"With\";\n const nextStepsBlock =\n entry.nextSteps.length > 0 ? entry.nextSteps.map((s) => `- [ ] ${s}`).join(\"\\n\") : \"- [ ] —\";\n\n return `${header}\n**${withLabel}:** ${entry.with}\n**Summary:** ${entry.summary}\n**Next Steps:**\n${nextStepsBlock}\n**Source:** ${entry.sourceRef}\n**Synced:** ${entry.synced}\n${INTERACTION_SEPARATOR}\n`;\n}\n\nexport async function readInteractions(dataDir: string, slug: string): Promise<string> {\n const filePath = path.join(dataDir, \"customers\", slug, \"interactions.md\");\n if (!fs.existsSync(filePath)) {\n return \"\";\n }\n return fs.readFileSync(filePath, \"utf-8\");\n}\n\n/**\n * Per-run source-ref deduplication index for bulk imports. Loads each slug's\n * interactions file once (not once per row) and tracks freshly-appended refs\n * in memory, so a 5k-row import stays linear instead of re-reading a growing\n * file on every row (the previous O(rows²) behavior).\n */\nexport class InteractionDedup {\n private readonly cache = new Map<string, string>();\n constructor(private readonly dataDir: string) {}\n\n /** True if `sourceRef` already exists for `slug` (on disk or appended this run). */\n async seen(slug: string, sourceRef: string): Promise<boolean> {\n let content = this.cache.get(slug);\n if (content === undefined) {\n content = await readInteractions(this.dataDir, slug).catch(() => \"\");\n this.cache.set(slug, content);\n }\n return content.includes(sourceRef);\n }\n\n /** Record that `sourceRef` was just appended, so later rows dedupe against it. */\n markAppended(slug: string, sourceRef: string): void {\n this.cache.set(slug, (this.cache.get(slug) ?? \"\") + sourceRef);\n }\n}\n\nexport async function appendInteraction(\n dataDir: string,\n slug: string,\n entry: InteractionEntry\n): Promise<void> {\n assertSafeSlug(slug);\n const filePath = path.join(dataDir, \"customers\", slug, \"interactions.md\");\n return withFileQueue(filePath, async () => {\n const existing = fs.existsSync(filePath) ? (fs.readFileSync(filePath, \"utf-8\") as string) : \"\";\n\n const formatted = formatInteractionEntry(entry);\n\n let newContent: string;\n if (existing === \"\") {\n newContent = formatted;\n } else {\n const headerEnd = existing.indexOf(\"\\n\\n\");\n if (headerEnd > -1) {\n const header = existing.slice(0, headerEnd + 2);\n const body = existing.slice(headerEnd + 2);\n newContent = header + formatted + \"\\n\" + body;\n } else {\n newContent = existing + \"\\n\" + formatted;\n }\n }\n\n writeFileAtomic(filePath, newContent);\n });\n}\n"],"mappings":";;;;;;;;;;;;AAOA,MAAM,wBAAwB;AAE9B,SAAgB,uBAAuB,OAAiC;CACtE,MAAM,SAAS,MAAM,MAAM,KAAK,KAAK,MAAM,OAAO,MAAM,YAAY,MAAM,MAAM,cAAc;CAC9F,MAAM,YAAY,MAAM,SAAS,UAAU,YAAY;CACvD,MAAM,iBACJ,MAAM,UAAU,SAAS,IAAI,MAAM,UAAU,KAAK,MAAM,SAAS,GAAG,EAAE,KAAK,IAAI,IAAI;CAErF,OAAO,GAAG,OAAO;IACf,UAAU,MAAM,MAAM,KAAK;eAChB,MAAM,QAAQ;;EAE3B,eAAe;cACH,MAAM,UAAU;cAChB,MAAM,OAAO;EACzB,sBAAsB;;AAExB;AAEA,eAAsB,iBAAiB,SAAiB,MAA+B;CACrF,MAAM,WAAW,KAAK,KAAK,SAAS,aAAa,MAAM,iBAAiB;CACxE,IAAI,CAAC,GAAG,WAAW,QAAQ,GACzB,OAAO;CAET,OAAO,GAAG,aAAa,UAAU,OAAO;AAC1C;AA4BA,eAAsB,kBACpB,SACA,MACA,OACe;CACf,eAAe,IAAI;CACnB,MAAM,WAAW,KAAK,KAAK,SAAS,aAAa,MAAM,iBAAiB;CACxE,OAAO,cAAc,UAAU,YAAY;EACzC,MAAM,WAAW,GAAG,WAAW,QAAQ,IAAK,GAAG,aAAa,UAAU,OAAO,IAAe;EAE5F,MAAM,YAAY,uBAAuB,KAAK;EAE9C,IAAI;EACJ,IAAI,aAAa,IACf,aAAa;OACR;GACL,MAAM,YAAY,SAAS,QAAQ,MAAM;GACzC,IAAI,YAAY,IAAI;IAClB,MAAM,SAAS,SAAS,MAAM,GAAG,YAAY,CAAC;IAC9C,MAAM,OAAO,SAAS,MAAM,YAAY,CAAC;IACzC,aAAa,SAAS,YAAY,OAAO;GAC3C,OACE,aAAa,WAAW,OAAO;EAEnC;EAEA,gBAAgB,UAAU,UAAU;CACtC,CAAC;AACH"}
@@ -1,3 +1,5 @@
1
+ import { t as assertSafeSlug } from "./customer-dir-CkMMXhb0.js";
2
+ import { t as writeFileAtomic } from "./atomic-write-8yjqqLtS.js";
1
3
  import { t as withFileQueue } from "./write-queue-IbsAjUnh.js";
2
4
  import path from "path";
3
5
  import fs from "fs";
@@ -22,7 +24,34 @@ async function readInteractions(dataDir, slug) {
22
24
  if (!fs.existsSync(filePath)) return "";
23
25
  return fs.readFileSync(filePath, "utf-8");
24
26
  }
27
+ /**
28
+ * Per-run source-ref deduplication index for bulk imports. Loads each slug's
29
+ * interactions file once (not once per row) and tracks freshly-appended refs
30
+ * in memory, so a 5k-row import stays linear instead of re-reading a growing
31
+ * file on every row (the previous O(rows²) behavior).
32
+ */
33
+ var InteractionDedup = class {
34
+ dataDir;
35
+ cache = /* @__PURE__ */ new Map();
36
+ constructor(dataDir) {
37
+ this.dataDir = dataDir;
38
+ }
39
+ /** True if `sourceRef` already exists for `slug` (on disk or appended this run). */
40
+ async seen(slug, sourceRef) {
41
+ let content = this.cache.get(slug);
42
+ if (content === void 0) {
43
+ content = await readInteractions(this.dataDir, slug).catch(() => "");
44
+ this.cache.set(slug, content);
45
+ }
46
+ return content.includes(sourceRef);
47
+ }
48
+ /** Record that `sourceRef` was just appended, so later rows dedupe against it. */
49
+ markAppended(slug, sourceRef) {
50
+ this.cache.set(slug, (this.cache.get(slug) ?? "") + sourceRef);
51
+ }
52
+ };
25
53
  async function appendInteraction(dataDir, slug, entry) {
54
+ assertSafeSlug(slug);
26
55
  const filePath = path.join(dataDir, "customers", slug, "interactions.md");
27
56
  return withFileQueue(filePath, async () => {
28
57
  const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf-8") : "";
@@ -37,10 +66,10 @@ async function appendInteraction(dataDir, slug, entry) {
37
66
  newContent = header + formatted + "\n" + body;
38
67
  } else newContent = existing + "\n" + formatted;
39
68
  }
40
- fs.writeFileSync(filePath, newContent, "utf-8");
69
+ writeFileAtomic(filePath, newContent);
41
70
  });
42
71
  }
43
72
  //#endregion
44
- export { formatInteractionEntry as n, readInteractions as r, appendInteraction as t };
73
+ export { readInteractions as i, appendInteraction as n, formatInteractionEntry as r, InteractionDedup as t };
45
74
 
46
- //# sourceMappingURL=interactions-writer-SLHnoEeE.js.map
75
+ //# sourceMappingURL=interactions-writer-DbSyI2rt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactions-writer-DbSyI2rt.js","names":[],"sources":["../src/fs/interactions-writer.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport type { InteractionEntry } from \"../schemas/interaction.js\";\nimport { withFileQueue } from \"./write-queue.js\";\nimport { writeFileAtomic } from \"./atomic-write.js\";\nimport { assertSafeSlug } from \"./customer-dir.js\";\n\nconst INTERACTION_SEPARATOR = \"---\";\n\nexport function formatInteractionEntry(entry: InteractionEntry): string {\n const header = `## ${entry.date} · ${entry.type}${entry.direction ? ` · ${entry.direction}` : \"\"}`;\n const withLabel = entry.type === \"Email\" ? \"Subject\" : \"With\";\n const nextStepsBlock =\n entry.nextSteps.length > 0 ? entry.nextSteps.map((s) => `- [ ] ${s}`).join(\"\\n\") : \"- [ ] —\";\n\n return `${header}\n**${withLabel}:** ${entry.with}\n**Summary:** ${entry.summary}\n**Next Steps:**\n${nextStepsBlock}\n**Source:** ${entry.sourceRef}\n**Synced:** ${entry.synced}\n${INTERACTION_SEPARATOR}\n`;\n}\n\nexport async function readInteractions(dataDir: string, slug: string): Promise<string> {\n const filePath = path.join(dataDir, \"customers\", slug, \"interactions.md\");\n if (!fs.existsSync(filePath)) {\n return \"\";\n }\n return fs.readFileSync(filePath, \"utf-8\");\n}\n\n/**\n * Per-run source-ref deduplication index for bulk imports. Loads each slug's\n * interactions file once (not once per row) and tracks freshly-appended refs\n * in memory, so a 5k-row import stays linear instead of re-reading a growing\n * file on every row (the previous O(rows²) behavior).\n */\nexport class InteractionDedup {\n private readonly cache = new Map<string, string>();\n constructor(private readonly dataDir: string) {}\n\n /** True if `sourceRef` already exists for `slug` (on disk or appended this run). */\n async seen(slug: string, sourceRef: string): Promise<boolean> {\n let content = this.cache.get(slug);\n if (content === undefined) {\n content = await readInteractions(this.dataDir, slug).catch(() => \"\");\n this.cache.set(slug, content);\n }\n return content.includes(sourceRef);\n }\n\n /** Record that `sourceRef` was just appended, so later rows dedupe against it. */\n markAppended(slug: string, sourceRef: string): void {\n this.cache.set(slug, (this.cache.get(slug) ?? \"\") + sourceRef);\n }\n}\n\nexport async function appendInteraction(\n dataDir: string,\n slug: string,\n entry: InteractionEntry\n): Promise<void> {\n assertSafeSlug(slug);\n const filePath = path.join(dataDir, \"customers\", slug, \"interactions.md\");\n return withFileQueue(filePath, async () => {\n const existing = fs.existsSync(filePath) ? (fs.readFileSync(filePath, \"utf-8\") as string) : \"\";\n\n const formatted = formatInteractionEntry(entry);\n\n let newContent: string;\n if (existing === \"\") {\n newContent = formatted;\n } else {\n const headerEnd = existing.indexOf(\"\\n\\n\");\n if (headerEnd > -1) {\n const header = existing.slice(0, headerEnd + 2);\n const body = existing.slice(headerEnd + 2);\n newContent = header + formatted + \"\\n\" + body;\n } else {\n newContent = existing + \"\\n\" + formatted;\n }\n }\n\n writeFileAtomic(filePath, newContent);\n });\n}\n"],"mappings":";;;;;;AAOA,MAAM,wBAAwB;AAE9B,SAAgB,uBAAuB,OAAiC;CACtE,MAAM,SAAS,MAAM,MAAM,KAAK,KAAK,MAAM,OAAO,MAAM,YAAY,MAAM,MAAM,cAAc;CAC9F,MAAM,YAAY,MAAM,SAAS,UAAU,YAAY;CACvD,MAAM,iBACJ,MAAM,UAAU,SAAS,IAAI,MAAM,UAAU,KAAK,MAAM,SAAS,GAAG,EAAE,KAAK,IAAI,IAAI;CAErF,OAAO,GAAG,OAAO;IACf,UAAU,MAAM,MAAM,KAAK;eAChB,MAAM,QAAQ;;EAE3B,eAAe;cACH,MAAM,UAAU;cAChB,MAAM,OAAO;EACzB,sBAAsB;;AAExB;AAEA,eAAsB,iBAAiB,SAAiB,MAA+B;CACrF,MAAM,WAAW,KAAK,KAAK,SAAS,aAAa,MAAM,iBAAiB;CACxE,IAAI,CAAC,GAAG,WAAW,QAAQ,GACzB,OAAO;CAET,OAAO,GAAG,aAAa,UAAU,OAAO;AAC1C;;;;;;;AAQA,IAAa,mBAAb,MAA8B;CAEC;CAD7B,wBAAyB,IAAI,IAAoB;CACjD,YAAY,SAAkC;EAAjB,KAAA,UAAA;CAAkB;;CAG/C,MAAM,KAAK,MAAc,WAAqC;EAC5D,IAAI,UAAU,KAAK,MAAM,IAAI,IAAI;EACjC,IAAI,YAAY,KAAA,GAAW;GACzB,UAAU,MAAM,iBAAiB,KAAK,SAAS,IAAI,EAAE,YAAY,EAAE;GACnE,KAAK,MAAM,IAAI,MAAM,OAAO;EAC9B;EACA,OAAO,QAAQ,SAAS,SAAS;CACnC;;CAGA,aAAa,MAAc,WAAyB;EAClD,KAAK,MAAM,IAAI,OAAO,KAAK,MAAM,IAAI,IAAI,KAAK,MAAM,SAAS;CAC/D;AACF;AAEA,eAAsB,kBACpB,SACA,MACA,OACe;CACf,eAAe,IAAI;CACnB,MAAM,WAAW,KAAK,KAAK,SAAS,aAAa,MAAM,iBAAiB;CACxE,OAAO,cAAc,UAAU,YAAY;EACzC,MAAM,WAAW,GAAG,WAAW,QAAQ,IAAK,GAAG,aAAa,UAAU,OAAO,IAAe;EAE5F,MAAM,YAAY,uBAAuB,KAAK;EAE9C,IAAI;EACJ,IAAI,aAAa,IACf,aAAa;OACR;GACL,MAAM,YAAY,SAAS,QAAQ,MAAM;GACzC,IAAI,YAAY,IAAI;IAClB,MAAM,SAAS,SAAS,MAAM,GAAG,YAAY,CAAC;IAC9C,MAAM,OAAO,SAAS,MAAM,YAAY,CAAC;IACzC,aAAa,SAAS,YAAY,OAAO;GAC3C,OACE,aAAa,WAAW,OAAO;EAEnC;EAEA,gBAAgB,UAAU,UAAU;CACtC,CAAC;AACH"}
@@ -0,0 +1,2 @@
1
+ import { i as readInteractions, n as appendInteraction, t as InteractionDedup } from "./interactions-writer-DbSyI2rt.js";
2
+ export { InteractionDedup, appendInteraction, readInteractions };
@@ -1,4 +1,6 @@
1
1
  const require_chunk = require("./chunk-DakpK96I.cjs");
2
+ const require_session_store = require("./session-store-yfwnj0OC.cjs");
3
+ const require_atomic_write = require("./atomic-write-BYmF-ThH.cjs");
2
4
  const require_write_queue = require("./write-queue-BDolUxfs.cjs");
3
5
  let path = require("path");
4
6
  path = require_chunk.__toESM(path, 1);
@@ -31,6 +33,7 @@ async function readInteractions(dataDir, slug) {
31
33
  return fs.default.readFileSync(filePath, "utf-8");
32
34
  }
33
35
  async function appendInteraction(dataDir, slug, entry) {
36
+ require_session_store.assertSafeSlug(slug);
34
37
  const filePath = path.default.join(dataDir, "customers", slug, "interactions.md");
35
38
  return require_write_queue.withFileQueue(filePath, async () => {
36
39
  const existing = fs.default.existsSync(filePath) ? fs.default.readFileSync(filePath, "utf-8") : "";
@@ -45,7 +48,7 @@ async function appendInteraction(dataDir, slug, entry) {
45
48
  newContent = header + formatted + "\n" + body;
46
49
  } else newContent = existing + "\n" + formatted;
47
50
  }
48
- fs.default.writeFileSync(filePath, newContent, "utf-8");
51
+ require_atomic_write.writeFileAtomic(filePath, newContent);
49
52
  });
50
53
  }
51
54
  //#endregion
@@ -74,4 +77,4 @@ Object.defineProperty(exports, "readInteractions", {
74
77
  }
75
78
  });
76
79
 
77
- //# sourceMappingURL=interactions-writer-CrPStUll.cjs.map
80
+ //# sourceMappingURL=interactions-writer-a2yzBd7T.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactions-writer-a2yzBd7T.cjs","names":["withFileQueue"],"sources":["../src/fs/interactions-writer.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport type { InteractionEntry } from \"../schemas/interaction.js\";\nimport { withFileQueue } from \"./write-queue.js\";\nimport { writeFileAtomic } from \"./atomic-write.js\";\nimport { assertSafeSlug } from \"./customer-dir.js\";\n\nconst INTERACTION_SEPARATOR = \"---\";\n\nexport function formatInteractionEntry(entry: InteractionEntry): string {\n const header = `## ${entry.date} · ${entry.type}${entry.direction ? ` · ${entry.direction}` : \"\"}`;\n const withLabel = entry.type === \"Email\" ? \"Subject\" : \"With\";\n const nextStepsBlock =\n entry.nextSteps.length > 0 ? entry.nextSteps.map((s) => `- [ ] ${s}`).join(\"\\n\") : \"- [ ] —\";\n\n return `${header}\n**${withLabel}:** ${entry.with}\n**Summary:** ${entry.summary}\n**Next Steps:**\n${nextStepsBlock}\n**Source:** ${entry.sourceRef}\n**Synced:** ${entry.synced}\n${INTERACTION_SEPARATOR}\n`;\n}\n\nexport async function readInteractions(dataDir: string, slug: string): Promise<string> {\n const filePath = path.join(dataDir, \"customers\", slug, \"interactions.md\");\n if (!fs.existsSync(filePath)) {\n return \"\";\n }\n return fs.readFileSync(filePath, \"utf-8\");\n}\n\n/**\n * Per-run source-ref deduplication index for bulk imports. Loads each slug's\n * interactions file once (not once per row) and tracks freshly-appended refs\n * in memory, so a 5k-row import stays linear instead of re-reading a growing\n * file on every row (the previous O(rows²) behavior).\n */\nexport class InteractionDedup {\n private readonly cache = new Map<string, string>();\n constructor(private readonly dataDir: string) {}\n\n /** True if `sourceRef` already exists for `slug` (on disk or appended this run). */\n async seen(slug: string, sourceRef: string): Promise<boolean> {\n let content = this.cache.get(slug);\n if (content === undefined) {\n content = await readInteractions(this.dataDir, slug).catch(() => \"\");\n this.cache.set(slug, content);\n }\n return content.includes(sourceRef);\n }\n\n /** Record that `sourceRef` was just appended, so later rows dedupe against it. */\n markAppended(slug: string, sourceRef: string): void {\n this.cache.set(slug, (this.cache.get(slug) ?? \"\") + sourceRef);\n }\n}\n\nexport async function appendInteraction(\n dataDir: string,\n slug: string,\n entry: InteractionEntry\n): Promise<void> {\n assertSafeSlug(slug);\n const filePath = path.join(dataDir, \"customers\", slug, \"interactions.md\");\n return withFileQueue(filePath, async () => {\n const existing = fs.existsSync(filePath) ? (fs.readFileSync(filePath, \"utf-8\") as string) : \"\";\n\n const formatted = formatInteractionEntry(entry);\n\n let newContent: string;\n if (existing === \"\") {\n newContent = formatted;\n } else {\n const headerEnd = existing.indexOf(\"\\n\\n\");\n if (headerEnd > -1) {\n const header = existing.slice(0, headerEnd + 2);\n const body = existing.slice(headerEnd + 2);\n newContent = header + formatted + \"\\n\" + body;\n } else {\n newContent = existing + \"\\n\" + formatted;\n }\n }\n\n writeFileAtomic(filePath, newContent);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;AAOA,MAAM,wBAAwB;AAE9B,SAAgB,uBAAuB,OAAiC;CACtE,MAAM,SAAS,MAAM,MAAM,KAAK,KAAK,MAAM,OAAO,MAAM,YAAY,MAAM,MAAM,cAAc;CAC9F,MAAM,YAAY,MAAM,SAAS,UAAU,YAAY;CACvD,MAAM,iBACJ,MAAM,UAAU,SAAS,IAAI,MAAM,UAAU,KAAK,MAAM,SAAS,GAAG,EAAE,KAAK,IAAI,IAAI;CAErF,OAAO,GAAG,OAAO;IACf,UAAU,MAAM,MAAM,KAAK;eAChB,MAAM,QAAQ;;EAE3B,eAAe;cACH,MAAM,UAAU;cAChB,MAAM,OAAO;EACzB,sBAAsB;;AAExB;AAEA,eAAsB,iBAAiB,SAAiB,MAA+B;CACrF,MAAM,WAAW,KAAA,QAAK,KAAK,SAAS,aAAa,MAAM,iBAAiB;CACxE,IAAI,CAAC,GAAA,QAAG,WAAW,QAAQ,GACzB,OAAO;CAET,OAAO,GAAA,QAAG,aAAa,UAAU,OAAO;AAC1C;AA4BA,eAAsB,kBACpB,SACA,MACA,OACe;CACf,sBAAA,eAAe,IAAI;CACnB,MAAM,WAAW,KAAA,QAAK,KAAK,SAAS,aAAa,MAAM,iBAAiB;CACxE,OAAOA,oBAAAA,cAAc,UAAU,YAAY;EACzC,MAAM,WAAW,GAAA,QAAG,WAAW,QAAQ,IAAK,GAAA,QAAG,aAAa,UAAU,OAAO,IAAe;EAE5F,MAAM,YAAY,uBAAuB,KAAK;EAE9C,IAAI;EACJ,IAAI,aAAa,IACf,aAAa;OACR;GACL,MAAM,YAAY,SAAS,QAAQ,MAAM;GACzC,IAAI,YAAY,IAAI;IAClB,MAAM,SAAS,SAAS,MAAM,GAAG,YAAY,CAAC;IAC9C,MAAM,OAAO,SAAS,MAAM,YAAY,CAAC;IACzC,aAAa,SAAS,YAAY,OAAO;GAC3C,OACE,aAAa,WAAW,OAAO;EAEnC;EAEA,qBAAA,gBAAgB,UAAU,UAAU;CACtC,CAAC;AACH"}
@@ -0,0 +1,43 @@
1
+ import { t as writeFileAtomic } from "./atomic-write-8yjqqLtS.js";
2
+ import fs from "fs";
3
+ //#region src/fs/json-store.ts
4
+ /**
5
+ * Small shared JSON persistence helpers. Many modules independently reimplemented
6
+ * the same "read a JSON file, fall back to a default on missing/parse-error" and
7
+ * "write a `{ key: items }` array store" logic — this centralizes both so the
8
+ * behavior (and the silent-fallback semantics) is defined in exactly one place.
9
+ *
10
+ * Writes go through writeFileAtomic, so a crash mid-write can never leave a
11
+ * half-written (corrupt) JSON file — readers always see either the old or the
12
+ * new complete document. This matters for the config, audit, and state files
13
+ * the whole product depends on.
14
+ */
15
+ /** Read and parse a JSON file, returning `fallback` if it is missing or invalid. */
16
+ function readJsonFile(filePath, fallback) {
17
+ if (!fs.existsSync(filePath)) return fallback;
18
+ try {
19
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
20
+ } catch {
21
+ return fallback;
22
+ }
23
+ }
24
+ /** Atomically write `value` as pretty-printed JSON, creating parent dirs as needed. */
25
+ function writeJsonFile(filePath, value) {
26
+ writeFileAtomic(filePath, JSON.stringify(value, null, 2));
27
+ }
28
+ /**
29
+ * Read an array stored under `key` in a `{ [key]: T[] }` JSON document. Returns
30
+ * an empty array if the file is missing, unparsable, or the key is not an array.
31
+ */
32
+ function readJsonArray(filePath, key) {
33
+ const arr = readJsonFile(filePath, {})[key];
34
+ return Array.isArray(arr) ? arr : [];
35
+ }
36
+ /** Write an array under `key` as a `{ [key]: items }` JSON document. */
37
+ function writeJsonArray(filePath, key, items) {
38
+ writeJsonFile(filePath, { [key]: items });
39
+ }
40
+ //#endregion
41
+ export { writeJsonFile as i, readJsonFile as n, writeJsonArray as r, readJsonArray as t };
42
+
43
+ //# sourceMappingURL=json-store-WWsFzXub.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-store-WWsFzXub.js","names":[],"sources":["../src/fs/json-store.ts"],"sourcesContent":["import fs from \"fs\";\nimport { writeFileAtomic } from \"./atomic-write.js\";\n\n/**\n * Small shared JSON persistence helpers. Many modules independently reimplemented\n * the same \"read a JSON file, fall back to a default on missing/parse-error\" and\n * \"write a `{ key: items }` array store\" logic — this centralizes both so the\n * behavior (and the silent-fallback semantics) is defined in exactly one place.\n *\n * Writes go through writeFileAtomic, so a crash mid-write can never leave a\n * half-written (corrupt) JSON file — readers always see either the old or the\n * new complete document. This matters for the config, audit, and state files\n * the whole product depends on.\n */\n\n/** Read and parse a JSON file, returning `fallback` if it is missing or invalid. */\nexport function readJsonFile<T>(filePath: string, fallback: T): T {\n if (!fs.existsSync(filePath)) return fallback;\n try {\n return JSON.parse(fs.readFileSync(filePath, \"utf-8\") as string) as T;\n } catch {\n return fallback;\n }\n}\n\n/** Atomically write `value` as pretty-printed JSON, creating parent dirs as needed. */\nexport function writeJsonFile(filePath: string, value: unknown): void {\n writeFileAtomic(filePath, JSON.stringify(value, null, 2));\n}\n\n/**\n * Read an array stored under `key` in a `{ [key]: T[] }` JSON document. Returns\n * an empty array if the file is missing, unparsable, or the key is not an array.\n */\nexport function readJsonArray<T>(filePath: string, key: string): T[] {\n const data = readJsonFile<Record<string, unknown>>(filePath, {});\n const arr = data[key];\n return Array.isArray(arr) ? (arr as T[]) : [];\n}\n\n/** Write an array under `key` as a `{ [key]: items }` JSON document. */\nexport function writeJsonArray<T>(filePath: string, key: string, items: T[]): void {\n writeJsonFile(filePath, { [key]: items });\n}\n"],"mappings":";;;;;;;;;;;;;;;AAgBA,SAAgB,aAAgB,UAAkB,UAAgB;CAChE,IAAI,CAAC,GAAG,WAAW,QAAQ,GAAG,OAAO;CACrC,IAAI;EACF,OAAO,KAAK,MAAM,GAAG,aAAa,UAAU,OAAO,CAAW;CAChE,QAAQ;EACN,OAAO;CACT;AACF;;AAGA,SAAgB,cAAc,UAAkB,OAAsB;CACpE,gBAAgB,UAAU,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAC1D;;;;;AAMA,SAAgB,cAAiB,UAAkB,KAAkB;CAEnE,MAAM,MADO,aAAsC,UAAU,CAAC,CAC/C,EAAE;CACjB,OAAO,MAAM,QAAQ,GAAG,IAAK,MAAc,CAAC;AAC9C;;AAGA,SAAgB,eAAkB,UAAkB,KAAa,OAAkB;CACjF,cAAc,UAAU,GAAG,MAAM,MAAM,CAAC;AAC1C"}