@triedotdev/mcp 1.0.136 → 1.0.138

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +6 -6
  2. package/dist/{autonomy-config-QA6ATWLJ.js → autonomy-config-TZ6HF4FA.js} +3 -3
  3. package/dist/{chat-store-HFOOWZYN.js → chat-store-OJLJCJFI.js} +3 -3
  4. package/dist/{chunk-DFPVUMVE.js → chunk-23RJT5WT.js} +5 -4
  5. package/dist/chunk-23RJT5WT.js.map +1 -0
  6. package/dist/{chunk-4YJ6KLGI.js → chunk-3MUCUZ46.js} +8 -8
  7. package/dist/chunk-3MUCUZ46.js.map +1 -0
  8. package/dist/{chunk-6VIMBFUZ.js → chunk-3RRXWX3V.js} +21 -17
  9. package/dist/chunk-3RRXWX3V.js.map +1 -0
  10. package/dist/{chunk-WHIQAGB7.js → chunk-4C67GV3O.js} +2 -2
  11. package/dist/{chunk-WS6OA7H6.js → chunk-4MJ52WBH.js} +2 -3
  12. package/dist/chunk-4MJ52WBH.js.map +1 -0
  13. package/dist/{chunk-AJ34GCMD.js → chunk-67GSG2ST.js} +41 -38
  14. package/dist/chunk-67GSG2ST.js.map +1 -0
  15. package/dist/{chunk-UHX4462X.js → chunk-6LLH3TBZ.js} +24 -25
  16. package/dist/chunk-6LLH3TBZ.js.map +1 -0
  17. package/dist/{chunk-DFHMB44X.js → chunk-D3AS5LY7.js} +6 -10
  18. package/dist/chunk-D3AS5LY7.js.map +1 -0
  19. package/dist/{chunk-6OUWNVLX.js → chunk-EDDT4ZIH.js} +8 -8
  20. package/dist/chunk-EDDT4ZIH.js.map +1 -0
  21. package/dist/{chunk-Z4DN527J.js → chunk-FG467PDD.js} +156 -39
  22. package/dist/chunk-FG467PDD.js.map +1 -0
  23. package/dist/{chunk-T4THB2OR.js → chunk-FOCXXIXY.js} +49 -28
  24. package/dist/chunk-FOCXXIXY.js.map +1 -0
  25. package/dist/{goal-validator-PDKYZSNP.js → chunk-GFFUDJMK.js} +97 -40
  26. package/dist/chunk-GFFUDJMK.js.map +1 -0
  27. package/dist/{chunk-ZEXMMTIQ.js → chunk-J5EMP4XW.js} +2 -2
  28. package/dist/{chunk-UHMMANC2.js → chunk-LT6VUZG2.js} +21 -18
  29. package/dist/chunk-LT6VUZG2.js.map +1 -0
  30. package/dist/{chunk-55CBWOEZ.js → chunk-QSWUPSLK.js} +2 -2
  31. package/dist/{chunk-45Y5TLQZ.js → chunk-SH7H3WRU.js} +3 -6
  32. package/dist/chunk-SH7H3WRU.js.map +1 -0
  33. package/dist/{chunk-VRLMTOB6.js → chunk-TIMIKBY2.js} +1 -1
  34. package/dist/chunk-TIMIKBY2.js.map +1 -0
  35. package/dist/{chunk-POHBQUG7.js → chunk-X3F5QDER.js} +1224 -448
  36. package/dist/chunk-X3F5QDER.js.map +1 -0
  37. package/dist/{chunk-O6OTJI3W.js → chunk-Y32FM3MR.js} +2 -2
  38. package/dist/{chunk-G5PRBQIQ.js → chunk-YOKQ25IW.js} +102 -82
  39. package/dist/chunk-YOKQ25IW.js.map +1 -0
  40. package/dist/{chunk-JAKMZI5S.js → chunk-Z2P4WST6.js} +291 -180
  41. package/dist/chunk-Z2P4WST6.js.map +1 -0
  42. package/dist/cli/create-agent.js +1 -1
  43. package/dist/cli/main.js +113 -86
  44. package/dist/cli/main.js.map +1 -1
  45. package/dist/cli/yolo-daemon.js +19 -19
  46. package/dist/cli/yolo-daemon.js.map +1 -1
  47. package/dist/{client-BZHI675W.js → client-JTU5TRLB.js} +3 -3
  48. package/dist/{codebase-index-CR6Q2HEI.js → codebase-index-FNJ4GCBE.js} +3 -3
  49. package/dist/{goal-manager-FAK7H4RR.js → goal-manager-6BJQ36AH.js} +7 -8
  50. package/dist/goal-validator-GISXYANK.js +22 -0
  51. package/dist/{graph-PAUZ5EMP.js → graph-X2FMRQLG.js} +3 -3
  52. package/dist/{hypothesis-L5446W36.js → hypothesis-K3KQJOXJ.js} +7 -8
  53. package/dist/{incident-index-ZCDSJ42L.js → incident-index-BWW2UEY7.js} +3 -3
  54. package/dist/index.js +343 -288
  55. package/dist/index.js.map +1 -1
  56. package/dist/{insight-store-F5KDBY5Y.js → insight-store-A5XXMFD6.js} +6 -6
  57. package/dist/issue-store-BO5OWLJW.js +32 -0
  58. package/dist/{output-manager-BOTMXSND.js → output-manager-DZO5LGSG.js} +2 -2
  59. package/dist/{tiered-storage-QW2G7GSG.js → tiered-storage-VZL7KK64.js} +3 -3
  60. package/dist/trie-agent-XMSGMD7E.js +26 -0
  61. package/dist/trie-agent-XMSGMD7E.js.map +1 -0
  62. package/dist/ui/chat.html +260 -67
  63. package/dist/ui/goals.html +246 -3
  64. package/dist/ui/hypotheses.html +248 -5
  65. package/dist/ui/ledger.html +252 -9
  66. package/dist/ui/nudges.html +244 -1
  67. package/package.json +1 -1
  68. package/dist/chunk-45Y5TLQZ.js.map +0 -1
  69. package/dist/chunk-4YJ6KLGI.js.map +0 -1
  70. package/dist/chunk-6OUWNVLX.js.map +0 -1
  71. package/dist/chunk-6VIMBFUZ.js.map +0 -1
  72. package/dist/chunk-AJ34GCMD.js.map +0 -1
  73. package/dist/chunk-DFHMB44X.js.map +0 -1
  74. package/dist/chunk-DFPVUMVE.js.map +0 -1
  75. package/dist/chunk-G5PRBQIQ.js.map +0 -1
  76. package/dist/chunk-JAKMZI5S.js.map +0 -1
  77. package/dist/chunk-PEJEYWVR.js +0 -135
  78. package/dist/chunk-PEJEYWVR.js.map +0 -1
  79. package/dist/chunk-POHBQUG7.js.map +0 -1
  80. package/dist/chunk-T4THB2OR.js.map +0 -1
  81. package/dist/chunk-UHMMANC2.js.map +0 -1
  82. package/dist/chunk-UHX4462X.js.map +0 -1
  83. package/dist/chunk-VRLMTOB6.js.map +0 -1
  84. package/dist/chunk-WS6OA7H6.js.map +0 -1
  85. package/dist/chunk-Z4DN527J.js.map +0 -1
  86. package/dist/goal-validator-PDKYZSNP.js.map +0 -1
  87. package/dist/guardian-agent-4RHGIXUD.js +0 -27
  88. package/dist/ledger-WKVJWHBX.js +0 -17
  89. /package/dist/{autonomy-config-QA6ATWLJ.js.map → autonomy-config-TZ6HF4FA.js.map} +0 -0
  90. /package/dist/{chat-store-HFOOWZYN.js.map → chat-store-OJLJCJFI.js.map} +0 -0
  91. /package/dist/{chunk-WHIQAGB7.js.map → chunk-4C67GV3O.js.map} +0 -0
  92. /package/dist/{chunk-ZEXMMTIQ.js.map → chunk-J5EMP4XW.js.map} +0 -0
  93. /package/dist/{chunk-55CBWOEZ.js.map → chunk-QSWUPSLK.js.map} +0 -0
  94. /package/dist/{chunk-O6OTJI3W.js.map → chunk-Y32FM3MR.js.map} +0 -0
  95. /package/dist/{client-BZHI675W.js.map → client-JTU5TRLB.js.map} +0 -0
  96. /package/dist/{codebase-index-CR6Q2HEI.js.map → codebase-index-FNJ4GCBE.js.map} +0 -0
  97. /package/dist/{goal-manager-FAK7H4RR.js.map → goal-manager-6BJQ36AH.js.map} +0 -0
  98. /package/dist/{graph-PAUZ5EMP.js.map → goal-validator-GISXYANK.js.map} +0 -0
  99. /package/dist/{guardian-agent-4RHGIXUD.js.map → graph-X2FMRQLG.js.map} +0 -0
  100. /package/dist/{hypothesis-L5446W36.js.map → hypothesis-K3KQJOXJ.js.map} +0 -0
  101. /package/dist/{incident-index-ZCDSJ42L.js.map → incident-index-BWW2UEY7.js.map} +0 -0
  102. /package/dist/{insight-store-F5KDBY5Y.js.map → insight-store-A5XXMFD6.js.map} +0 -0
  103. /package/dist/{ledger-WKVJWHBX.js.map → issue-store-BO5OWLJW.js.map} +0 -0
  104. /package/dist/{output-manager-BOTMXSND.js.map → output-manager-DZO5LGSG.js.map} +0 -0
  105. /package/dist/{tiered-storage-QW2G7GSG.js.map → tiered-storage-VZL7KK64.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/guardian/guardian-agent.ts","../src/guardian/risk-predictor.ts","../src/integrations/slack.ts","../src/guardian/escalation.ts","../src/guardian/meta-learning.ts"],"sourcesContent":["/**\n * Guardian Agent - A proactive, intelligent agent that watches over your codebase\n * \n * Unlike passive notification systems, the Guardian:\n * - Synthesizes insights from multiple skills\n * - Speaks conversationally, like a helpful colleague\n * - Suggests specific actions, not just problems\n * - Tracks patterns over time and learns\n * - Anticipates issues before they become critical\n * \n * Integration:\n * - Uses existing memory infrastructure (issue-store, global-memory)\n * - Persistent insight storage (survives restarts)\n * - Goal tracking and hypothesis validation\n * - Optionally enhances with LLM when ANTHROPIC_API_KEY is available\n * \n * Phase 1+ Guardian Agency: Full persistence support\n */\n\nimport type { Issue } from '../types/index.js';\nimport { storeIssues, autoResolveIssues, getIssueHash } from '../memory/issue-store.js';\nimport { recordToGlobalMemory, findCrossProjectPatterns } from '../memory/global-memory.js';\nimport { getHistoricalInsights } from '../memory/compactor.js';\nimport { isAIAvailable, runAIAnalysis } from '../ai/client.js';\nimport { basename } from 'path';\nimport { getInsightStore, type GuardianInsight } from './insight-store.js';\nimport { getGuardianState } from './guardian-state.js';\nimport { getGoalManager } from './goal-manager.js';\nimport { getRiskPredictor } from './risk-predictor.js';\nimport { getHypothesisEngine } from './hypothesis.js';\nimport { getEscalationManager } from './escalation.js';\nimport { getMetaLearner } from './meta-learning.js';\nimport { GotchaPredictor } from './gotcha-predictor.js';\nimport { ContextGraph } from '../context/graph.js';\n\n// Re-export GuardianInsight type from insight-store for backward compatibility\nexport type { GuardianInsight } from './insight-store.js';\n\n// Personality phrases for different situations\nconst PERSONALITY = {\n greetings: [\n \"Hey, quick heads up...\",\n \"Noticed something while scanning...\",\n \"Worth mentioning...\",\n \"Just so you know...\",\n \"Spotted this...\",\n ],\n warnings: [\n \"This needs your attention:\",\n \"I'd pause on this:\",\n \"Before you push...\",\n \"Hold up —\",\n \"Important:\",\n ],\n celebrations: [\n \"Nice work!\",\n \"Good catch!\",\n \"That's better.\",\n \"Clean.\",\n \"Progress.\",\n ],\n suggestions: [\n \"You might want to\",\n \"Consider\",\n \"Suggestion:\",\n \"Quick win:\",\n \"Idea:\",\n ],\n questions: [\n \"Did you mean to\",\n \"Should this\",\n \"Is it intentional that\",\n \"Quick question:\",\n ],\n};\n\nexport class GuardianAgent {\n private projectPath: string;\n private projectName: string;\n private lastIssueHashes: Set<string> = new Set();\n private initialized: boolean = false;\n \n // Persistent stores (Phase 1 Guardian Agency)\n private insightStore;\n private guardianState;\n \n // Agency modules (Phases 2-4)\n private goalManager;\n private riskPredictor;\n private hypothesisEngine;\n private escalationManager;\n private metaLearner;\n private gotchaPredictor;\n \n constructor(projectPath: string) {\n this.projectPath = projectPath;\n this.projectName = basename(projectPath);\n \n // Initialize persistent stores (Phase 1)\n this.insightStore = getInsightStore(projectPath);\n this.guardianState = getGuardianState(projectPath);\n \n // Initialize agency modules (Phases 2-4)\n this.goalManager = getGoalManager(projectPath);\n this.riskPredictor = getRiskPredictor(projectPath);\n this.hypothesisEngine = getHypothesisEngine(projectPath);\n this.escalationManager = getEscalationManager(projectPath);\n this.metaLearner = getMetaLearner(projectPath);\n this.gotchaPredictor = new GotchaPredictor(projectPath, new ContextGraph(projectPath));\n }\n \n /**\n * Initialize the Guardian - loads persistent state and historical data\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n \n try {\n // Load persistent stores (Phase 1 Guardian Agency)\n await this.insightStore.load();\n await this.guardianState.load();\n \n // Update last active timestamp\n await this.guardianState.touchActive();\n \n // Get historical context from existing memory infrastructure\n const historical = await getHistoricalInsights(this.projectPath);\n \n // If we have history, we can detect trends\n if (historical && historical.totalHistoricalIssues > 0) {\n const trend = historical.improvementTrend;\n if (trend === 'improving' && this.canCreateInsight('progress-trend')) {\n await this.addInsight(this.createInsight({\n type: 'celebration',\n message: `${this.pick(PERSONALITY.celebrations)} Your code quality has been improving over time.`,\n priority: 2,\n category: 'progress',\n }));\n await this.markInsightCreated('progress-trend');\n } else if (trend === 'declining' && this.canCreateInsight('progress-trend')) {\n await this.addInsight(this.createInsight({\n type: 'observation',\n message: `${this.pick(PERSONALITY.greetings)} Issue count has been trending up. Might be worth a focused cleanup session.`,\n suggestedAction: 'Run `trie scan` and address top issues',\n priority: 5,\n category: 'quality',\n }));\n await this.markInsightCreated('progress-trend');\n }\n }\n \n this.initialized = true;\n } catch {\n // Memory might not exist yet - that's fine\n this.initialized = true;\n }\n }\n \n /**\n * Add an insight to persistent storage\n */\n async addInsight(insight: GuardianInsight): Promise<boolean> {\n return this.insightStore.addInsight(insight);\n }\n \n /**\n * Restart the Guardian (reload state from disk)\n */\n async restart(): Promise<void> {\n this.initialized = false;\n await this.insightStore.reload();\n await this.guardianState.reload();\n await this.initialize();\n }\n \n /**\n * Load state from disk (for testing)\n */\n async loadState(): Promise<{ goals: any[]; riskBudget: any }> {\n await this.guardianState.load();\n return {\n goals: this.guardianState.getAllGoals(),\n riskBudget: this.guardianState.getRiskBudget(),\n };\n }\n \n /**\n * Process new issues from a scan and generate insights\n * Stores issues in memory and optionally uses LLM for deeper analysis\n */\n async processIssues(issues: Issue[], context: { filesChanged?: string[]; isWatchMode: boolean }): Promise<GuardianInsight[]> {\n const newInsights: GuardianInsight[] = [];\n \n // 1. Store issues in memory infrastructure\n try {\n await storeIssues(issues, this.projectName, this.projectPath);\n await recordToGlobalMemory(issues, this.projectName, this.projectPath);\n \n // Auto-resolve issues no longer detected in changed files\n if (context.filesChanged && context.filesChanged.length > 0) {\n const currentHashes = new Set(issues.map(i => getIssueHash(i)));\n await autoResolveIssues(currentHashes, context.filesChanged, this.projectPath);\n }\n } catch {\n // Memory errors shouldn't break the Guardian\n }\n \n // 2. Detect changes from last scan\n const currentHashes = new Set(issues.map(i => `${i.file}:${i.line}:${i.issue.slice(0, 50)}`));\n const newIssues = issues.filter(i => !this.lastIssueHashes.has(`${i.file}:${i.line}:${i.issue.slice(0, 50)}`));\n const fixedCount = [...this.lastIssueHashes].filter(h => !currentHashes.has(h)).length;\n \n // 3. Generate heuristic insights (with cooldowns to avoid duplicates)\n \n // Accessibility issues with visual QA recommendation\n const accessibilityIssues = issues.filter(i => \n i.agent === 'accessibility' && \n (i.severity === 'critical' || i.severity === 'serious')\n );\n \n if (accessibilityIssues.length >= 2 && this.canCreateInsight('accessibility-visual-qa')) {\n const critical = accessibilityIssues.filter(i => i.severity === 'critical');\n const serious = accessibilityIssues.filter(i => i.severity === 'serious');\n \n const breakdown: Record<string, number> = {};\n if (critical.length > 0) breakdown['critical'] = critical.length;\n if (serious.length > 0) breakdown['serious'] = serious.length;\n \n const affectedFiles = [...new Set(accessibilityIssues.map(i => i.file))];\n const examples = [...critical, ...serious]\n .slice(0, 3)\n .map(i => `${basename(i.file)}:${i.line} - ${i.issue.slice(0, 60)}`);\n \n const insight = this.createInsight({\n type: 'suggestion',\n message: `Found ${accessibilityIssues.length} accessibility issue${accessibilityIssues.length > 1 ? 's' : ''} that could block users. Screenshots would help validate real impact.`,\n suggestedAction: 'Capture screenshots for visual analysis',\n actionCommand: 'trie_visual_qa_browser url:\"http://localhost:3000\"',\n priority: 7,\n category: 'quality',\n relatedIssues: accessibilityIssues.map(i => i.id),\n details: {\n affectedFiles: affectedFiles.map(f => basename(f)),\n issueBreakdown: breakdown,\n examples,\n },\n });\n newInsights.push(insight);\n await this.addInsight(insight);\n await this.markInsightCreated('accessibility-visual-qa');\n }\n \n // Security concerns get immediate attention\n const securityIssues = issues.filter(i => \n i.category === 'security' || \n i.issue.toLowerCase().includes('secret') ||\n i.issue.toLowerCase().includes('vulnerability') ||\n i.issue.toLowerCase().includes('injection') ||\n i.issue.toLowerCase().includes('xss')\n );\n \n if (securityIssues.length > 0 && this.canCreateInsight('security-warning')) {\n const critical = securityIssues.filter(i => i.severity === 'critical');\n const serious = securityIssues.filter(i => i.severity === 'serious');\n if (critical.length > 0 || serious.length >= 2) {\n // Build severity breakdown\n const breakdown: Record<string, number> = {};\n if (critical.length > 0) breakdown['critical'] = critical.length;\n if (serious.length > 0) breakdown['serious'] = serious.length;\n \n // Get unique affected files\n const affectedFiles = [...new Set(securityIssues.map(i => i.file))];\n \n // Get example issues (most severe first)\n const examples = [...critical, ...serious]\n .slice(0, 3)\n .map(i => `${basename(i.file)}:${i.line} - ${i.issue.slice(0, 60)}`);\n \n const insight = this.createInsight({\n type: 'warning',\n message: `Found ${securityIssues.length} security issue${securityIssues.length > 1 ? 's' : ''} that could expose your app.`,\n suggestedAction: `Review ${affectedFiles.length} file${affectedFiles.length > 1 ? 's' : ''} immediately`,\n actionCommand: 'trie scan --skill security',\n priority: 10,\n category: 'security',\n relatedIssues: securityIssues.map(i => i.id),\n details: {\n affectedFiles: affectedFiles.map(f => basename(f)),\n issueBreakdown: breakdown,\n examples,\n },\n });\n newInsights.push(insight);\n await this.addInsight(insight);\n await this.markInsightCreated('security-warning');\n }\n }\n \n // New issues from recent changes\n if (newIssues.length >= 3 && context.filesChanged && context.filesChanged.length > 0 && this.canCreateInsight('new-issues')) {\n const affectedFiles = [...new Set(newIssues.map(i => basename(i.file)))];\n const filesChanged = context.filesChanged.map(f => basename(f));\n \n // Breakdown by severity\n const breakdown: Record<string, number> = {};\n const critical = newIssues.filter(i => i.severity === 'critical');\n const serious = newIssues.filter(i => i.severity === 'serious');\n const moderate = newIssues.filter(i => i.severity === 'moderate');\n if (critical.length > 0) breakdown['critical'] = critical.length;\n if (serious.length > 0) breakdown['serious'] = serious.length;\n if (moderate.length > 0) breakdown['moderate'] = moderate.length;\n \n // Get example issues\n const examples = newIssues\n .sort((a, b) => {\n const sev: Record<string, number> = { critical: 3, serious: 2, moderate: 1, minor: 0, low: 0 };\n return (sev[b.severity] || 0) - (sev[a.severity] || 0);\n })\n .slice(0, 3)\n .map(i => `${basename(i.file)}:${i.line} - ${i.issue.slice(0, 50)}`);\n \n const insight = this.createInsight({\n type: 'observation',\n message: `Recent changes introduced ${newIssues.length} new issues in ${affectedFiles.slice(0, 3).join(', ')}.`,\n suggestedAction: `Review ${affectedFiles.length} affected file${affectedFiles.length > 1 ? 's' : ''}`,\n priority: 6,\n category: 'quality',\n details: {\n affectedFiles: affectedFiles.slice(0, 8),\n issueBreakdown: breakdown,\n examples,\n comparison: `Changed: ${filesChanged.slice(0, 3).join(', ')}${filesChanged.length > 3 ? ` +${filesChanged.length - 3} more` : ''}`,\n },\n });\n newInsights.push(insight);\n await this.addInsight(insight);\n await this.markInsightCreated('new-issues');\n }\n \n // Celebrate fixes\n if (fixedCount > 0 && newIssues.length === 0 && this.canCreateInsight('celebration')) {\n const insight = this.createInsight({\n type: 'celebration',\n message: `${this.pick(PERSONALITY.celebrations)} ${fixedCount} issue${fixedCount > 1 ? 's' : ''} resolved.`,\n priority: 3,\n category: 'progress',\n });\n newInsights.push(insight);\n await this.addInsight(insight);\n await this.markInsightCreated('celebration');\n }\n \n // === AUTONOMOUS HYPOTHESIS GENERATION ===\n // After every scan, check if Claude should generate new hypotheses\n // This enables the agent to continuously learn and form theories about code quality\n if (issues.length >= 10 && this.canCreateInsight('hypothesis-generation')) {\n try {\n const patterns: string[] = [];\n const observations: string[] = [];\n \n // Observe patterns from this scan\n if (newIssues.length > issues.length * 0.3) {\n observations.push(`High new issue rate: ${newIssues.length} new out of ${issues.length} total`);\n }\n \n const fileFreq: Record<string, number> = {};\n for (const issue of issues) {\n fileFreq[issue.file] = (fileFreq[issue.file] || 0) + 1;\n }\n const hotFiles = Object.entries(fileFreq).filter(([, count]) => count >= 3);\n if (hotFiles.length > 0) {\n patterns.push(`Hotspot files: ${hotFiles.map(([f]) => basename(f)).join(', ')}`);\n }\n \n // Try AI-powered hypothesis generation\n const generated = await this.hypothesisEngine.generateHypothesesWithAI({\n recentIssues: issues.map(i => ({ issue: i, score: 1 })),\n patterns,\n observations,\n });\n \n // Create insights for new hypotheses\n for (const hypothesis of generated) {\n const insight = this.createInsight({\n type: 'observation',\n message: `${this.pick(PERSONALITY.questions)} New hypothesis to test: \"${hypothesis.statement}\"`,\n context: `Confidence: ${Math.round(hypothesis.confidence * 100)}%`,\n suggestedAction: `Monitor this pattern over time`,\n priority: 4,\n category: 'pattern',\n details: {\n hypothesis: hypothesis.statement,\n testCriteria: hypothesis.testCriteria || 'Collecting evidence...',\n confidence: Math.round(hypothesis.confidence * 100),\n },\n });\n newInsights.push(insight);\n await this.addInsight(insight);\n }\n \n if (generated.length > 0) {\n await this.markInsightCreated('hypothesis-generation');\n }\n } catch (error) {\n // Hypothesis generation is best-effort, don't break the scan\n }\n }\n \n // === AUTONOMOUS PATTERN DISCOVERY ===\n // Discover patterns from accumulated issues automatically\n // This makes patterns appear naturally from your workflow\n if (issues.length >= 5 && this.canCreateInsight('pattern-discovery')) {\n try {\n const { IncidentIndex } = await import('../context/incident-index.js');\n const { TriePatternDiscovery } = await import('../agent/pattern-discovery.js');\n const { ContextGraph } = await import('../context/graph.js');\n \n const graph = new ContextGraph(this.projectPath);\n const incidentIndex = await IncidentIndex.build(graph, this.projectPath);\n const discovery = new TriePatternDiscovery(graph, incidentIndex);\n \n // Discover hot patterns with lower threshold for faster discovery\n const hotPatterns = discovery.discoverHotPatterns(2);\n let patternsAdded = 0;\n \n for (const hot of hotPatterns.slice(0, 5)) { // Top 5 hot patterns\n const existingPatterns = await graph.listNodes();\n const alreadyExists = existingPatterns.some(\n n => n.type === 'pattern' && (n.data as any).description?.includes(hot.path)\n );\n \n if (!alreadyExists) {\n await graph.addNode('pattern', {\n description: `${hot.type === 'directory' ? 'Directory' : 'File'} hot zone: ${hot.path}`,\n appliesTo: [hot.path],\n confidence: Math.min(0.95, hot.confidence),\n occurrences: hot.incidentCount,\n firstSeen: new Date().toISOString(),\n lastSeen: new Date().toISOString(),\n isAntiPattern: hot.incidentCount >= 3,\n source: 'local'\n });\n patternsAdded++;\n }\n }\n \n // Create insight if patterns were discovered\n if (patternsAdded > 0) {\n const insight = this.createInsight({\n type: 'observation',\n message: `${this.pick(PERSONALITY.greetings)} Discovered ${patternsAdded} pattern${patternsAdded > 1 ? 's' : ''} in your codebase.`,\n suggestedAction: `Check Memory → Learned Patterns to see`,\n priority: 5,\n category: 'pattern',\n details: {\n patternsCount: patternsAdded,\n topPattern: hotPatterns[0]?.path,\n },\n });\n newInsights.push(insight);\n await this.addInsight(insight);\n await this.markInsightCreated('pattern-discovery');\n }\n } catch (error) {\n // Pattern discovery is best-effort\n }\n }\n \n // Check for recurring patterns across projects (from global memory)\n if (this.canCreateInsight('pattern-suggestion')) {\n try {\n const globalPatterns = await findCrossProjectPatterns();\n const crossProjectPattern = globalPatterns.find(p => p.projects.length > 1 && p.occurrences > 3);\n if (crossProjectPattern) {\n const insight = this.createInsight({\n type: 'suggestion',\n message: `\"${crossProjectPattern.description.slice(0, 40)}...\" appears in ${crossProjectPattern.projects.length} projects. Consider a shared lint rule.`,\n priority: 4,\n category: 'pattern',\n });\n newInsights.push(insight);\n await this.addInsight(insight);\n await this.markInsightCreated('pattern-suggestion');\n }\n } catch {\n // Global memory might not be available\n }\n }\n \n // Pre-push warning (with cooldown)\n if (context.isWatchMode && this.shouldWarnBeforePush(issues) && this.canCreateInsight('pre-push-warning')) {\n const criticalIssues = issues.filter(i => i.severity === 'critical');\n const seriousIssues = issues.filter(i => i.severity === 'serious');\n const moderateIssues = issues.filter(i => i.severity === 'moderate');\n \n // Build severity breakdown\n const breakdown: Record<string, number> = {};\n if (criticalIssues.length > 0) breakdown['critical'] = criticalIssues.length;\n if (seriousIssues.length > 0) breakdown['serious'] = seriousIssues.length;\n if (moderateIssues.length > 0) breakdown['moderate'] = moderateIssues.length;\n \n // Get affected files by severity\n const criticalFiles = [...new Set(criticalIssues.map(i => basename(i.file)))];\n const seriousFiles = [...new Set(seriousIssues.map(i => basename(i.file)))];\n const affectedFiles = [...new Set([...criticalFiles, ...seriousFiles])].slice(0, 5);\n \n // Get example issues (highest severity first)\n const examples = [...criticalIssues, ...seriousIssues]\n .slice(0, 4)\n .map(i => `${basename(i.file)}:${i.line} - ${i.issue.slice(0, 50)}`);\n \n // Determine trend if we have history\n const totalBlocking = criticalIssues.length + seriousIssues.length;\n const trend = this.lastIssueHashes.size > 0 \n ? (totalBlocking > this.lastIssueHashes.size ? 'worsening' : 'improving')\n : undefined;\n \n // Build details object, only including defined values\n const insightDetails: NonNullable<GuardianInsight['details']> = {\n affectedFiles,\n issueBreakdown: breakdown,\n examples,\n };\n if (trend) insightDetails.trend = trend;\n if (moderateIssues.length > 0) insightDetails.comparison = `+${moderateIssues.length} moderate (non-blocking)`;\n \n const insight = this.createInsight({\n type: 'warning',\n message: `${totalBlocking} issue${totalBlocking > 1 ? 's' : ''} need attention before pushing.`,\n suggestedAction: 'Run pre-push check',\n actionCommand: 'trie check',\n priority: 8,\n category: 'quality',\n details: insightDetails,\n });\n newInsights.push(insight);\n await this.addInsight(insight);\n await this.markInsightCreated('pre-push-warning');\n }\n \n // 4. Optionally enhance with LLM for deeper insights\n if (isAIAvailable() && issues.length > 0 && newIssues.length > 0) {\n const aiInsights = await this.generateAIInsights(issues, newIssues);\n newInsights.push(...aiInsights);\n }\n \n // ==========================================================================\n // 5. GUARDIAN AGENCY: Phases 2-4 Integration\n // ==========================================================================\n \n // Phase 2: Autonomous Goals - Analyze patterns and track progress\n if (this.canCreateInsight('goal-progress')) {\n try {\n const patterns = await this.goalManager.analyzeIncidentPatterns();\n \n // Generate goals from significant patterns (high confidence, enough occurrences)\n const significantPatterns = patterns.filter(p => p.confidence >= 0.6 && p.currentValue >= 3);\n if (significantPatterns.length > 0) {\n // Auto-generate goals which creates insights internally\n await this.goalManager.autoGenerateGoals();\n }\n \n // Update goal progress and check achievements\n await this.goalManager.updateGoalProgress();\n \n // Check goal progress and create insights for major milestones\n const goals = this.guardianState.getAllGoals();\n for (const goal of goals.filter(g => g.status === 'active')) {\n // Calculate percent complete\n const startVal = goal.startValue ?? goal.currentValue;\n if (startVal > 0 && goal.currentValue <= startVal) {\n const percentComplete = Math.round((1 - goal.currentValue / startVal) * 100);\n if (percentComplete >= 50 && this.canCreateInsight(`goal-${goal.id}`)) {\n const insight = this.createInsight({\n type: 'celebration',\n message: `Goal \"${goal.description}\" is ${percentComplete}% complete! ${goal.currentValue} issues remaining (started at ${startVal}).`,\n priority: 4,\n category: 'progress',\n details: {\n affectedFiles: goal.category ? [goal.category] : [],\n comparison: `${startVal} → ${goal.currentValue}`,\n },\n });\n newInsights.push(insight);\n await this.addInsight(insight);\n await this.markInsightCreated(`goal-${goal.id}`);\n }\n }\n }\n \n await this.markInsightCreated('goal-progress');\n } catch {\n // Goal analysis is optional\n }\n }\n \n // Phase 3: Risk Prediction - Warn about high-risk files\n if (context.filesChanged && context.filesChanged.length > 0 && this.canCreateInsight('risk-prediction')) {\n try {\n const riskSummary = await this.riskPredictor.predictRiskTrend(context.filesChanged);\n \n if (riskSummary.overallRisk >= 50) {\n const highRiskFactors = riskSummary.factors.filter(f => f.reasons.length > 0);\n \n if (highRiskFactors.length > 0) {\n const topFile = highRiskFactors[0];\n const insight = this.createInsight({\n type: 'warning',\n message: `Risk score ${Math.round(riskSummary.overallRisk)}/100 for changed files (${riskSummary.trend}). ${topFile ? basename(topFile.file) + ' is high-risk.' : ''}`,\n suggestedAction: 'Consider extra review before pushing',\n priority: 7,\n category: 'quality',\n details: {\n affectedFiles: highRiskFactors.slice(0, 5).map(f => basename(f.file)),\n trend: riskSummary.trend === 'increasing' ? 'worsening' : riskSummary.trend === 'decreasing' ? 'improving' : 'stable',\n },\n });\n newInsights.push(insight);\n await this.addInsight(insight);\n await this.markInsightCreated('risk-prediction');\n }\n }\n\n // NEW: Gotcha Predictor Integration\n const gotchas = await this.gotchaPredictor.predictGotchas(context.filesChanged);\n for (const gotcha of gotchas) {\n if (this.canCreateInsight(`gotcha-${gotcha.id}`)) {\n const explanation = await this.gotchaPredictor.synthesizeGotchaExplanation(gotcha);\n const insight = this.createInsight({\n type: 'warning',\n message: `[Gotcha] ${gotcha.message}`,\n context: explanation,\n suggestedAction: gotcha.recommendation,\n priority: gotcha.riskLevel === 'critical' ? 9 : 7,\n category: 'quality',\n details: {\n affectedFiles: context.filesChanged.map(f => basename(f)),\n examples: [gotcha.message, explanation],\n }\n });\n newInsights.push(insight);\n await this.addInsight(insight);\n await this.markInsightCreated(`gotcha-${gotcha.id}`);\n }\n }\n } catch {\n // Risk/Gotcha prediction is optional\n }\n }\n \n // Phase 3: Hypothesis Validation - Check and update hypotheses\n if (this.canCreateInsight('hypothesis-update')) {\n try {\n // Auto-generate hypotheses if we don't have many\n const hypotheses = this.guardianState.getAllHypotheses();\n const testingHypotheses = hypotheses.filter(h => h.status === 'testing');\n \n if (testingHypotheses.length < 3) {\n await this.hypothesisEngine.autoGenerateHypotheses();\n }\n \n // Check for newly validated/invalidated hypotheses and create insights\n const validatedHypotheses = hypotheses.filter(h => \n h.status === 'validated' && \n h.validatedAt && \n Date.now() - new Date(h.validatedAt).getTime() < 24 * 60 * 60 * 1000 // Within last 24h\n );\n \n for (const hypothesis of validatedHypotheses.slice(0, 2)) {\n if (this.canCreateInsight(`hypothesis-${hypothesis.id}`)) {\n const insight = this.createInsight({\n type: 'celebration',\n message: `Hypothesis validated: \"${hypothesis.statement}\" (${Math.round(hypothesis.confidence * 100)}% confidence)`,\n priority: 5,\n category: 'pattern',\n });\n newInsights.push(insight);\n await this.addInsight(insight);\n await this.markInsightCreated(`hypothesis-${hypothesis.id}`);\n }\n }\n \n await this.markInsightCreated('hypothesis-update');\n } catch {\n // Hypothesis validation is optional\n }\n }\n \n // Phase 4: Auto-Escalation - Escalate critical security issues\n const criticalSecurityIssues = issues.filter(i => \n i.severity === 'critical' && \n (i.category === 'security' || i.issue.toLowerCase().includes('secret'))\n );\n \n if (criticalSecurityIssues.length > 0) {\n try {\n const result = await this.escalationManager.escalateIssues(criticalSecurityIssues);\n if (result.action === 'auto_escalated' && result.message) {\n const insight = this.createInsight({\n type: 'observation',\n message: `Auto-escalated ${criticalSecurityIssues.length} critical security issue(s). Check your notifications.`,\n priority: 9,\n category: 'security',\n details: {\n affectedFiles: criticalSecurityIssues.slice(0, 5).map(i => basename(i.file)),\n examples: criticalSecurityIssues.slice(0, 3).map(i => i.issue.slice(0, 60)),\n },\n });\n newInsights.push(insight);\n await this.addInsight(insight);\n }\n } catch {\n // Escalation is best-effort\n }\n }\n \n // Phase 4: Meta-Learning - Note: actual feedback recording happens when user interacts\n // Here we just track that insights were shown (for latency tracking)\n // The user feedback is recorded via markInsightHelpful/dismissInsight/markInsightActedOn\n \n // Update state\n this.lastIssueHashes = currentHashes;\n \n // Record scan timestamp (Phase 1 Guardian Agency)\n await this.guardianState.recordScan();\n \n // Adapt scan frequency based on risk (Phase 2)\n try {\n const riskLevel = issues.filter(i => i.severity === 'critical').length > 0 ? 'critical' :\n issues.filter(i => i.severity === 'serious').length >= 3 ? 'high' :\n issues.length > 10 ? 'medium' : 'low';\n \n // Calculate and store adaptive scan frequency\n const { calculateAdaptiveScanFrequency } = await import('./goal-manager.js');\n const result = await calculateAdaptiveScanFrequency(riskLevel);\n await this.guardianState.setScanFrequency(result.frequencyMs);\n } catch {\n // Scan frequency adaptation is optional\n }\n \n return newInsights;\n }\n \n /**\n * Use LLM to generate deeper insights (optional, requires ANTHROPIC_API_KEY)\n */\n private async generateAIInsights(_allIssues: Issue[], newIssues: Issue[]): Promise<GuardianInsight[]> {\n const insights: GuardianInsight[] = [];\n \n try {\n // Only analyze if we have significant new issues\n if (newIssues.length < 2) return insights;\n \n const issuesSummary = newIssues.slice(0, 10).map(i => ({\n severity: i.severity,\n issue: i.issue.slice(0, 100),\n file: basename(i.file),\n agent: i.agent\n }));\n \n const result = await runAIAnalysis({\n systemPrompt: `You are a helpful code guardian. Analyze these issues and provide ONE brief, conversational insight.\nBe specific and actionable. Speak like a helpful colleague, not a system.\nKeep your response under 100 words. Focus on the most important pattern or concern.`,\n userPrompt: `New issues found:\\n${JSON.stringify(issuesSummary, null, 2)}\n\nWhat's the most important thing the developer should know? Provide a brief, conversational insight.`,\n maxTokens: 200,\n temperature: 0.7\n });\n \n if (result.success && result.content) {\n const insight = this.createInsight({\n type: 'observation',\n message: result.content.trim(),\n priority: 5,\n category: 'general',\n });\n insights.push(insight);\n await this.addInsight(insight);\n }\n } catch {\n // AI analysis is optional, don't fail\n }\n \n return insights;\n }\n \n /**\n * Get active insights (not dismissed, still relevant)\n * Now uses persistent storage (Phase 1 Guardian Agency)\n */\n getActiveInsights(): GuardianInsight[] {\n return this.insightStore.getActiveInsights();\n }\n \n /**\n * Dismiss an insight\n * Now persists to disk (Phase 1 Guardian Agency)\n */\n async dismissInsight(insightId: string): Promise<boolean> {\n const result = await this.insightStore.dismissInsight(insightId);\n \n // Record feedback for meta-learning (Phase 4)\n if (result) {\n await this.guardianState.recordInsightFeedback('dismissed');\n }\n \n return result;\n }\n \n /**\n * Record that a user found an insight helpful\n */\n async markInsightHelpful(_insightId: string): Promise<void> {\n await this.guardianState.recordInsightFeedback('helpful');\n }\n \n /**\n * Record that a user acted on an insight\n */\n async markInsightActedOn(_insightId: string): Promise<void> {\n await this.guardianState.recordInsightFeedback('acted');\n }\n \n /**\n * Get insight statistics\n */\n getInsightStats() {\n return this.insightStore.getStats();\n }\n \n /**\n * Get agent metrics (for dashboard display)\n */\n getAgentMetrics() {\n return this.guardianState.getMetrics();\n }\n \n /**\n * Check if in quiet hours\n */\n isQuietHours(): boolean {\n return this.guardianState.isQuietHours();\n }\n \n /**\n * Check if in crunch mode\n */\n isInCrunchMode(): boolean {\n return this.guardianState.isInCrunchMode();\n }\n \n /**\n * Get the insight store (for advanced operations)\n */\n getInsightStore() {\n return this.insightStore;\n }\n \n /**\n * Get the guardian state (for advanced operations)\n */\n getGuardianState() {\n return this.guardianState;\n }\n \n /**\n * Get agency modules (for watch mode integration)\n */\n getGoalManager() {\n return this.goalManager;\n }\n \n getRiskPredictor() {\n return this.riskPredictor;\n }\n \n getHypothesisEngine() {\n return this.hypothesisEngine;\n }\n \n getEscalationManager() {\n return this.escalationManager;\n }\n \n getMetaLearner() {\n return this.metaLearner;\n }\n \n /**\n * Get a rich agency status for display in watch mode\n */\n async getAgencyStatus(): Promise<{\n goals: { active: number; completed: number; topGoal?: string };\n hypotheses: { testing: number; validated: number; topHypothesis?: string };\n riskLevel: 'low' | 'medium' | 'high' | 'critical';\n scanFrequency: number;\n effectiveness: number;\n isQuietHours: boolean;\n }> {\n const goals = this.guardianState.getAllGoals();\n const activeGoals = goals.filter((g: { status: string }) => g.status === 'active');\n const completedGoals = goals.filter((g: { status: string }) => g.status === 'achieved');\n \n const hypotheses = this.guardianState.getAllHypotheses();\n const testingHypotheses = hypotheses.filter((h: { status: string }) => h.status === 'testing');\n const validatedHypotheses = hypotheses.filter((h: { status: string }) => h.status === 'validated');\n \n const metrics = this.guardianState.getMetrics();\n const budget = this.guardianState.getRiskBudget();\n \n // Calculate daily actions remaining\n const dailyActionsRemaining = budget.daily - budget.usedToday;\n \n // Calculate overall risk level\n let riskLevel: 'low' | 'medium' | 'high' | 'critical' = 'low';\n if (dailyActionsRemaining <= 1) riskLevel = 'critical';\n else if (dailyActionsRemaining <= 3) riskLevel = 'high';\n else if (dailyActionsRemaining <= 5) riskLevel = 'medium';\n \n // Calculate effectiveness using correct property names\n const totalFeedback = metrics.helpfulInsights + metrics.dismissedInsights + metrics.actedOnInsights;\n const effectiveness = totalFeedback > 0 \n ? Math.round(((metrics.helpfulInsights + metrics.actedOnInsights) / totalFeedback) * 100)\n : 100; // Default to 100% if no feedback yet\n \n // Build result with conditional optional properties\n const topGoal = activeGoals[0]?.description;\n const topHypothesis = testingHypotheses[0]?.statement?.slice(0, 50);\n \n const result: {\n goals: { active: number; completed: number; topGoal?: string };\n hypotheses: { testing: number; validated: number; topHypothesis?: string };\n riskLevel: 'low' | 'medium' | 'high' | 'critical';\n scanFrequency: number;\n effectiveness: number;\n isQuietHours: boolean;\n } = {\n goals: {\n active: activeGoals.length,\n completed: completedGoals.length,\n },\n hypotheses: {\n testing: testingHypotheses.length,\n validated: validatedHypotheses.length,\n },\n riskLevel,\n scanFrequency: this.guardianState.getScanFrequencyMs(),\n effectiveness,\n isQuietHours: this.guardianState.isQuietHours(),\n };\n \n if (topGoal) result.goals.topGoal = topGoal;\n if (topHypothesis) result.hypotheses.topHypothesis = topHypothesis;\n \n return result;\n }\n \n /**\n * Get a summary for the current state\n */\n getSummary(issues: Issue[]): string {\n const critical = issues.filter(i => i.severity === 'critical').length;\n const serious = issues.filter(i => i.severity === 'serious').length;\n const total = issues.length;\n \n if (total === 0) {\n return \"All clear. Your code looks good.\";\n }\n \n if (critical > 0) {\n return `${critical} critical issue${critical > 1 ? 's' : ''} need${critical === 1 ? 's' : ''} immediate attention.`;\n }\n \n if (serious > 0) {\n return `${serious} serious issue${serious > 1 ? 's' : ''} worth reviewing before shipping.`;\n }\n \n return `${total} minor thing${total > 1 ? 's' : ''} to polish when you have time.`;\n }\n \n // === Private helpers ===\n \n private shouldWarnBeforePush(issues: Issue[]): boolean {\n const critical = issues.filter(i => i.severity === 'critical').length;\n const serious = issues.filter(i => i.severity === 'serious').length;\n return critical > 0 || serious >= 3;\n }\n \n /**\n * Check if we should create an insight of this type (cooldown not expired)\n * Now uses persistent storage (Phase 1 Guardian Agency)\n */\n private canCreateInsight(insightKey: string): boolean {\n return this.insightStore.canCreateInsight(insightKey);\n }\n \n /**\n * Mark that we created an insight of this type\n * Now persists to disk (Phase 1 Guardian Agency)\n */\n private async markInsightCreated(insightKey: string): Promise<void> {\n await this.insightStore.markInsightCreated(insightKey);\n }\n \n private createInsight(params: Omit<GuardianInsight, 'id' | 'timestamp' | 'dismissed' | 'relatedIssues'> & { relatedIssues?: string[] }): GuardianInsight {\n return {\n id: `insight-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n timestamp: Date.now(),\n dismissed: false,\n relatedIssues: params.relatedIssues || [],\n ...params,\n };\n }\n \n private pick<T>(arr: T[]): T {\n return arr[Math.floor(Math.random() * arr.length)] as T;\n }\n}\n\n// Singleton instance per project\nconst guardianInstances: Map<string, GuardianAgent> = new Map();\n\nexport function getGuardian(projectPath: string): GuardianAgent {\n let guardian = guardianInstances.get(projectPath);\n if (!guardian) {\n guardian = new GuardianAgent(projectPath);\n guardianInstances.set(projectPath, guardian);\n }\n return guardian;\n}\n","/**\n * Risk Predictor - Predictive risk scoring with trend analysis\n * \n * Phase 3 of Guardian Agency Plan: Predictive Intelligence\n * \n * Features:\n * - Multi-factor risk scoring\n * - Trend analysis (increasing/stable/decreasing)\n * - File-level risk predictions\n * - Historical incident correlation\n * - Proactive risk warnings\n */\n\nimport type { GuardianInsight } from './insight-store.js';\nimport { getInsightStore } from './insight-store.js';\n// Note: getGuardianState is not used here but could be used for timing context\nimport { searchIssues, type StoredIssue } from '../memory/issue-store.js';\nimport { basename, dirname } from 'path';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Risk factor contributing to overall risk\n */\nexport interface RiskFactor {\n name: string;\n weight: number; // 0-1, contribution to risk\n value: number; // Current measured value\n description: string;\n trend?: 'increasing' | 'stable' | 'decreasing';\n}\n\n/**\n * Risk prediction for a file or directory\n */\nexport interface RiskPrediction {\n target: string; // File or directory path\n currentRisk: number; // 0-100\n predictedRisk: number; // 0-100 (future prediction)\n trend: 'increasing' | 'stable' | 'decreasing';\n factors: RiskFactor[];\n confidence: number; // 0-1\n recommendations: string[];\n lastIncidentDaysAgo?: number;\n incidentCount: number;\n}\n\n/**\n * Overall project risk summary\n */\nexport interface ProjectRiskSummary {\n overallRisk: number; // 0-100\n trend: 'increasing' | 'stable' | 'decreasing';\n hotspots: RiskPrediction[];\n lowRiskAreas: string[];\n predictions: RiskPrediction[];\n confidence: number;\n}\n\n/**\n * Risk prediction configuration\n */\nexport interface RiskPredictionConfig {\n historyDays: number; // Days of history to consider\n incidentThreshold: number; // Min incidents to flag as hotspot\n riskWeights: {\n incidentCount: number;\n recency: number;\n severity: number;\n complexity: number;\n churn: number;\n };\n}\n\nconst DEFAULT_CONFIG: RiskPredictionConfig = {\n historyDays: 30,\n incidentThreshold: 3,\n riskWeights: {\n incidentCount: 0.35,\n recency: 0.25,\n severity: 0.20,\n complexity: 0.10,\n churn: 0.10,\n },\n};\n\n// ============================================================================\n// RiskPredictor Class\n// ============================================================================\n\n/**\n * Predictive risk analysis engine\n */\nexport class RiskPredictor {\n private projectPath: string;\n private config: RiskPredictionConfig;\n private insightStore;\n \n constructor(projectPath: string, config: Partial<RiskPredictionConfig> = {}) {\n this.projectPath = projectPath;\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.insightStore = getInsightStore(projectPath);\n }\n \n /**\n * Calculate risk for a specific file or directory\n */\n async calculateRisk(target: string): Promise<RiskPrediction> {\n const factors: RiskFactor[] = [];\n let totalRisk = 0;\n \n try {\n // Get historical issues for this target\n const issues = await searchIssues(target, {\n workDir: this.projectPath,\n limit: 500,\n includeResolved: true,\n });\n \n const targetIssues = issues.filter(r => \n r.issue.file === target || \n r.issue.file.startsWith(target + '/') ||\n dirname(r.issue.file) === target\n );\n \n // 1. Incident count factor\n const incidentCount = targetIssues.length;\n const incidentWeight = this.config.riskWeights.incidentCount;\n const incidentScore = Math.min(100, incidentCount * 10);\n factors.push({\n name: 'Incident Count',\n weight: incidentWeight,\n value: incidentCount,\n description: `${incidentCount} historical incidents`,\n trend: this.calculateTrend(targetIssues.map(i => i.issue)),\n });\n totalRisk += incidentScore * incidentWeight;\n \n // 2. Recency factor (when was the last incident?)\n let recencyScore = 0;\n let lastIncidentDaysAgo: number | undefined;\n if (targetIssues.length > 0) {\n const latestIssue = targetIssues\n .sort((a, b) => new Date(b.issue.timestamp).getTime() - new Date(a.issue.timestamp).getTime())[0];\n \n if (latestIssue) {\n const daysSince = (Date.now() - new Date(latestIssue.issue.timestamp).getTime()) / (1000 * 60 * 60 * 24);\n lastIncidentDaysAgo = Math.floor(daysSince);\n \n // More recent = higher risk\n if (daysSince < 1) recencyScore = 100;\n else if (daysSince < 7) recencyScore = 80;\n else if (daysSince < 14) recencyScore = 60;\n else if (daysSince < 30) recencyScore = 40;\n else recencyScore = 20;\n }\n }\n \n factors.push({\n name: 'Recency',\n weight: this.config.riskWeights.recency,\n value: lastIncidentDaysAgo ?? 999,\n description: lastIncidentDaysAgo !== undefined \n ? `Last incident ${lastIncidentDaysAgo} days ago`\n : 'No recent incidents',\n });\n totalRisk += recencyScore * this.config.riskWeights.recency;\n \n // 3. Severity factor\n const criticalCount = targetIssues.filter(r => r.issue.severity === 'critical').length;\n const seriousCount = targetIssues.filter(r => r.issue.severity === 'serious').length;\n const severityScore = Math.min(100, (criticalCount * 25) + (seriousCount * 10));\n \n factors.push({\n name: 'Severity',\n weight: this.config.riskWeights.severity,\n value: severityScore,\n description: `${criticalCount} critical, ${seriousCount} serious`,\n });\n totalRisk += severityScore * this.config.riskWeights.severity;\n \n // 4. Complexity factor (approximated by issue diversity)\n const uniqueAgents = new Set(targetIssues.map(r => r.issue.agent)).size;\n const complexityScore = Math.min(100, uniqueAgents * 20);\n \n factors.push({\n name: 'Complexity',\n weight: this.config.riskWeights.complexity,\n value: uniqueAgents,\n description: `Issues from ${uniqueAgents} different analysis types`,\n });\n totalRisk += complexityScore * this.config.riskWeights.complexity;\n \n // 5. Churn factor (how often this file has issues)\n // Approximate by counting unique dates with issues\n const uniqueDates = new Set(\n targetIssues.map(r => r.issue.timestamp.split('T')[0])\n ).size;\n const churnScore = Math.min(100, uniqueDates * 10);\n \n factors.push({\n name: 'Churn',\n weight: this.config.riskWeights.churn,\n value: uniqueDates,\n description: `Issues found on ${uniqueDates} different days`,\n });\n totalRisk += churnScore * this.config.riskWeights.churn;\n \n // Calculate trend\n const trend = this.calculateTrend(targetIssues.map(i => i.issue));\n \n // Predict future risk based on trend\n let predictedRisk = totalRisk;\n if (trend === 'increasing') {\n predictedRisk = Math.min(100, totalRisk * 1.2);\n } else if (trend === 'decreasing') {\n predictedRisk = Math.max(0, totalRisk * 0.8);\n }\n \n // Generate recommendations\n const recommendations = this.generateRecommendations(factors, totalRisk);\n \n // Calculate confidence based on data quality\n const confidence = Math.min(0.95, 0.3 + (incidentCount * 0.05));\n \n const prediction: RiskPrediction = {\n target,\n currentRisk: Math.round(totalRisk),\n predictedRisk: Math.round(predictedRisk),\n trend,\n factors,\n confidence,\n recommendations,\n incidentCount,\n };\n \n if (lastIncidentDaysAgo !== undefined) {\n prediction.lastIncidentDaysAgo = lastIncidentDaysAgo;\n }\n \n return prediction;\n \n } catch (error) {\n console.error(`Failed to calculate risk for ${target}:`, error);\n return {\n target,\n currentRisk: 50,\n predictedRisk: 50,\n trend: 'stable',\n factors: [],\n confidence: 0.1,\n recommendations: ['Unable to analyze - insufficient data'],\n incidentCount: 0,\n };\n }\n }\n \n /**\n * Calculate trend from issues\n */\n private calculateTrend(issues: StoredIssue[]): 'increasing' | 'stable' | 'decreasing' {\n if (issues.length < 3) return 'stable';\n \n const now = Date.now();\n const recentCutoff = now - (7 * 24 * 60 * 60 * 1000); // 7 days\n const olderCutoff = now - (30 * 24 * 60 * 60 * 1000); // 30 days\n \n const recentIssues = issues.filter(i => new Date(i.timestamp).getTime() > recentCutoff).length;\n const olderIssues = issues.filter(i => {\n const time = new Date(i.timestamp).getTime();\n return time > olderCutoff && time <= recentCutoff;\n }).length;\n \n // Normalize by time period\n const recentRate = recentIssues / 7;\n const olderRate = olderIssues / 23;\n \n if (recentRate > olderRate * 1.5) return 'increasing';\n if (recentRate < olderRate * 0.5) return 'decreasing';\n return 'stable';\n }\n \n /**\n * Generate recommendations based on risk factors\n */\n private generateRecommendations(factors: RiskFactor[], totalRisk: number): string[] {\n const recommendations: string[] = [];\n \n if (totalRisk >= 70) {\n recommendations.push('Consider extra code review before merging changes');\n }\n \n const incidentFactor = factors.find(f => f.name === 'Incident Count');\n if (incidentFactor && incidentFactor.value >= 5) {\n recommendations.push('This area has recurring issues - consider refactoring');\n }\n \n const recencyFactor = factors.find(f => f.name === 'Recency');\n if (recencyFactor && recencyFactor.value < 7) {\n recommendations.push('Recent incident activity - monitor closely');\n }\n \n const severityFactor = factors.find(f => f.name === 'Severity');\n if (severityFactor && severityFactor.value >= 25) {\n recommendations.push('High severity issues present - prioritize fixes');\n }\n \n const complexityFactor = factors.find(f => f.name === 'Complexity');\n if (complexityFactor && complexityFactor.value >= 4) {\n recommendations.push('Multiple issue types - consider comprehensive review');\n }\n \n if (recommendations.length === 0) {\n recommendations.push('No specific concerns - maintain normal review process');\n }\n \n return recommendations;\n }\n \n /**\n * Predict risk trend for files that have recently changed\n */\n async predictRiskTrend(changedFiles: string[]): Promise<{\n trend: 'increasing' | 'stable' | 'decreasing';\n factors: Array<{ file: string; reasons: string[] }>;\n overallRisk: number;\n }> {\n const predictions = await Promise.all(\n changedFiles.map(f => this.calculateRisk(f))\n );\n \n const highRiskFiles = predictions.filter(p => p.currentRisk >= 50);\n const totalRisk = predictions.reduce((sum, p) => sum + p.currentRisk, 0) / Math.max(1, predictions.length);\n \n // Determine overall trend\n const trends = predictions.map(p => p.trend);\n const increasingCount = trends.filter(t => t === 'increasing').length;\n const decreasingCount = trends.filter(t => t === 'decreasing').length;\n \n let overallTrend: 'increasing' | 'stable' | 'decreasing' = 'stable';\n if (increasingCount > decreasingCount + 1) {\n overallTrend = 'increasing';\n } else if (decreasingCount > increasingCount + 1) {\n overallTrend = 'decreasing';\n }\n \n // Collect factors for high-risk files\n const factors = highRiskFiles.map(p => ({\n file: p.target,\n reasons: p.incidentCount > 0 \n ? ['past incidents', ...p.recommendations.slice(0, 2)]\n : ['no historical data'],\n }));\n \n return {\n trend: overallTrend,\n factors,\n overallRisk: Math.round(totalRisk),\n };\n }\n \n /**\n * Get project-wide risk summary\n */\n async getProjectRiskSummary(): Promise<ProjectRiskSummary> {\n try {\n const issues = await searchIssues('', {\n workDir: this.projectPath,\n limit: 1000,\n includeResolved: true,\n });\n \n // Group by directory\n const dirIssueCount = new Map<string, StoredIssue[]>();\n for (const { issue } of issues) {\n const dir = dirname(issue.file);\n const existing = dirIssueCount.get(dir) || [];\n existing.push(issue);\n dirIssueCount.set(dir, existing);\n }\n \n // Find hotspots (directories with many issues)\n const hotspotDirs = [...dirIssueCount.entries()]\n .filter(([_, issues]) => issues.length >= this.config.incidentThreshold)\n .sort((a, b) => b[1].length - a[1].length)\n .slice(0, 5);\n \n // Calculate risk for each hotspot\n const hotspots = await Promise.all(\n hotspotDirs.map(([dir]) => this.calculateRisk(dir))\n );\n \n // Find low-risk areas\n const allDirs = [...dirIssueCount.keys()];\n const lowRiskPredictions = await Promise.all(\n allDirs.map(dir => this.calculateRisk(dir))\n );\n const lowRiskAreas = lowRiskPredictions\n .filter(p => p.currentRisk < 20 && p.incidentCount === 0)\n .map(p => p.target)\n .slice(0, 5);\n \n // Calculate overall risk\n const overallRisk = hotspots.length > 0\n ? hotspots.reduce((sum, p) => sum + p.currentRisk, 0) / hotspots.length\n : 0;\n \n // Determine trend\n const trends = hotspots.map(p => p.trend);\n const increasingCount = trends.filter(t => t === 'increasing').length;\n const decreasingCount = trends.filter(t => t === 'decreasing').length;\n \n let trend: 'increasing' | 'stable' | 'decreasing' = 'stable';\n if (increasingCount > decreasingCount) {\n trend = 'increasing';\n } else if (decreasingCount > increasingCount) {\n trend = 'decreasing';\n }\n \n // Calculate confidence\n const confidence = Math.min(0.9, 0.4 + (issues.length * 0.001));\n \n return {\n overallRisk: Math.round(overallRisk),\n trend,\n hotspots,\n lowRiskAreas,\n predictions: hotspots,\n confidence,\n };\n \n } catch (error) {\n console.error('Failed to get project risk summary:', error);\n return {\n overallRisk: 0,\n trend: 'stable',\n hotspots: [],\n lowRiskAreas: [],\n predictions: [],\n confidence: 0.1,\n };\n }\n }\n \n /**\n * Create risk prediction insight\n */\n async generateRiskInsight(): Promise<GuardianInsight | null> {\n if (!this.insightStore.canCreateInsight('risk-prediction')) {\n return null;\n }\n \n const summary = await this.getProjectRiskSummary();\n \n // Only generate insight if there's meaningful risk\n if (summary.hotspots.length === 0 || summary.overallRisk < 30) {\n return null;\n }\n \n const topHotspot = summary.hotspots[0];\n if (!topHotspot) return null;\n \n // Convert trend format for insight display\n const trendMap: Record<'increasing' | 'stable' | 'decreasing', 'worsening' | 'stable' | 'improving'> = {\n 'increasing': 'worsening',\n 'stable': 'stable',\n 'decreasing': 'improving',\n };\n \n const insight: GuardianInsight = {\n id: `insight-risk-${Date.now()}`,\n type: 'warning',\n message: `[!] ${basename(topHotspot.target)}/ has elevated risk (${topHotspot.currentRisk}/100)`,\n context: `${topHotspot.incidentCount} past incidents. ${topHotspot.recommendations[0]}`,\n suggestedAction: 'Request extra review before merging changes to this area',\n relatedIssues: [],\n priority: Math.min(9, 5 + Math.floor(topHotspot.currentRisk / 20)),\n timestamp: Date.now(),\n dismissed: false,\n category: 'security',\n details: {\n affectedFiles: summary.hotspots.map(h => basename(h.target)),\n trend: trendMap[summary.trend],\n examples: topHotspot.recommendations,\n },\n };\n \n await this.insightStore.addInsight(insight);\n await this.insightStore.markInsightCreated('risk-prediction');\n \n return insight;\n }\n}\n\n// ============================================================================\n// Singleton Management\n// ============================================================================\n\nconst riskPredictors: Map<string, RiskPredictor> = new Map();\n\n/**\n * Get the RiskPredictor for a project (singleton per project)\n */\nexport function getRiskPredictor(projectPath: string): RiskPredictor {\n let predictor = riskPredictors.get(projectPath);\n if (!predictor) {\n predictor = new RiskPredictor(projectPath);\n riskPredictors.set(projectPath, predictor);\n }\n return predictor;\n}\n\n/**\n * Clear all RiskPredictor instances (for testing)\n */\nexport function clearRiskPredictors(): void {\n riskPredictors.clear();\n}\n","import type { Issue } from '../types/index.js';\nimport type { IssueGroup, PriorityReport } from '../utils/issue-analyzer.js';\nimport type { TeamNotification } from './team-collaboration.js';\n\ninterface SlackConfig {\n webhookUrl: string;\n channel?: string | undefined;\n username?: string | undefined;\n iconEmoji?: string | undefined;\n}\n\ninterface SlackMessage {\n text?: string;\n blocks?: SlackBlock[];\n attachments?: SlackAttachment[];\n channel?: string;\n username?: string;\n icon_emoji?: string;\n}\n\ninterface SlackBlock {\n type: string;\n text?: {\n type: string;\n text: string;\n };\n fields?: Array<{\n type: string;\n text: string;\n }>;\n accessory?: any;\n}\n\ninterface SlackAttachment {\n color: string;\n title?: string | undefined;\n text?: string | undefined;\n fields?: Array<{\n title: string;\n value: string;\n short?: boolean;\n }> | undefined;\n footer?: string | undefined;\n ts?: number | undefined;\n}\n\n/**\n * Slack integration for Trie team notifications\n */\nexport class SlackIntegration {\n constructor(private config: SlackConfig) {}\n\n /**\n * Send scan completion notification\n */\n async sendScanNotification(\n _issues: Issue[],\n priorityReport: PriorityReport,\n repositoryName: string,\n branch: string = 'main'\n ): Promise<void> {\n const { urgent, high, medium, low } = priorityReport;\n const statusEmoji = urgent.length > 0 ? '[URGENT]' : high.length > 0 ? '[HIGH]' : '[OK]';\n\n const message: SlackMessage = {\n blocks: [\n {\n type: 'section',\n text: {\n type: 'mrkdwn',\n text: `${statusEmoji} *Trie Security Scan Complete*\\n*Repository:* ${repositoryName} (${branch})`\n }\n },\n {\n type: 'section',\n fields: [\n {\n type: 'mrkdwn',\n text: `*Urgent:* ${urgent.length}`\n },\n {\n type: 'mrkdwn',\n text: `*High:* ${high.length}`\n },\n {\n type: 'mrkdwn',\n text: `*Medium:* ${medium.length}`\n },\n {\n type: 'mrkdwn',\n text: `*🔹 Low:* ${low.length}`\n }\n ]\n }\n ],\n attachments: []\n };\n\n // Add urgent issues details\n if (urgent.length > 0) {\n const urgentDetails = urgent.slice(0, 5).map(group =>\n `• ${group.description} (${group.count} instances)`\n ).join('\\n');\n\n message.attachments!.push({\n color: 'danger',\n title: 'Urgent Issues - Immediate Action Required',\n text: urgentDetails,\n footer: urgent.length > 5 ? `... and ${urgent.length - 5} more urgent issues` : undefined\n });\n }\n\n // Add high priority issues\n if (high.length > 0) {\n const highDetails = high.slice(0, 3).map(group =>\n `• ${group.description} (${group.count} instances)`\n ).join('\\n');\n\n message.attachments!.push({\n color: 'warning',\n title: 'High Priority Issues',\n text: highDetails,\n footer: high.length > 3 ? `... and ${high.length - 3} more high priority issues` : undefined\n });\n }\n\n // Add recommendations\n if (priorityReport.recommendations.length > 0) {\n message.attachments!.push({\n color: 'good',\n title: 'Recommendations',\n text: priorityReport.recommendations.slice(0, 3).join('\\n')\n });\n }\n\n await this.sendMessage(message);\n }\n\n /**\n * Send critical issue alert\n */\n async sendCriticalAlert(issues: Issue[], repositoryName: string): Promise<void> {\n const message: SlackMessage = {\n text: `CRITICAL SECURITY ALERT: ${repositoryName}`,\n blocks: [\n {\n type: 'section',\n text: {\n type: 'mrkdwn',\n text: `*CRITICAL SECURITY ALERT*\\n*Repository:* ${repositoryName}\\n*Critical Issues:* ${issues.length}`\n }\n }\n ],\n attachments: issues.slice(0, 5).map(issue => ({\n color: 'danger',\n title: `${issue.file}:${issue.line || '?'}`,\n text: issue.issue.slice(0, 200),\n fields: [\n {\n title: 'Fix',\n value: issue.fix.slice(0, 100),\n short: false\n }\n ],\n footer: `Agent: ${issue.agent}`,\n ts: Math.floor(Date.now() / 1000)\n }))\n };\n\n if (issues.length > 5) {\n message.attachments!.push({\n color: 'danger',\n text: `... and ${issues.length - 5} more critical issues. View full report for details.`\n });\n }\n\n await this.sendMessage(message);\n }\n\n /**\n * Send team notification\n */\n async sendTeamNotification(notification: TeamNotification): Promise<void> {\n const emoji = this.getNotificationEmoji(notification.type);\n\n const message: SlackMessage = {\n blocks: [\n {\n type: 'section',\n text: {\n type: 'mrkdwn',\n text: `${emoji} *${notification.title}*\\n${notification.message}`\n }\n }\n ]\n };\n\n // Add specific data based on notification type\n if (notification.type === 'assignment' && notification.data) {\n const { assignment, issue } = notification.data;\n message.attachments = [{\n color: this.getAssignmentColor(assignment.priority),\n fields: [\n {\n title: 'Priority',\n value: assignment.priority.toUpperCase(),\n short: true\n },\n {\n title: 'Due Date',\n value: assignment.dueDate ? new Date(assignment.dueDate).toLocaleDateString() : 'Not set',\n short: true\n },\n {\n title: 'File',\n value: issue.file,\n short: false\n }\n ]\n }];\n }\n\n await this.sendMessage(message);\n }\n\n /**\n * Send daily/weekly team summary\n */\n async sendTeamSummary(\n period: 'daily' | 'weekly',\n stats: {\n newIssues: number;\n resolvedIssues: number;\n overdueIssues: number;\n topCategories: Array<{ category: string; count: number }>;\n topContributors: Array<{ name: string; resolved: number }>;\n }\n ): Promise<void> {\n const emoji = period === 'daily' ? '[DAILY]' : '[WEEKLY]';\n const title = `${emoji} ${period.charAt(0).toUpperCase() + period.slice(1)} Security Summary`;\n\n const message: SlackMessage = {\n blocks: [\n {\n type: 'section',\n text: {\n type: 'mrkdwn',\n text: `*${title}*`\n }\n },\n {\n type: 'section',\n fields: [\n {\n type: 'mrkdwn',\n text: `*New Issues:* ${stats.newIssues}`\n },\n {\n type: 'mrkdwn',\n text: `*✅ Resolved:* ${stats.resolvedIssues}`\n },\n {\n type: 'mrkdwn',\n text: `*Overdue:* ${stats.overdueIssues}`\n },\n {\n type: 'mrkdwn',\n text: `*Net Change:* ${stats.resolvedIssues - stats.newIssues > 0 ? '+' : ''}${stats.resolvedIssues - stats.newIssues}`\n }\n ]\n }\n ],\n attachments: []\n };\n\n // Top issue categories\n if (stats.topCategories.length > 0) {\n const categoriesText = stats.topCategories\n .slice(0, 5)\n .map(cat => `• ${cat.category}: ${cat.count}`)\n .join('\\n');\n\n message.attachments!.push({\n color: 'good',\n title: 'Top Issue Categories',\n text: categoriesText\n });\n }\n\n // Top contributors\n if (stats.topContributors.length > 0) {\n const contributorsText = stats.topContributors\n .slice(0, 5)\n .map(contrib => `• ${contrib.name}: ${contrib.resolved} resolved`)\n .join('\\n');\n\n message.attachments!.push({\n color: 'good',\n title: 'Top Contributors',\n text: contributorsText\n });\n }\n\n await this.sendMessage(message);\n }\n\n /**\n * Send bulk fix notification\n */\n async sendBulkFixNotification(\n fixedGroups: IssueGroup[],\n totalFixed: number,\n repositoryName: string\n ): Promise<void> {\n const message: SlackMessage = {\n blocks: [\n {\n type: 'section',\n text: {\n type: 'mrkdwn',\n text: `*Bulk Fix Applied*\\n*Repository:* ${repositoryName}\\n*Issues Fixed:* ${totalFixed}`\n }\n }\n ],\n attachments: [{\n color: 'good',\n title: '🔧 Fixed Issue Groups',\n text: fixedGroups.map(group =>\n `• ${group.description} (${group.count} instances)`\n ).join('\\n')\n }]\n };\n\n await this.sendMessage(message);\n }\n\n /**\n * Send escalation notification\n */\n async sendEscalationNotification(\n overdueAssignments: Array<{\n issueId: string;\n assignee: string;\n daysOverdue: number;\n priority: string;\n }>\n ): Promise<void> {\n const message: SlackMessage = {\n text: 'OVERDUE ISSUE ESCALATION',\n blocks: [\n {\n type: 'section',\n text: {\n type: 'mrkdwn',\n text: `*Overdue Issue Escalation*\\n${overdueAssignments.length} issues are overdue and require attention.`\n }\n }\n ],\n attachments: overdueAssignments.map(assignment => ({\n color: 'warning',\n title: `Issue ${assignment.issueId}`,\n fields: [\n {\n title: 'Assignee',\n value: assignment.assignee,\n short: true\n },\n {\n title: 'Days Overdue',\n value: assignment.daysOverdue.toString(),\n short: true\n },\n {\n title: 'Priority',\n value: assignment.priority.toUpperCase(),\n short: true\n }\n ]\n }))\n };\n\n await this.sendMessage(message);\n }\n\n /**\n * Send message to Slack\n */\n private async sendMessage(message: SlackMessage): Promise<void> {\n const payload = {\n ...message,\n channel: this.config.channel || message.channel,\n username: this.config.username || 'Trie Security Bot',\n icon_emoji: this.config.iconEmoji || ':shield:'\n };\n\n try {\n const response = await fetch(this.config.webhookUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(payload)\n });\n\n if (!response.ok) {\n throw new Error(`Slack API error: ${response.status} ${response.statusText}`);\n }\n } catch (error) {\n console.error('Failed to send Slack notification:', error);\n throw error;\n }\n }\n\n /**\n * Get emoji for notification type\n */\n private getNotificationEmoji(type: string): string {\n const emojis: Record<string, string> = {\n assignment: '[ASSIGN]',\n escalation: '[ESCALATE]',\n completion: '[DONE]',\n reminder: '[REMIND]'\n };\n return emojis[type] ?? '[NOTIFY]';\n }\n\n /**\n * Get color for assignment priority\n */\n private getAssignmentColor(priority: string): string {\n const colors: Record<string, string> = {\n urgent: 'danger',\n high: 'warning',\n medium: 'good',\n low: '#36a64f'\n };\n return colors[priority] ?? 'good';\n }\n\n /**\n * Test Slack connection\n */\n async testConnection(): Promise<boolean> {\n try {\n await this.sendMessage({\n text: 'Trie Slack Integration Test',\n blocks: [{\n type: 'section',\n text: {\n type: 'mrkdwn',\n text: '*Trie Slack Integration Test*\\nIf you see this message, the integration is working correctly!'\n }\n }]\n });\n return true;\n } catch (error) {\n console.error('Slack connection test failed:', error);\n return false;\n }\n }\n}","/**\n * Auto-Escalation System - Autonomous issue escalation\n * \n * Phase 4 of Guardian Agency Plan: Autonomous Actions\n * \n * Features:\n * - Auto-escalate critical security issues\n * - Respect quiet hours and cooldowns\n * - Multi-channel support (Slack, email, webhook)\n * - Escalation tracking and history\n * - Fallback to draft mode during quiet hours\n */\n\nimport type { Issue } from '../types/index.js';\nimport type { GuardianInsight } from './insight-store.js';\nimport { getInsightStore } from './insight-store.js';\nimport { getGuardianState } from './guardian-state.js';\nimport { SlackIntegration } from '../integrations/slack.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Escalation target configuration\n */\nexport interface EscalationTarget {\n type: 'slack' | 'email' | 'webhook';\n config: {\n webhookUrl?: string;\n email?: string;\n channel?: string;\n username?: string;\n };\n enabled: boolean;\n forSeverities: ('critical' | 'serious' | 'moderate')[];\n forCategories: ('security' | 'quality' | 'performance' | 'all')[];\n}\n\n/**\n * Escalation message\n */\nexport interface EscalationMessage {\n id: string;\n severity: 'critical' | 'serious' | 'moderate';\n title: string;\n body: string;\n issues: Issue[];\n timestamp: number;\n sent: boolean;\n sentAt?: number;\n channel?: string;\n error?: string;\n}\n\n/**\n * Escalation result\n */\nexport interface EscalationResult {\n action: 'auto_escalated' | 'draft_only' | 'blocked' | 'failed' | 'no_action';\n reason: string;\n message?: EscalationMessage;\n draftLocation?: string;\n}\n\n/**\n * Escalation configuration\n */\nexport interface EscalationConfig {\n enabled: boolean;\n targets: EscalationTarget[];\n cooldownMinutes: number;\n maxEscalationsPerHour: number;\n respectQuietHours: boolean;\n criticalBypassQuietHours: boolean;\n draftFallbackEnabled: boolean;\n}\n\nconst DEFAULT_CONFIG: EscalationConfig = {\n enabled: true,\n targets: [],\n cooldownMinutes: 15,\n maxEscalationsPerHour: 5,\n respectQuietHours: true,\n criticalBypassQuietHours: true,\n draftFallbackEnabled: true,\n};\n\n// ============================================================================\n// EscalationManager Class\n// ============================================================================\n\n/**\n * Manages autonomous escalation of critical issues\n */\nexport class EscalationManager {\n private projectPath: string;\n private config: EscalationConfig;\n private guardianState;\n private insightStore;\n private escalationHistory: EscalationMessage[] = [];\n private slackClient?: SlackIntegration;\n \n constructor(projectPath: string, config: Partial<EscalationConfig> = {}) {\n this.projectPath = projectPath;\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.guardianState = getGuardianState(projectPath);\n this.insightStore = getInsightStore(projectPath);\n \n // Initialize Slack client if configured\n const slackTarget = this.config.targets.find(t => t.type === 'slack' && t.enabled);\n if (slackTarget?.config.webhookUrl) {\n this.slackClient = new SlackIntegration({\n webhookUrl: slackTarget.config.webhookUrl,\n channel: slackTarget.config.channel,\n username: slackTarget.config.username,\n });\n }\n }\n \n /**\n * Check if an issue should be auto-escalated\n */\n shouldAutoEscalate(issue: Issue): boolean {\n // Must be enabled\n if (!this.config.enabled) {\n return false;\n }\n \n // Must be critical severity\n if (issue.severity !== 'critical') {\n return false;\n }\n \n // Check category (security issues get priority)\n const isSecurityIssue = \n issue.category === 'security' ||\n issue.agent === 'security' ||\n issue.issue.toLowerCase().includes('security') ||\n issue.issue.toLowerCase().includes('vulnerability') ||\n issue.issue.toLowerCase().includes('injection') ||\n issue.issue.toLowerCase().includes('xss') ||\n issue.issue.toLowerCase().includes('secret');\n \n if (!isSecurityIssue) {\n return false;\n }\n \n // Check quiet hours (unless critical bypasses)\n if (this.guardianState.isQuietHours()) {\n if (!this.config.criticalBypassQuietHours) {\n return false;\n }\n }\n \n // Check cooldown\n if (!this.insightStore.canCreateInsight('auto-escalation')) {\n return false;\n }\n \n // Check hourly limit\n const recentEscalations = this.escalationHistory.filter(e => \n e.timestamp > Date.now() - (60 * 60 * 1000)\n );\n if (recentEscalations.length >= this.config.maxEscalationsPerHour) {\n return false;\n }\n \n // Check if recently escalated same file\n const recentlyEscalated = this.escalationHistory.some(e =>\n e.issues.some(i => i.file === issue.file) &&\n e.timestamp > Date.now() - (this.config.cooldownMinutes * 60 * 1000)\n );\n if (recentlyEscalated) {\n return false;\n }\n \n // Must have a valid target\n return this.hasValidEscalationTarget('critical', 'security');\n }\n \n /**\n * Check if we have a valid escalation target\n */\n private hasValidEscalationTarget(severity: string, category: string): boolean {\n return this.config.targets.some(t => \n t.enabled &&\n t.forSeverities.includes(severity as any) &&\n (t.forCategories.includes(category as any) || t.forCategories.includes('all'))\n );\n }\n \n /**\n * Auto-escalate if issue is critical\n */\n async autoEscalateIfCritical(issue: Issue): Promise<EscalationResult> {\n // Check if should escalate\n if (!this.shouldAutoEscalate(issue)) {\n // Check if we should create a draft instead\n if (issue.severity === 'critical' && this.config.draftFallbackEnabled) {\n if (this.guardianState.isQuietHours()) {\n return this.createDraftEscalation([issue], 'Blocked by quiet hours');\n }\n }\n \n return {\n action: 'no_action',\n reason: 'Issue does not meet escalation criteria',\n };\n }\n \n // Create escalation message\n const message = this.createEscalationMessage([issue]);\n \n // Try to send\n try {\n await this.sendEscalation(message);\n \n // Record escalation\n this.escalationHistory.push(message);\n await this.insightStore.markInsightCreated('auto-escalation');\n \n // Create insight about escalation\n await this.createEscalationInsight(message);\n \n // Use risk budget\n await this.guardianState.useRiskBudget(1);\n \n return {\n action: 'auto_escalated',\n reason: 'Critical security issue auto-escalated',\n message,\n };\n \n } catch (error) {\n console.error('Failed to send escalation:', error);\n \n // Fallback to draft\n if (this.config.draftFallbackEnabled) {\n return this.createDraftEscalation([issue], String(error));\n }\n \n return {\n action: 'failed',\n reason: `Send failed: ${error}`,\n message,\n };\n }\n }\n \n /**\n * Escalate multiple issues at once\n */\n async escalateIssues(issues: Issue[]): Promise<EscalationResult> {\n // Filter to only critical security issues\n const criticalSecurityIssues = issues.filter(i => \n i.severity === 'critical' &&\n (i.category === 'security' || i.agent === 'security')\n );\n \n if (criticalSecurityIssues.length === 0) {\n return {\n action: 'no_action',\n reason: 'No critical security issues to escalate',\n };\n }\n \n // Check quiet hours\n if (this.guardianState.isQuietHours() && !this.config.criticalBypassQuietHours) {\n return this.createDraftEscalation(criticalSecurityIssues, 'Blocked by quiet hours');\n }\n \n // Create and send message\n const message = this.createEscalationMessage(criticalSecurityIssues);\n \n try {\n await this.sendEscalation(message);\n \n this.escalationHistory.push(message);\n await this.insightStore.markInsightCreated('auto-escalation');\n await this.createEscalationInsight(message);\n \n return {\n action: 'auto_escalated',\n reason: `Escalated ${criticalSecurityIssues.length} critical security issues`,\n message,\n };\n \n } catch (error) {\n if (this.config.draftFallbackEnabled) {\n return this.createDraftEscalation(criticalSecurityIssues, String(error));\n }\n \n return {\n action: 'failed',\n reason: `Send failed: ${error}`,\n message,\n };\n }\n }\n \n /**\n * Create an escalation message\n */\n private createEscalationMessage(issues: Issue[]): EscalationMessage {\n const severity = issues.some(i => i.severity === 'critical') ? 'critical' : 'serious';\n \n return {\n id: `esc-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n severity,\n title: `${severity.toUpperCase()} Security Alert: ${issues.length} issue${issues.length > 1 ? 's' : ''} detected`,\n body: this.formatEscalationBody(issues),\n issues,\n timestamp: Date.now(),\n sent: false,\n };\n }\n \n /**\n * Format escalation body text\n */\n private formatEscalationBody(issues: Issue[]): string {\n const lines: string[] = [\n `**Critical Security Issues Detected**`,\n ``,\n `**Project:** ${this.projectPath.split('/').pop()}`,\n `**Issues:** ${issues.length}`,\n `**Detected:** ${new Date().toISOString()}`,\n ``,\n `**Summary:**`,\n ];\n \n for (const issue of issues.slice(0, 5)) {\n lines.push(`- \\`${issue.file}:${issue.line || '?'}\\`: ${issue.issue.slice(0, 100)}`);\n }\n \n if (issues.length > 5) {\n lines.push(`- ... and ${issues.length - 5} more`);\n }\n \n lines.push('');\n lines.push('**Action Required:** Review and address these issues immediately.');\n \n return lines.join('\\n');\n }\n \n /**\n * Send escalation through configured channels\n */\n private async sendEscalation(message: EscalationMessage): Promise<void> {\n const enabledTargets = this.config.targets.filter(t => t.enabled);\n \n if (enabledTargets.length === 0) {\n throw new Error('No enabled escalation targets configured');\n }\n \n const errors: string[] = [];\n \n for (const target of enabledTargets) {\n try {\n switch (target.type) {\n case 'slack':\n await this.sendToSlack(message, target);\n break;\n case 'email':\n await this.sendToEmail(message, target);\n break;\n case 'webhook':\n await this.sendToWebhook(message, target);\n break;\n }\n message.sent = true;\n message.sentAt = Date.now();\n message.channel = target.type;\n } catch (error) {\n errors.push(`${target.type}: ${error}`);\n }\n }\n \n if (errors.length === enabledTargets.length) {\n // All failed\n throw new Error(`All escalation channels failed: ${errors.join('; ')}`);\n }\n }\n \n /**\n * Send to Slack\n */\n private async sendToSlack(message: EscalationMessage, target: EscalationTarget): Promise<void> {\n if (!target.config.webhookUrl) {\n throw new Error('Slack webhook URL not configured');\n }\n \n // Use existing SlackIntegration if available\n if (this.slackClient) {\n await this.slackClient.sendCriticalAlert(message.issues, this.projectPath.split('/').pop() || 'Unknown');\n } else {\n // Direct webhook call\n const slack = new SlackIntegration({\n webhookUrl: target.config.webhookUrl,\n channel: target.config.channel,\n username: target.config.username || 'Trie Guardian',\n });\n \n await slack.sendCriticalAlert(message.issues, this.projectPath.split('/').pop() || 'Unknown');\n }\n }\n \n /**\n * Send to email (placeholder - would need email provider integration)\n */\n private async sendToEmail(message: EscalationMessage, target: EscalationTarget): Promise<void> {\n if (!target.config.email) {\n throw new Error('Email address not configured');\n }\n \n // In a real implementation, this would use an email provider (SendGrid, SES, etc.)\n // For now, we'll log and simulate success\n console.log(`[EMAIL ESCALATION] To: ${target.config.email}`);\n console.log(`Subject: ${message.title}`);\n console.log(`Body: ${message.body}`);\n \n // Note: In production, replace with actual email sending:\n // await sendEmail({\n // to: target.config.email,\n // subject: message.title,\n // body: message.body,\n // });\n }\n \n /**\n * Send to webhook\n */\n private async sendToWebhook(message: EscalationMessage, target: EscalationTarget): Promise<void> {\n if (!target.config.webhookUrl) {\n throw new Error('Webhook URL not configured');\n }\n \n const response = await fetch(target.config.webhookUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n id: message.id,\n severity: message.severity,\n title: message.title,\n body: message.body,\n issues: message.issues.map(i => ({\n file: i.file,\n line: i.line,\n severity: i.severity,\n issue: i.issue,\n agent: i.agent,\n })),\n timestamp: message.timestamp,\n project: this.projectPath,\n }),\n });\n \n if (!response.ok) {\n throw new Error(`Webhook returned ${response.status}: ${response.statusText}`);\n }\n }\n \n /**\n * Create a draft escalation (when sending is blocked)\n */\n private createDraftEscalation(issues: Issue[], reason: string): EscalationResult {\n const message = this.createEscalationMessage(issues);\n message.error = reason;\n \n // Store as draft\n this.escalationHistory.push(message);\n \n return {\n action: 'draft_only',\n reason,\n message,\n draftLocation: `.trie/drafts/escalation-${message.id}.json`,\n };\n }\n \n /**\n * Create insight about escalation\n */\n private async createEscalationInsight(message: EscalationMessage): Promise<void> {\n const insight: GuardianInsight = {\n id: `insight-esc-${message.id}`,\n type: 'warning',\n message: `Auto-escalated: ${message.issues.length} critical security issue${message.issues.length > 1 ? 's' : ''}`,\n context: `Sent to ${message.channel}. Issues in: ${[...new Set(message.issues.map(i => i.file))].slice(0, 3).join(', ')}`,\n relatedIssues: message.issues.map(i => i.id),\n priority: 10,\n timestamp: Date.now(),\n dismissed: false,\n category: 'security',\n details: {\n affectedFiles: [...new Set(message.issues.map(i => i.file))],\n },\n };\n \n await this.insightStore.addInsight(insight);\n }\n \n /**\n * Get escalation history\n */\n getEscalationHistory(): EscalationMessage[] {\n return [...this.escalationHistory];\n }\n \n /**\n * Get pending draft escalations\n */\n getPendingDrafts(): EscalationMessage[] {\n return this.escalationHistory.filter(e => !e.sent);\n }\n \n /**\n * Retry a failed/draft escalation\n */\n async retryEscalation(messageId: string): Promise<EscalationResult> {\n const message = this.escalationHistory.find(e => e.id === messageId);\n if (!message) {\n return {\n action: 'failed',\n reason: 'Escalation message not found',\n };\n }\n \n try {\n await this.sendEscalation(message);\n \n return {\n action: 'auto_escalated',\n reason: 'Retry successful',\n message,\n };\n } catch (error) {\n return {\n action: 'failed',\n reason: `Retry failed: ${error}`,\n message,\n };\n }\n }\n \n /**\n * Configure escalation targets\n */\n addEscalationTarget(target: EscalationTarget): void {\n this.config.targets.push(target);\n \n // Re-initialize Slack client if needed\n if (target.type === 'slack' && target.enabled && target.config.webhookUrl) {\n this.slackClient = new SlackIntegration({\n webhookUrl: target.config.webhookUrl,\n channel: target.config.channel,\n username: target.config.username,\n });\n }\n }\n \n /**\n * Get current configuration\n */\n getConfig(): EscalationConfig {\n return { ...this.config };\n }\n \n /**\n * Update configuration\n */\n setConfig(config: Partial<EscalationConfig>): void {\n this.config = { ...this.config, ...config };\n }\n}\n\n// ============================================================================\n// Singleton Management\n// ============================================================================\n\nconst escalationManagers: Map<string, EscalationManager> = new Map();\n\n/**\n * Get the EscalationManager for a project (singleton per project)\n */\nexport function getEscalationManager(projectPath: string): EscalationManager {\n let manager = escalationManagers.get(projectPath);\n if (!manager) {\n manager = new EscalationManager(projectPath);\n escalationManagers.set(projectPath, manager);\n }\n return manager;\n}\n\n/**\n * Clear all EscalationManager instances (for testing)\n */\nexport function clearEscalationManagers(): void {\n escalationManagers.clear();\n}\n","/**\n * Meta-Learning System - Self-improving agent behavior\n * \n * Phase 4 of Guardian Agency Plan: Autonomous Actions\n * \n * Features:\n * - Track user feedback on insights\n * - Adjust insight weights based on feedback\n * - Calculate agent effectiveness metrics\n * - Learn which insights are most valuable\n * - Improve prediction accuracy over time\n */\n\nimport type { GuardianInsight } from './insight-store.js';\nimport { getInsightStore } from './insight-store.js';\nimport { getGuardianState, type AgentMetrics } from './guardian-state.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Feedback types from users\n */\nexport type FeedbackType = 'helpful' | 'dismissed' | 'acted' | 'ignored';\n\n/**\n * Insight feedback record\n */\nexport interface InsightFeedback {\n insightId: string;\n insightType: GuardianInsight['type'];\n insightCategory: GuardianInsight['category'];\n feedback: FeedbackType;\n timestamp: number;\n latencyMs?: number; // Time from insight shown to feedback\n}\n\n/**\n * Category effectiveness stats\n */\nexport interface CategoryEffectiveness {\n category: string;\n totalInsights: number;\n helpfulCount: number;\n dismissedCount: number;\n actedCount: number;\n effectivenessScore: number; // 0-1\n}\n\n/**\n * Learning weights for insight generation\n */\nexport interface InsightWeights {\n security: number;\n quality: number;\n performance: number;\n pattern: number;\n progress: number;\n general: number;\n}\n\n/**\n * Agent effectiveness report\n */\nexport interface EffectivenessReport {\n overallScore: number;\n predictiveAccuracy: number;\n userSatisfaction: number;\n falsePositiveRate: number;\n categoryBreakdown: CategoryEffectiveness[];\n recommendations: string[];\n trends: {\n period: string;\n direction: 'improving' | 'stable' | 'declining';\n };\n}\n\n// ============================================================================\n// MetaLearner Class\n// ============================================================================\n\n/**\n * Meta-learning engine for agent self-improvement\n */\nexport class MetaLearner {\n private guardianState;\n private insightStore;\n private feedbackHistory: InsightFeedback[] = [];\n private weights: InsightWeights;\n \n constructor(projectPath: string) {\n this.guardianState = getGuardianState(projectPath);\n this.insightStore = getInsightStore(projectPath);\n \n // Initialize with default weights\n this.weights = {\n security: 1.0,\n quality: 1.0,\n performance: 1.0,\n pattern: 1.0,\n progress: 1.0,\n general: 1.0,\n };\n }\n \n /**\n * Record user feedback on an insight\n */\n async recordFeedback(\n feedback: FeedbackType,\n context: {\n insightId: string;\n latencyMs?: number;\n }\n ): Promise<void> {\n await this.insightStore.load();\n const insight = this.insightStore.getInsight(context.insightId);\n \n if (!insight) {\n console.error(`Insight not found: ${context.insightId}`);\n return;\n }\n \n // Record feedback\n const record: InsightFeedback = {\n insightId: context.insightId,\n insightType: insight.type,\n insightCategory: insight.category,\n feedback,\n timestamp: Date.now(),\n };\n \n if (context.latencyMs !== undefined) {\n record.latencyMs = context.latencyMs;\n }\n \n this.feedbackHistory.push(record);\n \n // Update guardian state metrics\n await this.guardianState.recordInsightFeedback(\n feedback === 'dismissed' ? 'dismissed' : \n feedback === 'acted' ? 'acted' : 'helpful'\n );\n \n // Adjust weights based on feedback\n await this.adjustWeights(record);\n }\n \n /**\n * Adjust insight weights based on feedback\n */\n private async adjustWeights(feedback: InsightFeedback): Promise<void> {\n const category = feedback.insightCategory as keyof InsightWeights;\n const currentWeight = this.weights[category];\n \n if (currentWeight === undefined) return;\n \n // Positive feedback increases weight, dismissal decreases\n let adjustment = 0;\n switch (feedback.feedback) {\n case 'acted':\n adjustment = 0.05; // Strong positive signal\n break;\n case 'helpful':\n adjustment = 0.02; // Moderate positive\n break;\n case 'dismissed':\n adjustment = -0.03; // Negative signal\n break;\n case 'ignored':\n adjustment = -0.01; // Weak negative\n break;\n }\n \n // Apply adjustment with bounds\n this.weights[category] = Math.max(0.3, Math.min(1.5, currentWeight + adjustment));\n }\n \n /**\n * Get current insight weights\n */\n getWeights(): InsightWeights {\n return { ...this.weights };\n }\n \n /**\n * Get weight for a category (used to adjust insight priority)\n */\n getCategoryWeight(category: GuardianInsight['category']): number {\n return this.weights[category] ?? 1.0;\n }\n \n /**\n * Calculate category effectiveness\n */\n calculateCategoryEffectiveness(): CategoryEffectiveness[] {\n const categories = ['security', 'quality', 'performance', 'pattern', 'progress', 'general'];\n const effectiveness: CategoryEffectiveness[] = [];\n \n for (const category of categories) {\n const categoryFeedback = this.feedbackHistory.filter(f => f.insightCategory === category);\n \n if (categoryFeedback.length === 0) {\n effectiveness.push({\n category,\n totalInsights: 0,\n helpfulCount: 0,\n dismissedCount: 0,\n actedCount: 0,\n effectivenessScore: 0.5, // Neutral when no data\n });\n continue;\n }\n \n const helpfulCount = categoryFeedback.filter(f => f.feedback === 'helpful' || f.feedback === 'acted').length;\n const dismissedCount = categoryFeedback.filter(f => f.feedback === 'dismissed').length;\n const actedCount = categoryFeedback.filter(f => f.feedback === 'acted').length;\n \n // Effectiveness = (helpful + 2*acted) / (total + dismissed)\n const score = (helpfulCount + actedCount) / Math.max(1, categoryFeedback.length);\n \n effectiveness.push({\n category,\n totalInsights: categoryFeedback.length,\n helpfulCount,\n dismissedCount,\n actedCount,\n effectivenessScore: score,\n });\n }\n \n return effectiveness;\n }\n \n /**\n * Get agent effectiveness metrics\n */\n getEffectiveness(): AgentMetrics {\n return this.guardianState.getMetrics();\n }\n \n /**\n * Generate a comprehensive effectiveness report\n */\n async generateEffectivenessReport(): Promise<EffectivenessReport> {\n await this.guardianState.load();\n const metrics = this.guardianState.getMetrics();\n const categoryBreakdown = this.calculateCategoryEffectiveness();\n \n // Calculate overall score (weighted average of metrics)\n const overallScore = (\n metrics.userSatisfaction * 0.4 +\n metrics.predictiveAccuracy * 0.3 +\n (1 - metrics.falsePositiveRate) * 0.3\n );\n \n // Generate recommendations\n const recommendations = this.generateRecommendations(metrics, categoryBreakdown);\n \n // Determine trend\n const trend = this.calculateTrend();\n \n return {\n overallScore,\n predictiveAccuracy: metrics.predictiveAccuracy,\n userSatisfaction: metrics.userSatisfaction,\n falsePositiveRate: metrics.falsePositiveRate,\n categoryBreakdown,\n recommendations,\n trends: trend,\n };\n }\n \n /**\n * Generate improvement recommendations\n */\n private generateRecommendations(\n metrics: AgentMetrics,\n categoryBreakdown: CategoryEffectiveness[]\n ): string[] {\n const recommendations: string[] = [];\n \n // Check false positive rate\n if (metrics.falsePositiveRate > 0.3) {\n recommendations.push('High dismissal rate detected. Consider raising insight thresholds.');\n }\n \n // Check user satisfaction\n if (metrics.userSatisfaction < 0.5) {\n recommendations.push('User satisfaction is low. Review insight quality and relevance.');\n }\n \n // Check category effectiveness\n const weakCategories = categoryBreakdown\n .filter(c => c.totalInsights >= 5 && c.effectivenessScore < 0.4)\n .map(c => c.category);\n \n if (weakCategories.length > 0) {\n recommendations.push(\n `Low effectiveness in: ${weakCategories.join(', ')}. Consider adjusting insight generation for these categories.`\n );\n }\n \n // Check for high-performing categories\n const strongCategories = categoryBreakdown\n .filter(c => c.totalInsights >= 5 && c.effectivenessScore > 0.7)\n .map(c => c.category);\n \n if (strongCategories.length > 0) {\n recommendations.push(\n `Strong performance in: ${strongCategories.join(', ')}. Consider emphasizing these insights.`\n );\n }\n \n // Check prediction accuracy\n if (metrics.predictiveAccuracy < 0.6 && metrics.totalPredictions >= 10) {\n recommendations.push('Prediction accuracy below target. Review risk scoring factors.');\n }\n \n // Positive reinforcement if doing well\n if (metrics.userSatisfaction >= 0.7 && metrics.falsePositiveRate <= 0.2) {\n recommendations.push('Agent performance is excellent. Keep up the good work!');\n }\n \n return recommendations;\n }\n \n /**\n * Calculate trend direction\n */\n private calculateTrend(): { period: string; direction: 'improving' | 'stable' | 'declining' } {\n // Compare recent feedback to older feedback\n const now = Date.now();\n const recentCutoff = now - (7 * 24 * 60 * 60 * 1000); // 7 days\n const olderCutoff = now - (30 * 24 * 60 * 60 * 1000); // 30 days\n \n const recentFeedback = this.feedbackHistory.filter(f => f.timestamp > recentCutoff);\n const olderFeedback = this.feedbackHistory.filter(f => \n f.timestamp > olderCutoff && f.timestamp <= recentCutoff\n );\n \n if (recentFeedback.length < 5 || olderFeedback.length < 5) {\n return { period: 'last 30 days', direction: 'stable' };\n }\n \n // Calculate satisfaction rates\n const recentPositive = recentFeedback.filter(f => \n f.feedback === 'helpful' || f.feedback === 'acted'\n ).length / recentFeedback.length;\n \n const olderPositive = olderFeedback.filter(f => \n f.feedback === 'helpful' || f.feedback === 'acted'\n ).length / olderFeedback.length;\n \n const diff = recentPositive - olderPositive;\n \n if (diff > 0.1) {\n return { period: 'last 30 days', direction: 'improving' };\n } else if (diff < -0.1) {\n return { period: 'last 30 days', direction: 'declining' };\n }\n \n return { period: 'last 30 days', direction: 'stable' };\n }\n \n /**\n * Should an insight be shown based on learning?\n * \n * Uses weights and user patterns to filter low-value insights.\n */\n shouldShowInsight(insight: GuardianInsight): boolean {\n const weight = this.getCategoryWeight(insight.category);\n \n // If weight is very low, filter out low-priority insights\n if (weight < 0.5 && insight.priority < 5) {\n return false;\n }\n \n // Adjust priority threshold based on category weight\n const adjustedPriority = insight.priority * weight;\n \n // Show if adjusted priority is above threshold\n return adjustedPriority >= 3;\n }\n \n /**\n * Adjust insight priority based on learning\n */\n adjustInsightPriority(insight: GuardianInsight): number {\n const weight = this.getCategoryWeight(insight.category);\n return Math.round(insight.priority * weight);\n }\n \n /**\n * Get feedback history stats\n */\n getFeedbackStats(): {\n total: number;\n helpful: number;\n dismissed: number;\n acted: number;\n ignored: number;\n averageLatencyMs: number | null;\n } {\n const stats = {\n total: this.feedbackHistory.length,\n helpful: 0,\n dismissed: 0,\n acted: 0,\n ignored: 0,\n averageLatencyMs: null as number | null,\n };\n \n let totalLatency = 0;\n let latencyCount = 0;\n \n for (const feedback of this.feedbackHistory) {\n switch (feedback.feedback) {\n case 'helpful': stats.helpful++; break;\n case 'dismissed': stats.dismissed++; break;\n case 'acted': stats.acted++; break;\n case 'ignored': stats.ignored++; break;\n }\n \n if (feedback.latencyMs !== undefined) {\n totalLatency += feedback.latencyMs;\n latencyCount++;\n }\n }\n \n if (latencyCount > 0) {\n stats.averageLatencyMs = Math.round(totalLatency / latencyCount);\n }\n \n return stats;\n }\n \n /**\n * Reset learning (for testing)\n */\n reset(): void {\n this.feedbackHistory = [];\n this.weights = {\n security: 1.0,\n quality: 1.0,\n performance: 1.0,\n pattern: 1.0,\n progress: 1.0,\n general: 1.0,\n };\n }\n}\n\n// ============================================================================\n// Singleton Management\n// ============================================================================\n\nconst metaLearners: Map<string, MetaLearner> = new Map();\n\n/**\n * Get the MetaLearner for a project (singleton per project)\n */\nexport function getMetaLearner(projectPath: string): MetaLearner {\n let learner = metaLearners.get(projectPath);\n if (!learner) {\n learner = new MetaLearner(projectPath);\n metaLearners.set(projectPath, learner);\n }\n return learner;\n}\n\n/**\n * Clear all MetaLearner instances (for testing)\n */\nexport function clearMetaLearners(): void {\n metaLearners.clear();\n}\n"],"mappings":"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","names":["basename","issues","DEFAULT_CONFIG","basename","currentHashes","ContextGraph"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/memory/compactor.ts","../src/memory/issue-store.ts","../src/memory/bm25.ts"],"sourcesContent":["/**\n * Memory Compactor\n * \n * Intelligently compacts old issues into summaries instead of deleting them.\n * Preserves patterns and insights while reducing storage.\n * \n * Phase 1 Hardening:\n * - Atomic writes to prevent corruption\n * - Backup rotation for recovery\n * - Zod validation for data integrity\n */\n\nimport { mkdir, readFile } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { getTrieDirectory } from '../utils/workspace.js';\nimport type { StoredIssue } from './issue-store.js';\nimport { atomicWriteJSON } from '../utils/atomic-write.js';\nimport { BackupManager } from '../utils/backup-manager.js';\nimport { CompactedSummariesIndexSchema, safeParseAndValidate } from './validation.js';\n\nexport interface CompactedSummary {\n period: string;\n startDate: string;\n endDate: string;\n totalIssues: number;\n resolvedCount: number;\n bySeverity: Record<string, number>;\n byAgent: Record<string, number>;\n topPatterns: PatternSummary[];\n hotFiles: { file: string; count: number }[];\n compactedAt: string;\n}\n\nexport interface PatternSummary {\n pattern: string;\n count: number;\n severity: string;\n agent: string;\n exampleFix: string;\n}\n\n/**\n * Compact old issues into summaries\n * Returns the compacted summary and the remaining (recent) issues\n */\nexport async function compactOldIssues(\n issues: StoredIssue[],\n options: {\n keepDays?: number;\n minIssuesToCompact?: number;\n } = {}\n): Promise<{ summary: CompactedSummary | null; remaining: StoredIssue[] }> {\n const keepDays = options.keepDays ?? 30;\n const minIssues = options.minIssuesToCompact ?? 100;\n \n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - keepDays);\n \n const oldIssues = issues.filter(i => new Date(i.timestamp) < cutoffDate);\n const recentIssues = issues.filter(i => new Date(i.timestamp) >= cutoffDate);\n \n // Only compact if we have enough old issues\n if (oldIssues.length < minIssues) {\n return { summary: null, remaining: issues };\n }\n \n // Build summary\n const summary = buildSummary(oldIssues);\n \n return { summary, remaining: recentIssues };\n}\n\n/**\n * Build a summary from a set of issues\n */\nfunction buildSummary(issues: StoredIssue[]): CompactedSummary {\n const sorted = issues.sort((a, b) => \n new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()\n );\n \n const bySeverity: Record<string, number> = {};\n const byAgent: Record<string, number> = {};\n const patternMap: Map<string, { count: number; issue: StoredIssue }> = new Map();\n const fileCount: Map<string, number> = new Map();\n \n for (const issue of issues) {\n // Count by severity\n bySeverity[issue.severity] = (bySeverity[issue.severity] || 0) + 1;\n \n // Count by agent\n byAgent[issue.agent] = (byAgent[issue.agent] || 0) + 1;\n \n // Track patterns (normalized issue text)\n const patternKey = normalizePattern(issue.issue);\n const existing = patternMap.get(patternKey);\n if (existing) {\n existing.count++;\n } else {\n patternMap.set(patternKey, { count: 1, issue });\n }\n \n // Count files\n const fileName = issue.file.split('/').pop() || issue.file;\n fileCount.set(fileName, (fileCount.get(fileName) || 0) + 1);\n }\n \n // Get top patterns\n const topPatterns = Array.from(patternMap.entries())\n .sort((a, b) => b[1].count - a[1].count)\n .slice(0, 10)\n .map(([pattern, data]) => ({\n pattern: pattern.slice(0, 100),\n count: data.count,\n severity: data.issue.severity,\n agent: data.issue.agent,\n exampleFix: data.issue.fix.slice(0, 200),\n }));\n \n // Get hot files\n const hotFiles = Array.from(fileCount.entries())\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n .map(([file, count]) => ({ file, count }));\n \n return {\n period: `${sorted[0]?.timestamp.split('T')[0]} to ${sorted[sorted.length - 1]?.timestamp.split('T')[0]}`,\n startDate: sorted[0]?.timestamp || '',\n endDate: sorted[sorted.length - 1]?.timestamp || '',\n totalIssues: issues.length,\n resolvedCount: issues.filter(i => i.resolved).length,\n bySeverity,\n byAgent,\n topPatterns,\n hotFiles,\n compactedAt: new Date().toISOString(),\n };\n}\n\n/**\n * Normalize issue text for pattern matching\n */\nfunction normalizePattern(text: string): string {\n return text\n .toLowerCase()\n .replace(/`[^`]+`/g, 'CODE')\n .replace(/\\b\\d+\\b/g, 'N')\n .replace(/[\"']/g, '')\n .replace(/\\s+/g, ' ')\n .trim()\n .slice(0, 150);\n}\n\n/**\n * Save compacted summary to disk with atomic write and backup\n */\nexport async function saveCompactedSummary(\n summary: CompactedSummary,\n projectDir: string\n): Promise<void> {\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n await mkdir(memoryDir, { recursive: true });\n \n const summaryPath = join(memoryDir, 'compacted-summaries.json');\n \n let summaries: CompactedSummary[] = [];\n try {\n if (existsSync(summaryPath)) {\n const content = await readFile(summaryPath, 'utf-8');\n const result = safeParseAndValidate(content, CompactedSummariesIndexSchema);\n if (result.success) {\n summaries = result.data as CompactedSummary[];\n }\n }\n } catch {\n summaries = [];\n }\n \n summaries.push(summary);\n \n // Keep only last 12 summaries (1 year of monthly summaries)\n if (summaries.length > 12) {\n summaries = summaries.slice(-12);\n }\n \n // Create backup before writing\n const backupManager = new BackupManager(summaryPath);\n await backupManager.createBackup();\n \n // Atomic write\n await atomicWriteJSON(summaryPath, summaries);\n}\n\n/**\n * Load compacted summaries with validation and auto-recovery\n */\nexport async function loadCompactedSummaries(projectDir: string): Promise<CompactedSummary[]> {\n const summaryPath = join(getTrieDirectory(projectDir), 'memory', 'compacted-summaries.json');\n \n try {\n if (existsSync(summaryPath)) {\n const content = await readFile(summaryPath, 'utf-8');\n const result = safeParseAndValidate(content, CompactedSummariesIndexSchema);\n \n if (result.success) {\n return result.data as CompactedSummary[];\n }\n \n // Validation failed - attempt recovery\n const backupManager = new BackupManager(summaryPath);\n if (await backupManager.recoverFromBackup()) {\n const recovered = await readFile(summaryPath, 'utf-8');\n const recoveredResult = safeParseAndValidate(recovered, CompactedSummariesIndexSchema);\n if (recoveredResult.success) {\n return recoveredResult.data as CompactedSummary[];\n }\n }\n }\n } catch {\n // File doesn't exist or recovery failed\n }\n \n return [];\n}\n\n/**\n * Generate a markdown summary of compacted history\n */\nexport function formatCompactedSummary(summary: CompactedSummary): string {\n const lines: string[] = [\n `## Compacted Summary: ${summary.period}`,\n '',\n `**Total Issues:** ${summary.totalIssues} (${summary.resolvedCount} resolved)`,\n '',\n '### By Severity',\n ...Object.entries(summary.bySeverity).map(([s, c]) => `- ${s}: ${c}`),\n '',\n '### Top Patterns',\n ...summary.topPatterns.slice(0, 5).map(p => \n `- **${p.pattern.slice(0, 50)}...** (${p.count}x, ${p.severity})`\n ),\n '',\n '### Hot Files',\n ...summary.hotFiles.slice(0, 5).map(f => `- ${f.file}: ${f.count} issues`),\n ];\n \n return lines.join('\\n');\n}\n\n/**\n * Get insights from compacted history\n */\nexport async function getHistoricalInsights(projectDir: string): Promise<{\n totalHistoricalIssues: number;\n recurringPatterns: PatternSummary[];\n improvementTrend: 'improving' | 'stable' | 'declining' | 'unknown';\n}> {\n const summaries = await loadCompactedSummaries(projectDir);\n \n if (summaries.length === 0) {\n return {\n totalHistoricalIssues: 0,\n recurringPatterns: [],\n improvementTrend: 'unknown',\n };\n }\n \n const totalHistoricalIssues = summaries.reduce((sum, s) => sum + s.totalIssues, 0);\n \n // Find patterns that appear across multiple summaries\n const patternCounts: Map<string, PatternSummary & { appearances: number }> = new Map();\n \n for (const summary of summaries) {\n for (const pattern of summary.topPatterns) {\n const key = pattern.pattern;\n const existing = patternCounts.get(key);\n if (existing) {\n existing.count += pattern.count;\n existing.appearances++;\n } else {\n patternCounts.set(key, { ...pattern, appearances: 1 });\n }\n }\n }\n \n const recurringPatterns = Array.from(patternCounts.values())\n .filter(p => p.appearances >= 2)\n .sort((a, b) => b.count - a.count)\n .slice(0, 5);\n \n // Calculate improvement trend\n let improvementTrend: 'improving' | 'stable' | 'declining' | 'unknown' = 'unknown';\n \n if (summaries.length >= 2) {\n const recent = summaries.slice(-2);\n const olderCount = recent[0]?.totalIssues || 0;\n const newerCount = recent[1]?.totalIssues || 0;\n \n if (newerCount < olderCount * 0.8) {\n improvementTrend = 'improving';\n } else if (newerCount > olderCount * 1.2) {\n improvementTrend = 'declining';\n } else {\n improvementTrend = 'stable';\n }\n }\n \n return {\n totalHistoricalIssues,\n recurringPatterns,\n improvementTrend,\n };\n}\n","/**\n * Issue Memory Store\n * \n * Stores issues for semantic search and pattern detection.\n * Uses BM25 ranking for search (same algorithm as Elasticsearch).\n * Local JSON storage with daily logs.\n * \n * Phase 1 Hardening:\n * - SHA256 hashing for proper deduplication\n * - Atomic writes to prevent corruption\n * - Rotational backups for recovery\n * - Zod validation for data integrity\n */\n\nimport { mkdir, writeFile, readFile, readdir } from 'fs/promises';\nimport { createHash } from 'crypto';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { getWorkingDirectory, getTrieDirectory } from '../utils/workspace.js';\nimport type { Issue } from '../types/index.js';\nimport { BM25Index } from './bm25.js';\nimport { compactOldIssues, saveCompactedSummary, getHistoricalInsights } from './compactor.js';\nimport { atomicWriteJSON } from '../utils/atomic-write.js';\nimport { BackupManager } from '../utils/backup-manager.js';\nimport { IssueIndexSchema, safeParseAndValidate } from './validation.js';\nimport { appendIssuesToLedger } from './ledger.js';\n\nexport interface StoredIssue {\n id: string;\n hash: string;\n severity: string;\n issue: string;\n fix: string;\n file: string;\n line: number | undefined;\n agent: string;\n category: string | undefined;\n timestamp: string;\n project: string;\n resolved: boolean | undefined;\n resolvedAt: string | undefined;\n}\n\nexport interface IssueSearchResult {\n issue: StoredIssue;\n score: number;\n matchType: 'bm25' | 'keyword' | 'fts5';\n}\n\nexport interface IssueMemoryStats {\n totalIssues: number;\n activeIssues: number; // Unresolved issues\n issuesByAgent: Record<string, number>;\n issuesBySeverity: Record<string, number>; // All issues (historical)\n activeIssuesBySeverity: Record<string, number>; // Only unresolved\n oldestIssue: string | undefined;\n newestIssue: string | undefined;\n resolvedCount: number;\n historicalIssues: number;\n improvementTrend: 'improving' | 'stable' | 'declining' | 'unknown';\n capacityInfo: {\n current: number;\n max: number;\n percentFull: number;\n isAtCap: boolean;\n };\n deduplicationStats: {\n duplicatesAvoided: number;\n uniquePatterns: number;\n };\n}\n\n/**\n * Store issues from a scan\n * Returns number of unique issues added (after deduplication)\n */\nexport async function storeIssues(\n issues: Issue[],\n project: string,\n workDir?: string\n): Promise<{ stored: number; duplicates: number }> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n await mkdir(memoryDir, { recursive: true });\n \n const stored: StoredIssue[] = [];\n const now = new Date().toISOString();\n const seenHashes = new Set<string>();\n let duplicates = 0;\n \n for (const issue of issues) {\n const hash = hashIssue(issue);\n \n // Skip duplicates within the same scan\n if (seenHashes.has(hash)) {\n duplicates++;\n continue;\n }\n seenHashes.add(hash);\n \n const storedIssue: StoredIssue = {\n id: issue.id,\n hash,\n severity: issue.severity,\n issue: issue.issue,\n fix: issue.fix,\n file: issue.file,\n line: issue.line,\n agent: issue.agent,\n category: issue.category,\n timestamp: now,\n project,\n resolved: false,\n resolvedAt: undefined,\n };\n stored.push(storedIssue);\n }\n\n await appendToDailyLog(stored, projectDir);\n await appendIssuesToLedger(stored, projectDir);\n const dedupedCount = await updateIssueIndex(stored, projectDir);\n \n return { stored: dedupedCount, duplicates: duplicates + (stored.length - dedupedCount) };\n}\n\n/**\n * Search issues using BM25 ranking (same algorithm as Elasticsearch)\n */\nexport async function searchIssues(\n query: string,\n options: {\n workDir?: string;\n limit?: number;\n project?: string;\n severity?: string[];\n agent?: string;\n includeResolved?: boolean;\n } = {}\n): Promise<IssueSearchResult[]> {\n const projectDir = options.workDir || getWorkingDirectory(undefined, true);\n const limit = options.limit || 10;\n const allIssues = await loadIssueIndex(projectDir);\n \n if (allIssues.length === 0) {\n return [];\n }\n\n // Filter issues first\n const filteredIssues = allIssues.filter(issue => {\n if (options.project && issue.project !== options.project) return false;\n if (options.severity && !options.severity.includes(issue.severity)) return false;\n if (options.agent && issue.agent !== options.agent) return false;\n if (!options.includeResolved && issue.resolved) return false;\n return true;\n });\n\n if (filteredIssues.length === 0) {\n return [];\n }\n\n // Build BM25 index\n const bm25 = new BM25Index();\n const issueMap = new Map<string, StoredIssue>();\n \n for (const issue of filteredIssues) {\n const searchText = `${issue.issue} ${issue.fix} ${issue.file} ${issue.agent} ${issue.category || ''} ${issue.severity}`;\n bm25.addDocument({\n id: issue.id,\n text: searchText,\n });\n issueMap.set(issue.id, issue);\n }\n\n // Search with BM25\n const bm25Results = bm25.search(query, limit);\n \n return bm25Results.map(result => ({\n issue: issueMap.get(result.id)!,\n score: result.score,\n matchType: 'bm25' as const,\n }));\n}\n\n/**\n * Find similar issues using BM25 similarity\n */\nexport async function findSimilarIssues(\n issue: Issue,\n options: {\n workDir?: string;\n limit?: number;\n excludeSameFile?: boolean;\n } = {}\n): Promise<IssueSearchResult[]> {\n // Use the issue description and fix as the query for similarity\n const query = `${issue.issue} ${issue.fix} ${issue.agent}`;\n const searchOptions: Parameters<typeof searchIssues>[1] = {\n limit: (options.limit || 5) + 5, // Get extra to account for filtering\n includeResolved: true,\n };\n if (options.workDir !== undefined) {\n searchOptions.workDir = options.workDir;\n }\n const results = await searchIssues(query, searchOptions);\n\n let filtered = results.filter(r => r.issue.id !== issue.id);\n \n if (options.excludeSameFile) {\n filtered = filtered.filter(r => r.issue.file !== issue.file);\n }\n \n return filtered.slice(0, options.limit || 5);\n}\n\n/**\n * Mark an issue as resolved\n */\nexport async function markIssueResolved(\n issueId: string,\n workDir?: string\n): Promise<boolean> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const index = await loadIssueIndex(projectDir);\n \n const issue = index.find(i => i.id === issueId);\n if (!issue) return false;\n \n issue.resolved = true;\n issue.resolvedAt = new Date().toISOString();\n \n await saveIssueIndex(index, projectDir);\n return true;\n}\n\n/**\n * Auto-resolve issues that were not found in the latest scan\n * \n * After a scan completes, this function compares new issues against stored issues.\n * Issues that were previously found in scanned files but are no longer detected\n * are automatically marked as resolved.\n * \n * @param newIssueHashes - Set of hashes from the current scan\n * @param scannedFiles - List of files that were scanned (to scope resolution)\n * @param workDir - Working directory\n * @returns Number of issues auto-resolved\n */\nexport async function autoResolveIssues(\n newIssueHashes: Set<string>,\n scannedFiles: string[],\n workDir?: string\n): Promise<{ resolved: number; stillActive: number }> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const index = await loadIssueIndex(projectDir);\n \n // Normalize scanned file paths for comparison\n const scannedFileSet = new Set(scannedFiles.map(f => f.replace(/\\\\/g, '/')));\n \n const now = new Date().toISOString();\n let resolvedCount = 0;\n let stillActiveCount = 0;\n \n for (const issue of index) {\n // Skip already resolved issues\n if (issue.resolved) continue;\n \n // Normalize the issue file path\n const normalizedFile = issue.file.replace(/\\\\/g, '/');\n \n // Only auto-resolve issues in files that were scanned\n // This prevents marking issues as resolved if we just did a partial scan\n if (!scannedFileSet.has(normalizedFile)) {\n stillActiveCount++;\n continue;\n }\n \n // If the issue's hash is NOT in the new scan results, it's been fixed\n if (!newIssueHashes.has(issue.hash)) {\n issue.resolved = true;\n issue.resolvedAt = now;\n resolvedCount++;\n } else {\n stillActiveCount++;\n }\n }\n \n // Only save if we resolved something\n if (resolvedCount > 0) {\n await saveIssueIndex(index, projectDir);\n }\n \n return { resolved: resolvedCount, stillActive: stillActiveCount };\n}\n\n/**\n * Get hash for an issue (for external callers)\n */\nexport function getIssueHash(issue: Issue): string {\n return hashIssue(issue);\n}\n\n/**\n * Get memory statistics including historical insights\n */\nexport async function getMemoryStats(workDir?: string): Promise<IssueMemoryStats> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const index = await loadIssueIndex(projectDir);\n const historical = await getHistoricalInsights(projectDir);\n \n const MAX_ISSUES = 10000;\n const uniqueHashes = new Set(index.map(i => i.hash));\n \n const stats: IssueMemoryStats = {\n totalIssues: index.length,\n activeIssues: 0,\n issuesByAgent: {},\n issuesBySeverity: {},\n activeIssuesBySeverity: {},\n oldestIssue: undefined,\n newestIssue: undefined,\n resolvedCount: 0,\n historicalIssues: historical.totalHistoricalIssues,\n improvementTrend: historical.improvementTrend,\n capacityInfo: {\n current: index.length,\n max: MAX_ISSUES,\n percentFull: Math.round((index.length / MAX_ISSUES) * 100),\n isAtCap: index.length >= MAX_ISSUES,\n },\n deduplicationStats: {\n duplicatesAvoided: index.length - uniqueHashes.size,\n uniquePatterns: uniqueHashes.size,\n },\n };\n\n for (const issue of index) {\n stats.issuesByAgent[issue.agent] = (stats.issuesByAgent[issue.agent] || 0) + 1;\n stats.issuesBySeverity[issue.severity] = (stats.issuesBySeverity[issue.severity] || 0) + 1;\n \n if (issue.resolved) {\n stats.resolvedCount++;\n } else {\n stats.activeIssues++;\n stats.activeIssuesBySeverity[issue.severity] = (stats.activeIssuesBySeverity[issue.severity] || 0) + 1;\n }\n }\n\n if (index.length > 0) {\n const sorted = [...index].sort((a, b) => \n new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()\n );\n const oldest = sorted[0]?.timestamp;\n const newest = sorted[sorted.length - 1]?.timestamp;\n if (oldest !== undefined) {\n stats.oldestIssue = oldest;\n }\n if (newest !== undefined) {\n stats.newestIssue = newest;\n }\n }\n\n return stats;\n}\n\n/**\n * Get recent issues\n * @param options.includeResolved - If false (default), only returns unresolved issues\n */\nexport async function getRecentIssues(\n options: {\n workDir?: string;\n limit?: number;\n daysBack?: number;\n includeResolved?: boolean;\n } = {}\n): Promise<StoredIssue[]> {\n const projectDir = options.workDir || getWorkingDirectory(undefined, true);\n const index = await loadIssueIndex(projectDir);\n const limit = options.limit || 20;\n const daysBack = options.daysBack || 7;\n const includeResolved = options.includeResolved ?? false;\n \n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - daysBack);\n \n return index\n .filter(i => {\n if (new Date(i.timestamp) < cutoff) return false;\n if (!includeResolved && i.resolved) return false;\n return true;\n })\n .sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())\n .slice(0, limit);\n}\n\n/**\n * Purge issues from memory\n * Offers different strategies for managing memory capacity\n */\nexport async function purgeIssues(\n strategy: 'smart' | 'resolved' | 'old' | 'all',\n options: {\n workDir?: string;\n daysOld?: number;\n } = {}\n): Promise<{ removed: number; remaining: number; strategy: string }> {\n const projectDir = options.workDir || getWorkingDirectory(undefined, true);\n const index = await loadIssueIndex(projectDir);\n const originalCount = index.length;\n \n let remaining: StoredIssue[] = [];\n \n switch (strategy) {\n case 'smart':\n // Keep: critical/high severity, recent (< 30 days), unresolved\n const thirtyDaysAgo = new Date();\n thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);\n \n remaining = index.filter(i => {\n const isRecent = new Date(i.timestamp) >= thirtyDaysAgo;\n const isImportant = ['critical', 'high'].includes(i.severity);\n const isUnresolved = !i.resolved;\n \n return isRecent || isImportant || isUnresolved;\n });\n break;\n \n case 'resolved':\n // Remove all resolved issues\n remaining = index.filter(i => !i.resolved);\n break;\n \n case 'old':\n // Remove issues older than specified days (default 90)\n const daysOld = options.daysOld || 90;\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - daysOld);\n \n remaining = index.filter(i => new Date(i.timestamp) >= cutoffDate);\n break;\n \n case 'all':\n // Clear all issues (keeps compacted summaries)\n remaining = [];\n break;\n }\n \n await saveIssueIndex(remaining, projectDir);\n \n return {\n removed: originalCount - remaining.length,\n remaining: remaining.length,\n strategy,\n };\n}\n\n/**\n * Get daily log files\n */\nexport async function getDailyLogs(workDir?: string): Promise<string[]> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n \n try {\n if (!existsSync(memoryDir)) return [];\n const files = await readdir(memoryDir);\n return files\n .filter(f => /^\\d{4}-\\d{2}-\\d{2}\\.md$/.test(f))\n .sort()\n .reverse();\n } catch {\n return [];\n }\n}\n\n// Private helpers\n\nasync function appendToDailyLog(issues: StoredIssue[], projectDir: string): Promise<void> {\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n const today = new Date().toISOString().split('T')[0];\n const logPath = join(memoryDir, `${today}.md`);\n\n let content = '';\n \n try {\n if (existsSync(logPath)) {\n content = await readFile(logPath, 'utf-8');\n } else {\n content = `# Issue Log: ${today}\\n\\n`;\n }\n } catch {\n content = `# Issue Log: ${today}\\n\\n`;\n }\n\n const time = new Date().toTimeString().split(' ')[0];\n \n const newEntries = issues.map(i => \n `## [${time}] ${i.severity.toUpperCase()}: ${i.issue.slice(0, 80)}${i.issue.length > 80 ? '...' : ''}\\n` +\n `- **File:** \\`${i.file}\\`${i.line ? `:${i.line}` : ''}\\n` +\n `- **Agent:** ${i.agent}\\n` +\n `- **Fix:** ${i.fix.slice(0, 200)}${i.fix.length > 200 ? '...' : ''}\\n`\n ).join('\\n');\n\n content += newEntries + '\\n';\n \n await writeFile(logPath, content);\n}\n\n/**\n * Load issue index with validation and auto-recovery\n * \n * If the file is corrupted:\n * 1. Attempts to recover from the most recent valid backup\n * 2. Returns empty array if no valid backup exists\n */\nasync function loadIssueIndex(projectDir: string): Promise<StoredIssue[]> {\n const indexPath = join(getTrieDirectory(projectDir), 'memory', 'issues.json');\n \n try {\n if (existsSync(indexPath)) {\n const content = await readFile(indexPath, 'utf-8');\n const result = safeParseAndValidate(content, IssueIndexSchema);\n \n if (result.success) {\n return result.data as StoredIssue[];\n }\n \n // Validation failed - attempt recovery from backup\n console.error(` Issue index corrupted: ${result.error}`);\n const backupManager = new BackupManager(indexPath);\n \n if (await backupManager.recoverFromBackup()) {\n console.error(' ✅ Recovered from backup');\n const recovered = await readFile(indexPath, 'utf-8');\n const recoveredResult = safeParseAndValidate(recovered, IssueIndexSchema);\n if (recoveredResult.success) {\n return recoveredResult.data as StoredIssue[];\n }\n }\n \n console.error(' No valid backup found, starting fresh');\n }\n } catch {\n // Index doesn't exist or recovery failed\n }\n \n return [];\n}\n\nasync function updateIssueIndex(newIssues: StoredIssue[], projectDir: string): Promise<number> {\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n await mkdir(memoryDir, { recursive: true });\n \n let existing = await loadIssueIndex(projectDir);\n \n // Intelligent deduplication: only add truly unique issues\n // Issues are unique if they have different hash (content + file + severity + agent)\n const hashSet = new Set(existing.map(i => i.hash));\n const toAdd = newIssues.filter(i => !hashSet.has(i.hash));\n const dedupedCount = toAdd.length;\n \n existing = [...existing, ...toAdd];\n \n // Intelligent compaction: summarize old issues instead of deleting\n if (existing.length > 500) {\n const { summary, remaining } = await compactOldIssues(existing, {\n keepDays: 30,\n minIssuesToCompact: 100,\n });\n \n if (summary) {\n await saveCompactedSummary(summary, projectDir);\n existing = remaining;\n }\n }\n \n // Hard cap: prune to 10,000 if still too large\n // Prioritize: 1) Recent issues, 2) High severity, 3) Unresolved\n if (existing.length > 10000) {\n existing = intelligentPrune(existing, 10000);\n }\n \n await saveIssueIndex(existing, projectDir);\n return dedupedCount;\n}\n\n/**\n * Intelligently prune issues to target count\n * Prioritizes: recent, high severity, unresolved\n */\nfunction intelligentPrune(issues: StoredIssue[], targetCount: number): StoredIssue[] {\n const severityWeight: Record<string, number> = {\n critical: 100,\n high: 50,\n moderate: 20,\n low: 10,\n info: 5,\n };\n \n const scored = issues.map(issue => {\n const ageInDays = (Date.now() - new Date(issue.timestamp).getTime()) / (1000 * 60 * 60 * 24);\n const recencyScore = Math.max(0, 100 - ageInDays * 2); // Newer = higher score\n const severityScore = severityWeight[issue.severity] || 10;\n const resolvedPenalty = issue.resolved ? -50 : 0;\n \n return {\n issue,\n score: recencyScore + severityScore + resolvedPenalty,\n };\n });\n \n return scored\n .sort((a, b) => b.score - a.score)\n .slice(0, targetCount)\n .map(s => s.issue);\n}\n\n/**\n * Save issue index with backup and atomic write\n * \n * 1. Creates a backup of the existing file\n * 2. Writes the new data atomically (temp file + rename)\n * 3. Maintains up to 5 rotational backups\n */\nasync function saveIssueIndex(issues: StoredIssue[], projectDir: string): Promise<void> {\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n await mkdir(memoryDir, { recursive: true });\n \n const indexPath = join(memoryDir, 'issues.json');\n \n // Create backup before writing\n const backupManager = new BackupManager(indexPath);\n await backupManager.createBackup();\n \n // Atomic write\n await atomicWriteJSON(indexPath, issues);\n}\n\n/**\n * Hash an issue using SHA256 for proper deduplication\n * \n * Uses cryptographic hashing to eliminate collision risk.\n * The hash is truncated to 16 characters for storage efficiency\n * while still providing effectively zero collision probability.\n */\nfunction hashIssue(issue: Issue): string {\n const content = `${issue.issue}|${issue.file}|${issue.severity}|${issue.agent}`;\n return createHash('sha256').update(content).digest('hex').slice(0, 16);\n}\n\n","/**\n * BM25 Search Implementation\n * \n * BM25 (Best Match 25) is a ranking function used by search engines.\n * It's more sophisticated than TF-IDF and handles term frequency saturation.\n * \n * This is the same algorithm used by Elasticsearch.\n */\n\nexport interface BM25Document {\n id: string;\n text: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface BM25Result {\n id: string;\n score: number;\n metadata?: Record<string, unknown>;\n}\n\nexport class BM25Index {\n private documents: Map<string, BM25Document> = new Map();\n private termFrequencies: Map<string, Map<string, number>> = new Map();\n private documentFrequencies: Map<string, number> = new Map();\n private documentLengths: Map<string, number> = new Map();\n private avgDocLength: number = 0;\n private k1: number = 1.5;\n private b: number = 0.75;\n\n /**\n * Add a document to the index\n */\n addDocument(doc: BM25Document): void {\n const tokens = this.tokenize(doc.text);\n this.documents.set(doc.id, doc);\n this.documentLengths.set(doc.id, tokens.length);\n\n const termFreq = new Map<string, number>();\n const seenTerms = new Set<string>();\n\n for (const token of tokens) {\n termFreq.set(token, (termFreq.get(token) || 0) + 1);\n \n if (!seenTerms.has(token)) {\n seenTerms.add(token);\n this.documentFrequencies.set(token, (this.documentFrequencies.get(token) || 0) + 1);\n }\n }\n\n this.termFrequencies.set(doc.id, termFreq);\n this.updateAvgDocLength();\n }\n\n /**\n * Add multiple documents\n */\n addDocuments(docs: BM25Document[]): void {\n for (const doc of docs) {\n this.addDocument(doc);\n }\n }\n\n /**\n * Search the index\n */\n search(query: string, limit: number = 10): BM25Result[] {\n const queryTokens = this.tokenize(query);\n const scores: Map<string, number> = new Map();\n const N = this.documents.size;\n\n for (const [docId] of this.documents) {\n let score = 0;\n const docLength = this.documentLengths.get(docId) || 0;\n const termFreqs = this.termFrequencies.get(docId);\n\n if (!termFreqs) continue;\n\n for (const term of queryTokens) {\n const tf = termFreqs.get(term) || 0;\n if (tf === 0) continue;\n\n const df = this.documentFrequencies.get(term) || 0;\n const idf = Math.log((N - df + 0.5) / (df + 0.5) + 1);\n\n const numerator = tf * (this.k1 + 1);\n const denominator = tf + this.k1 * (1 - this.b + this.b * (docLength / this.avgDocLength));\n \n score += idf * (numerator / denominator);\n }\n\n if (score > 0) {\n scores.set(docId, score);\n }\n }\n\n return Array.from(scores.entries())\n .sort((a, b) => b[1] - a[1])\n .slice(0, limit)\n .map(([id, score]) => {\n const metadata = this.documents.get(id)?.metadata;\n const result: BM25Result = { id, score };\n if (metadata !== undefined) {\n result.metadata = metadata;\n }\n return result;\n });\n }\n\n /**\n * Get document count\n */\n get size(): number {\n return this.documents.size;\n }\n\n /**\n * Clear the index\n */\n clear(): void {\n this.documents.clear();\n this.termFrequencies.clear();\n this.documentFrequencies.clear();\n this.documentLengths.clear();\n this.avgDocLength = 0;\n }\n\n /**\n * Serialize the index to JSON\n */\n serialize(): string {\n return JSON.stringify({\n documents: Array.from(this.documents.entries()),\n termFrequencies: Array.from(this.termFrequencies.entries()).map(([k, v]) => [k, Array.from(v.entries())]),\n documentFrequencies: Array.from(this.documentFrequencies.entries()),\n documentLengths: Array.from(this.documentLengths.entries()),\n avgDocLength: this.avgDocLength,\n });\n }\n\n /**\n * Load from serialized JSON\n */\n static deserialize(json: string): BM25Index {\n const data = JSON.parse(json);\n const index = new BM25Index();\n \n index.documents = new Map(data.documents);\n index.termFrequencies = new Map(data.termFrequencies.map(([k, v]: [string, [string, number][]]) => [k, new Map(v)]));\n index.documentFrequencies = new Map(data.documentFrequencies);\n index.documentLengths = new Map(data.documentLengths);\n index.avgDocLength = data.avgDocLength;\n \n return index;\n }\n\n private tokenize(text: string): string[] {\n return text\n .toLowerCase()\n .replace(/[^\\w\\s]/g, ' ')\n .split(/\\s+/)\n .filter(token => token.length > 2 && !this.isStopWord(token));\n }\n\n private isStopWord(word: string): boolean {\n const stopWords = new Set([\n 'the', 'be', 'to', 'of', 'and', 'a', 'in', 'that', 'have', 'i',\n 'it', 'for', 'not', 'on', 'with', 'he', 'as', 'you', 'do', 'at',\n 'this', 'but', 'his', 'by', 'from', 'they', 'we', 'say', 'her', 'she',\n 'or', 'an', 'will', 'my', 'one', 'all', 'would', 'there', 'their', 'what',\n 'so', 'up', 'out', 'if', 'about', 'who', 'get', 'which', 'go', 'me',\n 'when', 'make', 'can', 'like', 'time', 'no', 'just', 'him', 'know', 'take',\n 'into', 'year', 'your', 'some', 'could', 'them', 'see', 'other', 'than', 'then',\n 'now', 'look', 'only', 'come', 'its', 'over', 'also', 'back', 'after', 'use',\n 'two', 'how', 'our', 'first', 'way', 'even', 'new', 'want', 'because', 'any',\n 'these', 'give', 'day', 'most', 'us', 'should', 'been', 'has', 'was', 'are',\n ]);\n return stopWords.has(word);\n }\n\n private updateAvgDocLength(): void {\n if (this.documentLengths.size === 0) {\n this.avgDocLength = 0;\n return;\n }\n const total = Array.from(this.documentLengths.values()).reduce((a, b) => a + b, 0);\n this.avgDocLength = total / this.documentLengths.size;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAYA,SAAS,OAAO,gBAAgB;AAChC,SAAS,kBAAkB;AAC3B,SAAS,YAAY;AAgCrB,eAAsB,iBACpB,QACA,UAGI,CAAC,GACoE;AACzE,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,YAAY,QAAQ,sBAAsB;AAEhD,QAAM,aAAa,oBAAI,KAAK;AAC5B,aAAW,QAAQ,WAAW,QAAQ,IAAI,QAAQ;AAElD,QAAM,YAAY,OAAO,OAAO,OAAK,IAAI,KAAK,EAAE,SAAS,IAAI,UAAU;AACvE,QAAM,eAAe,OAAO,OAAO,OAAK,IAAI,KAAK,EAAE,SAAS,KAAK,UAAU;AAG3E,MAAI,UAAU,SAAS,WAAW;AAChC,WAAO,EAAE,SAAS,MAAM,WAAW,OAAO;AAAA,EAC5C;AAGA,QAAM,UAAU,aAAa,SAAS;AAEtC,SAAO,EAAE,SAAS,WAAW,aAAa;AAC5C;AAKA,SAAS,aAAa,QAAyC;AAC7D,QAAM,SAAS,OAAO;AAAA,IAAK,CAAC,GAAG,MAC7B,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ;AAAA,EAClE;AAEA,QAAM,aAAqC,CAAC;AAC5C,QAAM,UAAkC,CAAC;AACzC,QAAM,aAAiE,oBAAI,IAAI;AAC/E,QAAM,YAAiC,oBAAI,IAAI;AAE/C,aAAW,SAAS,QAAQ;AAE1B,eAAW,MAAM,QAAQ,KAAK,WAAW,MAAM,QAAQ,KAAK,KAAK;AAGjE,YAAQ,MAAM,KAAK,KAAK,QAAQ,MAAM,KAAK,KAAK,KAAK;AAGrD,UAAM,aAAa,iBAAiB,MAAM,KAAK;AAC/C,UAAM,WAAW,WAAW,IAAI,UAAU;AAC1C,QAAI,UAAU;AACZ,eAAS;AAAA,IACX,OAAO;AACL,iBAAW,IAAI,YAAY,EAAE,OAAO,GAAG,MAAM,CAAC;AAAA,IAChD;AAGA,UAAM,WAAW,MAAM,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK,MAAM;AACtD,cAAU,IAAI,WAAW,UAAU,IAAI,QAAQ,KAAK,KAAK,CAAC;AAAA,EAC5D;AAGA,QAAM,cAAc,MAAM,KAAK,WAAW,QAAQ,CAAC,EAChD,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EACtC,MAAM,GAAG,EAAE,EACX,IAAI,CAAC,CAAC,SAAS,IAAI,OAAO;AAAA,IACzB,SAAS,QAAQ,MAAM,GAAG,GAAG;AAAA,IAC7B,OAAO,KAAK;AAAA,IACZ,UAAU,KAAK,MAAM;AAAA,IACrB,OAAO,KAAK,MAAM;AAAA,IAClB,YAAY,KAAK,MAAM,IAAI,MAAM,GAAG,GAAG;AAAA,EACzC,EAAE;AAGJ,QAAM,WAAW,MAAM,KAAK,UAAU,QAAQ,CAAC,EAC5C,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EAC1B,MAAM,GAAG,EAAE,EACX,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,EAAE,MAAM,MAAM,EAAE;AAE3C,SAAO;AAAA,IACL,QAAQ,GAAG,OAAO,CAAC,GAAG,UAAU,MAAM,GAAG,EAAE,CAAC,CAAC,OAAO,OAAO,OAAO,SAAS,CAAC,GAAG,UAAU,MAAM,GAAG,EAAE,CAAC,CAAC;AAAA,IACtG,WAAW,OAAO,CAAC,GAAG,aAAa;AAAA,IACnC,SAAS,OAAO,OAAO,SAAS,CAAC,GAAG,aAAa;AAAA,IACjD,aAAa,OAAO;AAAA,IACpB,eAAe,OAAO,OAAO,OAAK,EAAE,QAAQ,EAAE;AAAA,IAC9C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,EACtC;AACF;AAKA,SAAS,iBAAiB,MAAsB;AAC9C,SAAO,KACJ,YAAY,EACZ,QAAQ,YAAY,MAAM,EAC1B,QAAQ,YAAY,GAAG,EACvB,QAAQ,SAAS,EAAE,EACnB,QAAQ,QAAQ,GAAG,EACnB,KAAK,EACL,MAAM,GAAG,GAAG;AACjB;AAKA,eAAsB,qBACpB,SACA,YACe;AACf,QAAM,YAAY,KAAK,iBAAiB,UAAU,GAAG,QAAQ;AAC7D,QAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAE1C,QAAM,cAAc,KAAK,WAAW,0BAA0B;AAE9D,MAAI,YAAgC,CAAC;AACrC,MAAI;AACF,QAAI,WAAW,WAAW,GAAG;AAC3B,YAAM,UAAU,MAAM,SAAS,aAAa,OAAO;AACnD,YAAM,SAAS,qBAAqB,SAAS,6BAA6B;AAC1E,UAAI,OAAO,SAAS;AAClB,oBAAY,OAAO;AAAA,MACrB;AAAA,IACF;AAAA,EACF,QAAQ;AACN,gBAAY,CAAC;AAAA,EACf;AAEA,YAAU,KAAK,OAAO;AAGtB,MAAI,UAAU,SAAS,IAAI;AACzB,gBAAY,UAAU,MAAM,GAAG;AAAA,EACjC;AAGA,QAAM,gBAAgB,IAAI,cAAc,WAAW;AACnD,QAAM,cAAc,aAAa;AAGjC,QAAM,gBAAgB,aAAa,SAAS;AAC9C;AAKA,eAAsB,uBAAuB,YAAiD;AAC5F,QAAM,cAAc,KAAK,iBAAiB,UAAU,GAAG,UAAU,0BAA0B;AAE3F,MAAI;AACF,QAAI,WAAW,WAAW,GAAG;AAC3B,YAAM,UAAU,MAAM,SAAS,aAAa,OAAO;AACnD,YAAM,SAAS,qBAAqB,SAAS,6BAA6B;AAE1E,UAAI,OAAO,SAAS;AAClB,eAAO,OAAO;AAAA,MAChB;AAGA,YAAM,gBAAgB,IAAI,cAAc,WAAW;AACnD,UAAI,MAAM,cAAc,kBAAkB,GAAG;AAC3C,cAAM,YAAY,MAAM,SAAS,aAAa,OAAO;AACrD,cAAM,kBAAkB,qBAAqB,WAAW,6BAA6B;AACrF,YAAI,gBAAgB,SAAS;AAC3B,iBAAO,gBAAgB;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,SAAO,CAAC;AACV;AA6BA,eAAsB,sBAAsB,YAIzC;AACD,QAAM,YAAY,MAAM,uBAAuB,UAAU;AAEzD,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO;AAAA,MACL,uBAAuB;AAAA,MACvB,mBAAmB,CAAC;AAAA,MACpB,kBAAkB;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,wBAAwB,UAAU,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,aAAa,CAAC;AAGjF,QAAM,gBAAuE,oBAAI,IAAI;AAErF,aAAW,WAAW,WAAW;AAC/B,eAAW,WAAW,QAAQ,aAAa;AACzC,YAAM,MAAM,QAAQ;AACpB,YAAM,WAAW,cAAc,IAAI,GAAG;AACtC,UAAI,UAAU;AACZ,iBAAS,SAAS,QAAQ;AAC1B,iBAAS;AAAA,MACX,OAAO;AACL,sBAAc,IAAI,KAAK,EAAE,GAAG,SAAS,aAAa,EAAE,CAAC;AAAA,MACvD;AAAA,IACF;AAAA,EACF;AAEA,QAAM,oBAAoB,MAAM,KAAK,cAAc,OAAO,CAAC,EACxD,OAAO,OAAK,EAAE,eAAe,CAAC,EAC9B,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAChC,MAAM,GAAG,CAAC;AAGb,MAAI,mBAAqE;AAEzE,MAAI,UAAU,UAAU,GAAG;AACzB,UAAM,SAAS,UAAU,MAAM,EAAE;AACjC,UAAM,aAAa,OAAO,CAAC,GAAG,eAAe;AAC7C,UAAM,aAAa,OAAO,CAAC,GAAG,eAAe;AAE7C,QAAI,aAAa,aAAa,KAAK;AACjC,yBAAmB;AAAA,IACrB,WAAW,aAAa,aAAa,KAAK;AACxC,yBAAmB;AAAA,IACrB,OAAO;AACL,yBAAmB;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC1SA,SAAS,SAAAA,QAAO,WAAW,YAAAC,WAAU,eAAe;AACpD,SAAS,kBAAkB;AAC3B,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,QAAAC,aAAY;;;ACId,IAAM,YAAN,MAAM,WAAU;AAAA,EACb,YAAuC,oBAAI,IAAI;AAAA,EAC/C,kBAAoD,oBAAI,IAAI;AAAA,EAC5D,sBAA2C,oBAAI,IAAI;AAAA,EACnD,kBAAuC,oBAAI,IAAI;AAAA,EAC/C,eAAuB;AAAA,EACvB,KAAa;AAAA,EACb,IAAY;AAAA;AAAA;AAAA;AAAA,EAKpB,YAAY,KAAyB;AACnC,UAAM,SAAS,KAAK,SAAS,IAAI,IAAI;AACrC,SAAK,UAAU,IAAI,IAAI,IAAI,GAAG;AAC9B,SAAK,gBAAgB,IAAI,IAAI,IAAI,OAAO,MAAM;AAE9C,UAAM,WAAW,oBAAI,IAAoB;AACzC,UAAM,YAAY,oBAAI,IAAY;AAElC,eAAW,SAAS,QAAQ;AAC1B,eAAS,IAAI,QAAQ,SAAS,IAAI,KAAK,KAAK,KAAK,CAAC;AAElD,UAAI,CAAC,UAAU,IAAI,KAAK,GAAG;AACzB,kBAAU,IAAI,KAAK;AACnB,aAAK,oBAAoB,IAAI,QAAQ,KAAK,oBAAoB,IAAI,KAAK,KAAK,KAAK,CAAC;AAAA,MACpF;AAAA,IACF;AAEA,SAAK,gBAAgB,IAAI,IAAI,IAAI,QAAQ;AACzC,SAAK,mBAAmB;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,MAA4B;AACvC,eAAW,OAAO,MAAM;AACtB,WAAK,YAAY,GAAG;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,OAAe,QAAgB,IAAkB;AACtD,UAAM,cAAc,KAAK,SAAS,KAAK;AACvC,UAAM,SAA8B,oBAAI,IAAI;AAC5C,UAAM,IAAI,KAAK,UAAU;AAEzB,eAAW,CAAC,KAAK,KAAK,KAAK,WAAW;AACpC,UAAI,QAAQ;AACZ,YAAM,YAAY,KAAK,gBAAgB,IAAI,KAAK,KAAK;AACrD,YAAM,YAAY,KAAK,gBAAgB,IAAI,KAAK;AAEhD,UAAI,CAAC,UAAW;AAEhB,iBAAW,QAAQ,aAAa;AAC9B,cAAM,KAAK,UAAU,IAAI,IAAI,KAAK;AAClC,YAAI,OAAO,EAAG;AAEd,cAAM,KAAK,KAAK,oBAAoB,IAAI,IAAI,KAAK;AACjD,cAAM,MAAM,KAAK,KAAK,IAAI,KAAK,QAAQ,KAAK,OAAO,CAAC;AAEpD,cAAM,YAAY,MAAM,KAAK,KAAK;AAClC,cAAM,cAAc,KAAK,KAAK,MAAM,IAAI,KAAK,IAAI,KAAK,KAAK,YAAY,KAAK;AAE5E,iBAAS,OAAO,YAAY;AAAA,MAC9B;AAEA,UAAI,QAAQ,GAAG;AACb,eAAO,IAAI,OAAO,KAAK;AAAA,MACzB;AAAA,IACF;AAEA,WAAO,MAAM,KAAK,OAAO,QAAQ,CAAC,EAC/B,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EAC1B,MAAM,GAAG,KAAK,EACd,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;AACpB,YAAM,WAAW,KAAK,UAAU,IAAI,EAAE,GAAG;AACzC,YAAM,SAAqB,EAAE,IAAI,MAAM;AACvC,UAAI,aAAa,QAAW;AAC1B,eAAO,WAAW;AAAA,MACpB;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,UAAU,MAAM;AACrB,SAAK,gBAAgB,MAAM;AAC3B,SAAK,oBAAoB,MAAM;AAC/B,SAAK,gBAAgB,MAAM;AAC3B,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,YAAoB;AAClB,WAAO,KAAK,UAAU;AAAA,MACpB,WAAW,MAAM,KAAK,KAAK,UAAU,QAAQ,CAAC;AAAA,MAC9C,iBAAiB,MAAM,KAAK,KAAK,gBAAgB,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;AAAA,MACxG,qBAAqB,MAAM,KAAK,KAAK,oBAAoB,QAAQ,CAAC;AAAA,MAClE,iBAAiB,MAAM,KAAK,KAAK,gBAAgB,QAAQ,CAAC;AAAA,MAC1D,cAAc,KAAK;AAAA,IACrB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,YAAY,MAAyB;AAC1C,UAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,UAAM,QAAQ,IAAI,WAAU;AAE5B,UAAM,YAAY,IAAI,IAAI,KAAK,SAAS;AACxC,UAAM,kBAAkB,IAAI,IAAI,KAAK,gBAAgB,IAAI,CAAC,CAAC,GAAG,CAAC,MAAoC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;AACnH,UAAM,sBAAsB,IAAI,IAAI,KAAK,mBAAmB;AAC5D,UAAM,kBAAkB,IAAI,IAAI,KAAK,eAAe;AACpD,UAAM,eAAe,KAAK;AAE1B,WAAO;AAAA,EACT;AAAA,EAEQ,SAAS,MAAwB;AACvC,WAAO,KACJ,YAAY,EACZ,QAAQ,YAAY,GAAG,EACvB,MAAM,KAAK,EACX,OAAO,WAAS,MAAM,SAAS,KAAK,CAAC,KAAK,WAAW,KAAK,CAAC;AAAA,EAChE;AAAA,EAEQ,WAAW,MAAuB;AACxC,UAAM,YAAY,oBAAI,IAAI;AAAA,MACxB;AAAA,MAAO;AAAA,MAAM;AAAA,MAAM;AAAA,MAAM;AAAA,MAAO;AAAA,MAAK;AAAA,MAAM;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAC3D;AAAA,MAAM;AAAA,MAAO;AAAA,MAAO;AAAA,MAAM;AAAA,MAAQ;AAAA,MAAM;AAAA,MAAM;AAAA,MAAO;AAAA,MAAM;AAAA,MAC3D;AAAA,MAAQ;AAAA,MAAO;AAAA,MAAO;AAAA,MAAM;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAM;AAAA,MAAO;AAAA,MAAO;AAAA,MAChE;AAAA,MAAM;AAAA,MAAM;AAAA,MAAQ;AAAA,MAAM;AAAA,MAAO;AAAA,MAAO;AAAA,MAAS;AAAA,MAAS;AAAA,MAAS;AAAA,MACnE;AAAA,MAAM;AAAA,MAAM;AAAA,MAAO;AAAA,MAAM;AAAA,MAAS;AAAA,MAAO;AAAA,MAAO;AAAA,MAAS;AAAA,MAAM;AAAA,MAC/D;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAO;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAM;AAAA,MAAQ;AAAA,MAAO;AAAA,MAAQ;AAAA,MACpE;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAS;AAAA,MAAQ;AAAA,MAAO;AAAA,MAAS;AAAA,MAAQ;AAAA,MACzE;AAAA,MAAO;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAO;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAS;AAAA,MACvE;AAAA,MAAO;AAAA,MAAO;AAAA,MAAO;AAAA,MAAS;AAAA,MAAO;AAAA,MAAQ;AAAA,MAAO;AAAA,MAAQ;AAAA,MAAW;AAAA,MACvE;AAAA,MAAS;AAAA,MAAQ;AAAA,MAAO;AAAA,MAAQ;AAAA,MAAM;AAAA,MAAU;AAAA,MAAQ;AAAA,MAAO;AAAA,MAAO;AAAA,IACxE,CAAC;AACD,WAAO,UAAU,IAAI,IAAI;AAAA,EAC3B;AAAA,EAEQ,qBAA2B;AACjC,QAAI,KAAK,gBAAgB,SAAS,GAAG;AACnC,WAAK,eAAe;AACpB;AAAA,IACF;AACA,UAAM,QAAQ,MAAM,KAAK,KAAK,gBAAgB,OAAO,CAAC,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AACjF,SAAK,eAAe,QAAQ,KAAK,gBAAgB;AAAA,EACnD;AACF;;;ADhHA,eAAsB,YACpB,QACA,SACA,SACiD;AACjD,QAAM,aAAa,WAAW,oBAAoB,QAAW,IAAI;AACjE,QAAM,YAAYC,MAAK,iBAAiB,UAAU,GAAG,QAAQ;AAC7D,QAAMC,OAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAE1C,QAAM,SAAwB,CAAC;AAC/B,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,QAAM,aAAa,oBAAI,IAAY;AACnC,MAAI,aAAa;AAEjB,aAAW,SAAS,QAAQ;AAC1B,UAAM,OAAO,UAAU,KAAK;AAG5B,QAAI,WAAW,IAAI,IAAI,GAAG;AACxB;AACA;AAAA,IACF;AACA,eAAW,IAAI,IAAI;AAEnB,UAAM,cAA2B;AAAA,MAC/B,IAAI,MAAM;AAAA,MACV;AAAA,MACA,UAAU,MAAM;AAAA,MAChB,OAAO,MAAM;AAAA,MACb,KAAK,MAAM;AAAA,MACX,MAAM,MAAM;AAAA,MACZ,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM;AAAA,MACb,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,MACX;AAAA,MACA,UAAU;AAAA,MACV,YAAY;AAAA,IACd;AACA,WAAO,KAAK,WAAW;AAAA,EACzB;AAEA,QAAM,iBAAiB,QAAQ,UAAU;AACzC,QAAM,qBAAqB,QAAQ,UAAU;AAC7C,QAAM,eAAe,MAAM,iBAAiB,QAAQ,UAAU;AAE9D,SAAO,EAAE,QAAQ,cAAc,YAAY,cAAc,OAAO,SAAS,cAAc;AACzF;AAKA,eAAsB,aACpB,OACA,UAOI,CAAC,GACyB;AAC9B,QAAM,aAAa,QAAQ,WAAW,oBAAoB,QAAW,IAAI;AACzE,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,YAAY,MAAM,eAAe,UAAU;AAEjD,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO,CAAC;AAAA,EACV;AAGA,QAAM,iBAAiB,UAAU,OAAO,WAAS;AAC/C,QAAI,QAAQ,WAAW,MAAM,YAAY,QAAQ,QAAS,QAAO;AACjE,QAAI,QAAQ,YAAY,CAAC,QAAQ,SAAS,SAAS,MAAM,QAAQ,EAAG,QAAO;AAC3E,QAAI,QAAQ,SAAS,MAAM,UAAU,QAAQ,MAAO,QAAO;AAC3D,QAAI,CAAC,QAAQ,mBAAmB,MAAM,SAAU,QAAO;AACvD,WAAO;AAAA,EACT,CAAC;AAED,MAAI,eAAe,WAAW,GAAG;AAC/B,WAAO,CAAC;AAAA,EACV;AAGA,QAAM,OAAO,IAAI,UAAU;AAC3B,QAAM,WAAW,oBAAI,IAAyB;AAE9C,aAAW,SAAS,gBAAgB;AAClC,UAAM,aAAa,GAAG,MAAM,KAAK,IAAI,MAAM,GAAG,IAAI,MAAM,IAAI,IAAI,MAAM,KAAK,IAAI,MAAM,YAAY,EAAE,IAAI,MAAM,QAAQ;AACrH,SAAK,YAAY;AAAA,MACf,IAAI,MAAM;AAAA,MACV,MAAM;AAAA,IACR,CAAC;AACD,aAAS,IAAI,MAAM,IAAI,KAAK;AAAA,EAC9B;AAGA,QAAM,cAAc,KAAK,OAAO,OAAO,KAAK;AAE5C,SAAO,YAAY,IAAI,aAAW;AAAA,IAChC,OAAO,SAAS,IAAI,OAAO,EAAE;AAAA,IAC7B,OAAO,OAAO;AAAA,IACd,WAAW;AAAA,EACb,EAAE;AACJ;AAKA,eAAsB,kBACpB,OACA,UAII,CAAC,GACyB;AAE9B,QAAM,QAAQ,GAAG,MAAM,KAAK,IAAI,MAAM,GAAG,IAAI,MAAM,KAAK;AACxD,QAAM,gBAAoD;AAAA,IACxD,QAAQ,QAAQ,SAAS,KAAK;AAAA;AAAA,IAC9B,iBAAiB;AAAA,EACnB;AACA,MAAI,QAAQ,YAAY,QAAW;AACjC,kBAAc,UAAU,QAAQ;AAAA,EAClC;AACA,QAAM,UAAU,MAAM,aAAa,OAAO,aAAa;AAEvD,MAAI,WAAW,QAAQ,OAAO,OAAK,EAAE,MAAM,OAAO,MAAM,EAAE;AAE1D,MAAI,QAAQ,iBAAiB;AAC3B,eAAW,SAAS,OAAO,OAAK,EAAE,MAAM,SAAS,MAAM,IAAI;AAAA,EAC7D;AAEA,SAAO,SAAS,MAAM,GAAG,QAAQ,SAAS,CAAC;AAC7C;AAKA,eAAsB,kBACpB,SACA,SACkB;AAClB,QAAM,aAAa,WAAW,oBAAoB,QAAW,IAAI;AACjE,QAAM,QAAQ,MAAM,eAAe,UAAU;AAE7C,QAAM,QAAQ,MAAM,KAAK,OAAK,EAAE,OAAO,OAAO;AAC9C,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,WAAW;AACjB,QAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAE1C,QAAM,eAAe,OAAO,UAAU;AACtC,SAAO;AACT;AAcA,eAAsB,kBACpB,gBACA,cACA,SACoD;AACpD,QAAM,aAAa,WAAW,oBAAoB,QAAW,IAAI;AACjE,QAAM,QAAQ,MAAM,eAAe,UAAU;AAG7C,QAAM,iBAAiB,IAAI,IAAI,aAAa,IAAI,OAAK,EAAE,QAAQ,OAAO,GAAG,CAAC,CAAC;AAE3E,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,MAAI,gBAAgB;AACpB,MAAI,mBAAmB;AAEvB,aAAW,SAAS,OAAO;AAEzB,QAAI,MAAM,SAAU;AAGpB,UAAM,iBAAiB,MAAM,KAAK,QAAQ,OAAO,GAAG;AAIpD,QAAI,CAAC,eAAe,IAAI,cAAc,GAAG;AACvC;AACA;AAAA,IACF;AAGA,QAAI,CAAC,eAAe,IAAI,MAAM,IAAI,GAAG;AACnC,YAAM,WAAW;AACjB,YAAM,aAAa;AACnB;AAAA,IACF,OAAO;AACL;AAAA,IACF;AAAA,EACF;AAGA,MAAI,gBAAgB,GAAG;AACrB,UAAM,eAAe,OAAO,UAAU;AAAA,EACxC;AAEA,SAAO,EAAE,UAAU,eAAe,aAAa,iBAAiB;AAClE;AAKO,SAAS,aAAa,OAAsB;AACjD,SAAO,UAAU,KAAK;AACxB;AAKA,eAAsB,eAAe,SAA6C;AAChF,QAAM,aAAa,WAAW,oBAAoB,QAAW,IAAI;AACjE,QAAM,QAAQ,MAAM,eAAe,UAAU;AAC7C,QAAM,aAAa,MAAM,sBAAsB,UAAU;AAEzD,QAAM,aAAa;AACnB,QAAM,eAAe,IAAI,IAAI,MAAM,IAAI,OAAK,EAAE,IAAI,CAAC;AAEnD,QAAM,QAA0B;AAAA,IAC9B,aAAa,MAAM;AAAA,IACnB,cAAc;AAAA,IACd,eAAe,CAAC;AAAA,IAChB,kBAAkB,CAAC;AAAA,IACnB,wBAAwB,CAAC;AAAA,IACzB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,eAAe;AAAA,IACf,kBAAkB,WAAW;AAAA,IAC7B,kBAAkB,WAAW;AAAA,IAC7B,cAAc;AAAA,MACZ,SAAS,MAAM;AAAA,MACf,KAAK;AAAA,MACL,aAAa,KAAK,MAAO,MAAM,SAAS,aAAc,GAAG;AAAA,MACzD,SAAS,MAAM,UAAU;AAAA,IAC3B;AAAA,IACA,oBAAoB;AAAA,MAClB,mBAAmB,MAAM,SAAS,aAAa;AAAA,MAC/C,gBAAgB,aAAa;AAAA,IAC/B;AAAA,EACF;AAEA,aAAW,SAAS,OAAO;AACzB,UAAM,cAAc,MAAM,KAAK,KAAK,MAAM,cAAc,MAAM,KAAK,KAAK,KAAK;AAC7E,UAAM,iBAAiB,MAAM,QAAQ,KAAK,MAAM,iBAAiB,MAAM,QAAQ,KAAK,KAAK;AAEzF,QAAI,MAAM,UAAU;AAClB,YAAM;AAAA,IACR,OAAO;AACL,YAAM;AACN,YAAM,uBAAuB,MAAM,QAAQ,KAAK,MAAM,uBAAuB,MAAM,QAAQ,KAAK,KAAK;AAAA,IACvG;AAAA,EACF;AAEA,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,SAAS,CAAC,GAAG,KAAK,EAAE;AAAA,MAAK,CAAC,GAAG,MACjC,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ;AAAA,IAClE;AACA,UAAM,SAAS,OAAO,CAAC,GAAG;AAC1B,UAAM,SAAS,OAAO,OAAO,SAAS,CAAC,GAAG;AAC1C,QAAI,WAAW,QAAW;AACxB,YAAM,cAAc;AAAA,IACtB;AACA,QAAI,WAAW,QAAW;AACxB,YAAM,cAAc;AAAA,IACtB;AAAA,EACF;AAEA,SAAO;AACT;AAMA,eAAsB,gBACpB,UAKI,CAAC,GACmB;AACxB,QAAM,aAAa,QAAQ,WAAW,oBAAoB,QAAW,IAAI;AACzE,QAAM,QAAQ,MAAM,eAAe,UAAU;AAC7C,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,kBAAkB,QAAQ,mBAAmB;AAEnD,QAAM,SAAS,oBAAI,KAAK;AACxB,SAAO,QAAQ,OAAO,QAAQ,IAAI,QAAQ;AAE1C,SAAO,MACJ,OAAO,OAAK;AACX,QAAI,IAAI,KAAK,EAAE,SAAS,IAAI,OAAQ,QAAO;AAC3C,QAAI,CAAC,mBAAmB,EAAE,SAAU,QAAO;AAC3C,WAAO;AAAA,EACT,CAAC,EACA,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAChF,MAAM,GAAG,KAAK;AACnB;AAMA,eAAsB,YACpB,UACA,UAGI,CAAC,GAC8D;AACnE,QAAM,aAAa,QAAQ,WAAW,oBAAoB,QAAW,IAAI;AACzE,QAAM,QAAQ,MAAM,eAAe,UAAU;AAC7C,QAAM,gBAAgB,MAAM;AAE5B,MAAI,YAA2B,CAAC;AAEhC,UAAQ,UAAU;AAAA,IAChB,KAAK;AAEH,YAAM,gBAAgB,oBAAI,KAAK;AAC/B,oBAAc,QAAQ,cAAc,QAAQ,IAAI,EAAE;AAElD,kBAAY,MAAM,OAAO,OAAK;AAC5B,cAAM,WAAW,IAAI,KAAK,EAAE,SAAS,KAAK;AAC1C,cAAM,cAAc,CAAC,YAAY,MAAM,EAAE,SAAS,EAAE,QAAQ;AAC5D,cAAM,eAAe,CAAC,EAAE;AAExB,eAAO,YAAY,eAAe;AAAA,MACpC,CAAC;AACD;AAAA,IAEF,KAAK;AAEH,kBAAY,MAAM,OAAO,OAAK,CAAC,EAAE,QAAQ;AACzC;AAAA,IAEF,KAAK;AAEH,YAAM,UAAU,QAAQ,WAAW;AACnC,YAAM,aAAa,oBAAI,KAAK;AAC5B,iBAAW,QAAQ,WAAW,QAAQ,IAAI,OAAO;AAEjD,kBAAY,MAAM,OAAO,OAAK,IAAI,KAAK,EAAE,SAAS,KAAK,UAAU;AACjE;AAAA,IAEF,KAAK;AAEH,kBAAY,CAAC;AACb;AAAA,EACJ;AAEA,QAAM,eAAe,WAAW,UAAU;AAE1C,SAAO;AAAA,IACL,SAAS,gBAAgB,UAAU;AAAA,IACnC,WAAW,UAAU;AAAA,IACrB;AAAA,EACF;AACF;AAKA,eAAsB,aAAa,SAAqC;AACtE,QAAM,aAAa,WAAW,oBAAoB,QAAW,IAAI;AACjE,QAAM,YAAYD,MAAK,iBAAiB,UAAU,GAAG,QAAQ;AAE7D,MAAI;AACF,QAAI,CAACE,YAAW,SAAS,EAAG,QAAO,CAAC;AACpC,UAAM,QAAQ,MAAM,QAAQ,SAAS;AACrC,WAAO,MACJ,OAAO,OAAK,0BAA0B,KAAK,CAAC,CAAC,EAC7C,KAAK,EACL,QAAQ;AAAA,EACb,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAIA,eAAe,iBAAiB,QAAuB,YAAmC;AACxF,QAAM,YAAYF,MAAK,iBAAiB,UAAU,GAAG,QAAQ;AAC7D,QAAM,SAAQ,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AACnD,QAAM,UAAUA,MAAK,WAAW,GAAG,KAAK,KAAK;AAE7C,MAAI,UAAU;AAEd,MAAI;AACF,QAAIE,YAAW,OAAO,GAAG;AACvB,gBAAU,MAAMC,UAAS,SAAS,OAAO;AAAA,IAC3C,OAAO;AACL,gBAAU,gBAAgB,KAAK;AAAA;AAAA;AAAA,IACjC;AAAA,EACF,QAAQ;AACN,cAAU,gBAAgB,KAAK;AAAA;AAAA;AAAA,EACjC;AAEA,QAAM,QAAO,oBAAI,KAAK,GAAE,aAAa,EAAE,MAAM,GAAG,EAAE,CAAC;AAEnD,QAAM,aAAa,OAAO;AAAA,IAAI,OAC5B,OAAO,IAAI,KAAK,EAAE,SAAS,YAAY,CAAC,KAAK,EAAE,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,SAAS,KAAK,QAAQ,EAAE;AAAA,gBACnF,EAAE,IAAI,KAAK,EAAE,OAAO,IAAI,EAAE,IAAI,KAAK,EAAE;AAAA,eACtC,EAAE,KAAK;AAAA,aACT,EAAE,IAAI,MAAM,GAAG,GAAG,CAAC,GAAG,EAAE,IAAI,SAAS,MAAM,QAAQ,EAAE;AAAA;AAAA,EACrE,EAAE,KAAK,IAAI;AAEX,aAAW,aAAa;AAExB,QAAM,UAAU,SAAS,OAAO;AAClC;AASA,eAAe,eAAe,YAA4C;AACxE,QAAM,YAAYH,MAAK,iBAAiB,UAAU,GAAG,UAAU,aAAa;AAE5E,MAAI;AACF,QAAIE,YAAW,SAAS,GAAG;AACzB,YAAM,UAAU,MAAMC,UAAS,WAAW,OAAO;AACjD,YAAM,SAAS,qBAAqB,SAAS,gBAAgB;AAE7D,UAAI,OAAO,SAAS;AAClB,eAAO,OAAO;AAAA,MAChB;AAGA,cAAQ,MAAM,6BAA6B,OAAO,KAAK,EAAE;AACzD,YAAM,gBAAgB,IAAI,cAAc,SAAS;AAEjD,UAAI,MAAM,cAAc,kBAAkB,GAAG;AAC3C,gBAAQ,MAAM,iCAA4B;AAC1C,cAAM,YAAY,MAAMA,UAAS,WAAW,OAAO;AACnD,cAAM,kBAAkB,qBAAqB,WAAW,gBAAgB;AACxE,YAAI,gBAAgB,SAAS;AAC3B,iBAAO,gBAAgB;AAAA,QACzB;AAAA,MACF;AAEA,cAAQ,MAAM,0CAA0C;AAAA,IAC1D;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,SAAO,CAAC;AACV;AAEA,eAAe,iBAAiB,WAA0B,YAAqC;AAC7F,QAAM,YAAYH,MAAK,iBAAiB,UAAU,GAAG,QAAQ;AAC7D,QAAMC,OAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAE1C,MAAI,WAAW,MAAM,eAAe,UAAU;AAI9C,QAAM,UAAU,IAAI,IAAI,SAAS,IAAI,OAAK,EAAE,IAAI,CAAC;AACjD,QAAM,QAAQ,UAAU,OAAO,OAAK,CAAC,QAAQ,IAAI,EAAE,IAAI,CAAC;AACxD,QAAM,eAAe,MAAM;AAE3B,aAAW,CAAC,GAAG,UAAU,GAAG,KAAK;AAGjC,MAAI,SAAS,SAAS,KAAK;AACzB,UAAM,EAAE,SAAS,UAAU,IAAI,MAAM,iBAAiB,UAAU;AAAA,MAC9D,UAAU;AAAA,MACV,oBAAoB;AAAA,IACtB,CAAC;AAED,QAAI,SAAS;AACX,YAAM,qBAAqB,SAAS,UAAU;AAC9C,iBAAW;AAAA,IACb;AAAA,EACF;AAIA,MAAI,SAAS,SAAS,KAAO;AAC3B,eAAW,iBAAiB,UAAU,GAAK;AAAA,EAC7C;AAEA,QAAM,eAAe,UAAU,UAAU;AACzC,SAAO;AACT;AAMA,SAAS,iBAAiB,QAAuB,aAAoC;AACnF,QAAM,iBAAyC;AAAA,IAC7C,UAAU;AAAA,IACV,MAAM;AAAA,IACN,UAAU;AAAA,IACV,KAAK;AAAA,IACL,MAAM;AAAA,EACR;AAEA,QAAM,SAAS,OAAO,IAAI,WAAS;AACjC,UAAM,aAAa,KAAK,IAAI,IAAI,IAAI,KAAK,MAAM,SAAS,EAAE,QAAQ,MAAM,MAAO,KAAK,KAAK;AACzF,UAAM,eAAe,KAAK,IAAI,GAAG,MAAM,YAAY,CAAC;AACpD,UAAM,gBAAgB,eAAe,MAAM,QAAQ,KAAK;AACxD,UAAM,kBAAkB,MAAM,WAAW,MAAM;AAE/C,WAAO;AAAA,MACL;AAAA,MACA,OAAO,eAAe,gBAAgB;AAAA,IACxC;AAAA,EACF,CAAC;AAED,SAAO,OACJ,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAChC,MAAM,GAAG,WAAW,EACpB,IAAI,OAAK,EAAE,KAAK;AACrB;AASA,eAAe,eAAe,QAAuB,YAAmC;AACtF,QAAM,YAAYD,MAAK,iBAAiB,UAAU,GAAG,QAAQ;AAC7D,QAAMC,OAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAE1C,QAAM,YAAYD,MAAK,WAAW,aAAa;AAG/C,QAAM,gBAAgB,IAAI,cAAc,SAAS;AACjD,QAAM,cAAc,aAAa;AAGjC,QAAM,gBAAgB,WAAW,MAAM;AACzC;AASA,SAAS,UAAU,OAAsB;AACvC,QAAM,UAAU,GAAG,MAAM,KAAK,IAAI,MAAM,IAAI,IAAI,MAAM,QAAQ,IAAI,MAAM,KAAK;AAC7E,SAAO,WAAW,QAAQ,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AACvE;","names":["mkdir","readFile","existsSync","join","join","mkdir","existsSync","readFile"]}