package inventory import ( "encoding/json" "os" "time" ) // Package represents a single installed package or application type Package struct { Name string `json:"name"` Version string `json:"version"` Source string `json:"source"` // homebrew, pip, npm, go, application Path string `json:"path,omitempty"` BundleID string `json:"bundle_id,omitempty"` } // SystemInfo contains macOS system information type SystemInfo struct { OS string `json:"os"` KernelRelease string `json:"kernel_release"` MacOSVersion string `json:"macos_version"` Hostname string `json:"hostname"` Username string `json:"username"` } // Inventory represents the full system inventory type Inventory struct { Timestamp time.Time `json:"timestamp"` System SystemInfo `json:"system"` Homebrew []Package `json:"homebrew"` Python []Package `json:"python"` Node []Package `json:"node"` Go []Package `json:"go"` Applications []Package `json:"applications"` } // LoadInventory reads the inventory JSON file func LoadInventory(path string) (*Inventory, error) { data, err := os.ReadFile(path) if err != nil { return nil, err } var inv Inventory if err := json.Unmarshal(data, &inv); err != nil { return nil, err } return &inv, nil } // AllPackages returns all packages as a flat slice func (i *Inventory) AllPackages() []Package { var all []Package all = append(all, i.Homebrew...) all = append(all, i.Python...) all = append(all, i.Node...) all = append(all, i.Go...) all = append(all, i.Applications...) return all } // CountPackages returns total number of packages func (i *Inventory) CountPackages() int { return len(i.AllPackages()) } // CountBySource returns count of packages by source type func (i *Inventory) CountBySource() map[string]int { counts := make(map[string]int) for _, pkg := range i.AllPackages() { counts[pkg.Source]++ } return counts }