@@ -13,6 +13,12 @@ import { program } from 'commander';
1313import { v4 as uuidv4 } from 'uuid' ;
1414import chalk from 'chalk' ;
1515import { initializeTracing , trace } from '../core/trace/index.js' ;
16+ import {
17+ generateSessionSummary ,
18+ formatSummaryMessage ,
19+ SessionContext ,
20+ } from '../hooks/session-summary.js' ;
21+ import { sendNotification } from '../hooks/sms-notify.js' ;
1622
1723// __filename and __dirname are provided by esbuild banner for ESM compatibility
1824
@@ -22,6 +28,7 @@ interface ClaudeSMConfig {
2228 defaultChrome: boolean ;
2329 defaultTracing: boolean ;
2430 defaultRemote: boolean ;
31+ defaultNotifyOnDone: boolean ;
2532}
2633
2734interface ClaudeConfig {
@@ -31,12 +38,14 @@ interface ClaudeConfig {
3138 useChrome: boolean ;
3239 useWorktree: boolean ;
3340 useRemote: boolean ;
41+ notifyOnDone: boolean ;
3442 contextEnabled: boolean ;
3543 branch ? : string ;
3644 task ? : string ;
3745 tracingEnabled: boolean ;
3846 verboseTracing: boolean ;
3947 claudeBin ? : string ;
48+ sessionStartTime: number ;
4049}
4150
4251const DEFAULT_SM_CONFIG : ClaudeSMConfig = {
@@ -45,6 +54,7 @@ const DEFAULT_SM_CONFIG: ClaudeSMConfig = {
4554 defaultChrome : false ,
4655 defaultTracing : true ,
4756 defaultRemote : false ,
57+ defaultNotifyOnDone : true ,
4858} ;
4959
5060function getConfigPath ( ) : string {
@@ -90,9 +100,11 @@ class ClaudeSM {
90100 useChrome : this . smConfig . defaultChrome ,
91101 useWorktree : this . smConfig . defaultWorktree ,
92102 useRemote : this . smConfig . defaultRemote ,
103+ notifyOnDone : this . smConfig . defaultNotifyOnDone ,
93104 contextEnabled : true ,
94105 tracingEnabled : this . smConfig . defaultTracing ,
95106 verboseTracing : false ,
107+ sessionStartTime : Date . now ( ) ,
96108 } ;
97109
98110 this . stackmemoryPath = this . findStackMemory ( ) ;
@@ -269,22 +281,24 @@ class ClaudeSM {
269281 try {
270282 console . log ( chalk . blue ( '📚 Loading previous context...' ) ) ;
271283
272- const cmd = `${ this . stackmemoryPath } context list --limit 5 --format json` ;
273- const output = execSync ( cmd , { encoding : 'utf8' } ) ;
274- const contexts = JSON . parse ( output ) ;
275-
276- if ( contexts . length > 0 ) {
277- console . log ( chalk . gray ( 'Recent context loaded:' ) ) ;
278- contexts . forEach (
279- ( ctx : { message : string ; metadata ?: { timestamp ?: string } } ) => {
280- console. log (
281- chalk . gray ( ` - ${ ctx . message } (${ ctx . metadata ?. timestamp } )` )
282- ) ;
283- }
284- ) ;
284+ // Use 'context show' command which outputs the current context stack
285+ const cmd = `${ this . stackmemoryPath } context show` ;
286+ const output = execSync ( cmd , {
287+ encoding : 'utf8' ,
288+ stdio : [ 'pipe' , 'pipe' , 'pipe' ] , // Capture stderr to suppress errors
289+ } ) ;
290+
291+ // Check if we got meaningful output (not empty or just headers)
292+ const lines = output
293+ . trim ( )
294+ . split ( '\n' )
295+ . filter ( ( l ) => l . trim ( ) ) ;
296+ if ( lines . length > 3 ) {
297+ // Has content beyond headers
298+ console . log ( chalk . gray ( 'Context stack loaded' ) ) ;
285299 }
286300 } catch {
287- // Silently continue
301+ // Silently continue - context loading is optional
288302 }
289303 }
290304
@@ -323,6 +337,58 @@ class ClaudeSM {
323337 }
324338 }
325339
340+ private async sendDoneNotification ( exitCode : number | null ) : Promise < void > {
341+ try {
342+ const context : SessionContext = {
343+ instanceId : this . config . instanceId ,
344+ exitCode,
345+ sessionStartTime : this . config . sessionStartTime ,
346+ worktreePath : this . config . worktreePath ,
347+ branch : this . config . branch ,
348+ task : this . config . task ,
349+ } ;
350+
351+ const summary = await generateSessionSummary ( context ) ;
352+ const message = formatSummaryMessage ( summary ) ;
353+
354+ console . log ( chalk . cyan ( '\nSending session summary via WhatsApp...' ) ) ;
355+
356+ // Build options from suggestions for interactive response
357+ const options = summary . suggestions . slice ( 0 , 4 ) . map ( ( s ) => ( {
358+ key : s . key ,
359+ label : s . label ,
360+ action : s . action ,
361+ } ) ) ;
362+
363+ const result = await sendNotification ( {
364+ type : 'task_complete' ,
365+ title : 'Claude Session Complete' ,
366+ message,
367+ prompt :
368+ options . length > 0
369+ ? {
370+ type : 'options' ,
371+ options,
372+ }
373+ : undefined ,
374+ } ) ;
375+
376+ if ( result . success ) {
377+ console . log ( chalk . green ( 'Notification sent successfully' ) ) ;
378+ } else {
379+ console . log (
380+ chalk . yellow ( `Notification not sent: ${ result . error || 'unknown' } ` )
381+ ) ;
382+ }
383+ } catch ( error ) {
384+ console . log (
385+ chalk . yellow (
386+ `Could not send notification: ${ error instanceof Error ? error . message : 'unknown' } `
387+ )
388+ ) ;
389+ }
390+ }
391+
326392 public async run ( args : string [ ] ) : Promise < void > {
327393 // Parse arguments
328394 const claudeArgs : string [ ] = [ ] ;
@@ -347,6 +413,13 @@ class ClaudeSM {
347413 case '--no-remote' :
348414 this . config . useRemote = false ;
349415 break ;
416+ case '--notify-done' :
417+ case '-n' :
418+ this . config . notifyOnDone = true ;
419+ break ;
420+ case '--no-notify-done' :
421+ this . config . notifyOnDone = false ;
422+ break ;
350423 case '--sandbox' :
351424 case '-s' :
352425 this . config . useSandbox = true ;
@@ -545,7 +618,7 @@ class ClaudeSM {
545618 } ) ;
546619
547620 // Handle exit
548- claude . on ( 'exit' , ( code ) => {
621+ claude . on ( 'exit' , async ( code ) => {
549622 // Save final context
550623 this . saveContext ( 'Claude session ended' , {
551624 action : 'session_end' ,
@@ -561,6 +634,11 @@ class ClaudeSM {
561634 console . log ( chalk . gray ( summary ) ) ;
562635 }
563636
637+ // Send notification when done (if enabled)
638+ if ( this . config . notifyOnDone || this . config . useRemote ) {
639+ await this . sendDoneNotification ( code ) ;
640+ }
641+
564642 // Offer to clean up worktree
565643 if ( this . config . worktreePath ) {
566644 console . log ( ) ;
@@ -624,6 +702,9 @@ configCmd
624702 console . log (
625703 ` defaultRemote: ${ config . defaultRemote ? chalk . green ( 'true' ) : chalk . gray ( 'false' ) } `
626704 ) ;
705+ console . log (
706+ ` defaultNotifyOnDone: ${ config . defaultNotifyOnDone ? chalk . green ( 'true' ) : chalk . gray ( 'false' ) } `
707+ ) ;
627708 console . log ( chalk . gray ( `\nConfig: ${ getConfigPath ( ) } ` ) ) ;
628709 } ) ;
629710
@@ -640,13 +721,17 @@ configCmd
640721 chrome : 'defaultChrome' ,
641722 tracing : 'defaultTracing' ,
642723 remote : 'defaultRemote' ,
724+ 'notify-done' : 'defaultNotifyOnDone' ,
725+ notifyondone : 'defaultNotifyOnDone' ,
643726 } ;
644727
645728 const configKey = keyMap [ key ] ;
646729 if ( ! configKey ) {
647730 console . log ( chalk . red ( `Unknown key: ${ key } ` ) ) ;
648731 console . log (
649- chalk . gray ( 'Valid keys: worktree, sandbox, chrome, tracing, remote' )
732+ chalk . gray (
733+ 'Valid keys: worktree, sandbox, chrome, tracing, remote, notify-done'
734+ )
650735 ) ;
651736 process . exit ( 1 ) ;
652737 }
@@ -696,12 +781,34 @@ configCmd
696781 console . log ( chalk . green ( 'Remote mode disabled by default' ) ) ;
697782 } ) ;
698783
784+ configCmd
785+ . command ( 'notify-done-on' )
786+ . description ( 'Enable WhatsApp notification when session ends (default)' )
787+ . action ( ( ) => {
788+ const config = loadSMConfig ( ) ;
789+ config . defaultNotifyOnDone = true ;
790+ saveSMConfig ( config ) ;
791+ console . log ( chalk . green ( 'Notify-on-done enabled by default' ) ) ;
792+ } ) ;
793+
794+ configCmd
795+ . command ( 'notify-done-off' )
796+ . description ( 'Disable notification when session ends' )
797+ . action ( ( ) => {
798+ const config = loadSMConfig ( ) ;
799+ config . defaultNotifyOnDone = false ;
800+ saveSMConfig ( config ) ;
801+ console . log ( chalk . green ( 'Notify-on-done disabled by default' ) ) ;
802+ } ) ;
803+
699804// Main command (default action when no subcommand)
700805program
701806 . option ( '-w, --worktree' , 'Create isolated worktree for this instance' )
702807 . option ( '-W, --no-worktree' , 'Disable worktree (override default)' )
703808 . option ( '-r, --remote' , 'Enable remote mode (WhatsApp for all questions)' )
704809 . option ( '--no-remote' , 'Disable remote mode (override default)' )
810+ . option ( '-n, --notify-done' , 'Send WhatsApp notification when session ends' )
811+ . option ( '--no-notify-done' , 'Disable notification when session ends' )
705812 . option ( '-s, --sandbox' , 'Enable sandbox mode (file/network restrictions)' )
706813 . option ( '-c, --chrome' , 'Enable Chrome automation' )
707814 . option ( '-a, --auto' , 'Automatically detect and apply best settings' )
0 commit comments