@@ -39,6 +39,18 @@ if (!GITHUB_TOKEN) {
3939
4040const bot = new Bot ( BOT_TOKEN )
4141
42+ // ---------------------------------------------------------------------------
43+ // Notification mode: 'verbose' (default) or 'quiet', keyed by chat ID
44+ // ---------------------------------------------------------------------------
45+
46+ const chatNotifyMode = new Map < number , 'verbose' | 'quiet' > ( )
47+
48+ /** Events that are skipped entirely in quiet mode. */
49+ const QUIET_EVENTS = new Set ( [ 'edit' , 'test_run' , 'cloned' ] )
50+
51+ /** Events that always deliver with notification sound regardless of mode. */
52+ const LOUD_EVENTS = new Set ( [ 'pr_created' , 'completed' ] )
53+
4254// ---------------------------------------------------------------------------
4355// Authorization middleware — restrict to known Telegram users
4456// ---------------------------------------------------------------------------
@@ -176,13 +188,31 @@ bot.command('start', async (ctx: Context) => {
176188 '/task <repo_url> <description> -- Submit a dev task' ,
177189 '/status <job_id> -- Check job status' ,
178190 '/cancel <job_id> -- Cancel a running job' ,
191+ '/verbose -- Enable all event notifications (default)' ,
192+ '/quiet -- Only send milestone notifications; silence noisy events' ,
179193 '' ,
180194 'When a PR is ready, I will send approve/reject buttons.' ,
181195 ] . join ( '\n' ) ,
182196 { parse_mode : 'HTML' } ,
183197 )
184198} )
185199
200+ bot . command ( 'verbose' , async ( ctx : Context ) => {
201+ const chatId = ctx . chat ! . id
202+ chatNotifyMode . set ( chatId , 'verbose' )
203+ await ctx . reply ( '\u{1F50A} Verbose mode enabled. You will receive all event notifications.' )
204+ } )
205+
206+ bot . command ( 'quiet' , async ( ctx : Context ) => {
207+ const chatId = ctx . chat ! . id
208+ chatNotifyMode . set ( chatId , 'quiet' )
209+ await ctx . reply (
210+ '\u{1F514} Quiet mode enabled. '
211+ + 'Only milestone notifications (loop start, test results, PR created, completed, errors) will be sent. '
212+ + 'Noisy events (edits, test runs, cloned) are silenced.' ,
213+ )
214+ } )
215+
186216bot . command ( 'task' , async ( ctx : Context ) => {
187217 const text = ctx . message ?. text ?? ''
188218 // Parse: /task <repo_url> <description...>
@@ -431,17 +461,28 @@ function startRealtimeBridge(): void {
431461 const job = await getJob ( event . job_id )
432462 if ( ! job ?. telegram_chat_id ) return
433463
464+ const chatId = job . telegram_chat_id
465+ const mode = chatNotifyMode . get ( chatId ) ?? 'verbose'
466+
467+ // In quiet mode, skip noisy events entirely
468+ if ( mode === 'quiet' && QUIET_EVENTS . has ( event . event_type ) ) return
469+
434470 const text = `<b>[${ job . id . slice ( 0 , 8 ) } ]</b> ${ formatJobEvent ( event ) } `
435471
472+ // In quiet mode, deliver silently unless this is a loud event
473+ const disableNotification = mode === 'quiet' && ! LOUD_EVENTS . has ( event . event_type )
474+
436475 // PR created events get the approval keyboard
437476 if ( event . event_type === 'pr_created' && job . pr_url ) {
438- await bot . api . sendMessage ( job . telegram_chat_id , text , {
477+ await bot . api . sendMessage ( chatId , text , {
439478 parse_mode : 'HTML' ,
440479 reply_markup : buildPrKeyboard ( job . id , job . pr_url ) ,
480+ disable_notification : disableNotification ,
441481 } )
442482 } else {
443- await bot . api . sendMessage ( job . telegram_chat_id , text , {
483+ await bot . api . sendMessage ( chatId , text , {
444484 parse_mode : 'HTML' ,
485+ disable_notification : disableNotification ,
445486 } )
446487 }
447488 } catch ( err ) {
@@ -458,16 +499,21 @@ function startRealtimeBridge(): void {
458499 if ( ! terminal . includes ( job . status ) ) return
459500
460501 try {
502+ const chatId = job . telegram_chat_id
503+ const mode = chatNotifyMode . get ( chatId ) ?? 'verbose'
461504 const text = formatJobStatus ( job )
462505
463506 if ( job . pr_url && job . status === JOB_STATUS . SUCCEEDED ) {
464- await bot . api . sendMessage ( job . telegram_chat_id , text , {
507+ await bot . api . sendMessage ( chatId , text , {
465508 parse_mode : 'HTML' ,
466509 reply_markup : buildPrKeyboard ( job . id , job . pr_url ) ,
467510 } )
468511 } else {
469- await bot . api . sendMessage ( job . telegram_chat_id , text , {
512+ // Terminal failure: respect quiet mode (silent delivery)
513+ const disableNotification = mode === 'quiet' && job . status === JOB_STATUS . FAILED
514+ await bot . api . sendMessage ( chatId , text , {
470515 parse_mode : 'HTML' ,
516+ disable_notification : disableNotification ,
471517 } )
472518 }
473519 } catch ( err ) {
0 commit comments