@datasynx/agentic-crm 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +767 -0
  3. package/dist/agent-config-zPvcqu07.js +14 -0
  4. package/dist/agent-config-zPvcqu07.js.map +1 -0
  5. package/dist/approvals-DpjxGHFp.js +67 -0
  6. package/dist/approvals-DpjxGHFp.js.map +1 -0
  7. package/dist/ask-CID3jnuL.js +52 -0
  8. package/dist/ask-CID3jnuL.js.map +1 -0
  9. package/dist/audit-log-DNMY9mUZ.js +49 -0
  10. package/dist/audit-log-DNMY9mUZ.js.map +1 -0
  11. package/dist/auth-CyFuu9X_.js +2 -0
  12. package/dist/auth-DFWwWcYD.js +93 -0
  13. package/dist/auth-DFWwWcYD.js.map +1 -0
  14. package/dist/autofill-Di_-SP7t.js +51 -0
  15. package/dist/autofill-Di_-SP7t.js.map +1 -0
  16. package/dist/backup-CeMk9z86.js +417 -0
  17. package/dist/backup-CeMk9z86.js.map +1 -0
  18. package/dist/backup-f_hC7rBV.js +2 -0
  19. package/dist/calendly-Bft_wwji.js +52 -0
  20. package/dist/calendly-Bft_wwji.js.map +1 -0
  21. package/dist/calendly-D3coO92o.cjs +53 -0
  22. package/dist/calendly-D3coO92o.cjs.map +1 -0
  23. package/dist/chunk-DakpK96I.cjs +43 -0
  24. package/dist/churn-C28IgnAj.js +54 -0
  25. package/dist/churn-C28IgnAj.js.map +1 -0
  26. package/dist/cli.js +4396 -0
  27. package/dist/cli.js.map +1 -0
  28. package/dist/colors-BG07TZQz.js +11 -0
  29. package/dist/colors-BG07TZQz.js.map +1 -0
  30. package/dist/compliance-B1kk5-YS.js +115 -0
  31. package/dist/compliance-B1kk5-YS.js.map +1 -0
  32. package/dist/compliance-B91zNvCR.cjs +156 -0
  33. package/dist/compliance-B91zNvCR.cjs.map +1 -0
  34. package/dist/compliance-CKSBoQUe.js +118 -0
  35. package/dist/compliance-CKSBoQUe.js.map +1 -0
  36. package/dist/compliance-CujOqAKk.js +2 -0
  37. package/dist/context-builder-BzWAp3Zs.js +96 -0
  38. package/dist/context-builder-BzWAp3Zs.js.map +1 -0
  39. package/dist/context-builder-DlrRcqmJ.js +2 -0
  40. package/dist/conversation-intel-mm7Lhemh.js +72 -0
  41. package/dist/conversation-intel-mm7Lhemh.js.map +1 -0
  42. package/dist/custom-fields-CzNeD3_v.js +2 -0
  43. package/dist/custom-fields-Pl2t9xzp.js +73 -0
  44. package/dist/custom-fields-Pl2t9xzp.js.map +1 -0
  45. package/dist/custom-objects-BHgn1GEX.js +78 -0
  46. package/dist/custom-objects-BHgn1GEX.js.map +1 -0
  47. package/dist/custom-objects-CIFrmQ2V.js +2 -0
  48. package/dist/customer-dir-DIylZ8Q6.js +75 -0
  49. package/dist/customer-dir-DIylZ8Q6.js.map +1 -0
  50. package/dist/daemon/worker.js +207 -0
  51. package/dist/daemon/worker.js.map +1 -0
  52. package/dist/enrichment-3XvgGDfB.js +103 -0
  53. package/dist/enrichment-3XvgGDfB.js.map +1 -0
  54. package/dist/file-lock-B_zi7NQl.js +22 -0
  55. package/dist/file-lock-B_zi7NQl.js.map +1 -0
  56. package/dist/gmail-auth-BP6cJwfw.js +40 -0
  57. package/dist/gmail-auth-BP6cJwfw.js.map +1 -0
  58. package/dist/gmail-auth-DxakCtGm.cjs +44 -0
  59. package/dist/gmail-auth-DxakCtGm.cjs.map +1 -0
  60. package/dist/gmail-auth-OComS92L.js +40 -0
  61. package/dist/gmail-auth-OComS92L.js.map +1 -0
  62. package/dist/gmail-push-watch-DELQFMPk.js +20 -0
  63. package/dist/gmail-push-watch-DELQFMPk.js.map +1 -0
  64. package/dist/gmail-sender-StTpJ9Ub.js +32 -0
  65. package/dist/gmail-sender-StTpJ9Ub.js.map +1 -0
  66. package/dist/gmail-sync-DIaxInDT.js +204 -0
  67. package/dist/gmail-sync-DIaxInDT.js.map +1 -0
  68. package/dist/gmail-sync-hHm9gaWd.cjs +218 -0
  69. package/dist/gmail-sync-hHm9gaWd.cjs.map +1 -0
  70. package/dist/gmail-sync-rQaVqKWd.js +214 -0
  71. package/dist/gmail-sync-rQaVqKWd.js.map +1 -0
  72. package/dist/gmail-webhook-handler-DS7OlRPX.js +3 -0
  73. package/dist/gmail-webhook-handler-e5Od25FX.js +97 -0
  74. package/dist/gmail-webhook-handler-e5Od25FX.js.map +1 -0
  75. package/dist/goal-engine-CUZSpERI.js +2 -0
  76. package/dist/goal-engine-KpBftn4V.js +295 -0
  77. package/dist/goal-engine-KpBftn4V.js.map +1 -0
  78. package/dist/google-drive-sync-DEPcqFca.js +105 -0
  79. package/dist/google-drive-sync-DEPcqFca.js.map +1 -0
  80. package/dist/hybrid-search-BmHttLrR.js +40 -0
  81. package/dist/hybrid-search-BmHttLrR.js.map +1 -0
  82. package/dist/hygiene-DZqfYpFf.js +38 -0
  83. package/dist/hygiene-DZqfYpFf.js.map +1 -0
  84. package/dist/identity-CI6olMNm.js +41 -0
  85. package/dist/identity-CI6olMNm.js.map +1 -0
  86. package/dist/identity-gyfWdrcX.js +2 -0
  87. package/dist/import-hubspot-BaK71U_K.js +588 -0
  88. package/dist/import-hubspot-BaK71U_K.js.map +1 -0
  89. package/dist/index-V8BFaH-b.d.ts +539 -0
  90. package/dist/index-V8BFaH-b.d.ts.map +1 -0
  91. package/dist/index-YqwMd6aQ.d.cts +538 -0
  92. package/dist/index-YqwMd6aQ.d.cts.map +1 -0
  93. package/dist/index.cjs +185 -0
  94. package/dist/index.cjs.map +1 -0
  95. package/dist/index.d.cts +538 -0
  96. package/dist/index.d.cts.map +1 -0
  97. package/dist/index.d.ts +539 -0
  98. package/dist/index.d.ts.map +1 -0
  99. package/dist/index.js +165 -0
  100. package/dist/index.js.map +1 -0
  101. package/dist/interactions-writer-CrPStUll.cjs +77 -0
  102. package/dist/interactions-writer-CrPStUll.cjs.map +1 -0
  103. package/dist/interactions-writer-DO3KcSR3.js +52 -0
  104. package/dist/interactions-writer-DO3KcSR3.js.map +1 -0
  105. package/dist/interactions-writer-SLHnoEeE.js +46 -0
  106. package/dist/interactions-writer-SLHnoEeE.js.map +1 -0
  107. package/dist/interactions-writer-dSPy1XfO.js +2 -0
  108. package/dist/knowledge-base-D0Fh40kc.js +1013 -0
  109. package/dist/knowledge-base-D0Fh40kc.js.map +1 -0
  110. package/dist/lancedb-CCBbpulq.js +2 -0
  111. package/dist/lancedb-rlvWoPwl.js +98 -0
  112. package/dist/lancedb-rlvWoPwl.js.map +1 -0
  113. package/dist/lead-model-BCFzyktm.js +109 -0
  114. package/dist/lead-model-BCFzyktm.js.map +1 -0
  115. package/dist/llm-DEjWcqmW.js +2 -0
  116. package/dist/llm-DvzZqva0.js +372 -0
  117. package/dist/llm-DvzZqva0.js.map +1 -0
  118. package/dist/llm-Z8RIYkpF.js +174 -0
  119. package/dist/llm-Z8RIYkpF.js.map +1 -0
  120. package/dist/llm-iijeXmgq.cjs +198 -0
  121. package/dist/llm-iijeXmgq.cjs.map +1 -0
  122. package/dist/mcp-CdTJWTJf.d.cts +12 -0
  123. package/dist/mcp-CdTJWTJf.d.cts.map +1 -0
  124. package/dist/mcp-CdTJWTJf.d.ts +12 -0
  125. package/dist/mcp-CdTJWTJf.d.ts.map +1 -0
  126. package/dist/mcp.cjs +7464 -0
  127. package/dist/mcp.cjs.map +1 -0
  128. package/dist/mcp.d.cts +12 -0
  129. package/dist/mcp.d.cts.map +1 -0
  130. package/dist/mcp.d.ts +12 -0
  131. package/dist/mcp.d.ts.map +1 -0
  132. package/dist/mcp.js +7448 -0
  133. package/dist/mcp.js.map +1 -0
  134. package/dist/memory-Bb6ky3kb.js +58 -0
  135. package/dist/memory-Bb6ky3kb.js.map +1 -0
  136. package/dist/memory-Cy6-Tbyl.js +2 -0
  137. package/dist/metrics-DH8wHvya.js +26 -0
  138. package/dist/metrics-DH8wHvya.js.map +1 -0
  139. package/dist/microsoft-auth-B8_S45gh.js +17 -0
  140. package/dist/microsoft-auth-B8_S45gh.js.map +1 -0
  141. package/dist/microsoft-calendar-B6MMtUQK.js +67 -0
  142. package/dist/microsoft-calendar-B6MMtUQK.js.map +1 -0
  143. package/dist/microsoft-sync-CpZVoSuq.js +68 -0
  144. package/dist/microsoft-sync-CpZVoSuq.js.map +1 -0
  145. package/dist/nba-3wanmJ0U.js +48 -0
  146. package/dist/nba-3wanmJ0U.js.map +1 -0
  147. package/dist/notification-dispatcher-0vYNngWe.js +97 -0
  148. package/dist/notification-dispatcher-0vYNngWe.js.map +1 -0
  149. package/dist/opportunity-score-BTMOQSTV.js +47 -0
  150. package/dist/opportunity-score-BTMOQSTV.js.map +1 -0
  151. package/dist/pipedrive-client-CdGKpH9b.js +17 -0
  152. package/dist/pipedrive-client-CdGKpH9b.js.map +1 -0
  153. package/dist/pipeline-writer-BqBrYrQc.js +2 -0
  154. package/dist/pipeline-writer-BvVquKIe.js +96 -0
  155. package/dist/pipeline-writer-BvVquKIe.js.map +1 -0
  156. package/dist/pipeline-writer-N2omexxp.cjs +121 -0
  157. package/dist/pipeline-writer-N2omexxp.cjs.map +1 -0
  158. package/dist/pipeline-writer-eufx_0o1.js +102 -0
  159. package/dist/pipeline-writer-eufx_0o1.js.map +1 -0
  160. package/dist/proactive-agent-BgQXw3ac.js +96 -0
  161. package/dist/proactive-agent-BgQXw3ac.js.map +1 -0
  162. package/dist/proactive-worker-BrLHNhjH.js +229 -0
  163. package/dist/proactive-worker-BrLHNhjH.js.map +1 -0
  164. package/dist/push-manager-CdqIIkuh.js +108 -0
  165. package/dist/push-manager-CdqIIkuh.js.map +1 -0
  166. package/dist/push-manager-CowY-0IK.js +2 -0
  167. package/dist/quote-generator-BfwENXzg.js +133 -0
  168. package/dist/quote-generator-BfwENXzg.js.map +1 -0
  169. package/dist/quote-generator-OhSFsi3x.js +2 -0
  170. package/dist/rbac-C7c8tcES.js +2 -0
  171. package/dist/rbac-CTIktZaC.js +91 -0
  172. package/dist/rbac-CTIktZaC.js.map +1 -0
  173. package/dist/relationship-health-odxEoQdJ.js +454 -0
  174. package/dist/relationship-health-odxEoQdJ.js.map +1 -0
  175. package/dist/revenue-simulation-BJdRTEHc.js +2 -0
  176. package/dist/revenue-simulation-Bqf2DLVB.js +251 -0
  177. package/dist/revenue-simulation-Bqf2DLVB.js.map +1 -0
  178. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  179. package/dist/salesforce-client-rhZFa_p5.js +51 -0
  180. package/dist/salesforce-client-rhZFa_p5.js.map +1 -0
  181. package/dist/segments-BqcD5HIl.js +61 -0
  182. package/dist/segments-BqcD5HIl.js.map +1 -0
  183. package/dist/sequence-engine-CCTHEBgi.js +2 -0
  184. package/dist/sequence-engine-J1lTW_in.js +91 -0
  185. package/dist/sequence-engine-J1lTW_in.js.map +1 -0
  186. package/dist/sequence-store-DaaWr0Os.js +221 -0
  187. package/dist/sequence-store-DaaWr0Os.js.map +1 -0
  188. package/dist/server-Dyva03K8.js +4287 -0
  189. package/dist/server-Dyva03K8.js.map +1 -0
  190. package/dist/session-B9AilxOE.js +81 -0
  191. package/dist/session-B9AilxOE.js.map +1 -0
  192. package/dist/session-D0qFkBla.cjs +82 -0
  193. package/dist/session-D0qFkBla.cjs.map +1 -0
  194. package/dist/session-D9ub6Wl1.js +79 -0
  195. package/dist/session-D9ub6Wl1.js.map +1 -0
  196. package/dist/session-mWHA71Lw.js +2 -0
  197. package/dist/session-store-B0QZE8Bx.cjs +697 -0
  198. package/dist/session-store-B0QZE8Bx.cjs.map +1 -0
  199. package/dist/session-store-C8tEvMPw.js +543 -0
  200. package/dist/session-store-C8tEvMPw.js.map +1 -0
  201. package/dist/session-store-CEa39Dxs.js +15 -0
  202. package/dist/session-store-CEa39Dxs.js.map +1 -0
  203. package/dist/sla-engine-5IhTsBUR.js +2 -0
  204. package/dist/sla-engine-BqX-7u-7.js +53 -0
  205. package/dist/sla-engine-BqX-7u-7.js.map +1 -0
  206. package/dist/sop-DkhVChGy.js +2 -0
  207. package/dist/sop-Vp0UPWFW.js +70 -0
  208. package/dist/sop-Vp0UPWFW.js.map +1 -0
  209. package/dist/survey-engine-C06hcQt3.js +2 -0
  210. package/dist/survey-engine-DBjCYqCv.js +147 -0
  211. package/dist/survey-engine-DBjCYqCv.js.map +1 -0
  212. package/dist/sync-state-ChaLbamC.js +33 -0
  213. package/dist/sync-state-ChaLbamC.js.map +1 -0
  214. package/dist/sync-state-CwLSt_1m.js +2 -0
  215. package/dist/ticket-writer-CjqKeIRD.js +2 -0
  216. package/dist/ticket-writer-j2oX_Wal.js +134 -0
  217. package/dist/ticket-writer-j2oX_Wal.js.map +1 -0
  218. package/dist/tone-Bdm5uaht.js +48 -0
  219. package/dist/tone-Bdm5uaht.js.map +1 -0
  220. package/dist/tone-DRKlZgPr.cjs +43 -0
  221. package/dist/tone-DRKlZgPr.cjs.map +1 -0
  222. package/dist/tone-vNb2DAAD.js +39 -0
  223. package/dist/tone-vNb2DAAD.js.map +1 -0
  224. package/dist/transcript-watcher-CL2QUygI.js +132 -0
  225. package/dist/transcript-watcher-CL2QUygI.js.map +1 -0
  226. package/dist/unmatched-transcripts-BsH5bhkU.js +26 -0
  227. package/dist/unmatched-transcripts-BsH5bhkU.js.map +1 -0
  228. package/dist/unmatched-transcripts-D0PrJ9iz.js +2 -0
  229. package/dist/update-deal-BNwPGaTV.js +2 -0
  230. package/dist/update-deal-DKC79skb.js +91 -0
  231. package/dist/update-deal-DKC79skb.js.map +1 -0
  232. package/dist/usage-CClTf5e6.cjs +57 -0
  233. package/dist/usage-CClTf5e6.cjs.map +1 -0
  234. package/dist/usage-D0-TYJkw.js +93 -0
  235. package/dist/usage-D0-TYJkw.js.map +1 -0
  236. package/dist/usage-D0u9a-lV.js +54 -0
  237. package/dist/usage-D0u9a-lV.js.map +1 -0
  238. package/dist/vault-C1D3zScD.js +2 -0
  239. package/dist/vault-DXCg29W-.js +86 -0
  240. package/dist/vault-DXCg29W-.js.map +1 -0
  241. package/dist/webhooks-7EpA05Qr.js +138 -0
  242. package/dist/webhooks-7EpA05Qr.js.map +1 -0
  243. package/dist/webhooks-BO2UAnmn.js +94 -0
  244. package/dist/webhooks-BO2UAnmn.js.map +1 -0
  245. package/dist/webhooks-Xn6zO6kd.cjs +97 -0
  246. package/dist/webhooks-Xn6zO6kd.cjs.map +1 -0
  247. package/dist/write-queue-BDolUxfs.cjs +26 -0
  248. package/dist/write-queue-BDolUxfs.cjs.map +1 -0
  249. package/dist/write-queue-IbsAjUnh.js +21 -0
  250. package/dist/write-queue-IbsAjUnh.js.map +1 -0
  251. package/package.json +142 -0
@@ -0,0 +1,588 @@
1
+ import path from "path";
2
+ import fs from "fs";
3
+ import { z } from "zod";
4
+ import { createHash } from "crypto";
5
+ import readline from "readline";
6
+ //#region src/core/csv-stream.ts
7
+ function parseCSVLine(line, delimiter = ",") {
8
+ const result = [];
9
+ let current = "";
10
+ let inQuotes = false;
11
+ for (let i = 0; i < line.length; i++) {
12
+ const ch = line[i];
13
+ if (ch === "\"") if (inQuotes && line[i + 1] === "\"") {
14
+ current += "\"";
15
+ i++;
16
+ } else inQuotes = !inQuotes;
17
+ else if (ch === delimiter && !inQuotes) {
18
+ result.push(current.trim());
19
+ current = "";
20
+ } else current += ch;
21
+ }
22
+ result.push(current.trim());
23
+ return result;
24
+ }
25
+ /** Streaming line-by-line CSV parser — O(1) memory for arbitrarily large files. */
26
+ async function* streamCSV(filePath, opts = {}) {
27
+ const delimiter = opts.delimiter ?? ",";
28
+ const stream = fs.createReadStream(filePath, { encoding: "utf-8" });
29
+ const rl = readline.createInterface({
30
+ input: stream,
31
+ crlfDelay: Infinity
32
+ });
33
+ let headers = null;
34
+ for await (const line of rl) {
35
+ const trimmed = line.trim();
36
+ if (!trimmed) continue;
37
+ const values = parseCSVLine(trimmed, delimiter);
38
+ if (!headers) {
39
+ headers = values.map((h) => h.replace(/^"|"$/g, "").trim());
40
+ continue;
41
+ }
42
+ const row = {};
43
+ headers.forEach((h, i) => {
44
+ row[h] = values[i] ?? "";
45
+ });
46
+ yield row;
47
+ }
48
+ }
49
+ //#endregion
50
+ //#region src/fs/contacts-writer.ts
51
+ const CustomerContactSchema = z.object({
52
+ email: z.string().email(),
53
+ name: z.string().min(1),
54
+ title: z.string().optional(),
55
+ phone: z.string().optional(),
56
+ department: z.string().optional(),
57
+ linkedinUrl: z.string().url().optional(),
58
+ isPrimary: z.boolean().default(false),
59
+ hubspotId: z.string().optional(),
60
+ hubspotOwnerId: z.string().optional(),
61
+ createdAt: z.string().optional()
62
+ });
63
+ function contactsPath(dataDir, slug) {
64
+ return path.join(dataDir, "customers", slug, "contacts.json");
65
+ }
66
+ function listContacts(dataDir, slug) {
67
+ const p = contactsPath(dataDir, slug);
68
+ if (!fs.existsSync(p)) return [];
69
+ try {
70
+ const raw = JSON.parse(fs.readFileSync(p, "utf-8"));
71
+ if (!Array.isArray(raw)) return [];
72
+ return raw.flatMap((item) => {
73
+ const r = CustomerContactSchema.safeParse(item);
74
+ return r.success ? [r.data] : [];
75
+ });
76
+ } catch {
77
+ return [];
78
+ }
79
+ }
80
+ function upsertContact(dataDir, slug, contact) {
81
+ const contacts = listContacts(dataDir, slug);
82
+ const idx = contacts.findIndex((c) => c.email.toLowerCase() === contact.email.toLowerCase());
83
+ if (idx >= 0) contacts[idx] = {
84
+ ...contacts[idx],
85
+ ...contact
86
+ };
87
+ else contacts.push(contact);
88
+ if (contact.isPrimary) {
89
+ for (const c of contacts) if (c.email.toLowerCase() !== contact.email.toLowerCase()) c.isPrimary = false;
90
+ }
91
+ const dir = path.dirname(contactsPath(dataDir, slug));
92
+ fs.mkdirSync(dir, { recursive: true });
93
+ fs.writeFileSync(contactsPath(dataDir, slug), JSON.stringify(contacts, null, 2), "utf-8");
94
+ }
95
+ //#endregion
96
+ //#region src/commands/import-hubspot.ts
97
+ const STAGE_MAP = {
98
+ appointmentscheduled: "qualified",
99
+ qualifiedtobuy: "qualified",
100
+ presentationscheduled: "proposal",
101
+ decisionmakerboughtin: "negotiation",
102
+ contractsent: "negotiation",
103
+ closedwon: "won",
104
+ closedlost: "lost",
105
+ prospecting: "lead",
106
+ qualification: "qualified",
107
+ proposal: "proposal",
108
+ negotiation: "negotiation",
109
+ closedwon2: "won",
110
+ closedlost2: "lost"
111
+ };
112
+ const TYPE_MAP = {
113
+ NOTE: "Note",
114
+ CALL: "Call",
115
+ EMAIL: "Email",
116
+ MEETING: "Meeting",
117
+ TASK: "Note",
118
+ LINKEDIN_MESSAGE: "Email",
119
+ WHATSAPP_MESSAGE: "Email",
120
+ POSTAL_MAIL: "Note"
121
+ };
122
+ const COMPANY_FIELD_MAP = {
123
+ hs_annual_revenue: "annual_revenue",
124
+ num_associated_contacts: "contact_count",
125
+ industry: "industry",
126
+ city: "city",
127
+ country: "country",
128
+ hs_lead_status: "lead_status",
129
+ lifecyclestage: "lifecycle_stage",
130
+ numberofemployees: "employee_count",
131
+ phone: "phone",
132
+ address: "address",
133
+ zip: "zip",
134
+ state: "state"
135
+ };
136
+ const KNOWN_COMPANY_COLUMNS = new Set([
137
+ "name",
138
+ "Name",
139
+ "domain",
140
+ "Domain",
141
+ "website",
142
+ "Website",
143
+ "phone",
144
+ "Phone",
145
+ "address",
146
+ "Address",
147
+ "city",
148
+ "City",
149
+ "country",
150
+ "Country",
151
+ "state",
152
+ "State",
153
+ "zip",
154
+ "Zip",
155
+ "industry",
156
+ "Industry",
157
+ "numberofemployees",
158
+ "Number of Employees",
159
+ "hs_annual_revenue",
160
+ "Annual Revenue",
161
+ "lifecyclestage",
162
+ "Lifecycle Stage",
163
+ "hubspot_owner_email",
164
+ "HubSpot Owner Email",
165
+ "create_date",
166
+ "createdate",
167
+ "hs_lastmodifieddate",
168
+ "hs_object_id",
169
+ "Record ID"
170
+ ]);
171
+ function slugify(name) {
172
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
173
+ }
174
+ function hashStr(s) {
175
+ return createHash("sha256").update(s).digest("hex").slice(0, 16);
176
+ }
177
+ function coerceDate(raw) {
178
+ if (!raw) return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
179
+ if (/^\d{13}$/.test(raw.trim())) return new Date(parseInt(raw, 10)).toISOString().slice(0, 10);
180
+ const d = new Date(raw.trim());
181
+ if (!isNaN(d.getTime())) return d.toISOString().slice(0, 10);
182
+ return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
183
+ }
184
+ function ensureCustomer(dataDir, name, domain, email, dryRun) {
185
+ const slug = slugify(name || "unknown");
186
+ const customerDir = path.join(dataDir, "customers", slug);
187
+ const mainFactsPath = path.join(customerDir, "main_facts.md");
188
+ if (fs.existsSync(mainFactsPath)) return {
189
+ slug,
190
+ created: false
191
+ };
192
+ if (dryRun) return {
193
+ slug,
194
+ created: true
195
+ };
196
+ fs.mkdirSync(customerDir, { recursive: true });
197
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
198
+ const lines = [
199
+ "---",
200
+ `name: ${name}`,
201
+ domain ? `domain: ${domain}` : null,
202
+ email ? `email: ${email}` : null,
203
+ "relationship_stage: prospect",
204
+ `created: ${today}`,
205
+ `updated: ${today}`,
206
+ `last_touchpoint: ${today}`,
207
+ "tags: []",
208
+ "currency: EUR",
209
+ "---"
210
+ ].filter(Boolean).join("\n");
211
+ fs.writeFileSync(mainFactsPath, `${lines}\n\n# Customer: ${name}\n`, "utf-8");
212
+ fs.writeFileSync(path.join(customerDir, "interactions.md"), `# Interactions — ${name}\n\n`, "utf-8");
213
+ fs.writeFileSync(path.join(customerDir, "pipeline.md"), `# Pipeline — ${name}\n\n`, "utf-8");
214
+ fs.writeFileSync(path.join(customerDir, "sources.json"), JSON.stringify({
215
+ gmail: {
216
+ query: domain ? `from:${domain} OR to:${domain}` : email ? `from:${email} OR to:${email}` : "",
217
+ enabled: true
218
+ },
219
+ transcripts: {
220
+ paths: [],
221
+ extensions: [".txt", ".vtt"],
222
+ enabled: false
223
+ }
224
+ }, null, 2), "utf-8");
225
+ return {
226
+ slug,
227
+ created: true
228
+ };
229
+ }
230
+ function readMainFactsRaw(dataDir, slug) {
231
+ const p = path.join(dataDir, "customers", slug, "main_facts.md");
232
+ return fs.existsSync(p) ? fs.readFileSync(p, "utf-8") : "";
233
+ }
234
+ function updateMainFactsField(dataDir, slug, field, value) {
235
+ const p = path.join(dataDir, "customers", slug, "main_facts.md");
236
+ if (!fs.existsSync(p)) return;
237
+ let content = fs.readFileSync(p, "utf-8");
238
+ const regex = new RegExp(`^${field}:.*$`, "m");
239
+ if (regex.test(content)) content = content.replace(regex, `${field}: ${value}`);
240
+ else {
241
+ const firstDash = content.indexOf("---");
242
+ const secondDash = content.indexOf("---", firstDash + 3);
243
+ if (secondDash >= 0) content = content.slice(0, secondDash) + `${field}: ${value}\n` + content.slice(secondDash);
244
+ }
245
+ fs.writeFileSync(p, content, "utf-8");
246
+ }
247
+ function saveCustomProperties(dataDir, slug, props) {
248
+ if (Object.keys(props).length === 0) return;
249
+ const p = path.join(dataDir, "customers", slug, "custom_properties.json");
250
+ let existing = {};
251
+ if (fs.existsSync(p)) try {
252
+ existing = JSON.parse(fs.readFileSync(p, "utf-8"));
253
+ } catch {
254
+ existing = {};
255
+ }
256
+ const merged = {
257
+ source: "hubspot-import",
258
+ importedAt: (/* @__PURE__ */ new Date()).toISOString(),
259
+ properties: {
260
+ ...existing["properties"] ?? {},
261
+ ...props
262
+ }
263
+ };
264
+ fs.writeFileSync(p, JSON.stringify(merged, null, 2), "utf-8");
265
+ }
266
+ function progressPath(dataDir) {
267
+ return path.join(dataDir, ".agentic", "import-progress.json");
268
+ }
269
+ function readProgress(dataDir) {
270
+ const p = progressPath(dataDir);
271
+ if (!fs.existsSync(p)) return null;
272
+ try {
273
+ return JSON.parse(fs.readFileSync(p, "utf-8"));
274
+ } catch {
275
+ return null;
276
+ }
277
+ }
278
+ function writeProgress(dataDir, progress) {
279
+ fs.mkdirSync(path.dirname(progressPath(dataDir)), { recursive: true });
280
+ fs.writeFileSync(progressPath(dataDir), JSON.stringify(progress, null, 2), "utf-8");
281
+ }
282
+ function clearProgress(dataDir) {
283
+ const p = progressPath(dataDir);
284
+ if (fs.existsSync(p)) fs.unlinkSync(p);
285
+ }
286
+ async function analyzeHubSpotExport(exportDir) {
287
+ const analysis = {
288
+ companiesFound: 0,
289
+ contactsFound: 0,
290
+ dealsFound: 0,
291
+ engagementsFound: 0,
292
+ customPropertiesDetected: [],
293
+ ownersDetected: [],
294
+ unknownStages: [],
295
+ unmappedContacts: 0,
296
+ estimatedMinutes: 0
297
+ };
298
+ const customProps = /* @__PURE__ */ new Set();
299
+ const owners = /* @__PURE__ */ new Set();
300
+ const unknownStages = /* @__PURE__ */ new Set();
301
+ const companyNames = /* @__PURE__ */ new Set();
302
+ const companiesPath = path.join(exportDir, "companies.csv");
303
+ if (fs.existsSync(companiesPath)) for await (const row of streamCSV(companiesPath)) {
304
+ analysis.companiesFound++;
305
+ const name = (row["name"] ?? row["Name"] ?? "").trim();
306
+ if (name) companyNames.add(name.toLowerCase());
307
+ const owner = row["hubspot_owner_email"] ?? row["HubSpot Owner Email"] ?? "";
308
+ if (owner) owners.add(owner);
309
+ for (const key of Object.keys(row)) if (!KNOWN_COMPANY_COLUMNS.has(key) && row[key]) customProps.add(key);
310
+ }
311
+ const contactsPath = path.join(exportDir, "contacts.csv");
312
+ if (fs.existsSync(contactsPath)) for await (const row of streamCSV(contactsPath)) {
313
+ analysis.contactsFound++;
314
+ const company = (row["company"] ?? row["Company"] ?? row["associated_company"] ?? "").trim();
315
+ if (company && !companyNames.has(company.toLowerCase())) analysis.unmappedContacts++;
316
+ const owner = row["contact_owner"] ?? row["Contact Owner"] ?? "";
317
+ if (owner) owners.add(owner);
318
+ }
319
+ const dealsPath = path.join(exportDir, "deals.csv");
320
+ if (fs.existsSync(dealsPath)) for await (const row of streamCSV(dealsPath)) {
321
+ analysis.dealsFound++;
322
+ const stage = (row["dealstage"] ?? row["Deal Stage"] ?? "").trim().toLowerCase();
323
+ if (stage && !STAGE_MAP[stage]) unknownStages.add(stage);
324
+ }
325
+ const engagementsPath = path.join(exportDir, "engagements.csv");
326
+ if (fs.existsSync(engagementsPath)) for await (const _row of streamCSV(engagementsPath)) analysis.engagementsFound++;
327
+ analysis.customPropertiesDetected = Array.from(customProps).slice(0, 50);
328
+ analysis.ownersDetected = Array.from(owners);
329
+ analysis.unknownStages = Array.from(unknownStages);
330
+ const totalRows = analysis.companiesFound + analysis.contactsFound + analysis.dealsFound + analysis.engagementsFound;
331
+ analysis.estimatedMinutes = Math.ceil(totalRows / 2e3);
332
+ return analysis;
333
+ }
334
+ async function runHubSpotCsvImport(exportDir, dataDir, opts = {}) {
335
+ const result = {
336
+ companiesProcessed: 0,
337
+ contactsImported: 0,
338
+ dealsImported: 0,
339
+ engagementsImported: 0,
340
+ errors: [],
341
+ customPropertiesSaved: 0,
342
+ ownersResolved: 0
343
+ };
344
+ const dryRun = opts.dryRun ?? false;
345
+ const ownerMap = opts.ownerMap ?? {};
346
+ let progress = null;
347
+ if (opts.resume) {
348
+ progress = readProgress(dataDir);
349
+ if (progress) console.error(`[import] Resuming import ${progress.importId}...`);
350
+ }
351
+ if (!progress) progress = {
352
+ importId: `hs-import-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19)}`,
353
+ source: exportDir,
354
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
355
+ phases: {
356
+ companies: {
357
+ status: "pending",
358
+ processed: 0
359
+ },
360
+ contacts: {
361
+ status: "pending",
362
+ processed: 0
363
+ },
364
+ deals: {
365
+ status: "pending",
366
+ processed: 0
367
+ },
368
+ engagements: {
369
+ status: "pending",
370
+ processed: 0
371
+ }
372
+ }
373
+ };
374
+ const companySlugMap = /* @__PURE__ */ new Map();
375
+ const emailSlugMap = /* @__PURE__ */ new Map();
376
+ const companiesPath = path.join(exportDir, "companies.csv");
377
+ if (fs.existsSync(companiesPath) && progress.phases.companies.status !== "done") {
378
+ progress.phases.companies.status = "in-progress";
379
+ if (!dryRun) writeProgress(dataDir, progress);
380
+ for await (const row of streamCSV(companiesPath)) {
381
+ const name = (row["name"] ?? row["Name"] ?? "").trim();
382
+ if (!name) continue;
383
+ const domain = (row["domain"] ?? row["Domain"] ?? row["website"] ?? row["Website"] ?? "").trim();
384
+ const hubspotId = (row["hs_object_id"] ?? row["Record ID"] ?? "").trim();
385
+ try {
386
+ const { slug, created } = ensureCustomer(dataDir, name, domain, "", dryRun);
387
+ companySlugMap.set(name.toLowerCase(), slug);
388
+ result.companiesProcessed++;
389
+ if (!dryRun && created) {
390
+ for (const [hsKey, dxKey] of Object.entries(COMPANY_FIELD_MAP)) {
391
+ const val = row[hsKey] ?? "";
392
+ if (val) updateMainFactsField(dataDir, slug, dxKey, val);
393
+ }
394
+ const ownerEmail = row["hubspot_owner_email"] ?? row["HubSpot Owner Email"] ?? "";
395
+ if (ownerEmail && ownerMap[ownerEmail]) {
396
+ updateMainFactsField(dataDir, slug, "assigned_rep", ownerMap[ownerEmail]);
397
+ result.ownersResolved++;
398
+ }
399
+ if (hubspotId) updateMainFactsField(dataDir, slug, "hubspot_company_id", hubspotId);
400
+ const customProps = {};
401
+ for (const [key, val] of Object.entries(row)) if (!KNOWN_COMPANY_COLUMNS.has(key) && val) customProps[key] = val;
402
+ if (Object.keys(customProps).length > 0) {
403
+ saveCustomProperties(dataDir, slug, customProps);
404
+ result.customPropertiesSaved += Object.keys(customProps).length;
405
+ }
406
+ }
407
+ } catch (err) {
408
+ result.errors.push(`Company '${name}': ${err.message}`);
409
+ }
410
+ progress.phases.companies.processed++;
411
+ }
412
+ progress.phases.companies.status = "done";
413
+ if (!dryRun) writeProgress(dataDir, progress);
414
+ } else if (progress.phases.companies.status === "done") {
415
+ const customersDir = path.join(dataDir, "customers");
416
+ if (fs.existsSync(customersDir)) for (const slug of fs.readdirSync(customersDir)) {
417
+ const mf = path.join(customersDir, slug, "main_facts.md");
418
+ if (!fs.existsSync(mf)) continue;
419
+ const nameMatch = fs.readFileSync(mf, "utf-8").match(/^name:\s*(.+)$/m);
420
+ if (nameMatch?.[1]) companySlugMap.set(nameMatch[1].trim().toLowerCase(), slug);
421
+ }
422
+ }
423
+ const contactsPath = path.join(exportDir, "contacts.csv");
424
+ if (fs.existsSync(contactsPath) && progress.phases.contacts.status !== "done") {
425
+ progress.phases.contacts.status = "in-progress";
426
+ if (!dryRun) writeProgress(dataDir, progress);
427
+ for await (const row of streamCSV(contactsPath)) {
428
+ const firstName = (row["firstname"] ?? row["First Name"] ?? "").trim();
429
+ const lastName = (row["lastname"] ?? row["Last Name"] ?? "").trim();
430
+ const email = (row["email"] ?? row["Email"] ?? "").trim();
431
+ const companyName = (row["company"] ?? row["Company"] ?? row["associated_company"] ?? row["Associated Company"] ?? "").trim();
432
+ const phone = (row["phone"] ?? row["Phone"] ?? row["mobilephone"] ?? "").trim();
433
+ const title = (row["jobtitle"] ?? row["Job Title"] ?? "").trim();
434
+ const department = (row["department"] ?? row["Department"] ?? "").trim();
435
+ const hubspotId = (row["vid"] ?? row["Contact ID"] ?? row["hs_object_id"] ?? "").trim();
436
+ let slug = companySlugMap.get(companyName.toLowerCase());
437
+ if (!slug && companyName) {
438
+ const domain = (row["website"] ?? "").trim();
439
+ try {
440
+ const { slug: newSlug, created } = ensureCustomer(dataDir, companyName, domain, email, dryRun);
441
+ slug = newSlug;
442
+ companySlugMap.set(companyName.toLowerCase(), newSlug);
443
+ if (created) result.companiesProcessed++;
444
+ } catch (err) {
445
+ result.errors.push(`Auto-company '${companyName}': ${err.message}`);
446
+ }
447
+ }
448
+ if (!slug) continue;
449
+ if (!dryRun) {
450
+ const contactName = [firstName, lastName].filter(Boolean).join(" ");
451
+ const isFirst = !fs.existsSync(path.join(dataDir, "customers", slug, "contacts.json"));
452
+ if (email || contactName) {
453
+ const contactEntry = {
454
+ email: email || `${slugify(contactName)}@unknown.local`,
455
+ name: contactName || email,
456
+ ...title ? { title } : {},
457
+ ...phone ? { phone } : {},
458
+ ...department ? { department } : {},
459
+ ...hubspotId ? { hubspotId } : {},
460
+ isPrimary: isFirst,
461
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
462
+ };
463
+ try {
464
+ upsertContact(dataDir, slug, contactEntry);
465
+ } catch {}
466
+ }
467
+ const existing = readMainFactsRaw(dataDir, slug);
468
+ if (email && !existing.includes("email:")) updateMainFactsField(dataDir, slug, "email", email);
469
+ if (phone && !existing.includes("phone:")) updateMainFactsField(dataDir, slug, "phone", phone);
470
+ if (contactName && !existing.includes("primary_contact:")) updateMainFactsField(dataDir, slug, "primary_contact", contactName);
471
+ const ownerEmail = row["contact_owner"] ?? row["Contact Owner"] ?? "";
472
+ if (ownerEmail && ownerMap[ownerEmail] && !existing.includes("assigned_rep:")) {
473
+ updateMainFactsField(dataDir, slug, "assigned_rep", ownerMap[ownerEmail]);
474
+ result.ownersResolved++;
475
+ }
476
+ }
477
+ if (email) emailSlugMap.set(email.toLowerCase(), slug);
478
+ result.contactsImported++;
479
+ progress.phases.contacts.processed++;
480
+ }
481
+ progress.phases.contacts.status = "done";
482
+ if (!dryRun) writeProgress(dataDir, progress);
483
+ }
484
+ const dealsPath = path.join(exportDir, "deals.csv");
485
+ if (fs.existsSync(dealsPath) && progress.phases.deals.status !== "done") if (!dryRun) {
486
+ const { upsertDeal } = await import("./pipeline-writer-BqBrYrQc.js");
487
+ progress.phases.deals.status = "in-progress";
488
+ writeProgress(dataDir, progress);
489
+ for await (const row of streamCSV(dealsPath)) {
490
+ const dealName = (row["dealname"] ?? row["Deal Name"] ?? row["name"] ?? "").trim();
491
+ if (!dealName) continue;
492
+ const companyName = (row["associated_company"] ?? row["Associated Company"] ?? row["company"] ?? "").trim();
493
+ const amountStr = (row["amount"] ?? row["Amount"] ?? "0").trim().replace(/[^0-9.]/g, "");
494
+ const stageRaw = (row["dealstage"] ?? row["Deal Stage"] ?? "").trim().toLowerCase();
495
+ const closeDateRaw = (row["closedate"] ?? row["Close Date"] ?? row["close_date"] ?? "").trim();
496
+ const currency = (row["deal_currency_code"] ?? row["Currency"] ?? "EUR").trim();
497
+ const dealId = (row["hs_deal_id"] ?? row["hs_object_id"] ?? row["Record ID"] ?? "").trim();
498
+ const ownerEmail = (row["hubspot_owner_email"] ?? row["HubSpot Owner Email"] ?? "").trim();
499
+ const description = (row["description"] ?? row["Description"] ?? "").trim();
500
+ const slug = companySlugMap.get(companyName.toLowerCase()) ?? slugify(companyName || "unknown");
501
+ const stage = STAGE_MAP[stageRaw] ?? "qualified";
502
+ const amount = parseFloat(amountStr) || 0;
503
+ const closeDate = coerceDate(closeDateRaw);
504
+ const notesParts = [];
505
+ if (dealId) notesParts.push(`hubspot://deal/${dealId}`);
506
+ if (description) notesParts.push(description.slice(0, 200));
507
+ if (ownerEmail && ownerMap[ownerEmail]) notesParts.push(`owner:${ownerMap[ownerEmail]}`);
508
+ const deal = {
509
+ name: dealName,
510
+ stage,
511
+ value: amount,
512
+ currency: currency || "EUR",
513
+ probability: stage === "won" ? 1 : stage === "lost" ? 0 : .5,
514
+ close_date: closeDate,
515
+ updated: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
516
+ ...notesParts.length > 0 ? { notes: notesParts.join(" | ") } : {}
517
+ };
518
+ try {
519
+ await upsertDeal(dataDir, slug, deal);
520
+ result.dealsImported++;
521
+ } catch (err) {
522
+ result.errors.push(`Deal '${dealName}': ${err.message}`);
523
+ }
524
+ progress.phases.deals.processed++;
525
+ }
526
+ progress.phases.deals.status = "done";
527
+ writeProgress(dataDir, progress);
528
+ } else {
529
+ for await (const row of streamCSV(dealsPath)) if ((row["dealname"] ?? row["name"] ?? "").trim()) result.dealsImported++;
530
+ progress.phases.deals.status = "done";
531
+ }
532
+ const engagementsPath = path.join(exportDir, "engagements.csv");
533
+ if (fs.existsSync(engagementsPath) && progress.phases.engagements.status !== "done") if (!dryRun) {
534
+ const { appendInteraction, readInteractions } = await import("./interactions-writer-dSPy1XfO.js");
535
+ progress.phases.engagements.status = "in-progress";
536
+ writeProgress(dataDir, progress);
537
+ for await (const row of streamCSV(engagementsPath)) {
538
+ const engType = (row["engagement_type"] ?? row["Engagement Type"] ?? row["type"] ?? row["Type"] ?? "NOTE").trim().toUpperCase();
539
+ const timestamp = (row["hs_timestamp"] ?? row["Timestamp"] ?? row["date"] ?? row["createdate"] ?? "").trim();
540
+ const body = (row["hs_body_preview"] ?? row["Body"] ?? row["notes"] ?? row["Notes"] ?? row["hs_note_body"] ?? "").trim();
541
+ const subject = (row["subject"] ?? row["Subject"] ?? "").trim();
542
+ const contactEmail = (row["associated_contact_email"] ?? row["Contact Email"] ?? row["from_email"] ?? "").trim().toLowerCase();
543
+ const engId = (row["id"] ?? row["engagement_id"] ?? row["hs_object_id"] ?? hashStr(timestamp + body)).trim();
544
+ const callDuration = (row["call_duration"] ?? row["hs_call_duration"] ?? "").trim();
545
+ const callOutcome = (row["call_outcome"] ?? row["hs_call_disposition"] ?? "").trim();
546
+ const callRecording = (row["call_recording_url"] ?? row["hs_call_recording_url"] ?? "").trim();
547
+ const slug = emailSlugMap.get(contactEmail) ?? companySlugMap.get((row["associated_company"] ?? "").toLowerCase().trim());
548
+ if (!slug) continue;
549
+ const sourceRef = `hubspot://engagement/${engId}`;
550
+ try {
551
+ if ((await readInteractions(dataDir, slug).catch(() => "")).includes(sourceRef)) continue;
552
+ const date = coerceDate(timestamp);
553
+ const type = TYPE_MAP[engType] ?? "Note";
554
+ const summaryParts = [];
555
+ if (subject) summaryParts.push(`Subject: ${subject}`);
556
+ if (body) summaryParts.push(body.slice(0, 500));
557
+ if (callDuration) summaryParts.push(`Duration: ${callDuration}s`);
558
+ if (callOutcome) summaryParts.push(`Outcome: ${callOutcome}`);
559
+ if (callRecording) summaryParts.push(`Recording: ${callRecording}`);
560
+ const summary = summaryParts.join(" | ") || `${type} imported from HubSpot`;
561
+ await appendInteraction(dataDir, slug, {
562
+ date,
563
+ type,
564
+ with: contactEmail || slug,
565
+ summary,
566
+ nextSteps: [],
567
+ sourceRef,
568
+ synced: (/* @__PURE__ */ new Date()).toISOString()
569
+ });
570
+ result.engagementsImported++;
571
+ } catch (err) {
572
+ result.errors.push(`Engagement ${engId}: ${err.message}`);
573
+ }
574
+ progress.phases.engagements.processed++;
575
+ }
576
+ progress.phases.engagements.status = "done";
577
+ writeProgress(dataDir, progress);
578
+ } else {
579
+ for await (const _row of streamCSV(engagementsPath)) result.engagementsImported++;
580
+ progress.phases.engagements.status = "done";
581
+ }
582
+ if (!dryRun) clearProgress(dataDir);
583
+ return result;
584
+ }
585
+ //#endregion
586
+ export { analyzeHubSpotExport, runHubSpotCsvImport };
587
+
588
+ //# sourceMappingURL=import-hubspot-BaK71U_K.js.map