PRIX / lib /src /feedback-capture.js
yamxxx1's picture
Upload 117 files
a2fe16e verified
Raw
History Blame
8.09 kB
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.feedbackCapture = exports.FeedbackCapture = void 0;
const octokit_1 = require("./octokit");
const context_1 = require("./context");
const feedback_tracker_1 = require("./feedback-tracker");
const info = console.log;
const warning = console.warn;
const FEEDBACK_TAG = '<!-- prix_feedback_tracking -->';
class FeedbackCapture {
commentMetadata = new Map();
pendingFeedback = new Map();
getCommentKey(pullNumber, path, startLine) {
return `${pullNumber}:${path}:${startLine}`;
}
trackComment(pullNumber, path, startLine, patternType, severity, confidence, commentId) {
const key = this.getCommentKey(pullNumber, path, startLine);
this.commentMetadata.set(key, {
commentId,
pullNumber,
path,
patternType,
severity,
confidence
});
}
async checkSuggestionApplied(pullNumber, path, startLine) {
const key = this.getCommentKey(pullNumber, path, startLine);
const metadata = this.commentMetadata.get(key);
if (!metadata || !metadata.commentId)
return false;
try {
const comments = await octokit_1.octokit.pulls.listReviewComments({
owner: context_1.als.getStore()?.repo.owner || '',
repo: context_1.als.getStore()?.repo.repo || '',
// eslint-disable-next-line camelcase
pull_number: pullNumber
});
const originalComment = comments.data.find((c) => c.id === metadata.commentId);
if (!originalComment)
return false;
const diff = await this.getFileDiffAtComment(pullNumber, path, startLine, originalComment.original_line || startLine);
const hasAppliedSuggestion = this.detectSuggestionApplication(originalComment.body || '', diff);
if (hasAppliedSuggestion) {
this.recordFeedback(key, 'accepted');
}
return hasAppliedSuggestion;
}
catch (e) {
warning(`Failed to check suggestion application: ${e}`);
return false;
}
}
async getFileDiffAtComment(pullNumber, path, startLine, originalLine) {
try {
const diff = await octokit_1.octokit.repos.compareCommits({
owner: context_1.als.getStore()?.repo.owner || '',
repo: context_1.als.getStore()?.repo.repo || '',
base: `${pullNumber}-base`,
head: `${pullNumber}-head`
});
const file = diff.data.files?.find((f) => f.filename === path);
if (!file?.patch)
return '';
const hunk = file.patch
.split('\n')
.slice(Math.max(0, originalLine - startLine - 1), originalLine - startLine + 5)
.join('\n');
return hunk;
}
catch (e) {
return '';
}
}
detectSuggestionApplication(originalBody, currentDiff) {
if (!originalBody.includes('```suggestion'))
return false;
if (!currentDiff)
return false;
const suggestionMatch = originalBody.match(/```suggestion\n([\s\S]*?)```/);
if (!suggestionMatch)
return false;
const suggestedCode = suggestionMatch[1].trim();
const hasApplied = currentDiff.includes(suggestedCode.substring(0, Math.min(50, suggestedCode.length)));
return hasApplied;
}
recordFeedback(key, type) {
const metadata = this.commentMetadata.get(key);
if (!metadata)
return;
this.pendingFeedback.set(key, type);
const ctx = context_1.als.getStore();
const teamId = ctx?.repo?.owner || 'default';
const repoSlug = ctx?.repo?.repo || 'default';
feedback_tracker_1.feedbackTracker.recordFeedback({
patternType: metadata.patternType,
severity: metadata.severity,
filenamePattern: metadata.path,
repoSlug,
teamId,
confidence: metadata.confidence,
feedbackType: type
});
info(`Recorded ${type} feedback for ${key}`);
}
async checkReactionFeedback(pullNumber) {
const ctx = context_1.als.getStore();
const teamId = ctx?.repo?.owner || 'default';
const repoSlug = ctx?.repo?.repo || 'default';
try {
const comments = await octokit_1.octokit.pulls.listReviewComments({
owner: teamId,
repo: repoSlug,
// eslint-disable-next-line camelcase
pull_number: pullNumber
});
for (const comment of comments.data) {
if (!comment.body?.includes(FEEDBACK_TAG))
continue;
const reactions = await octokit_1.octokit.reactions.listForIssueComment({
owner: teamId,
repo: repoSlug,
// eslint-disable-next-line camelcase
comment_id: comment.id
});
for (const reaction of reactions.data) {
const key = this.getCommentKey(pullNumber, comment.path || '', comment.line || comment.original_line || 0);
if (reaction.content === '+1' || reaction.content === 'heart') {
this.recordFeedback(key, 'accepted');
}
else if (reaction.content === '-1' || reaction.content === 'eyes') {
this.recordFeedback(key, 'rejected');
}
}
}
}
catch (e) {
warning(`Failed to check reaction feedback: ${e}`);
}
}
async trackReviewSubmission(pullNumber, reviewId, commitId) {
const ctx = context_1.als.getStore();
const teamId = ctx?.repo?.owner || 'default';
const repoSlug = ctx?.repo?.repo || 'default';
info(`Tracking review submission: PR #${pullNumber}, review ID: ${reviewId}`);
try {
const comments = await octokit_1.octokit.pulls.listReviewComments({
owner: teamId,
repo: repoSlug,
// eslint-disable-next-line camelcase
pull_number: pullNumber
});
for (const comment of comments.data) {
if (!comment.body?.includes(FEEDBACK_TAG))
continue;
if (comment.user?.login !== 'github-actions[bot]')
continue;
const metadataMatch = comment.body.match(/data-pattern="([^"]+)"/);
const severityMatch = comment.body.match(/data-severity="([^"]+)"/);
const confidenceMatch = comment.body.match(/data-confidence="([^"]+)"/);
if (metadataMatch && severityMatch && confidenceMatch) {
const key = this.getCommentKey(pullNumber, comment.path || '', comment.line || comment.original_line || 0);
this.commentMetadata.set(key, {
commentId: comment.id,
pullNumber,
path: comment.path || '',
patternType: metadataMatch[1],
severity: severityMatch[1],
confidence: parseFloat(confidenceMatch[1])
});
}
}
}
catch (e) {
warning(`Failed to track review submission: ${e}`);
}
}
getFeedbackStats(teamId, repoSlug) {
return feedback_tracker_1.feedbackTracker.getTeamInsights(teamId, repoSlug);
}
shouldSuppressFinding(patternType, filename, teamId, repoSlug) {
return feedback_tracker_1.feedbackTracker.shouldSuppressPattern(patternType, teamId, repoSlug);
}
}
exports.FeedbackCapture = FeedbackCapture;
exports.feedbackCapture = new FeedbackCapture();
//# sourceMappingURL=feedback-capture.js.map