* Handle incoming webhook event
(
payload: string,
signature: string
)
| 376 | * Handle incoming webhook event |
| 377 | */ |
| 378 | async handleWebhook( |
| 379 | payload: string, |
| 380 | signature: string |
| 381 | ): Promise<void> { |
| 382 | // 1. Verify signature |
| 383 | if (!this.verifySignature(payload, signature)) { |
| 384 | console.error('[GitHub] Invalid webhook signature'); |
| 385 | return; |
| 386 | } |
| 387 | |
| 388 | // 2. Parse event |
| 389 | const event: WebhookEvent = JSON.parse(payload); |
| 390 | const parsed = this.parseEvent(event); |
| 391 | if (!parsed) return; |
| 392 | |
| 393 | const { owner, repo, number, comment, eventType, issue, pullRequest } = parsed; |
| 394 | |
| 395 | // 3. Check @mention |
| 396 | if (!this.hasMention(comment)) return; |
| 397 | |
| 398 | console.log(`[GitHub] Processing ${eventType}: ${owner}/${repo}#${number}`); |
| 399 | |
| 400 | // 4. Build conversationId |
| 401 | const conversationId = this.buildConversationId(owner, repo, number); |
| 402 | |
| 403 | // 5. Check if new conversation |
| 404 | const existingConv = await db.getOrCreateConversation('github', conversationId); |
| 405 | const isNewConversation = !existingConv.codebase_id; |
| 406 | |
| 407 | // 6. Get/create codebase (checks for existing first!) |
| 408 | const { codebase, repoPath, isNew: isNewCodebase } = await this.getOrCreateCodebaseForRepo( |
| 409 | owner, |
| 410 | repo |
| 411 | ); |
| 412 | |
| 413 | // 7. Get default branch |
| 414 | const { data: repoData } = await this.octokit.rest.repos.get({ owner, repo }); |
| 415 | const defaultBranch = repoData.default_branch; |
| 416 | |
| 417 | // 8. Ensure repo ready (clone if needed, sync if new conversation) |
| 418 | await this.ensureRepoReady(owner, repo, defaultBranch, repoPath, isNewConversation); |
| 419 | |
| 420 | // 9. Auto-load commands if new codebase |
| 421 | if (isNewCodebase) { |
| 422 | await this.autoDetectAndLoadCommands(repoPath, codebase.id); |
| 423 | } |
| 424 | |
| 425 | // 10. Update conversation |
| 426 | if (isNewConversation) { |
| 427 | await db.updateConversation(existingConv.id, { |
| 428 | codebase_id: codebase.id, |
| 429 | cwd: repoPath, |
| 430 | }); |
| 431 | } |
| 432 | |
| 433 | // 11. Build message with context |
| 434 | const strippedComment = this.stripMention(comment); |
| 435 | let finalMessage = strippedComment; |
no test coverage detected