@@ -26,7 +26,8 @@ import (
2626
2727// CreateCommitMsg launches the interactive flow for reviewing, regenerating,
2828// editing, and accepting AI-generated commit messages in the current repo.
29- func CreateCommitMsg () {
29+ // If dryRun is true, it displays the prompt without making an API call.
30+ func CreateCommitMsg (dryRun bool ) {
3031 // Validate COMMIT_LLM and required API keys
3132 useLLM , err := store .DefaultLLMKey ()
3233 if err != nil {
@@ -94,6 +95,13 @@ func CreateCommitMsg() {
9495 return
9596 }
9697
98+ // Handle dry-run mode: display what would be sent to LLM without making API call
99+ if dryRun {
100+ pterm .Println ()
101+ displayDryRunInfo (commitLLM , config , changes , apiKey )
102+ return
103+ }
104+
97105 pterm .Println ()
98106 spinnerGenerating , err := pterm .DefaultSpinner .
99107 WithSequence ("⠋" , "⠙" , "⠹" , "⠸" , "⠼" , "⠴" , "⠦" , "⠧" , "⠇" , "⠏" ).
@@ -425,3 +433,96 @@ func displayProviderError(provider types.LLMProvider, err error) {
425433 pterm .Error .Printf ("LLM API error: %v\n " , err )
426434 }
427435}
436+
437+ // displayDryRunInfo shows what would be sent to the LLM without making an API call
438+ func displayDryRunInfo (provider types.LLMProvider , config * types.Config , changes string , apiKey string ) {
439+ pterm .DefaultHeader .WithFullWidth ().
440+ WithBackgroundStyle (pterm .NewStyle (pterm .BgBlue )).
441+ WithTextStyle (pterm .NewStyle (pterm .FgWhite , pterm .Bold )).
442+ Println ("DRY RUN MODE - Preview Only" )
443+
444+ pterm .Println ()
445+ pterm .Info .Println ("This is a dry-run. No API call will be made to the LLM provider." )
446+ pterm .Println ()
447+
448+ // Display provider information
449+ pterm .DefaultSection .Println ("LLM Provider Configuration" )
450+ providerInfo := [][]string {
451+ {"Provider" , provider .String ()},
452+ }
453+
454+ // Add provider-specific info
455+ switch provider {
456+ case types .ProviderOllama :
457+ url := apiKey
458+ if strings .TrimSpace (url ) == "" {
459+ url = os .Getenv ("OLLAMA_URL" )
460+ if url == "" {
461+ url = "http://localhost:11434/api/generate"
462+ }
463+ }
464+ model := os .Getenv ("OLLAMA_MODEL" )
465+ if model == "" {
466+ model = "llama3.1"
467+ }
468+ providerInfo = append (providerInfo , []string {"Ollama URL" , url })
469+ providerInfo = append (providerInfo , []string {"Model" , model })
470+ case types .ProviderGrok :
471+ providerInfo = append (providerInfo , []string {"API Endpoint" , config .GrokAPI })
472+ providerInfo = append (providerInfo , []string {"API Key" , maskAPIKey (apiKey )})
473+ default :
474+ providerInfo = append (providerInfo , []string {"API Key" , maskAPIKey (apiKey )})
475+ }
476+
477+ pterm .DefaultTable .WithHasHeader (false ).WithData (providerInfo ).Render ()
478+
479+ pterm .Println ()
480+
481+ // Build and display the prompt
482+ opts := & types.GenerationOptions {Attempt : 1 }
483+ prompt := types .BuildCommitPrompt (changes , opts )
484+
485+ pterm .DefaultSection .Println ("Prompt That Would Be Sent" )
486+ pterm .Println ()
487+
488+ // Display prompt in a box
489+ promptBox := pterm .DefaultBox .
490+ WithTitle ("Full LLM Prompt" ).
491+ WithTitleTopCenter ().
492+ WithBoxStyle (pterm .NewStyle (pterm .FgCyan ))
493+ promptBox .Println (prompt )
494+
495+ pterm .Println ()
496+
497+ // Display changes statistics
498+ pterm .DefaultSection .Println ("Changes Summary" )
499+ linesCount := len (strings .Split (changes , "\n " ))
500+ charsCount := len (changes )
501+
502+ statsData := [][]string {
503+ {"Total Lines" , fmt .Sprintf ("%d" , linesCount )},
504+ {"Total Characters" , fmt .Sprintf ("%d" , charsCount )},
505+ {"Prompt Size (approx)" , fmt .Sprintf ("%d tokens" , estimateTokens (prompt ))},
506+ }
507+ pterm .DefaultTable .WithHasHeader (false ).WithData (statsData ).Render ()
508+
509+ pterm .Println ()
510+ pterm .Success .Println ("Dry-run complete. To generate actual commit message, run without --dry-run flag." )
511+ }
512+
513+ // maskAPIKey masks the API key for display purposes
514+ func maskAPIKey (apiKey string ) string {
515+ if len (apiKey ) == 0 {
516+ return "[NOT SET]"
517+ }
518+ if len (apiKey ) <= 8 {
519+ return strings .Repeat ("*" , len (apiKey ))
520+ }
521+ // Show first 4 and last 4 characters
522+ return apiKey [:4 ] + strings .Repeat ("*" , len (apiKey )- 8 ) + apiKey [len (apiKey )- 4 :]
523+ }
524+
525+ // estimateTokens provides a rough estimate of token count (1 token ≈ 4 characters)
526+ func estimateTokens (text string ) int {
527+ return len (text ) / 4
528+ }
0 commit comments