@devo-bmad-custom/agent-orchestration 1.0.1 → 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 +44 -11
- 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/bmad-track-compact.md +1 -1
- package/src/.claude/commands/bmad-track-extended.md +1 -1
- package/src/.claude/commands/bmad-track-large.md +1 -1
- package/src/.claude/commands/bmad-track-medium.md +1 -1
- package/src/.claude/commands/bmad-track-nano.md +1 -1
- package/src/.claude/commands/bmad-track-rv.md +1 -1
- package/src/.claude/commands/bmad-track-small.md +1 -1
- 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/review-agent.md +1 -1
- 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/agents/master-orchestrator.md +3 -3
- 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,584 +1,584 @@
|
|
|
1
|
-
# AlarmKit Patterns
|
|
2
|
-
|
|
3
|
-
Complete implementation patterns for AlarmKit alarms, countdown timers,
|
|
4
|
-
authorization, state observation, and Live Activity integration. All patterns
|
|
5
|
-
target iOS 26+ / iPadOS 26+ with Swift 6.2.
|
|
6
|
-
|
|
7
|
-
## Contents
|
|
8
|
-
- Complete Alarm Scheduling Flow
|
|
9
|
-
- Complete Countdown Timer Flow
|
|
10
|
-
- Authorization Manager
|
|
11
|
-
- State Observation with Async Sequences
|
|
12
|
-
- Live Activity Widget Extension for Alarms
|
|
13
|
-
- Recurring Alarm Patterns
|
|
14
|
-
- Snooze and Dismiss Handling
|
|
15
|
-
- Info.plist Configuration
|
|
16
|
-
- Error Handling
|
|
17
|
-
- Apple Documentation Links
|
|
18
|
-
|
|
19
|
-
## Complete Alarm Scheduling Flow
|
|
20
|
-
|
|
21
|
-
End-to-end pattern for scheduling a wake-up alarm with snooze support.
|
|
22
|
-
|
|
23
|
-
```swift
|
|
24
|
-
import AlarmKit
|
|
25
|
-
import AppIntents
|
|
26
|
-
|
|
27
|
-
struct StopAlarmIntent: LiveActivityIntent {
|
|
28
|
-
static var title: LocalizedStringResource = "Stop Alarm"
|
|
29
|
-
@Parameter(title: "Alarm ID") var alarmID: String
|
|
30
|
-
init() {}
|
|
31
|
-
init(alarmID: String) { self.alarmID = alarmID }
|
|
32
|
-
func perform() async throws -> some IntentResult {
|
|
33
|
-
try AlarmManager.shared.stop(id: UUID(uuidString: alarmID)!)
|
|
34
|
-
return .result()
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
struct SnoozeAlarmIntent: LiveActivityIntent {
|
|
39
|
-
static var title: LocalizedStringResource = "Snooze Alarm"
|
|
40
|
-
@Parameter(title: "Alarm ID") var alarmID: String
|
|
41
|
-
init() {}
|
|
42
|
-
init(alarmID: String) { self.alarmID = alarmID }
|
|
43
|
-
func perform() async throws -> some IntentResult {
|
|
44
|
-
try AlarmManager.shared.countdown(id: UUID(uuidString: alarmID)!)
|
|
45
|
-
return .result()
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
struct WakeUpMetadata: AlarmMetadata {
|
|
50
|
-
var label: String
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
@MainActor
|
|
54
|
-
func scheduleWakeUpAlarm(
|
|
55
|
-
hour: Int, minute: Int, label: String
|
|
56
|
-
) async throws -> Alarm {
|
|
57
|
-
let manager = AlarmManager.shared
|
|
58
|
-
let authState = try await manager.requestAuthorization()
|
|
59
|
-
guard authState == .authorized else { throw AlarmSchedulingError.notAuthorized }
|
|
60
|
-
|
|
61
|
-
let alert = AlarmPresentation.Alert(
|
|
62
|
-
title: LocalizedStringResource(stringLiteral: label),
|
|
63
|
-
secondaryButton: AlarmButton(
|
|
64
|
-
text: "Snooze", textColor: .white, systemImageName: "bell.slash"
|
|
65
|
-
),
|
|
66
|
-
secondaryButtonBehavior: .countdown
|
|
67
|
-
)
|
|
68
|
-
let presentation = AlarmPresentation(alert: alert)
|
|
69
|
-
let attributes = AlarmAttributes(
|
|
70
|
-
presentation: presentation,
|
|
71
|
-
metadata: WakeUpMetadata(label: label),
|
|
72
|
-
tintColor: .indigo
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
let id = UUID()
|
|
76
|
-
let config = AlarmManager.AlarmConfiguration.alarm(
|
|
77
|
-
schedule: .relative(.init(
|
|
78
|
-
time: .init(hour: hour, minute: minute), repeats: .never
|
|
79
|
-
)),
|
|
80
|
-
attributes: attributes,
|
|
81
|
-
stopIntent: StopAlarmIntent(alarmID: id.uuidString),
|
|
82
|
-
secondaryIntent: SnoozeAlarmIntent(alarmID: id.uuidString),
|
|
83
|
-
sound: .default
|
|
84
|
-
)
|
|
85
|
-
return try await manager.schedule(id: id, configuration: config)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
enum AlarmSchedulingError: Error {
|
|
89
|
-
case notAuthorized
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## Complete Countdown Timer Flow
|
|
94
|
-
|
|
95
|
-
End-to-end pattern for a countdown timer with pause/resume support.
|
|
96
|
-
|
|
97
|
-
```swift
|
|
98
|
-
import AlarmKit
|
|
99
|
-
import AppIntents
|
|
100
|
-
|
|
101
|
-
struct StopTimerIntent: LiveActivityIntent {
|
|
102
|
-
static var title: LocalizedStringResource = "Stop Timer"
|
|
103
|
-
@Parameter(title: "Timer ID") var timerID: String
|
|
104
|
-
init() {}
|
|
105
|
-
init(timerID: String) { self.timerID = timerID }
|
|
106
|
-
func perform() async throws -> some IntentResult {
|
|
107
|
-
try AlarmManager.shared.stop(id: UUID(uuidString: timerID)!)
|
|
108
|
-
return .result()
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
struct CookingTimerMetadata: AlarmMetadata {
|
|
113
|
-
var recipeName: String
|
|
114
|
-
var stepDescription: String
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
@MainActor
|
|
118
|
-
func startCookingTimer(
|
|
119
|
-
durationSeconds: TimeInterval, recipeName: String, step: String
|
|
120
|
-
) async throws -> Alarm {
|
|
121
|
-
let manager = AlarmManager.shared
|
|
122
|
-
let authState = try await manager.requestAuthorization()
|
|
123
|
-
guard authState == .authorized else { throw AlarmSchedulingError.notAuthorized }
|
|
124
|
-
|
|
125
|
-
let alert = AlarmPresentation.Alert(
|
|
126
|
-
title: LocalizedStringResource(stringLiteral: "\(recipeName): \(step)"),
|
|
127
|
-
secondaryButton: nil, secondaryButtonBehavior: nil
|
|
128
|
-
)
|
|
129
|
-
let countdown = AlarmPresentation.Countdown(
|
|
130
|
-
title: LocalizedStringResource(stringLiteral: recipeName),
|
|
131
|
-
pauseButton: AlarmButton(
|
|
132
|
-
text: "Pause", textColor: .orange, systemImageName: "pause.fill"
|
|
133
|
-
)
|
|
134
|
-
)
|
|
135
|
-
let paused = AlarmPresentation.Paused(
|
|
136
|
-
title: "Paused",
|
|
137
|
-
resumeButton: AlarmButton(
|
|
138
|
-
text: "Resume", textColor: .green, systemImageName: "play.fill"
|
|
139
|
-
)
|
|
140
|
-
)
|
|
141
|
-
let presentation = AlarmPresentation(
|
|
142
|
-
alert: alert, countdown: countdown, paused: paused
|
|
143
|
-
)
|
|
144
|
-
let attributes = AlarmAttributes(
|
|
145
|
-
presentation: presentation,
|
|
146
|
-
metadata: CookingTimerMetadata(recipeName: recipeName, stepDescription: step),
|
|
147
|
-
tintColor: .orange
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
let id = UUID()
|
|
151
|
-
let config = AlarmManager.AlarmConfiguration.timer(
|
|
152
|
-
duration: durationSeconds,
|
|
153
|
-
attributes: attributes,
|
|
154
|
-
stopIntent: StopTimerIntent(timerID: id.uuidString),
|
|
155
|
-
sound: .default
|
|
156
|
-
)
|
|
157
|
-
return try await manager.schedule(id: id, configuration: config)
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
## Authorization Manager
|
|
162
|
-
|
|
163
|
-
Observable pattern for centralized authorization management.
|
|
164
|
-
|
|
165
|
-
```swift
|
|
166
|
-
import AlarmKit
|
|
167
|
-
import Observation
|
|
168
|
-
|
|
169
|
-
@Observable
|
|
170
|
-
@MainActor
|
|
171
|
-
final class AlarmAuthorizationManager {
|
|
172
|
-
private let manager = AlarmManager.shared
|
|
173
|
-
private(set) var isAuthorized = false
|
|
174
|
-
private(set) var authState: AlarmManager.AuthorizationState = .notDetermined
|
|
175
|
-
|
|
176
|
-
init() {
|
|
177
|
-
authState = manager.authorizationState
|
|
178
|
-
isAuthorized = authState == .authorized
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
func requestIfNeeded() async throws -> Bool {
|
|
182
|
-
guard authState == .notDetermined else { return isAuthorized }
|
|
183
|
-
let state = try await manager.requestAuthorization()
|
|
184
|
-
authState = state
|
|
185
|
-
isAuthorized = state == .authorized
|
|
186
|
-
return isAuthorized
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
func observeAuthorizationChanges() async {
|
|
190
|
-
for await state in manager.authorizationUpdates {
|
|
191
|
-
authState = state
|
|
192
|
-
isAuthorized = state == .authorized
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Usage in SwiftUI
|
|
198
|
-
struct AlarmSettingsView: View {
|
|
199
|
-
@State private var authManager = AlarmAuthorizationManager()
|
|
200
|
-
|
|
201
|
-
var body: some View {
|
|
202
|
-
Group {
|
|
203
|
-
if authManager.isAuthorized {
|
|
204
|
-
Text("Alarms are enabled")
|
|
205
|
-
} else if authManager.authState == .denied {
|
|
206
|
-
ContentUnavailableView(
|
|
207
|
-
"Alarms Disabled", systemImage: "alarm.waves.left.and.right",
|
|
208
|
-
description: Text("Enable in Settings > Your App > Alarms & Timers.")
|
|
209
|
-
)
|
|
210
|
-
} else {
|
|
211
|
-
Button("Enable Alarms") {
|
|
212
|
-
Task { try? await authManager.requestIfNeeded() }
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
.task { await authManager.observeAuthorizationChanges() }
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
## State Observation with Async Sequences
|
|
222
|
-
|
|
223
|
-
Pattern for tracking all alarms and reacting to state changes.
|
|
224
|
-
|
|
225
|
-
```swift
|
|
226
|
-
import AlarmKit
|
|
227
|
-
import Observation
|
|
228
|
-
|
|
229
|
-
@Observable
|
|
230
|
-
@MainActor
|
|
231
|
-
final class AlarmStore {
|
|
232
|
-
private let manager = AlarmManager.shared
|
|
233
|
-
private(set) var alarms: [Alarm] = []
|
|
234
|
-
|
|
235
|
-
init() { alarms = manager.alarms }
|
|
236
|
-
|
|
237
|
-
func startObserving() async {
|
|
238
|
-
for await updatedAlarms in manager.alarmUpdates {
|
|
239
|
-
alarms = updatedAlarms
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
func alarm(for id: UUID) -> Alarm? { alarms.first { $0.id == id } }
|
|
244
|
-
func alarms(in state: Alarm.State) -> [Alarm] { alarms.filter { $0.state == state } }
|
|
245
|
-
|
|
246
|
-
func cancel(_ id: Alarm.ID) throws { try manager.cancel(id: id) }
|
|
247
|
-
func pause(_ id: Alarm.ID) throws { try manager.pause(id: id) }
|
|
248
|
-
func resume(_ id: Alarm.ID) throws { try manager.resume(id: id) }
|
|
249
|
-
func stop(_ id: Alarm.ID) throws { try manager.stop(id: id) }
|
|
250
|
-
func snooze(_ id: Alarm.ID) throws { try manager.countdown(id: id) }
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Usage in SwiftUI
|
|
254
|
-
struct AlarmListView: View {
|
|
255
|
-
@State private var store = AlarmStore()
|
|
256
|
-
|
|
257
|
-
var body: some View {
|
|
258
|
-
List(store.alarms, id: \.id) { alarm in
|
|
259
|
-
HStack {
|
|
260
|
-
Text(alarm.id.uuidString.prefix(8)).font(.headline)
|
|
261
|
-
Spacer()
|
|
262
|
-
switch alarm.state {
|
|
263
|
-
case .scheduled:
|
|
264
|
-
Button("Cancel", role: .destructive) { try? store.cancel(alarm.id) }
|
|
265
|
-
case .countdown:
|
|
266
|
-
Button("Pause") { try? store.pause(alarm.id) }
|
|
267
|
-
case .paused:
|
|
268
|
-
Button("Resume") { try? store.resume(alarm.id) }
|
|
269
|
-
case .alerting:
|
|
270
|
-
Button("Stop") { try? store.stop(alarm.id) }
|
|
271
|
-
@unknown default:
|
|
272
|
-
EmptyView()
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
.task { await store.startObserving() }
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
## Live Activity Widget Extension for Alarms
|
|
282
|
-
|
|
283
|
-
Widget extension that renders countdown and paused states. Required when
|
|
284
|
-
your alarm uses countdown presentation.
|
|
285
|
-
|
|
286
|
-
```swift
|
|
287
|
-
import WidgetKit
|
|
288
|
-
import SwiftUI
|
|
289
|
-
import AlarmKit
|
|
290
|
-
|
|
291
|
-
// MARK: - Widget bundle
|
|
292
|
-
|
|
293
|
-
struct AlarmWidgetBundle: WidgetBundle {
|
|
294
|
-
var body: some Widget {
|
|
295
|
-
AlarmLiveActivityWidget()
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// MARK: - Live Activity configuration
|
|
300
|
-
|
|
301
|
-
struct AlarmLiveActivityWidget: Widget {
|
|
302
|
-
var body: some WidgetConfiguration {
|
|
303
|
-
ActivityConfiguration(for: AlarmAttributes<CookingTimerMetadata>.self) { context in
|
|
304
|
-
AlarmLockScreenView(context: context)
|
|
305
|
-
} dynamicIsland: { context in
|
|
306
|
-
DynamicIsland {
|
|
307
|
-
DynamicIslandExpandedRegion(.leading) {
|
|
308
|
-
Image(systemName: "alarm.fill")
|
|
309
|
-
.font(.title2)
|
|
310
|
-
.foregroundStyle(context.attributes.tintColor)
|
|
311
|
-
}
|
|
312
|
-
DynamicIslandExpandedRegion(.trailing) {
|
|
313
|
-
AlarmCountdownText(state: context.state)
|
|
314
|
-
.font(.title3.monospacedDigit())
|
|
315
|
-
}
|
|
316
|
-
DynamicIslandExpandedRegion(.center) {
|
|
317
|
-
Text(context.attributes.metadata?.recipeName ?? "Timer")
|
|
318
|
-
.font(.headline)
|
|
319
|
-
}
|
|
320
|
-
DynamicIslandExpandedRegion(.bottom) {
|
|
321
|
-
if let step = context.attributes.metadata?.stepDescription {
|
|
322
|
-
Text(step).font(.subheadline).foregroundStyle(.secondary)
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
} compactLeading: {
|
|
326
|
-
Image(systemName: "alarm.fill").foregroundStyle(context.attributes.tintColor)
|
|
327
|
-
} compactTrailing: {
|
|
328
|
-
AlarmCountdownText(state: context.state)
|
|
329
|
-
.frame(width: 44).monospacedDigit()
|
|
330
|
-
} minimal: {
|
|
331
|
-
Image(systemName: "alarm.fill").foregroundStyle(context.attributes.tintColor)
|
|
332
|
-
}
|
|
333
|
-
.keylineTint(context.attributes.tintColor)
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// MARK: - Lock Screen view
|
|
339
|
-
|
|
340
|
-
struct AlarmLockScreenView: View {
|
|
341
|
-
let context: ActivityViewContext<AlarmAttributes<CookingTimerMetadata>>
|
|
342
|
-
|
|
343
|
-
var body: some View {
|
|
344
|
-
VStack(alignment: .leading, spacing: 8) {
|
|
345
|
-
HStack {
|
|
346
|
-
Image(systemName: "alarm.fill")
|
|
347
|
-
.foregroundStyle(context.attributes.tintColor)
|
|
348
|
-
Text(context.attributes.metadata?.recipeName ?? "Timer")
|
|
349
|
-
.font(.headline)
|
|
350
|
-
Spacer()
|
|
351
|
-
AlarmCountdownText(state: context.state)
|
|
352
|
-
.font(.title3.monospacedDigit().bold())
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
switch context.state.mode {
|
|
356
|
-
case .countdown(let info):
|
|
357
|
-
ProgressView(
|
|
358
|
-
value: info.previouslyElapsedDuration,
|
|
359
|
-
total: info.totalCountdownDuration
|
|
360
|
-
)
|
|
361
|
-
.tint(context.attributes.tintColor)
|
|
362
|
-
case .paused:
|
|
363
|
-
Label("Paused", systemImage: "pause.fill")
|
|
364
|
-
.font(.subheadline).foregroundStyle(.secondary)
|
|
365
|
-
case .alert:
|
|
366
|
-
EmptyView() // System handles alerting UI
|
|
367
|
-
@unknown default:
|
|
368
|
-
EmptyView()
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
.padding()
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// MARK: - Helper views
|
|
376
|
-
|
|
377
|
-
struct AlarmCountdownText: View {
|
|
378
|
-
let state: AlarmPresentationState
|
|
379
|
-
|
|
380
|
-
var body: some View {
|
|
381
|
-
switch state.mode {
|
|
382
|
-
case .countdown(let info):
|
|
383
|
-
Text(info.fireDate, style: .timer)
|
|
384
|
-
case .paused(let info):
|
|
385
|
-
let remaining = info.totalCountdownDuration - info.previouslyElapsedDuration
|
|
386
|
-
Text(Duration.seconds(remaining), format: .time(pattern: .minuteSecond))
|
|
387
|
-
case .alert(let info):
|
|
388
|
-
Text("\(info.time.hour):\(String(format: "%02d", info.time.minute))")
|
|
389
|
-
@unknown default:
|
|
390
|
-
Text("--:--")
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
## Recurring Alarm Patterns
|
|
397
|
-
|
|
398
|
-
```swift
|
|
399
|
-
// Daily alarm (every day)
|
|
400
|
-
let dailySchedule = Alarm.Schedule.relative(.init(
|
|
401
|
-
time: .init(hour: 7, minute: 0),
|
|
402
|
-
repeats: .weekly([.sunday, .monday, .tuesday, .wednesday,
|
|
403
|
-
.thursday, .friday, .saturday])
|
|
404
|
-
))
|
|
405
|
-
|
|
406
|
-
// Weekday-only alarm
|
|
407
|
-
let weekdaySchedule = Alarm.Schedule.relative(.init(
|
|
408
|
-
time: .init(hour: 6, minute: 30),
|
|
409
|
-
repeats: .weekly([.monday, .tuesday, .wednesday, .thursday, .friday])
|
|
410
|
-
))
|
|
411
|
-
|
|
412
|
-
// Weekend alarm
|
|
413
|
-
let weekendSchedule = Alarm.Schedule.relative(.init(
|
|
414
|
-
time: .init(hour: 9, minute: 0),
|
|
415
|
-
repeats: .weekly([.saturday, .sunday])
|
|
416
|
-
))
|
|
417
|
-
|
|
418
|
-
// One-time alarm at a specific Date
|
|
419
|
-
let targetDate = Calendar.current.date(
|
|
420
|
-
from: DateComponents(year: 2026, month: 6, day: 15, hour: 14, minute: 30)
|
|
421
|
-
)!
|
|
422
|
-
let fixedSchedule = Alarm.Schedule.fixed(targetDate)
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
## Snooze and Dismiss Handling
|
|
426
|
-
|
|
427
|
-
Pattern for alarm with snooze (countdown behavior) and custom secondary action.
|
|
428
|
-
|
|
429
|
-
### Snooze with countdown restart
|
|
430
|
-
|
|
431
|
-
```swift
|
|
432
|
-
func scheduleAlarmWithSnooze(
|
|
433
|
-
hour: Int, minute: Int, snoozeDurationSeconds: TimeInterval
|
|
434
|
-
) async throws -> Alarm {
|
|
435
|
-
let id = UUID()
|
|
436
|
-
let alert = AlarmPresentation.Alert(
|
|
437
|
-
title: "Good Morning",
|
|
438
|
-
secondaryButton: AlarmButton(
|
|
439
|
-
text: "Snooze 5 min", textColor: .white, systemImageName: "zzz"
|
|
440
|
-
),
|
|
441
|
-
secondaryButtonBehavior: .countdown // tapping Snooze restarts countdown
|
|
442
|
-
)
|
|
443
|
-
// postAlert defines the snooze duration
|
|
444
|
-
let countdown = Alarm.CountdownDuration(
|
|
445
|
-
preAlert: nil, postAlert: snoozeDurationSeconds
|
|
446
|
-
)
|
|
447
|
-
let countdownPresentation = AlarmPresentation.Countdown(
|
|
448
|
-
title: "Snoozing...", pauseButton: nil
|
|
449
|
-
)
|
|
450
|
-
let presentation = AlarmPresentation(
|
|
451
|
-
alert: alert, countdown: countdownPresentation
|
|
452
|
-
)
|
|
453
|
-
let attributes = AlarmAttributes(
|
|
454
|
-
presentation: presentation,
|
|
455
|
-
metadata: nil as WakeUpMetadata?,
|
|
456
|
-
tintColor: .purple
|
|
457
|
-
)
|
|
458
|
-
let config = AlarmManager.AlarmConfiguration(
|
|
459
|
-
countdownDuration: countdown,
|
|
460
|
-
schedule: .relative(.init(
|
|
461
|
-
time: .init(hour: hour, minute: minute), repeats: .never
|
|
462
|
-
)),
|
|
463
|
-
attributes: attributes,
|
|
464
|
-
stopIntent: StopAlarmIntent(alarmID: id.uuidString),
|
|
465
|
-
secondaryIntent: SnoozeAlarmIntent(alarmID: id.uuidString),
|
|
466
|
-
sound: .default
|
|
467
|
-
)
|
|
468
|
-
return try await AlarmManager.shared.schedule(id: id, configuration: config)
|
|
469
|
-
}
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
### Custom secondary action (open app)
|
|
473
|
-
|
|
474
|
-
Use `.custom` behavior to trigger the `secondaryIntent` instead of restarting
|
|
475
|
-
a countdown. The intent opens the app or performs custom logic.
|
|
476
|
-
|
|
477
|
-
```swift
|
|
478
|
-
struct OpenAppIntent: LiveActivityIntent {
|
|
479
|
-
static var title: LocalizedStringResource = "Open App"
|
|
480
|
-
func perform() async throws -> some IntentResult { .result() }
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
func scheduleAlarmWithOpenAction(hour: Int, minute: Int) async throws -> Alarm {
|
|
484
|
-
let id = UUID()
|
|
485
|
-
let alert = AlarmPresentation.Alert(
|
|
486
|
-
title: "Medication Reminder",
|
|
487
|
-
secondaryButton: AlarmButton(
|
|
488
|
-
text: "Open", textColor: .blue, systemImageName: "pill.fill"
|
|
489
|
-
),
|
|
490
|
-
secondaryButtonBehavior: .custom // triggers secondaryIntent
|
|
491
|
-
)
|
|
492
|
-
let presentation = AlarmPresentation(alert: alert)
|
|
493
|
-
let attributes = AlarmAttributes<WakeUpMetadata>(
|
|
494
|
-
presentation: presentation, metadata: nil, tintColor: .blue
|
|
495
|
-
)
|
|
496
|
-
let config = AlarmManager.AlarmConfiguration.alarm(
|
|
497
|
-
schedule: .relative(.init(
|
|
498
|
-
time: .init(hour: hour, minute: minute), repeats: .never
|
|
499
|
-
)),
|
|
500
|
-
attributes: attributes,
|
|
501
|
-
stopIntent: StopAlarmIntent(alarmID: id.uuidString),
|
|
502
|
-
secondaryIntent: OpenAppIntent(),
|
|
503
|
-
sound: .default
|
|
504
|
-
)
|
|
505
|
-
return try await AlarmManager.shared.schedule(id: id, configuration: config)
|
|
506
|
-
}
|
|
507
|
-
```
|
|
508
|
-
|
|
509
|
-
## Info.plist Configuration
|
|
510
|
-
|
|
511
|
-
### Required key
|
|
512
|
-
|
|
513
|
-
```xml
|
|
514
|
-
<key>NSAlarmKitUsageDescription</key>
|
|
515
|
-
<string>We schedule alerts for alarms and timers you create.</string>
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
This key is **mandatory**. If missing or empty, `schedule(id:configuration:)`
|
|
519
|
-
will fail and no alarms can be created by the app.
|
|
520
|
-
|
|
521
|
-
### Recommended: NSSupportsLiveActivities
|
|
522
|
-
|
|
523
|
-
Since alarms create Live Activities, also include:
|
|
524
|
-
|
|
525
|
-
```xml
|
|
526
|
-
<key>NSSupportsLiveActivities</key>
|
|
527
|
-
<true/>
|
|
528
|
-
```
|
|
529
|
-
|
|
530
|
-
## Error Handling
|
|
531
|
-
|
|
532
|
-
```swift
|
|
533
|
-
import AlarmKit
|
|
534
|
-
|
|
535
|
-
func scheduleAlarmSafely(
|
|
536
|
-
id: UUID,
|
|
537
|
-
configuration: AlarmManager.AlarmConfiguration<some AlarmMetadata>
|
|
538
|
-
) async {
|
|
539
|
-
guard AlarmManager.shared.authorizationState == .authorized else {
|
|
540
|
-
print("Not authorized -- request authorization first")
|
|
541
|
-
return
|
|
542
|
-
}
|
|
543
|
-
do {
|
|
544
|
-
let alarm = try await AlarmManager.shared.schedule(
|
|
545
|
-
id: id, configuration: configuration
|
|
546
|
-
)
|
|
547
|
-
print("Scheduled alarm: \(alarm.id), state: \(alarm.state)")
|
|
548
|
-
} catch let error as AlarmManager.AlarmError {
|
|
549
|
-
switch error {
|
|
550
|
-
case .maximumLimitReached:
|
|
551
|
-
print("Too many alarms -- cancel an existing one first")
|
|
552
|
-
@unknown default:
|
|
553
|
-
print("AlarmKit error: \(error)")
|
|
554
|
-
}
|
|
555
|
-
} catch {
|
|
556
|
-
print("Unexpected error: \(error)")
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
// State transition helpers -- each throws if alarm is in wrong state
|
|
561
|
-
func cancelAlarmSafely(id: Alarm.ID) {
|
|
562
|
-
do { try AlarmManager.shared.cancel(id: id) }
|
|
563
|
-
catch { print("Failed to cancel: \(error)") }
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
func pauseAlarmSafely(id: Alarm.ID) {
|
|
567
|
-
// Only valid when alarm is in .countdown state
|
|
568
|
-
do { try AlarmManager.shared.pause(id: id) }
|
|
569
|
-
catch { print("Cannot pause: \(error)") }
|
|
570
|
-
}
|
|
571
|
-
```
|
|
572
|
-
|
|
573
|
-
## Apple Documentation Links
|
|
574
|
-
|
|
575
|
-
- [AlarmKit](https://sosumi.ai/documentation/alarmkit)
|
|
576
|
-
- [AlarmManager](https://sosumi.ai/documentation/alarmkit/alarmmanager)
|
|
577
|
-
- [AlarmAttributes](https://sosumi.ai/documentation/alarmkit/alarmattributes)
|
|
578
|
-
- [AlarmPresentation](https://sosumi.ai/documentation/alarmkit/alarmpresentation)
|
|
579
|
-
- [AlarmPresentationState](https://sosumi.ai/documentation/alarmkit/alarmpresentationstate)
|
|
580
|
-
- [AlarmButton](https://sosumi.ai/documentation/alarmkit/alarmbutton)
|
|
581
|
-
- [Alarm](https://sosumi.ai/documentation/alarmkit/alarm)
|
|
582
|
-
- [Alarm.Schedule](https://sosumi.ai/documentation/alarmkit/alarm/schedule-swift.enum)
|
|
583
|
-
- [Alarm.CountdownDuration](https://sosumi.ai/documentation/alarmkit/alarm/countdownduration-swift.struct)
|
|
584
|
-
- [Scheduling an alarm with AlarmKit](https://sosumi.ai/documentation/alarmkit/scheduling-an-alarm-with-alarmkit)
|
|
1
|
+
# AlarmKit Patterns
|
|
2
|
+
|
|
3
|
+
Complete implementation patterns for AlarmKit alarms, countdown timers,
|
|
4
|
+
authorization, state observation, and Live Activity integration. All patterns
|
|
5
|
+
target iOS 26+ / iPadOS 26+ with Swift 6.2.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
- Complete Alarm Scheduling Flow
|
|
9
|
+
- Complete Countdown Timer Flow
|
|
10
|
+
- Authorization Manager
|
|
11
|
+
- State Observation with Async Sequences
|
|
12
|
+
- Live Activity Widget Extension for Alarms
|
|
13
|
+
- Recurring Alarm Patterns
|
|
14
|
+
- Snooze and Dismiss Handling
|
|
15
|
+
- Info.plist Configuration
|
|
16
|
+
- Error Handling
|
|
17
|
+
- Apple Documentation Links
|
|
18
|
+
|
|
19
|
+
## Complete Alarm Scheduling Flow
|
|
20
|
+
|
|
21
|
+
End-to-end pattern for scheduling a wake-up alarm with snooze support.
|
|
22
|
+
|
|
23
|
+
```swift
|
|
24
|
+
import AlarmKit
|
|
25
|
+
import AppIntents
|
|
26
|
+
|
|
27
|
+
struct StopAlarmIntent: LiveActivityIntent {
|
|
28
|
+
static var title: LocalizedStringResource = "Stop Alarm"
|
|
29
|
+
@Parameter(title: "Alarm ID") var alarmID: String
|
|
30
|
+
init() {}
|
|
31
|
+
init(alarmID: String) { self.alarmID = alarmID }
|
|
32
|
+
func perform() async throws -> some IntentResult {
|
|
33
|
+
try AlarmManager.shared.stop(id: UUID(uuidString: alarmID)!)
|
|
34
|
+
return .result()
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
struct SnoozeAlarmIntent: LiveActivityIntent {
|
|
39
|
+
static var title: LocalizedStringResource = "Snooze Alarm"
|
|
40
|
+
@Parameter(title: "Alarm ID") var alarmID: String
|
|
41
|
+
init() {}
|
|
42
|
+
init(alarmID: String) { self.alarmID = alarmID }
|
|
43
|
+
func perform() async throws -> some IntentResult {
|
|
44
|
+
try AlarmManager.shared.countdown(id: UUID(uuidString: alarmID)!)
|
|
45
|
+
return .result()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
struct WakeUpMetadata: AlarmMetadata {
|
|
50
|
+
var label: String
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@MainActor
|
|
54
|
+
func scheduleWakeUpAlarm(
|
|
55
|
+
hour: Int, minute: Int, label: String
|
|
56
|
+
) async throws -> Alarm {
|
|
57
|
+
let manager = AlarmManager.shared
|
|
58
|
+
let authState = try await manager.requestAuthorization()
|
|
59
|
+
guard authState == .authorized else { throw AlarmSchedulingError.notAuthorized }
|
|
60
|
+
|
|
61
|
+
let alert = AlarmPresentation.Alert(
|
|
62
|
+
title: LocalizedStringResource(stringLiteral: label),
|
|
63
|
+
secondaryButton: AlarmButton(
|
|
64
|
+
text: "Snooze", textColor: .white, systemImageName: "bell.slash"
|
|
65
|
+
),
|
|
66
|
+
secondaryButtonBehavior: .countdown
|
|
67
|
+
)
|
|
68
|
+
let presentation = AlarmPresentation(alert: alert)
|
|
69
|
+
let attributes = AlarmAttributes(
|
|
70
|
+
presentation: presentation,
|
|
71
|
+
metadata: WakeUpMetadata(label: label),
|
|
72
|
+
tintColor: .indigo
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
let id = UUID()
|
|
76
|
+
let config = AlarmManager.AlarmConfiguration.alarm(
|
|
77
|
+
schedule: .relative(.init(
|
|
78
|
+
time: .init(hour: hour, minute: minute), repeats: .never
|
|
79
|
+
)),
|
|
80
|
+
attributes: attributes,
|
|
81
|
+
stopIntent: StopAlarmIntent(alarmID: id.uuidString),
|
|
82
|
+
secondaryIntent: SnoozeAlarmIntent(alarmID: id.uuidString),
|
|
83
|
+
sound: .default
|
|
84
|
+
)
|
|
85
|
+
return try await manager.schedule(id: id, configuration: config)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
enum AlarmSchedulingError: Error {
|
|
89
|
+
case notAuthorized
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Complete Countdown Timer Flow
|
|
94
|
+
|
|
95
|
+
End-to-end pattern for a countdown timer with pause/resume support.
|
|
96
|
+
|
|
97
|
+
```swift
|
|
98
|
+
import AlarmKit
|
|
99
|
+
import AppIntents
|
|
100
|
+
|
|
101
|
+
struct StopTimerIntent: LiveActivityIntent {
|
|
102
|
+
static var title: LocalizedStringResource = "Stop Timer"
|
|
103
|
+
@Parameter(title: "Timer ID") var timerID: String
|
|
104
|
+
init() {}
|
|
105
|
+
init(timerID: String) { self.timerID = timerID }
|
|
106
|
+
func perform() async throws -> some IntentResult {
|
|
107
|
+
try AlarmManager.shared.stop(id: UUID(uuidString: timerID)!)
|
|
108
|
+
return .result()
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
struct CookingTimerMetadata: AlarmMetadata {
|
|
113
|
+
var recipeName: String
|
|
114
|
+
var stepDescription: String
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@MainActor
|
|
118
|
+
func startCookingTimer(
|
|
119
|
+
durationSeconds: TimeInterval, recipeName: String, step: String
|
|
120
|
+
) async throws -> Alarm {
|
|
121
|
+
let manager = AlarmManager.shared
|
|
122
|
+
let authState = try await manager.requestAuthorization()
|
|
123
|
+
guard authState == .authorized else { throw AlarmSchedulingError.notAuthorized }
|
|
124
|
+
|
|
125
|
+
let alert = AlarmPresentation.Alert(
|
|
126
|
+
title: LocalizedStringResource(stringLiteral: "\(recipeName): \(step)"),
|
|
127
|
+
secondaryButton: nil, secondaryButtonBehavior: nil
|
|
128
|
+
)
|
|
129
|
+
let countdown = AlarmPresentation.Countdown(
|
|
130
|
+
title: LocalizedStringResource(stringLiteral: recipeName),
|
|
131
|
+
pauseButton: AlarmButton(
|
|
132
|
+
text: "Pause", textColor: .orange, systemImageName: "pause.fill"
|
|
133
|
+
)
|
|
134
|
+
)
|
|
135
|
+
let paused = AlarmPresentation.Paused(
|
|
136
|
+
title: "Paused",
|
|
137
|
+
resumeButton: AlarmButton(
|
|
138
|
+
text: "Resume", textColor: .green, systemImageName: "play.fill"
|
|
139
|
+
)
|
|
140
|
+
)
|
|
141
|
+
let presentation = AlarmPresentation(
|
|
142
|
+
alert: alert, countdown: countdown, paused: paused
|
|
143
|
+
)
|
|
144
|
+
let attributes = AlarmAttributes(
|
|
145
|
+
presentation: presentation,
|
|
146
|
+
metadata: CookingTimerMetadata(recipeName: recipeName, stepDescription: step),
|
|
147
|
+
tintColor: .orange
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
let id = UUID()
|
|
151
|
+
let config = AlarmManager.AlarmConfiguration.timer(
|
|
152
|
+
duration: durationSeconds,
|
|
153
|
+
attributes: attributes,
|
|
154
|
+
stopIntent: StopTimerIntent(timerID: id.uuidString),
|
|
155
|
+
sound: .default
|
|
156
|
+
)
|
|
157
|
+
return try await manager.schedule(id: id, configuration: config)
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Authorization Manager
|
|
162
|
+
|
|
163
|
+
Observable pattern for centralized authorization management.
|
|
164
|
+
|
|
165
|
+
```swift
|
|
166
|
+
import AlarmKit
|
|
167
|
+
import Observation
|
|
168
|
+
|
|
169
|
+
@Observable
|
|
170
|
+
@MainActor
|
|
171
|
+
final class AlarmAuthorizationManager {
|
|
172
|
+
private let manager = AlarmManager.shared
|
|
173
|
+
private(set) var isAuthorized = false
|
|
174
|
+
private(set) var authState: AlarmManager.AuthorizationState = .notDetermined
|
|
175
|
+
|
|
176
|
+
init() {
|
|
177
|
+
authState = manager.authorizationState
|
|
178
|
+
isAuthorized = authState == .authorized
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
func requestIfNeeded() async throws -> Bool {
|
|
182
|
+
guard authState == .notDetermined else { return isAuthorized }
|
|
183
|
+
let state = try await manager.requestAuthorization()
|
|
184
|
+
authState = state
|
|
185
|
+
isAuthorized = state == .authorized
|
|
186
|
+
return isAuthorized
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
func observeAuthorizationChanges() async {
|
|
190
|
+
for await state in manager.authorizationUpdates {
|
|
191
|
+
authState = state
|
|
192
|
+
isAuthorized = state == .authorized
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Usage in SwiftUI
|
|
198
|
+
struct AlarmSettingsView: View {
|
|
199
|
+
@State private var authManager = AlarmAuthorizationManager()
|
|
200
|
+
|
|
201
|
+
var body: some View {
|
|
202
|
+
Group {
|
|
203
|
+
if authManager.isAuthorized {
|
|
204
|
+
Text("Alarms are enabled")
|
|
205
|
+
} else if authManager.authState == .denied {
|
|
206
|
+
ContentUnavailableView(
|
|
207
|
+
"Alarms Disabled", systemImage: "alarm.waves.left.and.right",
|
|
208
|
+
description: Text("Enable in Settings > Your App > Alarms & Timers.")
|
|
209
|
+
)
|
|
210
|
+
} else {
|
|
211
|
+
Button("Enable Alarms") {
|
|
212
|
+
Task { try? await authManager.requestIfNeeded() }
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
.task { await authManager.observeAuthorizationChanges() }
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## State Observation with Async Sequences
|
|
222
|
+
|
|
223
|
+
Pattern for tracking all alarms and reacting to state changes.
|
|
224
|
+
|
|
225
|
+
```swift
|
|
226
|
+
import AlarmKit
|
|
227
|
+
import Observation
|
|
228
|
+
|
|
229
|
+
@Observable
|
|
230
|
+
@MainActor
|
|
231
|
+
final class AlarmStore {
|
|
232
|
+
private let manager = AlarmManager.shared
|
|
233
|
+
private(set) var alarms: [Alarm] = []
|
|
234
|
+
|
|
235
|
+
init() { alarms = manager.alarms }
|
|
236
|
+
|
|
237
|
+
func startObserving() async {
|
|
238
|
+
for await updatedAlarms in manager.alarmUpdates {
|
|
239
|
+
alarms = updatedAlarms
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
func alarm(for id: UUID) -> Alarm? { alarms.first { $0.id == id } }
|
|
244
|
+
func alarms(in state: Alarm.State) -> [Alarm] { alarms.filter { $0.state == state } }
|
|
245
|
+
|
|
246
|
+
func cancel(_ id: Alarm.ID) throws { try manager.cancel(id: id) }
|
|
247
|
+
func pause(_ id: Alarm.ID) throws { try manager.pause(id: id) }
|
|
248
|
+
func resume(_ id: Alarm.ID) throws { try manager.resume(id: id) }
|
|
249
|
+
func stop(_ id: Alarm.ID) throws { try manager.stop(id: id) }
|
|
250
|
+
func snooze(_ id: Alarm.ID) throws { try manager.countdown(id: id) }
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Usage in SwiftUI
|
|
254
|
+
struct AlarmListView: View {
|
|
255
|
+
@State private var store = AlarmStore()
|
|
256
|
+
|
|
257
|
+
var body: some View {
|
|
258
|
+
List(store.alarms, id: \.id) { alarm in
|
|
259
|
+
HStack {
|
|
260
|
+
Text(alarm.id.uuidString.prefix(8)).font(.headline)
|
|
261
|
+
Spacer()
|
|
262
|
+
switch alarm.state {
|
|
263
|
+
case .scheduled:
|
|
264
|
+
Button("Cancel", role: .destructive) { try? store.cancel(alarm.id) }
|
|
265
|
+
case .countdown:
|
|
266
|
+
Button("Pause") { try? store.pause(alarm.id) }
|
|
267
|
+
case .paused:
|
|
268
|
+
Button("Resume") { try? store.resume(alarm.id) }
|
|
269
|
+
case .alerting:
|
|
270
|
+
Button("Stop") { try? store.stop(alarm.id) }
|
|
271
|
+
@unknown default:
|
|
272
|
+
EmptyView()
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
.task { await store.startObserving() }
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Live Activity Widget Extension for Alarms
|
|
282
|
+
|
|
283
|
+
Widget extension that renders countdown and paused states. Required when
|
|
284
|
+
your alarm uses countdown presentation.
|
|
285
|
+
|
|
286
|
+
```swift
|
|
287
|
+
import WidgetKit
|
|
288
|
+
import SwiftUI
|
|
289
|
+
import AlarmKit
|
|
290
|
+
|
|
291
|
+
// MARK: - Widget bundle
|
|
292
|
+
|
|
293
|
+
struct AlarmWidgetBundle: WidgetBundle {
|
|
294
|
+
var body: some Widget {
|
|
295
|
+
AlarmLiveActivityWidget()
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// MARK: - Live Activity configuration
|
|
300
|
+
|
|
301
|
+
struct AlarmLiveActivityWidget: Widget {
|
|
302
|
+
var body: some WidgetConfiguration {
|
|
303
|
+
ActivityConfiguration(for: AlarmAttributes<CookingTimerMetadata>.self) { context in
|
|
304
|
+
AlarmLockScreenView(context: context)
|
|
305
|
+
} dynamicIsland: { context in
|
|
306
|
+
DynamicIsland {
|
|
307
|
+
DynamicIslandExpandedRegion(.leading) {
|
|
308
|
+
Image(systemName: "alarm.fill")
|
|
309
|
+
.font(.title2)
|
|
310
|
+
.foregroundStyle(context.attributes.tintColor)
|
|
311
|
+
}
|
|
312
|
+
DynamicIslandExpandedRegion(.trailing) {
|
|
313
|
+
AlarmCountdownText(state: context.state)
|
|
314
|
+
.font(.title3.monospacedDigit())
|
|
315
|
+
}
|
|
316
|
+
DynamicIslandExpandedRegion(.center) {
|
|
317
|
+
Text(context.attributes.metadata?.recipeName ?? "Timer")
|
|
318
|
+
.font(.headline)
|
|
319
|
+
}
|
|
320
|
+
DynamicIslandExpandedRegion(.bottom) {
|
|
321
|
+
if let step = context.attributes.metadata?.stepDescription {
|
|
322
|
+
Text(step).font(.subheadline).foregroundStyle(.secondary)
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
} compactLeading: {
|
|
326
|
+
Image(systemName: "alarm.fill").foregroundStyle(context.attributes.tintColor)
|
|
327
|
+
} compactTrailing: {
|
|
328
|
+
AlarmCountdownText(state: context.state)
|
|
329
|
+
.frame(width: 44).monospacedDigit()
|
|
330
|
+
} minimal: {
|
|
331
|
+
Image(systemName: "alarm.fill").foregroundStyle(context.attributes.tintColor)
|
|
332
|
+
}
|
|
333
|
+
.keylineTint(context.attributes.tintColor)
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// MARK: - Lock Screen view
|
|
339
|
+
|
|
340
|
+
struct AlarmLockScreenView: View {
|
|
341
|
+
let context: ActivityViewContext<AlarmAttributes<CookingTimerMetadata>>
|
|
342
|
+
|
|
343
|
+
var body: some View {
|
|
344
|
+
VStack(alignment: .leading, spacing: 8) {
|
|
345
|
+
HStack {
|
|
346
|
+
Image(systemName: "alarm.fill")
|
|
347
|
+
.foregroundStyle(context.attributes.tintColor)
|
|
348
|
+
Text(context.attributes.metadata?.recipeName ?? "Timer")
|
|
349
|
+
.font(.headline)
|
|
350
|
+
Spacer()
|
|
351
|
+
AlarmCountdownText(state: context.state)
|
|
352
|
+
.font(.title3.monospacedDigit().bold())
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
switch context.state.mode {
|
|
356
|
+
case .countdown(let info):
|
|
357
|
+
ProgressView(
|
|
358
|
+
value: info.previouslyElapsedDuration,
|
|
359
|
+
total: info.totalCountdownDuration
|
|
360
|
+
)
|
|
361
|
+
.tint(context.attributes.tintColor)
|
|
362
|
+
case .paused:
|
|
363
|
+
Label("Paused", systemImage: "pause.fill")
|
|
364
|
+
.font(.subheadline).foregroundStyle(.secondary)
|
|
365
|
+
case .alert:
|
|
366
|
+
EmptyView() // System handles alerting UI
|
|
367
|
+
@unknown default:
|
|
368
|
+
EmptyView()
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
.padding()
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// MARK: - Helper views
|
|
376
|
+
|
|
377
|
+
struct AlarmCountdownText: View {
|
|
378
|
+
let state: AlarmPresentationState
|
|
379
|
+
|
|
380
|
+
var body: some View {
|
|
381
|
+
switch state.mode {
|
|
382
|
+
case .countdown(let info):
|
|
383
|
+
Text(info.fireDate, style: .timer)
|
|
384
|
+
case .paused(let info):
|
|
385
|
+
let remaining = info.totalCountdownDuration - info.previouslyElapsedDuration
|
|
386
|
+
Text(Duration.seconds(remaining), format: .time(pattern: .minuteSecond))
|
|
387
|
+
case .alert(let info):
|
|
388
|
+
Text("\(info.time.hour):\(String(format: "%02d", info.time.minute))")
|
|
389
|
+
@unknown default:
|
|
390
|
+
Text("--:--")
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## Recurring Alarm Patterns
|
|
397
|
+
|
|
398
|
+
```swift
|
|
399
|
+
// Daily alarm (every day)
|
|
400
|
+
let dailySchedule = Alarm.Schedule.relative(.init(
|
|
401
|
+
time: .init(hour: 7, minute: 0),
|
|
402
|
+
repeats: .weekly([.sunday, .monday, .tuesday, .wednesday,
|
|
403
|
+
.thursday, .friday, .saturday])
|
|
404
|
+
))
|
|
405
|
+
|
|
406
|
+
// Weekday-only alarm
|
|
407
|
+
let weekdaySchedule = Alarm.Schedule.relative(.init(
|
|
408
|
+
time: .init(hour: 6, minute: 30),
|
|
409
|
+
repeats: .weekly([.monday, .tuesday, .wednesday, .thursday, .friday])
|
|
410
|
+
))
|
|
411
|
+
|
|
412
|
+
// Weekend alarm
|
|
413
|
+
let weekendSchedule = Alarm.Schedule.relative(.init(
|
|
414
|
+
time: .init(hour: 9, minute: 0),
|
|
415
|
+
repeats: .weekly([.saturday, .sunday])
|
|
416
|
+
))
|
|
417
|
+
|
|
418
|
+
// One-time alarm at a specific Date
|
|
419
|
+
let targetDate = Calendar.current.date(
|
|
420
|
+
from: DateComponents(year: 2026, month: 6, day: 15, hour: 14, minute: 30)
|
|
421
|
+
)!
|
|
422
|
+
let fixedSchedule = Alarm.Schedule.fixed(targetDate)
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
## Snooze and Dismiss Handling
|
|
426
|
+
|
|
427
|
+
Pattern for alarm with snooze (countdown behavior) and custom secondary action.
|
|
428
|
+
|
|
429
|
+
### Snooze with countdown restart
|
|
430
|
+
|
|
431
|
+
```swift
|
|
432
|
+
func scheduleAlarmWithSnooze(
|
|
433
|
+
hour: Int, minute: Int, snoozeDurationSeconds: TimeInterval
|
|
434
|
+
) async throws -> Alarm {
|
|
435
|
+
let id = UUID()
|
|
436
|
+
let alert = AlarmPresentation.Alert(
|
|
437
|
+
title: "Good Morning",
|
|
438
|
+
secondaryButton: AlarmButton(
|
|
439
|
+
text: "Snooze 5 min", textColor: .white, systemImageName: "zzz"
|
|
440
|
+
),
|
|
441
|
+
secondaryButtonBehavior: .countdown // tapping Snooze restarts countdown
|
|
442
|
+
)
|
|
443
|
+
// postAlert defines the snooze duration
|
|
444
|
+
let countdown = Alarm.CountdownDuration(
|
|
445
|
+
preAlert: nil, postAlert: snoozeDurationSeconds
|
|
446
|
+
)
|
|
447
|
+
let countdownPresentation = AlarmPresentation.Countdown(
|
|
448
|
+
title: "Snoozing...", pauseButton: nil
|
|
449
|
+
)
|
|
450
|
+
let presentation = AlarmPresentation(
|
|
451
|
+
alert: alert, countdown: countdownPresentation
|
|
452
|
+
)
|
|
453
|
+
let attributes = AlarmAttributes(
|
|
454
|
+
presentation: presentation,
|
|
455
|
+
metadata: nil as WakeUpMetadata?,
|
|
456
|
+
tintColor: .purple
|
|
457
|
+
)
|
|
458
|
+
let config = AlarmManager.AlarmConfiguration(
|
|
459
|
+
countdownDuration: countdown,
|
|
460
|
+
schedule: .relative(.init(
|
|
461
|
+
time: .init(hour: hour, minute: minute), repeats: .never
|
|
462
|
+
)),
|
|
463
|
+
attributes: attributes,
|
|
464
|
+
stopIntent: StopAlarmIntent(alarmID: id.uuidString),
|
|
465
|
+
secondaryIntent: SnoozeAlarmIntent(alarmID: id.uuidString),
|
|
466
|
+
sound: .default
|
|
467
|
+
)
|
|
468
|
+
return try await AlarmManager.shared.schedule(id: id, configuration: config)
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Custom secondary action (open app)
|
|
473
|
+
|
|
474
|
+
Use `.custom` behavior to trigger the `secondaryIntent` instead of restarting
|
|
475
|
+
a countdown. The intent opens the app or performs custom logic.
|
|
476
|
+
|
|
477
|
+
```swift
|
|
478
|
+
struct OpenAppIntent: LiveActivityIntent {
|
|
479
|
+
static var title: LocalizedStringResource = "Open App"
|
|
480
|
+
func perform() async throws -> some IntentResult { .result() }
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
func scheduleAlarmWithOpenAction(hour: Int, minute: Int) async throws -> Alarm {
|
|
484
|
+
let id = UUID()
|
|
485
|
+
let alert = AlarmPresentation.Alert(
|
|
486
|
+
title: "Medication Reminder",
|
|
487
|
+
secondaryButton: AlarmButton(
|
|
488
|
+
text: "Open", textColor: .blue, systemImageName: "pill.fill"
|
|
489
|
+
),
|
|
490
|
+
secondaryButtonBehavior: .custom // triggers secondaryIntent
|
|
491
|
+
)
|
|
492
|
+
let presentation = AlarmPresentation(alert: alert)
|
|
493
|
+
let attributes = AlarmAttributes<WakeUpMetadata>(
|
|
494
|
+
presentation: presentation, metadata: nil, tintColor: .blue
|
|
495
|
+
)
|
|
496
|
+
let config = AlarmManager.AlarmConfiguration.alarm(
|
|
497
|
+
schedule: .relative(.init(
|
|
498
|
+
time: .init(hour: hour, minute: minute), repeats: .never
|
|
499
|
+
)),
|
|
500
|
+
attributes: attributes,
|
|
501
|
+
stopIntent: StopAlarmIntent(alarmID: id.uuidString),
|
|
502
|
+
secondaryIntent: OpenAppIntent(),
|
|
503
|
+
sound: .default
|
|
504
|
+
)
|
|
505
|
+
return try await AlarmManager.shared.schedule(id: id, configuration: config)
|
|
506
|
+
}
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
## Info.plist Configuration
|
|
510
|
+
|
|
511
|
+
### Required key
|
|
512
|
+
|
|
513
|
+
```xml
|
|
514
|
+
<key>NSAlarmKitUsageDescription</key>
|
|
515
|
+
<string>We schedule alerts for alarms and timers you create.</string>
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
This key is **mandatory**. If missing or empty, `schedule(id:configuration:)`
|
|
519
|
+
will fail and no alarms can be created by the app.
|
|
520
|
+
|
|
521
|
+
### Recommended: NSSupportsLiveActivities
|
|
522
|
+
|
|
523
|
+
Since alarms create Live Activities, also include:
|
|
524
|
+
|
|
525
|
+
```xml
|
|
526
|
+
<key>NSSupportsLiveActivities</key>
|
|
527
|
+
<true/>
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
## Error Handling
|
|
531
|
+
|
|
532
|
+
```swift
|
|
533
|
+
import AlarmKit
|
|
534
|
+
|
|
535
|
+
func scheduleAlarmSafely(
|
|
536
|
+
id: UUID,
|
|
537
|
+
configuration: AlarmManager.AlarmConfiguration<some AlarmMetadata>
|
|
538
|
+
) async {
|
|
539
|
+
guard AlarmManager.shared.authorizationState == .authorized else {
|
|
540
|
+
print("Not authorized -- request authorization first")
|
|
541
|
+
return
|
|
542
|
+
}
|
|
543
|
+
do {
|
|
544
|
+
let alarm = try await AlarmManager.shared.schedule(
|
|
545
|
+
id: id, configuration: configuration
|
|
546
|
+
)
|
|
547
|
+
print("Scheduled alarm: \(alarm.id), state: \(alarm.state)")
|
|
548
|
+
} catch let error as AlarmManager.AlarmError {
|
|
549
|
+
switch error {
|
|
550
|
+
case .maximumLimitReached:
|
|
551
|
+
print("Too many alarms -- cancel an existing one first")
|
|
552
|
+
@unknown default:
|
|
553
|
+
print("AlarmKit error: \(error)")
|
|
554
|
+
}
|
|
555
|
+
} catch {
|
|
556
|
+
print("Unexpected error: \(error)")
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// State transition helpers -- each throws if alarm is in wrong state
|
|
561
|
+
func cancelAlarmSafely(id: Alarm.ID) {
|
|
562
|
+
do { try AlarmManager.shared.cancel(id: id) }
|
|
563
|
+
catch { print("Failed to cancel: \(error)") }
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
func pauseAlarmSafely(id: Alarm.ID) {
|
|
567
|
+
// Only valid when alarm is in .countdown state
|
|
568
|
+
do { try AlarmManager.shared.pause(id: id) }
|
|
569
|
+
catch { print("Cannot pause: \(error)") }
|
|
570
|
+
}
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
## Apple Documentation Links
|
|
574
|
+
|
|
575
|
+
- [AlarmKit](https://sosumi.ai/documentation/alarmkit)
|
|
576
|
+
- [AlarmManager](https://sosumi.ai/documentation/alarmkit/alarmmanager)
|
|
577
|
+
- [AlarmAttributes](https://sosumi.ai/documentation/alarmkit/alarmattributes)
|
|
578
|
+
- [AlarmPresentation](https://sosumi.ai/documentation/alarmkit/alarmpresentation)
|
|
579
|
+
- [AlarmPresentationState](https://sosumi.ai/documentation/alarmkit/alarmpresentationstate)
|
|
580
|
+
- [AlarmButton](https://sosumi.ai/documentation/alarmkit/alarmbutton)
|
|
581
|
+
- [Alarm](https://sosumi.ai/documentation/alarmkit/alarm)
|
|
582
|
+
- [Alarm.Schedule](https://sosumi.ai/documentation/alarmkit/alarm/schedule-swift.enum)
|
|
583
|
+
- [Alarm.CountdownDuration](https://sosumi.ai/documentation/alarmkit/alarm/countdownduration-swift.struct)
|
|
584
|
+
- [Scheduling an alarm with AlarmKit](https://sosumi.ai/documentation/alarmkit/scheduling-an-alarm-with-alarmkit)
|