@@ -23,6 +23,12 @@ import {
2323 createRateLimiter ,
2424 sanitizeOutboundText ,
2525} from "./security.mjs" ;
26+ import {
27+ formatGitHubEvent ,
28+ shouldSkipEvent ,
29+ parseIgnoredUsers ,
30+ extractActor ,
31+ } from "./github-events.mjs" ;
2632import {
2733 canonicalizeEnvelope ,
2834 canonicalizeProtocolRequest ,
@@ -135,6 +141,8 @@ if (ALLOWED_USERS.length === 0) {
135141 logWarn ( "⚠️ SLACK_ALLOWED_USERS not set — all workspace members can interact" ) ;
136142}
137143
144+ const GITHUB_IGNORED_USERS = parseIgnoredUsers ( process . env . GITHUB_IGNORED_USERS ) ;
145+
138146const slackRateLimiter = createRateLimiter ( { maxRequests : 5 , windowMs : 60_000 } ) ;
139147const apiRateLimiter = createRateLimiter ( { maxRequests : 30 , windowMs : 60_000 } ) ;
140148
@@ -864,6 +872,46 @@ async function handleSlackPayload(slackEventEnvelopePayload) {
864872 return true ;
865873}
866874
875+ async function handleGitHubEvent ( type , payload ) {
876+ const actor = extractActor ( type , payload ) ;
877+ const repo = payload ?. repository ?. full_name || "unknown/repo" ;
878+ logInfo ( `🐙 github event: ${ type } (action: ${ payload ?. action || "n/a" } ) repo: ${ repo } actor: ${ actor || "n/a" } ` ) ;
879+
880+ // Filtering: skip noisy or self-generated events
881+ const skipReason = shouldSkipEvent ( type , payload , GITHUB_IGNORED_USERS ) ;
882+ if ( skipReason ) {
883+ logInfo ( ` ↳ skipping: ${ skipReason } ` ) ;
884+ return true ;
885+ }
886+
887+ const { message, isPing, isUnknown } = formatGitHubEvent ( type , payload ) ;
888+
889+ if ( isPing ) {
890+ logInfo ( " ↳ ping event — webhook configured successfully" ) ;
891+ return true ;
892+ }
893+
894+ if ( isUnknown ) {
895+ logWarn ( ` ↳ unhandled github event type: ${ type } — forwarding minimal summary` ) ;
896+ }
897+
898+ if ( ! message ) {
899+ logWarn ( ` ↳ formatter returned no message for ${ type } — skipping` ) ;
900+ return true ;
901+ }
902+
903+ refreshSocket ( ) ;
904+ const currentSocket = socketPath ;
905+ if ( ! currentSocket ) {
906+ logError ( "🔌 no pi socket found for github event — agent may not be running" ) ;
907+ return true ;
908+ }
909+
910+ await enqueue ( ( ) => sendToAgent ( currentSocket , message ) ) ;
911+ logInfo ( ` ↳ forwarded to agent` ) ;
912+ return true ;
913+ }
914+
867915async function handleDashboardEvent ( type , payload ) {
868916 logInfo ( `📊 dashboard event: ${ type } ` , JSON . stringify ( payload ) . slice ( 0 , 200 ) ) ;
869917 // TODO: implement dashboard event handling (env updates, config changes)
@@ -896,6 +944,8 @@ async function processPulledMessage(message) {
896944 switch ( payload . source ) {
897945 case "slack" :
898946 return handleSlackPayload ( payload . payload ) ;
947+ case "github" :
948+ return handleGitHubEvent ( payload . type , payload . payload ) ;
899949 case "dashboard" :
900950 return handleDashboardEvent ( payload . type , payload . payload ) ;
901951 case "system" :
0 commit comments