55 "os"
66 "path/filepath"
77 "runtime"
8+ "sort"
89 "strings"
910 "time"
1011
@@ -633,7 +634,47 @@ type ResourceSize struct {
633634 ServerSize int64
634635 ClientSize int64
635636 TotalSize int64
636- IsViews bool // true if this is a views/UI bundle
637+ IsViews bool // true if this is a views/UI bundle
638+ Framework string // framework used (react, vue, svelte, vanilla) - only for views
639+ }
640+
641+ // detectFramework detects the framework used in a views directory
642+ func detectFramework (viewPath string ) string {
643+ // Check for framework-specific files
644+ hasReact := false
645+ hasVue := false
646+ hasSvelte := false
647+
648+ filepath .WalkDir (viewPath , func (path string , d os.DirEntry , err error ) error {
649+ if err != nil || d .IsDir () {
650+ if d != nil && d .Name () == "node_modules" {
651+ return filepath .SkipDir
652+ }
653+ return nil
654+ }
655+ ext := filepath .Ext (d .Name ())
656+ switch ext {
657+ case ".tsx" , ".jsx" :
658+ hasReact = true
659+ case ".vue" :
660+ hasVue = true
661+ case ".svelte" :
662+ hasSvelte = true
663+ }
664+ return nil
665+ })
666+
667+ // Return detected framework (prioritize by specificity)
668+ if hasSvelte {
669+ return "svelte"
670+ }
671+ if hasVue {
672+ return "vue"
673+ }
674+ if hasReact {
675+ return "react"
676+ }
677+ return "vanilla"
637678}
638679
639680// formatSize formats bytes into human readable format (KB/MB)
@@ -686,10 +727,13 @@ func (b *Builder) getResourceSizes(results []BuildResult) []ResourceSize {
686727 if r .Task .Type == TypeViews {
687728 totalSize := getDirSize (resourceDir )
688729 if totalSize > 0 {
730+ // Detect framework from source path
731+ framework := detectFramework (r .Task .Path )
689732 sizes = append (sizes , ResourceSize {
690733 Name : resourceName ,
691734 TotalSize : totalSize ,
692735 IsViews : true ,
736+ Framework : framework ,
693737 })
694738 }
695739 continue
@@ -719,14 +763,30 @@ func (b *Builder) getResourceSizes(results []BuildResult) []ResourceSize {
719763 }
720764 }
721765
766+ // Sort sizes to group related resources together (core, core/ui, xchat, xchat/ui, etc.)
767+ sort .Slice (sizes , func (i , j int ) bool {
768+ // Extract base names (before any /)
769+ baseI := strings .Split (sizes [i ].Name , "/" )[0 ]
770+ baseJ := strings .Split (sizes [j ].Name , "/" )[0 ]
771+
772+ // If different base names, sort alphabetically by base
773+ if baseI != baseJ {
774+ return baseI < baseJ
775+ }
776+
777+ // Same base: main resource comes before sub-resources (e.g., core before core/ui)
778+ return len (sizes [i ].Name ) < len (sizes [j ].Name )
779+ })
780+
722781 return sizes
723782}
724783
725784// showSummary displays the build summary
726785func (b * Builder ) showSummary (results []BuildResult ) {
727- // Count unique resources and standalones separately
786+ // Count unique resources, standalones, and UIs separately
728787 successResources := make (map [string ]struct {})
729788 successStandalones := make (map [string ]struct {})
789+ successUIs := make (map [string ]struct {})
730790 failedResources := make (map [string ]struct {})
731791 failedStandalones := make (map [string ]struct {})
732792 totalDuration := time .Duration (0 )
@@ -738,7 +798,9 @@ func (b *Builder) showSummary(results []BuildResult) {
738798 if r .Success {
739799 if isStandalone {
740800 successStandalones [baseResource ] = struct {}{}
741- } else if r .Task .Type != TypeViews { // Don't count views separately
801+ } else if r .Task .Type == TypeViews {
802+ successUIs [r .Task .ResourceName ] = struct {}{}
803+ } else {
742804 successResources [baseResource ] = struct {}{}
743805 }
744806 totalDuration += r .Duration
@@ -753,6 +815,7 @@ func (b *Builder) showSummary(results []BuildResult) {
753815
754816 successResourceCount := len (successResources )
755817 successStandaloneCount := len (successStandalones )
818+ successUICount := len (successUIs )
756819 failResourceCount := len (failedResources )
757820 failStandaloneCount := len (failedStandalones )
758821 failCount := failResourceCount + failStandaloneCount
@@ -771,12 +834,18 @@ func (b *Builder) showSummary(results []BuildResult) {
771834 boxContent .WriteString ("Build completed successfully!\n \n " )
772835
773836 // Show counts based on what's present
774- if successResourceCount > 0 && successStandaloneCount > 0 {
775- boxContent .WriteString (fmt .Sprintf ("Resources: %d | Standalones: %d\n " , successResourceCount , successStandaloneCount ))
776- } else if successResourceCount > 0 {
777- boxContent .WriteString (fmt .Sprintf ("Resources: %d\n " , successResourceCount ))
778- } else if successStandaloneCount > 0 {
779- boxContent .WriteString (fmt .Sprintf ("Standalones: %d\n " , successStandaloneCount ))
837+ var countParts []string
838+ if successResourceCount > 0 {
839+ countParts = append (countParts , fmt .Sprintf ("Resources: %d" , successResourceCount ))
840+ }
841+ if successUICount > 0 {
842+ countParts = append (countParts , fmt .Sprintf ("UIs: %d" , successUICount ))
843+ }
844+ if successStandaloneCount > 0 {
845+ countParts = append (countParts , fmt .Sprintf ("Standalones: %d" , successStandaloneCount ))
846+ }
847+ if len (countParts ) > 0 {
848+ boxContent .WriteString (strings .Join (countParts , " | " ) + "\n " )
780849 }
781850
782851 boxContent .WriteString (fmt .Sprintf ("Time: %s\n " , totalDuration .Round (time .Millisecond )))
@@ -794,10 +863,14 @@ func (b *Builder) showSummary(results []BuildResult) {
794863 for _ , s := range sizes {
795864 nameStyle := lipgloss .NewStyle ().Foreground (lipgloss .Color ("#FFFFFF" ))
796865 if s .IsViews {
797- // Views show only total size (includes JS, CSS, HTML, assets)
866+ // Views show only total size (includes JS, CSS, HTML, assets) + framework
798867 totalStr := lipgloss .NewStyle ().Foreground (lipgloss .Color ("#E879F9" )).Render (formatSize (s .TotalSize ))
799- boxContent .WriteString (fmt .Sprintf ("%s Total: %s\n " ,
800- nameStyle .Render (fmt .Sprintf ("%-14s" , s .Name )), totalStr ))
868+ frameworkStr := ""
869+ if s .Framework != "" {
870+ frameworkStr = lipgloss .NewStyle ().Foreground (lipgloss .Color ("#6B7280" )).Render (fmt .Sprintf (" (%s)" , s .Framework ))
871+ }
872+ boxContent .WriteString (fmt .Sprintf ("%s Total: %s%s\n " ,
873+ nameStyle .Render (fmt .Sprintf ("%-14s" , s .Name )), totalStr , frameworkStr ))
801874 } else {
802875 serverStr := lipgloss .NewStyle ().Foreground (lipgloss .Color ("#6B7280" )).Render ("-" )
803876 clientStr := lipgloss .NewStyle ().Foreground (lipgloss .Color ("#6B7280" )).Render ("-" )
@@ -821,14 +894,18 @@ func (b *Builder) showSummary(results []BuildResult) {
821894 boxContent .WriteString ("Build completed with errors\n \n " )
822895
823896 // Show success counts
824- if successResourceCount > 0 || successStandaloneCount > 0 {
825- if successResourceCount > 0 && successStandaloneCount > 0 {
826- boxContent .WriteString (fmt .Sprintf ("✓ Success: Resources: %d | Standalones: %d\n " , successResourceCount , successStandaloneCount ))
827- } else if successResourceCount > 0 {
828- boxContent .WriteString (fmt .Sprintf ("✓ Success: Resources: %d\n " , successResourceCount ))
829- } else if successStandaloneCount > 0 {
830- boxContent .WriteString (fmt .Sprintf ("✓ Success: Standalones: %d\n " , successStandaloneCount ))
897+ if successResourceCount > 0 || successStandaloneCount > 0 || successUICount > 0 {
898+ var successParts []string
899+ if successResourceCount > 0 {
900+ successParts = append (successParts , fmt .Sprintf ("Resources: %d" , successResourceCount ))
831901 }
902+ if successUICount > 0 {
903+ successParts = append (successParts , fmt .Sprintf ("UIs: %d" , successUICount ))
904+ }
905+ if successStandaloneCount > 0 {
906+ successParts = append (successParts , fmt .Sprintf ("Standalones: %d" , successStandaloneCount ))
907+ }
908+ boxContent .WriteString (fmt .Sprintf ("✓ Success: %s\n " , strings .Join (successParts , " | " )))
832909 }
833910
834911 // Show fail counts
@@ -1030,6 +1107,12 @@ func (m buildModel) renderFinal() string {
10301107 errMsg = fmt .Sprintf (": %v" , ts .result .Error )
10311108 }
10321109 b .WriteString (fmt .Sprintf ("%s [%s] failed%s\n " , ui .Error ("✗" ), ts .task .ResourceName , errMsg ))
1110+ // Show build output for failed tasks (contains detailed error messages)
1111+ if ts .result != nil && ts .result .Output != "" {
1112+ b .WriteString (ui .Muted ("Build output:\n " ))
1113+ b .WriteString (ts .result .Output )
1114+ b .WriteString ("\n " )
1115+ }
10331116 default :
10341117 b .WriteString (fmt .Sprintf ("○ [%s] skipped\n " , ts .task .ResourceName ))
10351118 }
0 commit comments