@devo-bmad-custom/agent-orchestration 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/installer.js +33 -0
- package/package.json +1 -1
- package/src/.agents/skills/audit-website/README.md +20 -20
- package/src/.agents/skills/audit-website/SKILL.md +470 -470
- package/src/.agents/skills/audit-website/agents/openai.yaml +6 -6
- package/src/.agents/skills/audit-website/assets/icon-small.svg +41 -41
- package/src/.agents/skills/audit-website/references/OUTPUT-FORMAT.md +250 -250
- package/src/.agents/skills/clean-code-standards/SKILL.md +104 -104
- package/src/.agents/skills/excalidraw-dark-standard/SKILL.md +281 -281
- package/src/.agents/skills/frontend-responsive-design-standards/SKILL.md +434 -434
- package/src/.agents/skills/java-fundamentals/SKILL.md +116 -116
- package/src/.agents/skills/java-performance/SKILL.md +119 -119
- package/src/.agents/skills/next-best-practices/SKILL.md +153 -153
- package/src/.agents/skills/next-best-practices/async-patterns.md +87 -87
- package/src/.agents/skills/next-best-practices/bundling.md +180 -180
- package/src/.agents/skills/next-best-practices/data-patterns.md +297 -297
- package/src/.agents/skills/next-best-practices/debug-tricks.md +105 -105
- package/src/.agents/skills/next-best-practices/directives.md +73 -73
- package/src/.agents/skills/next-best-practices/error-handling.md +227 -227
- package/src/.agents/skills/next-best-practices/file-conventions.md +140 -140
- package/src/.agents/skills/next-best-practices/font.md +245 -245
- package/src/.agents/skills/next-best-practices/functions.md +108 -108
- package/src/.agents/skills/next-best-practices/hydration-error.md +91 -91
- package/src/.agents/skills/next-best-practices/image.md +173 -173
- package/src/.agents/skills/next-best-practices/metadata.md +301 -301
- package/src/.agents/skills/next-best-practices/parallel-routes.md +287 -287
- package/src/.agents/skills/next-best-practices/route-handlers.md +146 -146
- package/src/.agents/skills/next-best-practices/rsc-boundaries.md +159 -159
- package/src/.agents/skills/next-best-practices/runtime-selection.md +39 -39
- package/src/.agents/skills/next-best-practices/scripts.md +141 -141
- package/src/.agents/skills/next-best-practices/self-hosting.md +371 -371
- package/src/.agents/skills/next-best-practices/suspense-boundaries.md +67 -67
- package/src/.agents/skills/nextjs-app-router-patterns/SKILL.md +537 -537
- package/src/.agents/skills/postgresql-optimization/SKILL.md +404 -404
- package/src/.agents/skills/python-backend/SKILL.md +153 -153
- package/src/.agents/skills/python-fundamentals/SKILL.md +234 -234
- package/src/.agents/skills/python-performance/SKILL.md +404 -404
- package/src/.agents/skills/react-expert/SKILL.md +335 -335
- package/src/.agents/skills/redis-best-practices/SKILL.md +438 -438
- package/src/.agents/skills/security-best-practices/SKILL.md +288 -288
- package/src/.agents/skills/security-review/LICENSE +22 -22
- package/src/.agents/skills/security-review/SKILL.md +312 -312
- package/src/.agents/skills/security-review/infrastructure/docker.md +432 -432
- package/src/.agents/skills/security-review/languages/javascript.md +388 -388
- package/src/.agents/skills/security-review/languages/python.md +363 -363
- package/src/.agents/skills/security-review/references/api-security.md +519 -519
- package/src/.agents/skills/security-review/references/authentication.md +353 -353
- package/src/.agents/skills/security-review/references/authorization.md +372 -372
- package/src/.agents/skills/security-review/references/business-logic.md +443 -443
- package/src/.agents/skills/security-review/references/cryptography.md +329 -329
- package/src/.agents/skills/security-review/references/csrf.md +398 -398
- package/src/.agents/skills/security-review/references/data-protection.md +378 -378
- package/src/.agents/skills/security-review/references/deserialization.md +410 -410
- package/src/.agents/skills/security-review/references/error-handling.md +436 -436
- package/src/.agents/skills/security-review/references/file-security.md +457 -457
- package/src/.agents/skills/security-review/references/injection.md +259 -259
- package/src/.agents/skills/security-review/references/logging.md +433 -433
- package/src/.agents/skills/security-review/references/misconfiguration.md +435 -435
- package/src/.agents/skills/security-review/references/modern-threats.md +475 -475
- package/src/.agents/skills/security-review/references/ssrf.md +415 -415
- package/src/.agents/skills/security-review/references/supply-chain.md +405 -405
- package/src/.agents/skills/security-review/references/xss.md +336 -336
- package/src/.agents/skills/subagent-driven-development/SKILL.md +275 -275
- package/src/.agents/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -26
- package/src/.agents/skills/subagent-driven-development/implementer-prompt.md +113 -113
- package/src/.agents/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -61
- package/src/.agents/skills/systematic-debugging/CREATION-LOG.md +119 -119
- package/src/.agents/skills/systematic-debugging/SKILL.md +296 -296
- package/src/.agents/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
- package/src/.agents/skills/systematic-debugging/condition-based-waiting.md +115 -115
- package/src/.agents/skills/systematic-debugging/defense-in-depth.md +122 -122
- package/src/.agents/skills/systematic-debugging/root-cause-tracing.md +169 -169
- package/src/.agents/skills/systematic-debugging/test-academic.md +14 -14
- package/src/.agents/skills/systematic-debugging/test-pressure-1.md +58 -58
- package/src/.agents/skills/systematic-debugging/test-pressure-2.md +68 -68
- package/src/.agents/skills/systematic-debugging/test-pressure-3.md +69 -69
- package/src/.agents/skills/typescript-best-practices/SKILL.md +373 -373
- package/src/.agents/skills/ui-ux-pro-custom/SKILL.md +348 -348
- package/src/.agents/skills/ui-ux-pro-custom/data/charts.csv +26 -26
- package/src/.agents/skills/ui-ux-pro-custom/data/colors.csv +97 -97
- package/src/.agents/skills/ui-ux-pro-custom/data/icons.csv +101 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/SKILL.md +106 -106
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/accessibility.md +475 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/animation.md +466 -466
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/composition-locals.md +231 -231
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/deprecated-patterns.md +323 -323
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/lists-scrolling.md +400 -400
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/modifiers.md +331 -331
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/navigation.md +416 -416
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/performance.md +446 -446
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/side-effects.md +516 -516
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/foundation-source.md +13327 -13327
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/material3-source.md +19097 -19097
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/navigation-source.md +2947 -2947
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/runtime-source.md +11316 -11316
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/ui-source.md +7896 -7896
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/state-management.md +377 -377
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/styles-experimental.md +470 -470
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/theming-material3.md +349 -349
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/view-composition.md +595 -595
- package/src/.agents/skills/ui-ux-pro-custom/data/landing.csv +31 -31
- package/src/.agents/skills/ui-ux-pro-custom/data/mobile-ui-layout.md +654 -654
- package/src/.agents/skills/ui-ux-pro-custom/data/products.csv +96 -96
- package/src/.agents/skills/ui-ux-pro-custom/data/react-performance.csv +45 -45
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/astro.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/flutter.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/html-tailwind.csv +56 -56
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/jetpack-compose.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nextjs.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nuxt-ui.csv +51 -51
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nuxtjs.csv +59 -59
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/react-native.csv +56 -56
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/react.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/shadcn.csv +61 -61
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/svelte.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/swiftui.csv +51 -51
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/vue.csv +50 -50
- package/src/.agents/skills/ui-ux-pro-custom/data/styles.csv +68 -68
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/alarmkit/SKILL.md +438 -438
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/alarmkit/references/alarmkit-patterns.md +584 -584
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-clips/SKILL.md +436 -436
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-intents/SKILL.md +489 -489
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-intents/references/appintents-advanced.md +1076 -1076
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/SKILL.md +340 -340
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/references/privacy-manifest.md +90 -90
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/references/review-checklists.md +106 -106
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/coreml-conversion.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/coreml-optimization.md +344 -344
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/foundation-models.md +508 -508
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/mlx-swift.md +285 -285
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/authentication/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/authentication/references/keychain-biometric.md +211 -211
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/background-processing/SKILL.md +499 -499
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/background-processing/references/background-task-patterns.md +390 -390
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/callkit-voip/SKILL.md +461 -461
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/callkit-voip/references/callkit-patterns.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/cloudkit-sync/SKILL.md +492 -492
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/cloudkit-sync/references/cloudkit-patterns.md +461 -461
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/codable-patterns/SKILL.md +467 -467
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/contacts-framework/SKILL.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/contacts-framework/references/contacts-patterns.md +409 -409
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-bluetooth/SKILL.md +491 -491
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-bluetooth/references/ble-patterns.md +435 -435
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-motion/SKILL.md +388 -388
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-motion/references/motion-patterns.md +405 -405
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-nfc/SKILL.md +495 -495
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-nfc/references/nfc-patterns.md +420 -420
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/coreml/SKILL.md +459 -459
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/coreml/references/coreml-swift-integration.md +765 -765
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/SKILL.md +422 -422
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/references/instruments-guide.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/references/lldb-patterns.md +298 -298
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/device-integrity/SKILL.md +477 -477
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/energykit/SKILL.md +460 -460
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/energykit/references/energykit-patterns.md +541 -541
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/eventkit-calendar/SKILL.md +483 -483
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/eventkit-calendar/references/eventkit-patterns.md +326 -326
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/healthkit/SKILL.md +498 -498
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/healthkit/references/healthkit-patterns.md +602 -602
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/homekit-matter/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/homekit-matter/references/matter-commissioning.md +455 -455
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-accessibility/SKILL.md +301 -301
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-accessibility/references/a11y-patterns.md +140 -140
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/SKILL.md +418 -418
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/references/formatstyle-locale.md +627 -627
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/references/string-catalogs.md +462 -462
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/SKILL.md +441 -441
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/background-websocket.md +862 -862
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/lightweight-clients.md +93 -93
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/network-framework.md +563 -563
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/urlsession-patterns.md +1116 -1116
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/app-review-guidelines.md +174 -174
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/cryptokit-advanced.md +296 -296
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/file-storage-patterns.md +354 -354
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/privacy-manifest.md +117 -117
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/live-activities/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/live-activities/references/live-activity-patterns.md +868 -868
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/SKILL.md +485 -485
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/references/corelocation-patterns.md +730 -730
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/references/mapkit-patterns.md +748 -748
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/metrickit-diagnostics/SKILL.md +479 -479
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/musickit-audio/SKILL.md +395 -395
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/musickit-audio/references/musickit-patterns.md +363 -363
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/natural-language/SKILL.md +412 -412
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/natural-language/references/translation-patterns.md +311 -311
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/passkit-wallet/SKILL.md +398 -398
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/passkit-wallet/references/wallet-passes.md +254 -254
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/SKILL.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/references/paperkit-integration.md +376 -376
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/references/pencilkit-patterns.md +302 -302
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/permissionkit/SKILL.md +446 -446
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/permissionkit/references/permissionkit-patterns.md +435 -435
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/av-playback.md +701 -701
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/camera-capture.md +774 -774
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/image-loading-caching.md +869 -869
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/photospicker-patterns.md +597 -597
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/references/notification-patterns.md +677 -677
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/references/rich-notifications.md +745 -745
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/realitykit-ar/SKILL.md +479 -479
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/realitykit-ar/references/realitykit-patterns.md +480 -480
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/shareplay-activities/SKILL.md +483 -483
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/shareplay-activities/references/shareplay-patterns.md +544 -544
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/speech-recognition/SKILL.md +485 -485
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/SKILL.md +478 -478
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/references/app-review-guidelines.md +58 -58
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/references/storekit-advanced.md +755 -755
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-charts/SKILL.md +487 -487
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-charts/references/charts-patterns.md +895 -895
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/SKILL.md +408 -408
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/approachable-concurrency.md +80 -80
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/swift-6-2-concurrency.md +233 -233
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/swiftui-concurrency.md +187 -187
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/synchronization-primitives.md +341 -341
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-language/SKILL.md +498 -498
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-language/references/swift-patterns-extended.md +505 -505
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-testing/SKILL.md +467 -467
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-testing/references/testing-patterns.md +504 -504
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/SKILL.md +334 -334
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/core-data-coexistence.md +504 -504
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/swiftdata-advanced.md +975 -975
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/swiftdata-queries.md +675 -675
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/SKILL.md +481 -481
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/references/animation-advanced.md +804 -804
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/references/core-animation-bridge.md +553 -553
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-gestures/SKILL.md +450 -450
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-gestures/references/gesture-patterns.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/SKILL.md +336 -336
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/form.md +97 -97
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/grids.md +69 -69
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/list.md +99 -99
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/scrollview.md +147 -147
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-liquid-glass/SKILL.md +325 -325
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-liquid-glass/references/liquid-glass.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/SKILL.md +262 -262
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/deeplinks.md +207 -207
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/navigationstack.md +177 -177
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/sheets.md +169 -169
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/tabview.md +178 -178
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/SKILL.md +381 -381
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/architecture-patterns.md +486 -486
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/deprecated-migration.md +1097 -1097
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/design-polish.md +780 -780
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/platform-and-sharing.md +696 -696
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/SKILL.md +491 -491
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +46 -46
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +29 -29
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/understanding-hangs-in-your-app.md +33 -33
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/understanding-improving-swiftui-performance.md +52 -52
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/SKILL.md +428 -428
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/references/hosting-migration.md +534 -534
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/references/representable-recipes.md +1133 -1133
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/tipkit/SKILL.md +494 -494
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/tipkit/references/tipkit-patterns.md +782 -782
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/SKILL.md +475 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/vision-requests.md +736 -736
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/visionkit-scanner.md +738 -738
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/SKILL.md +410 -410
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/references/weatherkit-patterns.md +567 -567
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/SKILL.md +497 -497
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/references/widgetkit-advanced.md +871 -871
- package/src/.agents/skills/ui-ux-pro-custom/data/typography.csv +57 -57
- package/src/.agents/skills/ui-ux-pro-custom/data/ui-reasoning.csv +101 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/ux-guidelines.csv +99 -99
- package/src/.agents/skills/ui-ux-pro-custom/data/web-interface.csv +31 -31
- package/src/.agents/skills/ui-ux-pro-custom/scripts/core.py +253 -253
- package/src/.agents/skills/ui-ux-pro-custom/scripts/design_system.py +1067 -1067
- package/src/.agents/skills/ui-ux-pro-custom/scripts/search.py +114 -114
- package/src/.agents/skills/ux-audit/SKILL.md +150 -150
- package/src/.agents/skills/websocket-engineer/SKILL.md +168 -168
- package/src/.agents/skills/websocket-engineer/references/alternatives.md +391 -391
- package/src/.agents/skills/websocket-engineer/references/patterns.md +400 -400
- package/src/.agents/skills/websocket-engineer/references/protocol.md +195 -195
- package/src/.agents/skills/websocket-engineer/references/scaling.md +333 -333
- package/src/.agents/skills/websocket-engineer/references/security.md +474 -474
- package/src/.agents/skills/writing-skills/SKILL.md +655 -655
- package/src/.agents/skills/writing-skills/anthropic-best-practices.md +1150 -1150
- package/src/.agents/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -189
- package/src/.agents/skills/writing-skills/graphviz-conventions.dot +171 -171
- package/src/.agents/skills/writing-skills/persuasion-principles.md +187 -187
- package/src/.agents/skills/writing-skills/render-graphs.js +168 -168
- package/src/.agents/skills/writing-skills/testing-skills-with-subagents.md +384 -384
- package/src/.claude/commands/master-orchestrator.md +15 -0
- package/src/_memory/config.yaml +11 -11
- package/src/_memory/master-orchestrator-sidecar/instructions.md +85 -32
- package/src/_memory/skills/nimbalyst-tracking/SKILL.md +103 -103
- package/src/_memory/skills/writing-skills/SKILL.md +655 -655
- package/src/bmb/agents/agent-builder.md +59 -59
- package/src/bmb/agents/module-builder.md +60 -60
- package/src/bmb/agents/workflow-builder.md +61 -61
- package/src/bmb/config.yaml +12 -12
- package/src/bmb/module-help.csv +13 -13
- package/src/bmb/workflows/agent/data/agent-architecture.md +258 -258
- package/src/bmb/workflows/agent/data/agent-compilation.md +185 -185
- package/src/bmb/workflows/agent/data/agent-menu-patterns.md +189 -189
- package/src/bmb/workflows/agent/data/agent-metadata.md +133 -133
- package/src/bmb/workflows/agent/data/agent-validation.md +111 -111
- package/src/bmb/workflows/agent/data/brainstorm-context.md +96 -96
- package/src/bmb/workflows/agent/data/communication-presets.csv +61 -61
- package/src/bmb/workflows/agent/data/critical-actions.md +75 -75
- package/src/bmb/workflows/agent/data/persona-properties.md +252 -252
- package/src/bmb/workflows/agent/data/principles-crafting.md +142 -142
- package/src/bmb/workflows/agent/data/reference/module-examples/architect.md +68 -68
- package/src/bmb/workflows/agent/data/reference/with-sidecar/journal-keeper/journal-keeper-sidecar/entries/yy-mm-dd-entry-template.md +16 -16
- package/src/bmb/workflows/agent/data/understanding-agent-types.md +126 -126
- package/src/bmb/workflows/agent/steps-c/step-01-brainstorm.md +129 -129
- package/src/bmb/workflows/agent/steps-c/step-02-discovery.md +170 -170
- package/src/bmb/workflows/agent/steps-c/step-03-sidecar-metadata.md +309 -309
- package/src/bmb/workflows/agent/steps-c/step-04-persona.md +213 -213
- package/src/bmb/workflows/agent/steps-c/step-05-commands-menu.md +179 -179
- package/src/bmb/workflows/agent/steps-c/step-06-activation.md +278 -278
- package/src/bmb/workflows/agent/steps-c/step-07-build-agent.md +316 -316
- package/src/bmb/workflows/agent/steps-c/step-08-celebrate.md +247 -247
- package/src/bmb/workflows/agent/steps-e/e-01-load-existing.md +221 -221
- package/src/bmb/workflows/agent/steps-e/e-02-discover-edits.md +195 -195
- package/src/bmb/workflows/agent/steps-e/e-04-sidecar-metadata.md +126 -126
- package/src/bmb/workflows/agent/steps-e/e-05-persona.md +135 -135
- package/src/bmb/workflows/agent/steps-e/e-06-commands-menu.md +123 -123
- package/src/bmb/workflows/agent/steps-e/e-07-activation.md +124 -124
- package/src/bmb/workflows/agent/steps-e/e-08-edit-agent.md +197 -197
- package/src/bmb/workflows/agent/steps-e/e-09-celebrate.md +155 -155
- package/src/bmb/workflows/agent/steps-v/v-01-load-review.md +137 -137
- package/src/bmb/workflows/agent/steps-v/v-02a-validate-metadata.md +116 -116
- package/src/bmb/workflows/agent/steps-v/v-02b-validate-persona.md +124 -124
- package/src/bmb/workflows/agent/steps-v/v-02c-validate-menu.md +127 -127
- package/src/bmb/workflows/agent/steps-v/v-02d-validate-structure.md +134 -134
- package/src/bmb/workflows/agent/steps-v/v-02e-validate-sidecar.md +134 -134
- package/src/bmb/workflows/agent/steps-v/v-03-summary.md +104 -104
- package/src/bmb/workflows/agent/templates/agent-plan.template.md +5 -5
- package/src/bmb/workflows/agent/templates/agent-template.md +89 -89
- package/src/bmb/workflows/agent/workflow-create-agent.md +72 -72
- package/src/bmb/workflows/agent/workflow-edit-agent.md +75 -75
- package/src/bmb/workflows/agent/workflow-validate-agent.md +73 -73
- package/src/bmb/workflows/module/data/agent-architecture.md +179 -179
- package/src/bmb/workflows/module/data/agent-spec-template.md +79 -79
- package/src/bmb/workflows/module/data/module-standards.md +263 -263
- package/src/bmb/workflows/module/data/module-yaml-conventions.md +392 -392
- package/src/bmb/workflows/module/module-help-generate.md +254 -254
- package/src/bmb/workflows/module/steps-b/step-01-welcome.md +148 -148
- package/src/bmb/workflows/module/steps-b/step-02-spark.md +141 -141
- package/src/bmb/workflows/module/steps-b/step-03-module-type.md +149 -149
- package/src/bmb/workflows/module/steps-b/step-04-vision.md +83 -83
- package/src/bmb/workflows/module/steps-b/step-05-identity.md +97 -97
- package/src/bmb/workflows/module/steps-b/step-06-users.md +86 -86
- package/src/bmb/workflows/module/steps-b/step-07-value.md +76 -76
- package/src/bmb/workflows/module/steps-b/step-08-agents.md +97 -97
- package/src/bmb/workflows/module/steps-b/step-09-workflows.md +83 -83
- package/src/bmb/workflows/module/steps-b/step-10-tools.md +91 -91
- package/src/bmb/workflows/module/steps-b/step-11-scenarios.md +84 -84
- package/src/bmb/workflows/module/steps-b/step-12-creative.md +95 -95
- package/src/bmb/workflows/module/steps-b/step-13-review.md +105 -105
- package/src/bmb/workflows/module/steps-b/step-14-finalize.md +117 -117
- package/src/bmb/workflows/module/steps-c/step-01-load-brief.md +179 -179
- package/src/bmb/workflows/module/steps-c/step-01b-continue.md +82 -82
- package/src/bmb/workflows/module/steps-c/step-02-structure.md +105 -105
- package/src/bmb/workflows/module/steps-c/step-03-config.md +119 -119
- package/src/bmb/workflows/module/steps-c/step-04-agents.md +168 -168
- package/src/bmb/workflows/module/steps-c/step-05-workflows.md +184 -184
- package/src/bmb/workflows/module/steps-c/step-06-docs.md +401 -401
- package/src/bmb/workflows/module/steps-c/step-07-complete.md +152 -152
- package/src/bmb/workflows/module/steps-e/step-01-load-target.md +81 -81
- package/src/bmb/workflows/module/steps-e/step-02-select-edit.md +77 -77
- package/src/bmb/workflows/module/steps-e/step-03-apply-edit.md +77 -77
- package/src/bmb/workflows/module/steps-e/step-04-review.md +80 -80
- package/src/bmb/workflows/module/steps-e/step-05-confirm.md +75 -75
- package/src/bmb/workflows/module/steps-v/step-01-load-target.md +96 -96
- package/src/bmb/workflows/module/steps-v/step-02-file-structure.md +93 -93
- package/src/bmb/workflows/module/steps-v/step-03-module-yaml.md +99 -99
- package/src/bmb/workflows/module/steps-v/step-04-agent-specs.md +152 -152
- package/src/bmb/workflows/module/steps-v/step-05-workflow-specs.md +152 -152
- package/src/bmb/workflows/module/steps-v/step-06-documentation.md +143 -143
- package/src/bmb/workflows/module/steps-v/step-07-installation.md +102 -102
- package/src/bmb/workflows/module/steps-v/step-08-report.md +197 -197
- package/src/bmb/workflows/module/templates/brief-template.md +154 -154
- package/src/bmb/workflows/module/templates/workflow-spec-template.md +96 -96
- package/src/bmb/workflows/module/workflow-create-module-brief.md +71 -71
- package/src/bmb/workflows/module/workflow-create-module.md +86 -86
- package/src/bmb/workflows/module/workflow-edit-module.md +66 -66
- package/src/bmb/workflows/module/workflow-validate-module.md +66 -66
- package/src/bmb/workflows/workflow/data/architecture.md +150 -150
- package/src/bmb/workflows/workflow/data/common-workflow-tools.csv +19 -19
- package/src/bmb/workflows/workflow/data/csv-data-file-standards.md +53 -53
- package/src/bmb/workflows/workflow/data/frontmatter-standards.md +184 -184
- package/src/bmb/workflows/workflow/data/input-discovery-standards.md +191 -191
- package/src/bmb/workflows/workflow/data/intent-vs-prescriptive-spectrum.md +44 -44
- package/src/bmb/workflows/workflow/data/menu-handling-standards.md +133 -133
- package/src/bmb/workflows/workflow/data/output-format-standards.md +135 -135
- package/src/bmb/workflows/workflow/data/step-file-rules.md +235 -235
- package/src/bmb/workflows/workflow/data/step-type-patterns.md +257 -257
- package/src/bmb/workflows/workflow/data/subprocess-optimization-patterns.md +188 -188
- package/src/bmb/workflows/workflow/data/trimodal-workflow-structure.md +164 -164
- package/src/bmb/workflows/workflow/data/workflow-chaining-standards.md +222 -222
- package/src/bmb/workflows/workflow/data/workflow-examples.md +232 -232
- package/src/bmb/workflows/workflow/data/workflow-type-criteria.md +134 -134
- package/src/bmb/workflows/workflow/steps-c/step-00-conversion.md +263 -263
- package/src/bmb/workflows/workflow/steps-c/step-01-discovery.md +194 -194
- package/src/bmb/workflows/workflow/steps-c/step-01b-continuation.md +3 -3
- package/src/bmb/workflows/workflow/steps-c/step-02-classification.md +270 -270
- package/src/bmb/workflows/workflow/steps-c/step-03-requirements.md +283 -283
- package/src/bmb/workflows/workflow/steps-c/step-04-tools.md +282 -282
- package/src/bmb/workflows/workflow/steps-c/step-05-plan-review.md +243 -243
- package/src/bmb/workflows/workflow/steps-c/step-06-design.md +330 -330
- package/src/bmb/workflows/workflow/steps-c/step-07-foundation.md +239 -239
- package/src/bmb/workflows/workflow/steps-c/step-08-build-step-01.md +379 -379
- package/src/bmb/workflows/workflow/steps-c/step-09-build-next-step.md +350 -350
- package/src/bmb/workflows/workflow/steps-c/step-10-confirmation.md +322 -322
- package/src/bmb/workflows/workflow/steps-c/step-11-completion.md +191 -191
- package/src/bmb/workflows/workflow/steps-e/step-e-01-assess-workflow.md +237 -237
- package/src/bmb/workflows/workflow/steps-e/step-e-02-discover-edits.md +251 -251
- package/src/bmb/workflows/workflow/steps-e/step-e-03-fix-validation.md +254 -254
- package/src/bmb/workflows/workflow/steps-e/step-e-04-direct-edit.md +277 -277
- package/src/bmb/workflows/workflow/steps-e/step-e-05-apply-edit.md +154 -154
- package/src/bmb/workflows/workflow/steps-e/step-e-06-validate-after.md +190 -190
- package/src/bmb/workflows/workflow/steps-e/step-e-07-complete.md +206 -206
- package/src/bmb/workflows/workflow/steps-v/step-01-validate-max-mode.md +109 -109
- package/src/bmb/workflows/workflow/steps-v/step-01-validate.md +221 -221
- package/src/bmb/workflows/workflow/steps-v/step-01b-structure.md +152 -152
- package/src/bmb/workflows/workflow/steps-v/step-02-frontmatter-validation.md +199 -199
- package/src/bmb/workflows/workflow/steps-v/step-02b-path-violations.md +265 -265
- package/src/bmb/workflows/workflow/steps-v/step-03-menu-validation.md +164 -164
- package/src/bmb/workflows/workflow/steps-v/step-04-step-type-validation.md +211 -211
- package/src/bmb/workflows/workflow/steps-v/step-05-output-format-validation.md +200 -200
- package/src/bmb/workflows/workflow/steps-v/step-06-validation-design-check.md +195 -195
- package/src/bmb/workflows/workflow/steps-v/step-07-instruction-style-check.md +209 -209
- package/src/bmb/workflows/workflow/steps-v/step-08-collaborative-experience-check.md +199 -199
- package/src/bmb/workflows/workflow/steps-v/step-08b-subprocess-optimization.md +179 -179
- package/src/bmb/workflows/workflow/steps-v/step-09-cohesive-review.md +186 -186
- package/src/bmb/workflows/workflow/steps-v/step-10-report-complete.md +154 -154
- package/src/bmb/workflows/workflow/steps-v/step-11-plan-validation.md +237 -237
- package/src/bmb/workflows/workflow/templates/minimal-output-template.md +11 -11
- package/src/bmb/workflows/workflow/templates/step-01-init-continuable-template.md +241 -241
- package/src/bmb/workflows/workflow/templates/step-1b-template.md +224 -224
- package/src/bmb/workflows/workflow/templates/step-template.md +294 -294
- package/src/bmb/workflows/workflow/templates/workflow-template.md +102 -102
- package/src/bmb/workflows/workflow/workflow-create-workflow.md +79 -79
- package/src/bmb/workflows/workflow/workflow-edit-workflow.md +65 -65
- package/src/bmb/workflows/workflow/workflow-rework-workflow.md +65 -65
- package/src/bmb/workflows/workflow/workflow-validate-max-parallel-workflow.md +66 -66
- package/src/bmb/workflows/workflow/workflow-validate-workflow.md +65 -65
- package/src/bmm/agents/analyst.md +104 -104
- package/src/bmm/agents/dev.md +100 -100
- package/src/bmm/agents/qa.md +100 -90
- package/src/bmm/agents/tech-writer/tech-writer.md +94 -94
- package/src/bmm/module-help.csv +31 -31
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01-init.md +115 -115
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01b-continue.md +107 -107
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +141 -141
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +144 -144
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +147 -147
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +161 -161
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +99 -99
- package/src/bmm/workflows/1-analysis/create-product-brief/workflow.md +57 -57
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-01-init.md +87 -87
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-02-domain-analysis.md +156 -156
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-03-competitive-landscape.md +165 -165
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-04-regulatory-focus.md +140 -140
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-05-technical-trends.md +152 -152
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-06-research-synthesis.md +345 -345
- package/src/bmm/workflows/1-analysis/research/market-steps/step-01-init.md +92 -92
- package/src/bmm/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +164 -164
- package/src/bmm/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +174 -174
- package/src/bmm/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +184 -184
- package/src/bmm/workflows/1-analysis/research/market-steps/step-05-competitive-analysis.md +105 -105
- package/src/bmm/workflows/1-analysis/research/market-steps/step-06-research-completion.md +360 -360
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-01-init.md +87 -87
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-02-technical-overview.md +165 -165
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-03-integration-patterns.md +174 -174
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-04-architectural-patterns.md +141 -141
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-05-implementation-research.md +159 -159
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-06-research-synthesis.md +387 -387
- package/src/bmm/workflows/1-analysis/research/workflow-domain-research.md +54 -54
- package/src/bmm/workflows/1-analysis/research/workflow-market-research.md +54 -54
- package/src/bmm/workflows/1-analysis/research/workflow-technical-research.md +54 -54
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-01b-continue.md +100 -100
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02-discovery.md +160 -160
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02b-vision.md +88 -88
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02c-executive-summary.md +99 -99
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md +169 -169
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +156 -156
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +136 -136
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +176 -176
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-07-project-type.md +184 -184
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-08-scoping.md +174 -174
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md +175 -175
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-10-nonfunctional.md +189 -189
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-11-polish.md +162 -162
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-12-complete.md +79 -79
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +183 -183
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md +149 -149
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md +187 -187
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md +192 -192
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-04-complete.md +108 -108
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +166 -166
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md +131 -131
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md +150 -150
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md +118 -118
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md +155 -155
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md +170 -170
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md +158 -158
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md +147 -147
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md +182 -182
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md +202 -202
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +148 -148
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +201 -201
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md +179 -179
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +164 -164
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-create-prd.md +65 -65
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-edit-prd.md +65 -65
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +63 -63
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01b-continue.md +63 -63
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +106 -106
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +111 -111
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +115 -115
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +127 -127
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +167 -167
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +143 -143
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +118 -118
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +154 -154
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +136 -136
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +165 -165
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +135 -135
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +192 -192
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +101 -101
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +45 -45
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-01-document-discovery.md +185 -185
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-02-prd-analysis.md +129 -129
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-03-epic-coverage-validation.md +130 -130
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-04-ux-alignment.md +93 -93
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-05-epic-quality-review.md +196 -196
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +129 -129
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/workflow.md +54 -54
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-01b-continue.md +82 -82
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +106 -106
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +138 -138
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +129 -129
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +166 -166
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +186 -186
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +163 -163
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +38 -38
- package/src/bmm/workflows/3-solutioning/create-architecture/workflow.md +49 -49
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +124 -124
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +122 -122
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +84 -84
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +58 -58
- package/src/bmm/workflows/4-implementation/code-review/workflow.yaml +43 -43
- package/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +53 -53
- package/src/bmm/workflows/4-implementation/create-story/checklist.md +159 -159
- package/src/bmm/workflows/4-implementation/create-story/template.md +79 -79
- package/src/bmm/workflows/4-implementation/create-story/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +20 -20
- package/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +25 -25
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-01-mode-detection.md +158 -158
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-02-context-gathering.md +122 -122
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-03-execute.md +93 -93
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-04-self-check.md +93 -93
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-05-adversarial-review.md +87 -87
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-06-resolve-findings.md +146 -146
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +50 -50
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-02-investigate.md +152 -152
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-03-generate.md +123 -123
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +201 -201
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +79 -79
- package/src/bmm/workflows/document-project/workflow.yaml +22 -22
- package/src/bmm/workflows/generate-project-context/steps/step-01-discover.md +184 -184
- package/src/bmm/workflows/generate-project-context/steps/step-02-generate.md +322 -322
- package/src/bmm/workflows/generate-project-context/steps/step-03-complete.md +235 -235
- package/src/bmm/workflows/generate-project-context/workflow.md +49 -49
- package/src/bmm/workflows/qa/automate/workflow.yaml +233 -233
- package/src/bmm/workflows/qa-generate-e2e-tests/workflow.yaml +42 -42
- package/src/core/config.yaml +9 -9
- package/src/core/module-help.csv +10 -10
- package/src/core/scripts/generate-loop-report.py +72 -72
- package/src/core/tasks/editorial-review-prose.xml +101 -101
- package/src/core/tasks/editorial-review-structure.xml +207 -207
- package/src/core/tasks/help.md +86 -86
- package/src/core/tasks/index-docs.xml +64 -64
- package/src/core/tasks/review-adversarial-general.xml +66 -66
- package/src/core/tasks/review-adversarial-loop.xml +46 -46
- package/src/core/tasks/review-edge-case-hunter.xml +63 -63
- package/src/core/tasks/review-party-loop.xml +46 -46
- package/src/core/tasks/shard-doc.xml +107 -107
- package/src/core/tasks/workflow.xml +235 -235
- package/src/core/templates/review-loop-report.html +88 -88
- package/src/core/templates/review-loop-report.md +5 -5
- package/src/core/workflows/advanced-elicitation/workflow.xml +117 -117
- package/src/core/workflows/brainstorming/steps/step-01-session-setup.md +212 -212
- package/src/core/workflows/brainstorming/steps/step-01b-continue.md +122 -122
- package/src/core/workflows/brainstorming/steps/step-02a-user-selected.md +225 -225
- package/src/core/workflows/brainstorming/steps/step-02b-ai-recommended.md +237 -237
- package/src/core/workflows/brainstorming/steps/step-02c-random-selection.md +209 -209
- package/src/core/workflows/brainstorming/steps/step-02d-progressive-flow.md +264 -264
- package/src/core/workflows/brainstorming/steps/step-02e-deep-dive.md +68 -68
- package/src/core/workflows/brainstorming/steps/step-03-technique-execution.md +403 -403
- package/src/core/workflows/brainstorming/steps/step-04-idea-organization.md +303 -303
- package/src/core/workflows/brainstorming/workflow.md +60 -60
- package/src/core/workflows/extract-trackers/workflow.md +45 -45
- package/src/core/workflows/party-mode/steps/step-01-agent-loading.md +142 -142
- package/src/core/workflows/party-mode/workflow.md +194 -194
- package/src/docs/dev/tmux/actions_popup.py +291 -291
- package/src/docs/dev/tmux/tmux-setup.md +62 -1
|
@@ -1,354 +1,354 @@
|
|
|
1
|
-
# File Storage Patterns
|
|
2
|
-
|
|
3
|
-
Guidance on choosing the right directory, applying file protection, managing
|
|
4
|
-
backup exclusions, and handling storage pressure on iOS.
|
|
5
|
-
|
|
6
|
-
## Contents
|
|
7
|
-
|
|
8
|
-
- [Directory Selection Guide](#directory-selection-guide)
|
|
9
|
-
- [FileProtectionType Levels](#fileprotectiontype-levels)
|
|
10
|
-
- [Backup Exclusion (isExcludedFromBackup)](#backup-exclusion-isexcludedfrombackup)
|
|
11
|
-
- [Storage Pressure Handling](#storage-pressure-handling)
|
|
12
|
-
|
|
13
|
-
## Directory Selection Guide
|
|
14
|
-
|
|
15
|
-
iOS provides four primary directories for app data. Choose based on whether
|
|
16
|
-
the data is user-generated, re-creatable, or temporary.
|
|
17
|
-
|
|
18
|
-
| Directory | Backed Up | Purged by System | Use For |
|
|
19
|
-
|---|---|---|---|
|
|
20
|
-
| `Documents/` | Yes | No | User-generated content (documents, exports, user files) |
|
|
21
|
-
| `Library/Application Support/` | Yes | No | App-generated supporting files (databases, config, caches that should survive updates) |
|
|
22
|
-
| `Library/Caches/` | No | Yes (low storage) | Re-creatable data (downloaded images, API responses, computed data) |
|
|
23
|
-
| `tmp/` | No | Yes (anytime) | Truly temporary files (in-progress uploads, scratch files) |
|
|
24
|
-
|
|
25
|
-
### Accessing Standard Directories
|
|
26
|
-
|
|
27
|
-
Use `FileManager.default.urls(for:in:)` to get the correct path. Never
|
|
28
|
-
hardcode paths.
|
|
29
|
-
|
|
30
|
-
```swift
|
|
31
|
-
import Foundation
|
|
32
|
-
|
|
33
|
-
// Documents/ — user-generated content, backed up by iCloud/iTunes
|
|
34
|
-
let documentsURL = FileManager.default.urls(
|
|
35
|
-
for: .documentDirectory, in: .userDomainMask
|
|
36
|
-
).first!
|
|
37
|
-
|
|
38
|
-
// Library/Application Support/ — app-generated supporting data, backed up
|
|
39
|
-
let appSupportURL = FileManager.default.urls(
|
|
40
|
-
for: .applicationSupportDirectory, in: .userDomainMask
|
|
41
|
-
).first!
|
|
42
|
-
// Create if it doesn't exist (not auto-created)
|
|
43
|
-
try FileManager.default.createDirectory(
|
|
44
|
-
at: appSupportURL, withIntermediateDirectories: true
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
// Library/Caches/ — re-creatable data, not backed up, may be purged
|
|
48
|
-
let cachesURL = FileManager.default.urls(
|
|
49
|
-
for: .cachesDirectory, in: .userDomainMask
|
|
50
|
-
).first!
|
|
51
|
-
|
|
52
|
-
// tmp/ — temporary files, purged by system periodically
|
|
53
|
-
let tmpURL = FileManager.default.temporaryDirectory
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Choosing the Right Directory
|
|
57
|
-
|
|
58
|
-
```swift
|
|
59
|
-
// User's exported PDF — Documents/
|
|
60
|
-
let exportURL = documentsURL.appendingPathComponent("Report.pdf")
|
|
61
|
-
try pdfData.write(to: exportURL)
|
|
62
|
-
|
|
63
|
-
// App's SQLite database — Library/Application Support/
|
|
64
|
-
let dbURL = appSupportURL.appendingPathComponent("AppData.sqlite")
|
|
65
|
-
|
|
66
|
-
// Downloaded thumbnail cache — Library/Caches/
|
|
67
|
-
let thumbURL = cachesURL.appendingPathComponent("thumbnails/\(imageID).jpg")
|
|
68
|
-
|
|
69
|
-
// In-progress upload — tmp/
|
|
70
|
-
let uploadURL = tmpURL.appendingPathComponent(UUID().uuidString + ".tmp")
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## FileProtectionType Levels
|
|
74
|
-
|
|
75
|
-
iOS encrypts files at rest using Data Protection. The protection level
|
|
76
|
-
determines when the file is accessible relative to the device lock state.
|
|
77
|
-
|
|
78
|
-
Docs: [FileProtectionType](https://sosumi.ai/documentation/foundation/fileprotectiontype),
|
|
79
|
-
[Encrypting Your App's Files](https://sosumi.ai/documentation/uikit/encrypting-your-app-s-files)
|
|
80
|
-
|
|
81
|
-
| Level | Constant | When Accessible | Use For |
|
|
82
|
-
|---|---|---|---|
|
|
83
|
-
| Complete | `.complete` | Only when device is unlocked | Sensitive user data (health records, financial data) |
|
|
84
|
-
| Complete Unless Open | `.completeUnlessOpen` | Can finish if opened before lock | Active downloads, recordings in progress |
|
|
85
|
-
| Until First Auth | `.completeUntilFirstUserAuthentication` | After first unlock (default) | Most app data; background-accessible content |
|
|
86
|
-
| None | `.none` | Always, even before first unlock | Non-sensitive system-required data |
|
|
87
|
-
|
|
88
|
-
### Setting File Protection
|
|
89
|
-
|
|
90
|
-
```swift
|
|
91
|
-
import Foundation
|
|
92
|
-
|
|
93
|
-
// Option 1: Set protection when writing data
|
|
94
|
-
try sensitiveData.write(to: fileURL, options: .completeFileProtection)
|
|
95
|
-
|
|
96
|
-
// Option 2: Set protection via FileManager attributes
|
|
97
|
-
try FileManager.default.setAttributes(
|
|
98
|
-
[.protectionKey: FileProtectionType.complete],
|
|
99
|
-
ofItemAtPath: fileURL.path
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
// Option 3: Set protection on a directory (applies to new files within)
|
|
103
|
-
try FileManager.default.setAttributes(
|
|
104
|
-
[.protectionKey: FileProtectionType.complete],
|
|
105
|
-
ofItemAtPath: secureDirectoryURL.path
|
|
106
|
-
)
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### Checking Current Protection Level
|
|
110
|
-
|
|
111
|
-
```swift
|
|
112
|
-
let attributes = try FileManager.default.attributesOfItem(atPath: fileURL.path)
|
|
113
|
-
if let protection = attributes[.protectionKey] as? FileProtectionType {
|
|
114
|
-
switch protection {
|
|
115
|
-
case .complete:
|
|
116
|
-
print("File is fully protected")
|
|
117
|
-
case .completeUnlessOpen:
|
|
118
|
-
print("Protected unless already open")
|
|
119
|
-
case .completeUntilFirstUserAuthentication:
|
|
120
|
-
print("Protected until first unlock (default)")
|
|
121
|
-
case .none:
|
|
122
|
-
print("No encryption")
|
|
123
|
-
default:
|
|
124
|
-
break
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### Handling Protected Data Availability
|
|
130
|
-
|
|
131
|
-
Files with `.complete` protection are inaccessible when the device is locked.
|
|
132
|
-
Check availability before accessing:
|
|
133
|
-
|
|
134
|
-
```swift
|
|
135
|
-
import UIKit
|
|
136
|
-
|
|
137
|
-
// Check if protected data is currently available
|
|
138
|
-
if UIApplication.shared.isProtectedDataAvailable {
|
|
139
|
-
// Safe to read .complete files
|
|
140
|
-
let data = try Data(contentsOf: protectedFileURL)
|
|
141
|
-
} else {
|
|
142
|
-
// Wait for device unlock
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Observe availability changes
|
|
146
|
-
NotificationCenter.default.addObserver(
|
|
147
|
-
forName: UIApplication.protectedDataDidBecomeAvailableNotification,
|
|
148
|
-
object: nil,
|
|
149
|
-
queue: .main
|
|
150
|
-
) { _ in
|
|
151
|
-
// Protected files are now accessible
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
NotificationCenter.default.addObserver(
|
|
155
|
-
forName: UIApplication.protectedDataWillBecomeUnavailableNotification,
|
|
156
|
-
object: nil,
|
|
157
|
-
queue: .main
|
|
158
|
-
) { _ in
|
|
159
|
-
// Close file handles to .complete files
|
|
160
|
-
}
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
## Backup Exclusion (isExcludedFromBackup)
|
|
164
|
-
|
|
165
|
-
Exclude large re-downloadable content from iCloud/iTunes backup to avoid
|
|
166
|
-
bloating the user's backup. Apple may reject apps that back up excessive
|
|
167
|
-
re-creatable data.
|
|
168
|
-
|
|
169
|
-
Docs: [URLResourceValues](https://sosumi.ai/documentation/foundation/urlresourcevalues)
|
|
170
|
-
|
|
171
|
-
### Setting the Exclusion Flag
|
|
172
|
-
|
|
173
|
-
```swift
|
|
174
|
-
import Foundation
|
|
175
|
-
|
|
176
|
-
// Exclude a file or directory from backup
|
|
177
|
-
func excludeFromBackup(_ url: URL) throws {
|
|
178
|
-
var resourceValues = URLResourceValues()
|
|
179
|
-
resourceValues.isExcludedFromBackup = true
|
|
180
|
-
var mutableURL = url
|
|
181
|
-
try mutableURL.setResourceValues(resourceValues)
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Usage
|
|
185
|
-
let largeCache = cachesURL.appendingPathComponent("video-cache")
|
|
186
|
-
try excludeFromBackup(largeCache)
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### Checking the Exclusion Flag
|
|
190
|
-
|
|
191
|
-
```swift
|
|
192
|
-
func isExcludedFromBackup(_ url: URL) throws -> Bool {
|
|
193
|
-
let values = try url.resourceValues(forKeys: [.isExcludedFromBackupKey])
|
|
194
|
-
return values.isExcludedFromBackup ?? false
|
|
195
|
-
}
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
### When to Exclude from Backup
|
|
199
|
-
|
|
200
|
-
| Exclude | Keep in Backup |
|
|
201
|
-
|---|---|
|
|
202
|
-
| Downloaded media (images, videos, audio) | User-created documents |
|
|
203
|
-
| API response caches | User preferences and settings |
|
|
204
|
-
| Generated thumbnails or previews | App databases with user data |
|
|
205
|
-
| Offline map tiles | In-app purchase receipts |
|
|
206
|
-
| Pre-computed search indexes | User-generated content |
|
|
207
|
-
|
|
208
|
-
### Common Pattern: Application Support with Exclusion
|
|
209
|
-
|
|
210
|
-
Store re-downloadable data in Application Support but exclude from backup:
|
|
211
|
-
|
|
212
|
-
```swift
|
|
213
|
-
let offlineDataURL = appSupportURL.appendingPathComponent("OfflineData")
|
|
214
|
-
try FileManager.default.createDirectory(
|
|
215
|
-
at: offlineDataURL, withIntermediateDirectories: true
|
|
216
|
-
)
|
|
217
|
-
try excludeFromBackup(offlineDataURL)
|
|
218
|
-
|
|
219
|
-
// Files in this directory persist across app updates but don't bloat backup
|
|
220
|
-
try downloadedData.write(to: offlineDataURL.appendingPathComponent("map-tiles.db"))
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
## Storage Pressure Handling
|
|
224
|
-
|
|
225
|
-
When the device runs low on storage, iOS may purge files in `Library/Caches/`
|
|
226
|
-
and `tmp/`. Apps should proactively manage storage and respond to low-space
|
|
227
|
-
conditions.
|
|
228
|
-
|
|
229
|
-
### Checking Available Storage
|
|
230
|
-
|
|
231
|
-
```swift
|
|
232
|
-
import Foundation
|
|
233
|
-
|
|
234
|
-
func availableDiskSpace() throws -> Int64 {
|
|
235
|
-
let values = try URL(fileURLWithPath: NSHomeDirectory())
|
|
236
|
-
.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey])
|
|
237
|
-
return values.volumeAvailableCapacityForImportantUsage ?? 0
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Use .volumeAvailableCapacityForImportantUsageKey for important operations
|
|
241
|
-
// Use .volumeAvailableCapacityForOpportunisticUsageKey for optional operations
|
|
242
|
-
// The opportunistic value is always <= the important value
|
|
243
|
-
|
|
244
|
-
func hasSpaceForDownload(bytes: Int64) throws -> Bool {
|
|
245
|
-
let available = try availableDiskSpace()
|
|
246
|
-
return available > bytes
|
|
247
|
-
}
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### Responding to Low Storage Notifications
|
|
251
|
-
|
|
252
|
-
```swift
|
|
253
|
-
import UIKit
|
|
254
|
-
|
|
255
|
-
// iOS posts this when storage is critically low (UIKit apps)
|
|
256
|
-
NotificationCenter.default.addObserver(
|
|
257
|
-
forName: UIApplication.didReceiveMemoryWarningNotification,
|
|
258
|
-
object: nil,
|
|
259
|
-
queue: .main
|
|
260
|
-
) { _ in
|
|
261
|
-
// Clear in-memory caches; consider trimming disk caches too
|
|
262
|
-
clearImageCache()
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Check storage proactively at app launch or before large operations
|
|
266
|
-
func checkStorageAndCleanup() throws {
|
|
267
|
-
let availableBytes = try availableDiskSpace()
|
|
268
|
-
let threshold: Int64 = 100 * 1024 * 1024 // 100 MB
|
|
269
|
-
|
|
270
|
-
if availableBytes < threshold {
|
|
271
|
-
try performCleanup()
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
### Implementing Cleanup Strategies
|
|
277
|
-
|
|
278
|
-
```swift
|
|
279
|
-
import Foundation
|
|
280
|
-
|
|
281
|
-
struct StorageCleaner {
|
|
282
|
-
let cachesURL: URL
|
|
283
|
-
let maxCacheAge: TimeInterval // e.g., 7 days
|
|
284
|
-
let maxCacheSize: Int64 // e.g., 500 MB
|
|
285
|
-
|
|
286
|
-
/// Remove files older than maxCacheAge
|
|
287
|
-
func removeExpiredFiles() throws {
|
|
288
|
-
let contents = try FileManager.default.contentsOfDirectory(
|
|
289
|
-
at: cachesURL,
|
|
290
|
-
includingPropertiesForKeys: [.contentModificationDateKey, .fileSizeKey],
|
|
291
|
-
options: .skipsHiddenFiles
|
|
292
|
-
)
|
|
293
|
-
|
|
294
|
-
let cutoff = Date.now.addingTimeInterval(-maxCacheAge)
|
|
295
|
-
|
|
296
|
-
for fileURL in contents {
|
|
297
|
-
let values = try fileURL.resourceValues(
|
|
298
|
-
forKeys: [.contentModificationDateKey]
|
|
299
|
-
)
|
|
300
|
-
if let modified = values.contentModificationDate, modified < cutoff {
|
|
301
|
-
try FileManager.default.removeItem(at: fileURL)
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/// Trim cache to maxCacheSize using LRU eviction
|
|
307
|
-
func trimToSize() throws {
|
|
308
|
-
let contents = try FileManager.default.contentsOfDirectory(
|
|
309
|
-
at: cachesURL,
|
|
310
|
-
includingPropertiesForKeys: [.contentModificationDateKey, .fileSizeKey],
|
|
311
|
-
options: .skipsHiddenFiles
|
|
312
|
-
)
|
|
313
|
-
|
|
314
|
-
// Sort oldest first
|
|
315
|
-
let sorted = try contents.sorted { a, b in
|
|
316
|
-
let aDate = try a.resourceValues(forKeys: [.contentModificationDateKey])
|
|
317
|
-
.contentModificationDate ?? .distantPast
|
|
318
|
-
let bDate = try b.resourceValues(forKeys: [.contentModificationDateKey])
|
|
319
|
-
.contentModificationDate ?? .distantPast
|
|
320
|
-
return aDate < bDate
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// Calculate total size
|
|
324
|
-
var totalSize: Int64 = 0
|
|
325
|
-
for fileURL in sorted {
|
|
326
|
-
let values = try fileURL.resourceValues(forKeys: [.fileSizeKey])
|
|
327
|
-
totalSize += Int64(values.fileSize ?? 0)
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// Delete oldest files until under budget
|
|
331
|
-
for fileURL in sorted {
|
|
332
|
-
guard totalSize > maxCacheSize else { break }
|
|
333
|
-
let values = try fileURL.resourceValues(forKeys: [.fileSizeKey])
|
|
334
|
-
let fileSize = Int64(values.fileSize ?? 0)
|
|
335
|
-
try FileManager.default.removeItem(at: fileURL)
|
|
336
|
-
totalSize -= fileSize
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
/// Full cleanup: expired files first, then trim to size
|
|
341
|
-
func performCleanup() throws {
|
|
342
|
-
try removeExpiredFiles()
|
|
343
|
-
try trimToSize()
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Usage
|
|
348
|
-
let cleaner = StorageCleaner(
|
|
349
|
-
cachesURL: FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!,
|
|
350
|
-
maxCacheAge: 7 * 24 * 60 * 60, // 7 days
|
|
351
|
-
maxCacheSize: 500 * 1024 * 1024 // 500 MB
|
|
352
|
-
)
|
|
353
|
-
try cleaner.performCleanup()
|
|
354
|
-
```
|
|
1
|
+
# File Storage Patterns
|
|
2
|
+
|
|
3
|
+
Guidance on choosing the right directory, applying file protection, managing
|
|
4
|
+
backup exclusions, and handling storage pressure on iOS.
|
|
5
|
+
|
|
6
|
+
## Contents
|
|
7
|
+
|
|
8
|
+
- [Directory Selection Guide](#directory-selection-guide)
|
|
9
|
+
- [FileProtectionType Levels](#fileprotectiontype-levels)
|
|
10
|
+
- [Backup Exclusion (isExcludedFromBackup)](#backup-exclusion-isexcludedfrombackup)
|
|
11
|
+
- [Storage Pressure Handling](#storage-pressure-handling)
|
|
12
|
+
|
|
13
|
+
## Directory Selection Guide
|
|
14
|
+
|
|
15
|
+
iOS provides four primary directories for app data. Choose based on whether
|
|
16
|
+
the data is user-generated, re-creatable, or temporary.
|
|
17
|
+
|
|
18
|
+
| Directory | Backed Up | Purged by System | Use For |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| `Documents/` | Yes | No | User-generated content (documents, exports, user files) |
|
|
21
|
+
| `Library/Application Support/` | Yes | No | App-generated supporting files (databases, config, caches that should survive updates) |
|
|
22
|
+
| `Library/Caches/` | No | Yes (low storage) | Re-creatable data (downloaded images, API responses, computed data) |
|
|
23
|
+
| `tmp/` | No | Yes (anytime) | Truly temporary files (in-progress uploads, scratch files) |
|
|
24
|
+
|
|
25
|
+
### Accessing Standard Directories
|
|
26
|
+
|
|
27
|
+
Use `FileManager.default.urls(for:in:)` to get the correct path. Never
|
|
28
|
+
hardcode paths.
|
|
29
|
+
|
|
30
|
+
```swift
|
|
31
|
+
import Foundation
|
|
32
|
+
|
|
33
|
+
// Documents/ — user-generated content, backed up by iCloud/iTunes
|
|
34
|
+
let documentsURL = FileManager.default.urls(
|
|
35
|
+
for: .documentDirectory, in: .userDomainMask
|
|
36
|
+
).first!
|
|
37
|
+
|
|
38
|
+
// Library/Application Support/ — app-generated supporting data, backed up
|
|
39
|
+
let appSupportURL = FileManager.default.urls(
|
|
40
|
+
for: .applicationSupportDirectory, in: .userDomainMask
|
|
41
|
+
).first!
|
|
42
|
+
// Create if it doesn't exist (not auto-created)
|
|
43
|
+
try FileManager.default.createDirectory(
|
|
44
|
+
at: appSupportURL, withIntermediateDirectories: true
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
// Library/Caches/ — re-creatable data, not backed up, may be purged
|
|
48
|
+
let cachesURL = FileManager.default.urls(
|
|
49
|
+
for: .cachesDirectory, in: .userDomainMask
|
|
50
|
+
).first!
|
|
51
|
+
|
|
52
|
+
// tmp/ — temporary files, purged by system periodically
|
|
53
|
+
let tmpURL = FileManager.default.temporaryDirectory
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Choosing the Right Directory
|
|
57
|
+
|
|
58
|
+
```swift
|
|
59
|
+
// User's exported PDF — Documents/
|
|
60
|
+
let exportURL = documentsURL.appendingPathComponent("Report.pdf")
|
|
61
|
+
try pdfData.write(to: exportURL)
|
|
62
|
+
|
|
63
|
+
// App's SQLite database — Library/Application Support/
|
|
64
|
+
let dbURL = appSupportURL.appendingPathComponent("AppData.sqlite")
|
|
65
|
+
|
|
66
|
+
// Downloaded thumbnail cache — Library/Caches/
|
|
67
|
+
let thumbURL = cachesURL.appendingPathComponent("thumbnails/\(imageID).jpg")
|
|
68
|
+
|
|
69
|
+
// In-progress upload — tmp/
|
|
70
|
+
let uploadURL = tmpURL.appendingPathComponent(UUID().uuidString + ".tmp")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## FileProtectionType Levels
|
|
74
|
+
|
|
75
|
+
iOS encrypts files at rest using Data Protection. The protection level
|
|
76
|
+
determines when the file is accessible relative to the device lock state.
|
|
77
|
+
|
|
78
|
+
Docs: [FileProtectionType](https://sosumi.ai/documentation/foundation/fileprotectiontype),
|
|
79
|
+
[Encrypting Your App's Files](https://sosumi.ai/documentation/uikit/encrypting-your-app-s-files)
|
|
80
|
+
|
|
81
|
+
| Level | Constant | When Accessible | Use For |
|
|
82
|
+
|---|---|---|---|
|
|
83
|
+
| Complete | `.complete` | Only when device is unlocked | Sensitive user data (health records, financial data) |
|
|
84
|
+
| Complete Unless Open | `.completeUnlessOpen` | Can finish if opened before lock | Active downloads, recordings in progress |
|
|
85
|
+
| Until First Auth | `.completeUntilFirstUserAuthentication` | After first unlock (default) | Most app data; background-accessible content |
|
|
86
|
+
| None | `.none` | Always, even before first unlock | Non-sensitive system-required data |
|
|
87
|
+
|
|
88
|
+
### Setting File Protection
|
|
89
|
+
|
|
90
|
+
```swift
|
|
91
|
+
import Foundation
|
|
92
|
+
|
|
93
|
+
// Option 1: Set protection when writing data
|
|
94
|
+
try sensitiveData.write(to: fileURL, options: .completeFileProtection)
|
|
95
|
+
|
|
96
|
+
// Option 2: Set protection via FileManager attributes
|
|
97
|
+
try FileManager.default.setAttributes(
|
|
98
|
+
[.protectionKey: FileProtectionType.complete],
|
|
99
|
+
ofItemAtPath: fileURL.path
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
// Option 3: Set protection on a directory (applies to new files within)
|
|
103
|
+
try FileManager.default.setAttributes(
|
|
104
|
+
[.protectionKey: FileProtectionType.complete],
|
|
105
|
+
ofItemAtPath: secureDirectoryURL.path
|
|
106
|
+
)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Checking Current Protection Level
|
|
110
|
+
|
|
111
|
+
```swift
|
|
112
|
+
let attributes = try FileManager.default.attributesOfItem(atPath: fileURL.path)
|
|
113
|
+
if let protection = attributes[.protectionKey] as? FileProtectionType {
|
|
114
|
+
switch protection {
|
|
115
|
+
case .complete:
|
|
116
|
+
print("File is fully protected")
|
|
117
|
+
case .completeUnlessOpen:
|
|
118
|
+
print("Protected unless already open")
|
|
119
|
+
case .completeUntilFirstUserAuthentication:
|
|
120
|
+
print("Protected until first unlock (default)")
|
|
121
|
+
case .none:
|
|
122
|
+
print("No encryption")
|
|
123
|
+
default:
|
|
124
|
+
break
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Handling Protected Data Availability
|
|
130
|
+
|
|
131
|
+
Files with `.complete` protection are inaccessible when the device is locked.
|
|
132
|
+
Check availability before accessing:
|
|
133
|
+
|
|
134
|
+
```swift
|
|
135
|
+
import UIKit
|
|
136
|
+
|
|
137
|
+
// Check if protected data is currently available
|
|
138
|
+
if UIApplication.shared.isProtectedDataAvailable {
|
|
139
|
+
// Safe to read .complete files
|
|
140
|
+
let data = try Data(contentsOf: protectedFileURL)
|
|
141
|
+
} else {
|
|
142
|
+
// Wait for device unlock
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Observe availability changes
|
|
146
|
+
NotificationCenter.default.addObserver(
|
|
147
|
+
forName: UIApplication.protectedDataDidBecomeAvailableNotification,
|
|
148
|
+
object: nil,
|
|
149
|
+
queue: .main
|
|
150
|
+
) { _ in
|
|
151
|
+
// Protected files are now accessible
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
NotificationCenter.default.addObserver(
|
|
155
|
+
forName: UIApplication.protectedDataWillBecomeUnavailableNotification,
|
|
156
|
+
object: nil,
|
|
157
|
+
queue: .main
|
|
158
|
+
) { _ in
|
|
159
|
+
// Close file handles to .complete files
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Backup Exclusion (isExcludedFromBackup)
|
|
164
|
+
|
|
165
|
+
Exclude large re-downloadable content from iCloud/iTunes backup to avoid
|
|
166
|
+
bloating the user's backup. Apple may reject apps that back up excessive
|
|
167
|
+
re-creatable data.
|
|
168
|
+
|
|
169
|
+
Docs: [URLResourceValues](https://sosumi.ai/documentation/foundation/urlresourcevalues)
|
|
170
|
+
|
|
171
|
+
### Setting the Exclusion Flag
|
|
172
|
+
|
|
173
|
+
```swift
|
|
174
|
+
import Foundation
|
|
175
|
+
|
|
176
|
+
// Exclude a file or directory from backup
|
|
177
|
+
func excludeFromBackup(_ url: URL) throws {
|
|
178
|
+
var resourceValues = URLResourceValues()
|
|
179
|
+
resourceValues.isExcludedFromBackup = true
|
|
180
|
+
var mutableURL = url
|
|
181
|
+
try mutableURL.setResourceValues(resourceValues)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Usage
|
|
185
|
+
let largeCache = cachesURL.appendingPathComponent("video-cache")
|
|
186
|
+
try excludeFromBackup(largeCache)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Checking the Exclusion Flag
|
|
190
|
+
|
|
191
|
+
```swift
|
|
192
|
+
func isExcludedFromBackup(_ url: URL) throws -> Bool {
|
|
193
|
+
let values = try url.resourceValues(forKeys: [.isExcludedFromBackupKey])
|
|
194
|
+
return values.isExcludedFromBackup ?? false
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### When to Exclude from Backup
|
|
199
|
+
|
|
200
|
+
| Exclude | Keep in Backup |
|
|
201
|
+
|---|---|
|
|
202
|
+
| Downloaded media (images, videos, audio) | User-created documents |
|
|
203
|
+
| API response caches | User preferences and settings |
|
|
204
|
+
| Generated thumbnails or previews | App databases with user data |
|
|
205
|
+
| Offline map tiles | In-app purchase receipts |
|
|
206
|
+
| Pre-computed search indexes | User-generated content |
|
|
207
|
+
|
|
208
|
+
### Common Pattern: Application Support with Exclusion
|
|
209
|
+
|
|
210
|
+
Store re-downloadable data in Application Support but exclude from backup:
|
|
211
|
+
|
|
212
|
+
```swift
|
|
213
|
+
let offlineDataURL = appSupportURL.appendingPathComponent("OfflineData")
|
|
214
|
+
try FileManager.default.createDirectory(
|
|
215
|
+
at: offlineDataURL, withIntermediateDirectories: true
|
|
216
|
+
)
|
|
217
|
+
try excludeFromBackup(offlineDataURL)
|
|
218
|
+
|
|
219
|
+
// Files in this directory persist across app updates but don't bloat backup
|
|
220
|
+
try downloadedData.write(to: offlineDataURL.appendingPathComponent("map-tiles.db"))
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Storage Pressure Handling
|
|
224
|
+
|
|
225
|
+
When the device runs low on storage, iOS may purge files in `Library/Caches/`
|
|
226
|
+
and `tmp/`. Apps should proactively manage storage and respond to low-space
|
|
227
|
+
conditions.
|
|
228
|
+
|
|
229
|
+
### Checking Available Storage
|
|
230
|
+
|
|
231
|
+
```swift
|
|
232
|
+
import Foundation
|
|
233
|
+
|
|
234
|
+
func availableDiskSpace() throws -> Int64 {
|
|
235
|
+
let values = try URL(fileURLWithPath: NSHomeDirectory())
|
|
236
|
+
.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey])
|
|
237
|
+
return values.volumeAvailableCapacityForImportantUsage ?? 0
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Use .volumeAvailableCapacityForImportantUsageKey for important operations
|
|
241
|
+
// Use .volumeAvailableCapacityForOpportunisticUsageKey for optional operations
|
|
242
|
+
// The opportunistic value is always <= the important value
|
|
243
|
+
|
|
244
|
+
func hasSpaceForDownload(bytes: Int64) throws -> Bool {
|
|
245
|
+
let available = try availableDiskSpace()
|
|
246
|
+
return available > bytes
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Responding to Low Storage Notifications
|
|
251
|
+
|
|
252
|
+
```swift
|
|
253
|
+
import UIKit
|
|
254
|
+
|
|
255
|
+
// iOS posts this when storage is critically low (UIKit apps)
|
|
256
|
+
NotificationCenter.default.addObserver(
|
|
257
|
+
forName: UIApplication.didReceiveMemoryWarningNotification,
|
|
258
|
+
object: nil,
|
|
259
|
+
queue: .main
|
|
260
|
+
) { _ in
|
|
261
|
+
// Clear in-memory caches; consider trimming disk caches too
|
|
262
|
+
clearImageCache()
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Check storage proactively at app launch or before large operations
|
|
266
|
+
func checkStorageAndCleanup() throws {
|
|
267
|
+
let availableBytes = try availableDiskSpace()
|
|
268
|
+
let threshold: Int64 = 100 * 1024 * 1024 // 100 MB
|
|
269
|
+
|
|
270
|
+
if availableBytes < threshold {
|
|
271
|
+
try performCleanup()
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Implementing Cleanup Strategies
|
|
277
|
+
|
|
278
|
+
```swift
|
|
279
|
+
import Foundation
|
|
280
|
+
|
|
281
|
+
struct StorageCleaner {
|
|
282
|
+
let cachesURL: URL
|
|
283
|
+
let maxCacheAge: TimeInterval // e.g., 7 days
|
|
284
|
+
let maxCacheSize: Int64 // e.g., 500 MB
|
|
285
|
+
|
|
286
|
+
/// Remove files older than maxCacheAge
|
|
287
|
+
func removeExpiredFiles() throws {
|
|
288
|
+
let contents = try FileManager.default.contentsOfDirectory(
|
|
289
|
+
at: cachesURL,
|
|
290
|
+
includingPropertiesForKeys: [.contentModificationDateKey, .fileSizeKey],
|
|
291
|
+
options: .skipsHiddenFiles
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
let cutoff = Date.now.addingTimeInterval(-maxCacheAge)
|
|
295
|
+
|
|
296
|
+
for fileURL in contents {
|
|
297
|
+
let values = try fileURL.resourceValues(
|
|
298
|
+
forKeys: [.contentModificationDateKey]
|
|
299
|
+
)
|
|
300
|
+
if let modified = values.contentModificationDate, modified < cutoff {
|
|
301
|
+
try FileManager.default.removeItem(at: fileURL)
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/// Trim cache to maxCacheSize using LRU eviction
|
|
307
|
+
func trimToSize() throws {
|
|
308
|
+
let contents = try FileManager.default.contentsOfDirectory(
|
|
309
|
+
at: cachesURL,
|
|
310
|
+
includingPropertiesForKeys: [.contentModificationDateKey, .fileSizeKey],
|
|
311
|
+
options: .skipsHiddenFiles
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
// Sort oldest first
|
|
315
|
+
let sorted = try contents.sorted { a, b in
|
|
316
|
+
let aDate = try a.resourceValues(forKeys: [.contentModificationDateKey])
|
|
317
|
+
.contentModificationDate ?? .distantPast
|
|
318
|
+
let bDate = try b.resourceValues(forKeys: [.contentModificationDateKey])
|
|
319
|
+
.contentModificationDate ?? .distantPast
|
|
320
|
+
return aDate < bDate
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Calculate total size
|
|
324
|
+
var totalSize: Int64 = 0
|
|
325
|
+
for fileURL in sorted {
|
|
326
|
+
let values = try fileURL.resourceValues(forKeys: [.fileSizeKey])
|
|
327
|
+
totalSize += Int64(values.fileSize ?? 0)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Delete oldest files until under budget
|
|
331
|
+
for fileURL in sorted {
|
|
332
|
+
guard totalSize > maxCacheSize else { break }
|
|
333
|
+
let values = try fileURL.resourceValues(forKeys: [.fileSizeKey])
|
|
334
|
+
let fileSize = Int64(values.fileSize ?? 0)
|
|
335
|
+
try FileManager.default.removeItem(at: fileURL)
|
|
336
|
+
totalSize -= fileSize
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/// Full cleanup: expired files first, then trim to size
|
|
341
|
+
func performCleanup() throws {
|
|
342
|
+
try removeExpiredFiles()
|
|
343
|
+
try trimToSize()
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Usage
|
|
348
|
+
let cleaner = StorageCleaner(
|
|
349
|
+
cachesURL: FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!,
|
|
350
|
+
maxCacheAge: 7 * 24 * 60 * 60, // 7 days
|
|
351
|
+
maxCacheSize: 500 * 1024 * 1024 // 500 MB
|
|
352
|
+
)
|
|
353
|
+
try cleaner.performCleanup()
|
|
354
|
+
```
|