opensentinel 2.1.1 → 3.1.1

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 (268) hide show
  1. package/README.md +354 -283
  2. package/dist/archiver-AVNBYCKQ.js +15340 -0
  3. package/dist/archiver-AVNBYCKQ.js.map +1 -0
  4. package/dist/audit-logger-OBPR7CRO.js +22 -0
  5. package/dist/auth-UOX5K2BE.js +18 -0
  6. package/dist/autonomy-ZXDBDQUJ.js +86 -0
  7. package/dist/autonomy-ZXDBDQUJ.js.map +1 -0
  8. package/dist/aws-s3-Q4LLZZPD.js +146 -0
  9. package/dist/aws-s3-Q4LLZZPD.js.map +1 -0
  10. package/dist/backup-restore-PZ7CYYB7.js +16 -0
  11. package/dist/blocks-R3PODY47.js +23 -0
  12. package/dist/bot-QRARP4UN.js +36 -0
  13. package/dist/brain-7XLLM3KC.js +56 -0
  14. package/dist/camera-monitor-M5CYKUU4.js +335 -0
  15. package/dist/camera-monitor-M5CYKUU4.js.map +1 -0
  16. package/dist/{charts-MMXM6BWW.js → charts-V7ARZNKF.js} +2 -2
  17. package/dist/chunk-22VGGA7S.js +330 -0
  18. package/dist/chunk-22VGGA7S.js.map +1 -0
  19. package/dist/chunk-35WYTA3C.js +382 -0
  20. package/dist/chunk-35WYTA3C.js.map +1 -0
  21. package/dist/chunk-3E2PSU2C.js +146 -0
  22. package/dist/chunk-3E2PSU2C.js.map +1 -0
  23. package/dist/{chunk-L3F43VPB.js → chunk-4GLYY4NN.js} +2 -2
  24. package/dist/{chunk-L3F43VPB.js.map → chunk-4GLYY4NN.js.map} +1 -1
  25. package/dist/{chunk-L3PDU3XN.js → chunk-4UOE5TUZ.js} +4 -4
  26. package/dist/{chunk-6SNHU3CY.js → chunk-66OJ3WB4.js} +2 -2
  27. package/dist/chunk-6KONMXQ6.js +297 -0
  28. package/dist/chunk-6KONMXQ6.js.map +1 -0
  29. package/dist/chunk-6PMVAAA7.js +196 -0
  30. package/dist/chunk-6PMVAAA7.js.map +1 -0
  31. package/dist/chunk-766ASQWE.js +32620 -0
  32. package/dist/chunk-766ASQWE.js.map +1 -0
  33. package/dist/chunk-7WQO5J2M.js +29 -0
  34. package/dist/chunk-7WQO5J2M.js.map +1 -0
  35. package/dist/chunk-APHSRMBS.js +148 -0
  36. package/dist/chunk-APHSRMBS.js.map +1 -0
  37. package/dist/{chunk-4LVWXUNC.js → chunk-AYUKPTSM.js} +57 -39
  38. package/dist/chunk-AYUKPTSM.js.map +1 -0
  39. package/dist/chunk-BIPYADGB.js +84 -0
  40. package/dist/chunk-BIPYADGB.js.map +1 -0
  41. package/dist/chunk-BRBWNV65.js +457 -0
  42. package/dist/chunk-BRBWNV65.js.map +1 -0
  43. package/dist/chunk-BXZ6EA52.js +382 -0
  44. package/dist/chunk-BXZ6EA52.js.map +1 -0
  45. package/dist/chunk-EVE7MIIY.js +290 -0
  46. package/dist/chunk-EVE7MIIY.js.map +1 -0
  47. package/dist/chunk-F3TTNID2.js +138 -0
  48. package/dist/chunk-F3TTNID2.js.map +1 -0
  49. package/dist/chunk-H5RQOFO2.js +190 -0
  50. package/dist/chunk-H5RQOFO2.js.map +1 -0
  51. package/dist/chunk-HN3F4WSW.js +145 -0
  52. package/dist/chunk-HN3F4WSW.js.map +1 -0
  53. package/dist/{chunk-6DRDKB45.js → chunk-I6BDYQIG.js} +20 -9
  54. package/dist/chunk-I6BDYQIG.js.map +1 -0
  55. package/dist/chunk-IZJMVV7O.js +347 -0
  56. package/dist/chunk-IZJMVV7O.js.map +1 -0
  57. package/dist/chunk-KM22GV7G.js +211 -0
  58. package/dist/chunk-KM22GV7G.js.map +1 -0
  59. package/dist/chunk-MGFBLVR7.js +103 -0
  60. package/dist/chunk-MGFBLVR7.js.map +1 -0
  61. package/dist/chunk-MQJ2ECQT.js +228 -0
  62. package/dist/chunk-MQJ2ECQT.js.map +1 -0
  63. package/dist/{chunk-F6QUZQGI.js → chunk-MXAPLSJ5.js} +2 -2
  64. package/dist/{chunk-GK3E2I7A.js → chunk-NHMBTUMW.js} +2 -2
  65. package/dist/chunk-NPRTSZIF.js +131 -0
  66. package/dist/chunk-NPRTSZIF.js.map +1 -0
  67. package/dist/chunk-O7IH7JTI.js +1898 -0
  68. package/dist/chunk-O7IH7JTI.js.map +1 -0
  69. package/dist/chunk-OCVQGBJK.js +293 -0
  70. package/dist/chunk-OCVQGBJK.js.map +1 -0
  71. package/dist/chunk-P6QINGFL.js +332 -0
  72. package/dist/chunk-P6QINGFL.js.map +1 -0
  73. package/dist/chunk-PHDZKPNE.js +91 -0
  74. package/dist/chunk-PHDZKPNE.js.map +1 -0
  75. package/dist/chunk-PLDDJCW6.js +49 -0
  76. package/dist/chunk-PTGTGXV2.js +164 -0
  77. package/dist/chunk-PTGTGXV2.js.map +1 -0
  78. package/dist/chunk-REMIY4U2.js +171 -0
  79. package/dist/chunk-REMIY4U2.js.map +1 -0
  80. package/dist/chunk-RZ4YESBG.js +141 -0
  81. package/dist/chunk-RZ4YESBG.js.map +1 -0
  82. package/dist/chunk-SAX5MHK4.js +111 -0
  83. package/dist/chunk-SAX5MHK4.js.map +1 -0
  84. package/dist/{chunk-GVJVEWHI.js → chunk-SJSUSJ47.js} +2 -2
  85. package/dist/chunk-SPPMCAKG.js +777 -0
  86. package/dist/chunk-SPPMCAKG.js.map +1 -0
  87. package/dist/chunk-SVAPX2XN.js +2441 -0
  88. package/dist/chunk-SVAPX2XN.js.map +1 -0
  89. package/dist/chunk-TVEWKIK3.js +452 -0
  90. package/dist/chunk-TVEWKIK3.js.map +1 -0
  91. package/dist/{chunk-HH2HBTQM.js → chunk-TYAGMJNV.js} +5 -5
  92. package/dist/{chunk-JXUP2X7V.js → chunk-VEHFVBLI.js} +2 -2
  93. package/dist/chunk-VNX5GMTN.js +128 -0
  94. package/dist/chunk-VNX5GMTN.js.map +1 -0
  95. package/dist/chunk-VRD5CYRL.js +1568 -0
  96. package/dist/chunk-VRD5CYRL.js.map +1 -0
  97. package/dist/chunk-WLUHNG6X.js +122 -0
  98. package/dist/chunk-WLUHNG6X.js.map +1 -0
  99. package/dist/chunk-WRAKK6K6.js +265 -0
  100. package/dist/chunk-WRAKK6K6.js.map +1 -0
  101. package/dist/chunk-XKYRH4FM.js +681 -0
  102. package/dist/chunk-XKYRH4FM.js.map +1 -0
  103. package/dist/{chunk-GUBEEYDW.js → chunk-XMCVRVTF.js} +2 -2
  104. package/dist/{chunk-GUBEEYDW.js.map → chunk-XMCVRVTF.js.map} +1 -1
  105. package/dist/chunk-ZLZKF2PM.js +310 -0
  106. package/dist/chunk-ZLZKF2PM.js.map +1 -0
  107. package/dist/cli.js +5 -1
  108. package/dist/cli.js.map +1 -1
  109. package/dist/client-ZQSFPMOB.js +21 -0
  110. package/dist/clipboard-manager-TEO2GEDN.js +24 -0
  111. package/dist/commands/setup.js +3 -3
  112. package/dist/commands/setup.js.map +1 -1
  113. package/dist/commands/start.js +3 -3
  114. package/dist/commands/status.js +2 -2
  115. package/dist/commands/stop.js +2 -2
  116. package/dist/commands/utils.js +2 -2
  117. package/dist/cron-explain-HHQKPD3M.js +16 -0
  118. package/dist/crypto-4AP47IKC.js +14 -0
  119. package/dist/crypto-4AP47IKC.js.map +1 -0
  120. package/dist/databases-37X4CI2Y.js +21 -0
  121. package/dist/databases-37X4CI2Y.js.map +1 -0
  122. package/dist/discord-B3HUPGQ6.js +70 -0
  123. package/dist/discord-B3HUPGQ6.js.map +1 -0
  124. package/dist/dist-UISMLMFN.js +21847 -0
  125. package/dist/dist-UISMLMFN.js.map +1 -0
  126. package/dist/email-K7LO2IPB.js +268 -0
  127. package/dist/email-K7LO2IPB.js.map +1 -0
  128. package/dist/enhanced-retrieval-DNLLEM4Z.js +753 -0
  129. package/dist/enhanced-retrieval-DNLLEM4Z.js.map +1 -0
  130. package/dist/enrichment-pipeline-MNHNW65K.js +13 -0
  131. package/dist/enrichment-pipeline-MNHNW65K.js.map +1 -0
  132. package/dist/entity-resolution-Y3IUWEAT.js +24 -0
  133. package/dist/entity-resolution-Y3IUWEAT.js.map +1 -0
  134. package/dist/env-IWXUVTCB.js +12 -0
  135. package/dist/env-IWXUVTCB.js.map +1 -0
  136. package/dist/google-workspace-DKWUVNGC.js +169 -0
  137. package/dist/google-workspace-DKWUVNGC.js.map +1 -0
  138. package/dist/hash-tool-ULQYD7B5.js +22 -0
  139. package/dist/hash-tool-ULQYD7B5.js.map +1 -0
  140. package/dist/heartbeat-monitor-GCISLXI3.js +22 -0
  141. package/dist/heartbeat-monitor-GCISLXI3.js.map +1 -0
  142. package/dist/image-generation-OSU7FP6F.js +486 -0
  143. package/dist/image-generation-OSU7FP6F.js.map +1 -0
  144. package/dist/imessage-NGA2XF2V.js +35 -0
  145. package/dist/imessage-NGA2XF2V.js.map +1 -0
  146. package/dist/inbox-summarizer-NRI4S7IF.js +47 -0
  147. package/dist/inbox-summarizer-NRI4S7IF.js.map +1 -0
  148. package/dist/incident-response-C5J7Q6DT.js +244 -0
  149. package/dist/incident-response-C5J7Q6DT.js.map +1 -0
  150. package/dist/inventory-manager-352OHXWD.js +24 -0
  151. package/dist/inventory-manager-352OHXWD.js.map +1 -0
  152. package/dist/jira-GSGDBMIG.js +199 -0
  153. package/dist/jira-GSGDBMIG.js.map +1 -0
  154. package/dist/json-tool-QE2SYHEG.js +26 -0
  155. package/dist/json-tool-QE2SYHEG.js.map +1 -0
  156. package/dist/key-rotation-DPHU4ZTB.js +18 -0
  157. package/dist/key-rotation-DPHU4ZTB.js.map +1 -0
  158. package/dist/lib.d.ts +603 -11
  159. package/dist/lib.js +161 -35
  160. package/dist/lib.js.map +1 -1
  161. package/dist/mailchimp-KKNF6QJ7.js +152 -0
  162. package/dist/mailchimp-KKNF6QJ7.js.map +1 -0
  163. package/dist/matrix-QVHG76I7.js +279 -0
  164. package/dist/matrix-QVHG76I7.js.map +1 -0
  165. package/dist/{mcp-LS7Q3Z5W.js → mcp-3JI6W7ZE.js} +3 -3
  166. package/dist/mcp-3JI6W7ZE.js.map +1 -0
  167. package/dist/microsoft365-UCBKJHNX.js +164 -0
  168. package/dist/microsoft365-UCBKJHNX.js.map +1 -0
  169. package/dist/ocr-AC7NPX33.js +22 -0
  170. package/dist/ocr-AC7NPX33.js.map +1 -0
  171. package/dist/ollama-BOAMSPLJ.js +8 -0
  172. package/dist/ollama-BOAMSPLJ.js.map +1 -0
  173. package/dist/pages-MI523RB7.js +26 -0
  174. package/dist/pages-MI523RB7.js.map +1 -0
  175. package/dist/pair-JDFTERIK.js +24 -0
  176. package/dist/pair-JDFTERIK.js.map +1 -0
  177. package/dist/pairing-IFQYCPNS.js +10 -0
  178. package/dist/pairing-IFQYCPNS.js.map +1 -0
  179. package/dist/pdf-ALQVOEJR.js +17 -0
  180. package/dist/pdf-ALQVOEJR.js.map +1 -0
  181. package/dist/presentations-DSV5IHG5.js +1002 -0
  182. package/dist/presentations-DSV5IHG5.js.map +1 -0
  183. package/dist/prometheus-JNT2BD4L.js +10 -0
  184. package/dist/prometheus-JNT2BD4L.js.map +1 -0
  185. package/dist/providers-J4LYPHDR.js +19 -0
  186. package/dist/providers-J4LYPHDR.js.map +1 -0
  187. package/dist/qr-code-WIX4PB4U.js +16 -0
  188. package/dist/qr-code-WIX4PB4U.js.map +1 -0
  189. package/dist/quickbooks-XB4NII2S.js +190 -0
  190. package/dist/quickbooks-XB4NII2S.js.map +1 -0
  191. package/dist/regex-tool-W4ABRKGK.js +24 -0
  192. package/dist/regex-tool-W4ABRKGK.js.map +1 -0
  193. package/dist/scheduler-VK4WFERV.js +63 -0
  194. package/dist/scheduler-VK4WFERV.js.map +1 -0
  195. package/dist/search-BCLBO5E3.js +25 -0
  196. package/dist/search-BCLBO5E3.js.map +1 -0
  197. package/dist/sendgrid-RNXCAFKM.js +152 -0
  198. package/dist/sendgrid-RNXCAFKM.js.map +1 -0
  199. package/dist/shopify-NCXYJB4R.js +171 -0
  200. package/dist/shopify-NCXYJB4R.js.map +1 -0
  201. package/dist/signal-6CGDFYL2.js +35 -0
  202. package/dist/signal-6CGDFYL2.js.map +1 -0
  203. package/dist/slack-IZQWIKOH.js +75 -0
  204. package/dist/slack-IZQWIKOH.js.map +1 -0
  205. package/dist/sms-M3JIOTCW.js +23 -0
  206. package/dist/sms-M3JIOTCW.js.map +1 -0
  207. package/dist/{src-K7GASHRH.js → src-VYUE6LRA.js} +138 -32
  208. package/dist/src-VYUE6LRA.js.map +1 -0
  209. package/dist/stocks-XXWBPOCU.js +14 -0
  210. package/dist/stocks-XXWBPOCU.js.map +1 -0
  211. package/dist/text-transform-6SGUA5Z4.js +22 -0
  212. package/dist/text-transform-6SGUA5Z4.js.map +1 -0
  213. package/dist/tools-2RLEI2N6.js +38 -0
  214. package/dist/tools-2RLEI2N6.js.map +1 -0
  215. package/dist/tunnel-IWMXUML4.js +301 -0
  216. package/dist/tunnel-IWMXUML4.js.map +1 -0
  217. package/dist/twilio-53GEW5JT.js +139 -0
  218. package/dist/twilio-53GEW5JT.js.map +1 -0
  219. package/dist/unit-converter-ZYXMEZOE.js +14 -0
  220. package/dist/unit-converter-ZYXMEZOE.js.map +1 -0
  221. package/dist/whatsapp-LFX6YKCM.js +35 -0
  222. package/dist/whatsapp-LFX6YKCM.js.map +1 -0
  223. package/dist/word-document-7B6SJMAY.js +902 -0
  224. package/dist/word-document-7B6SJMAY.js.map +1 -0
  225. package/dist/xero-QYO66D45.js +162 -0
  226. package/dist/xero-QYO66D45.js.map +1 -0
  227. package/dist/zapier-webhook-TBZ5YF2A.js +106 -0
  228. package/dist/zapier-webhook-TBZ5YF2A.js.map +1 -0
  229. package/drizzle/0002_mushy_master_mold.sql +140 -0
  230. package/drizzle/meta/0002_snapshot.json +3637 -0
  231. package/drizzle/meta/_journal.json +7 -0
  232. package/package.json +100 -98
  233. package/dist/bot-KJ26BG56.js +0 -15
  234. package/dist/chunk-4LVWXUNC.js.map +0 -1
  235. package/dist/chunk-4TG2IG5K.js +0 -5249
  236. package/dist/chunk-4TG2IG5K.js.map +0 -1
  237. package/dist/chunk-6DRDKB45.js.map +0 -1
  238. package/dist/chunk-CI6Q63MM.js +0 -1613
  239. package/dist/chunk-CI6Q63MM.js.map +0 -1
  240. package/dist/chunk-KHNYJY2Z.js +0 -178
  241. package/dist/chunk-KHNYJY2Z.js.map +0 -1
  242. package/dist/chunk-NSBPE2FW.js +0 -17
  243. package/dist/discord-ZOJFTVTB.js +0 -49
  244. package/dist/imessage-JFRB6EJ7.js +0 -14
  245. package/dist/scheduler-EZ7CZMCS.js +0 -42
  246. package/dist/signal-T3MCSULM.js +0 -14
  247. package/dist/slack-N2M4FHAJ.js +0 -54
  248. package/dist/src-K7GASHRH.js.map +0 -1
  249. package/dist/tools-24GZHYRF.js +0 -16
  250. package/dist/whatsapp-VCRUPAO5.js +0 -14
  251. /package/dist/{bot-KJ26BG56.js.map → audit-logger-OBPR7CRO.js.map} +0 -0
  252. /package/dist/{chunk-NSBPE2FW.js.map → auth-UOX5K2BE.js.map} +0 -0
  253. /package/dist/{discord-ZOJFTVTB.js.map → backup-restore-PZ7CYYB7.js.map} +0 -0
  254. /package/dist/{imessage-JFRB6EJ7.js.map → blocks-R3PODY47.js.map} +0 -0
  255. /package/dist/{mcp-LS7Q3Z5W.js.map → bot-QRARP4UN.js.map} +0 -0
  256. /package/dist/{scheduler-EZ7CZMCS.js.map → brain-7XLLM3KC.js.map} +0 -0
  257. /package/dist/{charts-MMXM6BWW.js.map → charts-V7ARZNKF.js.map} +0 -0
  258. /package/dist/{chunk-L3PDU3XN.js.map → chunk-4UOE5TUZ.js.map} +0 -0
  259. /package/dist/{chunk-6SNHU3CY.js.map → chunk-66OJ3WB4.js.map} +0 -0
  260. /package/dist/{chunk-F6QUZQGI.js.map → chunk-MXAPLSJ5.js.map} +0 -0
  261. /package/dist/{chunk-GK3E2I7A.js.map → chunk-NHMBTUMW.js.map} +0 -0
  262. /package/dist/{signal-T3MCSULM.js.map → chunk-PLDDJCW6.js.map} +0 -0
  263. /package/dist/{chunk-GVJVEWHI.js.map → chunk-SJSUSJ47.js.map} +0 -0
  264. /package/dist/{chunk-HH2HBTQM.js.map → chunk-TYAGMJNV.js.map} +0 -0
  265. /package/dist/{chunk-JXUP2X7V.js.map → chunk-VEHFVBLI.js.map} +0 -0
  266. /package/dist/{slack-N2M4FHAJ.js.map → client-ZQSFPMOB.js.map} +0 -0
  267. /package/dist/{tools-24GZHYRF.js.map → clipboard-manager-TEO2GEDN.js.map} +0 -0
  268. /package/dist/{whatsapp-VCRUPAO5.js.map → cron-explain-HHQKPD3M.js.map} +0 -0
@@ -0,0 +1,122 @@
1
+ // src/tools/regex-tool.ts
2
+ function testRegex(pattern, text, flags = "g") {
3
+ const regex = new RegExp(pattern, flags);
4
+ const matches = [];
5
+ let match;
6
+ while ((match = regex.exec(text)) !== null) {
7
+ matches.push({
8
+ match: match[0],
9
+ index: match.index,
10
+ groups: match.groups ? { ...match.groups } : void 0
11
+ });
12
+ if (!flags.includes("g")) break;
13
+ }
14
+ return { matches, count: matches.length };
15
+ }
16
+ function replaceWithRegex(pattern, text, replacement, flags = "g") {
17
+ const regex = new RegExp(pattern, flags);
18
+ let replacements = 0;
19
+ const result = text.replace(regex, (...args) => {
20
+ replacements++;
21
+ return replacement;
22
+ });
23
+ return { result, replacements };
24
+ }
25
+ function extractCaptures(pattern, text, flags = "g") {
26
+ const regex = new RegExp(pattern, flags);
27
+ const captures = [];
28
+ let match;
29
+ while ((match = regex.exec(text)) !== null) {
30
+ captures.push(match.slice(1));
31
+ if (!flags.includes("g")) break;
32
+ }
33
+ return captures;
34
+ }
35
+ function validateRegex(pattern) {
36
+ try {
37
+ new RegExp(pattern);
38
+ return { valid: true };
39
+ } catch (error) {
40
+ return { valid: false, error: error instanceof Error ? error.message : String(error) };
41
+ }
42
+ }
43
+ function explainRegex(pattern) {
44
+ const explanations = [];
45
+ const tokens = [
46
+ [/^\^/, "Start of string"],
47
+ [/\$$/, "End of string"],
48
+ [/\\d/g, "Any digit (0-9)"],
49
+ [/\\w/g, "Any word character (letter, digit, underscore)"],
50
+ [/\\s/g, "Any whitespace"],
51
+ [/\\D/g, "Any non-digit"],
52
+ [/\\W/g, "Any non-word character"],
53
+ [/\\S/g, "Any non-whitespace"],
54
+ [/\./g, "Any character"],
55
+ [/\+/g, "One or more of the preceding"],
56
+ [/\*/g, "Zero or more of the preceding"],
57
+ [/\?/g, "Zero or one of the preceding (optional)"],
58
+ [/\{(\d+)\}/g, "Exactly $1 of the preceding"],
59
+ [/\{(\d+),\}/g, "$1 or more of the preceding"],
60
+ [/\{(\d+),(\d+)\}/g, "Between $1 and $2 of the preceding"],
61
+ [/\[([^\]]+)\]/g, "One of: $1"],
62
+ [/\[^([^\]]+)\]/g, "Not one of: $1"],
63
+ [/\(([^)]+)\)/g, "Group: $1"],
64
+ [/\|/g, "OR"]
65
+ ];
66
+ for (const [regex, description] of tokens) {
67
+ if (regex.test(pattern)) {
68
+ explanations.push(description);
69
+ }
70
+ }
71
+ if (explanations.length === 0) {
72
+ return `Matches the literal string: "${pattern}"`;
73
+ }
74
+ return explanations.join("; ");
75
+ }
76
+ function escapeRegex(text) {
77
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
78
+ }
79
+ function splitWithRegex(pattern, text, flags = "") {
80
+ return text.split(new RegExp(pattern, flags));
81
+ }
82
+ async function regexTool(action, pattern, text, options) {
83
+ try {
84
+ const flags = options?.flags || "g";
85
+ switch (action) {
86
+ case "test":
87
+ return { success: true, result: testRegex(pattern, text, flags) };
88
+ case "replace": {
89
+ const replacement = options?.replacement || "";
90
+ return { success: true, result: replaceWithRegex(pattern, text, replacement, flags) };
91
+ }
92
+ case "extract":
93
+ return { success: true, result: extractCaptures(pattern, text, flags) };
94
+ case "validate":
95
+ return { success: true, result: validateRegex(pattern) };
96
+ case "explain":
97
+ return { success: true, result: explainRegex(pattern) };
98
+ case "escape":
99
+ return { success: true, result: escapeRegex(text) };
100
+ case "split":
101
+ return { success: true, result: splitWithRegex(pattern, text, flags) };
102
+ default:
103
+ return { success: false, error: `Unknown action: ${action}` };
104
+ }
105
+ } catch (error) {
106
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
107
+ }
108
+ }
109
+ var regex_tool_default = { regexTool, testRegex, replaceWithRegex, extractCaptures, validateRegex, explainRegex, escapeRegex, splitWithRegex };
110
+
111
+ export {
112
+ testRegex,
113
+ replaceWithRegex,
114
+ extractCaptures,
115
+ validateRegex,
116
+ explainRegex,
117
+ escapeRegex,
118
+ splitWithRegex,
119
+ regexTool,
120
+ regex_tool_default
121
+ };
122
+ //# sourceMappingURL=chunk-WLUHNG6X.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tools/regex-tool.ts"],"sourcesContent":["/**\r\n * Regex Tool\r\n * Build, test, explain, and apply regular expressions\r\n */\r\n\r\nexport interface RegexResult {\r\n success: boolean;\r\n result?: unknown;\r\n error?: string;\r\n}\r\n\r\n// Test a regex against text, return all matches\r\nexport function testRegex(\r\n pattern: string,\r\n text: string,\r\n flags: string = \"g\"\r\n): { matches: Array<{ match: string; index: number; groups?: Record<string, string> }>; count: number } {\r\n const regex = new RegExp(pattern, flags);\r\n const matches: Array<{ match: string; index: number; groups?: Record<string, string> }> = [];\r\n\r\n let match: RegExpExecArray | null;\r\n while ((match = regex.exec(text)) !== null) {\r\n matches.push({\r\n match: match[0],\r\n index: match.index,\r\n groups: match.groups ? { ...match.groups } : undefined,\r\n });\r\n if (!flags.includes(\"g\")) break;\r\n }\r\n\r\n return { matches, count: matches.length };\r\n}\r\n\r\n// Replace using regex\r\nexport function replaceWithRegex(\r\n pattern: string,\r\n text: string,\r\n replacement: string,\r\n flags: string = \"g\"\r\n): { result: string; replacements: number } {\r\n const regex = new RegExp(pattern, flags);\r\n let replacements = 0;\r\n\r\n const result = text.replace(regex, (...args) => {\r\n replacements++;\r\n return replacement;\r\n });\r\n\r\n return { result, replacements };\r\n}\r\n\r\n// Extract captures from regex\r\nexport function extractCaptures(\r\n pattern: string,\r\n text: string,\r\n flags: string = \"g\"\r\n): string[][] {\r\n const regex = new RegExp(pattern, flags);\r\n const captures: string[][] = [];\r\n\r\n let match: RegExpExecArray | null;\r\n while ((match = regex.exec(text)) !== null) {\r\n captures.push(match.slice(1));\r\n if (!flags.includes(\"g\")) break;\r\n }\r\n\r\n return captures;\r\n}\r\n\r\n// Validate a regex pattern\r\nexport function validateRegex(pattern: string): { valid: boolean; error?: string } {\r\n try {\r\n new RegExp(pattern);\r\n return { valid: true };\r\n } catch (error) {\r\n return { valid: false, error: error instanceof Error ? error.message : String(error) };\r\n }\r\n}\r\n\r\n// Explain regex pattern in natural language\r\nexport function explainRegex(pattern: string): string {\r\n const explanations: string[] = [];\r\n\r\n const tokens: Array<[RegExp, string]> = [\r\n [/^\\^/, \"Start of string\"],\r\n [/\\$$/, \"End of string\"],\r\n [/\\\\d/g, \"Any digit (0-9)\"],\r\n [/\\\\w/g, \"Any word character (letter, digit, underscore)\"],\r\n [/\\\\s/g, \"Any whitespace\"],\r\n [/\\\\D/g, \"Any non-digit\"],\r\n [/\\\\W/g, \"Any non-word character\"],\r\n [/\\\\S/g, \"Any non-whitespace\"],\r\n [/\\./g, \"Any character\"],\r\n [/\\+/g, \"One or more of the preceding\"],\r\n [/\\*/g, \"Zero or more of the preceding\"],\r\n [/\\?/g, \"Zero or one of the preceding (optional)\"],\r\n [/\\{(\\d+)\\}/g, \"Exactly $1 of the preceding\"],\r\n [/\\{(\\d+),\\}/g, \"$1 or more of the preceding\"],\r\n [/\\{(\\d+),(\\d+)\\}/g, \"Between $1 and $2 of the preceding\"],\r\n [/\\[([^\\]]+)\\]/g, \"One of: $1\"],\r\n [/\\[^([^\\]]+)\\]/g, \"Not one of: $1\"],\r\n [/\\(([^)]+)\\)/g, \"Group: $1\"],\r\n [/\\|/g, \"OR\"],\r\n ];\r\n\r\n for (const [regex, description] of tokens) {\r\n if (regex.test(pattern)) {\r\n explanations.push(description);\r\n }\r\n }\r\n\r\n if (explanations.length === 0) {\r\n return `Matches the literal string: \"${pattern}\"`;\r\n }\r\n\r\n return explanations.join(\"; \");\r\n}\r\n\r\n// Escape a string for use in regex\r\nexport function escapeRegex(text: string): string {\r\n return text.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\r\n}\r\n\r\n// Split text using regex\r\nexport function splitWithRegex(pattern: string, text: string, flags: string = \"\"): string[] {\r\n return text.split(new RegExp(pattern, flags));\r\n}\r\n\r\n// Main entry point\r\nexport async function regexTool(\r\n action: string,\r\n pattern: string,\r\n text: string,\r\n options?: Record<string, unknown>\r\n): Promise<RegexResult> {\r\n try {\r\n const flags = (options?.flags as string) || \"g\";\r\n\r\n switch (action) {\r\n case \"test\":\r\n return { success: true, result: testRegex(pattern, text, flags) };\r\n case \"replace\": {\r\n const replacement = (options?.replacement as string) || \"\";\r\n return { success: true, result: replaceWithRegex(pattern, text, replacement, flags) };\r\n }\r\n case \"extract\":\r\n return { success: true, result: extractCaptures(pattern, text, flags) };\r\n case \"validate\":\r\n return { success: true, result: validateRegex(pattern) };\r\n case \"explain\":\r\n return { success: true, result: explainRegex(pattern) };\r\n case \"escape\":\r\n return { success: true, result: escapeRegex(text) };\r\n case \"split\":\r\n return { success: true, result: splitWithRegex(pattern, text, flags) };\r\n default:\r\n return { success: false, error: `Unknown action: ${action}` };\r\n }\r\n } catch (error) {\r\n return { success: false, error: error instanceof Error ? error.message : String(error) };\r\n }\r\n}\r\n\r\nexport default { regexTool, testRegex, replaceWithRegex, extractCaptures, validateRegex, explainRegex, escapeRegex, splitWithRegex };\r\n"],"mappings":"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","names":[]}
@@ -0,0 +1,265 @@
1
+ import {
2
+ db,
3
+ graphEntities,
4
+ graphRelationships
5
+ } from "./chunk-XKYRH4FM.js";
6
+
7
+ // src/core/intelligence/entity-resolution.ts
8
+ import { eq, ilike, sql } from "drizzle-orm";
9
+ function normalizeEntityName(name) {
10
+ return name.toLowerCase().replace(/[.,;:'"!?()\[\]{}]/g, "").replace(/\b(inc|llc|corp|ltd|co|foundation|fund|assoc|association|committee|pac)\b\.?/gi, "").replace(/\s+/g, " ").trim();
11
+ }
12
+ function fuzzyMatch(a, b) {
13
+ const s1 = normalizeEntityName(a);
14
+ const s2 = normalizeEntityName(b);
15
+ if (s1 === s2) return 1;
16
+ if (s1.length === 0 || s2.length === 0) return 0;
17
+ const matchWindow = Math.max(Math.floor(Math.max(s1.length, s2.length) / 2) - 1, 0);
18
+ const s1Matches = new Array(s1.length).fill(false);
19
+ const s2Matches = new Array(s2.length).fill(false);
20
+ let matches = 0;
21
+ let transpositions = 0;
22
+ for (let i = 0; i < s1.length; i++) {
23
+ const start = Math.max(0, i - matchWindow);
24
+ const end = Math.min(i + matchWindow + 1, s2.length);
25
+ for (let j = start; j < end; j++) {
26
+ if (s2Matches[j] || s1[i] !== s2[j]) continue;
27
+ s1Matches[i] = true;
28
+ s2Matches[j] = true;
29
+ matches++;
30
+ break;
31
+ }
32
+ }
33
+ if (matches === 0) return 0;
34
+ let k = 0;
35
+ for (let i = 0; i < s1.length; i++) {
36
+ if (!s1Matches[i]) continue;
37
+ while (!s2Matches[k]) k++;
38
+ if (s1[i] !== s2[k]) transpositions++;
39
+ k++;
40
+ }
41
+ const jaro = (matches / s1.length + matches / s2.length + (matches - transpositions / 2) / matches) / 3;
42
+ let prefix = 0;
43
+ for (let i = 0; i < Math.min(4, Math.min(s1.length, s2.length)); i++) {
44
+ if (s1[i] === s2[i]) prefix++;
45
+ else break;
46
+ }
47
+ return jaro + prefix * 0.1 * (1 - jaro);
48
+ }
49
+ async function matchByEIN(ein) {
50
+ try {
51
+ const results = await db.select({ id: graphEntities.id }).from(graphEntities).where(sql`${graphEntities.attributes}->>'ein' = ${ein}`).limit(1);
52
+ return results.length > 0 ? results[0].id : null;
53
+ } catch (error) {
54
+ console.error("[EntityResolution] EIN match error:", error);
55
+ return null;
56
+ }
57
+ }
58
+ async function matchByCIK(cik) {
59
+ try {
60
+ const results = await db.select({ id: graphEntities.id }).from(graphEntities).where(sql`${graphEntities.attributes}->>'cik' = ${cik}`).limit(1);
61
+ return results.length > 0 ? results[0].id : null;
62
+ } catch (error) {
63
+ console.error("[EntityResolution] CIK match error:", error);
64
+ return null;
65
+ }
66
+ }
67
+ async function matchByFECId(fecId) {
68
+ try {
69
+ const results = await db.select({ id: graphEntities.id }).from(graphEntities).where(sql`${graphEntities.attributes}->>'fecId' = ${fecId}`).limit(1);
70
+ return results.length > 0 ? results[0].id : null;
71
+ } catch (error) {
72
+ console.error("[EntityResolution] FEC ID match error:", error);
73
+ return null;
74
+ }
75
+ }
76
+ async function resolveEntity(candidate) {
77
+ try {
78
+ const exactMatches = await db.select({ id: graphEntities.id }).from(graphEntities).where(ilike(graphEntities.name, candidate.name)).limit(1);
79
+ if (exactMatches.length > 0) {
80
+ await mergeAttributes(exactMatches[0].id, candidate);
81
+ return {
82
+ isNew: false,
83
+ entityId: exactMatches[0].id,
84
+ confidence: 1,
85
+ matchedBy: "exact"
86
+ };
87
+ }
88
+ if (candidate.identifiers) {
89
+ if (candidate.identifiers.ein) {
90
+ const id = await matchByEIN(candidate.identifiers.ein);
91
+ if (id) {
92
+ await mergeAttributes(id, candidate);
93
+ return { isNew: false, entityId: id, confidence: 0.99, matchedBy: "identifier" };
94
+ }
95
+ }
96
+ if (candidate.identifiers.cik) {
97
+ const id = await matchByCIK(candidate.identifiers.cik);
98
+ if (id) {
99
+ await mergeAttributes(id, candidate);
100
+ return { isNew: false, entityId: id, confidence: 0.99, matchedBy: "identifier" };
101
+ }
102
+ }
103
+ if (candidate.identifiers.fecId) {
104
+ const id = await matchByFECId(candidate.identifiers.fecId);
105
+ if (id) {
106
+ await mergeAttributes(id, candidate);
107
+ return { isNew: false, entityId: id, confidence: 0.99, matchedBy: "identifier" };
108
+ }
109
+ }
110
+ }
111
+ const typeFilter = ["person", "organization", "committee"].includes(candidate.type) ? candidate.type : void 0;
112
+ const potentialMatches = await db.select({ id: graphEntities.id, name: graphEntities.name, aliases: graphEntities.aliases }).from(graphEntities).where(typeFilter ? eq(graphEntities.type, typeFilter) : sql`true`).limit(500);
113
+ let bestMatch = null;
114
+ for (const entity of potentialMatches) {
115
+ const nameScore = fuzzyMatch(candidate.name, entity.name);
116
+ if (nameScore > (bestMatch?.score ?? 0.85)) {
117
+ bestMatch = { id: entity.id, score: nameScore };
118
+ }
119
+ const aliases = entity.aliases || [];
120
+ for (const alias of aliases) {
121
+ const aliasScore = fuzzyMatch(candidate.name, alias);
122
+ if (aliasScore > (bestMatch?.score ?? 0.85)) {
123
+ bestMatch = { id: entity.id, score: aliasScore };
124
+ }
125
+ }
126
+ }
127
+ if (bestMatch) {
128
+ await mergeAttributes(bestMatch.id, candidate);
129
+ return {
130
+ isNew: false,
131
+ entityId: bestMatch.id,
132
+ confidence: bestMatch.score,
133
+ matchedBy: "fuzzy"
134
+ };
135
+ }
136
+ const newEntity = await db.insert(graphEntities).values({
137
+ type: mapOSINTTypeToGraphType(candidate.type),
138
+ name: candidate.name,
139
+ aliases: candidate.aliases || [],
140
+ description: `Discovered from ${candidate.source}`,
141
+ attributes: {
142
+ ...candidate.attributes,
143
+ ...candidate.identifiers,
144
+ sources: [candidate.source],
145
+ discoveredAt: (/* @__PURE__ */ new Date()).toISOString()
146
+ },
147
+ importance: 5,
148
+ mentionCount: 1
149
+ }).returning({ id: graphEntities.id });
150
+ console.log(`[EntityResolution] Created new entity: ${candidate.name} (${candidate.type}) from ${candidate.source}`);
151
+ return {
152
+ isNew: true,
153
+ entityId: newEntity[0].id,
154
+ confidence: 1,
155
+ matchedBy: "new"
156
+ };
157
+ } catch (error) {
158
+ console.error("[EntityResolution] Error resolving entity:", error);
159
+ throw error;
160
+ }
161
+ }
162
+ async function mergeAttributes(entityId, candidate) {
163
+ try {
164
+ const existing = await db.select({ attributes: graphEntities.attributes, aliases: graphEntities.aliases, mentionCount: graphEntities.mentionCount }).from(graphEntities).where(eq(graphEntities.id, entityId)).limit(1);
165
+ if (existing.length === 0) return;
166
+ const currentAttrs = existing[0].attributes || {};
167
+ const currentAliases = existing[0].aliases || [];
168
+ const currentSources = currentAttrs.sources || [];
169
+ const mergedAttrs = {
170
+ ...currentAttrs,
171
+ ...candidate.attributes,
172
+ ...candidate.identifiers,
173
+ sources: [.../* @__PURE__ */ new Set([...currentSources, candidate.source])],
174
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
175
+ };
176
+ const newAliases = candidate.aliases || [];
177
+ const mergedAliases = [.../* @__PURE__ */ new Set([...currentAliases, ...newAliases])];
178
+ await db.update(graphEntities).set({
179
+ attributes: mergedAttrs,
180
+ aliases: mergedAliases,
181
+ mentionCount: (existing[0].mentionCount || 0) + 1
182
+ }).where(eq(graphEntities.id, entityId));
183
+ } catch (error) {
184
+ console.error("[EntityResolution] Error merging attributes:", error);
185
+ }
186
+ }
187
+ function mapOSINTTypeToGraphType(type) {
188
+ switch (type) {
189
+ case "person":
190
+ return "person";
191
+ case "organization":
192
+ return "organization";
193
+ case "committee":
194
+ return "organization";
195
+ case "contract":
196
+ return "event";
197
+ case "filing":
198
+ return "event";
199
+ case "location":
200
+ return "location";
201
+ case "topic":
202
+ return "topic";
203
+ default:
204
+ return "organization";
205
+ }
206
+ }
207
+ async function mergeEntities(primaryId, duplicateId) {
208
+ try {
209
+ const [primary, duplicate] = await Promise.all([
210
+ db.select().from(graphEntities).where(eq(graphEntities.id, primaryId)).limit(1),
211
+ db.select().from(graphEntities).where(eq(graphEntities.id, duplicateId)).limit(1)
212
+ ]);
213
+ if (primary.length === 0 || duplicate.length === 0) return;
214
+ const aliases = [.../* @__PURE__ */ new Set([
215
+ ...primary[0].aliases || [],
216
+ duplicate[0].name,
217
+ ...duplicate[0].aliases || []
218
+ ])];
219
+ const mergedAttrs = {
220
+ ...duplicate[0].attributes || {},
221
+ ...primary[0].attributes || {}
222
+ };
223
+ await db.update(graphEntities).set({ aliases, attributes: mergedAttrs }).where(eq(graphEntities.id, primaryId));
224
+ await db.update(graphRelationships).set({ sourceEntityId: primaryId }).where(eq(graphRelationships.sourceEntityId, duplicateId));
225
+ await db.update(graphRelationships).set({ targetEntityId: primaryId }).where(eq(graphRelationships.targetEntityId, duplicateId));
226
+ await db.delete(graphEntities).where(eq(graphEntities.id, duplicateId));
227
+ console.log(`[EntityResolution] Merged entity ${duplicate[0].name} into ${primary[0].name}`);
228
+ } catch (error) {
229
+ console.error("[EntityResolution] Error merging entities:", error);
230
+ }
231
+ }
232
+ async function findDuplicates(threshold = 0.85) {
233
+ try {
234
+ const allEntities = await db.select({ id: graphEntities.id, name: graphEntities.name }).from(graphEntities).limit(1e3);
235
+ const duplicates = [];
236
+ for (let i = 0; i < allEntities.length; i++) {
237
+ for (let j = i + 1; j < allEntities.length; j++) {
238
+ const score = fuzzyMatch(allEntities[i].name, allEntities[j].name);
239
+ if (score >= threshold && score < 1) {
240
+ duplicates.push({
241
+ entities: [allEntities[i].id, allEntities[j].id],
242
+ names: [allEntities[i].name, allEntities[j].name],
243
+ score
244
+ });
245
+ }
246
+ }
247
+ }
248
+ return duplicates.sort((a, b) => b.score - a.score);
249
+ } catch (error) {
250
+ console.error("[EntityResolution] Error finding duplicates:", error);
251
+ return [];
252
+ }
253
+ }
254
+
255
+ export {
256
+ normalizeEntityName,
257
+ fuzzyMatch,
258
+ matchByEIN,
259
+ matchByCIK,
260
+ matchByFECId,
261
+ resolveEntity,
262
+ mergeEntities,
263
+ findDuplicates
264
+ };
265
+ //# sourceMappingURL=chunk-WRAKK6K6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/intelligence/entity-resolution.ts"],"sourcesContent":["/**\n * Entity Resolution Pipeline\n *\n * Resolves, deduplicates, and matches entities across multiple public records\n * databases (FEC, IRS 990, USAspending, SEC EDGAR, OpenCorporates).\n *\n * Flow: exact match → identifier match (EIN/CIK/FEC) → fuzzy match → create new\n */\n\nimport { db } from \"../../db\";\nimport { graphEntities, graphRelationships } from \"../../db/schema\";\nimport { eq, ilike, sql } from \"drizzle-orm\";\n\n// Extended entity type for OSINT sources\nexport type OSINTEntityType =\n | \"person\"\n | \"organization\"\n | \"committee\"\n | \"contract\"\n | \"filing\"\n | \"location\"\n | \"topic\";\n\nexport interface EntityCandidate {\n name: string;\n type: OSINTEntityType;\n source: string; // \"fec\" | \"irs990\" | \"usaspending\" | \"sec\" | \"opencorporates\" | \"manual\"\n identifiers?: {\n ein?: string;\n cik?: string;\n fecId?: string;\n duns?: string;\n uei?: string;\n };\n attributes?: Record<string, unknown>;\n aliases?: string[];\n}\n\nexport interface ResolvedEntity {\n isNew: boolean;\n entityId: string; // postgres graphEntities.id\n confidence: number; // 0-1\n matchedBy: \"exact\" | \"fuzzy\" | \"identifier\" | \"new\";\n}\n\n/**\n * Normalize an entity name for comparison.\n * Strips punctuation, extra whitespace, common suffixes.\n */\nexport function normalizeEntityName(name: string): string {\n return name\n .toLowerCase()\n .replace(/[.,;:'\"!?()\\[\\]{}]/g, \"\")\n .replace(/\\b(inc|llc|corp|ltd|co|foundation|fund|assoc|association|committee|pac)\\b\\.?/gi, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/**\n * Jaro-Winkler similarity between two strings (0-1).\n */\nexport function fuzzyMatch(a: string, b: string): number {\n const s1 = normalizeEntityName(a);\n const s2 = normalizeEntityName(b);\n\n if (s1 === s2) return 1.0;\n if (s1.length === 0 || s2.length === 0) return 0.0;\n\n const matchWindow = Math.max(Math.floor(Math.max(s1.length, s2.length) / 2) - 1, 0);\n const s1Matches = new Array(s1.length).fill(false);\n const s2Matches = new Array(s2.length).fill(false);\n\n let matches = 0;\n let transpositions = 0;\n\n for (let i = 0; i < s1.length; i++) {\n const start = Math.max(0, i - matchWindow);\n const end = Math.min(i + matchWindow + 1, s2.length);\n for (let j = start; j < end; j++) {\n if (s2Matches[j] || s1[i] !== s2[j]) continue;\n s1Matches[i] = true;\n s2Matches[j] = true;\n matches++;\n break;\n }\n }\n\n if (matches === 0) return 0.0;\n\n let k = 0;\n for (let i = 0; i < s1.length; i++) {\n if (!s1Matches[i]) continue;\n while (!s2Matches[k]) k++;\n if (s1[i] !== s2[k]) transpositions++;\n k++;\n }\n\n const jaro =\n (matches / s1.length + matches / s2.length + (matches - transpositions / 2) / matches) / 3;\n\n // Winkler bonus for common prefix (up to 4 chars)\n let prefix = 0;\n for (let i = 0; i < Math.min(4, Math.min(s1.length, s2.length)); i++) {\n if (s1[i] === s2[i]) prefix++;\n else break;\n }\n\n return jaro + prefix * 0.1 * (1 - jaro);\n}\n\n/**\n * Match entity by EIN (Employer Identification Number).\n */\nexport async function matchByEIN(ein: string): Promise<string | null> {\n try {\n const results = await db\n .select({ id: graphEntities.id })\n .from(graphEntities)\n .where(sql`${graphEntities.attributes}->>'ein' = ${ein}`)\n .limit(1);\n return results.length > 0 ? results[0].id : null;\n } catch (error) {\n console.error(\"[EntityResolution] EIN match error:\", error);\n return null;\n }\n}\n\n/**\n * Match entity by CIK (SEC Central Index Key).\n */\nexport async function matchByCIK(cik: string): Promise<string | null> {\n try {\n const results = await db\n .select({ id: graphEntities.id })\n .from(graphEntities)\n .where(sql`${graphEntities.attributes}->>'cik' = ${cik}`)\n .limit(1);\n return results.length > 0 ? results[0].id : null;\n } catch (error) {\n console.error(\"[EntityResolution] CIK match error:\", error);\n return null;\n }\n}\n\n/**\n * Match entity by FEC committee/candidate ID.\n */\nexport async function matchByFECId(fecId: string): Promise<string | null> {\n try {\n const results = await db\n .select({ id: graphEntities.id })\n .from(graphEntities)\n .where(sql`${graphEntities.attributes}->>'fecId' = ${fecId}`)\n .limit(1);\n return results.length > 0 ? results[0].id : null;\n } catch (error) {\n console.error(\"[EntityResolution] FEC ID match error:\", error);\n return null;\n }\n}\n\n/**\n * Core entity resolution function.\n * Resolves a candidate entity against the existing knowledge graph.\n *\n * Resolution order:\n * 1. Exact name match\n * 2. Identifier match (EIN, CIK, FEC ID)\n * 3. Fuzzy name match (Jaro-Winkler > 0.85)\n * 4. Create new entity\n */\nexport async function resolveEntity(candidate: EntityCandidate): Promise<ResolvedEntity> {\n try {\n // 1. Exact name match\n const exactMatches = await db\n .select({ id: graphEntities.id })\n .from(graphEntities)\n .where(ilike(graphEntities.name, candidate.name))\n .limit(1);\n\n if (exactMatches.length > 0) {\n // Update with new source attributes\n await mergeAttributes(exactMatches[0].id, candidate);\n return {\n isNew: false,\n entityId: exactMatches[0].id,\n confidence: 1.0,\n matchedBy: \"exact\",\n };\n }\n\n // 2. Identifier match\n if (candidate.identifiers) {\n if (candidate.identifiers.ein) {\n const id = await matchByEIN(candidate.identifiers.ein);\n if (id) {\n await mergeAttributes(id, candidate);\n return { isNew: false, entityId: id, confidence: 0.99, matchedBy: \"identifier\" };\n }\n }\n if (candidate.identifiers.cik) {\n const id = await matchByCIK(candidate.identifiers.cik);\n if (id) {\n await mergeAttributes(id, candidate);\n return { isNew: false, entityId: id, confidence: 0.99, matchedBy: \"identifier\" };\n }\n }\n if (candidate.identifiers.fecId) {\n const id = await matchByFECId(candidate.identifiers.fecId);\n if (id) {\n await mergeAttributes(id, candidate);\n return { isNew: false, entityId: id, confidence: 0.99, matchedBy: \"identifier\" };\n }\n }\n }\n\n // 3. Fuzzy name match against existing entities of the same type\n const typeFilter = [\"person\", \"organization\", \"committee\"].includes(candidate.type)\n ? candidate.type\n : undefined;\n\n const potentialMatches = await db\n .select({ id: graphEntities.id, name: graphEntities.name, aliases: graphEntities.aliases })\n .from(graphEntities)\n .where(typeFilter ? eq(graphEntities.type, typeFilter as any) : sql`true`)\n .limit(500);\n\n let bestMatch: { id: string; score: number } | null = null;\n\n for (const entity of potentialMatches) {\n // Check main name\n const nameScore = fuzzyMatch(candidate.name, entity.name);\n if (nameScore > (bestMatch?.score ?? 0.85)) {\n bestMatch = { id: entity.id, score: nameScore };\n }\n\n // Check aliases\n const aliases = (entity.aliases as string[]) || [];\n for (const alias of aliases) {\n const aliasScore = fuzzyMatch(candidate.name, alias);\n if (aliasScore > (bestMatch?.score ?? 0.85)) {\n bestMatch = { id: entity.id, score: aliasScore };\n }\n }\n }\n\n if (bestMatch) {\n await mergeAttributes(bestMatch.id, candidate);\n return {\n isNew: false,\n entityId: bestMatch.id,\n confidence: bestMatch.score,\n matchedBy: \"fuzzy\",\n };\n }\n\n // 4. Create new entity\n const newEntity = await db\n .insert(graphEntities)\n .values({\n type: mapOSINTTypeToGraphType(candidate.type) as any,\n name: candidate.name,\n aliases: candidate.aliases || [],\n description: `Discovered from ${candidate.source}`,\n attributes: {\n ...candidate.attributes,\n ...candidate.identifiers,\n sources: [candidate.source],\n discoveredAt: new Date().toISOString(),\n },\n importance: 5,\n mentionCount: 1,\n })\n .returning({ id: graphEntities.id });\n\n console.log(`[EntityResolution] Created new entity: ${candidate.name} (${candidate.type}) from ${candidate.source}`);\n\n return {\n isNew: true,\n entityId: newEntity[0].id,\n confidence: 1.0,\n matchedBy: \"new\",\n };\n } catch (error) {\n console.error(\"[EntityResolution] Error resolving entity:\", error);\n throw error;\n }\n}\n\n/**\n * Merge new attributes and aliases into an existing entity.\n */\nasync function mergeAttributes(entityId: string, candidate: EntityCandidate): Promise<void> {\n try {\n const existing = await db\n .select({ attributes: graphEntities.attributes, aliases: graphEntities.aliases, mentionCount: graphEntities.mentionCount })\n .from(graphEntities)\n .where(eq(graphEntities.id, entityId))\n .limit(1);\n\n if (existing.length === 0) return;\n\n const currentAttrs = (existing[0].attributes as Record<string, unknown>) || {};\n const currentAliases = (existing[0].aliases as string[]) || [];\n const currentSources = (currentAttrs.sources as string[]) || [];\n\n // Merge attributes\n const mergedAttrs = {\n ...currentAttrs,\n ...candidate.attributes,\n ...candidate.identifiers,\n sources: [...new Set([...currentSources, candidate.source])],\n lastUpdated: new Date().toISOString(),\n };\n\n // Merge aliases\n const newAliases = candidate.aliases || [];\n const mergedAliases = [...new Set([...currentAliases, ...newAliases])];\n\n await db\n .update(graphEntities)\n .set({\n attributes: mergedAttrs,\n aliases: mergedAliases,\n mentionCount: (existing[0].mentionCount || 0) + 1,\n })\n .where(eq(graphEntities.id, entityId));\n } catch (error) {\n console.error(\"[EntityResolution] Error merging attributes:\", error);\n }\n}\n\n/**\n * Map OSINT entity types to the existing graph entity types.\n */\nfunction mapOSINTTypeToGraphType(type: OSINTEntityType): string {\n switch (type) {\n case \"person\": return \"person\";\n case \"organization\": return \"organization\";\n case \"committee\": return \"organization\";\n case \"contract\": return \"event\";\n case \"filing\": return \"event\";\n case \"location\": return \"location\";\n case \"topic\": return \"topic\";\n default: return \"organization\";\n }\n}\n\n/**\n * Merge two entities (mark duplicate as alias of primary).\n */\nexport async function mergeEntities(primaryId: string, duplicateId: string): Promise<void> {\n try {\n const [primary, duplicate] = await Promise.all([\n db.select().from(graphEntities).where(eq(graphEntities.id, primaryId)).limit(1),\n db.select().from(graphEntities).where(eq(graphEntities.id, duplicateId)).limit(1),\n ]);\n\n if (primary.length === 0 || duplicate.length === 0) return;\n\n // Add duplicate name as alias\n const aliases = [...new Set([\n ...((primary[0].aliases as string[]) || []),\n duplicate[0].name,\n ...((duplicate[0].aliases as string[]) || []),\n ])];\n\n // Merge attributes\n const mergedAttrs = {\n ...((duplicate[0].attributes as Record<string, unknown>) || {}),\n ...((primary[0].attributes as Record<string, unknown>) || {}),\n };\n\n await db\n .update(graphEntities)\n .set({ aliases, attributes: mergedAttrs })\n .where(eq(graphEntities.id, primaryId));\n\n // Reassign all relationships from duplicate to primary\n await db\n .update(graphRelationships)\n .set({ sourceEntityId: primaryId })\n .where(eq(graphRelationships.sourceEntityId, duplicateId));\n\n await db\n .update(graphRelationships)\n .set({ targetEntityId: primaryId })\n .where(eq(graphRelationships.targetEntityId, duplicateId));\n\n // Delete the duplicate\n await db.delete(graphEntities).where(eq(graphEntities.id, duplicateId));\n\n console.log(`[EntityResolution] Merged entity ${duplicate[0].name} into ${primary[0].name}`);\n } catch (error) {\n console.error(\"[EntityResolution] Error merging entities:\", error);\n }\n}\n\n/**\n * Find potential duplicate entities based on fuzzy matching.\n */\nexport async function findDuplicates(\n threshold: number = 0.85\n): Promise<Array<{ entities: [string, string]; names: [string, string]; score: number }>> {\n try {\n const allEntities = await db\n .select({ id: graphEntities.id, name: graphEntities.name })\n .from(graphEntities)\n .limit(1000);\n\n const duplicates: Array<{ entities: [string, string]; names: [string, string]; score: number }> = [];\n\n for (let i = 0; i < allEntities.length; i++) {\n for (let j = i + 1; j < allEntities.length; j++) {\n const score = fuzzyMatch(allEntities[i].name, allEntities[j].name);\n if (score >= threshold && score < 1.0) {\n duplicates.push({\n entities: [allEntities[i].id, allEntities[j].id],\n names: [allEntities[i].name, allEntities[j].name],\n score,\n });\n }\n }\n }\n\n return duplicates.sort((a, b) => b.score - a.score);\n } catch (error) {\n console.error(\"[EntityResolution] Error finding duplicates:\", error);\n return [];\n }\n}\n"],"mappings":"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","names":[]}