@@ -470,19 +470,28 @@ func (h *Handlers) interactiveRun(ctx context.Context, trainingRootFs *afero.Bas
470470
471471 postActions = append (postActions , internal.Action {Shortcut : 'q' , Action : "quit" })
472472
473- if h .loopState != nil {
474- // MCP mode: auto-continue. The MCP client already triggered
475- // the advance — no reason to block before running the solution.
476- continue
473+ postActionMap := map [rune ]loopAction {
474+ '\n' : loopActionRun ,
475+ 'q' : loopActionQuit ,
477476 }
478- promptResult := internal .Prompt (postActions , os .Stdin , os .Stdout )
479- if promptResult == 'q' {
480- os .Exit (0 )
477+ if currentExerciseConfig .IsOptional {
478+ postActionMap ['s' ] = loopActionSkip
481479 }
482480
483- if promptResult == 's' {
484- err = h .Skip (ctx )
485- if err != nil {
481+ postAction , fromMCP := h .waitForAction (
482+ postActions ,
483+ postActionMap ,
484+ map [mcppkg.CommandType ]loopAction {
485+ mcppkg .CmdRunSolution : loopActionRun ,
486+ },
487+ )
488+ ctx = withMCPTriggered (ctx , fromMCP )
489+
490+ if postAction == loopActionQuit {
491+ os .Exit (0 )
492+ }
493+ if postAction == loopActionSkip {
494+ if err := h .Skip (ctx ); err != nil {
486495 return err
487496 }
488497 }
@@ -664,6 +673,7 @@ const (
664673 loopActionQuit // Quit the loop
665674 loopActionResetExercise // Reset exercise to clean files
666675 loopActionUpdate // Update the CLI binary and exit
676+ loopActionSkip // Skip current (optional) exercise
667677)
668678
669679// backgroundUpdateCheck polls for a newer CLI release while the interactive
0 commit comments