"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.handleIssueComment = exports.repo = exports.context = void 0; const octokit_1 = require("./octokit"); const tokenizer_1 = require("./tokenizer"); const context_1 = require("./context"); const inputs_1 = require("./inputs"); const commenter_1 = require("./commenter"); let info = console.log; let warning = console.warn; exports.context = new Proxy({}, { get(target, prop) { return (context_1.als.getStore()?.probotContext)[prop]; } }); exports.repo = new Proxy({}, { get(target, prop) { return (context_1.als.getStore()?.repo)[prop]; } }); const ISSUE_COMMAND_TAG = '@prix'; const MAX_API_CALLS = 100; const MAX_FILES_RETURNED = 200; let apiCallCount = 0; const handleIssueComment = async (heavyBot, options, prompts) => { const inputs = new inputs_1.Inputs(); if (exports.context.name !== 'issue_comment') { warning(`Skipped: ${exports.context.name} is not an issue_comment event`); return; } if (!exports.context.payload) { warning(`Skipped: issue_comment event is missing payload`); return; } if (!exports.context.payload.repository) { warning(`Skipped: issue_comment event is missing repository`); return; } const comment = exports.context.payload.comment; if (comment == null) { warning(`Skipped: issue_comment event is missing comment`); return; } const issue = exports.context.payload.issue; if (issue == null) { warning(`Skipped: issue_comment event is missing issue`); return; } if (exports.context.payload.action !== 'created') { warning(`Skipped: issue_comment event is not created`); return; } const isBotComment = comment.user?.type === 'Bot'; if (isBotComment) { info(`Skipped: issue_comment event is from the bot itself`); return; } if (!comment.body.includes(ISSUE_COMMAND_TAG)) { info(`Skipped: comment does not mention @prix`); return; } if (!exports.repo?.owner || !exports.repo?.repo) { warning(`Skipped: repo context is missing`); return; } const issueNumber = issue.number; if (!issueNumber || typeof issueNumber !== 'number') { warning(`Skipped: issue number is invalid`); return; } const issueTitle = issue.title || ''; const issueBody = issue.body || ''; const commentBody = comment.body || ''; const commentUser = comment.user?.login || 'unknown'; if (issueTitle.length > 500) { await postIssueComment(issueNumber, `@${commentUser} Issue title is too long. Please shorten it to under 500 characters.`); return; } if (issueBody.length > 10000) { await postIssueComment(issueNumber, `@${commentUser} Issue description is too long. Please simplify it to under 10,000 characters.`); return; } info(`Processing issue comment for issue #${issueNumber} from @${commentUser}`); inputs.title = issueTitle; inputs.description = issueBody; inputs.comment = `${commentUser}: ${commentBody}`; const taskDescription = extractTaskFromComment(commentBody); inputs.taskDescription = taskDescription; apiCallCount = 0; const counter = { fileCount: 0 }; const codebaseStructure = await fetchCodebaseStructure(exports.repo.owner, exports.repo.repo, () => counter.fileCount >= MAX_FILES_RETURNED, counter); inputs.codebaseStructure = codebaseStructure; if (counter.fileCount > MAX_FILES_RETURNED) { info(`Codebase structure truncated: ${counter.fileCount} files found, limit is ${MAX_FILES_RETURNED}`); } const tokens = (0, tokenizer_1.getTokenCount)(prompts.renderIssueAnalysis(inputs)); if (tokens > options.heavyTokenLimits.requestTokens) { await postIssueComment(issueNumber, `@${commentUser} The issue content is too large to process. Please simplify or split the issue.`); return; } const [analysis] = await heavyBot.chat(prompts.renderIssueAnalysis(inputs), {}); if (!analysis || analysis.trim().length === 0) { warning(`Empty analysis received for issue #${issueNumber}`); return; } const response = formatIssueResponse(commentUser, analysis); await postIssueComment(issueNumber, response); info(`Successfully processed issue comment for issue #${issueNumber}`); }; exports.handleIssueComment = handleIssueComment; const EXCLUDED_DIRS = new Set([ 'node_modules', '.git', 'dist', 'build', 'coverage', '.next', '__pycache__', 'venv', '.venv', 'target', 'bin', 'obj', '.idea', '.vscode', 'vendor', 'packages' ]); async function fetchCodebaseStructure(owner, repoName, shouldStop, counter) { try { const structure = await fetchDirectoryTree(owner, repoName, '', 3, shouldStop, 0, counter); return structure || 'Unable to fetch codebase structure'; } catch (error) { warning(`Failed to fetch codebase structure: ${error}`); return 'Codebase structure unavailable'; } } async function fetchDirectoryTree(owner, repo, path, depth, shouldStop, currentDepth = 0, counter) { if (currentDepth >= depth) { return ''; } if (apiCallCount >= MAX_API_CALLS) { return ''; } if (shouldStop()) { return ''; } try { apiCallCount++; const response = await octokit_1.octokit.repos.getContent({ owner, repo, path, ref: exports.context.payload.repository?.default_branch || 'main' }); const items = Array.isArray(response.data) ? response.data : [response.data]; let tree = ''; for (const item of items) { if (shouldStop()) { break; } if (item.type === 'dir' && !EXCLUDED_DIRS.has(item.name)) { tree += `${' '.repeat(currentDepth)}📁 ${item.name}/\n`; const subTree = await fetchDirectoryTree(owner, repo, item.path, depth, shouldStop, currentDepth + 1, counter); tree += subTree; } else if (item.type === 'file') { const ext = item.name.split('.').pop() || ''; if (isRelevantExtension(ext)) { tree += `${' '.repeat(currentDepth)}📄 ${item.name}\n`; if (counter) { counter.fileCount++; } } } } return tree; } catch (error) { return ''; } } function isRelevantExtension(ext) { const relevantExts = new Set([ 'ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'py', 'rb', 'go', 'rs', 'java', 'kt', 'scala', 'cpp', 'c', 'h', 'hpp', 'cs', 'swift', 'json', 'yaml', 'yml', 'toml', 'xml', 'md', 'txt', 'sh', 'bash', 'zsh', 'css', 'scss', 'sass', 'less', 'html', 'htm', 'vue', 'svelte', 'sql', 'graphql', 'proto', 'dockerfile', 'env', 'gitignore', 'editorconfig' ]); return relevantExts.has(ext.toLowerCase()); } function extractTaskFromComment(commentBody) { const mentionPattern = /@prix\s*(.*)$/i; const match = commentBody.match(mentionPattern); return match ? match[1].trim() : commentBody; } async function postIssueComment(issueNumber, body) { try { await octokit_1.octokit.issues.createComment({ owner: exports.repo.owner, repo: exports.repo.repo, issue_number: issueNumber, body }); } catch (error) { warning(`Failed to post issue comment: ${error}`); } } function formatIssueResponse(user, analysis) { return `## @${user} Issue Analysis ${analysis}${commenter_1.PLAN_BRANDING}`; } //# sourceMappingURL=issue-handler.js.map