11import express , { Application } from 'express' ;
22import dotenv from 'dotenv' ;
3- import { Probot , Application as ProbotApplication } from 'probot' ;
3+ import { Probot } from 'probot' ;
44import { createNodeMiddleware } from '@octokit/webhooks' ;
5- import fs from 'fs' ; // Needed for reading private key if not a string
5+ import fs from 'fs' ;
6+ import pino from 'pino' ;
7+
8+ // Setup logger
9+ const logger = pino ( {
10+ level : process . env . LOG_LEVEL || 'info' ,
11+ transport : {
12+ target : 'pino-pretty' ,
13+ options : {
14+ colorize : true ,
15+ translateTime : 'SYS:yyyy-dd-mm, h:MM:ss' ,
16+ ignore : 'pid,hostname' ,
17+ }
18+ }
19+ } ) ;
620
721dotenv . config ( ) ;
822
923// Ensure environment variables are loaded and set
1024const appId = process . env . APP_ID ;
11- const privateKeyPath = process . env . PRIVATE_KEY_PATH ; // Suggest using a path for the private key
25+ const privateKeyPath = process . env . PRIVATE_KEY_PATH ;
1226const webhookSecret = process . env . WEBHOOK_SECRET ;
13- const appName = process . env . APP_NAME || 'om-bot' ; // Use app name for mention
27+ const appName = process . env . APP_NAME || 'om-bot' ;
1428
1529if ( ! appId || ! privateKeyPath || ! webhookSecret ) {
16- console . error ( 'Missing required environment variables: APP_ID, PRIVATE_KEY_PATH, WEBHOOK_SECRET' ) ;
30+ logger . error ( 'Missing required environment variables: APP_ID, PRIVATE_KEY_PATH, WEBHOOK_SECRET' ) ;
1731 process . exit ( 1 ) ;
1832}
1933
2034// Read the private key from the file
2135let privateKey : string ;
2236try {
2337 privateKey = fs . readFileSync ( privateKeyPath , 'utf8' ) ;
24- } catch ( error ) {
25- console . error ( `Error reading private key file at ${ privateKeyPath } :` , error ) ;
38+ } catch ( error : any ) {
39+ logger . error ( `Error reading private key file at ${ privateKeyPath } : ${ error . message } ` ) ;
2640 process . exit ( 1 ) ;
2741}
2842
2943const app : Application = express ( ) ;
3044app . use ( express . json ( ) ) ;
3145
3246// Initialize Probot
33- // Probot uses its own Octokit instance, no need to pass it.
34- // The webhook secret is primarily used by the middleware for signature verification.
3547const probot = new Probot ( {
36- appId : Number ( appId ) , // APP_ID should be a number
48+ appId : Number ( appId ) ,
3749 privateKey : privateKey ,
3850} ) ;
3951
4052// Register the webhook middleware from @octokit /webhooks
41- // This middleware verifies the webhook signature and passes the event to Probot.
4253const webhookMiddleware = createNodeMiddleware ( probot . receive , {
4354 secret : webhookSecret ,
4455} ) ;
@@ -47,6 +58,7 @@ app.use('/webhook', webhookMiddleware);
4758
4859// Basic root route
4960app . get ( '/' , ( req , res ) => {
61+ logger . info ( 'GET / request received' ) ;
5062 res . send ( 'Oh My Opencode GitHub Agent is running!' ) ;
5163} ) ;
5264
@@ -59,27 +71,20 @@ probot.on('issue_comment.created', async (context) => {
5971 const commentBody = comment . body ;
6072 const commentAuthor = comment . user . login ;
6173
62- console . log ( `Received issue_comment from ${ commentAuthor } in ${ owner } /${ repo } :` , commentBody ) ;
74+ logger . info ( `Received issue_comment from ${ commentAuthor } in ${ owner } /${ repo } : ${ commentBody } ` ) ;
6375
64- // Check for the mention and command syntax: "@om-bot create-pr <source-branch> <target-branch> \"<PR title>\""
6576 const mentionRegex = new RegExp ( `@${ appName } create-pr` , 'i' ) ;
6677
6778 if ( mentionRegex . test ( commentBody ) ) {
6879 const match = commentBody . match ( mentionRegex ) ;
6980 if ( match && match . index !== undefined ) {
7081 const commandPart = commentBody . substring ( match . index + match [ 0 ] . length ) . trim ( ) ;
71- // Regex to capture branches and a title, allowing for quotes around the title.
72- // It tries to capture:
73- // Group 1: source branch
74- // Group 2: target branch
75- // Group 3: The entire quoted title (if present) OR the rest of the string if no quotes.
76- const commandRegex = / ( \S + ) \s + ( \S + ) (?: \s + \" ( [ ^ \" ] + ) \" ) ? / ; // Non-greedy match for branches, then optionally a quoted title
82+ const commandRegex = / ( \S + ) \s + ( \S + ) (?: \s + \" ( [ ^ \" ] + ) \" ) ? / ;
7783 const parts = commandPart . match ( commandRegex ) ;
7884
7985 if ( parts && parts . length >= 3 ) {
8086 const sourceBranch = parts [ 1 ] ;
8187 const targetBranch = parts [ 2 ] ;
82- // If a quoted title was found (parts[3]), use it. Otherwise, use the rest of the command part as title.
8388 const prTitle = parts [ 3 ] || commandPart . substring ( parts [ 0 ] . indexOf ( parts [ 2 ] ) + parts [ 2 ] . length ) . trim ( ) ;
8489
8590 if ( ! sourceBranch || ! targetBranch || ! prTitle ) {
@@ -92,13 +97,11 @@ probot.on('issue_comment.created', async (context) => {
9297 return ;
9398 }
9499
95- console . log ( `Attempting to create PR: source=${ sourceBranch } , target=${ targetBranch } , title=${ prTitle } ` ) ;
100+ logger . info ( `Attempting to create PR: source=${ sourceBranch } , target=${ targetBranch } , title=${ prTitle } ` ) ;
96101
97102 try {
98- // Check if source branch exists (optional but good practice)
99103 await context . octokit . rest . repos . getBranch ( { owner, repo, branch : sourceBranch } ) ;
100104
101- // Create the pull request
102105 const prResponse = await context . octokit . rest . pulls . create ( {
103106 owner,
104107 repo,
@@ -115,11 +118,11 @@ probot.on('issue_comment.created', async (context) => {
115118 body : `Successfully created pull request: ${ prResponse . data . html_url } ` ,
116119 } ) ;
117120 } catch ( error : any ) {
118- console . error ( 'Error creating pull request:' , error ) ;
121+ logger . error ( { error : error , message : 'Error creating pull request' } ) ;
119122 let errorMessage = `Failed to create pull request. Error: ${ error . message } .` ;
120- if ( error . status === 422 ) { // Unprocessable Entity - often means branches don't exist or no diff
123+ if ( error . status === 422 ) {
121124 errorMessage += ' This could be due to non-existent branches, no differences between branches, or insufficient permissions.' ;
122- } else if ( error . status === 404 ) { // Not Found
125+ } else if ( error . status === 404 ) {
123126 errorMessage += ' One or more branches were not found.' ;
124127 }
125128 await context . octokit . rest . issues . createComment ( {
@@ -141,24 +144,28 @@ probot.on('issue_comment.created', async (context) => {
141144 }
142145} ) ;
143146
144- // Handle installation event to allow users to install the app
147+ // Handle installation event
145148probot . on ( 'installation.created' , async ( context ) => {
146- console . log ( 'GitHub App installed or updated.' ) ;
147- // You might want to send a message to the repo's main branch README or a default issue.
148- // For now, just logging is sufficient for the mechanism.
149+ logger . info ( 'GitHub App installed or updated.' ) ;
150+ } ) ;
151+
152+ // Handle unhandled promise rejections
153+ process . on ( 'unhandledRejection' , ( reason , promise ) => {
154+ logger . error ( { err : reason , promise : promise } , 'Unhandled Rejection at:' ) ;
155+ // Consider more graceful shutdown or error reporting here if necessary
149156} ) ;
150157
151158// Listen on a specific port
152- const port = parseInt ( process . env . PORT || '3000' , 10 ) ; // Ensure port is a number
159+ const port = parseInt ( process . env . PORT || '3000' , 10 ) ;
153160
154161// Start the server
155162app . listen ( port , ( ) => {
156- console . log ( `Server listening on port ${ port } ` ) ;
157- console . log ( `Webhook endpoint: /webhook` ) ;
158- console . log ( `Make sure your GitHub App webhook is configured to point to this URL and port.` ) ;
163+ logger . info ( `Server listening on port ${ port } ` ) ;
164+ logger . info ( `Webhook endpoint: /webhook` ) ;
165+ logger . info ( `Make sure your GitHub App webhook is configured to point to this URL and port.` ) ;
159166} ) ;
160167
161168// Optional: Log any unhandled events for debugging
162169// probot.onAny(async (context) => {
163- // console.log (`Unhandled event: ${context.name}`);
164- // });
170+ // logger.debug (`Unhandled event: ${context.name}`);
171+ // });
0 commit comments