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.
- package/README.md +12 -0
- package/dist/{agent-manager-7N7REQZQ.js → agent-manager-JZ4IM7XI.js} +8 -8
- package/dist/{agent-processor-I23VWQY3.js → agent-processor-DDDHC2SO.js} +22 -21
- package/dist/{agent-processor-I23VWQY3.js.map → agent-processor-DDDHC2SO.js.map} +1 -1
- package/dist/{alerting-4I37GG4U.js → alerting-LK7VVYTX.js} +4 -4
- package/dist/alerting-LK7VVYTX.js.map +1 -0
- package/dist/analyzer-OTWE3ARE.js +22 -0
- package/dist/{archiver-XLRIIXPY.js → archiver-FPGKRP6P.js} +16 -85
- package/dist/archiver-FPGKRP6P.js.map +1 -0
- package/dist/{audit-logger-AU3TMWKI.js → audit-logger-CI4WZQPD.js} +5 -5
- package/dist/bot-VDHBGUVI.js +47 -0
- package/dist/{brain-SLA474EU.js → brain-6QTXN4QP.js} +18 -17
- package/dist/{chunk-AR34B6XR.js → chunk-2I5QHYG6.js} +3 -3
- package/dist/chunk-2I5QHYG6.js.map +1 -0
- package/dist/chunk-3AWAWRWB.js +143 -0
- package/dist/chunk-3AWAWRWB.js.map +1 -0
- package/dist/{chunk-PUNIMPMY.js → chunk-4KIHDIXZ.js} +13 -2
- package/dist/chunk-4KIHDIXZ.js.map +1 -0
- package/dist/{chunk-GUKKW7JI.js → chunk-4WH6MFEW.js} +2 -2
- package/dist/chunk-4WH6MFEW.js.map +1 -0
- package/dist/{chunk-M7YLQHFP.js → chunk-56UJS2LA.js} +6 -6
- package/dist/{chunk-S4NJJS5C.js → chunk-5BTVJR7R.js} +3 -3
- package/dist/{chunk-HKOPRRDJ.js → chunk-5JJTLWOR.js} +3 -3
- package/dist/chunk-5JJTLWOR.js.map +1 -0
- package/dist/chunk-66SAOZPU.js +236 -0
- package/dist/chunk-66SAOZPU.js.map +1 -0
- package/dist/chunk-6HGMRR4J.js +113 -0
- package/dist/chunk-6HGMRR4J.js.map +1 -0
- package/dist/{chunk-BMOUYXLX.js → chunk-6ZNCY2GI.js} +5 -5
- package/dist/chunk-7BNFELEK.js +31 -0
- package/dist/chunk-7BNFELEK.js.map +1 -0
- package/dist/{chunk-KABG5PG3.js → chunk-BBN4VCNK.js} +4 -4
- package/dist/chunk-BBN4VCNK.js.map +1 -0
- package/dist/{chunk-4YJRBMMA.js → chunk-BNZHWAZC.js} +2 -2
- package/dist/{chunk-TAAZB5KN.js → chunk-CWT6CAE5.js} +2 -2
- package/dist/{chunk-UWUIJTT4.js → chunk-CZTMGHUC.js} +1 -1
- package/dist/chunk-CZTMGHUC.js.map +1 -0
- package/dist/chunk-DTISLIMB.js +89 -0
- package/dist/chunk-DTISLIMB.js.map +1 -0
- package/dist/{chunk-VKMFUIVA.js → chunk-GBVJTRXS.js} +2 -2
- package/dist/{chunk-MFK34XSY.js → chunk-GJETKBOY.js} +15 -15
- package/dist/chunk-GJETKBOY.js.map +1 -0
- package/dist/{chunk-HTF2GIQC.js → chunk-GW6V4D43.js} +2 -2
- package/dist/chunk-GW6V4D43.js.map +1 -0
- package/dist/{chunk-2RGPWU77.js → chunk-HJSEEFO3.js} +2 -2
- package/dist/{chunk-JOA5A3G3.js → chunk-HQZQFEAX.js} +5 -5
- package/dist/{chunk-45YXODSB.js → chunk-J4JW73TT.js} +2 -2
- package/dist/{chunk-KT7NLIXP.js → chunk-JHYYFPKX.js} +2 -2
- package/dist/{chunk-XMCVRVTF.js → chunk-P64EV4YY.js} +1 -1
- package/dist/chunk-P64EV4YY.js.map +1 -0
- package/dist/chunk-PBOCSGNL.js +84 -0
- package/dist/chunk-PBOCSGNL.js.map +1 -0
- package/dist/{chunk-H3BOLSTS.js → chunk-PD3CTDO6.js} +2 -2
- package/dist/{chunk-6UZPE35A.js → chunk-QPY3WRVM.js} +10 -87
- package/dist/chunk-QPY3WRVM.js.map +1 -0
- package/dist/{chunk-AD6YEH6U.js → chunk-S2EOIVF4.js} +590 -91
- package/dist/chunk-S2EOIVF4.js.map +1 -0
- package/dist/chunk-SDLOMKCW.js +213 -0
- package/dist/chunk-SDLOMKCW.js.map +1 -0
- package/dist/{chunk-7MZN73J2.js → chunk-TKBVW7ZJ.js} +4 -4
- package/dist/{chunk-A24GPVLY.js → chunk-V3OKHQUX.js} +5 -5
- package/dist/{chunk-NMSHVO5O.js → chunk-WMDVOWN6.js} +4 -4
- package/dist/{chunk-643M3AP5.js → chunk-WMFYI7XC.js} +7 -7
- package/dist/{chunk-6LTLIYAQ.js → chunk-YEDEAX6Y.js} +3 -3
- package/dist/{chunk-NYVBXUGD.js → chunk-ZIBRVA3Y.js} +60 -1
- package/dist/chunk-ZIBRVA3Y.js.map +1 -0
- package/dist/{chunk-6JY4HNUH.js → chunk-ZMML6T63.js} +361 -24
- package/dist/chunk-ZMML6T63.js.map +1 -0
- package/dist/{chunk-FFV2SXFD.js → chunk-ZVHG4KF2.js} +4 -4
- package/dist/cli.js.map +1 -1
- package/dist/commands/setup.js +1 -1
- package/dist/commands/start.js +2 -2
- package/dist/commands/status.js +1 -1
- package/dist/commands/stop.js +1 -1
- package/dist/commands/utils.js +1 -1
- package/dist/{cost-tracker-EMOIOYH7.js → cost-tracker-KZQSTSE2.js} +2 -2
- package/dist/{db-LRIOKQBO.js → db-I7MNG6CL.js} +10 -4
- package/dist/{discord-NKR3X4AV.js → discord-6UQHCN27.js} +24 -23
- package/dist/{documents-EYIYLZK2.js → documents-PFHSK7SZ.js} +19 -19
- package/dist/{email-EAQNULVD.js → email-6OIN4SYL.js} +22 -21
- package/dist/email-6OIN4SYL.js.map +1 -0
- package/dist/{enhanced-retrieval-OGHT6TS5.js → enhanced-retrieval-JWX2HWU4.js} +7 -6
- package/dist/{enhanced-retrieval-OGHT6TS5.js.map → enhanced-retrieval-JWX2HWU4.js.map} +1 -1
- package/dist/enrichment-pipeline-7FE5R5ZI.js +14 -0
- package/dist/{entity-resolution-4X4JU43O.js → entity-resolution-7Z6STVXX.js} +5 -5
- package/dist/{env-CHOFICED.js → env-GN5VHI43.js} +2 -2
- package/dist/{error-tracker-SVQSDQDW.js → error-tracker-64DEH3D7.js} +6 -6
- package/dist/{github-KGNILDWJ.js → github-DUWSXCNP.js} +4 -4
- package/dist/graph-client-NB475AK5.js +17 -0
- package/dist/{imessage-V2XNDDHT.js → imessage-DSGSGUZS.js} +19 -18
- package/dist/{inbox-summarizer-DKKRYXDR.js → inbox-summarizer-F2KAU72V.js} +19 -18
- package/dist/{incident-response-ZTIKUWEO.js → incident-response-E3UGMX5G.js} +5 -5
- package/dist/incident-response-E3UGMX5G.js.map +1 -0
- package/dist/{knowledge-base-J7PJ7MZ3.js → knowledge-base-5SMMOGQJ.js} +5 -5
- package/dist/lib.d.ts +21 -0
- package/dist/lib.js +64 -57
- package/dist/lib.js.map +1 -1
- package/dist/{matrix-XHTR53VQ.js → matrix-WYGEOZL5.js} +18 -17
- package/dist/{matrix-XHTR53VQ.js.map → matrix-WYGEOZL5.js.map} +1 -1
- package/dist/{mcp-3C2TN67D.js → mcp-DJ2QDA6A.js} +2 -2
- package/dist/{metrics-VJDWQWU7.js → metrics-BH3ZLGEV.js} +5 -5
- package/dist/{multi-user-S56GUD6L.js → multi-user-XAEMB244.js} +4 -4
- package/dist/oauth-UPJYFOVU.js +34 -0
- package/dist/{ocr-LGUIPKVZ.js → ocr-UONKTQU7.js} +4 -4
- package/dist/{presentations-HXTAMGHT.js → presentations-UOET2FVZ.js} +2 -2
- package/dist/{providers-H6YIC3MG.js → providers-2YQ6E3IF.js} +3 -3
- package/dist/{scheduler-CA5UNHZV.js → scheduler-6PLLAQI7.js} +21 -20
- package/dist/{schema-ALJ67YVG.js → schema-ETY7L2VA.js} +8 -2
- package/dist/sharepoint-V5P4Q62L.js +30 -0
- package/dist/{signal-X7IQJGRQ.js → signal-7D5EPGVL.js} +19 -18
- package/dist/{slack-P2LFUJUQ.js → slack-KSS6YK5Z.js} +23 -22
- package/dist/slack-KSS6YK5Z.js.map +1 -0
- package/dist/{sms-4VME2HUL.js → sms-CSUCC7HL.js} +3 -3
- package/dist/sms-CSUCC7HL.js.map +1 -0
- package/dist/{src-S5KX4YEV.js → src-GO7GGW7O.js} +48 -41
- package/dist/{src-S5KX4YEV.js.map → src-GO7GGW7O.js.map} +1 -1
- package/dist/token-store-SEWRX6RE.js +20 -0
- package/dist/token-store-SEWRX6RE.js.map +1 -0
- package/dist/{tools-FGPN522P.js → tools-PJZ6RI4P.js} +18 -17
- package/dist/tools-PJZ6RI4P.js.map +1 -0
- package/dist/{whatsapp-KRPQ4YUX.js → whatsapp-DWXK25V2.js} +19 -18
- package/dist/whatsapp-DWXK25V2.js.map +1 -0
- package/dist/{word-document-D6N2C47N.js → word-document-AV3YB4L2.js} +2 -2
- package/dist/{workflow-store-ZYAYE5P6.js → workflow-store-5Y56GUP7.js} +4 -4
- package/drizzle/0002_mushy_master_mold.sql +139 -139
- package/drizzle/0003_overjoyed_rhodey.sql +46 -0
- package/drizzle/meta/0002_snapshot.json +3636 -3636
- package/drizzle/meta/0003_snapshot.json +3946 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +110 -110
- package/dist/alerting-4I37GG4U.js.map +0 -1
- package/dist/archiver-XLRIIXPY.js.map +0 -1
- package/dist/bot-MU2TJQ3Y.js +0 -46
- package/dist/chunk-6JY4HNUH.js.map +0 -1
- package/dist/chunk-6UZPE35A.js.map +0 -1
- package/dist/chunk-AD6YEH6U.js.map +0 -1
- package/dist/chunk-AR34B6XR.js.map +0 -1
- package/dist/chunk-GUKKW7JI.js.map +0 -1
- package/dist/chunk-HKOPRRDJ.js.map +0 -1
- package/dist/chunk-HTF2GIQC.js.map +0 -1
- package/dist/chunk-KABG5PG3.js.map +0 -1
- package/dist/chunk-MFK34XSY.js.map +0 -1
- package/dist/chunk-NYVBXUGD.js.map +0 -1
- package/dist/chunk-PUNIMPMY.js.map +0 -1
- package/dist/chunk-UWUIJTT4.js.map +0 -1
- package/dist/chunk-XMCVRVTF.js.map +0 -1
- package/dist/email-EAQNULVD.js.map +0 -1
- package/dist/enrichment-pipeline-CMUVBDC7.js +0 -14
- package/dist/incident-response-ZTIKUWEO.js.map +0 -1
- /package/dist/{agent-manager-7N7REQZQ.js.map → agent-manager-JZ4IM7XI.js.map} +0 -0
- /package/dist/{audit-logger-AU3TMWKI.js.map → analyzer-OTWE3ARE.js.map} +0 -0
- /package/dist/{bot-MU2TJQ3Y.js.map → audit-logger-CI4WZQPD.js.map} +0 -0
- /package/dist/{brain-SLA474EU.js.map → bot-VDHBGUVI.js.map} +0 -0
- /package/dist/{cost-tracker-EMOIOYH7.js.map → brain-6QTXN4QP.js.map} +0 -0
- /package/dist/{chunk-M7YLQHFP.js.map → chunk-56UJS2LA.js.map} +0 -0
- /package/dist/{chunk-S4NJJS5C.js.map → chunk-5BTVJR7R.js.map} +0 -0
- /package/dist/{chunk-BMOUYXLX.js.map → chunk-6ZNCY2GI.js.map} +0 -0
- /package/dist/{chunk-4YJRBMMA.js.map → chunk-BNZHWAZC.js.map} +0 -0
- /package/dist/{chunk-TAAZB5KN.js.map → chunk-CWT6CAE5.js.map} +0 -0
- /package/dist/{chunk-VKMFUIVA.js.map → chunk-GBVJTRXS.js.map} +0 -0
- /package/dist/{chunk-2RGPWU77.js.map → chunk-HJSEEFO3.js.map} +0 -0
- /package/dist/{chunk-JOA5A3G3.js.map → chunk-HQZQFEAX.js.map} +0 -0
- /package/dist/{chunk-45YXODSB.js.map → chunk-J4JW73TT.js.map} +0 -0
- /package/dist/{chunk-KT7NLIXP.js.map → chunk-JHYYFPKX.js.map} +0 -0
- /package/dist/{chunk-H3BOLSTS.js.map → chunk-PD3CTDO6.js.map} +0 -0
- /package/dist/{chunk-7MZN73J2.js.map → chunk-TKBVW7ZJ.js.map} +0 -0
- /package/dist/{chunk-A24GPVLY.js.map → chunk-V3OKHQUX.js.map} +0 -0
- /package/dist/{chunk-NMSHVO5O.js.map → chunk-WMDVOWN6.js.map} +0 -0
- /package/dist/{chunk-643M3AP5.js.map → chunk-WMFYI7XC.js.map} +0 -0
- /package/dist/{chunk-6LTLIYAQ.js.map → chunk-YEDEAX6Y.js.map} +0 -0
- /package/dist/{chunk-FFV2SXFD.js.map → chunk-ZVHG4KF2.js.map} +0 -0
- /package/dist/{db-LRIOKQBO.js.map → cost-tracker-KZQSTSE2.js.map} +0 -0
- /package/dist/{discord-NKR3X4AV.js.map → db-I7MNG6CL.js.map} +0 -0
- /package/dist/{enrichment-pipeline-CMUVBDC7.js.map → discord-6UQHCN27.js.map} +0 -0
- /package/dist/{documents-EYIYLZK2.js.map → documents-PFHSK7SZ.js.map} +0 -0
- /package/dist/{entity-resolution-4X4JU43O.js.map → enrichment-pipeline-7FE5R5ZI.js.map} +0 -0
- /package/dist/{env-CHOFICED.js.map → entity-resolution-7Z6STVXX.js.map} +0 -0
- /package/dist/{error-tracker-SVQSDQDW.js.map → env-GN5VHI43.js.map} +0 -0
- /package/dist/{imessage-V2XNDDHT.js.map → error-tracker-64DEH3D7.js.map} +0 -0
- /package/dist/{github-KGNILDWJ.js.map → github-DUWSXCNP.js.map} +0 -0
- /package/dist/{inbox-summarizer-DKKRYXDR.js.map → graph-client-NB475AK5.js.map} +0 -0
- /package/dist/{knowledge-base-J7PJ7MZ3.js.map → imessage-DSGSGUZS.js.map} +0 -0
- /package/dist/{mcp-3C2TN67D.js.map → inbox-summarizer-F2KAU72V.js.map} +0 -0
- /package/dist/{metrics-VJDWQWU7.js.map → knowledge-base-5SMMOGQJ.js.map} +0 -0
- /package/dist/{ocr-LGUIPKVZ.js.map → mcp-DJ2QDA6A.js.map} +0 -0
- /package/dist/{providers-H6YIC3MG.js.map → metrics-BH3ZLGEV.js.map} +0 -0
- /package/dist/{multi-user-S56GUD6L.js.map → multi-user-XAEMB244.js.map} +0 -0
- /package/dist/{scheduler-CA5UNHZV.js.map → oauth-UPJYFOVU.js.map} +0 -0
- /package/dist/{schema-ALJ67YVG.js.map → ocr-UONKTQU7.js.map} +0 -0
- /package/dist/{presentations-HXTAMGHT.js.map → presentations-UOET2FVZ.js.map} +0 -0
- /package/dist/{signal-X7IQJGRQ.js.map → providers-2YQ6E3IF.js.map} +0 -0
- /package/dist/{slack-P2LFUJUQ.js.map → scheduler-6PLLAQI7.js.map} +0 -0
- /package/dist/{sms-4VME2HUL.js.map → schema-ETY7L2VA.js.map} +0 -0
- /package/dist/{tools-FGPN522P.js.map → sharepoint-V5P4Q62L.js.map} +0 -0
- /package/dist/{whatsapp-KRPQ4YUX.js.map → signal-7D5EPGVL.js.map} +0 -0
- /package/dist/{word-document-D6N2C47N.js.map → word-document-AV3YB4L2.js.map} +0 -0
- /package/dist/{workflow-store-ZYAYE5P6.js.map → workflow-store-5Y56GUP7.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/intelligence/entity-resolution.ts"],"sourcesContent":["/**\n * Entity Resolution Pipeline\n *\n * Resolves, deduplicates, and matches entities across multiple public records\n * databases (FEC, IRS 990, USAspending, SEC EDGAR, OpenCorporates).\n *\n * Flow: exact match → identifier match (EIN/CIK/FEC) → fuzzy match → create new\n */\n\nimport { db } from \"../../db\";\nimport { graphEntities, graphRelationships } from \"../../db/schema\";\nimport { eq, ilike, sql } from \"drizzle-orm\";\n\n// Extended entity type for OSINT sources\nexport type OSINTEntityType =\n | \"person\"\n | \"organization\"\n | \"committee\"\n | \"contract\"\n | \"filing\"\n | \"location\"\n | \"topic\";\n\nexport interface EntityCandidate {\n name: string;\n type: OSINTEntityType;\n source: string; // \"fec\" | \"irs990\" | \"usaspending\" | \"sec\" | \"opencorporates\" | \"manual\"\n identifiers?: {\n ein?: string;\n cik?: string;\n fecId?: string;\n duns?: string;\n uei?: string;\n };\n attributes?: Record<string, unknown>;\n aliases?: string[];\n}\n\nexport interface ResolvedEntity {\n isNew: boolean;\n entityId: string; // postgres graphEntities.id\n confidence: number; // 0-1\n matchedBy: \"exact\" | \"fuzzy\" | \"identifier\" | \"new\";\n}\n\n/**\n * Normalize an entity name for comparison.\n * Strips punctuation, extra whitespace, common suffixes.\n */\nexport function normalizeEntityName(name: string): string {\n return name\n .toLowerCase()\n .replace(/[.,;:'\"!?()\\[\\]{}]/g, \"\")\n .replace(/\\b(inc|llc|corp|ltd|co|foundation|fund|assoc|association|committee|pac)\\b\\.?/gi, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n/**\n * Jaro-Winkler similarity between two strings (0-1).\n */\nexport function fuzzyMatch(a: string, b: string): number {\n const s1 = normalizeEntityName(a);\n const s2 = normalizeEntityName(b);\n\n if (s1 === s2) return 1.0;\n if (s1.length === 0 || s2.length === 0) return 0.0;\n\n const matchWindow = Math.max(Math.floor(Math.max(s1.length, s2.length) / 2) - 1, 0);\n const s1Matches = new Array(s1.length).fill(false);\n const s2Matches = new Array(s2.length).fill(false);\n\n let matches = 0;\n let transpositions = 0;\n\n for (let i = 0; i < s1.length; i++) {\n const start = Math.max(0, i - matchWindow);\n const end = Math.min(i + matchWindow + 1, s2.length);\n for (let j = start; j < end; j++) {\n if (s2Matches[j] || s1[i] !== s2[j]) continue;\n s1Matches[i] = true;\n s2Matches[j] = true;\n matches++;\n break;\n }\n }\n\n if (matches === 0) return 0.0;\n\n let k = 0;\n for (let i = 0; i < s1.length; i++) {\n if (!s1Matches[i]) continue;\n while (!s2Matches[k]) k++;\n if (s1[i] !== s2[k]) transpositions++;\n k++;\n }\n\n const jaro =\n (matches / s1.length + matches / s2.length + (matches - transpositions / 2) / matches) / 3;\n\n // Winkler bonus for common prefix (up to 4 chars)\n let prefix = 0;\n for (let i = 0; i < Math.min(4, Math.min(s1.length, s2.length)); i++) {\n if (s1[i] === s2[i]) prefix++;\n else break;\n }\n\n return jaro + prefix * 0.1 * (1 - jaro);\n}\n\n/**\n * Match entity by EIN (Employer Identification Number).\n */\nexport async function matchByEIN(ein: string): Promise<string | null> {\n try {\n const results = await db\n .select({ id: graphEntities.id })\n .from(graphEntities)\n .where(sql`${graphEntities.attributes}->>'ein' = ${ein}`)\n .limit(1);\n return results.length > 0 ? results[0].id : null;\n } catch (error) {\n console.error(\"[EntityResolution] EIN match error:\", error);\n return null;\n }\n}\n\n/**\n * Match entity by CIK (SEC Central Index Key).\n */\nexport async function matchByCIK(cik: string): Promise<string | null> {\n try {\n const results = await db\n .select({ id: graphEntities.id })\n .from(graphEntities)\n .where(sql`${graphEntities.attributes}->>'cik' = ${cik}`)\n .limit(1);\n return results.length > 0 ? results[0].id : null;\n } catch (error) {\n console.error(\"[EntityResolution] CIK match error:\", error);\n return null;\n }\n}\n\n/**\n * Match entity by FEC committee/candidate ID.\n */\nexport async function matchByFECId(fecId: string): Promise<string | null> {\n try {\n const results = await db\n .select({ id: graphEntities.id })\n .from(graphEntities)\n .where(sql`${graphEntities.attributes}->>'fecId' = ${fecId}`)\n .limit(1);\n return results.length > 0 ? results[0].id : null;\n } catch (error) {\n console.error(\"[EntityResolution] FEC ID match error:\", error);\n return null;\n }\n}\n\n/**\n * Core entity resolution function.\n * Resolves a candidate entity against the existing knowledge graph.\n *\n * Resolution order:\n * 1. Exact name match\n * 2. Identifier match (EIN, CIK, FEC ID)\n * 3. Fuzzy name match (Jaro-Winkler > 0.85)\n * 4. Create new entity\n */\nexport async function resolveEntity(candidate: EntityCandidate): Promise<ResolvedEntity> {\n try {\n // 1. Exact name match\n const exactMatches = await db\n .select({ id: graphEntities.id })\n .from(graphEntities)\n .where(ilike(graphEntities.name, candidate.name))\n .limit(1);\n\n if (exactMatches.length > 0) {\n // Update with new source attributes\n await mergeAttributes(exactMatches[0].id, candidate);\n return {\n isNew: false,\n entityId: exactMatches[0].id,\n confidence: 1.0,\n matchedBy: \"exact\",\n };\n }\n\n // 2. Identifier match\n if (candidate.identifiers) {\n if (candidate.identifiers.ein) {\n const id = await matchByEIN(candidate.identifiers.ein);\n if (id) {\n await mergeAttributes(id, candidate);\n return { isNew: false, entityId: id, confidence: 0.99, matchedBy: \"identifier\" };\n }\n }\n if (candidate.identifiers.cik) {\n const id = await matchByCIK(candidate.identifiers.cik);\n if (id) {\n await mergeAttributes(id, candidate);\n return { isNew: false, entityId: id, confidence: 0.99, matchedBy: \"identifier\" };\n }\n }\n if (candidate.identifiers.fecId) {\n const id = await matchByFECId(candidate.identifiers.fecId);\n if (id) {\n await mergeAttributes(id, candidate);\n return { isNew: false, entityId: id, confidence: 0.99, matchedBy: \"identifier\" };\n }\n }\n }\n\n // 3. Fuzzy name match against existing entities of the same type\n const typeFilter = [\"person\", \"organization\", \"committee\"].includes(candidate.type)\n ? candidate.type\n : undefined;\n\n const potentialMatches = await db\n .select({ id: graphEntities.id, name: graphEntities.name, aliases: graphEntities.aliases })\n .from(graphEntities)\n .where(typeFilter ? eq(graphEntities.type, typeFilter as any) : sql`true`)\n .limit(500);\n\n let bestMatch: { id: string; score: number } | null = null;\n\n for (const entity of potentialMatches) {\n // Check main name\n const nameScore = fuzzyMatch(candidate.name, entity.name);\n if (nameScore > (bestMatch?.score ?? 0.85)) {\n bestMatch = { id: entity.id, score: nameScore };\n }\n\n // Check aliases\n const aliases = (entity.aliases as string[]) || [];\n for (const alias of aliases) {\n const aliasScore = fuzzyMatch(candidate.name, alias);\n if (aliasScore > (bestMatch?.score ?? 0.85)) {\n bestMatch = { id: entity.id, score: aliasScore };\n }\n }\n }\n\n if (bestMatch) {\n await mergeAttributes(bestMatch.id, candidate);\n return {\n isNew: false,\n entityId: bestMatch.id,\n confidence: bestMatch.score,\n matchedBy: \"fuzzy\",\n };\n }\n\n // 4. Create new entity\n const newEntity = await db\n .insert(graphEntities)\n .values({\n type: mapOSINTTypeToGraphType(candidate.type) as any,\n name: candidate.name,\n aliases: candidate.aliases || [],\n description: `Discovered from ${candidate.source}`,\n attributes: {\n ...candidate.attributes,\n ...candidate.identifiers,\n sources: [candidate.source],\n discoveredAt: new Date().toISOString(),\n },\n importance: 5,\n mentionCount: 1,\n })\n .returning({ id: graphEntities.id });\n\n console.log(`[EntityResolution] Created new entity: ${candidate.name} (${candidate.type}) from ${candidate.source}`);\n\n return {\n isNew: true,\n entityId: newEntity[0].id,\n confidence: 1.0,\n matchedBy: \"new\",\n };\n } catch (error) {\n console.error(\"[EntityResolution] Error resolving entity:\", error);\n throw error;\n }\n}\n\n/**\n * Merge new attributes and aliases into an existing entity.\n */\nasync function mergeAttributes(entityId: string, candidate: EntityCandidate): Promise<void> {\n try {\n const existing = await db\n .select({ attributes: graphEntities.attributes, aliases: graphEntities.aliases, mentionCount: graphEntities.mentionCount })\n .from(graphEntities)\n .where(eq(graphEntities.id, entityId))\n .limit(1);\n\n if (existing.length === 0) return;\n\n const currentAttrs = (existing[0].attributes as Record<string, unknown>) || {};\n const currentAliases = (existing[0].aliases as string[]) || [];\n const currentSources = (currentAttrs.sources as string[]) || [];\n\n // Merge attributes\n const mergedAttrs = {\n ...currentAttrs,\n ...candidate.attributes,\n ...candidate.identifiers,\n sources: [...new Set([...currentSources, candidate.source])],\n lastUpdated: new Date().toISOString(),\n };\n\n // Merge aliases\n const newAliases = candidate.aliases || [];\n const mergedAliases = [...new Set([...currentAliases, ...newAliases])];\n\n await db\n .update(graphEntities)\n .set({\n attributes: mergedAttrs,\n aliases: mergedAliases,\n mentionCount: (existing[0].mentionCount || 0) + 1,\n })\n .where(eq(graphEntities.id, entityId));\n } catch (error) {\n console.error(\"[EntityResolution] Error merging attributes:\", error);\n }\n}\n\n/**\n * Map OSINT entity types to the existing graph entity types.\n */\nfunction mapOSINTTypeToGraphType(type: OSINTEntityType): string {\n switch (type) {\n case \"person\": return \"person\";\n case \"organization\": return \"organization\";\n case \"committee\": return \"organization\";\n case \"contract\": return \"event\";\n case \"filing\": return \"event\";\n case \"location\": return \"location\";\n case \"topic\": return \"topic\";\n default: return \"organization\";\n }\n}\n\n/**\n * Merge two entities (mark duplicate as alias of primary).\n */\nexport async function mergeEntities(primaryId: string, duplicateId: string): Promise<void> {\n try {\n const [primary, duplicate] = await Promise.all([\n db.select().from(graphEntities).where(eq(graphEntities.id, primaryId)).limit(1),\n db.select().from(graphEntities).where(eq(graphEntities.id, duplicateId)).limit(1),\n ]);\n\n if (primary.length === 0 || duplicate.length === 0) return;\n\n // Add duplicate name as alias\n const aliases = [...new Set([\n ...((primary[0].aliases as string[]) || []),\n duplicate[0].name,\n ...((duplicate[0].aliases as string[]) || []),\n ])];\n\n // Merge attributes\n const mergedAttrs = {\n ...((duplicate[0].attributes as Record<string, unknown>) || {}),\n ...((primary[0].attributes as Record<string, unknown>) || {}),\n };\n\n await db\n .update(graphEntities)\n .set({ aliases, attributes: mergedAttrs })\n .where(eq(graphEntities.id, primaryId));\n\n // Reassign all relationships from duplicate to primary\n await db\n .update(graphRelationships)\n .set({ sourceEntityId: primaryId })\n .where(eq(graphRelationships.sourceEntityId, duplicateId));\n\n await db\n .update(graphRelationships)\n .set({ targetEntityId: primaryId })\n .where(eq(graphRelationships.targetEntityId, duplicateId));\n\n // Delete the duplicate\n await db.delete(graphEntities).where(eq(graphEntities.id, duplicateId));\n\n console.log(`[EntityResolution] Merged entity ${duplicate[0].name} into ${primary[0].name}`);\n } catch (error) {\n console.error(\"[EntityResolution] Error merging entities:\", error);\n }\n}\n\n/**\n * Find potential duplicate entities based on fuzzy matching.\n */\nexport async function findDuplicates(\n threshold: number = 0.85\n): Promise<Array<{ entities: [string, string]; names: [string, string]; score: number }>> {\n try {\n const allEntities = await db\n .select({ id: graphEntities.id, name: graphEntities.name })\n .from(graphEntities)\n .limit(1000);\n\n const duplicates: Array<{ entities: [string, string]; names: [string, string]; score: number }> = [];\n\n for (let i = 0; i < allEntities.length; i++) {\n for (let j = i + 1; j < allEntities.length; j++) {\n const score = fuzzyMatch(allEntities[i].name, allEntities[j].name);\n if (score >= threshold && score < 1.0) {\n duplicates.push({\n entities: [allEntities[i].id, allEntities[j].id],\n names: [allEntities[i].name, allEntities[j].name],\n score,\n });\n }\n }\n }\n\n return duplicates.sort((a, b) => b.score - a.score);\n } catch (error) {\n console.error(\"[EntityResolution] Error finding duplicates:\", error);\n return [];\n }\n}\n"],"mappings":";;;;;;;;;AAWA,SAAS,IAAI,OAAO,WAAW;AAsCxB,SAAS,oBAAoB,MAAsB;AACxD,SAAO,KACJ,YAAY,EACZ,QAAQ,uBAAuB,EAAE,EACjC,QAAQ,kFAAkF,EAAE,EAC5F,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAKO,SAAS,WAAW,GAAW,GAAmB;AACvD,QAAM,KAAK,oBAAoB,CAAC;AAChC,QAAM,KAAK,oBAAoB,CAAC;AAEhC,MAAI,OAAO,GAAI,QAAO;AACtB,MAAI,GAAG,WAAW,KAAK,GAAG,WAAW,EAAG,QAAO;AAE/C,QAAM,cAAc,KAAK,IAAI,KAAK,MAAM,KAAK,IAAI,GAAG,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,GAAG,CAAC;AAClF,QAAM,YAAY,IAAI,MAAM,GAAG,MAAM,EAAE,KAAK,KAAK;AACjD,QAAM,YAAY,IAAI,MAAM,GAAG,MAAM,EAAE,KAAK,KAAK;AAEjD,MAAI,UAAU;AACd,MAAI,iBAAiB;AAErB,WAAS,IAAI,GAAG,IAAI,GAAG,QAAQ,KAAK;AAClC,UAAM,QAAQ,KAAK,IAAI,GAAG,IAAI,WAAW;AACzC,UAAM,MAAM,KAAK,IAAI,IAAI,cAAc,GAAG,GAAG,MAAM;AACnD,aAAS,IAAI,OAAO,IAAI,KAAK,KAAK;AAChC,UAAI,UAAU,CAAC,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,EAAG;AACrC,gBAAU,CAAC,IAAI;AACf,gBAAU,CAAC,IAAI;AACf;AACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,YAAY,EAAG,QAAO;AAE1B,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,GAAG,QAAQ,KAAK;AAClC,QAAI,CAAC,UAAU,CAAC,EAAG;AACnB,WAAO,CAAC,UAAU,CAAC,EAAG;AACtB,QAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAG;AACrB;AAAA,EACF;AAEA,QAAM,QACH,UAAU,GAAG,SAAS,UAAU,GAAG,UAAU,UAAU,iBAAiB,KAAK,WAAW;AAG3F,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,QAAQ,GAAG,MAAM,CAAC,GAAG,KAAK;AACpE,QAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAG;AAAA,QAChB;AAAA,EACP;AAEA,SAAO,OAAO,SAAS,OAAO,IAAI;AACpC;AAKA,eAAsB,WAAW,KAAqC;AACpE,MAAI;AACF,UAAM,UAAU,MAAM,GACnB,OAAO,EAAE,IAAI,cAAc,GAAG,CAAC,EAC/B,KAAK,aAAa,EAClB,MAAM,MAAM,cAAc,UAAU,cAAc,GAAG,EAAE,EACvD,MAAM,CAAC;AACV,WAAO,QAAQ,SAAS,IAAI,QAAQ,CAAC,EAAE,KAAK;AAAA,EAC9C,SAAS,OAAO;AACd,YAAQ,MAAM,uCAAuC,KAAK;AAC1D,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,WAAW,KAAqC;AACpE,MAAI;AACF,UAAM,UAAU,MAAM,GACnB,OAAO,EAAE,IAAI,cAAc,GAAG,CAAC,EAC/B,KAAK,aAAa,EAClB,MAAM,MAAM,cAAc,UAAU,cAAc,GAAG,EAAE,EACvD,MAAM,CAAC;AACV,WAAO,QAAQ,SAAS,IAAI,QAAQ,CAAC,EAAE,KAAK;AAAA,EAC9C,SAAS,OAAO;AACd,YAAQ,MAAM,uCAAuC,KAAK;AAC1D,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,aAAa,OAAuC;AACxE,MAAI;AACF,UAAM,UAAU,MAAM,GACnB,OAAO,EAAE,IAAI,cAAc,GAAG,CAAC,EAC/B,KAAK,aAAa,EAClB,MAAM,MAAM,cAAc,UAAU,gBAAgB,KAAK,EAAE,EAC3D,MAAM,CAAC;AACV,WAAO,QAAQ,SAAS,IAAI,QAAQ,CAAC,EAAE,KAAK;AAAA,EAC9C,SAAS,OAAO;AACd,YAAQ,MAAM,0CAA0C,KAAK;AAC7D,WAAO;AAAA,EACT;AACF;AAYA,eAAsB,cAAc,WAAqD;AACvF,MAAI;AAEF,UAAM,eAAe,MAAM,GACxB,OAAO,EAAE,IAAI,cAAc,GAAG,CAAC,EAC/B,KAAK,aAAa,EAClB,MAAM,MAAM,cAAc,MAAM,UAAU,IAAI,CAAC,EAC/C,MAAM,CAAC;AAEV,QAAI,aAAa,SAAS,GAAG;AAE3B,YAAM,gBAAgB,aAAa,CAAC,EAAE,IAAI,SAAS;AACnD,aAAO;AAAA,QACL,OAAO;AAAA,QACP,UAAU,aAAa,CAAC,EAAE;AAAA,QAC1B,YAAY;AAAA,QACZ,WAAW;AAAA,MACb;AAAA,IACF;AAGA,QAAI,UAAU,aAAa;AACzB,UAAI,UAAU,YAAY,KAAK;AAC7B,cAAM,KAAK,MAAM,WAAW,UAAU,YAAY,GAAG;AACrD,YAAI,IAAI;AACN,gBAAM,gBAAgB,IAAI,SAAS;AACnC,iBAAO,EAAE,OAAO,OAAO,UAAU,IAAI,YAAY,MAAM,WAAW,aAAa;AAAA,QACjF;AAAA,MACF;AACA,UAAI,UAAU,YAAY,KAAK;AAC7B,cAAM,KAAK,MAAM,WAAW,UAAU,YAAY,GAAG;AACrD,YAAI,IAAI;AACN,gBAAM,gBAAgB,IAAI,SAAS;AACnC,iBAAO,EAAE,OAAO,OAAO,UAAU,IAAI,YAAY,MAAM,WAAW,aAAa;AAAA,QACjF;AAAA,MACF;AACA,UAAI,UAAU,YAAY,OAAO;AAC/B,cAAM,KAAK,MAAM,aAAa,UAAU,YAAY,KAAK;AACzD,YAAI,IAAI;AACN,gBAAM,gBAAgB,IAAI,SAAS;AACnC,iBAAO,EAAE,OAAO,OAAO,UAAU,IAAI,YAAY,MAAM,WAAW,aAAa;AAAA,QACjF;AAAA,MACF;AAAA,IACF;AAGA,UAAM,aAAa,CAAC,UAAU,gBAAgB,WAAW,EAAE,SAAS,UAAU,IAAI,IAC9E,UAAU,OACV;AAEJ,UAAM,mBAAmB,MAAM,GAC5B,OAAO,EAAE,IAAI,cAAc,IAAI,MAAM,cAAc,MAAM,SAAS,cAAc,QAAQ,CAAC,EACzF,KAAK,aAAa,EAClB,MAAM,aAAa,GAAG,cAAc,MAAM,UAAiB,IAAI,SAAS,EACxE,MAAM,GAAG;AAEZ,QAAI,YAAkD;AAEtD,eAAW,UAAU,kBAAkB;AAErC,YAAM,YAAY,WAAW,UAAU,MAAM,OAAO,IAAI;AACxD,UAAI,aAAa,WAAW,SAAS,OAAO;AAC1C,oBAAY,EAAE,IAAI,OAAO,IAAI,OAAO,UAAU;AAAA,MAChD;AAGA,YAAM,UAAW,OAAO,WAAwB,CAAC;AACjD,iBAAW,SAAS,SAAS;AAC3B,cAAM,aAAa,WAAW,UAAU,MAAM,KAAK;AACnD,YAAI,cAAc,WAAW,SAAS,OAAO;AAC3C,sBAAY,EAAE,IAAI,OAAO,IAAI,OAAO,WAAW;AAAA,QACjD;AAAA,MACF;AAAA,IACF;AAEA,QAAI,WAAW;AACb,YAAM,gBAAgB,UAAU,IAAI,SAAS;AAC7C,aAAO;AAAA,QACL,OAAO;AAAA,QACP,UAAU,UAAU;AAAA,QACpB,YAAY,UAAU;AAAA,QACtB,WAAW;AAAA,MACb;AAAA,IACF;AAGA,UAAM,YAAY,MAAM,GACrB,OAAO,aAAa,EACpB,OAAO;AAAA,MACN,MAAM,wBAAwB,UAAU,IAAI;AAAA,MAC5C,MAAM,UAAU;AAAA,MAChB,SAAS,UAAU,WAAW,CAAC;AAAA,MAC/B,aAAa,mBAAmB,UAAU,MAAM;AAAA,MAChD,YAAY;AAAA,QACV,GAAG,UAAU;AAAA,QACb,GAAG,UAAU;AAAA,QACb,SAAS,CAAC,UAAU,MAAM;AAAA,QAC1B,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,MACvC;AAAA,MACA,YAAY;AAAA,MACZ,cAAc;AAAA,IAChB,CAAC,EACA,UAAU,EAAE,IAAI,cAAc,GAAG,CAAC;AAErC,YAAQ,IAAI,0CAA0C,UAAU,IAAI,KAAK,UAAU,IAAI,UAAU,UAAU,MAAM,EAAE;AAEnH,WAAO;AAAA,MACL,OAAO;AAAA,MACP,UAAU,UAAU,CAAC,EAAE;AAAA,MACvB,YAAY;AAAA,MACZ,WAAW;AAAA,IACb;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,8CAA8C,KAAK;AACjE,UAAM;AAAA,EACR;AACF;AAKA,eAAe,gBAAgB,UAAkB,WAA2C;AAC1F,MAAI;AACF,UAAM,WAAW,MAAM,GACpB,OAAO,EAAE,YAAY,cAAc,YAAY,SAAS,cAAc,SAAS,cAAc,cAAc,aAAa,CAAC,EACzH,KAAK,aAAa,EAClB,MAAM,GAAG,cAAc,IAAI,QAAQ,CAAC,EACpC,MAAM,CAAC;AAEV,QAAI,SAAS,WAAW,EAAG;AAE3B,UAAM,eAAgB,SAAS,CAAC,EAAE,cAA0C,CAAC;AAC7E,UAAM,iBAAkB,SAAS,CAAC,EAAE,WAAwB,CAAC;AAC7D,UAAM,iBAAkB,aAAa,WAAwB,CAAC;AAG9D,UAAM,cAAc;AAAA,MAClB,GAAG;AAAA,MACH,GAAG,UAAU;AAAA,MACb,GAAG,UAAU;AAAA,MACb,SAAS,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,gBAAgB,UAAU,MAAM,CAAC,CAAC;AAAA,MAC3D,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACtC;AAGA,UAAM,aAAa,UAAU,WAAW,CAAC;AACzC,UAAM,gBAAgB,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,gBAAgB,GAAG,UAAU,CAAC,CAAC;AAErE,UAAM,GACH,OAAO,aAAa,EACpB,IAAI;AAAA,MACH,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,eAAe,SAAS,CAAC,EAAE,gBAAgB,KAAK;AAAA,IAClD,CAAC,EACA,MAAM,GAAG,cAAc,IAAI,QAAQ,CAAC;AAAA,EACzC,SAAS,OAAO;AACd,YAAQ,MAAM,gDAAgD,KAAK;AAAA,EACrE;AACF;AAKA,SAAS,wBAAwB,MAA+B;AAC9D,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAU,aAAO;AAAA,IACtB,KAAK;AAAgB,aAAO;AAAA,IAC5B,KAAK;AAAa,aAAO;AAAA,IACzB,KAAK;AAAY,aAAO;AAAA,IACxB,KAAK;AAAU,aAAO;AAAA,IACtB,KAAK;AAAY,aAAO;AAAA,IACxB,KAAK;AAAS,aAAO;AAAA,IACrB;AAAS,aAAO;AAAA,EAClB;AACF;AAKA,eAAsB,cAAc,WAAmB,aAAoC;AACzF,MAAI;AACF,UAAM,CAAC,SAAS,SAAS,IAAI,MAAM,QAAQ,IAAI;AAAA,MAC7C,GAAG,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,GAAG,cAAc,IAAI,SAAS,CAAC,EAAE,MAAM,CAAC;AAAA,MAC9E,GAAG,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,GAAG,cAAc,IAAI,WAAW,CAAC,EAAE,MAAM,CAAC;AAAA,IAClF,CAAC;AAED,QAAI,QAAQ,WAAW,KAAK,UAAU,WAAW,EAAG;AAGpD,UAAM,UAAU,CAAC,GAAG,oBAAI,IAAI;AAAA,MAC1B,GAAK,QAAQ,CAAC,EAAE,WAAwB,CAAC;AAAA,MACzC,UAAU,CAAC,EAAE;AAAA,MACb,GAAK,UAAU,CAAC,EAAE,WAAwB,CAAC;AAAA,IAC7C,CAAC,CAAC;AAGF,UAAM,cAAc;AAAA,MAClB,GAAK,UAAU,CAAC,EAAE,cAA0C,CAAC;AAAA,MAC7D,GAAK,QAAQ,CAAC,EAAE,cAA0C,CAAC;AAAA,IAC7D;AAEA,UAAM,GACH,OAAO,aAAa,EACpB,IAAI,EAAE,SAAS,YAAY,YAAY,CAAC,EACxC,MAAM,GAAG,cAAc,IAAI,SAAS,CAAC;AAGxC,UAAM,GACH,OAAO,kBAAkB,EACzB,IAAI,EAAE,gBAAgB,UAAU,CAAC,EACjC,MAAM,GAAG,mBAAmB,gBAAgB,WAAW,CAAC;AAE3D,UAAM,GACH,OAAO,kBAAkB,EACzB,IAAI,EAAE,gBAAgB,UAAU,CAAC,EACjC,MAAM,GAAG,mBAAmB,gBAAgB,WAAW,CAAC;AAG3D,UAAM,GAAG,OAAO,aAAa,EAAE,MAAM,GAAG,cAAc,IAAI,WAAW,CAAC;AAEtE,YAAQ,IAAI,oCAAoC,UAAU,CAAC,EAAE,IAAI,SAAS,QAAQ,CAAC,EAAE,IAAI,EAAE;AAAA,EAC7F,SAAS,OAAO;AACd,YAAQ,MAAM,8CAA8C,KAAK;AAAA,EACnE;AACF;AAKA,eAAsB,eACpB,YAAoB,MACoE;AACxF,MAAI;AACF,UAAM,cAAc,MAAM,GACvB,OAAO,EAAE,IAAI,cAAc,IAAI,MAAM,cAAc,KAAK,CAAC,EACzD,KAAK,aAAa,EAClB,MAAM,GAAI;AAEb,UAAM,aAA4F,CAAC;AAEnG,aAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,eAAS,IAAI,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC/C,cAAM,QAAQ,WAAW,YAAY,CAAC,EAAE,MAAM,YAAY,CAAC,EAAE,IAAI;AACjE,YAAI,SAAS,aAAa,QAAQ,GAAK;AACrC,qBAAW,KAAK;AAAA,YACd,UAAU,CAAC,YAAY,CAAC,EAAE,IAAI,YAAY,CAAC,EAAE,EAAE;AAAA,YAC/C,OAAO,CAAC,YAAY,CAAC,EAAE,MAAM,YAAY,CAAC,EAAE,IAAI;AAAA,YAChD;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAEA,WAAO,WAAW,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAAA,EACpD,SAAS,OAAO;AACd,YAAQ,MAAM,gDAAgD,KAAK;AACnE,WAAO,CAAC;AAAA,EACV;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tools/image-analysis.ts","../src/tools/ocr.ts"],"sourcesContent":["import { providerRegistry } from \"../core/providers\";\nimport { readFile } from \"fs/promises\";\nimport { isPathAllowed } from \"../utils/paths\";\n\nexport interface ImageAnalysisResult {\n success: boolean;\n analysis?: string;\n error?: string;\n}\n\n// Supported image MIME types\nconst SUPPORTED_TYPES: Record<string, string> = {\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".png\": \"image/png\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n};\n\nfunction getMimeType(filename: string): string | null {\n const ext = filename.toLowerCase().slice(filename.lastIndexOf(\".\"));\n return SUPPORTED_TYPES[ext] || null;\n}\n\n// Analyze image from URL\nexport async function analyzeImageUrl(\n imageUrl: string,\n prompt: string\n): Promise<ImageAnalysisResult> {\n try {\n const provider = providerRegistry.getDefault();\n const response = await provider.createMessage({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 1024,\n messages: [\n {\n role: \"user\",\n content: [\n {\n type: \"image\",\n source: {\n type: \"url\",\n url: imageUrl,\n },\n },\n {\n type: \"text\",\n text: prompt || \"Describe this image in detail.\",\n },\n ],\n },\n ],\n });\n\n const textContent = response.content.find((c) => c.type === \"text\");\n return {\n success: true,\n analysis: textContent?.text,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n// Analyze image from local file\nexport async function analyzeImageFile(\n filePath: string,\n prompt: string\n): Promise<ImageAnalysisResult> {\n try {\n // Security check\n if (!isPathAllowed(filePath)) {\n return {\n success: false,\n error: \"Access to this path is not allowed\",\n };\n }\n\n const mimeType = getMimeType(filePath);\n if (!mimeType) {\n return {\n success: false,\n error: \"Unsupported image format. Supported: jpg, png, gif, webp\",\n };\n }\n\n const imageData = await readFile(filePath);\n const base64 = imageData.toString(\"base64\");\n\n const provider = providerRegistry.getDefault();\n const response = await provider.createMessage({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 1024,\n messages: [\n {\n role: \"user\",\n content: [\n {\n type: \"image\",\n source: {\n type: \"base64\",\n mediaType: mimeType,\n data: base64,\n },\n },\n {\n type: \"text\",\n text: prompt || \"Describe this image in detail.\",\n },\n ],\n },\n ],\n });\n\n const textContent = response.content.find((c) => c.type === \"text\");\n return {\n success: true,\n analysis: textContent?.text,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n// Analyze image from buffer\nexport async function analyzeImageBuffer(\n imageBuffer: Buffer,\n mimeType: \"image/jpeg\" | \"image/png\" | \"image/gif\" | \"image/webp\",\n prompt: string\n): Promise<ImageAnalysisResult> {\n try {\n const base64 = imageBuffer.toString(\"base64\");\n\n const provider = providerRegistry.getDefault();\n const response = await provider.createMessage({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 1024,\n messages: [\n {\n role: \"user\",\n content: [\n {\n type: \"image\",\n source: {\n type: \"base64\",\n mediaType: mimeType,\n data: base64,\n },\n },\n {\n type: \"text\",\n text: prompt || \"Describe this image in detail.\",\n },\n ],\n },\n ],\n });\n\n const textContent = response.content.find((c) => c.type === \"text\");\n return {\n success: true,\n analysis: textContent?.text,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n// Combined function for tool use\nexport async function analyzeImage(\n options: {\n imageUrl?: string;\n imagePath?: string;\n prompt: string;\n }\n): Promise<ImageAnalysisResult> {\n if (options.imageUrl) {\n return analyzeImageUrl(options.imageUrl, options.prompt);\n }\n\n if (options.imagePath) {\n return analyzeImageFile(options.imagePath, options.prompt);\n }\n\n return {\n success: false,\n error: \"Either imageUrl or imagePath must be provided\",\n };\n}\n\nexport default {\n analyzeImage,\n analyzeImageUrl,\n analyzeImageFile,\n analyzeImageBuffer,\n};\n","import { readFile } from \"fs/promises\";\nimport { isPathAllowed } from \"../utils/paths\";\nimport { analyzeImageFile } from \"./image-analysis\";\n\nexport interface OCRResult {\n success: boolean;\n text?: string;\n confidence?: number;\n error?: string;\n}\n\n// OCR using Tesseract.js (local, no API key needed)\nexport async function ocrWithTesseract(\n filePath: string,\n language: string = \"eng\"\n): Promise<OCRResult> {\n try {\n const Tesseract = await import(\"tesseract.js\");\n const worker = await Tesseract.createWorker(language);\n const { data } = await worker.recognize(filePath);\n await worker.terminate();\n\n return {\n success: true,\n text: data.text,\n confidence: data.confidence / 100,\n };\n } catch (error) {\n return {\n success: false,\n error: `Tesseract OCR failed: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n}\n\n// Use LLM Vision for OCR (most reliable for complex documents)\nexport async function ocrWithVision(\n filePath: string,\n language?: string\n): Promise<OCRResult> {\n const prompt = language\n ? `Extract all text from this image. The text is in ${language}. Return only the extracted text, preserving the original formatting and layout as much as possible.`\n : `Extract all text from this image. Return only the extracted text, preserving the original formatting and layout as much as possible.`;\n\n const result = await analyzeImageFile(filePath, prompt);\n\n if (result.success && result.analysis) {\n return {\n success: true,\n text: result.analysis,\n };\n }\n\n return {\n success: false,\n error: result.error || \"Failed to extract text\",\n };\n}\n\n// OCR using Tesseract.js as primary, falling back to Vision API\nexport async function ocrSimple(filePath: string): Promise<OCRResult> {\n const result = await ocrWithTesseract(filePath);\n if (result.success && result.confidence && result.confidence > 0.6) {\n return result;\n }\n // Fall back to Vision API on low confidence or failure\n return ocrWithVision(filePath);\n}\n\n// OCR for PDF files (extract text from each page)\nexport async function ocrPdf(\n filePath: string,\n pages?: string // e.g., \"1-5\" or \"1,3,5\"\n): Promise<OCRResult> {\n // For PDFs, we'll use LLM Vision on the file directly\n const prompt = `Extract all text from this PDF document. Return the text content, preserving the structure and formatting as much as possible. If there are multiple pages, separate them clearly.`;\n\n const result = await analyzeImageFile(filePath, prompt);\n\n if (result.success && result.analysis) {\n return {\n success: true,\n text: result.analysis,\n };\n }\n\n return {\n success: false,\n error: result.error || \"Failed to extract text from PDF\",\n };\n}\n\n// Main OCR function that determines the best approach\nexport async function performOCR(\n filePath: string,\n options?: {\n language?: string;\n useVision?: boolean;\n }\n): Promise<OCRResult> {\n // Security check\n if (!isPathAllowed(filePath)) {\n return {\n success: false,\n error: \"Access to this path is not allowed\",\n };\n }\n\n const ext = filePath.toLowerCase().slice(filePath.lastIndexOf(\".\"));\n\n // PDF handling\n if (ext === \".pdf\") {\n return ocrPdf(filePath);\n }\n\n // Image handling - use Vision API (most accurate)\n if ([\".jpg\", \".jpeg\", \".png\", \".gif\", \".webp\", \".bmp\", \".tiff\"].includes(ext)) {\n if (options?.useVision !== false) {\n return ocrWithVision(filePath, options?.language);\n }\n return ocrSimple(filePath);\n }\n\n return {\n success: false,\n error: `Unsupported file type: ${ext}`,\n };\n}\n\n// Extract structured data from document (tables, forms)\nexport async function extractStructuredData(\n filePath: string,\n dataType?: \"table\" | \"form\" | \"receipt\" | \"invoice\"\n): Promise<{\n success: boolean;\n data?: Record<string, unknown>;\n error?: string;\n}> {\n const prompts: Record<string, string> = {\n table: `Extract all tables from this image. Return the data as JSON arrays where each table is an array of rows, and each row is an array of cell values.`,\n form: `Extract all form fields from this image. Return as a JSON object where keys are field labels and values are the filled-in content.`,\n receipt: `Extract receipt information from this image. Return as JSON with: store_name, date, items (array with name, quantity, price), subtotal, tax, total.`,\n invoice: `Extract invoice information from this image. Return as JSON with: vendor, invoice_number, date, due_date, line_items (array), subtotal, tax, total, billing_address.`,\n };\n\n const prompt = dataType\n ? prompts[dataType]\n : `Extract any structured data from this image. Return as JSON.`;\n\n const result = await analyzeImageFile(filePath, prompt);\n\n if (result.success && result.analysis) {\n try {\n // Try to parse as JSON\n const jsonMatch = result.analysis.match(/```json\\n?([\\s\\S]*?)\\n?```/);\n if (jsonMatch) {\n return {\n success: true,\n data: JSON.parse(jsonMatch[1]),\n };\n }\n\n // Try direct parse\n const data = JSON.parse(result.analysis);\n return { success: true, data };\n } catch {\n // Return raw text if not JSON\n return {\n success: true,\n data: { rawText: result.analysis },\n };\n }\n }\n\n return {\n success: false,\n error: result.error || \"Failed to extract structured data\",\n };\n}\n\nexport default {\n performOCR,\n ocrWithVision,\n ocrWithTesseract,\n extractStructuredData,\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/integrations/github/client.ts","../src/integrations/github/pull-requests.ts","../src/integrations/github/code-review.ts"],"sourcesContent":["/**\n * GitHub API Client\n *\n * Provides authenticated access to the GitHub API using Octokit.\n */\n\nimport { Octokit } from \"octokit\";\nimport { env } from \"../../config/env\";\n\nexport interface GitHubClientConfig {\n token?: string;\n baseUrl?: string;\n}\n\nlet octokitInstance: Octokit | null = null;\n\n/**\n * Get or create the Octokit instance\n */\nexport function getOctokit(config?: GitHubClientConfig): Octokit {\n const token = config?.token || env.GITHUB_TOKEN;\n\n if (!token) {\n throw new Error(\"GitHub token is required. Set GITHUB_TOKEN environment variable.\");\n }\n\n if (!octokitInstance || config?.token) {\n octokitInstance = new Octokit({\n auth: token,\n baseUrl: config?.baseUrl,\n });\n }\n\n return octokitInstance;\n}\n\n/**\n * Create a new Octokit instance with specific config\n */\nexport function createOctokit(config: GitHubClientConfig): Octokit {\n const token = config.token || env.GITHUB_TOKEN;\n\n if (!token) {\n throw new Error(\"GitHub token is required.\");\n }\n\n return new Octokit({\n auth: token,\n baseUrl: config.baseUrl,\n });\n}\n\n/**\n * Get authenticated user information\n */\nexport async function getAuthenticatedUser(config?: GitHubClientConfig): Promise<{\n login: string;\n id: number;\n name: string | null;\n email: string | null;\n avatarUrl: string;\n}> {\n const octokit = getOctokit(config);\n\n const { data } = await octokit.rest.users.getAuthenticated();\n\n return {\n login: data.login,\n id: data.id,\n name: data.name,\n email: data.email,\n avatarUrl: data.avatar_url,\n };\n}\n\n/**\n * Check rate limit status\n */\nexport async function getRateLimit(config?: GitHubClientConfig): Promise<{\n limit: number;\n remaining: number;\n reset: Date;\n used: number;\n}> {\n const octokit = getOctokit(config);\n\n const { data } = await octokit.rest.rateLimit.get();\n\n return {\n limit: data.rate.limit,\n remaining: data.rate.remaining,\n reset: new Date(data.rate.reset * 1000),\n used: data.rate.used,\n };\n}\n\n/**\n * Parse owner and repo from a repository URL or string\n */\nexport function parseRepoString(repoString: string): { owner: string; repo: string } {\n // Handle full GitHub URLs\n if (repoString.includes(\"github.com\")) {\n const match = repoString.match(/github\\.com[/:]([\\w.-]+)\\/([\\w.-]+)/);\n if (match) {\n return { owner: match[1], repo: match[2].replace(/\\.git$/, \"\") };\n }\n }\n\n // Handle owner/repo format\n const parts = repoString.split(\"/\");\n if (parts.length === 2) {\n return { owner: parts[0], repo: parts[1] };\n }\n\n throw new Error(`Invalid repository string: ${repoString}. Expected format: owner/repo or GitHub URL`);\n}\n\nexport { Octokit };\n","/**\r\n * GitHub Pull Request Operations\r\n *\r\n * Provides functions for creating, reviewing, and merging pull requests.\r\n */\r\n\r\nimport { getOctokit, parseRepoString, type GitHubClientConfig } from \"./client\";\r\n\r\nexport interface PullRequest {\r\n id: number;\r\n number: number;\r\n title: string;\r\n body: string | null;\r\n state: \"open\" | \"closed\";\r\n htmlUrl: string;\r\n diffUrl: string;\r\n patchUrl: string;\r\n draft: boolean;\r\n merged: boolean;\r\n mergeable: boolean | null;\r\n mergeableState: string;\r\n mergedAt: string | null;\r\n mergedBy: {\r\n login: string;\r\n id: number;\r\n avatarUrl: string;\r\n } | null;\r\n user: {\r\n login: string;\r\n id: number;\r\n avatarUrl: string;\r\n } | null;\r\n head: {\r\n ref: string;\r\n sha: string;\r\n repo: {\r\n fullName: string;\r\n cloneUrl: string;\r\n } | null;\r\n };\r\n base: {\r\n ref: string;\r\n sha: string;\r\n repo: {\r\n fullName: string;\r\n cloneUrl: string;\r\n } | null;\r\n };\r\n labels: Array<{\r\n id: number;\r\n name: string;\r\n color: string;\r\n description: string | null;\r\n }>;\r\n assignees: Array<{\r\n login: string;\r\n id: number;\r\n avatarUrl: string;\r\n }>;\r\n requestedReviewers: Array<{\r\n login: string;\r\n id: number;\r\n avatarUrl: string;\r\n }>;\r\n requestedTeams: Array<{\r\n id: number;\r\n name: string;\r\n slug: string;\r\n }>;\r\n milestone: {\r\n id: number;\r\n number: number;\r\n title: string;\r\n state: string;\r\n } | null;\r\n additions: number;\r\n deletions: number;\r\n changedFiles: number;\r\n commits: number;\r\n comments: number;\r\n reviewComments: number;\r\n createdAt: string;\r\n updatedAt: string;\r\n closedAt: string | null;\r\n}\r\n\r\nexport interface PullRequestReview {\r\n id: number;\r\n user: {\r\n login: string;\r\n id: number;\r\n avatarUrl: string;\r\n } | null;\r\n body: string | null;\r\n state: \"APPROVED\" | \"CHANGES_REQUESTED\" | \"COMMENTED\" | \"DISMISSED\" | \"PENDING\";\r\n htmlUrl: string;\r\n submittedAt: string | null;\r\n commitId: string;\r\n}\r\n\r\nexport interface ReviewComment {\r\n id: number;\r\n pullRequestReviewId: number | null;\r\n diffHunk: string;\r\n path: string;\r\n position: number | null;\r\n originalPosition: number | null;\r\n commitId: string;\r\n originalCommitId: string;\r\n user: {\r\n login: string;\r\n id: number;\r\n avatarUrl: string;\r\n } | null;\r\n body: string;\r\n htmlUrl: string;\r\n createdAt: string;\r\n updatedAt: string;\r\n line: number | null;\r\n side: \"LEFT\" | \"RIGHT\";\r\n startLine: number | null;\r\n startSide: \"LEFT\" | \"RIGHT\" | null;\r\n inReplyToId: number | null;\r\n}\r\n\r\nexport interface PullRequestFile {\r\n sha: string;\r\n filename: string;\r\n status: \"added\" | \"removed\" | \"modified\" | \"renamed\" | \"copied\" | \"changed\" | \"unchanged\";\r\n additions: number;\r\n deletions: number;\r\n changes: number;\r\n blobUrl: string;\r\n rawUrl: string;\r\n contentsUrl: string;\r\n patch?: string;\r\n previousFilename?: string;\r\n}\r\n\r\nexport interface CreatePullRequestOptions {\r\n title: string;\r\n body?: string;\r\n head: string;\r\n base: string;\r\n draft?: boolean;\r\n maintainerCanModify?: boolean;\r\n}\r\n\r\nexport interface UpdatePullRequestOptions {\r\n title?: string;\r\n body?: string;\r\n state?: \"open\" | \"closed\";\r\n base?: string;\r\n maintainerCanModify?: boolean;\r\n}\r\n\r\nexport interface ListPullRequestsOptions {\r\n state?: \"open\" | \"closed\" | \"all\";\r\n head?: string;\r\n base?: string;\r\n sort?: \"created\" | \"updated\" | \"popularity\" | \"long-running\";\r\n direction?: \"asc\" | \"desc\";\r\n perPage?: number;\r\n page?: number;\r\n}\r\n\r\nexport interface CreateReviewOptions {\r\n commitId?: string;\r\n body?: string;\r\n event?: \"APPROVE\" | \"REQUEST_CHANGES\" | \"COMMENT\";\r\n comments?: Array<{\r\n path: string;\r\n position?: number;\r\n body: string;\r\n line?: number;\r\n side?: \"LEFT\" | \"RIGHT\";\r\n startLine?: number;\r\n startSide?: \"LEFT\" | \"RIGHT\";\r\n }>;\r\n}\r\n\r\nexport interface MergeOptions {\r\n commitTitle?: string;\r\n commitMessage?: string;\r\n sha?: string;\r\n mergeMethod?: \"merge\" | \"squash\" | \"rebase\";\r\n}\r\n\r\n/**\r\n * List pull requests for a repository\r\n */\r\nexport async function listPullRequests(\r\n repoString: string,\r\n options: ListPullRequestsOptions = {},\r\n config?: GitHubClientConfig\r\n): Promise<PullRequest[]> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.list({\r\n owner,\r\n repo,\r\n state: options.state || \"open\",\r\n head: options.head,\r\n base: options.base,\r\n sort: options.sort || \"created\",\r\n direction: options.direction || \"desc\",\r\n per_page: options.perPage || 30,\r\n page: options.page || 1,\r\n });\r\n\r\n return data.map(mapPullRequest);\r\n}\r\n\r\n/**\r\n * Get a specific pull request by number\r\n */\r\nexport async function getPullRequest(\r\n repoString: string,\r\n prNumber: number,\r\n config?: GitHubClientConfig\r\n): Promise<PullRequest> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.get({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n });\r\n\r\n return mapPullRequest(data);\r\n}\r\n\r\n/**\r\n * Create a new pull request\r\n */\r\nexport async function createPullRequest(\r\n repoString: string,\r\n options: CreatePullRequestOptions,\r\n config?: GitHubClientConfig\r\n): Promise<PullRequest> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.create({\r\n owner,\r\n repo,\r\n title: options.title,\r\n body: options.body,\r\n head: options.head,\r\n base: options.base,\r\n draft: options.draft,\r\n maintainer_can_modify: options.maintainerCanModify,\r\n });\r\n\r\n return mapPullRequest(data);\r\n}\r\n\r\n/**\r\n * Update a pull request\r\n */\r\nexport async function updatePullRequest(\r\n repoString: string,\r\n prNumber: number,\r\n options: UpdatePullRequestOptions,\r\n config?: GitHubClientConfig\r\n): Promise<PullRequest> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.update({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n title: options.title,\r\n body: options.body,\r\n state: options.state,\r\n base: options.base,\r\n maintainer_can_modify: options.maintainerCanModify,\r\n });\r\n\r\n return mapPullRequest(data);\r\n}\r\n\r\n/**\r\n * Close a pull request without merging\r\n */\r\nexport async function closePullRequest(\r\n repoString: string,\r\n prNumber: number,\r\n config?: GitHubClientConfig\r\n): Promise<PullRequest> {\r\n return updatePullRequest(repoString, prNumber, { state: \"closed\" }, config);\r\n}\r\n\r\n/**\r\n * Reopen a closed pull request\r\n */\r\nexport async function reopenPullRequest(\r\n repoString: string,\r\n prNumber: number,\r\n config?: GitHubClientConfig\r\n): Promise<PullRequest> {\r\n return updatePullRequest(repoString, prNumber, { state: \"open\" }, config);\r\n}\r\n\r\n/**\r\n * Mark a pull request as ready for review (remove draft status)\r\n */\r\nexport async function markReadyForReview(\r\n repoString: string,\r\n prNumber: number,\r\n config?: GitHubClientConfig\r\n): Promise<void> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n // Use GraphQL API for this as REST doesn't support it\r\n await octokit.graphql(`\r\n mutation($pullRequestId: ID!) {\r\n markPullRequestReadyForReview(input: {pullRequestId: $pullRequestId}) {\r\n pullRequest {\r\n id\r\n }\r\n }\r\n }\r\n `, {\r\n pullRequestId: `PR_${Buffer.from(`010:PullRequest${await getPullRequestNodeId(octokit, owner, repo, prNumber)}`).toString(\"base64\")}`,\r\n }).catch(async () => {\r\n // Fallback: Get node ID properly\r\n const pr = await getPullRequest(repoString, prNumber, config);\r\n // If fallback is needed, the PR might already be ready or we don't have permission\r\n console.log(\"PR may already be ready for review or permissions are insufficient\");\r\n });\r\n}\r\n\r\n/**\r\n * Convert a pull request to draft\r\n */\r\nexport async function convertToDraft(\r\n repoString: string,\r\n prNumber: number,\r\n config?: GitHubClientConfig\r\n): Promise<void> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n // This requires GraphQL API\r\n const { repository } = await octokit.graphql<{ repository: { pullRequest: { id: string } } }>(`\r\n query($owner: String!, $repo: String!, $number: Int!) {\r\n repository(owner: $owner, name: $repo) {\r\n pullRequest(number: $number) {\r\n id\r\n }\r\n }\r\n }\r\n `, { owner, repo, number: prNumber });\r\n\r\n await octokit.graphql(`\r\n mutation($pullRequestId: ID!) {\r\n convertPullRequestToDraft(input: {pullRequestId: $pullRequestId}) {\r\n pullRequest {\r\n id\r\n }\r\n }\r\n }\r\n `, { pullRequestId: repository.pullRequest.id });\r\n}\r\n\r\n/**\r\n * Request reviewers for a pull request\r\n */\r\nexport async function requestReviewers(\r\n repoString: string,\r\n prNumber: number,\r\n reviewers: string[],\r\n teamReviewers?: string[],\r\n config?: GitHubClientConfig\r\n): Promise<PullRequest> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.requestReviewers({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n reviewers,\r\n team_reviewers: teamReviewers,\r\n });\r\n\r\n return mapPullRequest(data);\r\n}\r\n\r\n/**\r\n * Remove review request\r\n */\r\nexport async function removeReviewRequest(\r\n repoString: string,\r\n prNumber: number,\r\n reviewers: string[],\r\n teamReviewers?: string[],\r\n config?: GitHubClientConfig\r\n): Promise<PullRequest> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.removeRequestedReviewers({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n reviewers,\r\n team_reviewers: teamReviewers,\r\n });\r\n\r\n return mapPullRequest(data);\r\n}\r\n\r\n/**\r\n * List reviews on a pull request\r\n */\r\nexport async function listReviews(\r\n repoString: string,\r\n prNumber: number,\r\n options?: { perPage?: number; page?: number },\r\n config?: GitHubClientConfig\r\n): Promise<PullRequestReview[]> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.listReviews({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n per_page: options?.perPage || 30,\r\n page: options?.page || 1,\r\n });\r\n\r\n return data.map(mapReview);\r\n}\r\n\r\n/**\r\n * Create a review on a pull request\r\n */\r\nexport async function createReview(\r\n repoString: string,\r\n prNumber: number,\r\n options: CreateReviewOptions,\r\n config?: GitHubClientConfig\r\n): Promise<PullRequestReview> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.createReview({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n commit_id: options.commitId,\r\n body: options.body,\r\n event: options.event,\r\n comments: options.comments,\r\n });\r\n\r\n return mapReview(data);\r\n}\r\n\r\n/**\r\n * Approve a pull request\r\n */\r\nexport async function approvePullRequest(\r\n repoString: string,\r\n prNumber: number,\r\n body?: string,\r\n config?: GitHubClientConfig\r\n): Promise<PullRequestReview> {\r\n return createReview(repoString, prNumber, {\r\n event: \"APPROVE\",\r\n body,\r\n }, config);\r\n}\r\n\r\n/**\r\n * Request changes on a pull request\r\n */\r\nexport async function requestChanges(\r\n repoString: string,\r\n prNumber: number,\r\n body: string,\r\n config?: GitHubClientConfig\r\n): Promise<PullRequestReview> {\r\n return createReview(repoString, prNumber, {\r\n event: \"REQUEST_CHANGES\",\r\n body,\r\n }, config);\r\n}\r\n\r\n/**\r\n * Submit a pending review\r\n */\r\nexport async function submitReview(\r\n repoString: string,\r\n prNumber: number,\r\n reviewId: number,\r\n event: \"APPROVE\" | \"REQUEST_CHANGES\" | \"COMMENT\",\r\n body?: string,\r\n config?: GitHubClientConfig\r\n): Promise<PullRequestReview> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.submitReview({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n review_id: reviewId,\r\n event,\r\n body,\r\n });\r\n\r\n return mapReview(data);\r\n}\r\n\r\n/**\r\n * Dismiss a review\r\n */\r\nexport async function dismissReview(\r\n repoString: string,\r\n prNumber: number,\r\n reviewId: number,\r\n message: string,\r\n config?: GitHubClientConfig\r\n): Promise<PullRequestReview> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.dismissReview({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n review_id: reviewId,\r\n message,\r\n });\r\n\r\n return mapReview(data);\r\n}\r\n\r\n/**\r\n * List review comments on a pull request\r\n */\r\nexport async function listReviewComments(\r\n repoString: string,\r\n prNumber: number,\r\n options?: { sort?: \"created\" | \"updated\"; direction?: \"asc\" | \"desc\"; since?: string; perPage?: number; page?: number },\r\n config?: GitHubClientConfig\r\n): Promise<ReviewComment[]> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.listReviewComments({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n sort: options?.sort,\r\n direction: options?.direction,\r\n since: options?.since,\r\n per_page: options?.perPage || 30,\r\n page: options?.page || 1,\r\n });\r\n\r\n return data.map(mapReviewComment);\r\n}\r\n\r\n/**\r\n * Create a review comment\r\n */\r\nexport async function createReviewComment(\r\n repoString: string,\r\n prNumber: number,\r\n body: string,\r\n commitId: string,\r\n path: string,\r\n options?: { position?: number; line?: number; side?: \"LEFT\" | \"RIGHT\"; startLine?: number; startSide?: \"LEFT\" | \"RIGHT\"; inReplyTo?: number },\r\n config?: GitHubClientConfig\r\n): Promise<ReviewComment> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.createReviewComment({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n body,\r\n commit_id: commitId,\r\n path,\r\n position: options?.position,\r\n line: options?.line,\r\n side: options?.side,\r\n start_line: options?.startLine,\r\n start_side: options?.startSide,\r\n in_reply_to: options?.inReplyTo,\r\n });\r\n\r\n return mapReviewComment(data);\r\n}\r\n\r\n/**\r\n * Reply to a review comment\r\n */\r\nexport async function replyToReviewComment(\r\n repoString: string,\r\n prNumber: number,\r\n commentId: number,\r\n body: string,\r\n config?: GitHubClientConfig\r\n): Promise<ReviewComment> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.createReplyForReviewComment({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n comment_id: commentId,\r\n body,\r\n });\r\n\r\n return mapReviewComment(data);\r\n}\r\n\r\n/**\r\n * Get files changed in a pull request\r\n */\r\nexport async function listFiles(\r\n repoString: string,\r\n prNumber: number,\r\n options?: { perPage?: number; page?: number },\r\n config?: GitHubClientConfig\r\n): Promise<PullRequestFile[]> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.listFiles({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n per_page: options?.perPage || 30,\r\n page: options?.page || 1,\r\n });\r\n\r\n return data.map(mapPullRequestFile);\r\n}\r\n\r\n/**\r\n * Get commits in a pull request\r\n */\r\nexport async function listCommits(\r\n repoString: string,\r\n prNumber: number,\r\n options?: { perPage?: number; page?: number },\r\n config?: GitHubClientConfig\r\n): Promise<Array<{ sha: string; message: string; author: { name: string; email: string; date: string } | null; committer: { name: string; email: string; date: string } | null; htmlUrl: string }>> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.listCommits({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n per_page: options?.perPage || 30,\r\n page: options?.page || 1,\r\n });\r\n\r\n return data.map((commit: any) => ({\r\n sha: commit.sha,\r\n message: commit.commit.message,\r\n author: commit.commit.author\r\n ? {\r\n name: commit.commit.author.name || \"\",\r\n email: commit.commit.author.email || \"\",\r\n date: commit.commit.author.date || \"\",\r\n }\r\n : null,\r\n committer: commit.commit.committer\r\n ? {\r\n name: commit.commit.committer.name || \"\",\r\n email: commit.commit.committer.email || \"\",\r\n date: commit.commit.committer.date || \"\",\r\n }\r\n : null,\r\n htmlUrl: commit.html_url,\r\n }));\r\n}\r\n\r\n/**\r\n * Check if a pull request can be merged\r\n */\r\nexport async function checkMergeability(\r\n repoString: string,\r\n prNumber: number,\r\n config?: GitHubClientConfig\r\n): Promise<{ mergeable: boolean | null; mergeableState: string; merged: boolean }> {\r\n const pr = await getPullRequest(repoString, prNumber, config);\r\n\r\n return {\r\n mergeable: pr.mergeable,\r\n mergeableState: pr.mergeableState,\r\n merged: pr.merged,\r\n };\r\n}\r\n\r\n/**\r\n * Merge a pull request\r\n */\r\nexport async function mergePullRequest(\r\n repoString: string,\r\n prNumber: number,\r\n options: MergeOptions = {},\r\n config?: GitHubClientConfig\r\n): Promise<{ sha: string; merged: boolean; message: string }> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.merge({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n commit_title: options.commitTitle,\r\n commit_message: options.commitMessage,\r\n sha: options.sha,\r\n merge_method: options.mergeMethod || \"merge\",\r\n });\r\n\r\n return {\r\n sha: data.sha,\r\n merged: data.merged,\r\n message: data.message,\r\n };\r\n}\r\n\r\n/**\r\n * Update a pull request branch (merge base into head)\r\n */\r\nexport async function updateBranch(\r\n repoString: string,\r\n prNumber: number,\r\n expectedHeadSha?: string,\r\n config?: GitHubClientConfig\r\n): Promise<{ message: string; url: string }> {\r\n const octokit = getOctokit(config);\r\n const { owner, repo } = parseRepoString(repoString);\r\n\r\n const { data } = await octokit.rest.pulls.updateBranch({\r\n owner,\r\n repo,\r\n pull_number: prNumber,\r\n expected_head_sha: expectedHeadSha,\r\n });\r\n\r\n return {\r\n message: data.message || \"\",\r\n url: data.url || \"\",\r\n };\r\n}\r\n\r\n// Helper to get PR node ID for GraphQL operations\r\nasync function getPullRequestNodeId(\r\n octokit: ReturnType<typeof getOctokit>,\r\n owner: string,\r\n repo: string,\r\n prNumber: number\r\n): Promise<string> {\r\n const { repository } = await octokit.graphql<{ repository: { pullRequest: { id: string } } }>(`\r\n query($owner: String!, $repo: String!, $number: Int!) {\r\n repository(owner: $owner, name: $repo) {\r\n pullRequest(number: $number) {\r\n id\r\n }\r\n }\r\n }\r\n `, { owner, repo, number: prNumber });\r\n\r\n return repository.pullRequest.id;\r\n}\r\n\r\n// Helper function to map API response to PullRequest interface\r\nfunction mapPullRequest(data: any): PullRequest {\r\n return {\r\n id: data.id,\r\n number: data.number,\r\n title: data.title,\r\n body: data.body,\r\n state: data.state,\r\n htmlUrl: data.html_url,\r\n diffUrl: data.diff_url,\r\n patchUrl: data.patch_url,\r\n draft: data.draft || false,\r\n merged: data.merged || false,\r\n mergeable: data.mergeable,\r\n mergeableState: data.mergeable_state || \"unknown\",\r\n mergedAt: data.merged_at,\r\n mergedBy: data.merged_by\r\n ? {\r\n login: data.merged_by.login,\r\n id: data.merged_by.id,\r\n avatarUrl: data.merged_by.avatar_url,\r\n }\r\n : null,\r\n user: data.user\r\n ? {\r\n login: data.user.login,\r\n id: data.user.id,\r\n avatarUrl: data.user.avatar_url,\r\n }\r\n : null,\r\n head: {\r\n ref: data.head.ref,\r\n sha: data.head.sha,\r\n repo: data.head.repo\r\n ? {\r\n fullName: data.head.repo.full_name,\r\n cloneUrl: data.head.repo.clone_url,\r\n }\r\n : null,\r\n },\r\n base: {\r\n ref: data.base.ref,\r\n sha: data.base.sha,\r\n repo: data.base.repo\r\n ? {\r\n fullName: data.base.repo.full_name,\r\n cloneUrl: data.base.repo.clone_url,\r\n }\r\n : null,\r\n },\r\n labels: data.labels?.map((label: any) => ({\r\n id: label.id,\r\n name: label.name,\r\n color: label.color,\r\n description: label.description,\r\n })) || [],\r\n assignees: data.assignees?.map((assignee: any) => ({\r\n login: assignee.login,\r\n id: assignee.id,\r\n avatarUrl: assignee.avatar_url,\r\n })) || [],\r\n requestedReviewers: data.requested_reviewers?.map((reviewer: any) => ({\r\n login: reviewer.login,\r\n id: reviewer.id,\r\n avatarUrl: reviewer.avatar_url,\r\n })) || [],\r\n requestedTeams: data.requested_teams?.map((team: any) => ({\r\n id: team.id,\r\n name: team.name,\r\n slug: team.slug,\r\n })) || [],\r\n milestone: data.milestone\r\n ? {\r\n id: data.milestone.id,\r\n number: data.milestone.number,\r\n title: data.milestone.title,\r\n state: data.milestone.state,\r\n }\r\n : null,\r\n additions: data.additions || 0,\r\n deletions: data.deletions || 0,\r\n changedFiles: data.changed_files || 0,\r\n commits: data.commits || 0,\r\n comments: data.comments || 0,\r\n reviewComments: data.review_comments || 0,\r\n createdAt: data.created_at,\r\n updatedAt: data.updated_at,\r\n closedAt: data.closed_at,\r\n };\r\n}\r\n\r\n// Helper function to map API response to PullRequestReview interface\r\nfunction mapReview(data: any): PullRequestReview {\r\n return {\r\n id: data.id,\r\n user: data.user\r\n ? {\r\n login: data.user.login,\r\n id: data.user.id,\r\n avatarUrl: data.user.avatar_url,\r\n }\r\n : null,\r\n body: data.body,\r\n state: data.state,\r\n htmlUrl: data.html_url,\r\n submittedAt: data.submitted_at,\r\n commitId: data.commit_id,\r\n };\r\n}\r\n\r\n// Helper function to map API response to ReviewComment interface\r\nfunction mapReviewComment(data: any): ReviewComment {\r\n return {\r\n id: data.id,\r\n pullRequestReviewId: data.pull_request_review_id,\r\n diffHunk: data.diff_hunk,\r\n path: data.path,\r\n position: data.position,\r\n originalPosition: data.original_position,\r\n commitId: data.commit_id,\r\n originalCommitId: data.original_commit_id,\r\n user: data.user\r\n ? {\r\n login: data.user.login,\r\n id: data.user.id,\r\n avatarUrl: data.user.avatar_url,\r\n }\r\n : null,\r\n body: data.body,\r\n htmlUrl: data.html_url,\r\n createdAt: data.created_at,\r\n updatedAt: data.updated_at,\r\n line: data.line,\r\n side: data.side || \"RIGHT\",\r\n startLine: data.start_line,\r\n startSide: data.start_side,\r\n inReplyToId: data.in_reply_to_id,\r\n };\r\n}\r\n\r\n// Helper function to map API response to PullRequestFile interface\r\nfunction mapPullRequestFile(data: any): PullRequestFile {\r\n return {\r\n sha: data.sha,\r\n filename: data.filename,\r\n status: data.status,\r\n additions: data.additions,\r\n deletions: data.deletions,\r\n changes: data.changes,\r\n blobUrl: data.blob_url,\r\n rawUrl: data.raw_url,\r\n contentsUrl: data.contents_url,\r\n patch: data.patch,\r\n previousFilename: data.previous_filename,\r\n };\r\n}\r\n","/**\n * AI-Powered Code Review\n *\n * Uses the configured LLM provider to provide intelligent code review on pull requests.\n */\n\nimport { providerRegistry } from \"../../core/providers\";\nimport { getOctokit, parseRepoString, type GitHubClientConfig } from \"./client\";\nimport { getPullRequest, listFiles, listCommits, createReview, type PullRequestFile, type CreateReviewOptions } from \"./pull-requests\";\nimport { getContents } from \"./repos\";\n\nexport interface CodeReviewOptions {\n /**\n * Focus areas for the review\n */\n focusAreas?: Array<\n | \"security\"\n | \"performance\"\n | \"maintainability\"\n | \"readability\"\n | \"testing\"\n | \"documentation\"\n | \"error-handling\"\n | \"best-practices\"\n >;\n\n /**\n * Language-specific guidelines to apply\n */\n language?: string;\n\n /**\n * Custom review guidelines or rules\n */\n customGuidelines?: string;\n\n /**\n * Maximum number of files to review (default: 20)\n */\n maxFiles?: number;\n\n /**\n * Whether to automatically submit the review\n */\n autoSubmit?: boolean;\n\n /**\n * Severity threshold for auto-approval\n * If all issues are below this severity, approve automatically\n */\n autoApproveThreshold?: \"info\" | \"warning\" | \"error\";\n\n /**\n * GitHub client configuration\n */\n githubConfig?: GitHubClientConfig;\n}\n\nexport interface ReviewIssue {\n severity: \"info\" | \"warning\" | \"error\";\n file: string;\n line?: number;\n endLine?: number;\n message: string;\n suggestion?: string;\n category: string;\n}\n\nexport interface CodeReviewResult {\n pullRequest: {\n number: number;\n title: string;\n author: string | null;\n url: string;\n };\n summary: string;\n issues: ReviewIssue[];\n filesReviewed: number;\n linesReviewed: number;\n overallAssessment: \"approve\" | \"request-changes\" | \"comment\";\n recommendations: string[];\n metrics: {\n securityScore: number;\n maintainabilityScore: number;\n readabilityScore: number;\n overallScore: number;\n };\n reviewSubmitted: boolean;\n reviewId?: number;\n}\n\nexport interface DiffContext {\n file: PullRequestFile;\n oldContent?: string;\n newContent?: string;\n patch?: string;\n}\n\n/**\n * Perform an AI-powered code review on a pull request\n */\nexport async function reviewPullRequest(\n repoString: string,\n prNumber: number,\n options: CodeReviewOptions = {}\n): Promise<CodeReviewResult> {\n const { owner, repo } = parseRepoString(repoString);\n const maxFiles = options.maxFiles || 20;\n\n // Get PR details and files\n const [pr, files, commits] = await Promise.all([\n getPullRequest(repoString, prNumber, options.githubConfig),\n listFiles(repoString, prNumber, { perPage: maxFiles }, options.githubConfig),\n listCommits(repoString, prNumber, { perPage: 10 }, options.githubConfig),\n ]);\n\n // Filter out binary files and very large files\n const reviewableFiles = files.filter((f) => {\n // Skip binary files (no patch available)\n if (!f.patch) return false;\n // Skip very large patches\n if (f.patch.length > 50000) return false;\n // Skip generated files\n if (isGeneratedFile(f.filename)) return false;\n return true;\n });\n\n // Build context for the review\n const diffContexts: DiffContext[] = reviewableFiles.map((file) => ({\n file,\n patch: file.patch,\n }));\n\n // Calculate total lines\n const totalLines = reviewableFiles.reduce(\n (sum, f) => sum + f.additions + f.deletions,\n 0\n );\n\n // Build the review prompt\n const prompt = buildReviewPrompt(pr, diffContexts, commits, options);\n\n // Get AI review using the configured provider\n const provider = providerRegistry.getDefault();\n const response = await provider.createMessage({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 8192,\n system: getSystemPrompt(options),\n messages: [{ role: \"user\", content: prompt }],\n });\n\n // Parse the review response\n const reviewContent =\n response.content[0]?.type === \"text\" ? response.content[0].text || \"\" : \"\";\n\n const reviewResult = parseReviewResponse(\n reviewContent,\n pr,\n reviewableFiles.length,\n totalLines\n );\n\n // Submit the review if requested\n if (options.autoSubmit) {\n const reviewOptions = buildReviewOptions(reviewResult);\n const review = await createReview(\n repoString,\n prNumber,\n reviewOptions,\n options.githubConfig\n );\n reviewResult.reviewSubmitted = true;\n reviewResult.reviewId = review.id;\n }\n\n return reviewResult;\n}\n\n/**\n * Review a specific file in a pull request\n */\nexport async function reviewFile(\n repoString: string,\n prNumber: number,\n filename: string,\n options: CodeReviewOptions = {}\n): Promise<{\n issues: ReviewIssue[];\n suggestions: string[];\n summary: string;\n}> {\n const files = await listFiles(repoString, prNumber, { perPage: 100 }, options.githubConfig);\n const file = files.find((f) => f.filename === filename);\n\n if (!file) {\n throw new Error(`File not found in pull request: ${filename}`);\n }\n\n if (!file.patch) {\n throw new Error(`No diff available for file: ${filename}`);\n }\n\n const prompt = buildSingleFileReviewPrompt(file, options);\n\n const provider = providerRegistry.getDefault();\n const response = await provider.createMessage({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 4096,\n system: getSystemPrompt(options),\n messages: [{ role: \"user\", content: prompt }],\n });\n\n const reviewContent =\n response.content[0]?.type === \"text\" ? response.content[0].text || \"\" : \"\";\n\n return parseSingleFileReview(reviewContent, filename);\n}\n\n/**\n * Generate a summary of changes in a pull request\n */\nexport async function summarizeChanges(\n repoString: string,\n prNumber: number,\n options?: { githubConfig?: GitHubClientConfig }\n): Promise<{\n summary: string;\n keyChanges: string[];\n impactAreas: string[];\n breakingChanges: string[];\n testingRecommendations: string[];\n}> {\n const [pr, files, commits] = await Promise.all([\n getPullRequest(repoString, prNumber, options?.githubConfig),\n listFiles(repoString, prNumber, { perPage: 50 }, options?.githubConfig),\n listCommits(repoString, prNumber, { perPage: 20 }, options?.githubConfig),\n ]);\n\n const prompt = `Analyze this pull request and provide a summary:\n\n**Pull Request:** ${pr.title}\n**Description:** ${pr.body || \"No description provided\"}\n**Author:** ${pr.user?.login || \"Unknown\"}\n**Commits:** ${commits.length}\n**Files Changed:** ${files.length}\n**Lines Changed:** +${pr.additions} / -${pr.deletions}\n\n**Commit Messages:**\n${commits.map((c) => `- ${c.message.split(\"\\n\")[0]}`).join(\"\\n\")}\n\n**Files Changed:**\n${files.map((f) => `- ${f.filename} (${f.status}: +${f.additions}/-${f.deletions})`).join(\"\\n\")}\n\nProvide your analysis in the following JSON format:\n{\n \"summary\": \"A concise 2-3 sentence summary of what this PR does\",\n \"keyChanges\": [\"Key change 1\", \"Key change 2\"],\n \"impactAreas\": [\"Area that might be affected\"],\n \"breakingChanges\": [\"Any breaking changes, or empty array if none\"],\n \"testingRecommendations\": [\"What should be tested\"]\n}`;\n\n const provider = providerRegistry.getDefault();\n const response = await provider.createMessage({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 2048,\n messages: [{ role: \"user\", content: prompt }],\n });\n\n const content =\n response.content[0]?.type === \"text\" ? response.content[0].text || \"\" : \"\";\n\n try {\n // Extract JSON from the response\n const jsonMatch = content.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n return JSON.parse(jsonMatch[0]);\n }\n } catch (e) {\n // Fall back to default structure\n }\n\n return {\n summary: content,\n keyChanges: [],\n impactAreas: [],\n breakingChanges: [],\n testingRecommendations: [],\n };\n}\n\n/**\n * Check for security issues in a pull request\n */\nexport async function securityScan(\n repoString: string,\n prNumber: number,\n options?: { githubConfig?: GitHubClientConfig }\n): Promise<{\n vulnerabilities: Array<{\n severity: \"low\" | \"medium\" | \"high\" | \"critical\";\n type: string;\n file: string;\n line?: number;\n description: string;\n recommendation: string;\n }>;\n securityScore: number;\n summary: string;\n}> {\n const files = await listFiles(repoString, prNumber, { perPage: 50 }, options?.githubConfig);\n\n const reviewableFiles = files.filter((f) => f.patch && !isGeneratedFile(f.filename));\n\n const prompt = `Perform a security analysis of these code changes.\n\n**Files Changed:**\n${reviewableFiles\n .map(\n (f) => `\n### ${f.filename}\n\\`\\`\\`diff\n${f.patch?.slice(0, 5000) || \"\"}\n\\`\\`\\`\n`\n )\n .join(\"\\n\")}\n\nLook for:\n1. SQL injection vulnerabilities\n2. XSS vulnerabilities\n3. Authentication/authorization issues\n4. Hardcoded secrets or credentials\n5. Insecure dependencies\n6. Path traversal vulnerabilities\n7. Command injection\n8. Insecure deserialization\n9. Sensitive data exposure\n10. Security misconfigurations\n\nRespond in JSON format:\n{\n \"vulnerabilities\": [\n {\n \"severity\": \"high\",\n \"type\": \"SQL Injection\",\n \"file\": \"path/to/file.ts\",\n \"line\": 42,\n \"description\": \"Description of the issue\",\n \"recommendation\": \"How to fix it\"\n }\n ],\n \"securityScore\": 85,\n \"summary\": \"Overall security assessment\"\n}`;\n\n const provider = providerRegistry.getDefault();\n const response = await provider.createMessage({\n model: \"claude-sonnet-4-20250514\",\n max_tokens: 4096,\n system: \"You are a security expert reviewing code for vulnerabilities. Be thorough but avoid false positives.\",\n messages: [{ role: \"user\", content: prompt }],\n });\n\n const content =\n response.content[0]?.type === \"text\" ? response.content[0].text || \"\" : \"\";\n\n try {\n const jsonMatch = content.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n return JSON.parse(jsonMatch[0]);\n }\n } catch (e) {\n // Fall back to default\n }\n\n return {\n vulnerabilities: [],\n securityScore: 100,\n summary: \"Unable to parse security scan results\",\n };\n}\n\n// Helper functions\n\nfunction getSystemPrompt(options: CodeReviewOptions): string {\n let prompt = `You are an expert code reviewer with deep knowledge of software engineering best practices.\nYour task is to review pull requests and provide constructive, actionable feedback.\n\nGuidelines:\n- Be specific and constructive in your feedback\n- Prioritize issues by severity (error > warning > info)\n- Include code suggestions when possible\n- Consider the context and purpose of the changes\n- Acknowledge good practices when you see them`;\n\n if (options.focusAreas?.length) {\n prompt += `\\n\\nFocus especially on: ${options.focusAreas.join(\", \")}`;\n }\n\n if (options.language) {\n prompt += `\\n\\nThis codebase uses ${options.language}. Apply language-specific best practices.`;\n }\n\n if (options.customGuidelines) {\n prompt += `\\n\\nCustom Review Guidelines:\\n${options.customGuidelines}`;\n }\n\n return prompt;\n}\n\nfunction buildReviewPrompt(\n pr: Awaited<ReturnType<typeof getPullRequest>>,\n contexts: DiffContext[],\n commits: Awaited<ReturnType<typeof listCommits>>,\n options: CodeReviewOptions\n): string {\n let prompt = `Review this pull request:\n\n**Title:** ${pr.title}\n**Author:** ${pr.user?.login || \"Unknown\"}\n**Description:**\n${pr.body || \"No description provided\"}\n\n**Commits (${commits.length}):**\n${commits.slice(0, 5).map((c) => `- ${c.message.split(\"\\n\")[0]}`).join(\"\\n\")}\n${commits.length > 5 ? `... and ${commits.length - 5} more commits` : \"\"}\n\n**Changes:**\n- Files changed: ${contexts.length}\n- Additions: ${pr.additions}\n- Deletions: ${pr.deletions}\n\n**File Diffs:**\n`;\n\n for (const ctx of contexts) {\n prompt += `\n### ${ctx.file.filename} (${ctx.file.status}: +${ctx.file.additions}/-${ctx.file.deletions})\n\\`\\`\\`diff\n${ctx.patch?.slice(0, 8000) || \"No diff available\"}\n\\`\\`\\`\n`;\n }\n\n prompt += `\n\nPlease provide your review in the following JSON format:\n{\n \"summary\": \"A brief summary of the overall changes and their quality\",\n \"issues\": [\n {\n \"severity\": \"error|warning|info\",\n \"file\": \"path/to/file.ts\",\n \"line\": 42,\n \"endLine\": 45,\n \"message\": \"Description of the issue\",\n \"suggestion\": \"Code or explanation of how to fix it\",\n \"category\": \"security|performance|maintainability|readability|testing|documentation|error-handling|best-practices\"\n }\n ],\n \"overallAssessment\": \"approve|request-changes|comment\",\n \"recommendations\": [\"General recommendation 1\", \"General recommendation 2\"],\n \"metrics\": {\n \"securityScore\": 85,\n \"maintainabilityScore\": 90,\n \"readabilityScore\": 88,\n \"overallScore\": 87\n }\n}`;\n\n return prompt;\n}\n\nfunction buildSingleFileReviewPrompt(\n file: PullRequestFile,\n options: CodeReviewOptions\n): string {\n return `Review this file change:\n\n**File:** ${file.filename}\n**Status:** ${file.status}\n**Changes:** +${file.additions}/-${file.deletions}\n\n\\`\\`\\`diff\n${file.patch || \"No diff available\"}\n\\`\\`\\`\n\nProvide your review in JSON format:\n{\n \"issues\": [\n {\n \"severity\": \"error|warning|info\",\n \"line\": 42,\n \"message\": \"Issue description\",\n \"suggestion\": \"How to fix\",\n \"category\": \"category\"\n }\n ],\n \"suggestions\": [\"General improvement suggestion\"],\n \"summary\": \"Brief summary of the file changes\"\n}`;\n}\n\nfunction parseReviewResponse(\n content: string,\n pr: Awaited<ReturnType<typeof getPullRequest>>,\n filesReviewed: number,\n linesReviewed: number\n): CodeReviewResult {\n const defaultResult: CodeReviewResult = {\n pullRequest: {\n number: pr.number,\n title: pr.title,\n author: pr.user?.login || null,\n url: pr.htmlUrl,\n },\n summary: \"\",\n issues: [],\n filesReviewed,\n linesReviewed,\n overallAssessment: \"comment\",\n recommendations: [],\n metrics: {\n securityScore: 0,\n maintainabilityScore: 0,\n readabilityScore: 0,\n overallScore: 0,\n },\n reviewSubmitted: false,\n };\n\n try {\n const jsonMatch = content.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n const parsed = JSON.parse(jsonMatch[0]);\n return {\n ...defaultResult,\n summary: parsed.summary || \"\",\n issues: parsed.issues || [],\n overallAssessment: parsed.overallAssessment || \"comment\",\n recommendations: parsed.recommendations || [],\n metrics: parsed.metrics || defaultResult.metrics,\n };\n }\n } catch (e) {\n // JSON parsing failed, return default with content as summary\n return {\n ...defaultResult,\n summary: content.slice(0, 500),\n };\n }\n\n return defaultResult;\n}\n\nfunction parseSingleFileReview(\n content: string,\n filename: string\n): {\n issues: ReviewIssue[];\n suggestions: string[];\n summary: string;\n} {\n const defaultResult = {\n issues: [],\n suggestions: [],\n summary: content.slice(0, 300),\n };\n\n try {\n const jsonMatch = content.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n const parsed = JSON.parse(jsonMatch[0]);\n return {\n issues: (parsed.issues || []).map((issue: any) => ({\n ...issue,\n file: filename,\n })),\n suggestions: parsed.suggestions || [],\n summary: parsed.summary || \"\",\n };\n }\n } catch (e) {\n // Fall back to default\n }\n\n return defaultResult;\n}\n\nfunction buildReviewOptions(result: CodeReviewResult): CreateReviewOptions {\n const comments: CreateReviewOptions[\"comments\"] = [];\n\n // Add inline comments for issues with line numbers\n for (const issue of result.issues) {\n if (issue.line) {\n comments.push({\n path: issue.file,\n line: issue.line,\n body: `**${issue.severity.toUpperCase()}** (${issue.category}): ${issue.message}${\n issue.suggestion ? `\\n\\n**Suggestion:** ${issue.suggestion}` : \"\"\n }`,\n });\n }\n }\n\n let event: \"APPROVE\" | \"REQUEST_CHANGES\" | \"COMMENT\";\n switch (result.overallAssessment) {\n case \"approve\":\n event = \"APPROVE\";\n break;\n case \"request-changes\":\n event = \"REQUEST_CHANGES\";\n break;\n default:\n event = \"COMMENT\";\n }\n\n let body = `## AI Code Review\\n\\n${result.summary}\\n\\n`;\n\n if (result.issues.length > 0) {\n body += `### Issues Found (${result.issues.length})\\n\\n`;\n\n const errorCount = result.issues.filter((i) => i.severity === \"error\").length;\n const warningCount = result.issues.filter((i) => i.severity === \"warning\").length;\n const infoCount = result.issues.filter((i) => i.severity === \"info\").length;\n\n body += `- Errors: ${errorCount}\\n- Warnings: ${warningCount}\\n- Info: ${infoCount}\\n\\n`;\n }\n\n if (result.recommendations.length > 0) {\n body += `### Recommendations\\n\\n`;\n for (const rec of result.recommendations) {\n body += `- ${rec}\\n`;\n }\n body += \"\\n\";\n }\n\n body += `### Metrics\\n\\n`;\n body += `| Metric | Score |\\n|--------|-------|\\n`;\n body += `| Security | ${result.metrics.securityScore}/100 |\\n`;\n body += `| Maintainability | ${result.metrics.maintainabilityScore}/100 |\\n`;\n body += `| Readability | ${result.metrics.readabilityScore}/100 |\\n`;\n body += `| **Overall** | **${result.metrics.overallScore}/100** |\\n`;\n\n body += `\\n---\\n*Reviewed by OpenSentinel AI*`;\n\n return {\n event,\n body,\n comments: comments.length > 0 ? comments : undefined,\n };\n}\n\nfunction isGeneratedFile(filename: string): boolean {\n const generatedPatterns = [\n /\\.min\\.(js|css)$/,\n /\\.bundle\\.(js|css)$/,\n /package-lock\\.json$/,\n /yarn\\.lock$/,\n /bun\\.lockb$/,\n /\\.d\\.ts$/,\n /\\.map$/,\n /dist\\//,\n /build\\//,\n /node_modules\\//,\n /vendor\\//,\n /generated\\//,\n /\\.pb\\.(go|ts|js)$/,\n /\\.g\\.(dart|swift|kt)$/,\n ];\n\n return generatedPatterns.some((pattern) => pattern.test(filename));\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/providers/anthropic-provider.ts","../src/core/providers/gemini.ts","../src/core/providers/registry.ts","../src/core/providers/index.ts"],"sourcesContent":["/**\n * Anthropic Provider — Wraps the Anthropic SDK\n *\n * Converts between provider-agnostic LLM types and Anthropic's SDK types.\n * Handles extended thinking, vision, and tool use natively.\n */\n\nimport Anthropic from \"@anthropic-ai/sdk\";\nimport type { LLMProvider } from \"./provider\";\nimport type {\n LLMProviderCapabilities,\n LLMProviderConfig,\n LLMRequest,\n LLMResponse,\n LLMContentBlock,\n LLMStreamEvent,\n LLMStreamResult,\n LLMMessage,\n LLMTool,\n} from \"./types\";\n\nexport class AnthropicProvider implements LLMProvider {\n readonly id: string;\n readonly name: string;\n readonly type = \"anthropic\";\n private client: Anthropic;\n\n constructor(config: LLMProviderConfig) {\n this.id = config.id;\n this.name = config.name;\n this.client = new Anthropic({ apiKey: config.apiKey });\n }\n\n getCapabilities(): LLMProviderCapabilities {\n return {\n supportsVision: true,\n supportsToolUse: true,\n supportsStreaming: true,\n supportsExtendedThinking: true,\n supportsSystemPrompt: true,\n maxContextWindow: 200000,\n };\n }\n\n async createMessage(request: LLMRequest): Promise<LLMResponse> {\n const { system, messages } = this.extractSystem(request);\n\n const params: any = {\n model: request.model,\n max_tokens: request.max_tokens,\n system,\n messages,\n };\n\n if (request.tools?.length) {\n params.tools = request.tools.map(toLLMToolToAnthropicTool);\n }\n\n if (request.thinking) {\n params.thinking = request.thinking;\n }\n\n const response = await this.client.messages.create(params);\n\n return {\n content: response.content.map(anthropicBlockToLLM),\n stop_reason: mapStopReason(response.stop_reason),\n usage: {\n input_tokens: response.usage.input_tokens,\n output_tokens: response.usage.output_tokens,\n },\n model: response.model,\n };\n }\n\n streamMessage(request: LLMRequest): LLMStreamResult {\n const { system, messages } = this.extractSystem(request);\n\n const params: any = {\n model: request.model,\n max_tokens: request.max_tokens,\n system,\n messages,\n };\n\n if (request.tools?.length) {\n params.tools = request.tools.map(toLLMToolToAnthropicTool);\n }\n\n const stream = this.client.messages.stream(params);\n\n const events: AsyncIterable<LLMStreamEvent> = {\n async *[Symbol.asyncIterator]() {\n for await (const event of stream) {\n if (event.type === \"content_block_delta\" && (event.delta as any).type === \"text_delta\") {\n yield {\n type: \"content_block_delta\" as const,\n delta: { type: \"text_delta\" as const, text: (event.delta as any).text },\n };\n }\n }\n },\n };\n\n return {\n events,\n async finalMessage(): Promise<LLMResponse> {\n const msg = await stream.finalMessage();\n return {\n content: msg.content.map(anthropicBlockToLLM),\n stop_reason: mapStopReason(msg.stop_reason),\n usage: {\n input_tokens: msg.usage.input_tokens,\n output_tokens: msg.usage.output_tokens,\n },\n model: msg.model,\n };\n },\n };\n }\n\n async listModels(): Promise<string[]> {\n return [\n \"claude-haiku-4-5-20251001\",\n \"claude-sonnet-4-20250514\",\n \"claude-opus-4-20250514\",\n ];\n }\n\n async isAvailable(): Promise<boolean> {\n try {\n // Minimal API call to check connectivity\n await this.client.messages.create({\n model: \"claude-haiku-4-5-20251001\",\n max_tokens: 1,\n messages: [{ role: \"user\", content: \"hi\" }],\n });\n return true;\n } catch {\n return false;\n }\n }\n\n /** Get the raw Anthropic client (for specialized use cases like vision) */\n getClient(): Anthropic {\n return this.client;\n }\n\n /**\n * Extract system messages and convert LLMMessages to Anthropic MessageParam format.\n * Anthropic uses a separate `system` parameter instead of a system role message.\n */\n private extractSystem(request: LLMRequest): {\n system: string;\n messages: any[];\n } {\n let system = request.system || \"\";\n\n const messages = request.messages\n .filter((m) => m.role !== \"system\")\n .map((m) => llmMessageToAnthropicMessage(m));\n\n return { system, messages };\n }\n}\n\n// ============================================\n// Conversion helpers\n// ============================================\n\nfunction toLLMToolToAnthropicTool(tool: LLMTool): any {\n // Anthropic uses the same format: { name, description, input_schema }\n return {\n name: tool.name,\n description: tool.description,\n input_schema: tool.input_schema,\n };\n}\n\nfunction llmMessageToAnthropicMessage(msg: LLMMessage): any {\n if (typeof msg.content === \"string\") {\n return { role: msg.role, content: msg.content };\n }\n\n // Convert content blocks\n const anthropicContent = msg.content.map((block) => {\n switch (block.type) {\n case \"text\":\n return { type: \"text\", text: block.text };\n case \"image\":\n return {\n type: \"image\",\n source: {\n type: block.source?.type || \"base64\",\n media_type: block.source?.mediaType || \"image/jpeg\",\n data: block.source?.data,\n ...(block.source?.url ? { url: block.source.url } : {}),\n },\n };\n case \"tool_use\":\n return {\n type: \"tool_use\",\n id: block.id,\n name: block.name,\n input: block.input,\n };\n case \"tool_result\":\n return {\n type: \"tool_result\",\n tool_use_id: block.tool_use_id,\n content: block.content,\n };\n default:\n return { type: \"text\", text: block.text || \"\" };\n }\n });\n\n return { role: msg.role, content: anthropicContent };\n}\n\nfunction anthropicBlockToLLM(block: any): LLMContentBlock {\n switch (block.type) {\n case \"text\":\n return { type: \"text\", text: block.text };\n case \"tool_use\":\n return {\n type: \"tool_use\",\n id: block.id,\n name: block.name,\n input: block.input,\n };\n default:\n return { type: \"text\", text: block.text || \"\" };\n }\n}\n\nfunction mapStopReason(reason: string | null): LLMResponse[\"stop_reason\"] {\n switch (reason) {\n case \"end_turn\":\n return \"end_turn\";\n case \"tool_use\":\n return \"tool_use\";\n case \"max_tokens\":\n return \"max_tokens\";\n default:\n return \"end_turn\";\n }\n}\n","/**\r\n * Google Gemini Provider\r\n *\r\n * Extends the OpenAI-compatible provider for Google's Gemini API.\r\n * Gemini exposes an OpenAI-compatible endpoint at\r\n * https://generativelanguage.googleapis.com/v1beta/openai/\r\n */\r\n\r\nimport { OpenAICompatibleProvider } from \"./openai-compatible-provider\";\r\nimport type { LLMProviderCapabilities } from \"./types\";\r\n\r\nexport class GeminiProvider extends OpenAICompatibleProvider {\r\n constructor(\r\n apiKey: string,\r\n defaultModel: string = \"gemini-2.0-flash\"\r\n ) {\r\n super({\r\n id: \"gemini\",\r\n name: \"Google Gemini\",\r\n type: \"openai-compatible\",\r\n apiKey,\r\n baseUrl: \"https://generativelanguage.googleapis.com/v1beta/openai/\",\r\n defaultModel,\r\n enabled: true,\r\n });\r\n }\r\n\r\n /**\r\n * Gemini 2.0 Flash supports vision, tool use, and streaming\r\n * with a 1M token context window.\r\n */\r\n override getCapabilities(): LLMProviderCapabilities {\r\n return {\r\n supportsVision: true,\r\n supportsToolUse: true,\r\n supportsStreaming: true,\r\n supportsExtendedThinking: false,\r\n supportsSystemPrompt: true,\r\n maxContextWindow: 1048576, // 1M tokens\r\n };\r\n }\r\n}\r\n","/**\n * Provider Registry — Manages all configured LLM providers\n */\n\nimport type { LLMProvider } from \"./provider\";\n\nexport class ProviderRegistry {\n private providers: Map<string, LLMProvider> = new Map();\n private defaultProviderId: string | null = null;\n\n register(provider: LLMProvider): void {\n this.providers.set(provider.id, provider);\n // First registered provider becomes default\n if (!this.defaultProviderId) {\n this.defaultProviderId = provider.id;\n }\n }\n\n unregister(id: string): void {\n this.providers.delete(id);\n if (this.defaultProviderId === id) {\n this.defaultProviderId = this.providers.keys().next().value || null;\n }\n }\n\n get(id: string): LLMProvider | undefined {\n return this.providers.get(id);\n }\n\n getDefault(): LLMProvider {\n if (!this.defaultProviderId) {\n throw new Error(\n \"[ProviderRegistry] No LLM providers configured. Set CLAUDE_API_KEY, OPENROUTER_API_KEY, or OLLAMA_ENABLED.\"\n );\n }\n const provider = this.providers.get(this.defaultProviderId);\n if (!provider) {\n throw new Error(`[ProviderRegistry] Default provider '${this.defaultProviderId}' not found.`);\n }\n return provider;\n }\n\n setDefault(id: string): void {\n if (!this.providers.has(id)) {\n console.warn(`[ProviderRegistry] Provider '${id}' not registered, cannot set as default.`);\n return;\n }\n this.defaultProviderId = id;\n }\n\n getDefaultId(): string | null {\n return this.defaultProviderId;\n }\n\n has(id: string): boolean {\n return this.providers.has(id);\n }\n\n listProviders(): Array<{ id: string; name: string; type: string }> {\n return Array.from(this.providers.values()).map((p) => ({\n id: p.id,\n name: p.name,\n type: p.type,\n }));\n }\n\n getProviderCount(): number {\n return this.providers.size;\n }\n\n clear(): void {\n this.providers.clear();\n this.defaultProviderId = null;\n }\n}\n\nexport const providerRegistry = new ProviderRegistry();\n","/**\n * Provider initialization and re-exports\n */\n\nimport { env } from \"../../config/env\";\nimport { AnthropicProvider } from \"./anthropic-provider\";\nimport { OpenAICompatibleProvider } from \"./openai-compatible-provider\";\nimport { GeminiProvider } from \"./gemini\";\nimport { providerRegistry } from \"./registry\";\n\n/**\n * Initialize all configured LLM providers from environment variables.\n * Called once during application startup.\n */\nexport async function initializeProviders(): Promise<void> {\n // Always register Anthropic if CLAUDE_API_KEY is set\n if (env.CLAUDE_API_KEY) {\n providerRegistry.register(\n new AnthropicProvider({\n id: \"anthropic\",\n name: \"Anthropic\",\n type: \"anthropic\",\n apiKey: env.CLAUDE_API_KEY,\n enabled: true,\n })\n );\n console.log(\"[LLM] Registered provider: Anthropic\");\n }\n\n // Register OpenAI if key is set (for LLM use, separate from Whisper STT)\n if ((env as any).OPENAI_LLM_ENABLED && env.OPENAI_API_KEY) {\n providerRegistry.register(\n new OpenAICompatibleProvider({\n id: \"openai\",\n name: \"OpenAI\",\n type: \"openai\",\n apiKey: env.OPENAI_API_KEY,\n baseUrl: \"https://api.openai.com/v1\",\n defaultModel: \"gpt-4o\",\n enabled: true,\n })\n );\n console.log(\"[LLM] Registered provider: OpenAI\");\n }\n\n // Register OpenRouter if configured\n if ((env as any).OPENROUTER_API_KEY) {\n providerRegistry.register(\n new OpenAICompatibleProvider({\n id: \"openrouter\",\n name: \"OpenRouter\",\n type: \"openai-compatible\",\n apiKey: (env as any).OPENROUTER_API_KEY,\n baseUrl: (env as any).OPENROUTER_BASE_URL || \"https://openrouter.ai/api/v1\",\n defaultModel: \"anthropic/claude-sonnet-4-20250514\",\n enabled: true,\n })\n );\n console.log(\"[LLM] Registered provider: OpenRouter\");\n }\n\n // Register Groq if configured\n if ((env as any).GROQ_API_KEY) {\n providerRegistry.register(\n new OpenAICompatibleProvider({\n id: \"groq\",\n name: \"Groq\",\n type: \"openai-compatible\",\n apiKey: (env as any).GROQ_API_KEY,\n baseUrl: \"https://api.groq.com/openai/v1\",\n defaultModel: \"llama-3.1-70b-versatile\",\n enabled: true,\n })\n );\n console.log(\"[LLM] Registered provider: Groq\");\n }\n\n // Register Mistral if configured\n if ((env as any).MISTRAL_API_KEY) {\n providerRegistry.register(\n new OpenAICompatibleProvider({\n id: \"mistral\",\n name: \"Mistral\",\n type: \"openai-compatible\",\n apiKey: (env as any).MISTRAL_API_KEY,\n baseUrl: \"https://api.mistral.ai/v1\",\n defaultModel: \"mistral-large-latest\",\n enabled: true,\n })\n );\n console.log(\"[LLM] Registered provider: Mistral\");\n }\n\n // Register Google Gemini if configured\n if ((env as any).GEMINI_API_KEY) {\n providerRegistry.register(\n new GeminiProvider(\n (env as any).GEMINI_API_KEY,\n (env as any).GEMINI_DEFAULT_MODEL || \"gemini-2.0-flash\"\n )\n );\n console.log(\"[LLM] Registered provider: Google Gemini\");\n }\n\n // Register xAI (Grok) if configured\n if ((env as any).XAI_API_KEY) {\n providerRegistry.register(\n new OpenAICompatibleProvider({\n id: \"xai\",\n name: \"xAI (Grok)\",\n type: \"openai-compatible\",\n apiKey: (env as any).XAI_API_KEY,\n baseUrl: \"https://api.x.ai/v1\",\n defaultModel: (env as any).XAI_DEFAULT_MODEL || \"grok-2\",\n enabled: true,\n })\n );\n console.log(\"[LLM] Registered provider: xAI (Grok)\");\n }\n\n // Register generic OpenAI-compatible endpoint if configured\n if ((env as any).OPENAI_COMPATIBLE_BASE_URL) {\n providerRegistry.register(\n new OpenAICompatibleProvider({\n id: \"custom\",\n name: \"Custom Provider\",\n type: \"openai-compatible\",\n apiKey: (env as any).OPENAI_COMPATIBLE_API_KEY || \"not-needed\",\n baseUrl: (env as any).OPENAI_COMPATIBLE_BASE_URL,\n defaultModel: (env as any).OPENAI_COMPATIBLE_MODEL || \"default\",\n enabled: true,\n })\n );\n console.log(\"[LLM] Registered provider: Custom (\" + (env as any).OPENAI_COMPATIBLE_BASE_URL + \")\");\n }\n\n // Register Ollama if enabled (requires async probe)\n if ((env as any).OLLAMA_ENABLED) {\n try {\n const { OllamaProvider } = await import(\"./ollama\");\n const ollamaBaseUrl = (env as any).OLLAMA_BASE_URL || \"http://localhost:11434\";\n const ollamaModel = (env as any).OLLAMA_DEFAULT_MODEL || \"llama3.1\";\n const ollama = new OllamaProvider(ollamaBaseUrl, ollamaModel);\n\n const available = await ollama.isAvailable();\n if (available) {\n providerRegistry.register(ollama);\n const models = await ollama.listModels();\n console.log(`[LLM] Registered provider: Ollama (${models.length} model(s): ${models.slice(0, 5).join(\", \")})`);\n } else {\n console.warn(`[LLM] Ollama enabled but not reachable at ${ollamaBaseUrl}`);\n }\n } catch (err: any) {\n console.warn(\"[LLM] Failed to initialize Ollama:\", err.message);\n }\n }\n\n // Set default provider\n const defaultId = (env as any).LLM_PROVIDER || \"anthropic\";\n if (providerRegistry.has(defaultId)) {\n providerRegistry.setDefault(defaultId);\n }\n\n const providers = providerRegistry.listProviders();\n if (providers.length === 0) {\n console.warn(\"[LLM] No LLM providers configured. Set CLAUDE_API_KEY or another provider key.\");\n } else {\n console.log(\n `[LLM] ${providers.length} provider(s) ready. Default: ${providerRegistry.getDefaultId()}`\n );\n }\n}\n\n// Re-exports\nexport { providerRegistry } from \"./registry\";\nexport { AnthropicProvider } from \"./anthropic-provider\";\nexport { OpenAICompatibleProvider } from \"./openai-compatible-provider\";\nexport { OllamaProvider } from \"./ollama\";\nexport { GeminiProvider } from \"./gemini\";\nexport type { LLMProvider } from \"./provider\";\nexport type {\n LLMMessage,\n LLMContentBlock,\n LLMTool,\n LLMRequest,\n LLMResponse,\n LLMStreamEvent,\n LLMStreamResult,\n LLMProviderCapabilities,\n LLMProviderConfig,\n} from \"./types\";\n"],"mappings":"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","names":["OllamaProvider"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/security/audit-logger.ts"],"sourcesContent":["import { createHmac, randomUUID } from \"crypto\";\nimport { db } from \"../../db\";\nimport { auditLogs, NewAuditLog } from \"../../db/schema\";\nimport { eq, and, gte, lte, desc, count, min, max, asc } from \"drizzle-orm\";\nimport { env } from \"../../config/env\";\n\nexport type AuditAction =\n | \"login\"\n | \"logout\"\n | \"session_create\"\n | \"session_invalidate\"\n | \"api_key_create\"\n | \"api_key_revoke\"\n | \"tool_use\"\n | \"chat_message\"\n | \"memory_create\"\n | \"memory_delete\"\n | \"memory_archive\"\n | \"settings_change\"\n | \"mode_change\"\n | \"agent_spawn\"\n | \"agent_complete\"\n | \"file_read\"\n | \"file_write\"\n | \"shell_execute\"\n | \"web_browse\"\n | \"error\";\n\nexport type AuditResource =\n | \"session\"\n | \"api_key\"\n | \"tool\"\n | \"chat\"\n | \"memory\"\n | \"settings\"\n | \"mode\"\n | \"agent\"\n | \"file\"\n | \"shell\"\n | \"browser\";\n\nexport interface AuditLogEntry {\n userId?: string;\n sessionId?: string;\n action: AuditAction;\n resource?: AuditResource;\n resourceId?: string;\n details?: Record<string, unknown>;\n ipAddress?: string;\n userAgent?: string;\n success?: boolean;\n}\n\n// --- Tamper-proof chain hashing helpers (SOC 2 compliance) ---\n\nlet _cachedSigningKey: string | null = null;\n\nfunction getAuditSigningKey(): string {\n if (_cachedSigningKey) return _cachedSigningKey;\n if (env.AUDIT_SIGNING_KEY) {\n _cachedSigningKey = env.AUDIT_SIGNING_KEY;\n return _cachedSigningKey;\n }\n _cachedSigningKey = randomUUID();\n console.warn(\n \"[audit-logger] AUDIT_SIGNING_KEY not set — using a random ephemeral key. \" +\n \"Set AUDIT_SIGNING_KEY in .env for persistent tamper-proof audit chains.\"\n );\n return _cachedSigningKey;\n}\n\nfunction signAuditEntry(\n sequenceNumber: number,\n action: string,\n userId: string | undefined,\n resource: string | undefined,\n detailsJson: string,\n timestamp: string,\n previousHash: string | null\n): string {\n const key = getAuditSigningKey();\n const data = [\n String(sequenceNumber),\n action,\n userId ?? \"\",\n resource ?? \"\",\n detailsJson,\n timestamp,\n previousHash ?? \"\",\n ].join(\"|\");\n return createHmac(\"sha256\", key).update(data).digest(\"hex\");\n}\n\nasync function getLastAuditEntry(): Promise<{\n sequenceNumber: number;\n entryHash: string;\n} | null> {\n const [last] = await db\n .select({\n sequenceNumber: auditLogs.sequenceNumber,\n entryHash: auditLogs.entryHash,\n })\n .from(auditLogs)\n .orderBy(desc(auditLogs.sequenceNumber))\n .limit(1);\n\n if (!last || last.sequenceNumber == null || last.entryHash == null) {\n return null;\n }\n\n return {\n sequenceNumber: last.sequenceNumber,\n entryHash: last.entryHash,\n };\n}\n\nexport async function logAudit(entry: AuditLogEntry): Promise<string> {\n // Fetch previous chain entry for tamper-proof linking\n const last = await getLastAuditEntry();\n const sequenceNumber = (last?.sequenceNumber ?? 0) + 1;\n const previousHash = last?.entryHash ?? null;\n\n const timestamp = new Date().toISOString();\n const detailsJson = entry.details ? JSON.stringify(entry.details) : \"{}\";\n\n const entryHash = signAuditEntry(\n sequenceNumber,\n entry.action,\n entry.userId,\n entry.resource,\n detailsJson,\n timestamp,\n previousHash\n );\n\n const [log] = await db\n .insert(auditLogs)\n .values({\n userId: entry.userId,\n sessionId: entry.sessionId,\n action: entry.action,\n resource: entry.resource,\n resourceId: entry.resourceId,\n details: entry.details,\n ipAddress: entry.ipAddress,\n userAgent: entry.userAgent,\n success: entry.success ?? true,\n createdAt: new Date(timestamp),\n sequenceNumber,\n entryHash,\n previousHash,\n })\n .returning();\n\n return log.id;\n}\n\nexport interface AuditQueryOptions {\n userId?: string;\n action?: AuditAction;\n resource?: AuditResource;\n startDate?: Date;\n endDate?: Date;\n limit?: number;\n offset?: number;\n}\n\nexport async function queryAuditLogs(options: AuditQueryOptions = {}) {\n const {\n userId,\n action,\n resource,\n startDate,\n endDate,\n limit = 100,\n offset = 0,\n } = options;\n\n let query = db.select().from(auditLogs);\n\n const conditions = [];\n\n if (userId) {\n conditions.push(eq(auditLogs.userId, userId));\n }\n\n if (action) {\n conditions.push(eq(auditLogs.action, action));\n }\n\n if (resource) {\n conditions.push(eq(auditLogs.resource, resource));\n }\n\n if (startDate) {\n conditions.push(gte(auditLogs.createdAt, startDate));\n }\n\n if (endDate) {\n conditions.push(lte(auditLogs.createdAt, endDate));\n }\n\n if (conditions.length > 0) {\n query = query.where(and(...conditions)) as typeof query;\n }\n\n const logs = await query\n .orderBy(desc(auditLogs.createdAt))\n .limit(limit)\n .offset(offset);\n\n return logs;\n}\n\nexport async function getRecentUserActivity(\n userId: string,\n hours = 24\n): Promise<typeof auditLogs.$inferSelect[]> {\n const since = new Date(Date.now() - hours * 60 * 60 * 1000);\n\n return db\n .select()\n .from(auditLogs)\n .where(and(eq(auditLogs.userId, userId), gte(auditLogs.createdAt, since)))\n .orderBy(desc(auditLogs.createdAt))\n .limit(100);\n}\n\nexport async function countActionsByType(\n userId: string,\n startDate: Date,\n endDate: Date\n): Promise<Record<string, number>> {\n const logs = await db\n .select()\n .from(auditLogs)\n .where(\n and(\n eq(auditLogs.userId, userId),\n gte(auditLogs.createdAt, startDate),\n lte(auditLogs.createdAt, endDate)\n )\n );\n\n const counts: Record<string, number> = {};\n for (const log of logs) {\n counts[log.action] = (counts[log.action] || 0) + 1;\n }\n\n return counts;\n}\n\n// --- Audit chain verification (SOC 2 compliance) ---\n\nexport async function verifyAuditChain(\n options?: { fromSequence?: number; limit?: number }\n): Promise<{\n valid: boolean;\n totalChecked: number;\n firstInvalid?: number;\n errors: Array<{ sequenceNumber: number; error: string }>;\n}> {\n const fromSequence = options?.fromSequence ?? 1;\n const batchLimit = options?.limit ?? 10000;\n\n // Fetch the entry just before fromSequence to get its hash for linkage check\n let expectedPreviousHash: string | null = null;\n let expectedSequence = fromSequence;\n\n if (fromSequence > 1) {\n const [prev] = await db\n .select({\n sequenceNumber: auditLogs.sequenceNumber,\n entryHash: auditLogs.entryHash,\n })\n .from(auditLogs)\n .where(eq(auditLogs.sequenceNumber, fromSequence - 1))\n .limit(1);\n\n expectedPreviousHash = prev?.entryHash ?? null;\n }\n\n const entries = await db\n .select()\n .from(auditLogs)\n .where(gte(auditLogs.sequenceNumber, fromSequence))\n .orderBy(asc(auditLogs.sequenceNumber))\n .limit(batchLimit);\n\n const errors: Array<{ sequenceNumber: number; error: string }> = [];\n\n for (const entry of entries) {\n const seq = entry.sequenceNumber;\n\n if (seq == null) {\n errors.push({\n sequenceNumber: expectedSequence,\n error: \"Missing sequence number\",\n });\n expectedSequence++;\n continue;\n }\n\n // Check sequence continuity\n if (seq !== expectedSequence) {\n errors.push({\n sequenceNumber: expectedSequence,\n error: `Sequence gap: expected ${expectedSequence}, got ${seq}`,\n });\n expectedSequence = seq; // re-sync\n }\n\n // Check previousHash linkage\n if ((entry.previousHash ?? null) !== expectedPreviousHash) {\n errors.push({\n sequenceNumber: seq,\n error: `Previous hash mismatch: expected ${expectedPreviousHash ?? \"(null)\"}, got ${entry.previousHash ?? \"(null)\"}`,\n });\n }\n\n // Recompute and verify entryHash\n const detailsJson = entry.details ? JSON.stringify(entry.details) : \"{}\";\n const timestamp = entry.createdAt.toISOString();\n\n const recomputed = signAuditEntry(\n seq,\n entry.action,\n entry.userId ?? undefined,\n entry.resource ?? undefined,\n detailsJson,\n timestamp,\n entry.previousHash\n );\n\n if (recomputed !== entry.entryHash) {\n errors.push({\n sequenceNumber: seq,\n error: \"Entry hash mismatch — record may have been tampered with\",\n });\n }\n\n // Advance expectations\n expectedPreviousHash = entry.entryHash;\n expectedSequence = seq + 1;\n }\n\n return {\n valid: errors.length === 0,\n totalChecked: entries.length,\n firstInvalid: errors.length > 0 ? errors[0].sequenceNumber : undefined,\n errors,\n };\n}\n\nexport async function getAuditChainIntegrity(): Promise<{\n totalEntries: number;\n oldestEntry: Date | null;\n newestEntry: Date | null;\n lastVerified: number;\n chainValid: boolean;\n lastSequence: number;\n}> {\n const [stats] = await db\n .select({\n totalEntries: count(auditLogs.id),\n oldestEntry: min(auditLogs.createdAt),\n newestEntry: max(auditLogs.createdAt),\n lastSequence: max(auditLogs.sequenceNumber),\n })\n .from(auditLogs);\n\n const totalEntries = Number(stats.totalEntries ?? 0);\n const lastSequence = stats.lastSequence ?? 0;\n\n // Verify the last 1000 entries\n const verifyFrom = Math.max(1, lastSequence - 999);\n const verification = await verifyAuditChain({\n fromSequence: verifyFrom,\n limit: 1000,\n });\n\n return {\n totalEntries,\n oldestEntry: stats.oldestEntry ? new Date(stats.oldestEntry) : null,\n newestEntry: stats.newestEntry ? new Date(stats.newestEntry) : null,\n lastVerified: verification.totalChecked,\n chainValid: verification.valid,\n lastSequence,\n };\n}\n\n// Convenience functions for common audit events\nexport const audit = {\n login: (userId: string, ipAddress?: string, userAgent?: string) =>\n logAudit({\n userId,\n action: \"login\",\n resource: \"session\",\n ipAddress,\n userAgent,\n }),\n\n logout: (userId: string, sessionId: string) =>\n logAudit({\n userId,\n sessionId,\n action: \"logout\",\n resource: \"session\",\n }),\n\n toolUse: (\n userId: string,\n toolName: string,\n input: Record<string, unknown>,\n success: boolean\n ) =>\n logAudit({\n userId,\n action: \"tool_use\",\n resource: \"tool\",\n resourceId: toolName,\n details: { input },\n success,\n }),\n\n shellExecute: (\n userId: string,\n command: string,\n exitCode: number,\n durationMs: number\n ) =>\n logAudit({\n userId,\n action: \"shell_execute\",\n resource: \"shell\",\n details: { command, exitCode, durationMs },\n success: exitCode === 0,\n }),\n\n fileAccess: (\n userId: string,\n action: \"file_read\" | \"file_write\",\n filePath: string\n ) =>\n logAudit({\n userId,\n action,\n resource: \"file\",\n resourceId: filePath,\n }),\n\n memoryCreate: (userId: string, memoryId: string, memoryType: string) =>\n logAudit({\n userId,\n action: \"memory_create\",\n resource: \"memory\",\n resourceId: memoryId,\n details: { type: memoryType },\n }),\n\n modeChange: (\n userId: string,\n fromMode: string | null,\n toMode: string\n ) =>\n logAudit({\n userId,\n action: \"mode_change\",\n resource: \"mode\",\n details: { fromMode, toMode },\n }),\n\n agentSpawn: (userId: string, agentId: string, agentType: string) =>\n logAudit({\n userId,\n action: \"agent_spawn\",\n resource: \"agent\",\n resourceId: agentId,\n details: { type: agentType },\n }),\n\n error: (\n userId: string | undefined,\n errorType: string,\n message: string,\n context?: Record<string, unknown>\n ) =>\n logAudit({\n userId,\n action: \"error\",\n details: { errorType, message, ...context },\n success: false,\n }),\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
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\";\nimport Redis from \"ioredis\";\nimport { env } from \"../config/env\";\nimport { chat } from \"./brain\";\nimport { startAgentWorker, stopAgentWorker } from \"./agents/agent-worker\";\nimport { processCalendarTriggers, generateDailyBriefing } from \"../inputs/calendar/trigger-processor\";\nimport { autoShed } from \"./evolution/memory-shedder\";\nimport { generateWeeklyReport, generateMonthlyReport } from \"./evolution/growth-reporter\";\nimport { resetMonthlyUsage } from \"./permissions/permission-manager\";\nimport { flushMetrics } from \"./observability/metrics\";\n\n// Lazy Redis connection and queues — created on first use\nlet _connection: Redis | null = null;\nlet _taskQueue: Queue | null = null;\nlet _maintenanceQueue: Queue | null = null;\n\nfunction getConnection(): Redis {\n if (!_connection) {\n _connection = new Redis(env.REDIS_URL, {\n maxRetriesPerRequest: null,\n });\n }\n return _connection;\n}\n\nfunction getTaskQueue(): Queue {\n if (!_taskQueue) {\n _taskQueue = new Queue(\"sentinel-tasks\", { connection: getConnection() as any });\n }\n return _taskQueue;\n}\n\nfunction getMaintenanceQueue(): Queue {\n if (!_maintenanceQueue) {\n _maintenanceQueue = new Queue(\"sentinel-maintenance\", { connection: getConnection() as any });\n }\n return _maintenanceQueue;\n}\n\n// Backward-compatible exports\nconst connection = new Proxy({} as Redis, {\n get(_target, prop) {\n const instance = getConnection();\n const value = (instance as any)[prop];\n if (typeof value === \"function\") return value.bind(instance);\n return value;\n },\n});\nconst taskQueue = new Proxy({} as Queue, {\n get(_target, prop) {\n const instance = getTaskQueue();\n const value = (instance as any)[prop];\n if (typeof value === \"function\") return value.bind(instance);\n return value;\n },\n});\nconst maintenanceQueue = new Proxy({} as Queue, {\n get(_target, prop) {\n const instance = getMaintenanceQueue();\n const value = (instance as any)[prop];\n if (typeof value === \"function\") return value.bind(instance);\n return value;\n },\n});\n\ninterface ScheduledTask {\n type: \"reminder\" | \"briefing\" | \"custom\" | \"calendar_check\" | \"memory_shed\" | \"growth_report\" | \"metrics_flush\";\n message?: string;\n userId?: string;\n chatId?: string;\n metadata?: Record<string, unknown>;\n}\n\n// Schedule a task\nexport async function scheduleTask(\n task: ScheduledTask,\n delay: number\n): Promise<string> {\n const job = await taskQueue.add(\"scheduled-task\", task, {\n delay,\n removeOnComplete: true,\n removeOnFail: 100,\n });\n return job.id || \"\";\n}\n\n// Schedule a recurring task (cron-style)\nexport async function scheduleRecurring(\n name: string,\n task: ScheduledTask,\n pattern: string // cron pattern\n): Promise<void> {\n await taskQueue.add(name, task, {\n repeat: { pattern },\n removeOnComplete: true,\n });\n}\n\n// Cancel a scheduled task\nexport async function cancelTask(jobId: string): Promise<boolean> {\n const job = await taskQueue.getJob(jobId);\n if (job) {\n await job.remove();\n return true;\n }\n return false;\n}\n\n// Process scheduled tasks\nlet worker: Worker | null = null;\nlet maintenanceWorker: Worker | null = null;\n\nexport function startWorker(\n onTask: (task: ScheduledTask) => Promise<void>\n): void {\n if (worker) return;\n\n worker = new Worker(\n \"sentinel-tasks\",\n async (job: Job<ScheduledTask>) => {\n console.log(`[Scheduler] Processing task: ${job.name}`);\n await onTask(job.data);\n },\n { connection: getConnection() as any }\n );\n\n worker.on(\"completed\", (job) => {\n console.log(`[Scheduler] Task completed: ${job.id}`);\n });\n\n worker.on(\"failed\", (job, err) => {\n console.error(`[Scheduler] Task failed: ${job?.id}`, err);\n });\n\n console.log(\"[Scheduler] Worker started\");\n}\n\n// Start maintenance worker for background jobs\nexport function startMaintenanceWorker(): void {\n if (maintenanceWorker) return;\n\n maintenanceWorker = new Worker(\n \"sentinel-maintenance\",\n async (job: Job<ScheduledTask>) => {\n console.log(`[Maintenance] Processing: ${job.name}`);\n\n switch (job.data.type) {\n case \"calendar_check\":\n if (job.data.userId) {\n await processCalendarTriggers(job.data.userId, []);\n }\n break;\n\n case \"memory_shed\":\n if (job.data.userId) {\n const result = await autoShed(job.data.userId);\n console.log(`[Maintenance] Memory shed: archived ${result.archivedCount} memories`);\n }\n break;\n\n case \"growth_report\":\n if (job.data.userId) {\n const reportType = job.data.metadata?.reportType as \"weekly\" | \"monthly\";\n if (reportType === \"monthly\") {\n await generateMonthlyReport(job.data.userId);\n } else {\n await generateWeeklyReport(job.data.userId);\n }\n }\n break;\n\n case \"metrics_flush\":\n await flushMetrics();\n break;\n\n default:\n console.log(`[Maintenance] Unknown task type: ${job.data.type}`);\n }\n },\n { connection: getConnection() as any }\n );\n\n maintenanceWorker.on(\"completed\", (job) => {\n console.log(`[Maintenance] Completed: ${job.id}`);\n });\n\n maintenanceWorker.on(\"failed\", (job, err) => {\n console.error(`[Maintenance] Failed: ${job?.id}`, err);\n });\n\n console.log(\"[Maintenance] Worker started\");\n}\n\nexport function stopWorker(): void {\n if (worker) {\n worker.close();\n worker = null;\n }\n}\n\nexport function stopMaintenanceWorker(): void {\n if (maintenanceWorker) {\n maintenanceWorker.close();\n maintenanceWorker = null;\n }\n}\n\n// Start all workers and scheduled jobs\nexport async function initializeScheduler(\n onTask: (task: ScheduledTask) => Promise<void>\n): Promise<void> {\n // Start workers\n startWorker(onTask);\n startMaintenanceWorker();\n startAgentWorker();\n\n // Schedule recurring maintenance jobs\n await setupRecurringJobs();\n\n console.log(\"[Scheduler] Initialized\");\n}\n\n// Setup recurring maintenance jobs\nasync function setupRecurringJobs(): Promise<void> {\n // Calendar trigger check - every 15 minutes\n await maintenanceQueue.add(\n \"calendar-check\",\n { type: \"calendar_check\" },\n {\n repeat: { pattern: \"*/15 * * * *\" },\n removeOnComplete: true,\n }\n );\n\n // Metrics flush - every 5 minutes\n await maintenanceQueue.add(\n \"metrics-flush\",\n { type: \"metrics_flush\" },\n {\n repeat: { pattern: \"*/5 * * * *\" },\n removeOnComplete: true,\n }\n );\n\n // Weekly memory shedding - Sundays at 3 AM\n await maintenanceQueue.add(\n \"memory-shed-weekly\",\n { type: \"memory_shed\" },\n {\n repeat: { pattern: \"0 3 * * 0\" },\n removeOnComplete: true,\n }\n );\n\n // Monthly quota reset - 1st of month at midnight\n await maintenanceQueue.add(\n \"quota-reset-monthly\",\n { type: \"custom\", message: \"quota_reset\" },\n {\n repeat: { pattern: \"0 0 1 * *\" },\n removeOnComplete: true,\n }\n );\n\n console.log(\"[Scheduler] Recurring jobs scheduled\");\n}\n\n// Schedule user-specific maintenance\nexport async function scheduleUserMaintenance(\n userId: string,\n type: \"calendar_check\" | \"memory_shed\" | \"growth_report\",\n options?: { pattern?: string; reportType?: \"weekly\" | \"monthly\" }\n): Promise<void> {\n const task: ScheduledTask = {\n type,\n userId,\n metadata: options?.reportType ? { reportType: options.reportType } : undefined,\n };\n\n if (options?.pattern) {\n await maintenanceQueue.add(`${type}-${userId}`, task, {\n repeat: { pattern: options.pattern },\n removeOnComplete: true,\n });\n } else {\n await maintenanceQueue.add(`${type}-${userId}`, task, {\n removeOnComplete: true,\n });\n }\n}\n\n// Shutdown all workers\nexport async function shutdownScheduler(): Promise<void> {\n stopWorker();\n stopMaintenanceWorker();\n stopAgentWorker();\n if (_connection) await _connection.quit();\n console.log(\"[Scheduler] Shutdown complete\");\n}\n\n// Helper to schedule a reminder\nexport async function scheduleReminder(\n message: string,\n delayMs: number,\n chatId?: string\n): Promise<string> {\n return scheduleTask(\n {\n type: \"reminder\",\n message,\n chatId,\n },\n delayMs\n );\n}\n\n// Generate morning briefing content\nexport async function generateBriefing(userId?: string): Promise<string> {\n // Try to use calendar-aware briefing\n if (userId) {\n try {\n return await generateDailyBriefing(userId, []);\n } catch {\n // Fall back to simple briefing\n }\n }\n\n const response = await chat(\n [\n {\n role: \"user\",\n content: `Generate a brief morning briefing. Include:\n1. A motivational greeting\n2. Today's date and day of week\n3. A productivity tip\n\nKeep it concise and uplifting.`,\n },\n ],\n \"You are a helpful assistant creating a morning briefing.\"\n );\n\n return response.content;\n}\n\n// Get queue stats\nexport async function getQueueStats(): Promise<{\n tasks: { waiting: number; active: number; completed: number; failed: number };\n maintenance: { waiting: number; active: number; completed: number; failed: number };\n}> {\n const [taskStats, maintenanceStats] = await Promise.all([\n Promise.all([\n taskQueue.getWaitingCount(),\n taskQueue.getActiveCount(),\n taskQueue.getCompletedCount(),\n taskQueue.getFailedCount(),\n ]),\n Promise.all([\n maintenanceQueue.getWaitingCount(),\n maintenanceQueue.getActiveCount(),\n maintenanceQueue.getCompletedCount(),\n maintenanceQueue.getFailedCount(),\n ]),\n ]);\n\n return {\n tasks: {\n waiting: taskStats[0],\n active: taskStats[1],\n completed: taskStats[2],\n failed: taskStats[3],\n },\n maintenance: {\n waiting: maintenanceStats[0],\n active: maintenanceStats[1],\n completed: maintenanceStats[2],\n failed: maintenanceStats[3],\n },\n };\n}\n\nexport { taskQueue, maintenanceQueue, connection };\n","import { Worker, Job } from \"bullmq\";\nimport Redis from \"ioredis\";\nimport { env } from \"../../config/env\";\nimport {\n AgentType,\n AgentResult,\n AGENT_SYSTEM_PROMPTS,\n AGENT_TOOL_PERMISSIONS,\n} from \"./agent-types\";\nimport {\n updateAgentStatus,\n addAgentMessage,\n addAgentProgress,\n shouldAgentStop,\n updateAgentTokens,\n getAgent,\n} from \"./agent-manager\";\nimport { TOOLS, executeTool } from \"../../tools\";\nimport { riskEngine } from \"../intelligence/risk-engine\";\nimport { metric } from \"../observability/metrics\";\nimport { captureException } from \"../observability/error-tracker\";\nimport { providerRegistry } from \"../providers\";\nimport type { LLMMessage, LLMContentBlock, LLMTool } from \"../providers/types\";\n\n// Redis connection\nconst connection = new Redis(env.REDIS_URL, {\n maxRetriesPerRequest: null,\n});\n\ninterface AgentJobData {\n agentId: string;\n userId: string;\n type: AgentType;\n objective: string;\n context?: Record<string, unknown>;\n tokenBudget: number;\n timeBudgetMs: number;\n}\n\nlet worker: Worker | null = null;\n\n// Process an agent task\nasync function processAgentTask(job: Job<AgentJobData>): Promise<AgentResult> {\n const { agentId, userId, type, objective, context, tokenBudget } = job.data;\n const startTime = Date.now();\n let totalTokensUsed = 0;\n\n console.log(`[Agent ${agentId}] Starting ${type} agent: ${objective}`);\n\n // Update status to running\n await updateAgentStatus(agentId, \"running\");\n await addAgentProgress(agentId, 1, \"Starting agent\", \"running\");\n\n // Build system prompt\n const systemPrompt = buildSystemPrompt(type, context);\n\n // Get the configured LLM provider (respects LLM_PROVIDER env var)\n const provider = providerRegistry.getDefault();\n\n // Get allowed tools for this agent type\n const allowedToolNames = AGENT_TOOL_PERMISSIONS[type];\n const agentTools = TOOLS\n .filter((t) => allowedToolNames.includes(t.name))\n .map((t) => ({\n name: t.name,\n description: t.description || \"\",\n input_schema: (t.input_schema || { type: \"object\" as const, properties: {} }) as LLMTool[\"input_schema\"],\n }));\n\n // Build initial messages\n const userContent = `Your objective: ${objective}\n\n${context ? `Additional context:\\n${JSON.stringify(context, null, 2)}` : \"\"}\n\nPlease proceed with the task, reporting your progress as you go.`;\n\n const messages: LLMMessage[] = [\n { role: \"user\", content: userContent },\n ];\n\n await addAgentMessage(agentId, {\n role: \"user\",\n content: userContent,\n });\n\n let stepNumber = 2;\n const maxSteps = 20; // Prevent infinite loops\n\n try {\n // Agent loop\n while (stepNumber <= maxSteps) {\n // Check if we should stop\n const stopCheck = await shouldAgentStop(agentId);\n if (stopCheck.stop) {\n await addAgentProgress(\n agentId,\n stepNumber,\n `Stopping: ${stopCheck.reason}`,\n \"completed\"\n );\n break;\n }\n\n // Call the configured LLM provider (Claude, Gemini, OpenAI, etc.)\n const response = await provider.createMessage({\n model: \"\", // Use provider's default model\n max_tokens: 4096,\n system: systemPrompt,\n tools: agentTools,\n messages,\n });\n\n // Track tokens\n totalTokensUsed += response.usage.input_tokens + response.usage.output_tokens;\n await updateAgentTokens(agentId, totalTokensUsed);\n\n // Check token budget\n if (totalTokensUsed >= tokenBudget) {\n await addAgentProgress(\n agentId,\n stepNumber,\n \"Token budget reached\",\n \"completed\"\n );\n break;\n }\n\n // Process response\n const assistantContent = response.content;\n\n // Extract text for logging\n const textContent = assistantContent\n .filter((c) => c.type === \"text\")\n .map((c) => c.text || \"\")\n .join(\"\\n\");\n\n if (textContent) {\n await addAgentMessage(agentId, {\n role: \"assistant\",\n content: textContent,\n });\n\n // Extract progress description from text\n const progressDesc = textContent.slice(0, 200).replace(/\\n/g, \" \");\n await addAgentProgress(agentId, stepNumber, progressDesc, \"running\");\n }\n\n // Check if done\n if (response.stop_reason === \"end_turn\") {\n // Agent completed naturally\n await addAgentProgress(\n agentId,\n stepNumber + 1,\n \"Task completed\",\n \"completed\",\n textContent\n );\n\n return {\n success: true,\n output: textContent,\n summary: extractSummary(textContent),\n tokensUsed: totalTokensUsed,\n durationMs: Date.now() - startTime,\n };\n }\n\n // Process tool calls\n if (response.stop_reason === \"tool_use\") {\n const toolResultBlocks: LLMContentBlock[] = [];\n\n for (const block of assistantContent) {\n if (block.type === \"tool_use\") {\n const toolName = block.name!;\n const toolInput = block.input as Record<string, unknown>;\n\n console.log(`[Agent ${agentId}] Using tool: ${toolName}`);\n\n // Risk engine gate: evaluate before executing any tool from an agent\n const riskDecision = await riskEngine.evaluate({\n action: \"agent_tool_execute\",\n userId,\n toolName,\n input: toolInput,\n metadata: { agentId, agentType: type },\n });\n\n if (!riskDecision.allowed) {\n const failedChecks = riskDecision.checks\n .filter((c) => !c.passed)\n .map((c) => c.message)\n .join(\"; \");\n const result = {\n success: false,\n result: null,\n error: `[RiskEngine] Agent tool blocked: ${failedChecks}`,\n };\n\n await addAgentMessage(agentId, {\n role: \"tool_result\",\n content: JSON.stringify({ tool: toolName, result }),\n metadata: { toolInput },\n });\n\n toolResultBlocks.push({\n type: \"tool_result\",\n tool_use_id: block.id!,\n content: JSON.stringify(result),\n });\n continue;\n }\n\n // Inject caller context for financial tools\n if (toolName === \"crypto_exchange\") {\n toolInput._callerContext = \"agent\";\n }\n\n // Execute tool\n const result = await executeTool(toolName, toolInput);\n\n await addAgentMessage(agentId, {\n role: \"tool_result\",\n content: JSON.stringify({ tool: toolName, result }),\n metadata: { toolInput },\n });\n\n toolResultBlocks.push({\n type: \"tool_result\",\n tool_use_id: block.id!,\n content: JSON.stringify(result),\n });\n }\n }\n\n // Add assistant response and tool results to messages\n messages.push({ role: \"assistant\", content: assistantContent });\n messages.push({ role: \"user\", content: toolResultBlocks });\n }\n\n stepNumber++;\n }\n\n // Max steps reached\n const agent = await getAgent(agentId);\n const lastMessage = agent?.messages.slice(-1)[0]?.content || \"\";\n\n return {\n success: true,\n output: lastMessage,\n summary: \"Agent completed maximum steps\",\n tokensUsed: totalTokensUsed,\n durationMs: Date.now() - startTime,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n await captureException(error, \"agent\", {\n agentId,\n type,\n objective,\n }, userId);\n\n await addAgentProgress(\n agentId,\n stepNumber,\n `Error: ${errorMessage}`,\n \"failed\"\n );\n\n return {\n success: false,\n error: errorMessage,\n tokensUsed: totalTokensUsed,\n durationMs: Date.now() - startTime,\n };\n }\n}\n\nfunction buildSystemPrompt(\n type: AgentType,\n context?: Record<string, unknown>\n): string {\n let prompt = AGENT_SYSTEM_PROMPTS[type];\n\n if (context) {\n prompt += `\\n\\nAdditional context about the user/task:\\n${JSON.stringify(context, null, 2)}`;\n }\n\n return prompt;\n}\n\nfunction extractSummary(text: string): string {\n // Try to find a summary section\n const summaryMatch = text.match(/(?:summary|conclusion|result):\\s*(.+?)(?:\\n\\n|$)/i);\n if (summaryMatch) {\n return summaryMatch[1].trim();\n }\n\n // Otherwise, take the last paragraph\n const paragraphs = text.split(\"\\n\\n\").filter((p) => p.trim());\n return paragraphs.slice(-1)[0]?.slice(0, 500) || text.slice(0, 500);\n}\n\n// Start the agent worker\nexport function startAgentWorker(): void {\n if (worker) return;\n\n worker = new Worker(\n \"sentinel-agents\",\n async (job: Job<AgentJobData>) => {\n const result = await processAgentTask(job);\n\n // Update final status\n await updateAgentStatus(\n job.data.agentId,\n result.success ? \"completed\" : \"failed\",\n result\n );\n\n // Record metric\n metric.agentOperation(\"complete\", job.data.type);\n\n return result;\n },\n {\n connection,\n concurrency: 3, // Run up to 3 agents concurrently\n }\n );\n\n worker.on(\"completed\", (job) => {\n console.log(`[AgentWorker] Agent completed: ${job.data.agentId}`);\n });\n\n worker.on(\"failed\", (job, err) => {\n console.error(`[AgentWorker] Agent failed: ${job?.data.agentId}`, err);\n });\n\n console.log(\"[AgentWorker] Agent worker started\");\n}\n\n// Stop the agent worker\nexport function stopAgentWorker(): void {\n if (worker) {\n worker.close();\n worker = null;\n }\n}\n\nexport default {\n startAgentWorker,\n stopAgentWorker,\n};\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\";\nimport { memories, archivedMemories } from \"../../db/schema\";\nimport { eq, and, lt, lte, sql } from \"drizzle-orm\";\n\nexport type ShedReason =\n | \"stale\"\n | \"duplicate\"\n | \"low_importance\"\n | \"user_request\"\n | \"deprecated_workflow\";\n\nexport interface ShedCandidate {\n memoryId: string;\n content: string;\n type: string;\n reason: ShedReason;\n lastAccessed: Date | null;\n importance: number;\n confidence: number; // How confident we are this should be shed (0-100)\n}\n\nexport interface ShedResult {\n archivedCount: number;\n archivedIds: string[];\n skippedCount: number;\n}\n\n// Configuration for memory shedding\nconst SHED_CONFIG = {\n staleDays: 90, // Memories not accessed in 90 days\n lowImportanceThreshold: 3, // Memories with importance <= 3\n minConfidence: 70, // Minimum confidence to auto-shed\n};\n\n// Find stale memories (not accessed recently)\nexport async function findStaleMemories(\n userId: string,\n staleDays: number = SHED_CONFIG.staleDays\n): Promise<ShedCandidate[]> {\n const cutoff = new Date(Date.now() - staleDays * 24 * 60 * 60 * 1000);\n\n const stale = await db\n .select()\n .from(memories)\n .where(\n and(\n eq(memories.userId, userId),\n lt(memories.lastAccessed, cutoff)\n )\n );\n\n return stale.map((m) => ({\n memoryId: m.id,\n content: m.content,\n type: m.type,\n reason: \"stale\" as ShedReason,\n lastAccessed: m.lastAccessed,\n importance: m.importance || 5,\n confidence: calculateStaleConfidence(m.lastAccessed, m.importance || 5),\n }));\n}\n\nfunction calculateStaleConfidence(\n lastAccessed: Date | null,\n importance: number\n): number {\n if (!lastAccessed) return 80;\n\n const daysSinceAccess = Math.floor(\n (Date.now() - lastAccessed.getTime()) / (24 * 60 * 60 * 1000)\n );\n\n // Higher confidence for older, less important memories\n let confidence = Math.min(daysSinceAccess / 2, 50); // Max 50 from age\n confidence += (10 - importance) * 5; // Up to 50 from low importance\n\n return Math.min(confidence, 100);\n}\n\n// Find low importance memories\nexport async function findLowImportanceMemories(\n userId: string,\n threshold: number = SHED_CONFIG.lowImportanceThreshold\n): Promise<ShedCandidate[]> {\n const lowImportance = await db\n .select()\n .from(memories)\n .where(\n and(\n eq(memories.userId, userId),\n lte(memories.importance, threshold)\n )\n );\n\n return lowImportance.map((m) => ({\n memoryId: m.id,\n content: m.content,\n type: m.type,\n reason: \"low_importance\" as ShedReason,\n lastAccessed: m.lastAccessed,\n importance: m.importance || 5,\n confidence: (SHED_CONFIG.lowImportanceThreshold - (m.importance || 5) + 1) * 25,\n }));\n}\n\n// Find potential duplicate memories (simplified - would need better NLP in production)\nexport async function findDuplicateMemories(\n userId: string\n): Promise<ShedCandidate[]> {\n const allMemories = await db\n .select()\n .from(memories)\n .where(eq(memories.userId, userId));\n\n const candidates: ShedCandidate[] = [];\n const seen = new Map<string, typeof allMemories[0]>();\n\n for (const memory of allMemories) {\n // Simple duplicate detection: normalize and check for similar content\n const normalized = memory.content.toLowerCase().trim();\n const key = normalized.slice(0, 100); // Use first 100 chars as key\n\n const existing = seen.get(key);\n if (existing) {\n // Mark the newer one as duplicate (keep older memories)\n const isDuplicate =\n memory.createdAt > existing.createdAt ? memory : existing;\n\n candidates.push({\n memoryId: isDuplicate.id,\n content: isDuplicate.content,\n type: isDuplicate.type,\n reason: \"duplicate\",\n lastAccessed: isDuplicate.lastAccessed,\n importance: isDuplicate.importance || 5,\n confidence: 75, // Fairly confident about duplicates\n });\n } else {\n seen.set(key, memory);\n }\n }\n\n return candidates;\n}\n\n// Get all shed candidates for a user\nexport async function identifyShedCandidates(\n userId: string\n): Promise<ShedCandidate[]> {\n const [stale, lowImportance, duplicates] = await Promise.all([\n findStaleMemories(userId),\n findLowImportanceMemories(userId),\n findDuplicateMemories(userId),\n ]);\n\n // Combine and deduplicate by memoryId\n const candidateMap = new Map<string, ShedCandidate>();\n\n for (const candidate of [...stale, ...lowImportance, ...duplicates]) {\n const existing = candidateMap.get(candidate.memoryId);\n if (!existing || candidate.confidence > existing.confidence) {\n candidateMap.set(candidate.memoryId, candidate);\n }\n }\n\n return Array.from(candidateMap.values()).sort(\n (a, b) => b.confidence - a.confidence\n );\n}\n\n// Archive a single memory\nexport async function archiveMemory(\n memoryId: string,\n reason: ShedReason\n): Promise<boolean> {\n const [memory] = await db\n .select()\n .from(memories)\n .where(eq(memories.id, memoryId))\n .limit(1);\n\n if (!memory) return false;\n\n // Insert into archived memories\n await db.insert(archivedMemories).values({\n originalMemoryId: memory.id,\n userId: memory.userId,\n type: memory.type,\n content: memory.content,\n reason,\n originalCreatedAt: memory.createdAt,\n });\n\n // Delete from active memories\n await db.delete(memories).where(eq(memories.id, memoryId));\n\n return true;\n}\n\n// Archive multiple memories\nexport async function archiveMemories(\n memoryIds: string[],\n reason: ShedReason\n): Promise<ShedResult> {\n let archivedCount = 0;\n const archivedIds: string[] = [];\n\n for (const id of memoryIds) {\n const success = await archiveMemory(id, reason);\n if (success) {\n archivedCount++;\n archivedIds.push(id);\n }\n }\n\n return {\n archivedCount,\n archivedIds,\n skippedCount: memoryIds.length - archivedCount,\n };\n}\n\n// Auto-shed memories based on confidence threshold\nexport async function autoShed(\n userId: string,\n minConfidence: number = SHED_CONFIG.minConfidence\n): Promise<ShedResult> {\n const candidates = await identifyShedCandidates(userId);\n const toArchive = candidates.filter((c) => c.confidence >= minConfidence);\n\n const results: ShedResult = {\n archivedCount: 0,\n archivedIds: [],\n skippedCount: 0,\n };\n\n for (const candidate of toArchive) {\n const success = await archiveMemory(candidate.memoryId, candidate.reason);\n if (success) {\n results.archivedCount++;\n results.archivedIds.push(candidate.memoryId);\n } else {\n results.skippedCount++;\n }\n }\n\n return results;\n}\n\n// Restore an archived memory\nexport async function restoreMemory(archivedId: string): Promise<boolean> {\n const [archived] = await db\n .select()\n .from(archivedMemories)\n .where(eq(archivedMemories.id, archivedId))\n .limit(1);\n\n if (!archived) return false;\n\n // Re-insert into active memories (without embedding - would need to regenerate)\n await db.insert(memories).values({\n userId: archived.userId,\n type: archived.type as \"episodic\" | \"semantic\" | \"procedural\",\n content: archived.content,\n importance: 5, // Reset to medium importance\n source: \"restored\",\n });\n\n // Remove from archive\n await db.delete(archivedMemories).where(eq(archivedMemories.id, archivedId));\n\n return true;\n}\n\n// Get archived memories for a user\nexport async function getArchivedMemories(\n userId: string,\n limit: number = 50\n): Promise<typeof archivedMemories.$inferSelect[]> {\n return db\n .select()\n .from(archivedMemories)\n .where(eq(archivedMemories.userId, userId))\n .limit(limit);\n}\n\n// Get shedding statistics\nexport async function getShedStats(\n userId: string\n): Promise<{\n totalArchived: number;\n byReason: Record<ShedReason, number>;\n pendingCandidates: number;\n}> {\n const archived = await getArchivedMemories(userId, 1000);\n const candidates = await identifyShedCandidates(userId);\n\n const byReason: Record<ShedReason, number> = {\n stale: 0,\n duplicate: 0,\n low_importance: 0,\n user_request: 0,\n deprecated_workflow: 0,\n };\n\n for (const memory of archived) {\n const reason = memory.reason as ShedReason;\n if (reason in byReason) {\n byReason[reason]++;\n }\n }\n\n return {\n totalArchived: archived.length,\n byReason,\n pendingCandidates: candidates.length,\n };\n}\n\n// Cleanup old archives (permanent deletion)\nexport async function cleanupOldArchives(\n daysToKeep: number = 365\n): Promise<number> {\n const cutoff = new Date(Date.now() - daysToKeep * 24 * 60 * 60 * 1000);\n\n await db\n .delete(archivedMemories)\n .where(lt(archivedMemories.archivedAt, cutoff));\n\n return 0; // Cleanup completed\n}\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"]}
|