@@ -104,9 +104,7 @@ func runSnapshot(cmd *cobra.Command) error {
104104 if err != nil {
105105 return fmt .Errorf ("failed to save snapshot: %w" , err )
106106 }
107- fmt .Fprintln (os .Stderr )
108- fmt .Fprintln (os .Stderr , snapSuccessStyle .Render ("✓ Snapshot saved to " + path ))
109- fmt .Fprintln (os .Stderr )
107+ showLocalSaveSummary (snap , path )
110108 return nil
111109 }
112110
@@ -130,6 +128,9 @@ func runSnapshot(cmd *cobra.Command) error {
130128 return nil
131129 }
132130
131+ // --- SUMMARY PHASE ---
132+ showSnapshotSummary (edited )
133+
133134 // --- CONFIRM PHASE ---
134135 fmt .Fprintln (os .Stderr )
135136 upload , err := ui .Confirm ("Upload this snapshot to openboot.dev?" , false )
@@ -138,7 +139,7 @@ func runSnapshot(cmd *cobra.Command) error {
138139 }
139140
140141 if ! upload {
141- // Offer local save as fallback
142+ fmt . Fprintln ( os . Stderr )
142143 saveLocal , err := ui .Confirm ("Save snapshot locally instead?" , true )
143144 if err != nil {
144145 return err
@@ -148,11 +149,12 @@ func runSnapshot(cmd *cobra.Command) error {
148149 if err != nil {
149150 return fmt .Errorf ("failed to save snapshot: %w" , err )
150151 }
151- fmt . Fprintln ( os . Stderr , snapSuccessStyle . Render ( "✓ Snapshot saved to " + path ) )
152+ showLocalSaveSummary ( edited , path )
152153 } else {
154+ fmt .Fprintln (os .Stderr )
153155 fmt .Fprintln (os .Stderr , snapMutedStyle .Render ("Snapshot discarded." ))
156+ fmt .Fprintln (os .Stderr )
154157 }
155- fmt .Fprintln (os .Stderr )
156158 return nil
157159 }
158160
@@ -164,7 +166,7 @@ func runSnapshot(cmd *cobra.Command) error {
164166func captureWithUI () (* snapshot.Snapshot , error ) {
165167 fmt .Fprintln (os .Stderr )
166168
167- progress := ui .NewScanProgress (7 )
169+ progress := ui .NewScanProgress (8 )
168170
169171 snap , err := snapshot .CaptureWithProgress (func (step snapshot.ScanStep ) {
170172 progress .Update (step )
@@ -273,6 +275,110 @@ func uploadSnapshot(snap *snapshot.Snapshot) error {
273275 return nil
274276}
275277
278+ func showLocalSaveSummary (snap * snapshot.Snapshot , path string ) {
279+ fmt .Fprintln (os .Stderr )
280+ fmt .Fprintln (os .Stderr , snapSuccessStyle .Render ("✓ Snapshot saved successfully!" ))
281+ fmt .Fprintln (os .Stderr )
282+
283+ totalFormulae := len (snap .Packages .Formulae )
284+ totalCasks := len (snap .Packages .Casks )
285+ totalTaps := len (snap .Packages .Taps )
286+ totalNpm := len (snap .Packages .Npm )
287+
288+ fmt .Fprintf (os .Stderr , " %s %d formulae, %d casks, %d taps, %d npm\n " ,
289+ snapBoldStyle .Render ("Saved:" ),
290+ totalFormulae , totalCasks , totalTaps , totalNpm )
291+
292+ if snap .MatchedPreset != "" {
293+ matchRate := int (snap .CatalogMatch .MatchRate * 100 )
294+ fmt .Fprintf (os .Stderr , " %s Matches \" %s\" (%d%% similarity)\n " ,
295+ snapBoldStyle .Render ("Preset:" ),
296+ snap .MatchedPreset , matchRate )
297+ }
298+
299+ fmt .Fprintf (os .Stderr , " %s %s\n " ,
300+ snapBoldStyle .Render ("Location:" ),
301+ path )
302+
303+ fmt .Fprintln (os .Stderr )
304+ fmt .Fprintln (os .Stderr , snapBoldStyle .Render (" Restore this snapshot:" ))
305+ fmt .Fprintf (os .Stderr , " %s\n " , snapMutedStyle .Render ("openboot snapshot --import " + path ))
306+ fmt .Fprintln (os .Stderr )
307+ }
308+
309+ func showSnapshotSummary (snap * snapshot.Snapshot ) {
310+ fmt .Fprintln (os .Stderr )
311+ fmt .Fprintln (os .Stderr , snapTitleStyle .Render ("=== Snapshot Summary ===" ))
312+ fmt .Fprintln (os .Stderr )
313+
314+ totalFormulae := len (snap .Packages .Formulae )
315+ totalCasks := len (snap .Packages .Casks )
316+ totalTaps := len (snap .Packages .Taps )
317+ totalNpm := len (snap .Packages .Npm )
318+
319+ fmt .Fprintf (os .Stderr , " %s %d formulae, %d casks, %d taps, %d npm packages\n " ,
320+ snapBoldStyle .Render ("Packages:" ),
321+ totalFormulae , totalCasks , totalTaps , totalNpm )
322+
323+ if snap .MatchedPreset != "" {
324+ matchRate := int (snap .CatalogMatch .MatchRate * 100 )
325+ fmt .Fprintf (os .Stderr , " %s Matches \" %s\" (%d%% similarity)\n " ,
326+ snapBoldStyle .Render ("Preset:" ),
327+ snap .MatchedPreset , matchRate )
328+ } else {
329+ fmt .Fprintf (os .Stderr , " %s Custom configuration\n " ,
330+ snapBoldStyle .Render ("Preset:" ))
331+ }
332+
333+ omzStatus := "not installed"
334+ if snap .Shell .OhMyZsh {
335+ theme := snap .Shell .Theme
336+ if theme == "" {
337+ theme = "default"
338+ }
339+ pluginCount := len (snap .Shell .Plugins )
340+ omzStatus = fmt .Sprintf ("Oh-My-Zsh (%s theme, %d plugins)" , theme , pluginCount )
341+ }
342+ fmt .Fprintf (os .Stderr , " %s %s + %s\n " ,
343+ snapBoldStyle .Render ("Shell:" ),
344+ snap .Shell .Default , omzStatus )
345+
346+ if snap .Git .UserName != "" || snap .Git .UserEmail != "" {
347+ fmt .Fprintf (os .Stderr , " %s %s <%s>\n " ,
348+ snapBoldStyle .Render ("Git:" ),
349+ snap .Git .UserName , snap .Git .UserEmail )
350+ } else {
351+ fmt .Fprintf (os .Stderr , " %s Not configured\n " ,
352+ snapBoldStyle .Render ("Git:" ))
353+ }
354+
355+ if len (snap .DevTools ) > 0 {
356+ var toolNames []string
357+ for _ , tool := range snap .DevTools {
358+ toolNames = append (toolNames , tool .Name )
359+ }
360+ fmt .Fprintf (os .Stderr , " %s %s\n " ,
361+ snapBoldStyle .Render ("Dev Tools:" ),
362+ strings .Join (toolNames , ", " ))
363+ } else {
364+ fmt .Fprintf (os .Stderr , " %s None detected\n " ,
365+ snapBoldStyle .Render ("Dev Tools:" ))
366+ }
367+
368+ prefCount := len (snap .MacOSPrefs )
369+ fmt .Fprintf (os .Stderr , " %s %d preferences captured\n " ,
370+ snapBoldStyle .Render ("macOS:" ),
371+ prefCount )
372+
373+ fmt .Fprintln (os .Stderr )
374+ capturedTime := snap .CapturedAt .Format ("2006-01-02 15:04:05" )
375+ fmt .Fprintf (os .Stderr , " %s %s\n " ,
376+ snapMutedStyle .Render ("Captured:" ),
377+ snapMutedStyle .Render (capturedTime ))
378+
379+ fmt .Fprintln (os .Stderr )
380+ }
381+
276382func showSnapshotPreview (snap * snapshot.Snapshot ) {
277383 fmt .Fprintln (os .Stderr )
278384 fmt .Fprintln (os .Stderr , snapTitleStyle .Render ("=== Snapshot Preview ===" ))
0 commit comments