-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcorrelation-engine.ts
More file actions
137 lines (112 loc) · 4.42 KB
/
Copy pathcorrelation-engine.ts
File metadata and controls
137 lines (112 loc) · 4.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import { EventStore } from "./event-store.js";
import { RuntimeLogger } from "../core/logger.js";
export class CorrelationEngine {
private eventStore: EventStore;
constructor() {
this.eventStore = EventStore.getInstance();
}
async correlateAll() {
const db = (this.eventStore as any).db;
// 1. Find unlinked commits
const unlinkedCommits = db.prepare(`
SELECT c.* FROM commits c
LEFT JOIN execution_commits ec ON c.id = ec.commit_id
WHERE ec.commit_id IS NULL
`).all();
for (const commit of unlinkedCommits) {
const bestPrompt = this.findBestPromptMatch(commit);
if (bestPrompt) {
this.linkCommitToPrompt(commit.id, bestPrompt.id);
}
}
}
private findBestPromptMatch(commit: any): any | null {
const db = (this.eventStore as any).db;
// Find prompts in the same repo that happened within 2 hours BEFORE the commit
const candidates = db.prepare(`
SELECT * FROM prompts
WHERE repo_id = ?
AND julianday(timestamp) < julianday(?)
AND julianday(timestamp) > julianday(?, '-2 hours')
ORDER BY julianday(timestamp) DESC
`).all(commit.repo_id, commit.committed_at, commit.committed_at);
if (candidates.length === 0) return null;
// Simple scoring: Time proximity + Message matching
let bestMatch = null;
let highestScore = -1;
for (const prompt of candidates) {
let score = 0;
// Time score (up to 50 points, closer = higher)
const commitTime = new Date(commit.committed_at).getTime();
const promptTime = new Date(prompt.timestamp).getTime();
const diffMinutes = (commitTime - promptTime) / (1000 * 60);
score += Math.max(0, 50 - (diffMinutes / 2.4)); // 50 points if instant, 0 points if 120 mins
// Keyword match (up to 50 points)
const promptText = (prompt.raw_prompt + " " + (prompt.intent || "")).toLowerCase();
const commitMsg = commit.message.toLowerCase();
const keywords = promptText.split(/\s+/).filter(w => w.length > 3);
let matches = 0;
for (const word of keywords) {
if (commitMsg.includes(word)) matches++;
}
if (keywords.length > 0) {
score += (matches / keywords.length) * 50;
}
// File-awareness bonus (up to 40 points)
try {
const commitFiles = JSON.parse(commit.changed_files_json || "[]");
const promptText = (prompt.raw_prompt + " " + (prompt.normalized_prompt || "")).toLowerCase();
let fileMatches = 0;
for (const file of commitFiles) {
const fileName = file.split("/").pop() || file;
if (fileName.length > 3 && promptText.includes(fileName.toLowerCase())) {
fileMatches++;
}
}
if (fileMatches > 0) {
score += 40; // Flat bonus for any file match
score += Math.min(20, fileMatches * 5); // Additional per-file bonus
}
} catch (e) {
// Stats parsing failed
}
// If no keywords or files match at all, penalize heavily
if (matches === 0 && keywords.length > 0) {
score -= 40;
}
if (score > highestScore && score >= 50) { // Require at least a strong proximity or content match
highestScore = score;
bestMatch = prompt;
}
}
return bestMatch;
}
private linkCommitToPrompt(commitId: string, promptId: string) {
const db = (this.eventStore as any).db;
// 1. Ensure an execution exists for this prompt
let execution = db.prepare("SELECT id FROM executions WHERE prompt_id = ? LIMIT 1").get(promptId);
if (!execution) {
const execId = `exec_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
this.eventStore.recordExecution({
id: execId,
prompt_id: promptId,
workflow_name: "auto-correlated",
executor_name: "CorrelationEngine",
status: "completed"
});
execution = { id: execId };
}
// 2. Link them
this.eventStore.linkCommitToExecution(execution.id, commitId);
RuntimeLogger.info(`Correlated commit ${commitId} with prompt ${promptId}`);
// 3. Record a correlation event
this.eventStore.recordEvent({
id: `evt_corr_${Date.now()}`,
event_type: "commit_correlated",
prompt_id: promptId,
commit_id: commitId,
execution_id: execution.id,
summary: `Auto-linked commit to prompt via proximity and keyword matching.`
});
}
}