@triedotdev/mcp 1.0.140 → 1.0.141
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -7
- package/dist/{chunk-OQ4A3RDY.js → chunk-LHPWSUVT.js} +3 -356
- package/dist/chunk-LHPWSUVT.js.map +1 -0
- package/dist/{chunk-UOSTOLU7.js → chunk-M5R6DZQY.js} +356 -1
- package/dist/chunk-M5R6DZQY.js.map +1 -0
- package/dist/{chunk-4O2KRHK4.js → chunk-ROVR5OHR.js} +3 -3
- package/dist/cli/main.js +654 -426
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/yolo-daemon.js +3 -3
- package/dist/index.js +4 -4
- package/dist/{trie-agent-M6PHM6UD.js → trie-agent-CZ5CGATT.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-OQ4A3RDY.js.map +0 -1
- package/dist/chunk-UOSTOLU7.js.map +0 -1
- /package/dist/{chunk-4O2KRHK4.js.map → chunk-ROVR5OHR.js.map} +0 -0
- /package/dist/{trie-agent-M6PHM6UD.js.map → trie-agent-CZ5CGATT.js.map} +0 -0
|
@@ -457,6 +457,360 @@ var GotchaPredictor = class {
|
|
|
457
457
|
}
|
|
458
458
|
};
|
|
459
459
|
|
|
460
|
+
// src/integrations/slack.ts
|
|
461
|
+
var SlackIntegration = class {
|
|
462
|
+
constructor(config) {
|
|
463
|
+
this.config = config;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Send scan completion notification
|
|
467
|
+
*/
|
|
468
|
+
async sendScanNotification(_issues, priorityReport, repositoryName, branch = "main") {
|
|
469
|
+
const { urgent, high, medium, low } = priorityReport;
|
|
470
|
+
const statusEmoji = urgent.length > 0 ? "[URGENT]" : high.length > 0 ? "[HIGH]" : "[OK]";
|
|
471
|
+
const message = {
|
|
472
|
+
blocks: [
|
|
473
|
+
{
|
|
474
|
+
type: "section",
|
|
475
|
+
text: {
|
|
476
|
+
type: "mrkdwn",
|
|
477
|
+
text: `${statusEmoji} *Trie Security Scan Complete*
|
|
478
|
+
*Repository:* ${repositoryName} (${branch})`
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
type: "section",
|
|
483
|
+
fields: [
|
|
484
|
+
{
|
|
485
|
+
type: "mrkdwn",
|
|
486
|
+
text: `*Urgent:* ${urgent.length}`
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
type: "mrkdwn",
|
|
490
|
+
text: `*High:* ${high.length}`
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
type: "mrkdwn",
|
|
494
|
+
text: `*Medium:* ${medium.length}`
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
type: "mrkdwn",
|
|
498
|
+
text: `*\u{1F539} Low:* ${low.length}`
|
|
499
|
+
}
|
|
500
|
+
]
|
|
501
|
+
}
|
|
502
|
+
],
|
|
503
|
+
attachments: []
|
|
504
|
+
};
|
|
505
|
+
if (urgent.length > 0) {
|
|
506
|
+
const urgentDetails = urgent.slice(0, 5).map(
|
|
507
|
+
(group) => `\u2022 ${group.description} (${group.count} instances)`
|
|
508
|
+
).join("\n");
|
|
509
|
+
message.attachments.push({
|
|
510
|
+
color: "danger",
|
|
511
|
+
title: "Urgent Issues - Immediate Action Required",
|
|
512
|
+
text: urgentDetails,
|
|
513
|
+
footer: urgent.length > 5 ? `... and ${urgent.length - 5} more urgent issues` : void 0
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
if (high.length > 0) {
|
|
517
|
+
const highDetails = high.slice(0, 3).map(
|
|
518
|
+
(group) => `\u2022 ${group.description} (${group.count} instances)`
|
|
519
|
+
).join("\n");
|
|
520
|
+
message.attachments.push({
|
|
521
|
+
color: "warning",
|
|
522
|
+
title: "High Priority Issues",
|
|
523
|
+
text: highDetails,
|
|
524
|
+
footer: high.length > 3 ? `... and ${high.length - 3} more high priority issues` : void 0
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
if (priorityReport.recommendations.length > 0) {
|
|
528
|
+
message.attachments.push({
|
|
529
|
+
color: "good",
|
|
530
|
+
title: "Recommendations",
|
|
531
|
+
text: priorityReport.recommendations.slice(0, 3).join("\n")
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
await this.sendMessage(message);
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Send critical issue alert
|
|
538
|
+
*/
|
|
539
|
+
async sendCriticalAlert(issues, repositoryName) {
|
|
540
|
+
const message = {
|
|
541
|
+
text: `CRITICAL SECURITY ALERT: ${repositoryName}`,
|
|
542
|
+
blocks: [
|
|
543
|
+
{
|
|
544
|
+
type: "section",
|
|
545
|
+
text: {
|
|
546
|
+
type: "mrkdwn",
|
|
547
|
+
text: `*CRITICAL SECURITY ALERT*
|
|
548
|
+
*Repository:* ${repositoryName}
|
|
549
|
+
*Critical Issues:* ${issues.length}`
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
],
|
|
553
|
+
attachments: issues.slice(0, 5).map((issue) => ({
|
|
554
|
+
color: "danger",
|
|
555
|
+
title: `${issue.file}:${issue.line || "?"}`,
|
|
556
|
+
text: issue.issue.slice(0, 200),
|
|
557
|
+
fields: [
|
|
558
|
+
{
|
|
559
|
+
title: "Fix",
|
|
560
|
+
value: issue.fix.slice(0, 100),
|
|
561
|
+
short: false
|
|
562
|
+
}
|
|
563
|
+
],
|
|
564
|
+
footer: `Agent: ${issue.agent}`,
|
|
565
|
+
ts: Math.floor(Date.now() / 1e3)
|
|
566
|
+
}))
|
|
567
|
+
};
|
|
568
|
+
if (issues.length > 5) {
|
|
569
|
+
message.attachments.push({
|
|
570
|
+
color: "danger",
|
|
571
|
+
text: `... and ${issues.length - 5} more critical issues. View full report for details.`
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
await this.sendMessage(message);
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Send team notification
|
|
578
|
+
*/
|
|
579
|
+
async sendTeamNotification(notification) {
|
|
580
|
+
const emoji = this.getNotificationEmoji(notification.type);
|
|
581
|
+
const message = {
|
|
582
|
+
blocks: [
|
|
583
|
+
{
|
|
584
|
+
type: "section",
|
|
585
|
+
text: {
|
|
586
|
+
type: "mrkdwn",
|
|
587
|
+
text: `${emoji} *${notification.title}*
|
|
588
|
+
${notification.message}`
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
]
|
|
592
|
+
};
|
|
593
|
+
if (notification.type === "assignment" && notification.data) {
|
|
594
|
+
const { assignment, issue } = notification.data;
|
|
595
|
+
message.attachments = [{
|
|
596
|
+
color: this.getAssignmentColor(assignment.priority),
|
|
597
|
+
fields: [
|
|
598
|
+
{
|
|
599
|
+
title: "Priority",
|
|
600
|
+
value: assignment.priority.toUpperCase(),
|
|
601
|
+
short: true
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
title: "Due Date",
|
|
605
|
+
value: assignment.dueDate ? new Date(assignment.dueDate).toLocaleDateString() : "Not set",
|
|
606
|
+
short: true
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
title: "File",
|
|
610
|
+
value: issue.file,
|
|
611
|
+
short: false
|
|
612
|
+
}
|
|
613
|
+
]
|
|
614
|
+
}];
|
|
615
|
+
}
|
|
616
|
+
await this.sendMessage(message);
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Send daily/weekly team summary
|
|
620
|
+
*/
|
|
621
|
+
async sendTeamSummary(period, stats) {
|
|
622
|
+
const emoji = period === "daily" ? "[DAILY]" : "[WEEKLY]";
|
|
623
|
+
const title = `${emoji} ${period.charAt(0).toUpperCase() + period.slice(1)} Security Summary`;
|
|
624
|
+
const message = {
|
|
625
|
+
blocks: [
|
|
626
|
+
{
|
|
627
|
+
type: "section",
|
|
628
|
+
text: {
|
|
629
|
+
type: "mrkdwn",
|
|
630
|
+
text: `*${title}*`
|
|
631
|
+
}
|
|
632
|
+
},
|
|
633
|
+
{
|
|
634
|
+
type: "section",
|
|
635
|
+
fields: [
|
|
636
|
+
{
|
|
637
|
+
type: "mrkdwn",
|
|
638
|
+
text: `*New Issues:* ${stats.newIssues}`
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
type: "mrkdwn",
|
|
642
|
+
text: `*\u2705 Resolved:* ${stats.resolvedIssues}`
|
|
643
|
+
},
|
|
644
|
+
{
|
|
645
|
+
type: "mrkdwn",
|
|
646
|
+
text: `*Overdue:* ${stats.overdueIssues}`
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
type: "mrkdwn",
|
|
650
|
+
text: `*Net Change:* ${stats.resolvedIssues - stats.newIssues > 0 ? "+" : ""}${stats.resolvedIssues - stats.newIssues}`
|
|
651
|
+
}
|
|
652
|
+
]
|
|
653
|
+
}
|
|
654
|
+
],
|
|
655
|
+
attachments: []
|
|
656
|
+
};
|
|
657
|
+
if (stats.topCategories.length > 0) {
|
|
658
|
+
const categoriesText = stats.topCategories.slice(0, 5).map((cat) => `\u2022 ${cat.category}: ${cat.count}`).join("\n");
|
|
659
|
+
message.attachments.push({
|
|
660
|
+
color: "good",
|
|
661
|
+
title: "Top Issue Categories",
|
|
662
|
+
text: categoriesText
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
if (stats.topContributors.length > 0) {
|
|
666
|
+
const contributorsText = stats.topContributors.slice(0, 5).map((contrib) => `\u2022 ${contrib.name}: ${contrib.resolved} resolved`).join("\n");
|
|
667
|
+
message.attachments.push({
|
|
668
|
+
color: "good",
|
|
669
|
+
title: "Top Contributors",
|
|
670
|
+
text: contributorsText
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
await this.sendMessage(message);
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Send bulk fix notification
|
|
677
|
+
*/
|
|
678
|
+
async sendBulkFixNotification(fixedGroups, totalFixed, repositoryName) {
|
|
679
|
+
const message = {
|
|
680
|
+
blocks: [
|
|
681
|
+
{
|
|
682
|
+
type: "section",
|
|
683
|
+
text: {
|
|
684
|
+
type: "mrkdwn",
|
|
685
|
+
text: `*Bulk Fix Applied*
|
|
686
|
+
*Repository:* ${repositoryName}
|
|
687
|
+
*Issues Fixed:* ${totalFixed}`
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
],
|
|
691
|
+
attachments: [{
|
|
692
|
+
color: "good",
|
|
693
|
+
title: "\u{1F527} Fixed Issue Groups",
|
|
694
|
+
text: fixedGroups.map(
|
|
695
|
+
(group) => `\u2022 ${group.description} (${group.count} instances)`
|
|
696
|
+
).join("\n")
|
|
697
|
+
}]
|
|
698
|
+
};
|
|
699
|
+
await this.sendMessage(message);
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Send escalation notification
|
|
703
|
+
*/
|
|
704
|
+
async sendEscalationNotification(overdueAssignments) {
|
|
705
|
+
const message = {
|
|
706
|
+
text: "OVERDUE ISSUE ESCALATION",
|
|
707
|
+
blocks: [
|
|
708
|
+
{
|
|
709
|
+
type: "section",
|
|
710
|
+
text: {
|
|
711
|
+
type: "mrkdwn",
|
|
712
|
+
text: `*Overdue Issue Escalation*
|
|
713
|
+
${overdueAssignments.length} issues are overdue and require attention.`
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
],
|
|
717
|
+
attachments: overdueAssignments.map((assignment) => ({
|
|
718
|
+
color: "warning",
|
|
719
|
+
title: `Issue ${assignment.issueId}`,
|
|
720
|
+
fields: [
|
|
721
|
+
{
|
|
722
|
+
title: "Assignee",
|
|
723
|
+
value: assignment.assignee,
|
|
724
|
+
short: true
|
|
725
|
+
},
|
|
726
|
+
{
|
|
727
|
+
title: "Days Overdue",
|
|
728
|
+
value: assignment.daysOverdue.toString(),
|
|
729
|
+
short: true
|
|
730
|
+
},
|
|
731
|
+
{
|
|
732
|
+
title: "Priority",
|
|
733
|
+
value: assignment.priority.toUpperCase(),
|
|
734
|
+
short: true
|
|
735
|
+
}
|
|
736
|
+
]
|
|
737
|
+
}))
|
|
738
|
+
};
|
|
739
|
+
await this.sendMessage(message);
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Send message to Slack
|
|
743
|
+
*/
|
|
744
|
+
async sendMessage(message) {
|
|
745
|
+
const payload = {
|
|
746
|
+
...message,
|
|
747
|
+
channel: this.config.channel || message.channel,
|
|
748
|
+
username: this.config.username || "Trie Security Bot",
|
|
749
|
+
icon_emoji: this.config.iconEmoji || ":shield:"
|
|
750
|
+
};
|
|
751
|
+
try {
|
|
752
|
+
const response = await fetch(this.config.webhookUrl, {
|
|
753
|
+
method: "POST",
|
|
754
|
+
headers: {
|
|
755
|
+
"Content-Type": "application/json"
|
|
756
|
+
},
|
|
757
|
+
body: JSON.stringify(payload)
|
|
758
|
+
});
|
|
759
|
+
if (!response.ok) {
|
|
760
|
+
throw new Error(`Slack API error: ${response.status} ${response.statusText}`);
|
|
761
|
+
}
|
|
762
|
+
} catch (error) {
|
|
763
|
+
console.error("Failed to send Slack notification:", error);
|
|
764
|
+
throw error;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Get emoji for notification type
|
|
769
|
+
*/
|
|
770
|
+
getNotificationEmoji(type) {
|
|
771
|
+
const emojis = {
|
|
772
|
+
assignment: "[ASSIGN]",
|
|
773
|
+
escalation: "[ESCALATE]",
|
|
774
|
+
completion: "[DONE]",
|
|
775
|
+
reminder: "[REMIND]"
|
|
776
|
+
};
|
|
777
|
+
return emojis[type] ?? "[NOTIFY]";
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Get color for assignment priority
|
|
781
|
+
*/
|
|
782
|
+
getAssignmentColor(priority) {
|
|
783
|
+
const colors = {
|
|
784
|
+
urgent: "danger",
|
|
785
|
+
high: "warning",
|
|
786
|
+
medium: "good",
|
|
787
|
+
low: "#36a64f"
|
|
788
|
+
};
|
|
789
|
+
return colors[priority] ?? "good";
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Test Slack connection
|
|
793
|
+
*/
|
|
794
|
+
async testConnection() {
|
|
795
|
+
try {
|
|
796
|
+
await this.sendMessage({
|
|
797
|
+
text: "Trie Slack Integration Test",
|
|
798
|
+
blocks: [{
|
|
799
|
+
type: "section",
|
|
800
|
+
text: {
|
|
801
|
+
type: "mrkdwn",
|
|
802
|
+
text: "*Trie Slack Integration Test*\nIf you see this message, the integration is working correctly!"
|
|
803
|
+
}
|
|
804
|
+
}]
|
|
805
|
+
});
|
|
806
|
+
return true;
|
|
807
|
+
} catch (error) {
|
|
808
|
+
console.error("Slack connection test failed:", error);
|
|
809
|
+
return false;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
|
|
460
814
|
export {
|
|
461
815
|
recordToGlobalMemory,
|
|
462
816
|
findCrossProjectPatterns,
|
|
@@ -464,6 +818,7 @@ export {
|
|
|
464
818
|
getGlobalMemoryStats,
|
|
465
819
|
updateGlobalMemoryMd,
|
|
466
820
|
searchGlobalPatterns,
|
|
821
|
+
SlackIntegration,
|
|
467
822
|
GotchaPredictor
|
|
468
823
|
};
|
|
469
|
-
//# sourceMappingURL=chunk-
|
|
824
|
+
//# sourceMappingURL=chunk-M5R6DZQY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/memory/global-memory.ts","../src/agent/gotcha-predictor.ts","../src/integrations/slack.ts"],"sourcesContent":["/**\n * Cross-Project Memory\n * \n * Stores and retrieves patterns across all projects.\n * Location: ~/.trie/memory/\n * \n * Phase 1 Hardening:\n * - SHA256 hashing for pattern IDs\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 { homedir } from 'os';\nimport type { Issue } from '../types/index.js';\nimport { atomicWriteJSON } from '../utils/atomic-write.js';\nimport { BackupManager } from '../utils/backup-manager.js';\nimport { GlobalPatternsIndexSchema, safeParseAndValidate } from './validation.js';\n\nconst GLOBAL_TRIE_DIR = join(homedir(), '.trie');\nconst GLOBAL_MEMORY_DIR = join(GLOBAL_TRIE_DIR, 'memory');\n\nexport interface GlobalPattern {\n id: string;\n pattern: string;\n description: string;\n severity: string;\n agent: string;\n occurrences: number;\n projects: string[];\n firstSeen: string;\n lastSeen: string;\n fixApplied?: {\n project: string;\n timestamp: string;\n fix: string;\n };\n}\n\nexport interface ProjectSummary {\n name: string;\n path: string;\n lastScan: string;\n totalIssues: number;\n patterns: string[];\n}\n\n/**\n * Record issues to global memory\n */\nexport async function recordToGlobalMemory(\n issues: Issue[],\n projectName: string,\n projectPath: string\n): Promise<void> {\n await mkdir(GLOBAL_MEMORY_DIR, { recursive: true });\n await mkdir(join(GLOBAL_MEMORY_DIR, 'projects'), { recursive: true });\n\n const patterns = await loadGlobalPatterns();\n const now = new Date().toISOString();\n\n for (const issue of issues) {\n const patternId = extractPatternId(issue);\n const existing = patterns.find(p => p.id === patternId);\n\n if (existing) {\n existing.occurrences++;\n existing.lastSeen = now;\n if (!existing.projects.includes(projectName)) {\n existing.projects.push(projectName);\n }\n } else {\n patterns.push({\n id: patternId,\n pattern: issue.issue.slice(0, 200),\n description: issue.fix.slice(0, 200),\n severity: issue.severity,\n agent: issue.agent,\n occurrences: 1,\n projects: [projectName],\n firstSeen: now,\n lastSeen: now,\n });\n }\n }\n\n await saveGlobalPatterns(patterns);\n\n const summaryPath = join(GLOBAL_MEMORY_DIR, 'projects', `${sanitizeName(projectName)}.json`);\n const summary: ProjectSummary = {\n name: projectName,\n path: projectPath,\n lastScan: now,\n totalIssues: issues.length,\n patterns: [...new Set(issues.map(i => extractPatternId(i)))],\n };\n \n // Use atomic write for project summary\n await atomicWriteJSON(summaryPath, summary);\n}\n\n/**\n * Find patterns that appear across multiple projects\n */\nexport async function findCrossProjectPatterns(\n minOccurrences: number = 2\n): Promise<GlobalPattern[]> {\n const patterns = await loadGlobalPatterns();\n return patterns\n .filter(p => p.projects.length >= minOccurrences)\n .sort((a, b) => b.occurrences - a.occurrences);\n}\n\n/**\n * Check if an issue has been fixed in another project\n */\nexport async function findFixFromOtherProjects(\n issue: Issue\n): Promise<GlobalPattern | null> {\n const patterns = await loadGlobalPatterns();\n const patternId = extractPatternId(issue);\n const pattern = patterns.find(p => p.id === patternId);\n\n if (pattern?.fixApplied) {\n return pattern;\n }\n\n return null;\n}\n\n/**\n * Record that a pattern was fixed\n */\nexport async function recordPatternFix(\n issue: Issue,\n projectName: string,\n fix: string\n): Promise<void> {\n const patterns = await loadGlobalPatterns();\n const patternId = extractPatternId(issue);\n const pattern = patterns.find(p => p.id === patternId);\n\n if (pattern && !pattern.fixApplied) {\n pattern.fixApplied = {\n project: projectName,\n timestamp: new Date().toISOString(),\n fix: fix.slice(0, 500),\n };\n await saveGlobalPatterns(patterns);\n }\n}\n\n/**\n * Get all tracked projects\n */\nexport async function listTrackedProjects(): Promise<ProjectSummary[]> {\n const projectsDir = join(GLOBAL_MEMORY_DIR, 'projects');\n \n try {\n if (!existsSync(projectsDir)) return [];\n \n const files = await readdir(projectsDir);\n const summaries: ProjectSummary[] = [];\n \n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n try {\n const content = await readFile(join(projectsDir, file), 'utf-8');\n summaries.push(JSON.parse(content));\n } catch {\n // Skip invalid files\n }\n }\n \n return summaries.sort((a, b) => \n new Date(b.lastScan).getTime() - new Date(a.lastScan).getTime()\n );\n } catch {\n return [];\n }\n}\n\n/**\n * Get global memory statistics\n */\nexport async function getGlobalMemoryStats(): Promise<{\n totalPatterns: number;\n crossProjectPatterns: number;\n trackedProjects: number;\n totalOccurrences: number;\n fixedPatterns: number;\n patternsByAgent: Record<string, number>;\n capacityInfo: {\n current: number;\n max: number;\n percentFull: number;\n isAtCap: boolean;\n };\n deduplicationStats: {\n uniquePatterns: number;\n averageOccurrences: number;\n };\n}> {\n const patterns = await loadGlobalPatterns();\n const projects = await listTrackedProjects();\n \n const MAX_PATTERNS = 500;\n \n // Count patterns by agent type\n const patternsByAgent: Record<string, number> = {};\n for (const pattern of patterns) {\n patternsByAgent[pattern.agent] = (patternsByAgent[pattern.agent] || 0) + 1;\n }\n \n const totalOccurrences = patterns.reduce((sum, p) => sum + p.occurrences, 0);\n const avgOccurrences = patterns.length > 0 ? totalOccurrences / patterns.length : 0;\n \n return {\n totalPatterns: patterns.length,\n crossProjectPatterns: patterns.filter(p => p.projects.length >= 2).length,\n trackedProjects: projects.length,\n totalOccurrences,\n fixedPatterns: patterns.filter(p => p.fixApplied).length,\n patternsByAgent,\n capacityInfo: {\n current: patterns.length,\n max: MAX_PATTERNS,\n percentFull: Math.round((patterns.length / MAX_PATTERNS) * 100),\n isAtCap: patterns.length >= MAX_PATTERNS,\n },\n deduplicationStats: {\n uniquePatterns: patterns.length,\n averageOccurrences: Math.round(avgOccurrences * 10) / 10,\n },\n };\n}\n\n/**\n * Update GLOBAL_MEMORY.md with current patterns\n */\nexport async function updateGlobalMemoryMd(): Promise<void> {\n const patterns = await loadGlobalPatterns();\n const crossProject = patterns.filter(p => p.projects.length >= 2);\n const projects = await listTrackedProjects();\n\n const lines: string[] = [\n '# Global Trie Memory',\n '',\n '> Auto-generated file tracking patterns across all your projects.',\n `> Last updated: ${new Date().toISOString()}`,\n '',\n '## Summary',\n '',\n `- **Projects tracked:** ${projects.length}`,\n `- **Total patterns:** ${patterns.length}`,\n `- **Cross-project patterns:** ${crossProject.length}`,\n '',\n '## Cross-Project Patterns',\n '',\n 'These issues appear in multiple projects:',\n '',\n ];\n \n for (const p of crossProject.slice(0, 20)) {\n lines.push(\n `### ${p.pattern.slice(0, 60)}${p.pattern.length > 60 ? '...' : ''}`,\n '',\n `- **Severity:** ${p.severity}`,\n `- **Agent:** ${p.agent}`,\n `- **Occurrences:** ${p.occurrences} across ${p.projects.length} projects`,\n `- **Projects:** ${p.projects.slice(0, 5).join(', ')}${p.projects.length > 5 ? '...' : ''}`,\n );\n if (p.fixApplied) {\n lines.push(`- **Fixed in:** ${p.fixApplied.project} on ${p.fixApplied.timestamp.split('T')[0]}`);\n } else {\n lines.push('- **Status:** Not fixed');\n }\n lines.push('');\n }\n\n lines.push(\n '## Tracked Projects',\n '',\n '| Project | Last Scan | Issues |',\n '|---------|-----------|--------|',\n );\n \n for (const p of projects.slice(0, 20)) {\n lines.push(`| ${p.name} | ${p.lastScan.split('T')[0]} | ${p.totalIssues} |`);\n }\n\n lines.push('', '---', '', '*This file is auto-generated by Trie. Do not edit manually.*');\n\n await mkdir(GLOBAL_MEMORY_DIR, { recursive: true });\n await writeFile(join(GLOBAL_MEMORY_DIR, 'GLOBAL_MEMORY.md'), lines.join('\\n'));\n}\n\n/**\n * Search global patterns\n */\nexport async function searchGlobalPatterns(\n query: string,\n options: {\n limit?: number;\n severity?: string[];\n agent?: string;\n } = {}\n): Promise<GlobalPattern[]> {\n const patterns = await loadGlobalPatterns();\n const limit = options.limit || 10;\n const queryTerms = query.toLowerCase().split(/\\s+/).filter(t => t.length > 2);\n \n const scored = patterns\n .filter(p => {\n if (options.severity && !options.severity.includes(p.severity)) return false;\n if (options.agent && p.agent !== options.agent) return false;\n return true;\n })\n .map(p => {\n const text = `${p.pattern} ${p.description} ${p.agent}`.toLowerCase();\n let score = 0;\n for (const term of queryTerms) {\n if (text.includes(term)) score++;\n }\n return { pattern: p, score };\n })\n .filter(s => s.score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, limit);\n \n return scored.map(s => s.pattern);\n}\n\n// Private helpers\n\n/**\n * Load global patterns with validation and auto-recovery\n */\nasync function loadGlobalPatterns(): Promise<GlobalPattern[]> {\n const patternsPath = join(GLOBAL_MEMORY_DIR, 'global-patterns.json');\n \n try {\n if (existsSync(patternsPath)) {\n const content = await readFile(patternsPath, 'utf-8');\n const result = safeParseAndValidate(content, GlobalPatternsIndexSchema);\n \n if (result.success) {\n return result.data as GlobalPattern[];\n }\n \n // Validation failed - attempt recovery\n const backupManager = new BackupManager(patternsPath);\n if (await backupManager.recoverFromBackup()) {\n const recovered = await readFile(patternsPath, 'utf-8');\n const recoveredResult = safeParseAndValidate(recovered, GlobalPatternsIndexSchema);\n if (recoveredResult.success) {\n return recoveredResult.data as GlobalPattern[];\n }\n }\n }\n } catch {\n // File doesn't exist or recovery failed\n }\n \n return [];\n}\n\n/**\n * Save global patterns with backup and atomic write\n */\nasync function saveGlobalPatterns(patterns: GlobalPattern[]): Promise<void> {\n await mkdir(GLOBAL_MEMORY_DIR, { recursive: true });\n const patternsPath = join(GLOBAL_MEMORY_DIR, 'global-patterns.json');\n \n // Intelligent deduplication: merge patterns with same ID\n const patternMap = new Map<string, GlobalPattern>();\n for (const pattern of patterns) {\n const existing = patternMap.get(pattern.id);\n if (existing) {\n // Merge: update occurrences, projects, and timestamps\n existing.occurrences += pattern.occurrences;\n for (const proj of pattern.projects) {\n if (!existing.projects.includes(proj)) {\n existing.projects.push(proj);\n }\n }\n existing.lastSeen = pattern.lastSeen > existing.lastSeen ? pattern.lastSeen : existing.lastSeen;\n } else {\n patternMap.set(pattern.id, pattern);\n }\n }\n \n const deduplicated = Array.from(patternMap.values());\n \n // Intelligent pruning: prioritize recent, high-severity, cross-project patterns\n const pruned = intelligentPruneGlobalPatterns(deduplicated, 500);\n \n // Create backup before writing\n const backupManager = new BackupManager(patternsPath);\n await backupManager.createBackup();\n \n // Atomic write\n await atomicWriteJSON(patternsPath, pruned);\n}\n\n/**\n * Intelligently prune global patterns to target count\n * Prioritizes: cross-project, high severity, recent, fixed patterns\n */\nfunction intelligentPruneGlobalPatterns(patterns: GlobalPattern[], targetCount: number): GlobalPattern[] {\n if (patterns.length <= targetCount) {\n return patterns;\n }\n \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 = patterns.map(pattern => {\n const ageInDays = (Date.now() - new Date(pattern.lastSeen).getTime()) / (1000 * 60 * 60 * 24);\n const recencyScore = Math.max(0, 100 - ageInDays * 2);\n const severityScore = severityWeight[pattern.severity] || 10;\n const crossProjectBonus = (pattern.projects.length - 1) * 30; // More projects = higher score\n const fixedBonus = pattern.fixApplied ? 20 : 0;\n const occurrenceScore = Math.min(pattern.occurrences * 2, 100);\n \n return {\n pattern,\n score: recencyScore + severityScore + crossProjectBonus + fixedBonus + occurrenceScore,\n };\n });\n \n return scored\n .sort((a, b) => b.score - a.score)\n .slice(0, targetCount)\n .map(s => s.pattern);\n}\n\n/**\n * Extract a pattern ID using SHA256 for proper deduplication\n * \n * Normalizes the issue text to group similar patterns:\n * - Lowercases\n * - Replaces code snippets with 'CODE'\n * - Replaces numbers with 'N'\n * - Removes quotes\n * \n * Uses SHA256 truncated to 12 chars for collision-free IDs.\n */\nfunction extractPatternId(issue: Issue): string {\n const normalized = issue.issue\n .toLowerCase()\n .replace(/`[^`]+`/g, 'CODE')\n .replace(/\\b\\d+\\b/g, 'N')\n .replace(/['\"]/g, '')\n .slice(0, 100);\n \n const hash = createHash('sha256')\n .update(normalized)\n .digest('hex')\n .slice(0, 12);\n \n return `${issue.agent}-${issue.severity}-${hash}`;\n}\n\nfunction sanitizeName(name: string): string {\n return name.replace(/[^a-zA-Z0-9-_]/g, '-').toLowerCase();\n}\n","import { ContextGraph } from '../context/graph.js';\nimport { searchIssues } from '../memory/issue-store.js';\nimport { scanForVulnerabilities } from '../trie/vulnerability-signatures.js';\nimport { scanForVibeCodeIssues } from '../trie/vibe-code-signatures.js';\nimport type { LinearTicketNode, LinearTicketNodeData } from '../context/nodes.js';\nimport { tryGetClient } from '../ai/client.js';\nimport { getStorage } from '../storage/tiered-storage.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nexport interface GotchaPrediction {\n id: string;\n message: string;\n confidence: number;\n riskLevel: 'low' | 'medium' | 'high' | 'critical';\n precedentId?: string;\n recommendation: string;\n evidence: {\n pastIncidents: string[];\n matchingPatterns: string[];\n relatedTickets: string[];\n };\n}\n\nexport class GotchaPredictor {\n private readonly projectPath: string;\n private readonly graph: ContextGraph;\n\n constructor(projectPath: string, graph: ContextGraph) {\n this.projectPath = projectPath;\n this.graph = graph;\n }\n\n async predictGotchas(changedFiles: string[]): Promise<GotchaPrediction[]> {\n const gotchas: GotchaPrediction[] = [];\n\n // 1. Get active Linear tickets\n const tickets = (await this.graph.listNodes()).filter(n => n.type === 'linear-ticket') as LinearTicketNode[];\n \n for (const file of changedFiles) {\n const fileGotchas = await this.predictForFile(file, tickets);\n gotchas.push(...fileGotchas);\n }\n\n return gotchas;\n }\n\n private async predictForFile(filePath: string, tickets: LinearTicketNode[]): Promise<GotchaPrediction[]> {\n const gotchas: GotchaPrediction[] = [];\n const fullPath = path.resolve(this.projectPath, filePath);\n\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n\n // 1. Run deterministic scanners for signatures\n const vulnerabilities = await scanForVulnerabilities(content, filePath);\n const vibeIssues = await scanForVibeCodeIssues(content, filePath);\n\n const signatures = [\n ...vulnerabilities.map(v => v.category),\n ...vibeIssues.map(v => v.category)\n ];\n\n // === NEW: Query warm storage for relevant decisions and blockers ===\n const storage = getStorage(this.projectPath);\n await storage.initialize();\n\n // Infer tags from file path and signatures\n const tags = this.extractTagsFromFile(filePath, signatures);\n \n // Query relevant governance for this file/area\n const relevantGovernance = await storage.queryGovernance({\n tags,\n limit: 10,\n });\n\n // Query active blockers for this area\n const activeBlockers = await storage.queryBlockers({\n tags,\n limit: 5,\n });\n\n // === NEW: Add gotchas from governance ledger ===\n for (const gov of relevantGovernance) {\n // Check if this file is in the governance record's file list\n if (gov.files.some(f => f.includes(filePath) || filePath.includes(f))) {\n gotchas.push({\n id: `gotcha-gov-${gov.id}`,\n message: `Governance: ${gov.decision}`,\n confidence: 0.85,\n riskLevel: 'medium',\n precedentId: gov.id,\n recommendation: gov.reasoning || 'Review this governance before making changes',\n evidence: {\n pastIncidents: [],\n matchingPatterns: gov.tags,\n relatedTickets: []\n }\n });\n }\n }\n\n // === NEW: Add gotchas from active blockers ===\n for (const blocker of activeBlockers) {\n gotchas.push({\n id: `gotcha-blocker-${blocker.id}`,\n message: `⚠️ Active Blocker: ${blocker.blocker}`,\n confidence: 0.95,\n riskLevel: blocker.impact === 'critical' ? 'critical' : \n blocker.impact === 'high' ? 'high' : 'medium',\n recommendation: `This area is currently blocked. Consider resolving this before making changes.`,\n evidence: {\n pastIncidents: [],\n matchingPatterns: blocker.tags,\n relatedTickets: []\n }\n });\n }\n\n for (const ticket of tickets) {\n const ticketData = ticket.data as LinearTicketNodeData;\n \n // Correlation 1: Ticket Intent vs Deterministic Signatures\n const intentMatch = this.correlateIntentWithSignatures(ticketData, signatures);\n if (intentMatch) {\n gotchas.push(intentMatch);\n }\n\n // Correlation 2: Historical Precedents\n const historicalPrecedents = await this.findHistoricalPrecedents(filePath, ticketData);\n if (historicalPrecedents) {\n gotchas.push(historicalPrecedents);\n }\n }\n\n return gotchas;\n }\n\n /**\n * Extract tags from file path and signatures for storage queries\n */\n private extractTagsFromFile(filePath: string, signatures: string[]): string[] {\n const tags = new Set<string>();\n\n // Add tags from file path\n const normalized = filePath.toLowerCase();\n if (normalized.includes('/auth/')) tags.add('auth');\n if (normalized.includes('/payment/')) tags.add('payments');\n if (normalized.includes('/api/')) tags.add('api');\n if (normalized.includes('/frontend/') || normalized.includes('/ui/')) tags.add('ui');\n if (normalized.includes('/backend/')) tags.add('backend');\n if (normalized.includes('/database/') || normalized.includes('/models/')) tags.add('database');\n\n // Add tags from signatures\n signatures.forEach(sig => tags.add(sig.toLowerCase()));\n\n return Array.from(tags);\n }\n\n private correlateIntentWithSignatures(ticket: LinearTicketNodeData, signatures: string[]): GotchaPrediction | null {\n const relevantSignatures = signatures.filter(sig => \n ticket.intentVibe.some(vibe => this.vibeToSignatureMap(vibe).includes(sig))\n );\n\n if (relevantSignatures.length > 0) {\n return {\n id: `gotcha-intent-${ticket.ticketId}-${Date.now()}`,\n message: `[${ticket.ticketId}] Working on \"${ticket.title}\" (${ticket.intentVibe.join(', ')}) in a file with ${relevantSignatures.join(', ')} signatures.`,\n confidence: 0.8,\n riskLevel: 'high',\n recommendation: `Be careful with ${relevantSignatures[0]} patterns as they correlate with the intent of your ticket.`,\n evidence: {\n pastIncidents: [],\n matchingPatterns: relevantSignatures,\n relatedTickets: [ticket.ticketId]\n }\n };\n }\n\n return null;\n }\n\n private async findHistoricalPrecedents(filePath: string, ticket: LinearTicketNodeData): Promise<GotchaPrediction | null> {\n // Search for historical issues similar to this ticket's description\n const similarIssues = await searchIssues(ticket.description, {\n workDir: this.projectPath,\n limit: 3\n });\n\n const relevantIssues = similarIssues.filter(r => r.issue.file === filePath || r.issue.file.includes(path.basename(filePath)));\n\n const [firstMatch] = relevantIssues;\n if (firstMatch) {\n const issue = firstMatch.issue;\n return {\n id: `gotcha-precedent-${ticket.ticketId}-${Date.now()}`,\n message: `A similar task in the past caused an issue: \"${issue.issue}\"`,\n confidence: 0.9,\n riskLevel: 'critical',\n precedentId: issue.id,\n recommendation: `Last time we worked on something similar here, we had to fix: \"${issue.fix}\". Check this first.`,\n evidence: {\n pastIncidents: [issue.id],\n matchingPatterns: [],\n relatedTickets: [ticket.ticketId]\n }\n };\n }\n\n return null;\n }\n\n private vibeToSignatureMap(vibe: string): string[] {\n const map: Record<string, string[]> = {\n 'performance': ['giant-file', 'performance', 'react-antipattern'],\n 'security': ['injection', 'secrets', 'auth', 'xss', 'crypto'],\n 'auth': ['auth', 'secrets', 'config'],\n 'bug': ['no-error-handling', 'async', 'error-handling'],\n 'feature': ['mixing-concerns', 'hardcoded'],\n 'refactor': ['code-smell', 'giant-file', 'mixing-concerns']\n };\n return map[vibe] || [];\n }\n\n async synthesizeGotchaExplanation(gotcha: GotchaPrediction): Promise<string> {\n const client = tryGetClient();\n if (!client) return gotcha.message;\n\n const prompt = `\n You are a JIT Defect Predictor. You found a potential \"gotcha\" for a developer.\n \n Ticket context: ${gotcha.evidence.relatedTickets.join(', ')}\n Signatures detected: ${gotcha.evidence.matchingPatterns.join(', ')}\n Past incidents: ${gotcha.evidence.pastIncidents.join(', ')}\n \n Raw message: ${gotcha.message}\n Recommendation: ${gotcha.recommendation}\n \n Explain this gotcha in a concise, human-friendly way (max 2 sentences). \n Make it sound like a senior dev giving a helpful nudge.\n `;\n\n try {\n const response = await client.messages.create({\n model: 'claude-3-5-sonnet-20240620',\n max_tokens: 100,\n messages: [{ role: 'user', content: prompt }]\n });\n\n const text = response.content\n .filter((block): block is { type: 'text'; text: string } => block.type === 'text')\n .map(block => block.text)\n .join('');\n \n return text.trim() || gotcha.message;\n } catch {\n return gotcha.message;\n }\n }\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}"],"mappings":"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","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-23RJT5WT.js";
|
|
4
4
|
import {
|
|
5
5
|
getTrieAgent
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-LHPWSUVT.js";
|
|
7
7
|
import {
|
|
8
8
|
LearningEngine,
|
|
9
9
|
exportToJson,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from "./chunk-4C67GV3O.js";
|
|
24
24
|
import {
|
|
25
25
|
findCrossProjectPatterns
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-M5R6DZQY.js";
|
|
27
27
|
import {
|
|
28
28
|
ContextGraph
|
|
29
29
|
} from "./chunk-FH335WL5.js";
|
|
@@ -8399,4 +8399,4 @@ export {
|
|
|
8399
8399
|
GitHubBranchesTool,
|
|
8400
8400
|
InteractiveDashboard
|
|
8401
8401
|
};
|
|
8402
|
-
//# sourceMappingURL=chunk-
|
|
8402
|
+
//# sourceMappingURL=chunk-ROVR5OHR.js.map
|