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