Spaces:
Paused
Paused
| ; | |
| 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 |