@datasynx/agentic-crm 0.1.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +270 -669
- package/dist/{approvals-DpjxGHFp.js → approvals-CmDT2eUg.js} +7 -24
- package/dist/approvals-CmDT2eUg.js.map +1 -0
- package/dist/{ask-CID3jnuL.js → ask-CDysGnRg.js} +6 -6
- package/dist/{ask-CID3jnuL.js.map → ask-CDysGnRg.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/attachments-CX2GAtsw.cjs +517 -0
- package/dist/attachments-CX2GAtsw.cjs.map +1 -0
- package/dist/attachments-D207gXfN.js +514 -0
- package/dist/attachments-D207gXfN.js.map +1 -0
- package/dist/attachments-rLa96rOK.js +514 -0
- package/dist/attachments-rLa96rOK.js.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/chunk-BfDYWZQ8.cjs +32 -0
- package/dist/chunk-BfDYWZQ8.cjs.map +1 -0
- package/dist/chunk-BhUZmQg5.js +32 -0
- package/dist/chunk-BhUZmQg5.js.map +1 -0
- package/dist/chunk-ChC83jai.js +2 -0
- package/dist/chunk-e_w8qqtP.js +32 -0
- package/dist/chunk-e_w8qqtP.js.map +1 -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 +285 -186
- 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/email-body-BFSRa0AW.cjs +42 -0
- package/dist/email-body-BFSRa0AW.cjs.map +1 -0
- package/dist/email-body-BOd7U-D2.js +42 -0
- package/dist/email-body-BOd7U-D2.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-DIaxInDT.js → gmail-sync-B4Iu3AQb.js} +56 -22
- package/dist/gmail-sync-B4Iu3AQb.js.map +1 -0
- package/dist/{gmail-sync-hHm9gaWd.cjs → gmail-sync-BpSVESSe.cjs} +55 -21
- package/dist/gmail-sync-BpSVESSe.cjs.map +1 -0
- package/dist/{gmail-sync-rQaVqKWd.js → gmail-sync-DIbrPnTK.js} +55 -21
- package/dist/gmail-sync-DIbrPnTK.js.map +1 -0
- package/dist/{gmail-webhook-handler-e5Od25FX.js → gmail-webhook-handler-BzOFbvgh.js} +4 -4
- package/dist/{gmail-webhook-handler-e5Od25FX.js.map → gmail-webhook-handler-BzOFbvgh.js.map} +1 -1
- package/dist/{gmail-webhook-handler-DS7OlRPX.js → gmail-webhook-handler-CvSDW_Js.js} +2 -2
- 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-B_I1d54Y.js} +3 -3
- package/dist/{google-drive-sync-DEPcqFca.js.map → google-drive-sync-B_I1d54Y.js.map} +1 -1
- package/dist/html-BaeOCZKE.js +36 -0
- package/dist/html-BaeOCZKE.js.map +1 -0
- package/dist/html-CmOku6jS.cjs +47 -0
- package/dist/html-CmOku6jS.cjs.map +1 -0
- 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-CTId9IGV.js} +51 -45
- package/dist/import-hubspot-CTId9IGV.js.map +1 -0
- package/dist/{index-YqwMd6aQ.d.cts → index-BAutNcAT.d.cts} +20 -12
- package/dist/index-BAutNcAT.d.cts.map +1 -0
- package/dist/{index-V8BFaH-b.d.ts → index-FzDsNSSb.d.ts} +12 -4
- package/dist/index-FzDsNSSb.d.ts.map +1 -0
- package/dist/index.cjs +19 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -12
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +12 -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-B2y-73lh.js +2 -0
- package/dist/{interactions-writer-SLHnoEeE.js → interactions-writer-B8XAzdqR.js} +34 -4
- package/dist/interactions-writer-B8XAzdqR.js.map +1 -0
- package/dist/{interactions-writer-CrPStUll.cjs → interactions-writer-BRJNrefF.cjs} +7 -3
- package/dist/interactions-writer-BRJNrefF.cjs.map +1 -0
- package/dist/{interactions-writer-DO3KcSR3.js → interactions-writer-ZQcpFOh9.js} +7 -3
- package/dist/interactions-writer-ZQcpFOh9.js.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--063Kpa3.js} +51 -22
- package/dist/knowledge-base--063Kpa3.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 +365 -319
- 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 +365 -319
- 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-BgVR8GDv.js} +4 -4
- package/dist/{microsoft-calendar-B6MMtUQK.js.map → microsoft-calendar-BgVR8GDv.js.map} +1 -1
- package/dist/{microsoft-sync-CpZVoSuq.js → microsoft-sync-D30_XksI.js} +5 -5
- package/dist/{microsoft-sync-CpZVoSuq.js.map → microsoft-sync-D30_XksI.js.map} +1 -1
- package/dist/{nba-3wanmJ0U.js → nba-DwdfM93s.js} +3 -3
- package/dist/{nba-3wanmJ0U.js.map → nba-DwdfM93s.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-DoRPPOeR.js} +308 -230
- package/dist/server-DoRPPOeR.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-BoClrJAz.js} +18 -11
- package/dist/transcript-watcher-BoClrJAz.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 +22 -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/index-V8BFaH-b.d.ts.map +0 -1
- package/dist/index-YqwMd6aQ.d.cts.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
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as loadMemories, r as searchMemory, t as addMemory } from "./memory-
|
|
1
|
+
import { n as loadMemories, r as searchMemory, t as addMemory } from "./memory-Dzr9dXSM.js";
|
|
2
2
|
export { addMemory, loadMemories, searchMemory };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { r as writeJsonArray, t as readJsonArray } from "./json-store-WWsFzXub.js";
|
|
1
2
|
import { t as hybridSearch } from "./hybrid-search-BmHttLrR.js";
|
|
2
3
|
import path from "path";
|
|
3
|
-
import fs from "fs";
|
|
4
4
|
import { randomBytes } from "crypto";
|
|
5
5
|
//#region src/core/memory.ts
|
|
6
6
|
function globalPath(dataDir) {
|
|
@@ -10,17 +10,10 @@ function customerPath(dataDir, slug) {
|
|
|
10
10
|
return path.join(dataDir, "customers", slug, "memory.json");
|
|
11
11
|
}
|
|
12
12
|
function readFile(p) {
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
const data = JSON.parse(fs.readFileSync(p, "utf-8"));
|
|
16
|
-
return Array.isArray(data.memories) ? data.memories : [];
|
|
17
|
-
} catch {
|
|
18
|
-
return [];
|
|
19
|
-
}
|
|
13
|
+
return readJsonArray(p, "memories");
|
|
20
14
|
}
|
|
21
15
|
function writeFile(p, memories) {
|
|
22
|
-
|
|
23
|
-
fs.writeFileSync(p, JSON.stringify({ memories }, null, 2), "utf-8");
|
|
16
|
+
writeJsonArray(p, "memories", memories);
|
|
24
17
|
}
|
|
25
18
|
function addMemory(dataDir, m) {
|
|
26
19
|
const entry = {
|
|
@@ -55,4 +48,4 @@ async function searchMemory(dataDir, query, slug, limit = 5) {
|
|
|
55
48
|
//#endregion
|
|
56
49
|
export { loadMemories as n, searchMemory as r, addMemory as t };
|
|
57
50
|
|
|
58
|
-
//# sourceMappingURL=memory-
|
|
51
|
+
//# sourceMappingURL=memory-Dzr9dXSM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-Dzr9dXSM.js","names":[],"sources":["../src/core/memory.ts"],"sourcesContent":["import { randomBytes } from \"crypto\";\nimport path from \"path\";\nimport { hybridSearch } from \"./hybrid-search.js\";\nimport { readJsonArray, writeJsonArray } from \"../fs/json-store.js\";\n\n/**\n * Agent memory (domino D6 / F4): persistent, typed memories per customer and\n * global, retrievable via hybrid search. Injected into context so the agent\n * gets durably smarter across every interaction (CoALA: semantic/procedural).\n */\nexport type MemoryType = \"fact\" | \"preference\" | \"learning\" | \"instruction\";\n\nexport interface MemoryEntry {\n id: string;\n scope: \"global\" | \"customer\";\n slug?: string;\n type: MemoryType;\n text: string;\n confidence?: number;\n createdAt: string;\n}\n\nfunction globalPath(dataDir: string): string {\n return path.join(dataDir, \".agentic\", \"memory\", \"global.json\");\n}\nfunction customerPath(dataDir: string, slug: string): string {\n return path.join(dataDir, \"customers\", slug, \"memory.json\");\n}\n\nfunction readFile(p: string): MemoryEntry[] {\n return readJsonArray<MemoryEntry>(p, \"memories\");\n}\nfunction writeFile(p: string, memories: MemoryEntry[]): void {\n writeJsonArray(p, \"memories\", memories);\n}\n\nexport function addMemory(\n dataDir: string,\n m: {\n scope: \"global\" | \"customer\";\n slug?: string;\n type: MemoryType;\n text: string;\n confidence?: number;\n }\n): MemoryEntry {\n const entry: MemoryEntry = {\n id: `mem_${randomBytes(5).toString(\"hex\")}`,\n scope: m.scope,\n ...(m.slug ? { slug: m.slug } : {}),\n type: m.type,\n text: m.text,\n ...(typeof m.confidence === \"number\" ? { confidence: m.confidence } : {}),\n createdAt: new Date().toISOString(),\n };\n const p = m.scope === \"global\" ? globalPath(dataDir) : customerPath(dataDir, m.slug ?? \"\");\n writeFile(p, [...readFile(p), entry]);\n return entry;\n}\n\n/** Load memories: global always; plus the customer's own when a slug is given. */\nexport function loadMemories(dataDir: string, slug?: string): MemoryEntry[] {\n const global = readFile(globalPath(dataDir));\n if (!slug) return global;\n return [...global, ...readFile(customerPath(dataDir, slug))];\n}\n\n/** Search memories by relevance (hybrid keyword ranking over memory texts). */\nexport async function searchMemory(\n dataDir: string,\n query: string,\n slug?: string,\n limit = 5\n): Promise<MemoryEntry[]> {\n const memories = loadMemories(dataDir, slug);\n const docs = memories.map((m) => ({ id: m.id, text: m.text }));\n const ranked = hybridSearch(query, docs, { limit });\n const byId = new Map(memories.map((m) => [m.id, m]));\n return ranked.map((r) => byId.get(r.id)!).filter(Boolean);\n}\n"],"mappings":";;;;;AAsBA,SAAS,WAAW,SAAyB;CAC3C,OAAO,KAAK,KAAK,SAAS,YAAY,UAAU,aAAa;AAC/D;AACA,SAAS,aAAa,SAAiB,MAAsB;CAC3D,OAAO,KAAK,KAAK,SAAS,aAAa,MAAM,aAAa;AAC5D;AAEA,SAAS,SAAS,GAA0B;CAC1C,OAAO,cAA2B,GAAG,UAAU;AACjD;AACA,SAAS,UAAU,GAAW,UAA+B;CAC3D,eAAe,GAAG,YAAY,QAAQ;AACxC;AAEA,SAAgB,UACd,SACA,GAOa;CACb,MAAM,QAAqB;EACzB,IAAI,OAAO,YAAY,CAAC,EAAE,SAAS,KAAK;EACxC,OAAO,EAAE;EACT,GAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;EACjC,MAAM,EAAE;EACR,MAAM,EAAE;EACR,GAAI,OAAO,EAAE,eAAe,WAAW,EAAE,YAAY,EAAE,WAAW,IAAI,CAAC;EACvE,4BAAW,IAAI,KAAK,GAAE,YAAY;CACpC;CACA,MAAM,IAAI,EAAE,UAAU,WAAW,WAAW,OAAO,IAAI,aAAa,SAAS,EAAE,QAAQ,EAAE;CACzF,UAAU,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC;CACpC,OAAO;AACT;;AAGA,SAAgB,aAAa,SAAiB,MAA8B;CAC1E,MAAM,SAAS,SAAS,WAAW,OAAO,CAAC;CAC3C,IAAI,CAAC,MAAM,OAAO;CAClB,OAAO,CAAC,GAAG,QAAQ,GAAG,SAAS,aAAa,SAAS,IAAI,CAAC,CAAC;AAC7D;;AAGA,eAAsB,aACpB,SACA,OACA,MACA,QAAQ,GACgB;CACxB,MAAM,WAAW,aAAa,SAAS,IAAI;CAE3C,MAAM,SAAS,aAAa,OADf,SAAS,KAAK,OAAO;EAAE,IAAI,EAAE;EAAI,MAAM,EAAE;CAAK,EACrB,GAAG,EAAE,MAAM,CAAC;CAClD,MAAM,OAAO,IAAI,IAAI,SAAS,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;CACnD,OAAO,OAAO,KAAK,MAAM,KAAK,IAAI,EAAE,EAAE,CAAE,EAAE,OAAO,OAAO;AAC1D"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as updateSlugSyncState } from "./sync-state-
|
|
2
|
-
import {
|
|
1
|
+
import { r as updateSlugSyncState } from "./sync-state-DMZgzpez.js";
|
|
2
|
+
import { n as appendInteraction } from "./interactions-writer-B8XAzdqR.js";
|
|
3
3
|
//#region src/sync/microsoft-calendar.ts
|
|
4
4
|
async function syncMicrosoftCalendar(opts) {
|
|
5
5
|
const result = {
|
|
@@ -12,7 +12,7 @@ async function syncMicrosoftCalendar(opts) {
|
|
|
12
12
|
const top = opts.maxResults ?? 50;
|
|
13
13
|
const startStr = since.toISOString();
|
|
14
14
|
const endStr = until.toISOString();
|
|
15
|
-
const { readInteractions } = await import("./interactions-writer-
|
|
15
|
+
const { readInteractions } = await import("./interactions-writer-B2y-73lh.js");
|
|
16
16
|
const existing = await readInteractions(opts.dataDir, opts.slug).catch(() => "");
|
|
17
17
|
let url = `https://graph.microsoft.com/v1.0/me/calendarView?startDateTime=${startStr}&endDateTime=${endStr}&$top=${top}&$select=id,subject,bodyPreview,start,end,attendees,organizer`;
|
|
18
18
|
while (url) {
|
|
@@ -64,4 +64,4 @@ async function syncMicrosoftCalendar(opts) {
|
|
|
64
64
|
//#endregion
|
|
65
65
|
export { syncMicrosoftCalendar };
|
|
66
66
|
|
|
67
|
-
//# sourceMappingURL=microsoft-calendar-
|
|
67
|
+
//# sourceMappingURL=microsoft-calendar-BgVR8GDv.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"microsoft-calendar-
|
|
1
|
+
{"version":3,"file":"microsoft-calendar-BgVR8GDv.js","names":[],"sources":["../src/sync/microsoft-calendar.ts"],"sourcesContent":["import { appendInteraction } from \"../fs/interactions-writer.js\";\nimport { updateSlugSyncState } from \"../fs/sync-state.js\";\n\nexport interface CalendarSyncOptions {\n slug: string;\n dataDir: string;\n accessToken: string;\n since?: Date;\n maxResults?: number;\n}\n\nexport interface CalendarSyncResult {\n synced: number;\n skipped: number;\n errors: string[];\n}\n\ninterface GraphEvent {\n id: string;\n subject?: string;\n bodyPreview?: string;\n start?: { dateTime?: string };\n end?: { dateTime?: string };\n attendees?: Array<{ emailAddress?: { name?: string; address?: string } }>;\n organizer?: { emailAddress?: { name?: string; address?: string } };\n}\n\ninterface GraphEventsResponse {\n value: GraphEvent[];\n \"@odata.nextLink\"?: string;\n}\n\nexport async function syncMicrosoftCalendar(\n opts: CalendarSyncOptions\n): Promise<CalendarSyncResult> {\n const result: CalendarSyncResult = { synced: 0, skipped: 0, errors: [] };\n const since = opts.since ?? new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);\n const until = new Date();\n const top = opts.maxResults ?? 50;\n\n const startStr = since.toISOString();\n const endStr = until.toISOString();\n\n const { readInteractions } = await import(\"../fs/interactions-writer.js\");\n const existing = await readInteractions(opts.dataDir, opts.slug).catch(() => \"\");\n\n let url: string | undefined =\n `https://graph.microsoft.com/v1.0/me/calendarView?startDateTime=${startStr}&endDateTime=${endStr}&$top=${top}&$select=id,subject,bodyPreview,start,end,attendees,organizer`;\n\n while (url) {\n let events: GraphEvent[];\n let nextLink: string | undefined;\n try {\n const res = await fetch(url, {\n headers: { Authorization: `Bearer ${opts.accessToken}` },\n });\n if (!res.ok) {\n result.errors.push(`Graph Calendar API error: ${res.status} ${res.statusText}`);\n break;\n }\n const data = (await res.json()) as GraphEventsResponse;\n events = data.value ?? [];\n nextLink = data[\"@odata.nextLink\"];\n } catch (err) {\n result.errors.push(`Network error: ${(err as Error).message}`);\n break;\n }\n\n for (const event of events) {\n const sourceRef = `microsoft://calendar/${event.id}`;\n if (existing.includes(sourceRef)) {\n result.skipped++;\n continue;\n }\n\n const date = event.start?.dateTime\n ? new Date(event.start.dateTime).toISOString().slice(0, 10)\n : new Date().toISOString().slice(0, 10);\n\n const attendeeNames = (event.attendees ?? [])\n .map((a) => a.emailAddress?.name ?? a.emailAddress?.address ?? \"unknown\")\n .join(\", \");\n\n const organizer =\n event.organizer?.emailAddress?.name ?? event.organizer?.emailAddress?.address ?? \"unknown\";\n\n try {\n await appendInteraction(opts.dataDir, opts.slug, {\n date,\n type: \"Meeting\",\n with: attendeeNames || organizer,\n summary: `${event.subject ?? \"(no subject)\"}: ${event.bodyPreview?.slice(0, 200) ?? \"\"}`,\n nextSteps: [],\n sourceRef,\n synced: new Date().toISOString(),\n direction: \"inbound\",\n });\n result.synced++;\n } catch (err) {\n result.errors.push(`Failed to append ${event.id}: ${(err as Error).message}`);\n }\n }\n\n url = nextLink;\n }\n\n if (result.synced > 0) {\n updateSlugSyncState(opts.dataDir, opts.slug, {\n lastGmailSync: new Date().toISOString(),\n });\n }\n\n return result;\n}\n"],"mappings":";;;AAgCA,eAAsB,sBACpB,MAC6B;CAC7B,MAAM,SAA6B;EAAE,QAAQ;EAAG,SAAS;EAAG,QAAQ,CAAC;CAAE;CACvE,MAAM,QAAQ,KAAK,yBAAS,IAAI,KAAK,KAAK,IAAI,IAAI,MAAU,KAAK,KAAK,GAAI;CAC1E,MAAM,wBAAQ,IAAI,KAAK;CACvB,MAAM,MAAM,KAAK,cAAc;CAE/B,MAAM,WAAW,MAAM,YAAY;CACnC,MAAM,SAAS,MAAM,YAAY;CAEjC,MAAM,EAAE,qBAAqB,MAAM,OAAO;CAC1C,MAAM,WAAW,MAAM,iBAAiB,KAAK,SAAS,KAAK,IAAI,EAAE,YAAY,EAAE;CAE/E,IAAI,MACF,kEAAkE,SAAS,eAAe,OAAO,QAAQ,IAAI;CAE/G,OAAO,KAAK;EACV,IAAI;EACJ,IAAI;EACJ,IAAI;GACF,MAAM,MAAM,MAAM,MAAM,KAAK,EAC3B,SAAS,EAAE,eAAe,UAAU,KAAK,cAAc,EACzD,CAAC;GACD,IAAI,CAAC,IAAI,IAAI;IACX,OAAO,OAAO,KAAK,6BAA6B,IAAI,OAAO,GAAG,IAAI,YAAY;IAC9E;GACF;GACA,MAAM,OAAQ,MAAM,IAAI,KAAK;GAC7B,SAAS,KAAK,SAAS,CAAC;GACxB,WAAW,KAAK;EAClB,SAAS,KAAK;GACZ,OAAO,OAAO,KAAK,kBAAmB,IAAc,SAAS;GAC7D;EACF;EAEA,KAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,YAAY,wBAAwB,MAAM;GAChD,IAAI,SAAS,SAAS,SAAS,GAAG;IAChC,OAAO;IACP;GACF;GAEA,MAAM,OAAO,MAAM,OAAO,WACtB,IAAI,KAAK,MAAM,MAAM,QAAQ,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE,qBACxD,IAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;GAExC,MAAM,iBAAiB,MAAM,aAAa,CAAC,GACxC,KAAK,MAAM,EAAE,cAAc,QAAQ,EAAE,cAAc,WAAW,SAAS,EACvE,KAAK,IAAI;GAEZ,MAAM,YACJ,MAAM,WAAW,cAAc,QAAQ,MAAM,WAAW,cAAc,WAAW;GAEnF,IAAI;IACF,MAAM,kBAAkB,KAAK,SAAS,KAAK,MAAM;KAC/C;KACA,MAAM;KACN,MAAM,iBAAiB;KACvB,SAAS,GAAG,MAAM,WAAW,eAAe,IAAI,MAAM,aAAa,MAAM,GAAG,GAAG,KAAK;KACpF,WAAW,CAAC;KACZ;KACA,yBAAQ,IAAI,KAAK,GAAE,YAAY;KAC/B,WAAW;IACb,CAAC;IACD,OAAO;GACT,SAAS,KAAK;IACZ,OAAO,OAAO,KAAK,oBAAoB,MAAM,GAAG,IAAK,IAAc,SAAS;GAC9E;EACF;EAEA,MAAM;CACR;CAEA,IAAI,OAAO,SAAS,GAClB,oBAAoB,KAAK,SAAS,KAAK,MAAM,EAC3C,gCAAe,IAAI,KAAK,GAAE,YAAY,EACxC,CAAC;CAGH,OAAO;AACT"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as updateSlugSyncState } from "./sync-state-
|
|
2
|
-
import {
|
|
1
|
+
import { r as updateSlugSyncState } from "./sync-state-DMZgzpez.js";
|
|
2
|
+
import { n as appendInteraction } from "./interactions-writer-B8XAzdqR.js";
|
|
3
3
|
//#region src/sync/microsoft-sync.ts
|
|
4
4
|
async function syncMicrosoft(opts) {
|
|
5
5
|
const result = {
|
|
@@ -24,7 +24,7 @@ async function syncMicrosoft(opts) {
|
|
|
24
24
|
result.errors.push(`Network error: ${err.message}`);
|
|
25
25
|
return result;
|
|
26
26
|
}
|
|
27
|
-
const { readInteractions } = await import("./interactions-writer-
|
|
27
|
+
const { readInteractions } = await import("./interactions-writer-B2y-73lh.js");
|
|
28
28
|
const existing = await readInteractions(opts.dataDir, opts.slug).catch(() => "");
|
|
29
29
|
for (const msg of messages) {
|
|
30
30
|
const sourceRef = `microsoft://message/${msg.id}`;
|
|
@@ -39,7 +39,7 @@ async function syncMicrosoft(opts) {
|
|
|
39
39
|
let summary = preview.slice(0, 300);
|
|
40
40
|
let nextSteps = [];
|
|
41
41
|
try {
|
|
42
|
-
const { summarizeEmail } = await import("./llm-
|
|
42
|
+
const { summarizeEmail } = await import("./llm-DSX1-wFu.js");
|
|
43
43
|
const llmResult = await summarizeEmail(subject, preview, from);
|
|
44
44
|
summary = llmResult.summary;
|
|
45
45
|
nextSteps = llmResult.nextSteps;
|
|
@@ -65,4 +65,4 @@ async function syncMicrosoft(opts) {
|
|
|
65
65
|
//#endregion
|
|
66
66
|
export { syncMicrosoft };
|
|
67
67
|
|
|
68
|
-
//# sourceMappingURL=microsoft-sync-
|
|
68
|
+
//# sourceMappingURL=microsoft-sync-D30_XksI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"microsoft-sync-
|
|
1
|
+
{"version":3,"file":"microsoft-sync-D30_XksI.js","names":[],"sources":["../src/sync/microsoft-sync.ts"],"sourcesContent":["import { appendInteraction } from \"../fs/interactions-writer.js\";\nimport { updateSlugSyncState } from \"../fs/sync-state.js\";\n\nexport interface MicrosoftSyncOptions {\n slug: string;\n dataDir: string;\n accessToken: string;\n query?: string;\n since?: Date;\n maxResults?: number;\n}\n\nexport interface MicrosoftSyncResult {\n synced: number;\n skipped: number;\n errors: string[];\n}\n\ninterface GraphMessage {\n id: string;\n subject?: string;\n bodyPreview?: string;\n receivedDateTime?: string;\n from?: { emailAddress?: { address?: string; name?: string } };\n}\n\ninterface GraphResponse {\n value: GraphMessage[];\n}\n\nexport async function syncMicrosoft(opts: MicrosoftSyncOptions): Promise<MicrosoftSyncResult> {\n const result: MicrosoftSyncResult = { synced: 0, skipped: 0, errors: [] };\n const maxResults = opts.maxResults ?? 50;\n\n let filter = \"\";\n if (opts.since) {\n filter = `&$filter=receivedDateTime ge ${opts.since.toISOString()}`;\n }\n if (opts.query) {\n filter += (filter ? \" and \" : \"&$filter=\") + opts.query;\n }\n\n const url = `https://graph.microsoft.com/v1.0/me/messages?$top=${maxResults}${filter}`;\n\n let messages: GraphMessage[];\n try {\n const res = await fetch(url, {\n headers: { Authorization: `Bearer ${opts.accessToken}` },\n });\n if (!res.ok) {\n result.errors.push(`Graph API error: ${res.status} ${res.statusText}`);\n return result;\n }\n const data = (await res.json()) as GraphResponse;\n messages = data.value ?? [];\n } catch (err) {\n result.errors.push(`Network error: ${(err as Error).message}`);\n return result;\n }\n\n const { readInteractions } = await import(\"../fs/interactions-writer.js\");\n const existing = await readInteractions(opts.dataDir, opts.slug).catch(() => \"\");\n\n for (const msg of messages) {\n const sourceRef = `microsoft://message/${msg.id}`;\n if (existing.includes(sourceRef)) {\n result.skipped++;\n continue;\n }\n\n const date = msg.receivedDateTime\n ? new Date(msg.receivedDateTime).toISOString().slice(0, 10)\n : new Date().toISOString().slice(0, 10);\n\n const from = msg.from?.emailAddress?.name ?? msg.from?.emailAddress?.address ?? \"unknown\";\n const subject = msg.subject ?? \"(no subject)\";\n const preview = msg.bodyPreview ?? \"\";\n\n let summary = preview.slice(0, 300);\n let nextSteps: string[] = [];\n\n try {\n const { summarizeEmail } = await import(\"../core/llm.js\");\n const llmResult = await summarizeEmail(subject, preview, from);\n summary = llmResult.summary;\n nextSteps = llmResult.nextSteps;\n } catch {\n // LLM unavailable — use raw preview\n }\n\n try {\n await appendInteraction(opts.dataDir, opts.slug, {\n date,\n type: \"Email\",\n with: from,\n summary: `${subject}: ${summary}`,\n nextSteps,\n sourceRef,\n synced: new Date().toISOString(),\n });\n result.synced++;\n } catch (err) {\n result.errors.push(`Failed to append ${msg.id}: ${(err as Error).message}`);\n }\n }\n\n if (result.synced > 0) {\n updateSlugSyncState(opts.dataDir, opts.slug, {\n lastGmailSync: new Date().toISOString(),\n });\n }\n\n return result;\n}\n"],"mappings":";;;AA8BA,eAAsB,cAAc,MAA0D;CAC5F,MAAM,SAA8B;EAAE,QAAQ;EAAG,SAAS;EAAG,QAAQ,CAAC;CAAE;CACxE,MAAM,aAAa,KAAK,cAAc;CAEtC,IAAI,SAAS;CACb,IAAI,KAAK,OACP,SAAS,gCAAgC,KAAK,MAAM,YAAY;CAElE,IAAI,KAAK,OACP,WAAW,SAAS,UAAU,eAAe,KAAK;CAGpD,MAAM,MAAM,qDAAqD,aAAa;CAE9E,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,MAAM,MAAM,KAAK,EAC3B,SAAS,EAAE,eAAe,UAAU,KAAK,cAAc,EACzD,CAAC;EACD,IAAI,CAAC,IAAI,IAAI;GACX,OAAO,OAAO,KAAK,oBAAoB,IAAI,OAAO,GAAG,IAAI,YAAY;GACrE,OAAO;EACT;EAEA,YAAW,MADS,IAAI,KAAK,GACb,SAAS,CAAC;CAC5B,SAAS,KAAK;EACZ,OAAO,OAAO,KAAK,kBAAmB,IAAc,SAAS;EAC7D,OAAO;CACT;CAEA,MAAM,EAAE,qBAAqB,MAAM,OAAO;CAC1C,MAAM,WAAW,MAAM,iBAAiB,KAAK,SAAS,KAAK,IAAI,EAAE,YAAY,EAAE;CAE/E,KAAK,MAAM,OAAO,UAAU;EAC1B,MAAM,YAAY,uBAAuB,IAAI;EAC7C,IAAI,SAAS,SAAS,SAAS,GAAG;GAChC,OAAO;GACP;EACF;EAEA,MAAM,OAAO,IAAI,mBACb,IAAI,KAAK,IAAI,gBAAgB,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE,qBACxD,IAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;EAExC,MAAM,OAAO,IAAI,MAAM,cAAc,QAAQ,IAAI,MAAM,cAAc,WAAW;EAChF,MAAM,UAAU,IAAI,WAAW;EAC/B,MAAM,UAAU,IAAI,eAAe;EAEnC,IAAI,UAAU,QAAQ,MAAM,GAAG,GAAG;EAClC,IAAI,YAAsB,CAAC;EAE3B,IAAI;GACF,MAAM,EAAE,mBAAmB,MAAM,OAAO;GACxC,MAAM,YAAY,MAAM,eAAe,SAAS,SAAS,IAAI;GAC7D,UAAU,UAAU;GACpB,YAAY,UAAU;EACxB,QAAQ,CAER;EAEA,IAAI;GACF,MAAM,kBAAkB,KAAK,SAAS,KAAK,MAAM;IAC/C;IACA,MAAM;IACN,MAAM;IACN,SAAS,GAAG,QAAQ,IAAI;IACxB;IACA;IACA,yBAAQ,IAAI,KAAK,GAAE,YAAY;GACjC,CAAC;GACD,OAAO;EACT,SAAS,KAAK;GACZ,OAAO,OAAO,KAAK,oBAAoB,IAAI,GAAG,IAAK,IAAc,SAAS;EAC5E;CACF;CAEA,IAAI,OAAO,SAAS,GAClB,oBAAoB,KAAK,SAAS,KAAK,MAAM,EAC3C,gCAAe,IAAI,KAAK,GAAE,YAAY,EACxC,CAAC;CAGH,OAAO;AACT"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as readPipeline } from "./pipeline-writer-
|
|
1
|
+
import { i as readInteractions } from "./interactions-writer-B8XAzdqR.js";
|
|
2
|
+
import { t as readPipeline } from "./pipeline-writer-CIllfnZl.js";
|
|
3
3
|
import { t as scoreOpportunity } from "./opportunity-score-BTMOQSTV.js";
|
|
4
4
|
//#region src/core/nba.ts
|
|
5
5
|
const STAGE_ACTION = {
|
|
@@ -45,4 +45,4 @@ async function nextBestAction(dataDir, slug) {
|
|
|
45
45
|
//#endregion
|
|
46
46
|
export { nextBestAction };
|
|
47
47
|
|
|
48
|
-
//# sourceMappingURL=nba-
|
|
48
|
+
//# sourceMappingURL=nba-DwdfM93s.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nba-
|
|
1
|
+
{"version":3,"file":"nba-DwdfM93s.js","names":[],"sources":["../src/core/nba.ts"],"sourcesContent":["import { readPipeline } from \"../fs/pipeline-writer.js\";\nimport { readInteractions } from \"../fs/interactions-writer.js\";\nimport { scoreOpportunity } from \"./opportunity-score.js\";\nimport type { PipelineDeal } from \"../schemas/pipeline.js\";\n\n/**\n * Next-Best-Action engine (domino D11 / C3): from a customer's open pipeline +\n * engagement recency, recommend prioritized next steps with rationale. Builds\n * on opportunity scoring; actions are meant to run through the D4 approval gate.\n */\nexport type Priority = \"high\" | \"medium\" | \"low\";\n\nexport interface NbaAction {\n action: string;\n reason: string;\n priority: Priority;\n deal?: string;\n}\n\nconst STAGE_ACTION: Record<PipelineDeal[\"stage\"], string> = {\n lead: \"Qualify the lead and book a discovery call\",\n qualified: \"Send a tailored proposal\",\n proposal: \"Follow up on the open proposal\",\n negotiation: \"Address objections and push to close\",\n won: \"Kick off onboarding\",\n lost: \"Run a loss post-mortem\",\n};\n\nconst RANK: Record<Priority, number> = { high: 0, medium: 1, low: 2 };\n\nexport async function nextBestAction(dataDir: string, slug: string): Promise<NbaAction[]> {\n const actions: NbaAction[] = [];\n\n const deals = await readPipeline(dataDir, slug).catch(() => [] as PipelineDeal[]);\n const open = deals.filter((d) => d.stage !== \"won\" && d.stage !== \"lost\");\n for (const d of open) {\n const { score } = scoreOpportunity(d);\n const priority: Priority = score >= 70 ? \"high\" : score >= 40 ? \"medium\" : \"low\";\n actions.push({\n action: STAGE_ACTION[d.stage],\n reason: `Deal '${d.name}' is in ${d.stage} (win-likelihood ${score})`,\n priority,\n deal: d.name,\n });\n }\n\n const interactions = await readInteractions(dataDir, slug).catch(() => \"\");\n if (!/## \\d{4}-\\d{2}-\\d{2}/.test(interactions)) {\n actions.push({\n action: \"Re-engage — no logged interactions yet\",\n reason: \"No interaction history for this customer\",\n priority: \"medium\",\n });\n }\n\n if (open.length === 0 && deals.length === 0) {\n actions.push({\n action: \"Create an opportunity\",\n reason: \"No pipeline deals exist for this customer\",\n priority: \"low\",\n });\n }\n\n return actions.sort((a, b) => RANK[a.priority] - RANK[b.priority]);\n}\n"],"mappings":";;;;AAmBA,MAAM,eAAsD;CAC1D,MAAM;CACN,WAAW;CACX,UAAU;CACV,aAAa;CACb,KAAK;CACL,MAAM;AACR;AAEA,MAAM,OAAiC;CAAE,MAAM;CAAG,QAAQ;CAAG,KAAK;AAAE;AAEpE,eAAsB,eAAe,SAAiB,MAAoC;CACxF,MAAM,UAAuB,CAAC;CAE9B,MAAM,QAAQ,MAAM,aAAa,SAAS,IAAI,EAAE,YAAY,CAAC,CAAmB;CAChF,MAAM,OAAO,MAAM,QAAQ,MAAM,EAAE,UAAU,SAAS,EAAE,UAAU,MAAM;CACxE,KAAK,MAAM,KAAK,MAAM;EACpB,MAAM,EAAE,UAAU,iBAAiB,CAAC;EACpC,MAAM,WAAqB,SAAS,KAAK,SAAS,SAAS,KAAK,WAAW;EAC3E,QAAQ,KAAK;GACX,QAAQ,aAAa,EAAE;GACvB,QAAQ,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,MAAM;GACnE;GACA,MAAM,EAAE;EACV,CAAC;CACH;CAEA,MAAM,eAAe,MAAM,iBAAiB,SAAS,IAAI,EAAE,YAAY,EAAE;CACzE,IAAI,CAAC,uBAAuB,KAAK,YAAY,GAC3C,QAAQ,KAAK;EACX,QAAQ;EACR,QAAQ;EACR,UAAU;CACZ,CAAC;CAGH,IAAI,KAAK,WAAW,KAAK,MAAM,WAAW,GACxC,QAAQ,KAAK;EACX,QAAQ;EACR,QAAQ;EACR,UAAU;CACZ,CAAC;CAGH,OAAO,QAAQ,MAAM,GAAG,MAAM,KAAK,EAAE,YAAY,KAAK,EAAE,SAAS;AACnE"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as logger } from "./logger-Dyl4VcLO.js";
|
|
2
|
+
import { i as readQueue, r as markTaskDone } from "./proactive-agent-B7u3Bj_l.js";
|
|
2
3
|
import https from "https";
|
|
3
4
|
//#region src/core/notification-dispatcher.ts
|
|
4
5
|
async function sendTelegram(token, chatId, text) {
|
|
@@ -83,7 +84,10 @@ async function drainProactiveQueue(dataDir) {
|
|
|
83
84
|
sent++;
|
|
84
85
|
} catch (err) {
|
|
85
86
|
failed++;
|
|
86
|
-
|
|
87
|
+
logger.error("dispatch", "task failed", {
|
|
88
|
+
task: task.id,
|
|
89
|
+
error: err.message
|
|
90
|
+
});
|
|
87
91
|
}
|
|
88
92
|
}
|
|
89
93
|
return {
|
|
@@ -94,4 +98,4 @@ async function drainProactiveQueue(dataDir) {
|
|
|
94
98
|
//#endregion
|
|
95
99
|
export { drainProactiveQueue };
|
|
96
100
|
|
|
97
|
-
//# sourceMappingURL=notification-dispatcher-
|
|
101
|
+
//# sourceMappingURL=notification-dispatcher-inpKyuBz.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-dispatcher-inpKyuBz.js","names":[],"sources":["../src/core/notification-dispatcher.ts"],"sourcesContent":["// src/core/notification-dispatcher.ts\n// Drains agent-queue.json and dispatches pending tasks to Telegram, Slack, or\n// marks them done for mcp_tool_response (consumed by get_proactive_briefing).\nimport https from \"https\";\nimport { readQueue, markTaskDone, type AgentTask } from \"./proactive-agent.js\";\nimport { logger } from \"./logger.js\";\n\n// ─── Transport helpers ────────────────────────────────────────────────────────\n\nexport async function sendTelegram(token: string, chatId: string, text: string): Promise<void> {\n const body = JSON.stringify({ chat_id: chatId, text, parse_mode: \"Markdown\" });\n await new Promise<void>((resolve, reject) => {\n const req = https.request(\n `https://api.telegram.org/bot${token}/sendMessage`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(body),\n },\n },\n (res) => {\n res.resume();\n resolve();\n }\n );\n req.on(\"error\", reject);\n req.write(body);\n req.end();\n });\n}\n\nexport async function sendSlack(webhookUrl: string, text: string): Promise<void> {\n const body = JSON.stringify({ text });\n const url = new URL(webhookUrl);\n await new Promise<void>((resolve, reject) => {\n const req = https.request(\n {\n hostname: url.hostname,\n path: url.pathname + url.search,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(body),\n },\n },\n (res) => {\n res.resume();\n resolve();\n }\n );\n req.on(\"error\", reject);\n req.write(body);\n req.end();\n });\n}\n\n// ─── Message formatting ───────────────────────────────────────────────────────\n\nexport function formatTaskMessage(task: AgentTask): string {\n const payload = task.payload as Record<string, unknown>;\n const slug = task.slug ?? \"\";\n\n switch (task.type) {\n case \"daily_briefing\": {\n const b = payload as { urgent?: string[]; forecast?: string; topAction?: string };\n const lines: string[] = [\"📋 *Daily CRM Briefing*\", \"\"];\n if (b.urgent?.length) {\n lines.push(\"🚨 *Urgent:*\");\n b.urgent.slice(0, 3).forEach((u) => lines.push(`• ${u}`));\n lines.push(\"\");\n }\n if (b.forecast) lines.push(`📊 ${b.forecast}`);\n if (b.topAction) lines.push(`\\n⚡ *Top Action:* ${b.topAction}`);\n return lines.join(\"\\n\");\n }\n case \"relationship_decay_alert\":\n return `⚠️ *Relationship Alert: ${slug}*\\n${String(payload[\"name\"] ?? \"\")} — ${String(payload[\"daysSinceContact\"] ?? \"?\")} days silent, grade ${String(payload[\"grade\"] ?? \"?\")}`;\n case \"deal_risk_alert\":\n return `🔴 *Deal Risk: ${slug}*\\n\"${String(payload[\"dealName\"] ?? \"\")}\" closes in ${String(payload[\"daysToClose\"] ?? \"?\")} days`;\n case \"external_signal_alert\":\n return `💡 *Signal: ${slug}*\\n${String(payload[\"summary\"] ?? \"\")}`;\n case \"follow_up_nudge\":\n return `📞 *Follow-up: ${slug}*\\n${String(payload[\"message\"] ?? \"\")}`;\n default:\n return `📌 CRM Task (${task.type})\\n${JSON.stringify(payload).slice(0, 200)}`;\n }\n}\n\n// ─── Queue drain ──────────────────────────────────────────────────────────────\n\nexport interface DrainResult {\n sent: number;\n failed: number;\n}\n\nexport async function drainProactiveQueue(dataDir: string): Promise<DrainResult> {\n const token = process.env[\"TELEGRAM_BOT_TOKEN\"];\n const chatId = process.env[\"TELEGRAM_CHAT_ID\"];\n const slackUrl = process.env[\"SLACK_WEBHOOK_URL\"];\n\n const tasks = readQueue(dataDir).filter((t) => t.status === \"pending\");\n let sent = 0;\n let failed = 0;\n\n for (const task of tasks) {\n const message = formatTaskMessage(task);\n try {\n if (task.channel === \"telegram\" && token && chatId) {\n await sendTelegram(token, chatId, message);\n } else if (task.channel === \"slack\" && slackUrl) {\n await sendSlack(slackUrl, message);\n }\n // mcp_tool_response tasks: consumed by get_proactive_briefing — just mark done\n await markTaskDone(dataDir, task.id, \"dispatched\");\n sent++;\n } catch (err) {\n failed++;\n logger.error(\"dispatch\", \"task failed\", { task: task.id, error: (err as Error).message });\n }\n }\n\n return { sent, failed };\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as readPipelineSync, r as upsertDeal, t as readPipeline } from "./pipeline-writer-
|
|
1
|
+
import { n as readPipelineSync, r as upsertDeal, t as readPipeline } from "./pipeline-writer-CIllfnZl.js";
|
|
2
2
|
export { readPipeline, readPipelineSync, upsertDeal };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-DakpK96I.cjs");
|
|
2
|
+
const require_session_store = require("./session-store-yfwnj0OC.cjs");
|
|
3
|
+
const require_atomic_write = require("./atomic-write-BYmF-ThH.cjs");
|
|
2
4
|
let path = require("path");
|
|
3
5
|
path = require_chunk.__toESM(path, 1);
|
|
4
6
|
let fs = require("fs");
|
|
@@ -87,6 +89,7 @@ async function readPipeline(dataDir, slug) {
|
|
|
87
89
|
return readPipelineSync(dataDir, slug);
|
|
88
90
|
}
|
|
89
91
|
async function upsertDeal(dataDir, slug, deal) {
|
|
92
|
+
require_session_store.assertSafeSlug(slug);
|
|
90
93
|
const filePath = path.default.join(dataDir, "customers", slug, "pipeline.md");
|
|
91
94
|
const existing = await readPipeline(dataDir, slug);
|
|
92
95
|
const idx = existing.findIndex((d) => d.name === deal.name);
|
|
@@ -95,8 +98,7 @@ async function upsertDeal(dataDir, slug, deal) {
|
|
|
95
98
|
updated = [...existing];
|
|
96
99
|
updated[idx] = deal;
|
|
97
100
|
} else updated = [...existing, deal];
|
|
98
|
-
|
|
99
|
-
fs.default.writeFileSync(filePath, content, "utf-8");
|
|
101
|
+
require_atomic_write.writeFileAtomic(filePath, serializeDeals(updated));
|
|
100
102
|
}
|
|
101
103
|
//#endregion
|
|
102
104
|
Object.defineProperty(exports, "pipeline_writer_exports", {
|
|
@@ -111,6 +113,12 @@ Object.defineProperty(exports, "readPipeline", {
|
|
|
111
113
|
return readPipeline;
|
|
112
114
|
}
|
|
113
115
|
});
|
|
116
|
+
Object.defineProperty(exports, "readPipelineSync", {
|
|
117
|
+
enumerable: true,
|
|
118
|
+
get: function() {
|
|
119
|
+
return readPipelineSync;
|
|
120
|
+
}
|
|
121
|
+
});
|
|
114
122
|
Object.defineProperty(exports, "upsertDeal", {
|
|
115
123
|
enumerable: true,
|
|
116
124
|
get: function() {
|
|
@@ -118,4 +126,4 @@ Object.defineProperty(exports, "upsertDeal", {
|
|
|
118
126
|
}
|
|
119
127
|
});
|
|
120
128
|
|
|
121
|
-
//# sourceMappingURL=pipeline-writer-
|
|
129
|
+
//# sourceMappingURL=pipeline-writer-B1tRAhuD.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-writer-B1tRAhuD.cjs","names":["z"],"sources":["../src/schemas/pipeline.ts","../src/fs/pipeline-writer.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const PipelineDealSchema = z.object({\n name: z.string().min(1),\n stage: z.enum([\"lead\", \"qualified\", \"proposal\", \"negotiation\", \"won\", \"lost\"]),\n value: z.number().optional(),\n currency: z.string().default(\"EUR\"),\n probability: z.number().min(0).max(100).optional(),\n close_date: z\n .string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"YYYY-MM-DD required\")\n .optional(),\n notes: z.string().optional(),\n updated: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"YYYY-MM-DD required\"),\n});\n\nexport type PipelineDeal = z.infer<typeof PipelineDealSchema>;\n","import fs from \"fs\";\nimport path from \"path\";\nimport { PipelineDealSchema, type PipelineDeal } from \"../schemas/pipeline.js\";\nimport { writeFileAtomic } from \"./atomic-write.js\";\nimport { assertSafeSlug } from \"./customer-dir.js\";\n\nconst PIPELINE_HEADER = \"# Pipeline\\n\\n\";\nconst TABLE_HEADER = `| Name | Stage | Value | Currency | Probability | Close Date | Notes | Updated |\n|------|-------|-------|----------|-------------|------------|-------|---------|`;\n\nfunction escapeMd(val: string | undefined | null): string {\n if (val === undefined || val === null) return \"\";\n return String(val).replace(/\\|/g, \"\\\\|\");\n}\n\nfunction serializeDeal(deal: PipelineDeal): string {\n return `| ${escapeMd(deal.name)} | ${escapeMd(deal.stage)} | ${deal.value !== undefined ? String(deal.value) : \"\"} | ${escapeMd(deal.currency)} | ${deal.probability !== undefined ? String(deal.probability) : \"\"} | ${escapeMd(deal.close_date)} | ${escapeMd(deal.notes)} | ${escapeMd(deal.updated)} |`;\n}\n\nfunction parseDealsFromMarkdown(content: string): PipelineDeal[] {\n const lines = content.split(\"\\n\");\n const deals: PipelineDeal[] = [];\n\n let inTable = false;\n let headerParsed = false;\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Look for the table header row\n if (!inTable && trimmed.startsWith(\"| Name |\")) {\n inTable = true;\n headerParsed = false;\n continue;\n }\n\n if (inTable && !headerParsed && trimmed.startsWith(\"|---\")) {\n headerParsed = true;\n continue;\n }\n\n if (inTable && headerParsed && trimmed.startsWith(\"|\")) {\n // Parse a data row\n const cells = trimmed\n .split(\"|\")\n .slice(1, -1)\n .map((c) => c.trim().replace(/\\\\\\|/g, \"|\"));\n\n const [name, stage, valueStr, currency, probabilityStr, close_date, notes, updated] =\n cells as [string, string, string, string, string, string, string, string];\n\n if (!name || !stage || !updated) continue;\n\n const raw: Record<string, unknown> = {\n name,\n stage,\n currency: currency || \"EUR\",\n updated,\n };\n\n if (valueStr) raw[\"value\"] = parseFloat(valueStr);\n if (probabilityStr) raw[\"probability\"] = parseFloat(probabilityStr);\n if (close_date) raw[\"close_date\"] = close_date;\n if (notes) raw[\"notes\"] = notes;\n\n const result = PipelineDealSchema.safeParse(raw);\n if (result.success) {\n deals.push(result.data);\n }\n } else if (inTable && !trimmed.startsWith(\"|\")) {\n // End of table\n inTable = false;\n }\n }\n\n return deals;\n}\n\nfunction serializeDeals(deals: PipelineDeal[]): string {\n if (deals.length === 0) {\n return `${PIPELINE_HEADER}<!-- Deals listed here -->\\n`;\n }\n const rows = deals.map(serializeDeal).join(\"\\n\");\n return `${PIPELINE_HEADER}${TABLE_HEADER}\\n${rows}\\n`;\n}\n\nexport function readPipelineSync(dataDir: string, slug: string): PipelineDeal[] {\n const filePath = path.join(dataDir, \"customers\", slug, \"pipeline.md\");\n if (!fs.existsSync(filePath)) {\n return [];\n }\n const content = fs.readFileSync(filePath, \"utf-8\") as string;\n return parseDealsFromMarkdown(content);\n}\n\nexport async function readPipeline(dataDir: string, slug: string): Promise<PipelineDeal[]> {\n return readPipelineSync(dataDir, slug);\n}\n\nexport async function upsertDeal(dataDir: string, slug: string, deal: PipelineDeal): Promise<void> {\n assertSafeSlug(slug);\n const filePath = path.join(dataDir, \"customers\", slug, \"pipeline.md\");\n const existing = await readPipeline(dataDir, slug);\n\n const idx = existing.findIndex((d) => d.name === deal.name);\n let updated: PipelineDeal[];\n if (idx >= 0) {\n updated = [...existing];\n updated[idx] = deal;\n } else {\n updated = [...existing, deal];\n }\n\n const content = serializeDeals(updated);\n writeFileAtomic(filePath, content);\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { t as assertSafeSlug } from "./customer-dir-CkMMXhb0.js";
|
|
2
|
+
import { t as writeFileAtomic } from "./atomic-write-8yjqqLtS.js";
|
|
1
3
|
import path from "path";
|
|
2
4
|
import fs from "fs";
|
|
3
5
|
import { z } from "zod";
|
|
@@ -79,6 +81,7 @@ async function readPipeline(dataDir, slug) {
|
|
|
79
81
|
return readPipelineSync(dataDir, slug);
|
|
80
82
|
}
|
|
81
83
|
async function upsertDeal(dataDir, slug, deal) {
|
|
84
|
+
assertSafeSlug(slug);
|
|
82
85
|
const filePath = path.join(dataDir, "customers", slug, "pipeline.md");
|
|
83
86
|
const existing = await readPipeline(dataDir, slug);
|
|
84
87
|
const idx = existing.findIndex((d) => d.name === deal.name);
|
|
@@ -87,10 +90,9 @@ async function upsertDeal(dataDir, slug, deal) {
|
|
|
87
90
|
updated = [...existing];
|
|
88
91
|
updated[idx] = deal;
|
|
89
92
|
} else updated = [...existing, deal];
|
|
90
|
-
|
|
91
|
-
fs.writeFileSync(filePath, content, "utf-8");
|
|
93
|
+
writeFileAtomic(filePath, serializeDeals(updated));
|
|
92
94
|
}
|
|
93
95
|
//#endregion
|
|
94
96
|
export { readPipelineSync as n, upsertDeal as r, readPipeline as t };
|
|
95
97
|
|
|
96
|
-
//# sourceMappingURL=pipeline-writer-
|
|
98
|
+
//# sourceMappingURL=pipeline-writer-CIllfnZl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-writer-CIllfnZl.js","names":[],"sources":["../src/schemas/pipeline.ts","../src/fs/pipeline-writer.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const PipelineDealSchema = z.object({\n name: z.string().min(1),\n stage: z.enum([\"lead\", \"qualified\", \"proposal\", \"negotiation\", \"won\", \"lost\"]),\n value: z.number().optional(),\n currency: z.string().default(\"EUR\"),\n probability: z.number().min(0).max(100).optional(),\n close_date: z\n .string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"YYYY-MM-DD required\")\n .optional(),\n notes: z.string().optional(),\n updated: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"YYYY-MM-DD required\"),\n});\n\nexport type PipelineDeal = z.infer<typeof PipelineDealSchema>;\n","import fs from \"fs\";\nimport path from \"path\";\nimport { PipelineDealSchema, type PipelineDeal } from \"../schemas/pipeline.js\";\nimport { writeFileAtomic } from \"./atomic-write.js\";\nimport { assertSafeSlug } from \"./customer-dir.js\";\n\nconst PIPELINE_HEADER = \"# Pipeline\\n\\n\";\nconst TABLE_HEADER = `| Name | Stage | Value | Currency | Probability | Close Date | Notes | Updated |\n|------|-------|-------|----------|-------------|------------|-------|---------|`;\n\nfunction escapeMd(val: string | undefined | null): string {\n if (val === undefined || val === null) return \"\";\n return String(val).replace(/\\|/g, \"\\\\|\");\n}\n\nfunction serializeDeal(deal: PipelineDeal): string {\n return `| ${escapeMd(deal.name)} | ${escapeMd(deal.stage)} | ${deal.value !== undefined ? String(deal.value) : \"\"} | ${escapeMd(deal.currency)} | ${deal.probability !== undefined ? String(deal.probability) : \"\"} | ${escapeMd(deal.close_date)} | ${escapeMd(deal.notes)} | ${escapeMd(deal.updated)} |`;\n}\n\nfunction parseDealsFromMarkdown(content: string): PipelineDeal[] {\n const lines = content.split(\"\\n\");\n const deals: PipelineDeal[] = [];\n\n let inTable = false;\n let headerParsed = false;\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Look for the table header row\n if (!inTable && trimmed.startsWith(\"| Name |\")) {\n inTable = true;\n headerParsed = false;\n continue;\n }\n\n if (inTable && !headerParsed && trimmed.startsWith(\"|---\")) {\n headerParsed = true;\n continue;\n }\n\n if (inTable && headerParsed && trimmed.startsWith(\"|\")) {\n // Parse a data row\n const cells = trimmed\n .split(\"|\")\n .slice(1, -1)\n .map((c) => c.trim().replace(/\\\\\\|/g, \"|\"));\n\n const [name, stage, valueStr, currency, probabilityStr, close_date, notes, updated] =\n cells as [string, string, string, string, string, string, string, string];\n\n if (!name || !stage || !updated) continue;\n\n const raw: Record<string, unknown> = {\n name,\n stage,\n currency: currency || \"EUR\",\n updated,\n };\n\n if (valueStr) raw[\"value\"] = parseFloat(valueStr);\n if (probabilityStr) raw[\"probability\"] = parseFloat(probabilityStr);\n if (close_date) raw[\"close_date\"] = close_date;\n if (notes) raw[\"notes\"] = notes;\n\n const result = PipelineDealSchema.safeParse(raw);\n if (result.success) {\n deals.push(result.data);\n }\n } else if (inTable && !trimmed.startsWith(\"|\")) {\n // End of table\n inTable = false;\n }\n }\n\n return deals;\n}\n\nfunction serializeDeals(deals: PipelineDeal[]): string {\n if (deals.length === 0) {\n return `${PIPELINE_HEADER}<!-- Deals listed here -->\\n`;\n }\n const rows = deals.map(serializeDeal).join(\"\\n\");\n return `${PIPELINE_HEADER}${TABLE_HEADER}\\n${rows}\\n`;\n}\n\nexport function readPipelineSync(dataDir: string, slug: string): PipelineDeal[] {\n const filePath = path.join(dataDir, \"customers\", slug, \"pipeline.md\");\n if (!fs.existsSync(filePath)) {\n return [];\n }\n const content = fs.readFileSync(filePath, \"utf-8\") as string;\n return parseDealsFromMarkdown(content);\n}\n\nexport async function readPipeline(dataDir: string, slug: string): Promise<PipelineDeal[]> {\n return readPipelineSync(dataDir, slug);\n}\n\nexport async function upsertDeal(dataDir: string, slug: string, deal: PipelineDeal): Promise<void> {\n assertSafeSlug(slug);\n const filePath = path.join(dataDir, \"customers\", slug, \"pipeline.md\");\n const existing = await readPipeline(dataDir, slug);\n\n const idx = existing.findIndex((d) => d.name === deal.name);\n let updated: PipelineDeal[];\n if (idx >= 0) {\n updated = [...existing];\n updated[idx] = deal;\n } else {\n updated = [...existing, deal];\n }\n\n const content = serializeDeals(updated);\n writeFileAtomic(filePath, content);\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
+
import { T as assertSafeSlug } from "./session-store-DWxJ5Pof.js";
|
|
3
|
+
import { t as writeFileAtomic } from "./atomic-write-8yjqqLtS.js";
|
|
2
4
|
import path from "path";
|
|
3
5
|
import fs from "fs";
|
|
4
6
|
import { z } from "zod";
|
|
@@ -85,6 +87,7 @@ async function readPipeline(dataDir, slug) {
|
|
|
85
87
|
return readPipelineSync(dataDir, slug);
|
|
86
88
|
}
|
|
87
89
|
async function upsertDeal(dataDir, slug, deal) {
|
|
90
|
+
assertSafeSlug(slug);
|
|
88
91
|
const filePath = path.join(dataDir, "customers", slug, "pipeline.md");
|
|
89
92
|
const existing = await readPipeline(dataDir, slug);
|
|
90
93
|
const idx = existing.findIndex((d) => d.name === deal.name);
|
|
@@ -93,10 +96,9 @@ async function upsertDeal(dataDir, slug, deal) {
|
|
|
93
96
|
updated = [...existing];
|
|
94
97
|
updated[idx] = deal;
|
|
95
98
|
} else updated = [...existing, deal];
|
|
96
|
-
|
|
97
|
-
fs.writeFileSync(filePath, content, "utf-8");
|
|
99
|
+
writeFileAtomic(filePath, serializeDeals(updated));
|
|
98
100
|
}
|
|
99
101
|
//#endregion
|
|
100
|
-
export { readPipeline as n,
|
|
102
|
+
export { upsertDeal as i, readPipeline as n, readPipelineSync as r, pipeline_writer_exports as t };
|
|
101
103
|
|
|
102
|
-
//# sourceMappingURL=pipeline-writer-
|
|
104
|
+
//# sourceMappingURL=pipeline-writer-rDj-ni6q.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-writer-rDj-ni6q.js","names":[],"sources":["../src/schemas/pipeline.ts","../src/fs/pipeline-writer.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const PipelineDealSchema = z.object({\n name: z.string().min(1),\n stage: z.enum([\"lead\", \"qualified\", \"proposal\", \"negotiation\", \"won\", \"lost\"]),\n value: z.number().optional(),\n currency: z.string().default(\"EUR\"),\n probability: z.number().min(0).max(100).optional(),\n close_date: z\n .string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"YYYY-MM-DD required\")\n .optional(),\n notes: z.string().optional(),\n updated: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, \"YYYY-MM-DD required\"),\n});\n\nexport type PipelineDeal = z.infer<typeof PipelineDealSchema>;\n","import fs from \"fs\";\nimport path from \"path\";\nimport { PipelineDealSchema, type PipelineDeal } from \"../schemas/pipeline.js\";\nimport { writeFileAtomic } from \"./atomic-write.js\";\nimport { assertSafeSlug } from \"./customer-dir.js\";\n\nconst PIPELINE_HEADER = \"# Pipeline\\n\\n\";\nconst TABLE_HEADER = `| Name | Stage | Value | Currency | Probability | Close Date | Notes | Updated |\n|------|-------|-------|----------|-------------|------------|-------|---------|`;\n\nfunction escapeMd(val: string | undefined | null): string {\n if (val === undefined || val === null) return \"\";\n return String(val).replace(/\\|/g, \"\\\\|\");\n}\n\nfunction serializeDeal(deal: PipelineDeal): string {\n return `| ${escapeMd(deal.name)} | ${escapeMd(deal.stage)} | ${deal.value !== undefined ? String(deal.value) : \"\"} | ${escapeMd(deal.currency)} | ${deal.probability !== undefined ? String(deal.probability) : \"\"} | ${escapeMd(deal.close_date)} | ${escapeMd(deal.notes)} | ${escapeMd(deal.updated)} |`;\n}\n\nfunction parseDealsFromMarkdown(content: string): PipelineDeal[] {\n const lines = content.split(\"\\n\");\n const deals: PipelineDeal[] = [];\n\n let inTable = false;\n let headerParsed = false;\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Look for the table header row\n if (!inTable && trimmed.startsWith(\"| Name |\")) {\n inTable = true;\n headerParsed = false;\n continue;\n }\n\n if (inTable && !headerParsed && trimmed.startsWith(\"|---\")) {\n headerParsed = true;\n continue;\n }\n\n if (inTable && headerParsed && trimmed.startsWith(\"|\")) {\n // Parse a data row\n const cells = trimmed\n .split(\"|\")\n .slice(1, -1)\n .map((c) => c.trim().replace(/\\\\\\|/g, \"|\"));\n\n const [name, stage, valueStr, currency, probabilityStr, close_date, notes, updated] =\n cells as [string, string, string, string, string, string, string, string];\n\n if (!name || !stage || !updated) continue;\n\n const raw: Record<string, unknown> = {\n name,\n stage,\n currency: currency || \"EUR\",\n updated,\n };\n\n if (valueStr) raw[\"value\"] = parseFloat(valueStr);\n if (probabilityStr) raw[\"probability\"] = parseFloat(probabilityStr);\n if (close_date) raw[\"close_date\"] = close_date;\n if (notes) raw[\"notes\"] = notes;\n\n const result = PipelineDealSchema.safeParse(raw);\n if (result.success) {\n deals.push(result.data);\n }\n } else if (inTable && !trimmed.startsWith(\"|\")) {\n // End of table\n inTable = false;\n }\n }\n\n return deals;\n}\n\nfunction serializeDeals(deals: PipelineDeal[]): string {\n if (deals.length === 0) {\n return `${PIPELINE_HEADER}<!-- Deals listed here -->\\n`;\n }\n const rows = deals.map(serializeDeal).join(\"\\n\");\n return `${PIPELINE_HEADER}${TABLE_HEADER}\\n${rows}\\n`;\n}\n\nexport function readPipelineSync(dataDir: string, slug: string): PipelineDeal[] {\n const filePath = path.join(dataDir, \"customers\", slug, \"pipeline.md\");\n if (!fs.existsSync(filePath)) {\n return [];\n }\n const content = fs.readFileSync(filePath, \"utf-8\") as string;\n return parseDealsFromMarkdown(content);\n}\n\nexport async function readPipeline(dataDir: string, slug: string): Promise<PipelineDeal[]> {\n return readPipelineSync(dataDir, slug);\n}\n\nexport async function upsertDeal(dataDir: string, slug: string, deal: PipelineDeal): Promise<void> {\n assertSafeSlug(slug);\n const filePath = path.join(dataDir, \"customers\", slug, \"pipeline.md\");\n const existing = await readPipeline(dataDir, slug);\n\n const idx = existing.findIndex((d) => d.name === deal.name);\n let updated: PipelineDeal[];\n if (idx >= 0) {\n updated = [...existing];\n updated[idx] = deal;\n } else {\n updated = [...existing, deal];\n }\n\n const content = serializeDeals(updated);\n writeFileAtomic(filePath, content);\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as withJsonFile } from "./file-lock-
|
|
3
|
-
import { i as buildSimulationInput, l as runSimulation } from "./revenue-simulation-
|
|
4
|
-
import { t as readPipeline } from "./pipeline-writer-
|
|
5
|
-
import { n as readHealth, t as computeCustomerHealth } from "./relationship-health-
|
|
1
|
+
import { i as listCustomerSlugs } from "./customer-dir-CkMMXhb0.js";
|
|
2
|
+
import { t as withJsonFile } from "./file-lock-CcHotQkZ.js";
|
|
3
|
+
import { i as buildSimulationInput, l as runSimulation } from "./revenue-simulation-D8f_YkUY.js";
|
|
4
|
+
import { t as readPipeline } from "./pipeline-writer-CIllfnZl.js";
|
|
5
|
+
import { n as readHealth, t as computeCustomerHealth } from "./relationship-health-ZZNXR1RZ.js";
|
|
6
6
|
import path from "path";
|
|
7
7
|
import fs from "fs";
|
|
8
8
|
//#region src/core/proactive-agent.ts
|
|
@@ -93,4 +93,4 @@ async function buildDailyBriefing(dataDir, today) {
|
|
|
93
93
|
//#endregion
|
|
94
94
|
export { readQueue as i, enqueueTask as n, markTaskDone as r, buildDailyBriefing as t };
|
|
95
95
|
|
|
96
|
-
//# sourceMappingURL=proactive-agent-
|
|
96
|
+
//# sourceMappingURL=proactive-agent-B7u3Bj_l.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proactive-agent-
|
|
1
|
+
{"version":3,"file":"proactive-agent-B7u3Bj_l.js","names":[],"sources":["../src/core/proactive-agent.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport { withJsonFile } from \"./file-lock.js\";\nimport { computeCustomerHealth, readHealth } from \"./relationship-health.js\";\nimport { readPipeline } from \"../fs/pipeline-writer.js\";\nimport { listCustomerSlugs } from \"../fs/customer-dir.js\";\nimport { buildSimulationInput, runSimulation } from \"./revenue-simulation.js\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type TaskType =\n | \"daily_briefing\"\n | \"relationship_decay_alert\"\n | \"deal_risk_alert\"\n | \"external_signal_alert\"\n | \"follow_up_nudge\"\n | \"goal_progress_update\"\n | \"pipeline_forecast_weekly\"\n | \"playbook_suggestion\";\n\nexport type NotificationChannel = \"telegram\" | \"slack\" | \"email\" | \"mcp_tool_response\";\nexport type TaskPriority = \"urgent\" | \"high\" | \"normal\";\nexport type TaskStatus = \"pending\" | \"processing\" | \"done\" | \"failed\";\n\nexport interface AgentTask {\n id: string;\n type: TaskType;\n slug?: string;\n priority: TaskPriority;\n payload: unknown;\n createdAt: string;\n scheduledFor: string;\n status: TaskStatus;\n result?: string;\n channel: NotificationChannel;\n}\n\nexport interface DailyBriefing {\n date: string;\n generatedAt: string;\n urgent: string[];\n opportunities: string[];\n forecast: string;\n topAction: string;\n}\n\n// ─── Queue path ───────────────────────────────────────────────────────────────\n\nfunction queuePath(dataDir: string): string {\n return path.join(dataDir, \".agentic\", \"agent-queue.json\");\n}\n\n// ─── Queue operations ─────────────────────────────────────────────────────────\n\nexport function readQueue(dataDir: string): AgentTask[] {\n const p = queuePath(dataDir);\n if (!fs.existsSync(p)) return [];\n try {\n const raw = JSON.parse(fs.readFileSync(p, \"utf-8\") as string) as unknown;\n return Array.isArray(raw) ? (raw as AgentTask[]) : [];\n } catch {\n return [];\n }\n}\n\nexport async function enqueueTask(\n dataDir: string,\n task: Omit<AgentTask, \"id\" | \"createdAt\" | \"status\">\n): Promise<AgentTask> {\n const now = new Date().toISOString();\n const newTask: AgentTask = {\n ...task,\n id: `task_${Date.now()}_${Math.random().toString(16).slice(2, 8)}`,\n createdAt: now,\n status: \"pending\",\n };\n\n await withJsonFile<AgentTask[]>(queuePath(dataDir), (current) => {\n const existing = Array.isArray(current) ? current : [];\n return [...existing, newTask];\n });\n\n return newTask;\n}\n\nexport async function markTaskDone(\n dataDir: string,\n taskId: string,\n result?: string\n): Promise<void> {\n await withJsonFile<AgentTask[]>(queuePath(dataDir), (current) => {\n const tasks = Array.isArray(current) ? [...current] : [];\n const idx = tasks.findIndex((t) => t.id === taskId);\n if (idx >= 0) {\n tasks[idx] = { ...tasks[idx]!, status: \"done\", ...(result ? { result } : {}) };\n }\n return tasks;\n });\n}\n\n// ─── Daily briefing ───────────────────────────────────────────────────────────\n\nexport async function buildDailyBriefing(dataDir: string, today: string): Promise<DailyBriefing> {\n const slugs = listCustomerSlugs(dataDir);\n\n const urgent: string[] = [];\n const opportunities: string[] = [];\n const todayDate = new Date(`${today}T00:00:00Z`);\n\n // Parallel I/O across all customers\n const customerData = await Promise.all(\n slugs.map(async (slug) => {\n const cached = readHealth(dataDir, slug);\n const health = cached ?? computeCustomerHealth(dataDir, slug, today);\n const deals = await readPipeline(dataDir, slug).catch(() => []);\n return { slug, health, deals };\n })\n );\n\n for (const { slug, health, deals } of customerData) {\n // Relationship decay alerts\n for (const contact of health.contacts) {\n if (contact.riskFlags.includes(\"NO_CONTACT_30D\")) {\n urgent.push(\n `${slug}: ${contact.name} has been silent for ${contact.daysSinceContact} days — health ${contact.score}/100`\n );\n }\n }\n\n // Opportunities — B-grade+ relationship health with active deals\n const activeDeals = deals.filter((d) => d.stage !== \"won\" && d.stage !== \"lost\");\n if (health.overallHealth >= 65 && activeDeals.length > 0) {\n opportunities.push(\n `${slug}: relationship health ${health.overallHealth}/100 with ${activeDeals.length} active deal(s) — good time for expansion or upsell.`\n );\n }\n\n // Deal risk alerts\n for (const deal of deals) {\n if (deal.stage === \"won\" || deal.stage === \"lost\") continue;\n if (deal.close_date && deal.close_date.trim() !== \"\") {\n const daysToClose = Math.floor(\n (new Date(deal.close_date).getTime() - todayDate.getTime()) / 86_400_000\n );\n if (daysToClose <= 7 && daysToClose >= 0) {\n urgent.push(\n `${slug}: Deal \"${deal.name}\" closes in ${daysToClose} day(s) — ${deal.stage}`\n );\n } else if (daysToClose < 0) {\n urgent.push(\n `${slug}: Deal \"${deal.name}\" close date passed (${Math.abs(daysToClose)} days overdue)`\n );\n }\n }\n }\n }\n\n // Revenue forecast\n let forecast = \"No active pipeline.\";\n try {\n const simInput = await buildSimulationInput(dataDir, \"quarter\", today);\n if (simInput.deals.length > 0) {\n const sim = runSimulation({ ...simInput, iterations: 1000 });\n forecast = `Q forecast: P50 €${(sim.p50 / 1000).toFixed(1)}k / P90 €${(sim.p90 / 1000).toFixed(1)}k — ${simInput.deals.length} deal(s) in pipeline.`;\n }\n } catch {\n // forecast stays as default\n }\n\n // Top action\n const topAction =\n urgent.length > 0\n ? (urgent[0]!\n .replace(/^[^:]+: /, \"\")\n .split(\"—\")[0]\n ?.trim() ?? urgent[0]!)\n : \"Review your pipeline and schedule next customer check-ins.\";\n\n return {\n date: today,\n generatedAt: new Date().toISOString(),\n urgent,\n opportunities,\n forecast,\n topAction,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { n as
|
|
1
|
+
import { i as writeJsonFile } from "./json-store-WWsFzXub.js";
|
|
2
|
+
import { u as runScheduledBackupIfDue } from "./backup-CTlIxUdO.js";
|
|
3
|
+
import { t as readPipeline } from "./pipeline-writer-CIllfnZl.js";
|
|
4
|
+
import { n as readHealth, t as computeCustomerHealth } from "./relationship-health-ZZNXR1RZ.js";
|
|
5
|
+
import { n as enqueueTask, t as buildDailyBriefing } from "./proactive-agent-B7u3Bj_l.js";
|
|
5
6
|
import path from "path";
|
|
6
7
|
import fs from "fs";
|
|
7
8
|
import https from "https";
|
|
@@ -13,9 +14,7 @@ function signalsFilePath(dataDir, slug, date) {
|
|
|
13
14
|
return path.join(signalsDir(dataDir, slug), `${date}.json`);
|
|
14
15
|
}
|
|
15
16
|
function writeSignals(dataDir, slug, date, signals) {
|
|
16
|
-
|
|
17
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
18
|
-
fs.writeFileSync(signalsFilePath(dataDir, slug, date), JSON.stringify(signals, null, 2), "utf-8");
|
|
17
|
+
writeJsonFile(signalsFilePath(dataDir, slug, date), signals);
|
|
19
18
|
}
|
|
20
19
|
async function fetchJson(url, headers = {}) {
|
|
21
20
|
return new Promise((resolve, reject) => {
|
|
@@ -226,4 +225,4 @@ async function runDailyProactiveChecks(dataDir, today = (/* @__PURE__ */ new Dat
|
|
|
226
225
|
//#endregion
|
|
227
226
|
export { runDailyProactiveChecks };
|
|
228
227
|
|
|
229
|
-
//# sourceMappingURL=proactive-worker-
|
|
228
|
+
//# sourceMappingURL=proactive-worker-1zkm6aJD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proactive-worker-1zkm6aJD.js","names":[],"sources":["../src/sync/external-signals.ts","../src/daemon/proactive-worker.ts"],"sourcesContent":["// src/sync/external-signals.ts\n// External signal detection: Hacker News (free), Crunchbase (key optional),\n// Clearbit (key optional). Non-fatal on network errors — CRM works offline.\nimport https from \"https\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport { writeJsonFile } from \"../fs/json-store.js\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type SignalType =\n | \"funding_round\"\n | \"leadership_change\"\n | \"layoffs\"\n | \"acquisition\"\n | \"expansion\"\n | \"product_launch\"\n | \"news_mention\";\n\nexport type SignalImpact = \"positive\" | \"negative\" | \"neutral\";\n\nexport interface ExternalSignal {\n id: string;\n slug: string;\n source: \"hacker_news\" | \"crunchbase\" | \"clearbit\" | \"rss\";\n type: SignalType;\n summary: string;\n url?: string;\n detectedAt: string;\n impact: SignalImpact;\n}\n\n// ─── File I/O ─────────────────────────────────────────────────────────────────\n\nexport function signalsDir(dataDir: string, slug: string): string {\n return path.join(dataDir, \"customers\", slug, \"signals\");\n}\n\nexport function signalsFilePath(dataDir: string, slug: string, date: string): string {\n return path.join(signalsDir(dataDir, slug), `${date}.json`);\n}\n\nexport function readSignals(dataDir: string, slug: string, date: string): ExternalSignal[] {\n const p = signalsFilePath(dataDir, slug, date);\n if (!fs.existsSync(p)) return [];\n try {\n return JSON.parse(fs.readFileSync(p, \"utf-8\") as string) as ExternalSignal[];\n } catch {\n return [];\n }\n}\n\nexport function writeSignals(\n dataDir: string,\n slug: string,\n date: string,\n signals: ExternalSignal[]\n): void {\n writeJsonFile(signalsFilePath(dataDir, slug, date), signals);\n}\n\n// ─── HTTP helper ──────────────────────────────────────────────────────────────\n\nexport async function fetchJson<T>(url: string, headers: Record<string, string> = {}): Promise<T> {\n return new Promise((resolve, reject) => {\n const u = new URL(url);\n const options = {\n hostname: u.hostname,\n path: u.pathname + u.search,\n method: \"GET\",\n headers: { \"User-Agent\": \"datasynx-opencrm/2.0\", ...headers },\n };\n const req = https.request(options, (res) => {\n let data = \"\";\n res.on(\"data\", (chunk: Buffer) => {\n data += chunk.toString();\n });\n res.on(\"end\", () => {\n try {\n resolve(JSON.parse(data) as T);\n } catch (e) {\n reject(e);\n }\n });\n });\n req.on(\"error\", reject);\n req.setTimeout(5000, () => {\n req.destroy();\n reject(new Error(\"timeout\"));\n });\n req.end();\n });\n}\n\n// ─── Hacker News / Algolia API (free, no key needed) ─────────────────────────\n\ninterface HNHit {\n objectID: string;\n title?: string;\n story_title?: string;\n url?: string;\n created_at: string;\n}\n\ninterface HNSearchResult {\n hits: HNHit[];\n}\n\nexport async function checkCompanyNews(\n domain: string,\n companyName: string\n): Promise<ExternalSignal[]> {\n const signals: ExternalSignal[] = [];\n try {\n const query = encodeURIComponent(companyName.split(\" \")[0] ?? domain.split(\".\")[0] ?? \"\");\n const since = Math.floor(Date.now() / 1000) - 30 * 86400;\n const url = `https://hn.algolia.com/api/v1/search?query=${query}&tags=story&numericFilters=created_at_i>${since}&hitsPerPage=5`;\n const result = await fetchJson<HNSearchResult>(url);\n\n for (const hit of result.hits ?? []) {\n const title = hit.title ?? hit.story_title ?? \"\";\n if (!title.toLowerCase().includes(query.toLowerCase())) continue;\n\n const titleLc = title.toLowerCase();\n const type: SignalType = titleLc.includes(\"fund\")\n ? \"funding_round\"\n : titleLc.includes(\"acqui\")\n ? \"acquisition\"\n : titleLc.includes(\"lay\") || titleLc.includes(\"reduc\")\n ? \"layoffs\"\n : \"news_mention\";\n\n const impact: SignalImpact =\n type === \"funding_round\" || type === \"acquisition\"\n ? \"positive\"\n : type === \"layoffs\"\n ? \"negative\"\n : \"neutral\";\n\n signals.push({\n id: `hn_${hit.objectID}`,\n slug: \"\",\n source: \"hacker_news\",\n type,\n summary: title,\n url: hit.url ?? `https://news.ycombinator.com/item?id=${hit.objectID}`,\n detectedAt: new Date().toISOString(),\n impact,\n });\n }\n } catch {\n // Network errors are non-fatal\n }\n return signals;\n}\n\n// ─── Crunchbase Basic API (CRUNCHBASE_API_KEY optional) ──────────────────────\n\ninterface CrunchbaseOrg {\n properties?: {\n short_description?: string;\n funding_total?: { value_usd?: number };\n last_funding_type?: string;\n };\n}\n\nexport async function checkFundingEvents(domain: string): Promise<ExternalSignal[]> {\n const apiKey = process.env[\"CRUNCHBASE_API_KEY\"];\n if (!apiKey) return [];\n\n const signals: ExternalSignal[] = [];\n try {\n const orgName = domain.split(\".\")[0] ?? domain;\n const url = `https://api.crunchbase.com/api/v4/entities/organizations/${orgName}?field_ids=short_description,funding_total,last_funding_type&user_key=${apiKey}`;\n const result = await fetchJson<{ data?: CrunchbaseOrg }>(url);\n const props = result.data?.properties;\n\n if (props?.last_funding_type && props?.funding_total?.value_usd) {\n const millions = (props.funding_total.value_usd / 1_000_000).toFixed(1);\n signals.push({\n id: `cb_${domain}_${Date.now()}`,\n slug: \"\",\n source: \"crunchbase\",\n type: \"funding_round\",\n summary: `${domain} raised funding (${props.last_funding_type}, $${millions}M total)`,\n detectedAt: new Date().toISOString(),\n impact: \"positive\",\n });\n }\n } catch {\n // Non-fatal\n }\n return signals;\n}\n\n// ─── Clearbit enrichment (CLEARBIT_API_KEY optional) ─────────────────────────\n\ninterface ClearbitPerson {\n name?: { fullName?: string };\n employment?: { title?: string; name?: string };\n}\n\nexport async function enrichContact(\n email: string\n): Promise<{ name?: string; title?: string; company?: string } | null> {\n const apiKey = process.env[\"CLEARBIT_API_KEY\"];\n if (!apiKey) return null;\n\n try {\n const url = `https://person.clearbit.com/v2/combined/find?email=${encodeURIComponent(email)}`;\n const result = await fetchJson<ClearbitPerson>(url, {\n Authorization: `Bearer ${apiKey}`,\n });\n return {\n ...(result.name?.fullName ? { name: result.name.fullName } : {}),\n ...(result.employment?.title ? { title: result.employment.title } : {}),\n ...(result.employment?.name ? { company: result.employment.name } : {}),\n };\n } catch {\n return null;\n }\n}\n\n// ─── Main entry point ─────────────────────────────────────────────────────────\n\nexport async function fetchSignalsForCustomer(\n dataDir: string,\n slug: string,\n domain: string,\n companyName: string,\n today: string\n): Promise<ExternalSignal[]> {\n const [newsSignals, fundingSignals] = await Promise.all([\n checkCompanyNews(domain, companyName),\n checkFundingEvents(domain),\n ]);\n\n const signals: ExternalSignal[] = [\n ...newsSignals.map((s) => ({ ...s, slug })),\n ...fundingSignals.map((s) => ({ ...s, slug })),\n ];\n\n if (signals.length > 0) {\n writeSignals(dataDir, slug, today, signals);\n }\n\n return signals;\n}\n","// src/daemon/proactive-worker.ts\n// Daily proactive checks: relationship decay + deal risk + daily briefing.\n// Called from worker.ts CronJob at 07:00. Enqueues tasks to agent-queue.json.\n// Queue draining (Telegram/Slack dispatch) is handled by G3 / notification-dispatcher.\nimport fs from \"fs\";\nimport path from \"path\";\nimport { computeCustomerHealth, readHealth } from \"../core/relationship-health.js\";\nimport { readPipeline } from \"../fs/pipeline-writer.js\";\nimport {\n buildDailyBriefing,\n enqueueTask,\n type NotificationChannel,\n} from \"../core/proactive-agent.js\";\nimport { fetchSignalsForCustomer } from \"../sync/external-signals.js\";\nimport { runScheduledBackupIfDue } from \"../commands/backup.js\";\n\nconst MAX_CUSTOMERS_PER_CYCLE = 50;\n\nfunction defaultChannel(): NotificationChannel {\n if (process.env[\"TELEGRAM_BOT_TOKEN\"] && process.env[\"TELEGRAM_CHAT_ID\"]) return \"telegram\";\n if (process.env[\"SLACK_WEBHOOK_URL\"]) return \"slack\";\n return \"mcp_tool_response\";\n}\n\nexport interface ProactiveCheckResult {\n today: string;\n customersChecked: number;\n tasksEnqueued: number;\n errors: string[];\n}\n\nexport async function runDailyProactiveChecks(\n dataDir: string,\n today: string = new Date().toISOString().slice(0, 10)\n): Promise<ProactiveCheckResult> {\n const result: ProactiveCheckResult = { today, customersChecked: 0, tasksEnqueued: 0, errors: [] };\n const channel = defaultChannel();\n\n const customersDir = path.join(dataDir, \"customers\");\n const slugs = fs.existsSync(customersDir)\n ? fs\n .readdirSync(customersDir)\n .filter((s) => {\n try {\n return fs.statSync(path.join(customersDir, s)).isDirectory();\n } catch {\n return false;\n }\n })\n .slice(0, MAX_CUSTOMERS_PER_CYCLE)\n : [];\n\n const todayMs = new Date(`${today}T00:00:00Z`).getTime();\n\n await Promise.all(\n slugs.map(async (slug) => {\n try {\n // Relationship health — use cached snapshot if fresh, compute otherwise\n const health = readHealth(dataDir, slug) ?? computeCustomerHealth(dataDir, slug, today);\n\n for (const contact of health.contacts) {\n const isDecayed = contact.riskFlags.includes(\"NO_CONTACT_30D\") || contact.grade === \"F\";\n\n if (isDecayed) {\n await enqueueTask(dataDir, {\n type: \"relationship_decay_alert\",\n slug,\n priority: contact.grade === \"F\" ? \"urgent\" : \"high\",\n payload: {\n contactId: contact.contactId,\n name: contact.name,\n email: contact.email,\n daysSinceContact: contact.daysSinceContact,\n grade: contact.grade,\n riskFlags: contact.riskFlags,\n },\n scheduledFor: new Date().toISOString(),\n channel,\n });\n result.tasksEnqueued++;\n }\n }\n\n // Deal risk — close date within 7 days or already overdue\n const deals = await readPipeline(dataDir, slug).catch(() => []);\n for (const deal of deals) {\n if (deal.stage === \"won\" || deal.stage === \"lost\") continue;\n if (!deal.close_date?.trim()) continue;\n\n const daysToClose = Math.floor(\n (new Date(deal.close_date).getTime() - todayMs) / 86_400_000\n );\n\n if (daysToClose <= 7) {\n await enqueueTask(dataDir, {\n type: \"deal_risk_alert\",\n slug,\n priority: daysToClose < 0 ? \"urgent\" : \"high\",\n payload: {\n dealName: deal.name,\n stage: deal.stage,\n value: deal.value,\n closeDate: deal.close_date,\n daysToClose,\n overdue: daysToClose < 0,\n },\n scheduledFor: new Date().toISOString(),\n channel,\n });\n result.tasksEnqueued++;\n }\n }\n\n // External signals — read domain/name from main_facts if available\n try {\n const factsPath = path.join(dataDir, \"customers\", slug, \"main_facts.md\");\n if (fs.existsSync(factsPath)) {\n const raw = fs.readFileSync(factsPath, \"utf-8\");\n const domainMatch = raw.match(/^domain:\\s*(.+)$/im);\n const nameMatch = raw.match(/^name:\\s*(.+)$/im);\n const domain = domainMatch?.[1]?.trim();\n const companyName = nameMatch?.[1]?.trim() ?? slug;\n if (domain) {\n const signals = await fetchSignalsForCustomer(\n dataDir,\n slug,\n domain,\n companyName,\n today\n );\n for (const signal of signals) {\n if (signal.impact === \"neutral\") continue;\n await enqueueTask(dataDir, {\n type: \"external_signal_alert\",\n slug,\n priority: signal.impact === \"negative\" ? \"urgent\" : \"high\",\n payload: signal,\n scheduledFor: new Date().toISOString(),\n channel,\n });\n result.tasksEnqueued++;\n }\n }\n }\n } catch {\n // External signals are best-effort — never block the rest of the cycle\n }\n\n result.customersChecked++;\n } catch (err) {\n result.errors.push(`${slug}: ${(err as Error).message}`);\n }\n })\n );\n\n // Daily briefing — always enqueue, agents consume via get_proactive_briefing\n try {\n const briefing = await buildDailyBriefing(dataDir, today);\n await enqueueTask(dataDir, {\n type: \"daily_briefing\",\n priority: \"normal\",\n payload: briefing,\n scheduledFor: new Date().toISOString(),\n channel,\n });\n result.tasksEnqueued++;\n } catch (err) {\n result.errors.push(`daily_briefing: ${(err as Error).message}`);\n }\n\n // Scheduled backup — fire-and-forget, non-blocking\n runScheduledBackupIfDue(dataDir).catch(() => {\n // non-critical — proactive cycle must not fail due to backup errors\n });\n\n return result;\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as renewExpiringSubscriptions, n as readSubscriptions, s as writeSubscriptions } from "./push-manager-
|
|
1
|
+
import { i as renewExpiringSubscriptions, n as readSubscriptions, s as writeSubscriptions } from "./push-manager-C0ECQgva.js";
|
|
2
2
|
export { readSubscriptions, renewExpiringSubscriptions, writeSubscriptions };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { i as writeJsonFile } from "./json-store-WWsFzXub.js";
|
|
1
2
|
import path from "path";
|
|
2
3
|
import fs from "fs";
|
|
3
4
|
//#region src/sync/push-manager.ts
|
|
@@ -20,11 +21,10 @@ async function readSubscriptions(dataDir) {
|
|
|
20
21
|
async function writeSubscriptions(dataDir, subs) {
|
|
21
22
|
const filePath = subscriptionsPath(dataDir);
|
|
22
23
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
23
|
-
|
|
24
|
+
writeJsonFile(filePath, {
|
|
24
25
|
subscriptions: subs,
|
|
25
26
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
26
|
-
};
|
|
27
|
-
fs.writeFileSync(filePath, JSON.stringify(file, null, 2), "utf-8");
|
|
27
|
+
});
|
|
28
28
|
}
|
|
29
29
|
function expiresAtForProvider(provider) {
|
|
30
30
|
if (provider === "gmail") return new Date(Date.now() + 10080 * 60 * 1e3).toISOString();
|
|
@@ -105,4 +105,4 @@ async function renewExpiringSubscriptions(dataDir, renewFn, thresholdHours = 24)
|
|
|
105
105
|
//#endregion
|
|
106
106
|
export { revoke as a, renewExpiringSubscriptions as i, readSubscriptions as n, subscriptionsPath as o, register as r, writeSubscriptions as s, makePushSubId as t };
|
|
107
107
|
|
|
108
|
-
//# sourceMappingURL=push-manager-
|
|
108
|
+
//# sourceMappingURL=push-manager-C0ECQgva.js.map
|