opensentinel 3.6.1 → 3.7.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 (197) hide show
  1. package/README.md +12 -0
  2. package/dist/{agent-manager-7N7REQZQ.js → agent-manager-JZ4IM7XI.js} +8 -8
  3. package/dist/{agent-processor-I23VWQY3.js → agent-processor-DDDHC2SO.js} +22 -21
  4. package/dist/{agent-processor-I23VWQY3.js.map → agent-processor-DDDHC2SO.js.map} +1 -1
  5. package/dist/{alerting-4I37GG4U.js → alerting-LK7VVYTX.js} +4 -4
  6. package/dist/alerting-LK7VVYTX.js.map +1 -0
  7. package/dist/analyzer-OTWE3ARE.js +22 -0
  8. package/dist/{archiver-XLRIIXPY.js → archiver-FPGKRP6P.js} +16 -85
  9. package/dist/archiver-FPGKRP6P.js.map +1 -0
  10. package/dist/{audit-logger-AU3TMWKI.js → audit-logger-CI4WZQPD.js} +5 -5
  11. package/dist/bot-VDHBGUVI.js +47 -0
  12. package/dist/{brain-SLA474EU.js → brain-6QTXN4QP.js} +18 -17
  13. package/dist/{chunk-AR34B6XR.js → chunk-2I5QHYG6.js} +3 -3
  14. package/dist/chunk-2I5QHYG6.js.map +1 -0
  15. package/dist/chunk-3AWAWRWB.js +143 -0
  16. package/dist/chunk-3AWAWRWB.js.map +1 -0
  17. package/dist/{chunk-PUNIMPMY.js → chunk-4KIHDIXZ.js} +13 -2
  18. package/dist/chunk-4KIHDIXZ.js.map +1 -0
  19. package/dist/{chunk-GUKKW7JI.js → chunk-4WH6MFEW.js} +2 -2
  20. package/dist/chunk-4WH6MFEW.js.map +1 -0
  21. package/dist/{chunk-M7YLQHFP.js → chunk-56UJS2LA.js} +6 -6
  22. package/dist/{chunk-S4NJJS5C.js → chunk-5BTVJR7R.js} +3 -3
  23. package/dist/{chunk-HKOPRRDJ.js → chunk-5JJTLWOR.js} +3 -3
  24. package/dist/chunk-5JJTLWOR.js.map +1 -0
  25. package/dist/chunk-66SAOZPU.js +236 -0
  26. package/dist/chunk-66SAOZPU.js.map +1 -0
  27. package/dist/chunk-6HGMRR4J.js +113 -0
  28. package/dist/chunk-6HGMRR4J.js.map +1 -0
  29. package/dist/{chunk-BMOUYXLX.js → chunk-6ZNCY2GI.js} +5 -5
  30. package/dist/chunk-7BNFELEK.js +31 -0
  31. package/dist/chunk-7BNFELEK.js.map +1 -0
  32. package/dist/{chunk-KABG5PG3.js → chunk-BBN4VCNK.js} +4 -4
  33. package/dist/chunk-BBN4VCNK.js.map +1 -0
  34. package/dist/{chunk-4YJRBMMA.js → chunk-BNZHWAZC.js} +2 -2
  35. package/dist/{chunk-TAAZB5KN.js → chunk-CWT6CAE5.js} +2 -2
  36. package/dist/{chunk-UWUIJTT4.js → chunk-CZTMGHUC.js} +1 -1
  37. package/dist/chunk-CZTMGHUC.js.map +1 -0
  38. package/dist/chunk-DTISLIMB.js +89 -0
  39. package/dist/chunk-DTISLIMB.js.map +1 -0
  40. package/dist/{chunk-VKMFUIVA.js → chunk-GBVJTRXS.js} +2 -2
  41. package/dist/{chunk-MFK34XSY.js → chunk-GJETKBOY.js} +15 -15
  42. package/dist/chunk-GJETKBOY.js.map +1 -0
  43. package/dist/{chunk-HTF2GIQC.js → chunk-GW6V4D43.js} +2 -2
  44. package/dist/chunk-GW6V4D43.js.map +1 -0
  45. package/dist/{chunk-2RGPWU77.js → chunk-HJSEEFO3.js} +2 -2
  46. package/dist/{chunk-JOA5A3G3.js → chunk-HQZQFEAX.js} +5 -5
  47. package/dist/{chunk-45YXODSB.js → chunk-J4JW73TT.js} +2 -2
  48. package/dist/{chunk-KT7NLIXP.js → chunk-JHYYFPKX.js} +2 -2
  49. package/dist/{chunk-XMCVRVTF.js → chunk-P64EV4YY.js} +1 -1
  50. package/dist/chunk-P64EV4YY.js.map +1 -0
  51. package/dist/chunk-PBOCSGNL.js +84 -0
  52. package/dist/chunk-PBOCSGNL.js.map +1 -0
  53. package/dist/{chunk-H3BOLSTS.js → chunk-PD3CTDO6.js} +2 -2
  54. package/dist/{chunk-6UZPE35A.js → chunk-QPY3WRVM.js} +10 -87
  55. package/dist/chunk-QPY3WRVM.js.map +1 -0
  56. package/dist/{chunk-AD6YEH6U.js → chunk-S2EOIVF4.js} +590 -91
  57. package/dist/chunk-S2EOIVF4.js.map +1 -0
  58. package/dist/chunk-SDLOMKCW.js +213 -0
  59. package/dist/chunk-SDLOMKCW.js.map +1 -0
  60. package/dist/{chunk-7MZN73J2.js → chunk-TKBVW7ZJ.js} +4 -4
  61. package/dist/{chunk-A24GPVLY.js → chunk-V3OKHQUX.js} +5 -5
  62. package/dist/{chunk-NMSHVO5O.js → chunk-WMDVOWN6.js} +4 -4
  63. package/dist/{chunk-643M3AP5.js → chunk-WMFYI7XC.js} +7 -7
  64. package/dist/{chunk-6LTLIYAQ.js → chunk-YEDEAX6Y.js} +3 -3
  65. package/dist/{chunk-NYVBXUGD.js → chunk-ZIBRVA3Y.js} +60 -1
  66. package/dist/chunk-ZIBRVA3Y.js.map +1 -0
  67. package/dist/{chunk-6JY4HNUH.js → chunk-ZMML6T63.js} +361 -24
  68. package/dist/chunk-ZMML6T63.js.map +1 -0
  69. package/dist/{chunk-FFV2SXFD.js → chunk-ZVHG4KF2.js} +4 -4
  70. package/dist/cli.js.map +1 -1
  71. package/dist/commands/setup.js +1 -1
  72. package/dist/commands/start.js +2 -2
  73. package/dist/commands/status.js +1 -1
  74. package/dist/commands/stop.js +1 -1
  75. package/dist/commands/utils.js +1 -1
  76. package/dist/{cost-tracker-EMOIOYH7.js → cost-tracker-KZQSTSE2.js} +2 -2
  77. package/dist/{db-LRIOKQBO.js → db-I7MNG6CL.js} +10 -4
  78. package/dist/{discord-NKR3X4AV.js → discord-6UQHCN27.js} +24 -23
  79. package/dist/{documents-EYIYLZK2.js → documents-PFHSK7SZ.js} +19 -19
  80. package/dist/{email-EAQNULVD.js → email-6OIN4SYL.js} +22 -21
  81. package/dist/email-6OIN4SYL.js.map +1 -0
  82. package/dist/{enhanced-retrieval-OGHT6TS5.js → enhanced-retrieval-JWX2HWU4.js} +7 -6
  83. package/dist/{enhanced-retrieval-OGHT6TS5.js.map → enhanced-retrieval-JWX2HWU4.js.map} +1 -1
  84. package/dist/enrichment-pipeline-7FE5R5ZI.js +14 -0
  85. package/dist/{entity-resolution-4X4JU43O.js → entity-resolution-7Z6STVXX.js} +5 -5
  86. package/dist/{env-CHOFICED.js → env-GN5VHI43.js} +2 -2
  87. package/dist/{error-tracker-SVQSDQDW.js → error-tracker-64DEH3D7.js} +6 -6
  88. package/dist/{github-KGNILDWJ.js → github-DUWSXCNP.js} +4 -4
  89. package/dist/graph-client-NB475AK5.js +17 -0
  90. package/dist/{imessage-V2XNDDHT.js → imessage-DSGSGUZS.js} +19 -18
  91. package/dist/{inbox-summarizer-DKKRYXDR.js → inbox-summarizer-F2KAU72V.js} +19 -18
  92. package/dist/{incident-response-ZTIKUWEO.js → incident-response-E3UGMX5G.js} +5 -5
  93. package/dist/incident-response-E3UGMX5G.js.map +1 -0
  94. package/dist/{knowledge-base-J7PJ7MZ3.js → knowledge-base-5SMMOGQJ.js} +5 -5
  95. package/dist/lib.d.ts +21 -0
  96. package/dist/lib.js +64 -57
  97. package/dist/lib.js.map +1 -1
  98. package/dist/{matrix-XHTR53VQ.js → matrix-WYGEOZL5.js} +18 -17
  99. package/dist/{matrix-XHTR53VQ.js.map → matrix-WYGEOZL5.js.map} +1 -1
  100. package/dist/{mcp-3C2TN67D.js → mcp-DJ2QDA6A.js} +2 -2
  101. package/dist/{metrics-VJDWQWU7.js → metrics-BH3ZLGEV.js} +5 -5
  102. package/dist/{multi-user-S56GUD6L.js → multi-user-XAEMB244.js} +4 -4
  103. package/dist/oauth-UPJYFOVU.js +34 -0
  104. package/dist/{ocr-LGUIPKVZ.js → ocr-UONKTQU7.js} +4 -4
  105. package/dist/{presentations-HXTAMGHT.js → presentations-UOET2FVZ.js} +2 -2
  106. package/dist/{providers-H6YIC3MG.js → providers-2YQ6E3IF.js} +3 -3
  107. package/dist/{scheduler-CA5UNHZV.js → scheduler-6PLLAQI7.js} +21 -20
  108. package/dist/{schema-ALJ67YVG.js → schema-ETY7L2VA.js} +8 -2
  109. package/dist/sharepoint-V5P4Q62L.js +30 -0
  110. package/dist/{signal-X7IQJGRQ.js → signal-7D5EPGVL.js} +19 -18
  111. package/dist/{slack-P2LFUJUQ.js → slack-KSS6YK5Z.js} +23 -22
  112. package/dist/slack-KSS6YK5Z.js.map +1 -0
  113. package/dist/{sms-4VME2HUL.js → sms-CSUCC7HL.js} +3 -3
  114. package/dist/sms-CSUCC7HL.js.map +1 -0
  115. package/dist/{src-S5KX4YEV.js → src-GO7GGW7O.js} +48 -41
  116. package/dist/{src-S5KX4YEV.js.map → src-GO7GGW7O.js.map} +1 -1
  117. package/dist/token-store-SEWRX6RE.js +20 -0
  118. package/dist/token-store-SEWRX6RE.js.map +1 -0
  119. package/dist/{tools-FGPN522P.js → tools-PJZ6RI4P.js} +18 -17
  120. package/dist/tools-PJZ6RI4P.js.map +1 -0
  121. package/dist/{whatsapp-KRPQ4YUX.js → whatsapp-DWXK25V2.js} +19 -18
  122. package/dist/whatsapp-DWXK25V2.js.map +1 -0
  123. package/dist/{word-document-D6N2C47N.js → word-document-AV3YB4L2.js} +2 -2
  124. package/dist/{workflow-store-ZYAYE5P6.js → workflow-store-5Y56GUP7.js} +4 -4
  125. package/drizzle/0002_mushy_master_mold.sql +139 -139
  126. package/drizzle/0003_overjoyed_rhodey.sql +46 -0
  127. package/drizzle/meta/0002_snapshot.json +3636 -3636
  128. package/drizzle/meta/0003_snapshot.json +3946 -0
  129. package/drizzle/meta/_journal.json +7 -0
  130. package/package.json +110 -110
  131. package/dist/alerting-4I37GG4U.js.map +0 -1
  132. package/dist/archiver-XLRIIXPY.js.map +0 -1
  133. package/dist/bot-MU2TJQ3Y.js +0 -46
  134. package/dist/chunk-6JY4HNUH.js.map +0 -1
  135. package/dist/chunk-6UZPE35A.js.map +0 -1
  136. package/dist/chunk-AD6YEH6U.js.map +0 -1
  137. package/dist/chunk-AR34B6XR.js.map +0 -1
  138. package/dist/chunk-GUKKW7JI.js.map +0 -1
  139. package/dist/chunk-HKOPRRDJ.js.map +0 -1
  140. package/dist/chunk-HTF2GIQC.js.map +0 -1
  141. package/dist/chunk-KABG5PG3.js.map +0 -1
  142. package/dist/chunk-MFK34XSY.js.map +0 -1
  143. package/dist/chunk-NYVBXUGD.js.map +0 -1
  144. package/dist/chunk-PUNIMPMY.js.map +0 -1
  145. package/dist/chunk-UWUIJTT4.js.map +0 -1
  146. package/dist/chunk-XMCVRVTF.js.map +0 -1
  147. package/dist/email-EAQNULVD.js.map +0 -1
  148. package/dist/enrichment-pipeline-CMUVBDC7.js +0 -14
  149. package/dist/incident-response-ZTIKUWEO.js.map +0 -1
  150. /package/dist/{agent-manager-7N7REQZQ.js.map → agent-manager-JZ4IM7XI.js.map} +0 -0
  151. /package/dist/{audit-logger-AU3TMWKI.js.map → analyzer-OTWE3ARE.js.map} +0 -0
  152. /package/dist/{bot-MU2TJQ3Y.js.map → audit-logger-CI4WZQPD.js.map} +0 -0
  153. /package/dist/{brain-SLA474EU.js.map → bot-VDHBGUVI.js.map} +0 -0
  154. /package/dist/{cost-tracker-EMOIOYH7.js.map → brain-6QTXN4QP.js.map} +0 -0
  155. /package/dist/{chunk-M7YLQHFP.js.map → chunk-56UJS2LA.js.map} +0 -0
  156. /package/dist/{chunk-S4NJJS5C.js.map → chunk-5BTVJR7R.js.map} +0 -0
  157. /package/dist/{chunk-BMOUYXLX.js.map → chunk-6ZNCY2GI.js.map} +0 -0
  158. /package/dist/{chunk-4YJRBMMA.js.map → chunk-BNZHWAZC.js.map} +0 -0
  159. /package/dist/{chunk-TAAZB5KN.js.map → chunk-CWT6CAE5.js.map} +0 -0
  160. /package/dist/{chunk-VKMFUIVA.js.map → chunk-GBVJTRXS.js.map} +0 -0
  161. /package/dist/{chunk-2RGPWU77.js.map → chunk-HJSEEFO3.js.map} +0 -0
  162. /package/dist/{chunk-JOA5A3G3.js.map → chunk-HQZQFEAX.js.map} +0 -0
  163. /package/dist/{chunk-45YXODSB.js.map → chunk-J4JW73TT.js.map} +0 -0
  164. /package/dist/{chunk-KT7NLIXP.js.map → chunk-JHYYFPKX.js.map} +0 -0
  165. /package/dist/{chunk-H3BOLSTS.js.map → chunk-PD3CTDO6.js.map} +0 -0
  166. /package/dist/{chunk-7MZN73J2.js.map → chunk-TKBVW7ZJ.js.map} +0 -0
  167. /package/dist/{chunk-A24GPVLY.js.map → chunk-V3OKHQUX.js.map} +0 -0
  168. /package/dist/{chunk-NMSHVO5O.js.map → chunk-WMDVOWN6.js.map} +0 -0
  169. /package/dist/{chunk-643M3AP5.js.map → chunk-WMFYI7XC.js.map} +0 -0
  170. /package/dist/{chunk-6LTLIYAQ.js.map → chunk-YEDEAX6Y.js.map} +0 -0
  171. /package/dist/{chunk-FFV2SXFD.js.map → chunk-ZVHG4KF2.js.map} +0 -0
  172. /package/dist/{db-LRIOKQBO.js.map → cost-tracker-KZQSTSE2.js.map} +0 -0
  173. /package/dist/{discord-NKR3X4AV.js.map → db-I7MNG6CL.js.map} +0 -0
  174. /package/dist/{enrichment-pipeline-CMUVBDC7.js.map → discord-6UQHCN27.js.map} +0 -0
  175. /package/dist/{documents-EYIYLZK2.js.map → documents-PFHSK7SZ.js.map} +0 -0
  176. /package/dist/{entity-resolution-4X4JU43O.js.map → enrichment-pipeline-7FE5R5ZI.js.map} +0 -0
  177. /package/dist/{env-CHOFICED.js.map → entity-resolution-7Z6STVXX.js.map} +0 -0
  178. /package/dist/{error-tracker-SVQSDQDW.js.map → env-GN5VHI43.js.map} +0 -0
  179. /package/dist/{imessage-V2XNDDHT.js.map → error-tracker-64DEH3D7.js.map} +0 -0
  180. /package/dist/{github-KGNILDWJ.js.map → github-DUWSXCNP.js.map} +0 -0
  181. /package/dist/{inbox-summarizer-DKKRYXDR.js.map → graph-client-NB475AK5.js.map} +0 -0
  182. /package/dist/{knowledge-base-J7PJ7MZ3.js.map → imessage-DSGSGUZS.js.map} +0 -0
  183. /package/dist/{mcp-3C2TN67D.js.map → inbox-summarizer-F2KAU72V.js.map} +0 -0
  184. /package/dist/{metrics-VJDWQWU7.js.map → knowledge-base-5SMMOGQJ.js.map} +0 -0
  185. /package/dist/{ocr-LGUIPKVZ.js.map → mcp-DJ2QDA6A.js.map} +0 -0
  186. /package/dist/{providers-H6YIC3MG.js.map → metrics-BH3ZLGEV.js.map} +0 -0
  187. /package/dist/{multi-user-S56GUD6L.js.map → multi-user-XAEMB244.js.map} +0 -0
  188. /package/dist/{scheduler-CA5UNHZV.js.map → oauth-UPJYFOVU.js.map} +0 -0
  189. /package/dist/{schema-ALJ67YVG.js.map → ocr-UONKTQU7.js.map} +0 -0
  190. /package/dist/{presentations-HXTAMGHT.js.map → presentations-UOET2FVZ.js.map} +0 -0
  191. /package/dist/{signal-X7IQJGRQ.js.map → providers-2YQ6E3IF.js.map} +0 -0
  192. /package/dist/{slack-P2LFUJUQ.js.map → scheduler-6PLLAQI7.js.map} +0 -0
  193. /package/dist/{sms-4VME2HUL.js.map → schema-ETY7L2VA.js.map} +0 -0
  194. /package/dist/{tools-FGPN522P.js.map → sharepoint-V5P4Q62L.js.map} +0 -0
  195. /package/dist/{whatsapp-KRPQ4YUX.js.map → signal-7D5EPGVL.js.map} +0 -0
  196. /package/dist/{word-document-D6N2C47N.js.map → word-document-AV3YB4L2.js.map} +0 -0
  197. /package/dist/{workflow-store-ZYAYE5P6.js.map → workflow-store-5Y56GUP7.js.map} +0 -0
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  db
3
- } from "./chunk-S4NJJS5C.js";
3
+ } from "./chunk-5BTVJR7R.js";
4
4
  import {
5
5
  env
6
- } from "./chunk-PUNIMPMY.js";
6
+ } from "./chunk-4KIHDIXZ.js";
7
7
  import {
8
8
  auditLogs
9
- } from "./chunk-NYVBXUGD.js";
9
+ } from "./chunk-ZIBRVA3Y.js";
10
10
 
11
11
  // src/core/security/audit-logger.ts
12
12
  import { createHmac, randomUUID } from "crypto";
@@ -292,4 +292,4 @@ export {
292
292
  getAuditChainIntegrity,
293
293
  audit
294
294
  };
295
- //# sourceMappingURL=chunk-KABG5PG3.js.map
295
+ //# sourceMappingURL=chunk-BBN4VCNK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/security/audit-logger.ts"],"sourcesContent":["import { createHmac, randomUUID } from \"crypto\";\r\nimport { db } from \"../../db\";\r\nimport { auditLogs, NewAuditLog } from \"../../db/schema\";\r\nimport { eq, and, gte, lte, desc, count, min, max, asc } from \"drizzle-orm\";\r\nimport { env } from \"../../config/env\";\r\n\r\nexport type AuditAction =\r\n | \"login\"\r\n | \"logout\"\r\n | \"session_create\"\r\n | \"session_invalidate\"\r\n | \"api_key_create\"\r\n | \"api_key_revoke\"\r\n | \"tool_use\"\r\n | \"chat_message\"\r\n | \"memory_create\"\r\n | \"memory_delete\"\r\n | \"memory_archive\"\r\n | \"settings_change\"\r\n | \"mode_change\"\r\n | \"agent_spawn\"\r\n | \"agent_complete\"\r\n | \"file_read\"\r\n | \"file_write\"\r\n | \"shell_execute\"\r\n | \"web_browse\"\r\n | \"error\";\r\n\r\nexport type AuditResource =\r\n | \"session\"\r\n | \"api_key\"\r\n | \"tool\"\r\n | \"chat\"\r\n | \"memory\"\r\n | \"settings\"\r\n | \"mode\"\r\n | \"agent\"\r\n | \"file\"\r\n | \"shell\"\r\n | \"browser\";\r\n\r\nexport interface AuditLogEntry {\r\n userId?: string;\r\n sessionId?: string;\r\n action: AuditAction;\r\n resource?: AuditResource;\r\n resourceId?: string;\r\n details?: Record<string, unknown>;\r\n ipAddress?: string;\r\n userAgent?: string;\r\n success?: boolean;\r\n}\r\n\r\n// --- Tamper-proof chain hashing helpers (SOC 2 compliance) ---\r\n\r\nlet _cachedSigningKey: string | null = null;\r\n\r\nfunction getAuditSigningKey(): string {\r\n if (_cachedSigningKey) return _cachedSigningKey;\r\n if (env.AUDIT_SIGNING_KEY) {\r\n _cachedSigningKey = env.AUDIT_SIGNING_KEY;\r\n return _cachedSigningKey;\r\n }\r\n _cachedSigningKey = randomUUID();\r\n console.warn(\r\n \"[audit-logger] AUDIT_SIGNING_KEY not set — using a random ephemeral key. \" +\r\n \"Set AUDIT_SIGNING_KEY in .env for persistent tamper-proof audit chains.\"\r\n );\r\n return _cachedSigningKey;\r\n}\r\n\r\nfunction signAuditEntry(\r\n sequenceNumber: number,\r\n action: string,\r\n userId: string | undefined,\r\n resource: string | undefined,\r\n detailsJson: string,\r\n timestamp: string,\r\n previousHash: string | null\r\n): string {\r\n const key = getAuditSigningKey();\r\n const data = [\r\n String(sequenceNumber),\r\n action,\r\n userId ?? \"\",\r\n resource ?? \"\",\r\n detailsJson,\r\n timestamp,\r\n previousHash ?? \"\",\r\n ].join(\"|\");\r\n return createHmac(\"sha256\", key).update(data).digest(\"hex\");\r\n}\r\n\r\nasync function getLastAuditEntry(): Promise<{\r\n sequenceNumber: number;\r\n entryHash: string;\r\n} | null> {\r\n const [last] = await db\r\n .select({\r\n sequenceNumber: auditLogs.sequenceNumber,\r\n entryHash: auditLogs.entryHash,\r\n })\r\n .from(auditLogs)\r\n .orderBy(desc(auditLogs.sequenceNumber))\r\n .limit(1);\r\n\r\n if (!last || last.sequenceNumber == null || last.entryHash == null) {\r\n return null;\r\n }\r\n\r\n return {\r\n sequenceNumber: last.sequenceNumber,\r\n entryHash: last.entryHash,\r\n };\r\n}\r\n\r\nexport async function logAudit(entry: AuditLogEntry): Promise<string> {\r\n // Fetch previous chain entry for tamper-proof linking\r\n const last = await getLastAuditEntry();\r\n const sequenceNumber = (last?.sequenceNumber ?? 0) + 1;\r\n const previousHash = last?.entryHash ?? null;\r\n\r\n const timestamp = new Date().toISOString();\r\n const detailsJson = entry.details ? JSON.stringify(entry.details) : \"{}\";\r\n\r\n const entryHash = signAuditEntry(\r\n sequenceNumber,\r\n entry.action,\r\n entry.userId,\r\n entry.resource,\r\n detailsJson,\r\n timestamp,\r\n previousHash\r\n );\r\n\r\n const [log] = await db\r\n .insert(auditLogs)\r\n .values({\r\n userId: entry.userId,\r\n sessionId: entry.sessionId,\r\n action: entry.action,\r\n resource: entry.resource,\r\n resourceId: entry.resourceId,\r\n details: entry.details,\r\n ipAddress: entry.ipAddress,\r\n userAgent: entry.userAgent,\r\n success: entry.success ?? true,\r\n createdAt: new Date(timestamp),\r\n sequenceNumber,\r\n entryHash,\r\n previousHash,\r\n })\r\n .returning();\r\n\r\n return log.id;\r\n}\r\n\r\nexport interface AuditQueryOptions {\r\n userId?: string;\r\n action?: AuditAction;\r\n resource?: AuditResource;\r\n startDate?: Date;\r\n endDate?: Date;\r\n limit?: number;\r\n offset?: number;\r\n}\r\n\r\nexport async function queryAuditLogs(options: AuditQueryOptions = {}) {\r\n const {\r\n userId,\r\n action,\r\n resource,\r\n startDate,\r\n endDate,\r\n limit = 100,\r\n offset = 0,\r\n } = options;\r\n\r\n let query = db.select().from(auditLogs);\r\n\r\n const conditions = [];\r\n\r\n if (userId) {\r\n conditions.push(eq(auditLogs.userId, userId));\r\n }\r\n\r\n if (action) {\r\n conditions.push(eq(auditLogs.action, action));\r\n }\r\n\r\n if (resource) {\r\n conditions.push(eq(auditLogs.resource, resource));\r\n }\r\n\r\n if (startDate) {\r\n conditions.push(gte(auditLogs.createdAt, startDate));\r\n }\r\n\r\n if (endDate) {\r\n conditions.push(lte(auditLogs.createdAt, endDate));\r\n }\r\n\r\n if (conditions.length > 0) {\r\n query = query.where(and(...conditions)) as typeof query;\r\n }\r\n\r\n const logs = await query\r\n .orderBy(desc(auditLogs.createdAt))\r\n .limit(limit)\r\n .offset(offset);\r\n\r\n return logs;\r\n}\r\n\r\nexport async function getRecentUserActivity(\r\n userId: string,\r\n hours = 24\r\n): Promise<typeof auditLogs.$inferSelect[]> {\r\n const since = new Date(Date.now() - hours * 60 * 60 * 1000);\r\n\r\n return db\r\n .select()\r\n .from(auditLogs)\r\n .where(and(eq(auditLogs.userId, userId), gte(auditLogs.createdAt, since)))\r\n .orderBy(desc(auditLogs.createdAt))\r\n .limit(100);\r\n}\r\n\r\nexport async function countActionsByType(\r\n userId: string,\r\n startDate: Date,\r\n endDate: Date\r\n): Promise<Record<string, number>> {\r\n const logs = await db\r\n .select()\r\n .from(auditLogs)\r\n .where(\r\n and(\r\n eq(auditLogs.userId, userId),\r\n gte(auditLogs.createdAt, startDate),\r\n lte(auditLogs.createdAt, endDate)\r\n )\r\n );\r\n\r\n const counts: Record<string, number> = {};\r\n for (const log of logs) {\r\n counts[log.action] = (counts[log.action] || 0) + 1;\r\n }\r\n\r\n return counts;\r\n}\r\n\r\n// --- Audit chain verification (SOC 2 compliance) ---\r\n\r\nexport async function verifyAuditChain(\r\n options?: { fromSequence?: number; limit?: number }\r\n): Promise<{\r\n valid: boolean;\r\n totalChecked: number;\r\n firstInvalid?: number;\r\n errors: Array<{ sequenceNumber: number; error: string }>;\r\n}> {\r\n const fromSequence = options?.fromSequence ?? 1;\r\n const batchLimit = options?.limit ?? 10000;\r\n\r\n // Fetch the entry just before fromSequence to get its hash for linkage check\r\n let expectedPreviousHash: string | null = null;\r\n let expectedSequence = fromSequence;\r\n\r\n if (fromSequence > 1) {\r\n const [prev] = await db\r\n .select({\r\n sequenceNumber: auditLogs.sequenceNumber,\r\n entryHash: auditLogs.entryHash,\r\n })\r\n .from(auditLogs)\r\n .where(eq(auditLogs.sequenceNumber, fromSequence - 1))\r\n .limit(1);\r\n\r\n expectedPreviousHash = prev?.entryHash ?? null;\r\n }\r\n\r\n const entries = await db\r\n .select()\r\n .from(auditLogs)\r\n .where(gte(auditLogs.sequenceNumber, fromSequence))\r\n .orderBy(asc(auditLogs.sequenceNumber))\r\n .limit(batchLimit);\r\n\r\n const errors: Array<{ sequenceNumber: number; error: string }> = [];\r\n\r\n for (const entry of entries) {\r\n const seq = entry.sequenceNumber;\r\n\r\n if (seq == null) {\r\n errors.push({\r\n sequenceNumber: expectedSequence,\r\n error: \"Missing sequence number\",\r\n });\r\n expectedSequence++;\r\n continue;\r\n }\r\n\r\n // Check sequence continuity\r\n if (seq !== expectedSequence) {\r\n errors.push({\r\n sequenceNumber: expectedSequence,\r\n error: `Sequence gap: expected ${expectedSequence}, got ${seq}`,\r\n });\r\n expectedSequence = seq; // re-sync\r\n }\r\n\r\n // Check previousHash linkage\r\n if ((entry.previousHash ?? null) !== expectedPreviousHash) {\r\n errors.push({\r\n sequenceNumber: seq,\r\n error: `Previous hash mismatch: expected ${expectedPreviousHash ?? \"(null)\"}, got ${entry.previousHash ?? \"(null)\"}`,\r\n });\r\n }\r\n\r\n // Recompute and verify entryHash\r\n const detailsJson = entry.details ? JSON.stringify(entry.details) : \"{}\";\r\n const timestamp = entry.createdAt.toISOString();\r\n\r\n const recomputed = signAuditEntry(\r\n seq,\r\n entry.action,\r\n entry.userId ?? undefined,\r\n entry.resource ?? undefined,\r\n detailsJson,\r\n timestamp,\r\n entry.previousHash\r\n );\r\n\r\n if (recomputed !== entry.entryHash) {\r\n errors.push({\r\n sequenceNumber: seq,\r\n error: \"Entry hash mismatch — record may have been tampered with\",\r\n });\r\n }\r\n\r\n // Advance expectations\r\n expectedPreviousHash = entry.entryHash;\r\n expectedSequence = seq + 1;\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n totalChecked: entries.length,\r\n firstInvalid: errors.length > 0 ? errors[0].sequenceNumber : undefined,\r\n errors,\r\n };\r\n}\r\n\r\nexport async function getAuditChainIntegrity(): Promise<{\r\n totalEntries: number;\r\n oldestEntry: Date | null;\r\n newestEntry: Date | null;\r\n lastVerified: number;\r\n chainValid: boolean;\r\n lastSequence: number;\r\n}> {\r\n const [stats] = await db\r\n .select({\r\n totalEntries: count(auditLogs.id),\r\n oldestEntry: min(auditLogs.createdAt),\r\n newestEntry: max(auditLogs.createdAt),\r\n lastSequence: max(auditLogs.sequenceNumber),\r\n })\r\n .from(auditLogs);\r\n\r\n const totalEntries = Number(stats.totalEntries ?? 0);\r\n const lastSequence = stats.lastSequence ?? 0;\r\n\r\n // Verify the last 1000 entries\r\n const verifyFrom = Math.max(1, lastSequence - 999);\r\n const verification = await verifyAuditChain({\r\n fromSequence: verifyFrom,\r\n limit: 1000,\r\n });\r\n\r\n return {\r\n totalEntries,\r\n oldestEntry: stats.oldestEntry ? new Date(stats.oldestEntry) : null,\r\n newestEntry: stats.newestEntry ? new Date(stats.newestEntry) : null,\r\n lastVerified: verification.totalChecked,\r\n chainValid: verification.valid,\r\n lastSequence,\r\n };\r\n}\r\n\r\n// Convenience functions for common audit events\r\nexport const audit = {\r\n login: (userId: string, ipAddress?: string, userAgent?: string) =>\r\n logAudit({\r\n userId,\r\n action: \"login\",\r\n resource: \"session\",\r\n ipAddress,\r\n userAgent,\r\n }),\r\n\r\n logout: (userId: string, sessionId: string) =>\r\n logAudit({\r\n userId,\r\n sessionId,\r\n action: \"logout\",\r\n resource: \"session\",\r\n }),\r\n\r\n toolUse: (\r\n userId: string,\r\n toolName: string,\r\n input: Record<string, unknown>,\r\n success: boolean\r\n ) =>\r\n logAudit({\r\n userId,\r\n action: \"tool_use\",\r\n resource: \"tool\",\r\n resourceId: toolName,\r\n details: { input },\r\n success,\r\n }),\r\n\r\n shellExecute: (\r\n userId: string,\r\n command: string,\r\n exitCode: number,\r\n durationMs: number\r\n ) =>\r\n logAudit({\r\n userId,\r\n action: \"shell_execute\",\r\n resource: \"shell\",\r\n details: { command, exitCode, durationMs },\r\n success: exitCode === 0,\r\n }),\r\n\r\n fileAccess: (\r\n userId: string,\r\n action: \"file_read\" | \"file_write\",\r\n filePath: string\r\n ) =>\r\n logAudit({\r\n userId,\r\n action,\r\n resource: \"file\",\r\n resourceId: filePath,\r\n }),\r\n\r\n memoryCreate: (userId: string, memoryId: string, memoryType: string) =>\r\n logAudit({\r\n userId,\r\n action: \"memory_create\",\r\n resource: \"memory\",\r\n resourceId: memoryId,\r\n details: { type: memoryType },\r\n }),\r\n\r\n modeChange: (\r\n userId: string,\r\n fromMode: string | null,\r\n toMode: string\r\n ) =>\r\n logAudit({\r\n userId,\r\n action: \"mode_change\",\r\n resource: \"mode\",\r\n details: { fromMode, toMode },\r\n }),\r\n\r\n agentSpawn: (userId: string, agentId: string, agentType: string) =>\r\n logAudit({\r\n userId,\r\n action: \"agent_spawn\",\r\n resource: \"agent\",\r\n resourceId: agentId,\r\n details: { type: agentType },\r\n }),\r\n\r\n error: (\r\n userId: string | undefined,\r\n errorType: string,\r\n message: string,\r\n context?: Record<string, unknown>\r\n ) =>\r\n logAudit({\r\n userId,\r\n action: \"error\",\r\n details: { errorType, message, ...context },\r\n success: false,\r\n }),\r\n};\r\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  env
3
- } from "./chunk-PUNIMPMY.js";
3
+ } from "./chunk-4KIHDIXZ.js";
4
4
 
5
5
  // src/outputs/stt.ts
6
6
  import OpenAI from "openai";
@@ -26,4 +26,4 @@ async function transcribeAudio(audioBuffer, language) {
26
26
  export {
27
27
  transcribeAudio
28
28
  };
29
- //# sourceMappingURL=chunk-4YJRBMMA.js.map
29
+ //# sourceMappingURL=chunk-BNZHWAZC.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  chatWithTools
3
- } from "./chunk-6JY4HNUH.js";
3
+ } from "./chunk-ZMML6T63.js";
4
4
 
5
5
  // src/inputs/imessage/index.ts
6
6
  var iMessageBot = class {
@@ -213,4 +213,4 @@ export {
213
213
  iMessageBot,
214
214
  imessage_default
215
215
  };
216
- //# sourceMappingURL=chunk-TAAZB5KN.js.map
216
+ //# sourceMappingURL=chunk-CWT6CAE5.js.map
@@ -655,4 +655,4 @@ export {
655
655
  getMCPToolSummary,
656
656
  findMCPTool
657
657
  };
658
- //# sourceMappingURL=chunk-UWUIJTT4.js.map
658
+ //# sourceMappingURL=chunk-CZTMGHUC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/mcp/client.ts","../src/core/mcp/registry.ts","../src/core/mcp/tool-bridge.ts"],"sourcesContent":["/**\r\n * MCP Client - Handles communication with MCP servers\r\n * Supports STDIO and HTTP+SSE transports\r\n */\r\n\r\nimport { spawn, type ChildProcess } from \"node:child_process\";\r\nimport { nanoid } from \"nanoid\";\r\nimport type {\r\n MCPServerConfig,\r\n MCPServerState,\r\n MCPTool,\r\n MCPInitializeParams,\r\n MCPInitializeResult,\r\n MCPToolListResult,\r\n MCPToolCallParams,\r\n MCPToolCallResult,\r\n MCPToolResult,\r\n JsonRpcRequest,\r\n JsonRpcResponse,\r\n} from \"./types\";\r\n\r\nconst MCP_PROTOCOL_VERSION = \"2024-11-05\";\r\n\r\nexport class MCPClient {\r\n private config: MCPServerConfig;\r\n private state: MCPServerState;\r\n private process: ChildProcess | null = null;\r\n private pendingRequests: Map<string | number, {\r\n resolve: (value: unknown) => void;\r\n reject: (error: Error) => void;\r\n timeout: Timer;\r\n }> = new Map();\r\n private messageBuffer = \"\";\r\n private requestTimeout: number;\r\n\r\n constructor(config: MCPServerConfig, timeout = 30000) {\r\n this.config = config;\r\n this.requestTimeout = timeout;\r\n this.state = {\r\n config,\r\n status: \"disconnected\",\r\n tools: [],\r\n };\r\n }\r\n\r\n get id(): string {\r\n return this.config.id;\r\n }\r\n\r\n get name(): string {\r\n return this.config.name;\r\n }\r\n\r\n get status(): MCPServerState[\"status\"] {\r\n return this.state.status;\r\n }\r\n\r\n get tools(): MCPTool[] {\r\n return this.state.tools;\r\n }\r\n\r\n get serverInfo() {\r\n return this.state.serverInfo;\r\n }\r\n\r\n // ============================================\r\n // CONNECTION MANAGEMENT\r\n // ============================================\r\n\r\n async connect(): Promise<void> {\r\n if (this.state.status === \"connected\") {\r\n return;\r\n }\r\n\r\n this.state.status = \"connecting\";\r\n\r\n try {\r\n if (this.config.transport === \"stdio\") {\r\n await this.connectStdio();\r\n } else if (this.config.transport === \"http+sse\") {\r\n await this.connectHttpSse();\r\n } else {\r\n throw new Error(`Unsupported transport: ${this.config.transport}`);\r\n }\r\n\r\n // Initialize MCP connection\r\n const initResult = await this.initialize();\r\n this.state.capabilities = initResult.capabilities;\r\n this.state.serverInfo = initResult.serverInfo;\r\n\r\n // Fetch available tools\r\n await this.refreshTools();\r\n\r\n this.state.status = \"connected\";\r\n this.state.lastActivity = new Date();\r\n\r\n console.log(`[MCP] Connected to ${this.name} (${this.state.tools.length} tools)`);\r\n } catch (error) {\r\n this.state.status = \"error\";\r\n this.state.lastError = error instanceof Error ? error.message : \"Unknown error\";\r\n throw error;\r\n }\r\n }\r\n\r\n async disconnect(): Promise<void> {\r\n if (this.state.status === \"disconnected\") {\r\n return;\r\n }\r\n\r\n // Cancel pending requests\r\n for (const [, pending] of this.pendingRequests) {\r\n clearTimeout(pending.timeout);\r\n pending.reject(new Error(\"Connection closed\"));\r\n }\r\n this.pendingRequests.clear();\r\n\r\n // Kill subprocess if STDIO\r\n if (this.process) {\r\n this.process.kill();\r\n this.process = null;\r\n }\r\n\r\n this.state.status = \"disconnected\";\r\n this.state.tools = [];\r\n console.log(`[MCP] Disconnected from ${this.name}`);\r\n }\r\n\r\n // ============================================\r\n // STDIO TRANSPORT\r\n // ============================================\r\n\r\n private async connectStdio(): Promise<void> {\r\n if (!this.config.command) {\r\n throw new Error(\"STDIO transport requires a command\");\r\n }\r\n\r\n const env: Record<string, string> = {\r\n ...process.env as Record<string, string>,\r\n ...this.config.env,\r\n };\r\n\r\n this.process = spawn(\r\n this.config.command,\r\n this.config.args || [],\r\n {\r\n cwd: this.config.cwd || process.cwd(),\r\n env,\r\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\r\n }\r\n );\r\n\r\n // Start reading stdout in background\r\n this.readStdout();\r\n\r\n // Start reading stderr in background\r\n this.readStderr();\r\n\r\n // Give the process a moment to start\r\n await new Promise((resolve) => setTimeout(resolve, 500));\r\n }\r\n\r\n private readStdout(): void {\r\n if (!this.process?.stdout) return;\r\n\r\n this.process.stdout.on(\"data\", (chunk: Buffer) => {\r\n this.messageBuffer += chunk.toString();\r\n this.processMessageBuffer();\r\n });\r\n\r\n this.process.stdout.on(\"error\", (error) => {\r\n if (this.state.status === \"connected\" || this.state.status === \"connecting\") {\r\n console.error(`[MCP] ${this.name} stdout error:`, error);\r\n }\r\n });\r\n }\r\n\r\n private readStderr(): void {\r\n if (!this.process?.stderr) return;\r\n\r\n this.process.stderr.on(\"data\", (chunk: Buffer) => {\r\n const text = chunk.toString();\r\n if (text.trim()) {\r\n console.log(`[MCP] ${this.name} stderr: ${text.trim()}`);\r\n }\r\n });\r\n }\r\n\r\n private processMessageBuffer(): void {\r\n // JSON-RPC messages are newline-delimited\r\n const lines = this.messageBuffer.split(\"\\n\");\r\n this.messageBuffer = lines.pop() || \"\";\r\n\r\n for (const line of lines) {\r\n if (!line.trim()) continue;\r\n\r\n try {\r\n const message = JSON.parse(line) as JsonRpcResponse;\r\n this.handleResponse(message);\r\n } catch {\r\n console.warn(`[MCP] ${this.name} failed to parse message: ${line.slice(0, 100)}`);\r\n }\r\n }\r\n }\r\n\r\n private handleResponse(response: JsonRpcResponse): void {\r\n if (response.id === undefined || response.id === null) {\r\n // Notification from server, ignore for now\r\n return;\r\n }\r\n\r\n const pending = this.pendingRequests.get(response.id);\r\n if (!pending) {\r\n console.warn(`[MCP] ${this.name} received response for unknown request: ${response.id}`);\r\n return;\r\n }\r\n\r\n clearTimeout(pending.timeout);\r\n this.pendingRequests.delete(response.id);\r\n\r\n if (response.error) {\r\n pending.reject(new Error(response.error.message));\r\n } else {\r\n pending.resolve(response.result);\r\n }\r\n }\r\n\r\n private async sendRequest(method: string, params?: unknown): Promise<unknown> {\r\n if (!this.process?.stdin) {\r\n throw new Error(\"Not connected\");\r\n }\r\n\r\n const id = nanoid();\r\n const request: JsonRpcRequest = {\r\n jsonrpc: \"2.0\",\r\n id,\r\n method,\r\n params,\r\n };\r\n\r\n const promise = new Promise((resolve, reject) => {\r\n const timeout = setTimeout(() => {\r\n this.pendingRequests.delete(id);\r\n reject(new Error(`Request timeout: ${method}`));\r\n }, this.requestTimeout);\r\n\r\n this.pendingRequests.set(id, { resolve, reject, timeout });\r\n });\r\n\r\n // Write request to stdin\r\n const data = JSON.stringify(request) + \"\\n\";\r\n this.process.stdin.write(data);\r\n\r\n return promise;\r\n }\r\n\r\n // ============================================\r\n // HTTP+SSE TRANSPORT\r\n // ============================================\r\n\r\n private async connectHttpSse(): Promise<void> {\r\n if (!this.config.url) {\r\n throw new Error(\"HTTP+SSE transport requires a URL\");\r\n }\r\n\r\n // For HTTP+SSE, we don't maintain a persistent connection\r\n // Each request is a separate HTTP call\r\n // SSE is used for streaming responses (not implemented yet)\r\n\r\n // Just verify the server is reachable\r\n try {\r\n const response = await fetch(`${this.config.url}/health`, {\r\n headers: this.config.headers,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Server health check failed: ${response.status}`);\r\n }\r\n } catch (error) {\r\n // Health endpoint might not exist, try main endpoint\r\n const response = await fetch(this.config.url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...this.config.headers,\r\n },\r\n body: JSON.stringify({\r\n jsonrpc: \"2.0\",\r\n id: \"ping\",\r\n method: \"ping\",\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Server connection failed: ${response.status}`);\r\n }\r\n }\r\n }\r\n\r\n private async sendHttpRequest(method: string, params?: unknown): Promise<unknown> {\r\n if (!this.config.url) {\r\n throw new Error(\"HTTP+SSE transport requires a URL\");\r\n }\r\n\r\n const request: JsonRpcRequest = {\r\n jsonrpc: \"2.0\",\r\n id: nanoid(),\r\n method,\r\n params,\r\n };\r\n\r\n const response = await fetch(this.config.url, {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...this.config.headers,\r\n },\r\n body: JSON.stringify(request),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`HTTP request failed: ${response.status}`);\r\n }\r\n\r\n const result = await response.json() as JsonRpcResponse;\r\n\r\n if (result.error) {\r\n throw new Error(result.error.message);\r\n }\r\n\r\n return result.result;\r\n }\r\n\r\n // ============================================\r\n // MCP PROTOCOL METHODS\r\n // ============================================\r\n\r\n private async initialize(): Promise<MCPInitializeResult> {\r\n const params: MCPInitializeParams = {\r\n protocolVersion: MCP_PROTOCOL_VERSION,\r\n capabilities: {\r\n roots: { listChanged: true },\r\n },\r\n clientInfo: {\r\n name: \"OpenSentinel\",\r\n version: \"3.0.0\",\r\n },\r\n };\r\n\r\n const result = await this.request(\"initialize\", params) as MCPInitializeResult;\r\n\r\n // Send initialized notification\r\n await this.notify(\"notifications/initialized\", {});\r\n\r\n return result;\r\n }\r\n\r\n async refreshTools(): Promise<MCPTool[]> {\r\n const result = await this.request(\"tools/list\", {}) as MCPToolListResult;\r\n this.state.tools = result.tools || [];\r\n return this.state.tools;\r\n }\r\n\r\n async callTool(name: string, args?: Record<string, unknown>): Promise<MCPToolResult> {\r\n const params: MCPToolCallParams = {\r\n name,\r\n arguments: args,\r\n };\r\n\r\n try {\r\n const result = await this.request(\"tools/call\", params) as MCPToolCallResult;\r\n this.state.lastActivity = new Date();\r\n\r\n // Extract text content from result\r\n const textContent = result.content\r\n .filter((c) => c.type === \"text\" && c.text)\r\n .map((c) => c.text)\r\n .join(\"\\n\");\r\n\r\n return {\r\n success: !result.isError,\r\n output: textContent || JSON.stringify(result.content),\r\n isError: result.isError,\r\n };\r\n } catch (error) {\r\n return {\r\n success: false,\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n };\r\n }\r\n }\r\n\r\n // ============================================\r\n // GENERIC REQUEST/NOTIFY\r\n // ============================================\r\n\r\n private async request(method: string, params?: unknown): Promise<unknown> {\r\n if (this.config.transport === \"stdio\") {\r\n return this.sendRequest(method, params);\r\n } else {\r\n return this.sendHttpRequest(method, params);\r\n }\r\n }\r\n\r\n private async notify(method: string, params?: unknown): Promise<void> {\r\n if (this.config.transport === \"stdio\" && this.process?.stdin) {\r\n const notification = {\r\n jsonrpc: \"2.0\",\r\n method,\r\n params,\r\n };\r\n this.process.stdin.write(JSON.stringify(notification) + \"\\n\");\r\n }\r\n // HTTP+SSE notifications are not typically supported\r\n }\r\n\r\n // ============================================\r\n // STATE ACCESS\r\n // ============================================\r\n\r\n getState(): MCPServerState {\r\n return { ...this.state };\r\n }\r\n}\r\n","/**\r\n * MCP Registry - Manages multiple MCP server connections\r\n * Aggregates tools from all connected servers\r\n */\r\n\r\nimport { MCPClient } from \"./client\";\r\nimport type {\r\n MCPConfig,\r\n MCPServerConfig,\r\n MCPServerState,\r\n MCPTool,\r\n MCPToolResult,\r\n} from \"./types\";\r\n\r\nexport class MCPRegistry {\r\n private clients: Map<string, MCPClient> = new Map();\r\n private config: MCPConfig;\r\n private defaultTimeout: number;\r\n\r\n constructor(config: MCPConfig) {\r\n this.config = config;\r\n this.defaultTimeout = config.settings?.timeout || 30000;\r\n }\r\n\r\n // ============================================\r\n // INITIALIZATION\r\n // ============================================\r\n\r\n /**\r\n * Connect to all enabled MCP servers\r\n */\r\n async initialize(): Promise<void> {\r\n const enabledServers = this.config.servers.filter((s) => s.enabled);\r\n\r\n console.log(`[MCP] Initializing ${enabledServers.length} server(s)...`);\r\n\r\n const withTimeout = (promise: Promise<void>, name: string, ms = 15000) =>\r\n Promise.race([\r\n promise,\r\n new Promise<void>((_, reject) =>\r\n setTimeout(() => reject(new Error(`${name} timed out after ${ms / 1000}s`)), ms)\r\n ),\r\n ]);\r\n\r\n const results = await Promise.allSettled(\r\n enabledServers.map((config) => withTimeout(this.connectServer(config), config.name))\r\n );\r\n\r\n // Log any failures\r\n results.forEach((result, index) => {\r\n if (result.status === \"rejected\") {\r\n console.error(\r\n `[MCP] Failed to connect to ${enabledServers[index].name}:`,\r\n result.reason\r\n );\r\n }\r\n });\r\n\r\n const connected = results.filter((r) => r.status === \"fulfilled\").length;\r\n console.log(`[MCP] Connected to ${connected}/${enabledServers.length} servers`);\r\n }\r\n\r\n /**\r\n * Connect to a single MCP server\r\n */\r\n async connectServer(config: MCPServerConfig): Promise<void> {\r\n if (this.clients.has(config.id)) {\r\n throw new Error(`Server ${config.id} already connected`);\r\n }\r\n\r\n const client = new MCPClient(config, this.defaultTimeout);\r\n await client.connect();\r\n this.clients.set(config.id, client);\r\n }\r\n\r\n /**\r\n * Disconnect from a specific server\r\n */\r\n async disconnectServer(id: string): Promise<void> {\r\n const client = this.clients.get(id);\r\n if (client) {\r\n await client.disconnect();\r\n this.clients.delete(id);\r\n }\r\n }\r\n\r\n /**\r\n * Disconnect from all servers\r\n */\r\n async shutdown(): Promise<void> {\r\n console.log(\"[MCP] Shutting down all connections...\");\r\n await Promise.all(\r\n Array.from(this.clients.values()).map((client) => client.disconnect())\r\n );\r\n this.clients.clear();\r\n }\r\n\r\n // ============================================\r\n // TOOL MANAGEMENT\r\n // ============================================\r\n\r\n /**\r\n * Get all tools from all connected servers\r\n * Tools are prefixed with \"mcp_{serverId}_\" for routing\r\n */\r\n getAllTools(): Array<{ serverId: string; tool: MCPTool }> {\r\n const tools: Array<{ serverId: string; tool: MCPTool }> = [];\r\n\r\n for (const [serverId, client] of this.clients) {\r\n if (client.status === \"connected\") {\r\n for (const tool of client.tools) {\r\n tools.push({ serverId, tool });\r\n }\r\n }\r\n }\r\n\r\n return tools;\r\n }\r\n\r\n /**\r\n * Get tools from a specific server\r\n */\r\n getServerTools(serverId: string): MCPTool[] {\r\n const client = this.clients.get(serverId);\r\n return client?.tools || [];\r\n }\r\n\r\n /**\r\n * Call a tool on a specific server\r\n */\r\n async callTool(\r\n serverId: string,\r\n toolName: string,\r\n args?: Record<string, unknown>\r\n ): Promise<MCPToolResult> {\r\n const client = this.clients.get(serverId);\r\n\r\n if (!client) {\r\n return {\r\n success: false,\r\n error: `MCP server not found: ${serverId}`,\r\n };\r\n }\r\n\r\n if (client.status !== \"connected\") {\r\n return {\r\n success: false,\r\n error: `MCP server not connected: ${serverId}`,\r\n };\r\n }\r\n\r\n console.log(`[MCP] Calling ${serverId}:${toolName}`);\r\n return client.callTool(toolName, args);\r\n }\r\n\r\n // ============================================\r\n // SERVER MANAGEMENT\r\n // ============================================\r\n\r\n /**\r\n * Get status of all servers\r\n */\r\n getServerStates(): MCPServerState[] {\r\n return Array.from(this.clients.values()).map((client) => client.getState());\r\n }\r\n\r\n /**\r\n * Get status of a specific server\r\n */\r\n getServerState(serverId: string): MCPServerState | undefined {\r\n return this.clients.get(serverId)?.getState();\r\n }\r\n\r\n /**\r\n * Check if a server is connected\r\n */\r\n isConnected(serverId: string): boolean {\r\n const client = this.clients.get(serverId);\r\n return client?.status === \"connected\";\r\n }\r\n\r\n /**\r\n * Refresh tools from all connected servers\r\n */\r\n async refreshAllTools(): Promise<void> {\r\n await Promise.all(\r\n Array.from(this.clients.values())\r\n .filter((client) => client.status === \"connected\")\r\n .map((client) => client.refreshTools())\r\n );\r\n }\r\n\r\n /**\r\n * Add a new server configuration and optionally connect\r\n */\r\n async addServer(config: MCPServerConfig, connect = true): Promise<void> {\r\n if (this.clients.has(config.id)) {\r\n throw new Error(`Server ${config.id} already exists`);\r\n }\r\n\r\n this.config.servers.push(config);\r\n\r\n if (connect && config.enabled) {\r\n await this.connectServer(config);\r\n }\r\n }\r\n\r\n /**\r\n * Remove a server\r\n */\r\n async removeServer(serverId: string): Promise<void> {\r\n await this.disconnectServer(serverId);\r\n this.config.servers = this.config.servers.filter((s) => s.id !== serverId);\r\n }\r\n\r\n /**\r\n * Get the current configuration\r\n */\r\n getConfig(): MCPConfig {\r\n return { ...this.config };\r\n }\r\n\r\n /**\r\n * Get count of connected servers\r\n */\r\n get connectedCount(): number {\r\n return Array.from(this.clients.values()).filter(\r\n (c) => c.status === \"connected\"\r\n ).length;\r\n }\r\n\r\n /**\r\n * Get total tool count across all servers\r\n */\r\n get totalToolCount(): number {\r\n return this.getAllTools().length;\r\n }\r\n}\r\n\r\n// ============================================\r\n// HELPER FUNCTIONS\r\n// ============================================\r\n\r\n/**\r\n * Load MCP configuration from a file\r\n */\r\nexport async function loadMCPConfig(path: string): Promise<MCPConfig> {\r\n try {\r\n const { readFile, access } = await import(\"node:fs/promises\");\r\n try {\r\n await access(path);\r\n } catch {\r\n console.log(`[MCP] Config file not found: ${path}, using empty config`);\r\n return { servers: [] };\r\n }\r\n\r\n const content = await readFile(path, \"utf-8\");\r\n const config = JSON.parse(content) as MCPConfig;\r\n\r\n // Validate config\r\n if (!Array.isArray(config.servers)) {\r\n console.warn(\"[MCP] Invalid config: servers must be an array\");\r\n return { servers: [] };\r\n }\r\n\r\n return config;\r\n } catch (error) {\r\n console.error(\"[MCP] Failed to load config:\", error);\r\n return { servers: [] };\r\n }\r\n}\r\n\r\n/**\r\n * Create and initialize an MCP registry from a config file\r\n */\r\nexport async function initMCPRegistry(configPath: string): Promise<MCPRegistry> {\r\n const config = await loadMCPConfig(configPath);\r\n const registry = new MCPRegistry(config);\r\n await registry.initialize();\r\n return registry;\r\n}\r\n","/**\n * MCP Tool Bridge - Converts MCP tools to Anthropic format\n * Handles tool routing between native and MCP tools\n */\n\nimport type { Tool } from \"@anthropic-ai/sdk/resources/messages\";\nimport type { MCPRegistry } from \"./registry\";\nimport type { MCPTool, MCPToolProperty, MCPToolResult } from \"./types\";\n\n// MCP tool prefix format: mcp_{serverId}_{toolName}\nconst MCP_TOOL_PREFIX = \"mcp_\";\n\n// ============================================\n// TOOL NAME UTILITIES\n// ============================================\n\n/**\n * Create a prefixed tool name for routing\n */\nexport function createMCPToolName(serverId: string, toolName: string): string {\n // Sanitize serverId and toolName to be safe for use as identifiers\n const safeServerId = serverId.replace(/[^a-zA-Z0-9_]/g, \"_\");\n const safeToolName = toolName.replace(/[^a-zA-Z0-9_]/g, \"_\");\n return `${MCP_TOOL_PREFIX}${safeServerId}__${safeToolName}`;\n}\n\n/**\n * Check if a tool name is an MCP tool\n */\nexport function isMCPTool(name: string): boolean {\n return name.startsWith(MCP_TOOL_PREFIX);\n}\n\n/**\n * Parse an MCP tool name to get serverId and original tool name\n */\nexport function parseMCPToolName(name: string): { serverId: string; toolName: string } | null {\n if (!isMCPTool(name)) {\n return null;\n }\n\n const withoutPrefix = name.slice(MCP_TOOL_PREFIX.length);\n const separatorIndex = withoutPrefix.indexOf(\"__\");\n\n if (separatorIndex === -1) {\n return null;\n }\n\n return {\n serverId: withoutPrefix.slice(0, separatorIndex),\n toolName: withoutPrefix.slice(separatorIndex + 2),\n };\n}\n\n// ============================================\n// SCHEMA CONVERSION\n// ============================================\n\n/**\n * Convert MCP tool property to JSON Schema format\n */\nfunction convertProperty(prop: MCPToolProperty): Record<string, unknown> {\n const result: Record<string, unknown> = {\n type: prop.type,\n };\n\n if (prop.description) {\n result.description = prop.description;\n }\n\n if (prop.enum) {\n result.enum = prop.enum;\n }\n\n if (prop.items) {\n result.items = convertProperty(prop.items);\n }\n\n if (prop.properties) {\n result.properties = Object.fromEntries(\n Object.entries(prop.properties).map(([key, value]) => [\n key,\n convertProperty(value),\n ])\n );\n }\n\n if (prop.required) {\n result.required = prop.required;\n }\n\n return result;\n}\n\n/**\n * Convert MCP tool to Anthropic Tool format\n */\nexport function mcpToolToAnthropicTool(\n serverId: string,\n serverName: string,\n tool: MCPTool\n): Tool {\n const properties: Record<string, Record<string, unknown>> = {};\n\n if (tool.inputSchema.properties) {\n for (const [key, value] of Object.entries(tool.inputSchema.properties)) {\n properties[key] = convertProperty(value);\n }\n }\n\n const inputSchema: Tool.InputSchema = {\n type: \"object\",\n properties,\n required: tool.inputSchema.required || [],\n };\n\n // Create a unique name and add server context to description\n const name = createMCPToolName(serverId, tool.name);\n const description = tool.description\n ? `[${serverName}] ${tool.description}`\n : `[${serverName}] ${tool.name}`;\n\n return {\n name,\n description,\n input_schema: inputSchema,\n };\n}\n\n/**\n * Convert all tools from an MCP registry to Anthropic format\n */\nexport function mcpToolsToAnthropicTools(registry: MCPRegistry): Tool[] {\n const tools: Tool[] = [];\n const serverStates = registry.getServerStates();\n\n for (const state of serverStates) {\n if (state.status !== \"connected\") continue;\n\n const serverName = state.serverInfo?.name || state.config.name;\n\n for (const tool of state.tools) {\n tools.push(mcpToolToAnthropicTool(state.config.id, serverName, tool));\n }\n }\n\n return tools;\n}\n\n// ============================================\n// TOOL EXECUTION\n// ============================================\n\n/**\n * Execute an MCP tool call through the registry\n */\nexport async function executeMCPTool(\n registry: MCPRegistry,\n toolName: string,\n args: Record<string, unknown>\n): Promise<MCPToolResult> {\n const parsed = parseMCPToolName(toolName);\n\n if (!parsed) {\n return {\n success: false,\n error: `Invalid MCP tool name: ${toolName}`,\n };\n }\n\n return registry.callTool(parsed.serverId, parsed.toolName, args);\n}\n\n// ============================================\n// TOOL DISCOVERY\n// ============================================\n\n/**\n * Get a summary of available MCP tools for logging/display\n */\nexport function getMCPToolSummary(registry: MCPRegistry): string {\n const states = registry.getServerStates();\n const lines: string[] = [];\n\n for (const state of states) {\n const status = state.status === \"connected\" ? \"✓\" : \"✗\";\n const serverName = state.serverInfo?.name || state.config.name;\n const toolCount = state.tools.length;\n\n lines.push(` ${status} ${serverName}: ${toolCount} tools`);\n\n if (state.status === \"connected\" && state.tools.length > 0) {\n const toolNames = state.tools.map((t) => t.name).join(\", \");\n lines.push(` Tools: ${toolNames}`);\n } else if (state.lastError) {\n lines.push(` Error: ${state.lastError}`);\n }\n }\n\n if (lines.length === 0) {\n return \" No MCP servers configured\";\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Find an MCP tool by its original name (searches all servers)\n */\nexport function findMCPTool(\n registry: MCPRegistry,\n toolName: string\n): { serverId: string; tool: MCPTool } | null {\n const allTools = registry.getAllTools();\n\n for (const { serverId, tool } of allTools) {\n if (tool.name === toolName) {\n return { serverId, tool };\n }\n }\n\n return null;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,89 @@
1
+ import {
2
+ env
3
+ } from "./chunk-4KIHDIXZ.js";
4
+
5
+ // src/core/security/field-encryption.ts
6
+ import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
7
+ var ALGORITHM = "aes-256-gcm";
8
+ var IV_LENGTH = 16;
9
+ var TAG_LENGTH = 16;
10
+ var KEY_LENGTH = 32;
11
+ var CURRENT_KEY_VERSION = 1;
12
+ var _masterKey = null;
13
+ function getMasterKey() {
14
+ if (_masterKey) return _masterKey;
15
+ const keyBase64 = env.ENCRYPTION_MASTER_KEY;
16
+ if (keyBase64) {
17
+ const key = Buffer.from(keyBase64, "base64");
18
+ if (key.length !== KEY_LENGTH) {
19
+ throw new Error(
20
+ `ENCRYPTION_MASTER_KEY must be ${KEY_LENGTH} bytes (${KEY_LENGTH * 4 / 3} base64 chars). Got ${key.length} bytes.`
21
+ );
22
+ }
23
+ _masterKey = key;
24
+ return _masterKey;
25
+ }
26
+ if (env.NODE_ENV === "production") {
27
+ throw new Error(
28
+ `ENCRYPTION_MASTER_KEY is required in production for SOC 2 compliance. Generate one with: node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"`
29
+ );
30
+ }
31
+ console.warn("[field-encryption] No ENCRYPTION_MASTER_KEY set \u2014 using ephemeral key (dev only)");
32
+ _masterKey = randomBytes(KEY_LENGTH);
33
+ return _masterKey;
34
+ }
35
+ function encryptField(plaintext) {
36
+ if (plaintext === null || plaintext === void 0) return null;
37
+ const key = getMasterKey();
38
+ const iv = randomBytes(IV_LENGTH);
39
+ const cipher = createCipheriv(ALGORITHM, key, iv);
40
+ const encrypted = Buffer.concat([
41
+ cipher.update(plaintext, "utf8"),
42
+ cipher.final()
43
+ ]);
44
+ const tag = cipher.getAuthTag();
45
+ const combined = Buffer.concat([
46
+ Buffer.from([CURRENT_KEY_VERSION]),
47
+ iv,
48
+ tag,
49
+ encrypted
50
+ ]);
51
+ return combined.toString("base64");
52
+ }
53
+ function decryptField(encryptedBase64) {
54
+ if (encryptedBase64 === null || encryptedBase64 === void 0) return null;
55
+ const combined = Buffer.from(encryptedBase64, "base64");
56
+ if (combined.length < 1 + IV_LENGTH + TAG_LENGTH + 1) {
57
+ throw new Error("Encrypted data too short");
58
+ }
59
+ const keyVersion = combined[0];
60
+ if (keyVersion !== CURRENT_KEY_VERSION) {
61
+ throw new Error(`Unsupported encryption key version: ${keyVersion}`);
62
+ }
63
+ const iv = combined.subarray(1, 1 + IV_LENGTH);
64
+ const tag = combined.subarray(1 + IV_LENGTH, 1 + IV_LENGTH + TAG_LENGTH);
65
+ const ciphertext = combined.subarray(1 + IV_LENGTH + TAG_LENGTH);
66
+ const key = getMasterKey();
67
+ const decipher = createDecipheriv(ALGORITHM, key, iv);
68
+ decipher.setAuthTag(tag);
69
+ const decrypted = Buffer.concat([
70
+ decipher.update(ciphertext),
71
+ decipher.final()
72
+ ]);
73
+ return decrypted.toString("utf8");
74
+ }
75
+ function isEncryptionAvailable() {
76
+ try {
77
+ getMasterKey();
78
+ return true;
79
+ } catch {
80
+ return false;
81
+ }
82
+ }
83
+
84
+ export {
85
+ encryptField,
86
+ decryptField,
87
+ isEncryptionAvailable
88
+ };
89
+ //# sourceMappingURL=chunk-DTISLIMB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/security/field-encryption.ts"],"sourcesContent":["/**\r\n * Field-Level Encryption for SOC 2 Compliance\r\n *\r\n * AES-256-GCM encryption for database column values.\r\n * Used to encrypt sensitive fields (messages, memories) at rest.\r\n *\r\n * Format: base64(keyVersion[1] + iv[16] + authTag[16] + ciphertext)\r\n */\r\n\r\nimport { createCipheriv, createDecipheriv, randomBytes } from \"crypto\";\r\nimport { env } from \"../../config/env\";\r\n\r\nconst ALGORITHM = \"aes-256-gcm\";\r\nconst IV_LENGTH = 16;\r\nconst TAG_LENGTH = 16;\r\nconst KEY_LENGTH = 32;\r\nconst CURRENT_KEY_VERSION = 1;\r\n\r\nlet _masterKey: Buffer | null = null;\r\n\r\nfunction getMasterKey(): Buffer {\r\n if (_masterKey) return _masterKey;\r\n\r\n const keyBase64 = env.ENCRYPTION_MASTER_KEY;\r\n\r\n if (keyBase64) {\r\n const key = Buffer.from(keyBase64, \"base64\");\r\n if (key.length !== KEY_LENGTH) {\r\n throw new Error(\r\n `ENCRYPTION_MASTER_KEY must be ${KEY_LENGTH} bytes (${KEY_LENGTH * 4 / 3} base64 chars). Got ${key.length} bytes.`\r\n );\r\n }\r\n _masterKey = key;\r\n return _masterKey;\r\n }\r\n\r\n // No key configured — in production this is an error\r\n if (env.NODE_ENV === \"production\") {\r\n throw new Error(\r\n \"ENCRYPTION_MASTER_KEY is required in production for SOC 2 compliance. \" +\r\n \"Generate one with: node -e \\\"console.log(require('crypto').randomBytes(32).toString('base64'))\\\"\"\r\n );\r\n }\r\n\r\n // Dev/test: generate ephemeral key (data won't survive restarts)\r\n console.warn(\"[field-encryption] No ENCRYPTION_MASTER_KEY set — using ephemeral key (dev only)\");\r\n _masterKey = randomBytes(KEY_LENGTH);\r\n return _masterKey;\r\n}\r\n\r\n/**\r\n * Encrypt a field value using AES-256-GCM.\r\n * Returns base64(keyVersion + iv + authTag + ciphertext), or null if input is null.\r\n */\r\nexport function encryptField(plaintext: string | null): string | null {\r\n if (plaintext === null || plaintext === undefined) return null;\r\n\r\n const key = getMasterKey();\r\n const iv = randomBytes(IV_LENGTH);\r\n const cipher = createCipheriv(ALGORITHM, key, iv);\r\n\r\n const encrypted = Buffer.concat([\r\n cipher.update(plaintext, \"utf8\"),\r\n cipher.final(),\r\n ]);\r\n const tag = cipher.getAuthTag();\r\n\r\n // keyVersion (1 byte) + iv (16) + tag (16) + ciphertext\r\n const combined = Buffer.concat([\r\n Buffer.from([CURRENT_KEY_VERSION]),\r\n iv,\r\n tag,\r\n encrypted,\r\n ]);\r\n\r\n return combined.toString(\"base64\");\r\n}\r\n\r\n/**\r\n * Decrypt a field value encrypted by encryptField().\r\n * Returns plaintext, or null if input is null.\r\n */\r\nexport function decryptField(encryptedBase64: string | null): string | null {\r\n if (encryptedBase64 === null || encryptedBase64 === undefined) return null;\r\n\r\n const combined = Buffer.from(encryptedBase64, \"base64\");\r\n\r\n if (combined.length < 1 + IV_LENGTH + TAG_LENGTH + 1) {\r\n throw new Error(\"Encrypted data too short\");\r\n }\r\n\r\n const keyVersion = combined[0];\r\n if (keyVersion !== CURRENT_KEY_VERSION) {\r\n throw new Error(`Unsupported encryption key version: ${keyVersion}`);\r\n }\r\n\r\n const iv = combined.subarray(1, 1 + IV_LENGTH);\r\n const tag = combined.subarray(1 + IV_LENGTH, 1 + IV_LENGTH + TAG_LENGTH);\r\n const ciphertext = combined.subarray(1 + IV_LENGTH + TAG_LENGTH);\r\n\r\n const key = getMasterKey();\r\n const decipher = createDecipheriv(ALGORITHM, key, iv);\r\n decipher.setAuthTag(tag);\r\n\r\n const decrypted = Buffer.concat([\r\n decipher.update(ciphertext),\r\n decipher.final(),\r\n ]);\r\n\r\n return decrypted.toString(\"utf8\");\r\n}\r\n\r\n/**\r\n * Encrypt multiple fields at once.\r\n */\r\nexport function encryptFields(\r\n fields: Record<string, string | null>\r\n): Record<string, string | null> {\r\n const result: Record<string, string | null> = {};\r\n for (const [k, v] of Object.entries(fields)) {\r\n result[k] = encryptField(v);\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Decrypt multiple fields at once.\r\n */\r\nexport function decryptFields(\r\n fields: Record<string, string | null>\r\n): Record<string, string | null> {\r\n const result: Record<string, string | null> = {};\r\n for (const [k, v] of Object.entries(fields)) {\r\n result[k] = decryptField(v);\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Generate a new random 32-byte encryption key, returned as base64.\r\n * Use this to create an ENCRYPTION_MASTER_KEY for .env.\r\n */\r\nexport function generateEncryptionKey(): string {\r\n return randomBytes(KEY_LENGTH).toString(\"base64\");\r\n}\r\n\r\n/**\r\n * Check whether field encryption is available (master key is configured).\r\n */\r\nexport function isEncryptionAvailable(): boolean {\r\n try {\r\n getMasterKey();\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n"],"mappings":";;;;;AASA,SAAS,gBAAgB,kBAAkB,mBAAmB;AAG9D,IAAM,YAAY;AAClB,IAAM,YAAY;AAClB,IAAM,aAAa;AACnB,IAAM,aAAa;AACnB,IAAM,sBAAsB;AAE5B,IAAI,aAA4B;AAEhC,SAAS,eAAuB;AAC9B,MAAI,WAAY,QAAO;AAEvB,QAAM,YAAY,IAAI;AAEtB,MAAI,WAAW;AACb,UAAM,MAAM,OAAO,KAAK,WAAW,QAAQ;AAC3C,QAAI,IAAI,WAAW,YAAY;AAC7B,YAAM,IAAI;AAAA,QACR,iCAAiC,UAAU,WAAW,aAAa,IAAI,CAAC,uBAAuB,IAAI,MAAM;AAAA,MAC3G;AAAA,IACF;AACA,iBAAa;AACb,WAAO;AAAA,EACT;AAGA,MAAI,IAAI,aAAa,cAAc;AACjC,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAGA,UAAQ,KAAK,uFAAkF;AAC/F,eAAa,YAAY,UAAU;AACnC,SAAO;AACT;AAMO,SAAS,aAAa,WAAyC;AACpE,MAAI,cAAc,QAAQ,cAAc,OAAW,QAAO;AAE1D,QAAM,MAAM,aAAa;AACzB,QAAM,KAAK,YAAY,SAAS;AAChC,QAAM,SAAS,eAAe,WAAW,KAAK,EAAE;AAEhD,QAAM,YAAY,OAAO,OAAO;AAAA,IAC9B,OAAO,OAAO,WAAW,MAAM;AAAA,IAC/B,OAAO,MAAM;AAAA,EACf,CAAC;AACD,QAAM,MAAM,OAAO,WAAW;AAG9B,QAAM,WAAW,OAAO,OAAO;AAAA,IAC7B,OAAO,KAAK,CAAC,mBAAmB,CAAC;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO,SAAS,SAAS,QAAQ;AACnC;AAMO,SAAS,aAAa,iBAA+C;AAC1E,MAAI,oBAAoB,QAAQ,oBAAoB,OAAW,QAAO;AAEtE,QAAM,WAAW,OAAO,KAAK,iBAAiB,QAAQ;AAEtD,MAAI,SAAS,SAAS,IAAI,YAAY,aAAa,GAAG;AACpD,UAAM,IAAI,MAAM,0BAA0B;AAAA,EAC5C;AAEA,QAAM,aAAa,SAAS,CAAC;AAC7B,MAAI,eAAe,qBAAqB;AACtC,UAAM,IAAI,MAAM,uCAAuC,UAAU,EAAE;AAAA,EACrE;AAEA,QAAM,KAAK,SAAS,SAAS,GAAG,IAAI,SAAS;AAC7C,QAAM,MAAM,SAAS,SAAS,IAAI,WAAW,IAAI,YAAY,UAAU;AACvE,QAAM,aAAa,SAAS,SAAS,IAAI,YAAY,UAAU;AAE/D,QAAM,MAAM,aAAa;AACzB,QAAM,WAAW,iBAAiB,WAAW,KAAK,EAAE;AACpD,WAAS,WAAW,GAAG;AAEvB,QAAM,YAAY,OAAO,OAAO;AAAA,IAC9B,SAAS,OAAO,UAAU;AAAA,IAC1B,SAAS,MAAM;AAAA,EACjB,CAAC;AAED,SAAO,UAAU,SAAS,MAAM;AAClC;AAuCO,SAAS,wBAAiC;AAC/C,MAAI;AACF,iBAAa;AACb,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  chat
3
- } from "./chunk-6JY4HNUH.js";
3
+ } from "./chunk-ZMML6T63.js";
4
4
 
5
5
  // src/integrations/email/email-parser.ts
6
6
  function parseEmail(email) {
@@ -774,4 +774,4 @@ export {
774
774
  analyzeSentiment,
775
775
  inbox_summarizer_default
776
776
  };
777
- //# sourceMappingURL=chunk-VKMFUIVA.js.map
777
+ //# sourceMappingURL=chunk-GBVJTRXS.js.map
@@ -1,10 +1,3 @@
1
- import {
2
- AGENT_SYSTEM_PROMPTS,
3
- AGENT_TOOL_PERMISSIONS
4
- } from "./chunk-LFDXEYYB.js";
5
- import {
6
- captureException
7
- } from "./chunk-7MZN73J2.js";
8
1
  import {
9
2
  TOOLS,
10
3
  chat,
@@ -17,7 +10,14 @@ import {
17
10
  getTodaysEvents,
18
11
  getUpcomingEvents,
19
12
  getUserPoints
20
- } from "./chunk-6JY4HNUH.js";
13
+ } from "./chunk-ZMML6T63.js";
14
+ import {
15
+ AGENT_SYSTEM_PROMPTS,
16
+ AGENT_TOOL_PERMISSIONS
17
+ } from "./chunk-LFDXEYYB.js";
18
+ import {
19
+ captureException
20
+ } from "./chunk-TKBVW7ZJ.js";
21
21
  import {
22
22
  riskEngine
23
23
  } from "./chunk-ODCFS5WD.js";
@@ -28,25 +28,25 @@ import {
28
28
  shouldAgentStop,
29
29
  updateAgentStatus,
30
30
  updateAgentTokens
31
- } from "./chunk-643M3AP5.js";
31
+ } from "./chunk-WMFYI7XC.js";
32
32
  import {
33
33
  flushMetrics,
34
34
  metric
35
- } from "./chunk-6LTLIYAQ.js";
35
+ } from "./chunk-YEDEAX6Y.js";
36
36
  import {
37
37
  providerRegistry
38
- } from "./chunk-HTF2GIQC.js";
38
+ } from "./chunk-GW6V4D43.js";
39
39
  import {
40
40
  db
41
- } from "./chunk-S4NJJS5C.js";
41
+ } from "./chunk-5BTVJR7R.js";
42
42
  import {
43
43
  env
44
- } from "./chunk-PUNIMPMY.js";
44
+ } from "./chunk-4KIHDIXZ.js";
45
45
  import {
46
46
  archivedMemories,
47
47
  calendarTriggers,
48
48
  memories
49
- } from "./chunk-NYVBXUGD.js";
49
+ } from "./chunk-ZIBRVA3Y.js";
50
50
 
51
51
  // src/core/scheduler.ts
52
52
  import { Queue, Worker as Worker2 } from "bullmq";
@@ -972,4 +972,4 @@ export {
972
972
  generateBriefing,
973
973
  getQueueStats
974
974
  };
975
- //# sourceMappingURL=chunk-MFK34XSY.js.map
975
+ //# sourceMappingURL=chunk-GJETKBOY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/scheduler.ts","../src/core/agents/agent-worker.ts","../src/inputs/calendar/trigger-processor.ts","../src/core/evolution/memory-shedder.ts","../src/core/evolution/growth-reporter.ts"],"sourcesContent":["import { Queue, Worker, type Job } from \"bullmq\";\r\nimport Redis from \"ioredis\";\r\nimport { env } from \"../config/env\";\r\nimport { chat } from \"./brain\";\r\nimport { startAgentWorker, stopAgentWorker } from \"./agents/agent-worker\";\r\nimport { processCalendarTriggers, generateDailyBriefing } from \"../inputs/calendar/trigger-processor\";\r\nimport { autoShed } from \"./evolution/memory-shedder\";\r\nimport { generateWeeklyReport, generateMonthlyReport } from \"./evolution/growth-reporter\";\r\nimport { resetMonthlyUsage } from \"./permissions/permission-manager\";\r\nimport { flushMetrics } from \"./observability/metrics\";\r\n\r\n// Lazy Redis connection and queues — created on first use\r\nlet _connection: Redis | null = null;\r\nlet _taskQueue: Queue | null = null;\r\nlet _maintenanceQueue: Queue | null = null;\r\n\r\nfunction getConnection(): Redis {\r\n if (!_connection) {\r\n _connection = new Redis(env.REDIS_URL, {\r\n maxRetriesPerRequest: null,\r\n });\r\n }\r\n return _connection;\r\n}\r\n\r\nfunction getTaskQueue(): Queue {\r\n if (!_taskQueue) {\r\n _taskQueue = new Queue(\"sentinel-tasks\", { connection: getConnection() as any });\r\n }\r\n return _taskQueue;\r\n}\r\n\r\nfunction getMaintenanceQueue(): Queue {\r\n if (!_maintenanceQueue) {\r\n _maintenanceQueue = new Queue(\"sentinel-maintenance\", { connection: getConnection() as any });\r\n }\r\n return _maintenanceQueue;\r\n}\r\n\r\n// Backward-compatible exports\r\nconst connection = new Proxy({} as Redis, {\r\n get(_target, prop) {\r\n const instance = getConnection();\r\n const value = (instance as any)[prop];\r\n if (typeof value === \"function\") return value.bind(instance);\r\n return value;\r\n },\r\n});\r\nconst taskQueue = new Proxy({} as Queue, {\r\n get(_target, prop) {\r\n const instance = getTaskQueue();\r\n const value = (instance as any)[prop];\r\n if (typeof value === \"function\") return value.bind(instance);\r\n return value;\r\n },\r\n});\r\nconst maintenanceQueue = new Proxy({} as Queue, {\r\n get(_target, prop) {\r\n const instance = getMaintenanceQueue();\r\n const value = (instance as any)[prop];\r\n if (typeof value === \"function\") return value.bind(instance);\r\n return value;\r\n },\r\n});\r\n\r\ninterface ScheduledTask {\r\n type: \"reminder\" | \"briefing\" | \"custom\" | \"calendar_check\" | \"memory_shed\" | \"growth_report\" | \"metrics_flush\";\r\n message?: string;\r\n userId?: string;\r\n chatId?: string;\r\n metadata?: Record<string, unknown>;\r\n}\r\n\r\n// Schedule a task\r\nexport async function scheduleTask(\r\n task: ScheduledTask,\r\n delay: number\r\n): Promise<string> {\r\n const job = await taskQueue.add(\"scheduled-task\", task, {\r\n delay,\r\n removeOnComplete: true,\r\n removeOnFail: 100,\r\n });\r\n return job.id || \"\";\r\n}\r\n\r\n// Schedule a recurring task (cron-style)\r\nexport async function scheduleRecurring(\r\n name: string,\r\n task: ScheduledTask,\r\n pattern: string // cron pattern\r\n): Promise<void> {\r\n await taskQueue.add(name, task, {\r\n repeat: { pattern },\r\n removeOnComplete: true,\r\n });\r\n}\r\n\r\n// Cancel a scheduled task\r\nexport async function cancelTask(jobId: string): Promise<boolean> {\r\n const job = await taskQueue.getJob(jobId);\r\n if (job) {\r\n await job.remove();\r\n return true;\r\n }\r\n return false;\r\n}\r\n\r\n// Process scheduled tasks\r\nlet worker: Worker | null = null;\r\nlet maintenanceWorker: Worker | null = null;\r\n\r\nexport function startWorker(\r\n onTask: (task: ScheduledTask) => Promise<void>\r\n): void {\r\n if (worker) return;\r\n\r\n worker = new Worker(\r\n \"sentinel-tasks\",\r\n async (job: Job<ScheduledTask>) => {\r\n console.log(`[Scheduler] Processing task: ${job.name}`);\r\n await onTask(job.data);\r\n },\r\n { connection: getConnection() as any }\r\n );\r\n\r\n worker.on(\"completed\", (job) => {\r\n console.log(`[Scheduler] Task completed: ${job.id}`);\r\n });\r\n\r\n worker.on(\"failed\", (job, err) => {\r\n console.error(`[Scheduler] Task failed: ${job?.id}`, err);\r\n });\r\n\r\n console.log(\"[Scheduler] Worker started\");\r\n}\r\n\r\n// Start maintenance worker for background jobs\r\nexport function startMaintenanceWorker(): void {\r\n if (maintenanceWorker) return;\r\n\r\n maintenanceWorker = new Worker(\r\n \"sentinel-maintenance\",\r\n async (job: Job<ScheduledTask>) => {\r\n console.log(`[Maintenance] Processing: ${job.name}`);\r\n\r\n switch (job.data.type) {\r\n case \"calendar_check\":\r\n if (job.data.userId) {\r\n await processCalendarTriggers(job.data.userId, []);\r\n }\r\n break;\r\n\r\n case \"memory_shed\":\r\n if (job.data.userId) {\r\n const result = await autoShed(job.data.userId);\r\n console.log(`[Maintenance] Memory shed: archived ${result.archivedCount} memories`);\r\n }\r\n break;\r\n\r\n case \"growth_report\":\r\n if (job.data.userId) {\r\n const reportType = job.data.metadata?.reportType as \"weekly\" | \"monthly\";\r\n if (reportType === \"monthly\") {\r\n await generateMonthlyReport(job.data.userId);\r\n } else {\r\n await generateWeeklyReport(job.data.userId);\r\n }\r\n }\r\n break;\r\n\r\n case \"metrics_flush\":\r\n await flushMetrics();\r\n break;\r\n\r\n default:\r\n console.log(`[Maintenance] Unknown task type: ${job.data.type}`);\r\n }\r\n },\r\n { connection: getConnection() as any }\r\n );\r\n\r\n maintenanceWorker.on(\"completed\", (job) => {\r\n console.log(`[Maintenance] Completed: ${job.id}`);\r\n });\r\n\r\n maintenanceWorker.on(\"failed\", (job, err) => {\r\n console.error(`[Maintenance] Failed: ${job?.id}`, err);\r\n });\r\n\r\n console.log(\"[Maintenance] Worker started\");\r\n}\r\n\r\nexport function stopWorker(): void {\r\n if (worker) {\r\n worker.close();\r\n worker = null;\r\n }\r\n}\r\n\r\nexport function stopMaintenanceWorker(): void {\r\n if (maintenanceWorker) {\r\n maintenanceWorker.close();\r\n maintenanceWorker = null;\r\n }\r\n}\r\n\r\n// Start all workers and scheduled jobs\r\nexport async function initializeScheduler(\r\n onTask: (task: ScheduledTask) => Promise<void>\r\n): Promise<void> {\r\n // Start workers\r\n startWorker(onTask);\r\n startMaintenanceWorker();\r\n startAgentWorker();\r\n\r\n // Schedule recurring maintenance jobs\r\n await setupRecurringJobs();\r\n\r\n console.log(\"[Scheduler] Initialized\");\r\n}\r\n\r\n// Setup recurring maintenance jobs\r\nasync function setupRecurringJobs(): Promise<void> {\r\n // Calendar trigger check - every 15 minutes\r\n await maintenanceQueue.add(\r\n \"calendar-check\",\r\n { type: \"calendar_check\" },\r\n {\r\n repeat: { pattern: \"*/15 * * * *\" },\r\n removeOnComplete: true,\r\n }\r\n );\r\n\r\n // Metrics flush - every 5 minutes\r\n await maintenanceQueue.add(\r\n \"metrics-flush\",\r\n { type: \"metrics_flush\" },\r\n {\r\n repeat: { pattern: \"*/5 * * * *\" },\r\n removeOnComplete: true,\r\n }\r\n );\r\n\r\n // Weekly memory shedding - Sundays at 3 AM\r\n await maintenanceQueue.add(\r\n \"memory-shed-weekly\",\r\n { type: \"memory_shed\" },\r\n {\r\n repeat: { pattern: \"0 3 * * 0\" },\r\n removeOnComplete: true,\r\n }\r\n );\r\n\r\n // Monthly quota reset - 1st of month at midnight\r\n await maintenanceQueue.add(\r\n \"quota-reset-monthly\",\r\n { type: \"custom\", message: \"quota_reset\" },\r\n {\r\n repeat: { pattern: \"0 0 1 * *\" },\r\n removeOnComplete: true,\r\n }\r\n );\r\n\r\n console.log(\"[Scheduler] Recurring jobs scheduled\");\r\n}\r\n\r\n// Schedule user-specific maintenance\r\nexport async function scheduleUserMaintenance(\r\n userId: string,\r\n type: \"calendar_check\" | \"memory_shed\" | \"growth_report\",\r\n options?: { pattern?: string; reportType?: \"weekly\" | \"monthly\" }\r\n): Promise<void> {\r\n const task: ScheduledTask = {\r\n type,\r\n userId,\r\n metadata: options?.reportType ? { reportType: options.reportType } : undefined,\r\n };\r\n\r\n if (options?.pattern) {\r\n await maintenanceQueue.add(`${type}-${userId}`, task, {\r\n repeat: { pattern: options.pattern },\r\n removeOnComplete: true,\r\n });\r\n } else {\r\n await maintenanceQueue.add(`${type}-${userId}`, task, {\r\n removeOnComplete: true,\r\n });\r\n }\r\n}\r\n\r\n// Shutdown all workers\r\nexport async function shutdownScheduler(): Promise<void> {\r\n stopWorker();\r\n stopMaintenanceWorker();\r\n stopAgentWorker();\r\n if (_connection) await _connection.quit();\r\n console.log(\"[Scheduler] Shutdown complete\");\r\n}\r\n\r\n// Helper to schedule a reminder\r\nexport async function scheduleReminder(\r\n message: string,\r\n delayMs: number,\r\n chatId?: string\r\n): Promise<string> {\r\n return scheduleTask(\r\n {\r\n type: \"reminder\",\r\n message,\r\n chatId,\r\n },\r\n delayMs\r\n );\r\n}\r\n\r\n// Generate morning briefing content\r\nexport async function generateBriefing(userId?: string): Promise<string> {\r\n // Try to use calendar-aware briefing\r\n if (userId) {\r\n try {\r\n return await generateDailyBriefing(userId, []);\r\n } catch {\r\n // Fall back to simple briefing\r\n }\r\n }\r\n\r\n const response = await chat(\r\n [\r\n {\r\n role: \"user\",\r\n content: `Generate a brief morning briefing. Include:\r\n1. A motivational greeting\r\n2. Today's date and day of week\r\n3. A productivity tip\r\n\r\nKeep it concise and uplifting.`,\r\n },\r\n ],\r\n \"You are a helpful assistant creating a morning briefing.\"\r\n );\r\n\r\n return response.content;\r\n}\r\n\r\n// Get queue stats\r\nexport async function getQueueStats(): Promise<{\r\n tasks: { waiting: number; active: number; completed: number; failed: number };\r\n maintenance: { waiting: number; active: number; completed: number; failed: number };\r\n}> {\r\n const [taskStats, maintenanceStats] = await Promise.all([\r\n Promise.all([\r\n taskQueue.getWaitingCount(),\r\n taskQueue.getActiveCount(),\r\n taskQueue.getCompletedCount(),\r\n taskQueue.getFailedCount(),\r\n ]),\r\n Promise.all([\r\n maintenanceQueue.getWaitingCount(),\r\n maintenanceQueue.getActiveCount(),\r\n maintenanceQueue.getCompletedCount(),\r\n maintenanceQueue.getFailedCount(),\r\n ]),\r\n ]);\r\n\r\n return {\r\n tasks: {\r\n waiting: taskStats[0],\r\n active: taskStats[1],\r\n completed: taskStats[2],\r\n failed: taskStats[3],\r\n },\r\n maintenance: {\r\n waiting: maintenanceStats[0],\r\n active: maintenanceStats[1],\r\n completed: maintenanceStats[2],\r\n failed: maintenanceStats[3],\r\n },\r\n };\r\n}\r\n\r\nexport { taskQueue, maintenanceQueue, connection };\r\n","import { Worker, Job } from \"bullmq\";\r\nimport Redis from \"ioredis\";\r\nimport { env } from \"../../config/env\";\r\nimport {\r\n AgentType,\r\n AgentResult,\r\n AGENT_SYSTEM_PROMPTS,\r\n AGENT_TOOL_PERMISSIONS,\r\n} from \"./agent-types\";\r\nimport {\r\n updateAgentStatus,\r\n addAgentMessage,\r\n addAgentProgress,\r\n shouldAgentStop,\r\n updateAgentTokens,\r\n getAgent,\r\n} from \"./agent-manager\";\r\nimport { TOOLS, executeTool } from \"../../tools\";\r\nimport { riskEngine } from \"../intelligence/risk-engine\";\r\nimport { metric } from \"../observability/metrics\";\r\nimport { captureException } from \"../observability/error-tracker\";\r\nimport { providerRegistry } from \"../providers\";\r\nimport type { LLMMessage, LLMContentBlock, LLMTool } from \"../providers/types\";\r\n\r\n// Redis connection\r\nconst connection = new Redis(env.REDIS_URL, {\r\n maxRetriesPerRequest: null,\r\n});\r\n\r\ninterface AgentJobData {\r\n agentId: string;\r\n userId: string;\r\n type: AgentType;\r\n objective: string;\r\n context?: Record<string, unknown>;\r\n tokenBudget: number;\r\n timeBudgetMs: number;\r\n}\r\n\r\nlet worker: Worker | null = null;\r\n\r\n// Process an agent task\r\nasync function processAgentTask(job: Job<AgentJobData>): Promise<AgentResult> {\r\n const { agentId, userId, type, objective, context, tokenBudget } = job.data;\r\n const startTime = Date.now();\r\n let totalTokensUsed = 0;\r\n\r\n console.log(`[Agent ${agentId}] Starting ${type} agent: ${objective}`);\r\n\r\n // Update status to running\r\n await updateAgentStatus(agentId, \"running\");\r\n await addAgentProgress(agentId, 1, \"Starting agent\", \"running\");\r\n\r\n // Build system prompt\r\n const systemPrompt = buildSystemPrompt(type, context);\r\n\r\n // Get the configured LLM provider (respects LLM_PROVIDER env var)\r\n const provider = providerRegistry.getDefault();\r\n\r\n // Get allowed tools for this agent type\r\n const allowedToolNames = AGENT_TOOL_PERMISSIONS[type];\r\n const agentTools = TOOLS\r\n .filter((t) => allowedToolNames.includes(t.name))\r\n .map((t) => ({\r\n name: t.name,\r\n description: t.description || \"\",\r\n input_schema: (t.input_schema || { type: \"object\" as const, properties: {} }) as LLMTool[\"input_schema\"],\r\n }));\r\n\r\n // Build initial messages\r\n const userContent = `Your objective: ${objective}\r\n\r\n${context ? `Additional context:\\n${JSON.stringify(context, null, 2)}` : \"\"}\r\n\r\nPlease proceed with the task, reporting your progress as you go.`;\r\n\r\n const messages: LLMMessage[] = [\r\n { role: \"user\", content: userContent },\r\n ];\r\n\r\n await addAgentMessage(agentId, {\r\n role: \"user\",\r\n content: userContent,\r\n });\r\n\r\n let stepNumber = 2;\r\n const maxSteps = 20; // Prevent infinite loops\r\n\r\n try {\r\n // Agent loop\r\n while (stepNumber <= maxSteps) {\r\n // Check if we should stop\r\n const stopCheck = await shouldAgentStop(agentId);\r\n if (stopCheck.stop) {\r\n await addAgentProgress(\r\n agentId,\r\n stepNumber,\r\n `Stopping: ${stopCheck.reason}`,\r\n \"completed\"\r\n );\r\n break;\r\n }\r\n\r\n // Call the configured LLM provider (Claude, Gemini, OpenAI, etc.)\r\n const response = await provider.createMessage({\r\n model: \"\", // Use provider's default model\r\n max_tokens: 4096,\r\n system: systemPrompt,\r\n tools: agentTools,\r\n messages,\r\n });\r\n\r\n // Track tokens\r\n totalTokensUsed += response.usage.input_tokens + response.usage.output_tokens;\r\n await updateAgentTokens(agentId, totalTokensUsed);\r\n\r\n // Check token budget\r\n if (totalTokensUsed >= tokenBudget) {\r\n await addAgentProgress(\r\n agentId,\r\n stepNumber,\r\n \"Token budget reached\",\r\n \"completed\"\r\n );\r\n break;\r\n }\r\n\r\n // Process response\r\n const assistantContent = response.content;\r\n\r\n // Extract text for logging\r\n const textContent = assistantContent\r\n .filter((c) => c.type === \"text\")\r\n .map((c) => c.text || \"\")\r\n .join(\"\\n\");\r\n\r\n if (textContent) {\r\n await addAgentMessage(agentId, {\r\n role: \"assistant\",\r\n content: textContent,\r\n });\r\n\r\n // Extract progress description from text\r\n const progressDesc = textContent.slice(0, 200).replace(/\\n/g, \" \");\r\n await addAgentProgress(agentId, stepNumber, progressDesc, \"running\");\r\n }\r\n\r\n // Check if done\r\n if (response.stop_reason === \"end_turn\") {\r\n // Agent completed naturally\r\n await addAgentProgress(\r\n agentId,\r\n stepNumber + 1,\r\n \"Task completed\",\r\n \"completed\",\r\n textContent\r\n );\r\n\r\n return {\r\n success: true,\r\n output: textContent,\r\n summary: extractSummary(textContent),\r\n tokensUsed: totalTokensUsed,\r\n durationMs: Date.now() - startTime,\r\n };\r\n }\r\n\r\n // Process tool calls\r\n if (response.stop_reason === \"tool_use\") {\r\n const toolResultBlocks: LLMContentBlock[] = [];\r\n\r\n for (const block of assistantContent) {\r\n if (block.type === \"tool_use\") {\r\n const toolName = block.name!;\r\n const toolInput = block.input as Record<string, unknown>;\r\n\r\n console.log(`[Agent ${agentId}] Using tool: ${toolName}`);\r\n\r\n // Risk engine gate: evaluate before executing any tool from an agent\r\n const riskDecision = await riskEngine.evaluate({\r\n action: \"agent_tool_execute\",\r\n userId,\r\n toolName,\r\n input: toolInput,\r\n metadata: { agentId, agentType: type },\r\n });\r\n\r\n if (!riskDecision.allowed) {\r\n const failedChecks = riskDecision.checks\r\n .filter((c) => !c.passed)\r\n .map((c) => c.message)\r\n .join(\"; \");\r\n const result = {\r\n success: false,\r\n result: null,\r\n error: `[RiskEngine] Agent tool blocked: ${failedChecks}`,\r\n };\r\n\r\n await addAgentMessage(agentId, {\r\n role: \"tool_result\",\r\n content: JSON.stringify({ tool: toolName, result }),\r\n metadata: { toolInput },\r\n });\r\n\r\n toolResultBlocks.push({\r\n type: \"tool_result\",\r\n tool_use_id: block.id!,\r\n content: JSON.stringify(result),\r\n });\r\n continue;\r\n }\r\n\r\n // Inject caller context for financial tools\r\n if (toolName === \"crypto_exchange\") {\r\n toolInput._callerContext = \"agent\";\r\n }\r\n\r\n // Execute tool\r\n const result = await executeTool(toolName, toolInput);\r\n\r\n await addAgentMessage(agentId, {\r\n role: \"tool_result\",\r\n content: JSON.stringify({ tool: toolName, result }),\r\n metadata: { toolInput },\r\n });\r\n\r\n toolResultBlocks.push({\r\n type: \"tool_result\",\r\n tool_use_id: block.id!,\r\n content: JSON.stringify(result),\r\n });\r\n }\r\n }\r\n\r\n // Add assistant response and tool results to messages\r\n messages.push({ role: \"assistant\", content: assistantContent });\r\n messages.push({ role: \"user\", content: toolResultBlocks });\r\n }\r\n\r\n stepNumber++;\r\n }\r\n\r\n // Max steps reached\r\n const agent = await getAgent(agentId);\r\n const lastMessage = agent?.messages.slice(-1)[0]?.content || \"\";\r\n\r\n return {\r\n success: true,\r\n output: lastMessage,\r\n summary: \"Agent completed maximum steps\",\r\n tokensUsed: totalTokensUsed,\r\n durationMs: Date.now() - startTime,\r\n };\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : String(error);\r\n\r\n await captureException(error, \"agent\", {\r\n agentId,\r\n type,\r\n objective,\r\n }, userId);\r\n\r\n await addAgentProgress(\r\n agentId,\r\n stepNumber,\r\n `Error: ${errorMessage}`,\r\n \"failed\"\r\n );\r\n\r\n return {\r\n success: false,\r\n error: errorMessage,\r\n tokensUsed: totalTokensUsed,\r\n durationMs: Date.now() - startTime,\r\n };\r\n }\r\n}\r\n\r\nfunction buildSystemPrompt(\r\n type: AgentType,\r\n context?: Record<string, unknown>\r\n): string {\r\n let prompt = AGENT_SYSTEM_PROMPTS[type];\r\n\r\n if (context) {\r\n prompt += `\\n\\nAdditional context about the user/task:\\n${JSON.stringify(context, null, 2)}`;\r\n }\r\n\r\n return prompt;\r\n}\r\n\r\nfunction extractSummary(text: string): string {\r\n // Try to find a summary section\r\n const summaryMatch = text.match(/(?:summary|conclusion|result):\\s*(.+?)(?:\\n\\n|$)/i);\r\n if (summaryMatch) {\r\n return summaryMatch[1].trim();\r\n }\r\n\r\n // Otherwise, take the last paragraph\r\n const paragraphs = text.split(\"\\n\\n\").filter((p) => p.trim());\r\n return paragraphs.slice(-1)[0]?.slice(0, 500) || text.slice(0, 500);\r\n}\r\n\r\n// Start the agent worker\r\nexport function startAgentWorker(): void {\r\n if (worker) return;\r\n\r\n worker = new Worker(\r\n \"sentinel-agents\",\r\n async (job: Job<AgentJobData>) => {\r\n const result = await processAgentTask(job);\r\n\r\n // Update final status\r\n await updateAgentStatus(\r\n job.data.agentId,\r\n result.success ? \"completed\" : \"failed\",\r\n result\r\n );\r\n\r\n // Record metric\r\n metric.agentOperation(\"complete\", job.data.type);\r\n\r\n return result;\r\n },\r\n {\r\n connection,\r\n concurrency: 3, // Run up to 3 agents concurrently\r\n }\r\n );\r\n\r\n worker.on(\"completed\", (job) => {\r\n console.log(`[AgentWorker] Agent completed: ${job.data.agentId}`);\r\n });\r\n\r\n worker.on(\"failed\", (job, err) => {\r\n console.error(`[AgentWorker] Agent failed: ${job?.data.agentId}`, err);\r\n });\r\n\r\n console.log(\"[AgentWorker] Agent worker started\");\r\n}\r\n\r\n// Stop the agent worker\r\nexport function stopAgentWorker(): void {\r\n if (worker) {\r\n worker.close();\r\n worker = null;\r\n }\r\n}\r\n\r\nexport default {\r\n startAgentWorker,\r\n stopAgentWorker,\r\n};\r\n","import { db } from \"../../db\";\nimport { calendarTriggers, users } from \"../../db/schema\";\nimport { eq, and, lte, gte, isNull } from \"drizzle-orm\";\nimport { scheduleTask } from \"../../core/scheduler\";\nimport {\n fetchICalFromUrl,\n CalendarEvent,\n getUpcomingEvents,\n getTodaysEvents,\n} from \"./ical-parser\";\n\nexport type TriggerType = \"event_start\" | \"event_end\" | \"daily_briefing\";\nexport type CalendarSource = \"google\" | \"outlook\" | \"ical\";\n\nexport interface CalendarTriggerConfig {\n id: string;\n userId: string;\n name: string;\n calendarSource: CalendarSource;\n calendarId?: string;\n triggerType: TriggerType;\n offsetMinutes: number;\n action: {\n type: \"message\" | \"tool\" | \"webhook\";\n payload: Record<string, unknown>;\n };\n enabled: boolean;\n}\n\nexport interface TriggerResult {\n triggerId: string;\n event?: CalendarEvent;\n scheduledJobId?: string;\n error?: string;\n}\n\n// Create a calendar trigger\nexport async function createCalendarTrigger(\n config: Omit<CalendarTriggerConfig, \"id\">\n): Promise<string> {\n const [trigger] = await db\n .insert(calendarTriggers)\n .values({\n userId: config.userId,\n name: config.name,\n calendarSource: config.calendarSource,\n calendarId: config.calendarId,\n triggerType: config.triggerType,\n offsetMinutes: config.offsetMinutes,\n action: config.action,\n enabled: config.enabled,\n })\n .returning();\n\n return trigger.id;\n}\n\n// Get user's calendar triggers\nexport async function getUserTriggers(\n userId: string\n): Promise<CalendarTriggerConfig[]> {\n const triggers = await db\n .select()\n .from(calendarTriggers)\n .where(eq(calendarTriggers.userId, userId));\n\n return triggers.map((t) => ({\n id: t.id,\n userId: t.userId,\n name: t.name,\n calendarSource: t.calendarSource as CalendarSource,\n calendarId: t.calendarId || undefined,\n triggerType: t.triggerType as TriggerType,\n offsetMinutes: t.offsetMinutes || 0,\n action: t.action as CalendarTriggerConfig[\"action\"],\n enabled: t.enabled ?? true,\n }));\n}\n\n// Enable/disable a trigger\nexport async function setTriggerEnabled(\n triggerId: string,\n enabled: boolean\n): Promise<boolean> {\n const [updated] = await db\n .update(calendarTriggers)\n .set({ enabled })\n .where(eq(calendarTriggers.id, triggerId))\n .returning();\n\n return !!updated;\n}\n\n// Delete a trigger\nexport async function deleteTrigger(triggerId: string): Promise<boolean> {\n await db.delete(calendarTriggers).where(eq(calendarTriggers.id, triggerId));\n return true;\n}\n\n// Process triggers for upcoming events\nexport async function processCalendarTriggers(\n userId: string,\n events: CalendarEvent[],\n chatId?: string\n): Promise<TriggerResult[]> {\n const triggers = await getUserTriggers(userId);\n const enabledTriggers = triggers.filter((t) => t.enabled);\n const results: TriggerResult[] = [];\n const now = Date.now();\n\n for (const trigger of enabledTriggers) {\n try {\n if (trigger.triggerType === \"daily_briefing\") {\n // Handle daily briefing separately\n continue;\n }\n\n for (const event of events) {\n const eventTime =\n trigger.triggerType === \"event_start\"\n ? event.startDate.getTime()\n : event.endDate.getTime();\n\n const triggerTime = eventTime - trigger.offsetMinutes * 60 * 1000;\n\n // Only schedule if trigger time is in the future\n if (triggerTime > now) {\n const delay = triggerTime - now;\n\n const jobId = await scheduleTask(\n {\n type: \"custom\",\n message: formatTriggerMessage(trigger, event),\n userId,\n chatId,\n },\n delay\n );\n\n results.push({\n triggerId: trigger.id,\n event,\n scheduledJobId: jobId,\n });\n\n // Update last triggered\n await db\n .update(calendarTriggers)\n .set({ lastTriggered: new Date() })\n .where(eq(calendarTriggers.id, trigger.id));\n }\n }\n } catch (error) {\n results.push({\n triggerId: trigger.id,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return results;\n}\n\nfunction formatTriggerMessage(\n trigger: CalendarTriggerConfig,\n event: CalendarEvent\n): string {\n const timeStr = event.startDate.toLocaleTimeString([], {\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n\n if (trigger.triggerType === \"event_start\") {\n if (trigger.offsetMinutes > 0) {\n return `⏰ Reminder: \"${event.summary}\" starts in ${trigger.offsetMinutes} minutes at ${timeStr}`;\n }\n return `🔔 \"${event.summary}\" is starting now!`;\n }\n\n if (trigger.triggerType === \"event_end\") {\n return `✅ \"${event.summary}\" has ended`;\n }\n\n return `📅 Calendar event: ${event.summary}`;\n}\n\n// Generate daily briefing from calendar\nexport async function generateDailyBriefing(\n userId: string,\n events: CalendarEvent[]\n): Promise<string> {\n const todayEvents = getTodaysEvents(events);\n const upcomingEvents = getUpcomingEvents(events, 5);\n\n let briefing = \"📅 **Your Daily Calendar Briefing**\\n\\n\";\n\n if (todayEvents.length === 0) {\n briefing += \"No events scheduled for today.\\n\\n\";\n } else {\n briefing += `**Today's Events (${todayEvents.length}):**\\n`;\n for (const event of todayEvents) {\n const timeStr = event.isAllDay\n ? \"All day\"\n : event.startDate.toLocaleTimeString([], {\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n briefing += `• ${timeStr}: ${event.summary}`;\n if (event.location) {\n briefing += ` @ ${event.location}`;\n }\n briefing += \"\\n\";\n }\n briefing += \"\\n\";\n }\n\n const futureEvents = upcomingEvents.filter(\n (e) => !todayEvents.some((t) => t.uid === e.uid)\n );\n\n if (futureEvents.length > 0) {\n briefing += \"**Upcoming:**\\n\";\n for (const event of futureEvents.slice(0, 3)) {\n const dateStr = event.startDate.toLocaleDateString([], {\n weekday: \"short\",\n month: \"short\",\n day: \"numeric\",\n });\n briefing += `• ${dateStr}: ${event.summary}\\n`;\n }\n }\n\n return briefing;\n}\n\n// Sync calendar and process triggers\nexport async function syncCalendarAndTriggers(\n userId: string,\n icalUrl: string,\n chatId?: string\n): Promise<{\n eventsFound: number;\n triggersScheduled: number;\n errors: string[];\n}> {\n const errors: string[] = [];\n let eventsFound = 0;\n let triggersScheduled = 0;\n\n try {\n const calendar = await fetchICalFromUrl(icalUrl);\n eventsFound = calendar.events.length;\n\n // Get events for next 24 hours\n const now = new Date();\n const tomorrow = new Date(now.getTime() + 24 * 60 * 60 * 1000);\n const upcomingEvents = calendar.events.filter(\n (e) => e.startDate >= now && e.startDate <= tomorrow\n );\n\n const results = await processCalendarTriggers(userId, upcomingEvents, chatId);\n triggersScheduled = results.filter((r) => r.scheduledJobId).length;\n errors.push(...results.filter((r) => r.error).map((r) => r.error!));\n } catch (error) {\n errors.push(error instanceof Error ? error.message : String(error));\n }\n\n return { eventsFound, triggersScheduled, errors };\n}\n\nexport default {\n createCalendarTrigger,\n getUserTriggers,\n setTriggerEnabled,\n deleteTrigger,\n processCalendarTriggers,\n generateDailyBriefing,\n syncCalendarAndTriggers,\n};\n","import { db } from \"../../db\";\r\nimport { memories, archivedMemories } from \"../../db/schema\";\r\nimport { eq, and, lt, lte, sql } from \"drizzle-orm\";\r\n\r\nexport type ShedReason =\r\n | \"stale\"\r\n | \"duplicate\"\r\n | \"low_importance\"\r\n | \"user_request\"\r\n | \"deprecated_workflow\";\r\n\r\nexport interface ShedCandidate {\r\n memoryId: string;\r\n content: string;\r\n type: string;\r\n reason: ShedReason;\r\n lastAccessed: Date | null;\r\n importance: number;\r\n confidence: number; // How confident we are this should be shed (0-100)\r\n}\r\n\r\nexport interface ShedResult {\r\n archivedCount: number;\r\n archivedIds: string[];\r\n skippedCount: number;\r\n}\r\n\r\n// Configuration for memory shedding\r\nconst SHED_CONFIG = {\r\n staleDays: 90, // Memories not accessed in 90 days\r\n lowImportanceThreshold: 3, // Memories with importance <= 3\r\n minConfidence: 70, // Minimum confidence to auto-shed\r\n};\r\n\r\n// Find stale memories (not accessed recently)\r\nexport async function findStaleMemories(\r\n userId: string,\r\n staleDays: number = SHED_CONFIG.staleDays\r\n): Promise<ShedCandidate[]> {\r\n const cutoff = new Date(Date.now() - staleDays * 24 * 60 * 60 * 1000);\r\n\r\n const stale = await db\r\n .select()\r\n .from(memories)\r\n .where(\r\n and(\r\n eq(memories.userId, userId),\r\n lt(memories.lastAccessed, cutoff)\r\n )\r\n );\r\n\r\n return stale.map((m) => ({\r\n memoryId: m.id,\r\n content: m.content,\r\n type: m.type,\r\n reason: \"stale\" as ShedReason,\r\n lastAccessed: m.lastAccessed,\r\n importance: m.importance || 5,\r\n confidence: calculateStaleConfidence(m.lastAccessed, m.importance || 5),\r\n }));\r\n}\r\n\r\nfunction calculateStaleConfidence(\r\n lastAccessed: Date | null,\r\n importance: number\r\n): number {\r\n if (!lastAccessed) return 80;\r\n\r\n const daysSinceAccess = Math.floor(\r\n (Date.now() - lastAccessed.getTime()) / (24 * 60 * 60 * 1000)\r\n );\r\n\r\n // Higher confidence for older, less important memories\r\n let confidence = Math.min(daysSinceAccess / 2, 50); // Max 50 from age\r\n confidence += (10 - importance) * 5; // Up to 50 from low importance\r\n\r\n return Math.min(confidence, 100);\r\n}\r\n\r\n// Find low importance memories\r\nexport async function findLowImportanceMemories(\r\n userId: string,\r\n threshold: number = SHED_CONFIG.lowImportanceThreshold\r\n): Promise<ShedCandidate[]> {\r\n const lowImportance = await db\r\n .select()\r\n .from(memories)\r\n .where(\r\n and(\r\n eq(memories.userId, userId),\r\n lte(memories.importance, threshold)\r\n )\r\n );\r\n\r\n return lowImportance.map((m) => ({\r\n memoryId: m.id,\r\n content: m.content,\r\n type: m.type,\r\n reason: \"low_importance\" as ShedReason,\r\n lastAccessed: m.lastAccessed,\r\n importance: m.importance || 5,\r\n confidence: (SHED_CONFIG.lowImportanceThreshold - (m.importance || 5) + 1) * 25,\r\n }));\r\n}\r\n\r\n// Find potential duplicate memories (simplified - would need better NLP in production)\r\nexport async function findDuplicateMemories(\r\n userId: string\r\n): Promise<ShedCandidate[]> {\r\n const allMemories = await db\r\n .select()\r\n .from(memories)\r\n .where(eq(memories.userId, userId));\r\n\r\n const candidates: ShedCandidate[] = [];\r\n const seen = new Map<string, typeof allMemories[0]>();\r\n\r\n for (const memory of allMemories) {\r\n // Simple duplicate detection: normalize and check for similar content\r\n const normalized = memory.content.toLowerCase().trim();\r\n const key = normalized.slice(0, 100); // Use first 100 chars as key\r\n\r\n const existing = seen.get(key);\r\n if (existing) {\r\n // Mark the newer one as duplicate (keep older memories)\r\n const isDuplicate =\r\n memory.createdAt > existing.createdAt ? memory : existing;\r\n\r\n candidates.push({\r\n memoryId: isDuplicate.id,\r\n content: isDuplicate.content,\r\n type: isDuplicate.type,\r\n reason: \"duplicate\",\r\n lastAccessed: isDuplicate.lastAccessed,\r\n importance: isDuplicate.importance || 5,\r\n confidence: 75, // Fairly confident about duplicates\r\n });\r\n } else {\r\n seen.set(key, memory);\r\n }\r\n }\r\n\r\n return candidates;\r\n}\r\n\r\n// Get all shed candidates for a user\r\nexport async function identifyShedCandidates(\r\n userId: string\r\n): Promise<ShedCandidate[]> {\r\n const [stale, lowImportance, duplicates] = await Promise.all([\r\n findStaleMemories(userId),\r\n findLowImportanceMemories(userId),\r\n findDuplicateMemories(userId),\r\n ]);\r\n\r\n // Combine and deduplicate by memoryId\r\n const candidateMap = new Map<string, ShedCandidate>();\r\n\r\n for (const candidate of [...stale, ...lowImportance, ...duplicates]) {\r\n const existing = candidateMap.get(candidate.memoryId);\r\n if (!existing || candidate.confidence > existing.confidence) {\r\n candidateMap.set(candidate.memoryId, candidate);\r\n }\r\n }\r\n\r\n return Array.from(candidateMap.values()).sort(\r\n (a, b) => b.confidence - a.confidence\r\n );\r\n}\r\n\r\n// Archive a single memory\r\nexport async function archiveMemory(\r\n memoryId: string,\r\n reason: ShedReason\r\n): Promise<boolean> {\r\n const [memory] = await db\r\n .select()\r\n .from(memories)\r\n .where(eq(memories.id, memoryId))\r\n .limit(1);\r\n\r\n if (!memory) return false;\r\n\r\n // Insert into archived memories\r\n await db.insert(archivedMemories).values({\r\n originalMemoryId: memory.id,\r\n userId: memory.userId,\r\n type: memory.type,\r\n content: memory.content,\r\n reason,\r\n originalCreatedAt: memory.createdAt,\r\n });\r\n\r\n // Delete from active memories\r\n await db.delete(memories).where(eq(memories.id, memoryId));\r\n\r\n return true;\r\n}\r\n\r\n// Archive multiple memories\r\nexport async function archiveMemories(\r\n memoryIds: string[],\r\n reason: ShedReason\r\n): Promise<ShedResult> {\r\n let archivedCount = 0;\r\n const archivedIds: string[] = [];\r\n\r\n for (const id of memoryIds) {\r\n const success = await archiveMemory(id, reason);\r\n if (success) {\r\n archivedCount++;\r\n archivedIds.push(id);\r\n }\r\n }\r\n\r\n return {\r\n archivedCount,\r\n archivedIds,\r\n skippedCount: memoryIds.length - archivedCount,\r\n };\r\n}\r\n\r\n// Auto-shed memories based on confidence threshold\r\nexport async function autoShed(\r\n userId: string,\r\n minConfidence: number = SHED_CONFIG.minConfidence\r\n): Promise<ShedResult> {\r\n const candidates = await identifyShedCandidates(userId);\r\n const toArchive = candidates.filter((c) => c.confidence >= minConfidence);\r\n\r\n const results: ShedResult = {\r\n archivedCount: 0,\r\n archivedIds: [],\r\n skippedCount: 0,\r\n };\r\n\r\n for (const candidate of toArchive) {\r\n const success = await archiveMemory(candidate.memoryId, candidate.reason);\r\n if (success) {\r\n results.archivedCount++;\r\n results.archivedIds.push(candidate.memoryId);\r\n } else {\r\n results.skippedCount++;\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\n// Restore an archived memory\r\nexport async function restoreMemory(archivedId: string): Promise<boolean> {\r\n const [archived] = await db\r\n .select()\r\n .from(archivedMemories)\r\n .where(eq(archivedMemories.id, archivedId))\r\n .limit(1);\r\n\r\n if (!archived) return false;\r\n\r\n // Re-insert into active memories (without embedding - would need to regenerate)\r\n await db.insert(memories).values({\r\n userId: archived.userId,\r\n type: archived.type as \"episodic\" | \"semantic\" | \"procedural\",\r\n content: archived.content,\r\n importance: 5, // Reset to medium importance\r\n source: \"restored\",\r\n });\r\n\r\n // Remove from archive\r\n await db.delete(archivedMemories).where(eq(archivedMemories.id, archivedId));\r\n\r\n return true;\r\n}\r\n\r\n// Get archived memories for a user\r\nexport async function getArchivedMemories(\r\n userId: string,\r\n limit: number = 50\r\n): Promise<typeof archivedMemories.$inferSelect[]> {\r\n return db\r\n .select()\r\n .from(archivedMemories)\r\n .where(eq(archivedMemories.userId, userId))\r\n .limit(limit);\r\n}\r\n\r\n// Get shedding statistics\r\nexport async function getShedStats(\r\n userId: string\r\n): Promise<{\r\n totalArchived: number;\r\n byReason: Record<ShedReason, number>;\r\n pendingCandidates: number;\r\n}> {\r\n const archived = await getArchivedMemories(userId, 1000);\r\n const candidates = await identifyShedCandidates(userId);\r\n\r\n const byReason: Record<ShedReason, number> = {\r\n stale: 0,\r\n duplicate: 0,\r\n low_importance: 0,\r\n user_request: 0,\r\n deprecated_workflow: 0,\r\n };\r\n\r\n for (const memory of archived) {\r\n const reason = memory.reason as ShedReason;\r\n if (reason in byReason) {\r\n byReason[reason]++;\r\n }\r\n }\r\n\r\n return {\r\n totalArchived: archived.length,\r\n byReason,\r\n pendingCandidates: candidates.length,\r\n };\r\n}\r\n\r\n// Cleanup old archives (permanent deletion)\r\nexport async function cleanupOldArchives(\r\n daysToKeep: number = 365\r\n): Promise<number> {\r\n const cutoff = new Date(Date.now() - daysToKeep * 24 * 60 * 60 * 1000);\r\n\r\n await db\r\n .delete(archivedMemories)\r\n .where(lt(archivedMemories.archivedAt, cutoff));\r\n\r\n return 0; // Cleanup completed\r\n}\r\n","import { generateGrowthReport, getEvolutionSnapshot } from \"./evolution-tracker\";\r\nimport { getUserAchievements, checkAchievements, getUserPoints, getAchievementProgress } from \"./achievement-system\";\r\nimport { getModeStats, getCurrentMode } from \"./mode-manager\";\r\nimport { getShedStats } from \"./memory-shedder\";\r\n\r\nexport interface GrowthReport {\r\n period: {\r\n type: \"weekly\" | \"monthly\";\r\n start: Date;\r\n end: Date;\r\n };\r\n summary: string;\r\n metrics: {\r\n conversations: number;\r\n messages: number;\r\n toolUses: number;\r\n newMemories: number;\r\n archivedMemories: number;\r\n };\r\n achievements: {\r\n newlyUnlocked: Array<{ name: string; emoji: string; points: number }>;\r\n totalPoints: number;\r\n pointsGained: number;\r\n };\r\n modeUsage: Record<string, { sessions: number; minutes: number }>;\r\n highlights: string[];\r\n suggestions: string[];\r\n}\r\n\r\n// Generate a weekly growth report\r\nexport async function generateWeeklyReport(userId: string): Promise<GrowthReport> {\r\n const endDate = new Date();\r\n const startDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);\r\n\r\n return generateReport(userId, startDate, endDate, \"weekly\");\r\n}\r\n\r\n// Generate a monthly growth report\r\nexport async function generateMonthlyReport(userId: string): Promise<GrowthReport> {\r\n const endDate = new Date();\r\n const startDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);\r\n\r\n return generateReport(userId, startDate, endDate, \"monthly\");\r\n}\r\n\r\nasync function generateReport(\r\n userId: string,\r\n startDate: Date,\r\n endDate: Date,\r\n type: \"weekly\" | \"monthly\"\r\n): Promise<GrowthReport> {\r\n // Get growth data\r\n const growthData = await generateGrowthReport(userId, startDate, endDate);\r\n\r\n // Check for new achievements\r\n const newAchievements = await checkAchievements(userId);\r\n const totalPoints = await getUserPoints(userId);\r\n\r\n // Get mode stats\r\n const modeStats = await getModeStats(userId);\r\n\r\n // Get shed stats\r\n const shedStats = await getShedStats(userId);\r\n\r\n // Generate highlights\r\n const highlights = generateHighlights(growthData, newAchievements);\r\n\r\n // Generate suggestions\r\n const suggestions = await generateSuggestions(userId, growthData);\r\n\r\n // Generate summary\r\n const summary = generateSummary(growthData, newAchievements, type);\r\n\r\n return {\r\n period: {\r\n type,\r\n start: startDate,\r\n end: endDate,\r\n },\r\n summary,\r\n metrics: {\r\n conversations: growthData.metrics.conversations,\r\n messages: growthData.metrics.messages,\r\n toolUses: growthData.metrics.toolUses,\r\n newMemories: growthData.metrics.newMemories,\r\n archivedMemories: shedStats.totalArchived,\r\n },\r\n achievements: {\r\n newlyUnlocked: newAchievements.map((a) => ({\r\n name: a.name,\r\n emoji: a.iconEmoji,\r\n points: a.points,\r\n })),\r\n totalPoints,\r\n pointsGained: newAchievements.reduce((sum, a) => sum + a.points, 0),\r\n },\r\n modeUsage: {\r\n productivity: { sessions: modeStats.productivity.totalSessions, minutes: modeStats.productivity.totalMinutes },\r\n creative: { sessions: modeStats.creative.totalSessions, minutes: modeStats.creative.totalMinutes },\r\n research: { sessions: modeStats.research.totalSessions, minutes: modeStats.research.totalMinutes },\r\n learning: { sessions: modeStats.learning.totalSessions, minutes: modeStats.learning.totalMinutes },\r\n },\r\n highlights,\r\n suggestions,\r\n };\r\n}\r\n\r\nfunction generateHighlights(\r\n growthData: Awaited<ReturnType<typeof generateGrowthReport>>,\r\n newAchievements: Array<{ name: string; iconEmoji: string }>\r\n): string[] {\r\n const highlights: string[] = [];\r\n\r\n if (growthData.metrics.conversations > 0) {\r\n highlights.push(\r\n `You had ${growthData.metrics.conversations} conversations this period!`\r\n );\r\n }\r\n\r\n if (growthData.metrics.toolUses > 10) {\r\n highlights.push(\r\n `Power user alert! You used tools ${growthData.metrics.toolUses} times.`\r\n );\r\n }\r\n\r\n if (growthData.metrics.newMemories > 5) {\r\n highlights.push(\r\n `I learned ${growthData.metrics.newMemories} new things about you.`\r\n );\r\n }\r\n\r\n for (const achievement of newAchievements) {\r\n highlights.push(\r\n `${achievement.iconEmoji} Achievement unlocked: ${achievement.name}!`\r\n );\r\n }\r\n\r\n if (growthData.patterns.length > 0) {\r\n const topPattern = growthData.patterns[0];\r\n highlights.push(\r\n `New pattern detected: You frequently use ${topPattern.key}.`\r\n );\r\n }\r\n\r\n return highlights;\r\n}\r\n\r\nasync function generateSuggestions(\r\n userId: string,\r\n growthData: Awaited<ReturnType<typeof generateGrowthReport>>\r\n): Promise<string[]> {\r\n const suggestions: string[] = [];\r\n\r\n // Check achievement progress\r\n const progress = await getAchievementProgress(userId);\r\n const almostUnlocked = progress.filter(\r\n (p) => p.progress / p.target >= 0.7 && p.progress / p.target < 1\r\n );\r\n\r\n for (const achievement of almostUnlocked.slice(0, 2)) {\r\n const remaining = achievement.target - achievement.progress;\r\n suggestions.push(\r\n `You're close to unlocking \"${achievement.achievement.name}\"! Just ${remaining} more ${achievement.achievement.criteria.metric}.`\r\n );\r\n }\r\n\r\n // Suggest mode if not used\r\n const currentMode = await getCurrentMode(userId);\r\n if (!currentMode) {\r\n suggestions.push(\r\n \"Try activating a transformation mode! Say 'switch to productivity mode' to get started.\"\r\n );\r\n }\r\n\r\n // Suggest based on low activity\r\n if (growthData.metrics.toolUses < 5) {\r\n suggestions.push(\r\n \"You haven't used many tools this period. Try asking me to search the web, browse a page, or run a command!\"\r\n );\r\n }\r\n\r\n return suggestions;\r\n}\r\n\r\nfunction generateSummary(\r\n growthData: Awaited<ReturnType<typeof generateGrowthReport>>,\r\n newAchievements: Array<{ name: string }>,\r\n type: \"weekly\" | \"monthly\"\r\n): string {\r\n const period = type === \"weekly\" ? \"this week\" : \"this month\";\r\n\r\n let summary = `Here's your ${type} growth report! `;\r\n\r\n if (growthData.metrics.conversations > 0) {\r\n summary += `You've been active with ${growthData.metrics.conversations} conversations ${period}. `;\r\n } else {\r\n summary += `I missed you ${period}! Let's catch up. `;\r\n }\r\n\r\n if (newAchievements.length > 0) {\r\n summary += `You unlocked ${newAchievements.length} new achievement${newAchievements.length > 1 ? \"s\" : \"\"}! `;\r\n }\r\n\r\n if (growthData.metrics.newMemories > 0) {\r\n summary += `I've been learning about you - ${growthData.metrics.newMemories} new memories stored. `;\r\n }\r\n\r\n return summary.trim();\r\n}\r\n\r\n// Format report as text for Telegram/display\r\nexport function formatReportAsText(report: GrowthReport): string {\r\n let text = `📊 **${report.period.type === \"weekly\" ? \"Weekly\" : \"Monthly\"} Growth Report**\\n\\n`;\r\n\r\n text += `${report.summary}\\n\\n`;\r\n\r\n text += `**📈 Activity**\\n`;\r\n text += `• Conversations: ${report.metrics.conversations}\\n`;\r\n text += `• Messages: ${report.metrics.messages}\\n`;\r\n text += `• Tool uses: ${report.metrics.toolUses}\\n`;\r\n text += `• New memories: ${report.metrics.newMemories}\\n\\n`;\r\n\r\n if (report.achievements.newlyUnlocked.length > 0) {\r\n text += `**🏆 New Achievements**\\n`;\r\n for (const achievement of report.achievements.newlyUnlocked) {\r\n text += `${achievement.emoji} ${achievement.name} (+${achievement.points} pts)\\n`;\r\n }\r\n text += `\\nTotal points: ${report.achievements.totalPoints}\\n\\n`;\r\n }\r\n\r\n if (report.highlights.length > 0) {\r\n text += `**✨ Highlights**\\n`;\r\n for (const highlight of report.highlights) {\r\n text += `• ${highlight}\\n`;\r\n }\r\n text += `\\n`;\r\n }\r\n\r\n if (report.suggestions.length > 0) {\r\n text += `**💡 Suggestions**\\n`;\r\n for (const suggestion of report.suggestions) {\r\n text += `• ${suggestion}\\n`;\r\n }\r\n }\r\n\r\n return text;\r\n}\r\n\r\n// Schedule report generation (to be called from scheduler)\r\nexport async function scheduleReportGeneration(\r\n userId: string,\r\n type: \"weekly\" | \"monthly\",\r\n chatId: string\r\n): Promise<{ report: GrowthReport; formattedText: string }> {\r\n const report =\r\n type === \"weekly\"\r\n ? await generateWeeklyReport(userId)\r\n : await generateMonthlyReport(userId);\r\n\r\n const formattedText = formatReportAsText(report);\r\n\r\n return { report, formattedText };\r\n}\r\n"],"mappings":"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","names":["Worker","Redis","result","eq","and","lte","eq","Redis","connection","worker","Worker"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  env
3
- } from "./chunk-PUNIMPMY.js";
3
+ } from "./chunk-4KIHDIXZ.js";
4
4
  import {
5
5
  OpenAICompatibleProvider
6
6
  } from "./chunk-35WYTA3C.js";
@@ -433,4 +433,4 @@ export {
433
433
  providerRegistry,
434
434
  initializeProviders
435
435
  };
436
- //# sourceMappingURL=chunk-HTF2GIQC.js.map
436
+ //# sourceMappingURL=chunk-GW6V4D43.js.map