Files
simslim-mirror/profiles.go
Interlap ffd3a13d34 refactor: split into an importable library and a cmd/simslim CLI (#14)
The repo root becomes `package simslim`, an importable library holding every
piece of slimming logic; the CLI moves to `cmd/simslim`. Previously everything
was `package main`, so nothing here could be imported at all.

The library carries no external dependencies — urfave/cli stays on the CLI side,
along with all terminal-facing code: the interactive profile wizard, writeJSON,
truncate/humanBytes, fatal and usage. The library never writes to stdout; it
returns values and reports progress through the Reporter callback.

Renames forced by collisions with existing types: status() -> ReadStatus,
statusForDevice() -> ReadStatusForDevice, diskCleanupPlan() -> PlanDiskCleanup.
The shutdown/boot timeouts move to simctl.go as ShutdownTimeout/BootTimeout.

`go install` gains a path element: github.com/mobai-app/simslim/cmd/simslim.
The installed binary is still named simslim, and -X main.version still applies.
packaging/homebrew/simslim.rb.in is updated to match, since std_go_args passes
no package path.

Verified live against a real simulator: list, profiles, status, doctor, size,
disk-plan, measure, boot, shutdown, on, off, on --except, on --profile, clone,
rename, delete and the interactive wizard all behave identically to the previous
build. JSON output, human output, help text and exit codes are unchanged.
2026-07-23 12:39:20 +02:00

426 lines
13 KiB
Go

package simslim
import "sort"
// Category groups launchd daemon labels that a slim boot disables together.
type Category struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Downside string `json:"downside"`
ApproxMemoryMB int `json:"approxMemoryMB"`
Labels []string `json:"labels"`
ServiceDescriptions map[string]string `json:"serviceDescriptions"`
AlwaysEnabled []AlwaysEnabledService `json:"alwaysEnabled,omitempty"`
}
// AlwaysEnabledService is shown alongside a category for transparency but is
// never included in a slim profile. Earlier versions may have disabled it, so
// it remains in the mutation allowlist solely to repair that legacy state.
type AlwaysEnabledService struct {
Label string `json:"label"`
Reason string `json:"reason"`
}
// Categories is the complete allowlist of daemons a profile may disable.
// ApproxMemoryMB values are rounded median increases in phys_footprint when
// only that category is kept on versus a fully slim iOS 26.5 clean boot. The
// estimates vary by runtime and workload and are not additive.
var Categories = []Category{
{
ID: "widgets",
Name: "Widgets & Wallpaper",
Description: "Home and lock screen posters, widgets, and Live Activities.",
Downside: "Home and Lock Screen widgets, wallpaper posters, and Live Activities stop updating.",
ApproxMemoryMB: 675,
Labels: []string{
"com.apple.PosterBoard",
"com.apple.chronod",
"com.apple.liveactivitiesd",
},
},
{
ID: "siri",
Name: "Siri & Intelligence",
Description: "Siri, Apple Intelligence, speech, and on-device ML model services.",
Downside: "Siri, speech features, and Apple Intelligence services are unavailable.",
ApproxMemoryMB: 265,
Labels: []string{
"com.apple.assistantd",
"com.apple.assistant_cdmd",
"com.apple.assistant_service",
"com.apple.siriactionsd",
"com.apple.siriinferenced",
"com.apple.siriknowledged",
"com.apple.sirittsd",
"com.apple.siri.context.service",
"com.apple.siri.acousticsignature",
"com.apple.corespeechd",
"com.apple.voiced",
"com.apple.voicebankingd",
"com.apple.speechmodeltrainingd",
"com.apple.intelligenceplatformd",
"com.apple.intelligencecontextd",
"com.apple.intelligenceflowd",
"com.apple.intelligencetasksd",
"com.apple.generativeexperiencesd",
"com.apple.knowledgeconstructiond",
"com.apple.naturallanguaged",
"com.apple.textunderstandingd",
"com.apple.modelcatalogd",
"com.apple.modelmanagerd",
"com.apple.mlhostd",
"com.apple.mlruntimed",
"com.apple.suggestd",
"com.apple.parsecd",
"com.apple.parsec-fbf",
"com.apple.proactiveeventtrackerd",
},
},
{
ID: "search",
Name: "Spotlight & Search",
Description: "On-device Spotlight and in-Settings search services.",
Downside: "Spotlight and Settings search return no results.",
ApproxMemoryMB: 50,
Labels: []string{
"com.apple.searchd",
"com.apple.searchtoold",
"com.apple.spotlightknowledged",
"com.apple.spotlightknowledged.updater",
"com.apple.corespotlightservice",
},
},
{
ID: "icloud",
Name: "iCloud & Apple Account",
Description: "iCloud sync, Apple Account, keychain, and backup services.",
Downside: "iCloud sync, Apple Account, Keychain, and backup workflows will not work.",
ApproxMemoryMB: 100,
Labels: []string{
"com.apple.appleaccountd",
"com.apple.appleaccounttransparencyd",
"com.apple.appleidsetupd",
"com.apple.akd",
"com.apple.amsaccountsd",
"com.apple.amsengagementd",
"com.apple.amsondevicestoraged",
"com.apple.cloudd",
"com.apple.cloudphotod",
"com.apple.ckdiscretionaryd",
"com.apple.cloudsettingssyncagent",
"com.apple.bird",
"com.apple.syncdefaultsd",
"com.apple.cdpd",
"com.apple.sosd",
"com.apple.SecureBackupDaemon",
"com.apple.TrustedPeersHelper",
"com.apple.protectedcloudstorage.protectedcloudkeysyncing",
"com.apple.icloudmailagent",
"com.apple.icloudsubscriptionoptimizerd",
"com.apple.communicationtrustd",
},
},
{
ID: "store",
Name: "App Store, Push & Media",
Description: "App Store, push notification, StoreKit, and media services.",
Downside: "Remote push notifications and StoreKit or App Store testing will not work.",
ApproxMemoryMB: 80,
Labels: []string{
"com.apple.appstored",
"com.apple.appstorecomponentsd",
"com.apple.apsd",
"com.apple.itunescloudd",
"com.apple.itunesstored",
"com.apple.storekitd",
"com.apple.videosubscriptionsd",
"com.apple.assetsubscriptiond",
"com.apple.musicd",
},
},
{
ID: "pim",
Name: "Mail, Calendar & Contacts",
Description: "Mail, Calendar, Contacts, Reminders, and related sync services.",
Downside: "Contacts, Calendar, Reminders, and Mail-backed pickers or sync may fail.",
ApproxMemoryMB: 80,
Labels: []string{
"com.apple.email.maild",
"com.apple.exchangesyncd",
"com.apple.dataaccess.dataaccessd",
"com.apple.calaccessd",
"com.apple.remindd",
"com.apple.contactsd",
"com.apple.contacts.postersyncd",
"com.apple.peopled",
},
},
{
ID: "web",
Name: "Safari Sync & Web Services",
Description: "Safari sync, web push, privacy, and universal-link services.",
Downside: "Universal links and Safari sync or background web services will not work.",
ApproxMemoryMB: 50,
Labels: []string{
"com.apple.SafariBookmarksSyncAgent",
"com.apple.Safari.History",
"com.apple.Safari.passwordbreachd",
"com.apple.Safari.SafeBrowsing.Service",
"com.apple.safarifetcherd",
"com.apple.WebBookmarks.webbookmarksd",
"com.apple.webkit.adattributiond",
"com.apple.webkit.webpushd",
"com.apple.webprivacyd",
"com.apple.swcd",
},
},
{
ID: "family",
Name: "Family & Screen Time",
Description: "Family Sharing, Screen Time, and usage tracking.",
Downside: "Family Sharing, Screen Time, and usage tracking stop working.",
ApproxMemoryMB: 65,
Labels: []string{
"com.apple.familycircled",
"com.apple.FamilyControlsAgent",
"com.apple.familynotification",
"com.apple.askpermissiond",
"com.apple.asktod",
"com.apple.ScreenTimeAgent",
"com.apple.ScreenTimeSettingsAgent",
"com.apple.UsageTrackingAgent",
},
},
{
ID: "health",
Name: "Health, Home & Fitness",
Description: "HealthKit, HomeKit, and Fitness services.",
Downside: "HealthKit, HomeKit, and Fitness integrations will not work.",
ApproxMemoryMB: 135,
Labels: []string{
"com.apple.healthd",
"com.apple.healthappd",
"com.apple.healthcontentd",
"com.apple.healtheventsd",
"com.apple.healthrecordsd",
"com.apple.finhealthd",
"com.apple.homed",
"com.apple.homeeventsd",
"com.apple.fitcore",
"com.apple.fitcore.session",
"com.apple.fitnesscoachingd",
"com.apple.fitnessintelligenced",
"com.apple.activityawardsd",
"com.apple.activitysharingd",
},
},
{
ID: "photos",
Name: "Photos & Media Analysis",
Description: "Photos library, photo analysis, and media analysis services.",
Downside: "Photo picker, Photos-library workflows, and media analysis may fail.",
ApproxMemoryMB: 60,
Labels: []string{
"com.apple.photoanalysisd",
"com.apple.photosface",
"com.apple.mediaanalysisd",
"com.apple.mediaanalysisd.service",
"com.apple.mediastream.mstreamd",
"com.apple.medialibraryd",
"com.apple.assetsd",
"com.apple.assetsd.nebulad",
},
},
{
ID: "apps",
Name: "News, Weather, Maps & Games",
Description: "News, Weather, Maps, Tips, and game services.",
Downside: "News, Weather, Maps background data, and game-controller services are unavailable.",
ApproxMemoryMB: 90,
Labels: []string{
"com.apple.newsd",
"com.apple.weatherd",
"com.apple.Maps.mapssyncd",
"com.apple.Maps.mapspushd",
"com.apple.Maps.geocorrectiond",
"com.apple.maps.destinationd",
"com.apple.MapKit.SnapshotService",
"com.apple.jetpackassetd",
"com.apple.tipsd",
"com.apple.gamed",
"com.apple.gamesaved",
"com.apple.GameController.gamecontrollerd",
},
},
{
ID: "messaging",
Name: "Messaging & FaceTime",
Description: "iMessage, FaceTime, call, and identity services.",
Downside: "iMessage, FaceTime, and related identity services will not work.",
ApproxMemoryMB: 60,
Labels: []string{
"com.apple.identityservicesd",
"com.apple.ids_simd",
"com.apple.imautomatichistorydeletionagent",
"com.apple.imcore.imtransferagent",
"com.apple.imdpersistence.IMDPersistenceAgent",
"com.apple.facetimemessagestored",
"com.apple.telephonyutilities.callservicesd",
},
},
{
ID: "connectivity",
Name: "Sharing & Device Connectivity",
Description: "AirDrop, Continuity, CarPlay, Watch, and Find My services.",
Downside: "AirDrop, Continuity, CarPlay, Watch, and Find My connectivity will not work.",
ApproxMemoryMB: 65,
Labels: []string{
"com.apple.rapportd",
"com.apple.companiond",
"com.apple.carkitd",
"com.apple.wcd",
"com.apple.tvremoted",
"com.apple.avatarsd",
"com.apple.stickersd",
"com.apple.sociallayerd",
"com.apple.announced",
"com.apple.navd",
"com.apple.findmy.findmylocated",
},
AlwaysEnabled: []AlwaysEnabledService{
{
Label: "com.apple.sharingd",
Reason: "Required for system share sheets.",
},
},
},
{
ID: "telemetry",
Name: "Ads, Diagnostics & Telemetry",
Description: "DeviceCheck, ad privacy, analytics, diagnostics, and feedback services.",
Downside: "DeviceCheck plus analytics, diagnostics, and feedback services are unavailable.",
ApproxMemoryMB: 105,
Labels: []string{
"com.apple.ap.adprivacyd",
"com.apple.ap.promotedcontentd",
"com.apple.diagnosticextensionsd",
"com.apple.feedbackd",
"com.apple.rtcreportingd",
"com.apple.securityuploadd",
"com.apple.geoanalyticsd",
"com.apple.triald",
"com.apple.followupd",
"com.apple.purplebuddy.budd",
"com.apple.devicecheckd",
},
},
{
ID: "other",
Name: "Other Background Services",
Description: "Wallet, business services, assets, and miscellaneous background daemons.",
Downside: "Wallet, merchant, business, asset, and miscellaneous background services are unavailable.",
ApproxMemoryMB: 195,
Labels: []string{
"com.apple.financed",
"com.apple.passd",
"com.apple.merchantd",
"com.apple.coreidvd",
"com.apple.businessservicesd",
"com.apple.deviceaccessd",
"com.apple.replicatord",
"com.apple.linkd",
"com.apple.ind",
"com.apple.storagedatad",
"com.apple.StatusKitAgent",
"com.apple.countryd",
"com.apple.mobileassetd",
"com.apple.managedconfiguration.passcodenagd",
},
},
}
func CategoryByID(id string) (Category, bool) {
for _, c := range Categories {
if c.ID == id {
return c, true
}
}
return Category{}, false
}
// slimmableSet is every label a service profile may disable.
func SlimmableSet() map[string]bool {
set := make(map[string]bool)
for _, c := range Categories {
for _, l := range c.Labels {
set[l] = true
}
}
return set
}
// managedSet is the complete mutation allowlist. Most labels are slimmable;
// required labels may only transition back to enabled for compatibility.
func managedSet() map[string]bool {
set := SlimmableSet()
for _, category := range Categories {
for _, service := range category.AlwaysEnabled {
set[service.Label] = true
}
}
return set
}
// Profile selects which managed daemons a slim boot should disable.
type Profile struct {
ExceptCategories map[string]bool // category IDs to leave fully enabled
Keep map[string]bool // individual labels to leave enabled
}
// desired returns the labels this profile wants disabled.
func (p Profile) Desired() map[string]bool {
set := make(map[string]bool)
for _, c := range Categories {
if p.ExceptCategories[c.ID] {
continue
}
for _, l := range c.Labels {
if p.Keep[l] {
continue
}
set[l] = true
}
}
return set
}
// delta returns the launchctl transitions to move from current to desired,
// scoped to managed labels. Labels outside managed are never touched: a
// non-managed desired label is ignored, and a non-managed label that is already
// disabled is left disabled. Empty results mean the device is already correct.
func delta(current, desired, managed map[string]bool) (toDisable, toEnable []string) {
dis := map[string]bool{}
for l := range desired {
if managed[l] && !current[l] {
dis[l] = true
}
}
en := map[string]bool{}
for l := range current {
if managed[l] && !desired[l] {
en[l] = true
}
}
return keys(dis), keys(en)
}
func keys(set map[string]bool) []string {
out := make([]string, 0, len(set))
for k := range set {
out = append(out, k)
}
sort.Strings(out)
return out
}