@devo-bmad-custom/agent-orchestration 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/installer.js +33 -0
- package/package.json +1 -1
- package/src/.agents/skills/audit-website/README.md +20 -20
- package/src/.agents/skills/audit-website/SKILL.md +470 -470
- package/src/.agents/skills/audit-website/agents/openai.yaml +6 -6
- package/src/.agents/skills/audit-website/assets/icon-small.svg +41 -41
- package/src/.agents/skills/audit-website/references/OUTPUT-FORMAT.md +250 -250
- package/src/.agents/skills/clean-code-standards/SKILL.md +104 -104
- package/src/.agents/skills/excalidraw-dark-standard/SKILL.md +281 -281
- package/src/.agents/skills/frontend-responsive-design-standards/SKILL.md +434 -434
- package/src/.agents/skills/java-fundamentals/SKILL.md +116 -116
- package/src/.agents/skills/java-performance/SKILL.md +119 -119
- package/src/.agents/skills/next-best-practices/SKILL.md +153 -153
- package/src/.agents/skills/next-best-practices/async-patterns.md +87 -87
- package/src/.agents/skills/next-best-practices/bundling.md +180 -180
- package/src/.agents/skills/next-best-practices/data-patterns.md +297 -297
- package/src/.agents/skills/next-best-practices/debug-tricks.md +105 -105
- package/src/.agents/skills/next-best-practices/directives.md +73 -73
- package/src/.agents/skills/next-best-practices/error-handling.md +227 -227
- package/src/.agents/skills/next-best-practices/file-conventions.md +140 -140
- package/src/.agents/skills/next-best-practices/font.md +245 -245
- package/src/.agents/skills/next-best-practices/functions.md +108 -108
- package/src/.agents/skills/next-best-practices/hydration-error.md +91 -91
- package/src/.agents/skills/next-best-practices/image.md +173 -173
- package/src/.agents/skills/next-best-practices/metadata.md +301 -301
- package/src/.agents/skills/next-best-practices/parallel-routes.md +287 -287
- package/src/.agents/skills/next-best-practices/route-handlers.md +146 -146
- package/src/.agents/skills/next-best-practices/rsc-boundaries.md +159 -159
- package/src/.agents/skills/next-best-practices/runtime-selection.md +39 -39
- package/src/.agents/skills/next-best-practices/scripts.md +141 -141
- package/src/.agents/skills/next-best-practices/self-hosting.md +371 -371
- package/src/.agents/skills/next-best-practices/suspense-boundaries.md +67 -67
- package/src/.agents/skills/nextjs-app-router-patterns/SKILL.md +537 -537
- package/src/.agents/skills/postgresql-optimization/SKILL.md +404 -404
- package/src/.agents/skills/python-backend/SKILL.md +153 -153
- package/src/.agents/skills/python-fundamentals/SKILL.md +234 -234
- package/src/.agents/skills/python-performance/SKILL.md +404 -404
- package/src/.agents/skills/react-expert/SKILL.md +335 -335
- package/src/.agents/skills/redis-best-practices/SKILL.md +438 -438
- package/src/.agents/skills/security-best-practices/SKILL.md +288 -288
- package/src/.agents/skills/security-review/LICENSE +22 -22
- package/src/.agents/skills/security-review/SKILL.md +312 -312
- package/src/.agents/skills/security-review/infrastructure/docker.md +432 -432
- package/src/.agents/skills/security-review/languages/javascript.md +388 -388
- package/src/.agents/skills/security-review/languages/python.md +363 -363
- package/src/.agents/skills/security-review/references/api-security.md +519 -519
- package/src/.agents/skills/security-review/references/authentication.md +353 -353
- package/src/.agents/skills/security-review/references/authorization.md +372 -372
- package/src/.agents/skills/security-review/references/business-logic.md +443 -443
- package/src/.agents/skills/security-review/references/cryptography.md +329 -329
- package/src/.agents/skills/security-review/references/csrf.md +398 -398
- package/src/.agents/skills/security-review/references/data-protection.md +378 -378
- package/src/.agents/skills/security-review/references/deserialization.md +410 -410
- package/src/.agents/skills/security-review/references/error-handling.md +436 -436
- package/src/.agents/skills/security-review/references/file-security.md +457 -457
- package/src/.agents/skills/security-review/references/injection.md +259 -259
- package/src/.agents/skills/security-review/references/logging.md +433 -433
- package/src/.agents/skills/security-review/references/misconfiguration.md +435 -435
- package/src/.agents/skills/security-review/references/modern-threats.md +475 -475
- package/src/.agents/skills/security-review/references/ssrf.md +415 -415
- package/src/.agents/skills/security-review/references/supply-chain.md +405 -405
- package/src/.agents/skills/security-review/references/xss.md +336 -336
- package/src/.agents/skills/subagent-driven-development/SKILL.md +275 -275
- package/src/.agents/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -26
- package/src/.agents/skills/subagent-driven-development/implementer-prompt.md +113 -113
- package/src/.agents/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -61
- package/src/.agents/skills/systematic-debugging/CREATION-LOG.md +119 -119
- package/src/.agents/skills/systematic-debugging/SKILL.md +296 -296
- package/src/.agents/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
- package/src/.agents/skills/systematic-debugging/condition-based-waiting.md +115 -115
- package/src/.agents/skills/systematic-debugging/defense-in-depth.md +122 -122
- package/src/.agents/skills/systematic-debugging/root-cause-tracing.md +169 -169
- package/src/.agents/skills/systematic-debugging/test-academic.md +14 -14
- package/src/.agents/skills/systematic-debugging/test-pressure-1.md +58 -58
- package/src/.agents/skills/systematic-debugging/test-pressure-2.md +68 -68
- package/src/.agents/skills/systematic-debugging/test-pressure-3.md +69 -69
- package/src/.agents/skills/typescript-best-practices/SKILL.md +373 -373
- package/src/.agents/skills/ui-ux-pro-custom/SKILL.md +348 -348
- package/src/.agents/skills/ui-ux-pro-custom/data/charts.csv +26 -26
- package/src/.agents/skills/ui-ux-pro-custom/data/colors.csv +97 -97
- package/src/.agents/skills/ui-ux-pro-custom/data/icons.csv +101 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/SKILL.md +106 -106
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/accessibility.md +475 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/animation.md +466 -466
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/composition-locals.md +231 -231
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/deprecated-patterns.md +323 -323
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/lists-scrolling.md +400 -400
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/modifiers.md +331 -331
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/navigation.md +416 -416
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/performance.md +446 -446
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/side-effects.md +516 -516
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/foundation-source.md +13327 -13327
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/material3-source.md +19097 -19097
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/navigation-source.md +2947 -2947
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/runtime-source.md +11316 -11316
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/ui-source.md +7896 -7896
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/state-management.md +377 -377
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/styles-experimental.md +470 -470
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/theming-material3.md +349 -349
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/view-composition.md +595 -595
- package/src/.agents/skills/ui-ux-pro-custom/data/landing.csv +31 -31
- package/src/.agents/skills/ui-ux-pro-custom/data/mobile-ui-layout.md +654 -654
- package/src/.agents/skills/ui-ux-pro-custom/data/products.csv +96 -96
- package/src/.agents/skills/ui-ux-pro-custom/data/react-performance.csv +45 -45
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/astro.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/flutter.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/html-tailwind.csv +56 -56
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/jetpack-compose.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nextjs.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nuxt-ui.csv +51 -51
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nuxtjs.csv +59 -59
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/react-native.csv +56 -56
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/react.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/shadcn.csv +61 -61
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/svelte.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/swiftui.csv +51 -51
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/vue.csv +50 -50
- package/src/.agents/skills/ui-ux-pro-custom/data/styles.csv +68 -68
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/alarmkit/SKILL.md +438 -438
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/alarmkit/references/alarmkit-patterns.md +584 -584
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-clips/SKILL.md +436 -436
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-intents/SKILL.md +489 -489
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-intents/references/appintents-advanced.md +1076 -1076
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/SKILL.md +340 -340
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/references/privacy-manifest.md +90 -90
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/references/review-checklists.md +106 -106
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/coreml-conversion.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/coreml-optimization.md +344 -344
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/foundation-models.md +508 -508
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/mlx-swift.md +285 -285
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/authentication/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/authentication/references/keychain-biometric.md +211 -211
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/background-processing/SKILL.md +499 -499
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/background-processing/references/background-task-patterns.md +390 -390
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/callkit-voip/SKILL.md +461 -461
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/callkit-voip/references/callkit-patterns.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/cloudkit-sync/SKILL.md +492 -492
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/cloudkit-sync/references/cloudkit-patterns.md +461 -461
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/codable-patterns/SKILL.md +467 -467
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/contacts-framework/SKILL.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/contacts-framework/references/contacts-patterns.md +409 -409
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-bluetooth/SKILL.md +491 -491
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-bluetooth/references/ble-patterns.md +435 -435
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-motion/SKILL.md +388 -388
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-motion/references/motion-patterns.md +405 -405
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-nfc/SKILL.md +495 -495
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-nfc/references/nfc-patterns.md +420 -420
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/coreml/SKILL.md +459 -459
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/coreml/references/coreml-swift-integration.md +765 -765
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/SKILL.md +422 -422
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/references/instruments-guide.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/references/lldb-patterns.md +298 -298
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/device-integrity/SKILL.md +477 -477
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/energykit/SKILL.md +460 -460
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/energykit/references/energykit-patterns.md +541 -541
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/eventkit-calendar/SKILL.md +483 -483
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/eventkit-calendar/references/eventkit-patterns.md +326 -326
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/healthkit/SKILL.md +498 -498
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/healthkit/references/healthkit-patterns.md +602 -602
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/homekit-matter/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/homekit-matter/references/matter-commissioning.md +455 -455
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-accessibility/SKILL.md +301 -301
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-accessibility/references/a11y-patterns.md +140 -140
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/SKILL.md +418 -418
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/references/formatstyle-locale.md +627 -627
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/references/string-catalogs.md +462 -462
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/SKILL.md +441 -441
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/background-websocket.md +862 -862
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/lightweight-clients.md +93 -93
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/network-framework.md +563 -563
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/urlsession-patterns.md +1116 -1116
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/app-review-guidelines.md +174 -174
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/cryptokit-advanced.md +296 -296
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/file-storage-patterns.md +354 -354
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/privacy-manifest.md +117 -117
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/live-activities/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/live-activities/references/live-activity-patterns.md +868 -868
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/SKILL.md +485 -485
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/references/corelocation-patterns.md +730 -730
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/references/mapkit-patterns.md +748 -748
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/metrickit-diagnostics/SKILL.md +479 -479
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/musickit-audio/SKILL.md +395 -395
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/musickit-audio/references/musickit-patterns.md +363 -363
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/natural-language/SKILL.md +412 -412
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/natural-language/references/translation-patterns.md +311 -311
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/passkit-wallet/SKILL.md +398 -398
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/passkit-wallet/references/wallet-passes.md +254 -254
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/SKILL.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/references/paperkit-integration.md +376 -376
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/references/pencilkit-patterns.md +302 -302
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/permissionkit/SKILL.md +446 -446
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/permissionkit/references/permissionkit-patterns.md +435 -435
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/av-playback.md +701 -701
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/camera-capture.md +774 -774
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/image-loading-caching.md +869 -869
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/photospicker-patterns.md +597 -597
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/references/notification-patterns.md +677 -677
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/references/rich-notifications.md +745 -745
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/realitykit-ar/SKILL.md +479 -479
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/realitykit-ar/references/realitykit-patterns.md +480 -480
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/shareplay-activities/SKILL.md +483 -483
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/shareplay-activities/references/shareplay-patterns.md +544 -544
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/speech-recognition/SKILL.md +485 -485
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/SKILL.md +478 -478
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/references/app-review-guidelines.md +58 -58
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/references/storekit-advanced.md +755 -755
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-charts/SKILL.md +487 -487
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-charts/references/charts-patterns.md +895 -895
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/SKILL.md +408 -408
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/approachable-concurrency.md +80 -80
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/swift-6-2-concurrency.md +233 -233
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/swiftui-concurrency.md +187 -187
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/synchronization-primitives.md +341 -341
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-language/SKILL.md +498 -498
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-language/references/swift-patterns-extended.md +505 -505
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-testing/SKILL.md +467 -467
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-testing/references/testing-patterns.md +504 -504
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/SKILL.md +334 -334
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/core-data-coexistence.md +504 -504
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/swiftdata-advanced.md +975 -975
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/swiftdata-queries.md +675 -675
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/SKILL.md +481 -481
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/references/animation-advanced.md +804 -804
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/references/core-animation-bridge.md +553 -553
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-gestures/SKILL.md +450 -450
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-gestures/references/gesture-patterns.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/SKILL.md +336 -336
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/form.md +97 -97
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/grids.md +69 -69
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/list.md +99 -99
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/scrollview.md +147 -147
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-liquid-glass/SKILL.md +325 -325
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-liquid-glass/references/liquid-glass.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/SKILL.md +262 -262
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/deeplinks.md +207 -207
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/navigationstack.md +177 -177
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/sheets.md +169 -169
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/tabview.md +178 -178
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/SKILL.md +381 -381
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/architecture-patterns.md +486 -486
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/deprecated-migration.md +1097 -1097
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/design-polish.md +780 -780
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/platform-and-sharing.md +696 -696
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/SKILL.md +491 -491
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +46 -46
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +29 -29
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/understanding-hangs-in-your-app.md +33 -33
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/understanding-improving-swiftui-performance.md +52 -52
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/SKILL.md +428 -428
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/references/hosting-migration.md +534 -534
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/references/representable-recipes.md +1133 -1133
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/tipkit/SKILL.md +494 -494
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/tipkit/references/tipkit-patterns.md +782 -782
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/SKILL.md +475 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/vision-requests.md +736 -736
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/visionkit-scanner.md +738 -738
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/SKILL.md +410 -410
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/references/weatherkit-patterns.md +567 -567
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/SKILL.md +497 -497
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/references/widgetkit-advanced.md +871 -871
- package/src/.agents/skills/ui-ux-pro-custom/data/typography.csv +57 -57
- package/src/.agents/skills/ui-ux-pro-custom/data/ui-reasoning.csv +101 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/ux-guidelines.csv +99 -99
- package/src/.agents/skills/ui-ux-pro-custom/data/web-interface.csv +31 -31
- package/src/.agents/skills/ui-ux-pro-custom/scripts/core.py +253 -253
- package/src/.agents/skills/ui-ux-pro-custom/scripts/design_system.py +1067 -1067
- package/src/.agents/skills/ui-ux-pro-custom/scripts/search.py +114 -114
- package/src/.agents/skills/ux-audit/SKILL.md +150 -150
- package/src/.agents/skills/websocket-engineer/SKILL.md +168 -168
- package/src/.agents/skills/websocket-engineer/references/alternatives.md +391 -391
- package/src/.agents/skills/websocket-engineer/references/patterns.md +400 -400
- package/src/.agents/skills/websocket-engineer/references/protocol.md +195 -195
- package/src/.agents/skills/websocket-engineer/references/scaling.md +333 -333
- package/src/.agents/skills/websocket-engineer/references/security.md +474 -474
- package/src/.agents/skills/writing-skills/SKILL.md +655 -655
- package/src/.agents/skills/writing-skills/anthropic-best-practices.md +1150 -1150
- package/src/.agents/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -189
- package/src/.agents/skills/writing-skills/graphviz-conventions.dot +171 -171
- package/src/.agents/skills/writing-skills/persuasion-principles.md +187 -187
- package/src/.agents/skills/writing-skills/render-graphs.js +168 -168
- package/src/.agents/skills/writing-skills/testing-skills-with-subagents.md +384 -384
- package/src/.claude/commands/master-orchestrator.md +15 -0
- package/src/_memory/config.yaml +11 -11
- package/src/_memory/master-orchestrator-sidecar/instructions.md +97 -47
- package/src/_memory/skills/nimbalyst-tracking/SKILL.md +103 -103
- package/src/_memory/skills/writing-skills/SKILL.md +655 -655
- package/src/bmb/agents/agent-builder.md +59 -59
- package/src/bmb/agents/module-builder.md +60 -60
- package/src/bmb/agents/workflow-builder.md +61 -61
- package/src/bmb/config.yaml +12 -12
- package/src/bmb/module-help.csv +13 -13
- package/src/bmb/workflows/agent/data/agent-architecture.md +258 -258
- package/src/bmb/workflows/agent/data/agent-compilation.md +185 -185
- package/src/bmb/workflows/agent/data/agent-menu-patterns.md +189 -189
- package/src/bmb/workflows/agent/data/agent-metadata.md +133 -133
- package/src/bmb/workflows/agent/data/agent-validation.md +111 -111
- package/src/bmb/workflows/agent/data/brainstorm-context.md +96 -96
- package/src/bmb/workflows/agent/data/communication-presets.csv +61 -61
- package/src/bmb/workflows/agent/data/critical-actions.md +75 -75
- package/src/bmb/workflows/agent/data/persona-properties.md +252 -252
- package/src/bmb/workflows/agent/data/principles-crafting.md +142 -142
- package/src/bmb/workflows/agent/data/reference/module-examples/architect.md +68 -68
- package/src/bmb/workflows/agent/data/reference/with-sidecar/journal-keeper/journal-keeper-sidecar/entries/yy-mm-dd-entry-template.md +16 -16
- package/src/bmb/workflows/agent/data/understanding-agent-types.md +126 -126
- package/src/bmb/workflows/agent/steps-c/step-01-brainstorm.md +129 -129
- package/src/bmb/workflows/agent/steps-c/step-02-discovery.md +170 -170
- package/src/bmb/workflows/agent/steps-c/step-03-sidecar-metadata.md +309 -309
- package/src/bmb/workflows/agent/steps-c/step-04-persona.md +213 -213
- package/src/bmb/workflows/agent/steps-c/step-05-commands-menu.md +179 -179
- package/src/bmb/workflows/agent/steps-c/step-06-activation.md +278 -278
- package/src/bmb/workflows/agent/steps-c/step-07-build-agent.md +316 -316
- package/src/bmb/workflows/agent/steps-c/step-08-celebrate.md +247 -247
- package/src/bmb/workflows/agent/steps-e/e-01-load-existing.md +221 -221
- package/src/bmb/workflows/agent/steps-e/e-02-discover-edits.md +195 -195
- package/src/bmb/workflows/agent/steps-e/e-04-sidecar-metadata.md +126 -126
- package/src/bmb/workflows/agent/steps-e/e-05-persona.md +135 -135
- package/src/bmb/workflows/agent/steps-e/e-06-commands-menu.md +123 -123
- package/src/bmb/workflows/agent/steps-e/e-07-activation.md +124 -124
- package/src/bmb/workflows/agent/steps-e/e-08-edit-agent.md +197 -197
- package/src/bmb/workflows/agent/steps-e/e-09-celebrate.md +155 -155
- package/src/bmb/workflows/agent/steps-v/v-01-load-review.md +137 -137
- package/src/bmb/workflows/agent/steps-v/v-02a-validate-metadata.md +116 -116
- package/src/bmb/workflows/agent/steps-v/v-02b-validate-persona.md +124 -124
- package/src/bmb/workflows/agent/steps-v/v-02c-validate-menu.md +127 -127
- package/src/bmb/workflows/agent/steps-v/v-02d-validate-structure.md +134 -134
- package/src/bmb/workflows/agent/steps-v/v-02e-validate-sidecar.md +134 -134
- package/src/bmb/workflows/agent/steps-v/v-03-summary.md +104 -104
- package/src/bmb/workflows/agent/templates/agent-plan.template.md +5 -5
- package/src/bmb/workflows/agent/templates/agent-template.md +89 -89
- package/src/bmb/workflows/agent/workflow-create-agent.md +72 -72
- package/src/bmb/workflows/agent/workflow-edit-agent.md +75 -75
- package/src/bmb/workflows/agent/workflow-validate-agent.md +73 -73
- package/src/bmb/workflows/module/data/agent-architecture.md +179 -179
- package/src/bmb/workflows/module/data/agent-spec-template.md +79 -79
- package/src/bmb/workflows/module/data/module-standards.md +263 -263
- package/src/bmb/workflows/module/data/module-yaml-conventions.md +392 -392
- package/src/bmb/workflows/module/module-help-generate.md +254 -254
- package/src/bmb/workflows/module/steps-b/step-01-welcome.md +148 -148
- package/src/bmb/workflows/module/steps-b/step-02-spark.md +141 -141
- package/src/bmb/workflows/module/steps-b/step-03-module-type.md +149 -149
- package/src/bmb/workflows/module/steps-b/step-04-vision.md +83 -83
- package/src/bmb/workflows/module/steps-b/step-05-identity.md +97 -97
- package/src/bmb/workflows/module/steps-b/step-06-users.md +86 -86
- package/src/bmb/workflows/module/steps-b/step-07-value.md +76 -76
- package/src/bmb/workflows/module/steps-b/step-08-agents.md +97 -97
- package/src/bmb/workflows/module/steps-b/step-09-workflows.md +83 -83
- package/src/bmb/workflows/module/steps-b/step-10-tools.md +91 -91
- package/src/bmb/workflows/module/steps-b/step-11-scenarios.md +84 -84
- package/src/bmb/workflows/module/steps-b/step-12-creative.md +95 -95
- package/src/bmb/workflows/module/steps-b/step-13-review.md +105 -105
- package/src/bmb/workflows/module/steps-b/step-14-finalize.md +117 -117
- package/src/bmb/workflows/module/steps-c/step-01-load-brief.md +179 -179
- package/src/bmb/workflows/module/steps-c/step-01b-continue.md +82 -82
- package/src/bmb/workflows/module/steps-c/step-02-structure.md +105 -105
- package/src/bmb/workflows/module/steps-c/step-03-config.md +119 -119
- package/src/bmb/workflows/module/steps-c/step-04-agents.md +168 -168
- package/src/bmb/workflows/module/steps-c/step-05-workflows.md +184 -184
- package/src/bmb/workflows/module/steps-c/step-06-docs.md +401 -401
- package/src/bmb/workflows/module/steps-c/step-07-complete.md +152 -152
- package/src/bmb/workflows/module/steps-e/step-01-load-target.md +81 -81
- package/src/bmb/workflows/module/steps-e/step-02-select-edit.md +77 -77
- package/src/bmb/workflows/module/steps-e/step-03-apply-edit.md +77 -77
- package/src/bmb/workflows/module/steps-e/step-04-review.md +80 -80
- package/src/bmb/workflows/module/steps-e/step-05-confirm.md +75 -75
- package/src/bmb/workflows/module/steps-v/step-01-load-target.md +96 -96
- package/src/bmb/workflows/module/steps-v/step-02-file-structure.md +93 -93
- package/src/bmb/workflows/module/steps-v/step-03-module-yaml.md +99 -99
- package/src/bmb/workflows/module/steps-v/step-04-agent-specs.md +152 -152
- package/src/bmb/workflows/module/steps-v/step-05-workflow-specs.md +152 -152
- package/src/bmb/workflows/module/steps-v/step-06-documentation.md +143 -143
- package/src/bmb/workflows/module/steps-v/step-07-installation.md +102 -102
- package/src/bmb/workflows/module/steps-v/step-08-report.md +197 -197
- package/src/bmb/workflows/module/templates/brief-template.md +154 -154
- package/src/bmb/workflows/module/templates/workflow-spec-template.md +96 -96
- package/src/bmb/workflows/module/workflow-create-module-brief.md +71 -71
- package/src/bmb/workflows/module/workflow-create-module.md +86 -86
- package/src/bmb/workflows/module/workflow-edit-module.md +66 -66
- package/src/bmb/workflows/module/workflow-validate-module.md +66 -66
- package/src/bmb/workflows/workflow/data/architecture.md +150 -150
- package/src/bmb/workflows/workflow/data/common-workflow-tools.csv +19 -19
- package/src/bmb/workflows/workflow/data/csv-data-file-standards.md +53 -53
- package/src/bmb/workflows/workflow/data/frontmatter-standards.md +184 -184
- package/src/bmb/workflows/workflow/data/input-discovery-standards.md +191 -191
- package/src/bmb/workflows/workflow/data/intent-vs-prescriptive-spectrum.md +44 -44
- package/src/bmb/workflows/workflow/data/menu-handling-standards.md +133 -133
- package/src/bmb/workflows/workflow/data/output-format-standards.md +135 -135
- package/src/bmb/workflows/workflow/data/step-file-rules.md +235 -235
- package/src/bmb/workflows/workflow/data/step-type-patterns.md +257 -257
- package/src/bmb/workflows/workflow/data/subprocess-optimization-patterns.md +188 -188
- package/src/bmb/workflows/workflow/data/trimodal-workflow-structure.md +164 -164
- package/src/bmb/workflows/workflow/data/workflow-chaining-standards.md +222 -222
- package/src/bmb/workflows/workflow/data/workflow-examples.md +232 -232
- package/src/bmb/workflows/workflow/data/workflow-type-criteria.md +134 -134
- package/src/bmb/workflows/workflow/steps-c/step-00-conversion.md +263 -263
- package/src/bmb/workflows/workflow/steps-c/step-01-discovery.md +194 -194
- package/src/bmb/workflows/workflow/steps-c/step-01b-continuation.md +3 -3
- package/src/bmb/workflows/workflow/steps-c/step-02-classification.md +270 -270
- package/src/bmb/workflows/workflow/steps-c/step-03-requirements.md +283 -283
- package/src/bmb/workflows/workflow/steps-c/step-04-tools.md +282 -282
- package/src/bmb/workflows/workflow/steps-c/step-05-plan-review.md +243 -243
- package/src/bmb/workflows/workflow/steps-c/step-06-design.md +330 -330
- package/src/bmb/workflows/workflow/steps-c/step-07-foundation.md +239 -239
- package/src/bmb/workflows/workflow/steps-c/step-08-build-step-01.md +379 -379
- package/src/bmb/workflows/workflow/steps-c/step-09-build-next-step.md +350 -350
- package/src/bmb/workflows/workflow/steps-c/step-10-confirmation.md +322 -322
- package/src/bmb/workflows/workflow/steps-c/step-11-completion.md +191 -191
- package/src/bmb/workflows/workflow/steps-e/step-e-01-assess-workflow.md +237 -237
- package/src/bmb/workflows/workflow/steps-e/step-e-02-discover-edits.md +251 -251
- package/src/bmb/workflows/workflow/steps-e/step-e-03-fix-validation.md +254 -254
- package/src/bmb/workflows/workflow/steps-e/step-e-04-direct-edit.md +277 -277
- package/src/bmb/workflows/workflow/steps-e/step-e-05-apply-edit.md +154 -154
- package/src/bmb/workflows/workflow/steps-e/step-e-06-validate-after.md +190 -190
- package/src/bmb/workflows/workflow/steps-e/step-e-07-complete.md +206 -206
- package/src/bmb/workflows/workflow/steps-v/step-01-validate-max-mode.md +109 -109
- package/src/bmb/workflows/workflow/steps-v/step-01-validate.md +221 -221
- package/src/bmb/workflows/workflow/steps-v/step-01b-structure.md +152 -152
- package/src/bmb/workflows/workflow/steps-v/step-02-frontmatter-validation.md +199 -199
- package/src/bmb/workflows/workflow/steps-v/step-02b-path-violations.md +265 -265
- package/src/bmb/workflows/workflow/steps-v/step-03-menu-validation.md +164 -164
- package/src/bmb/workflows/workflow/steps-v/step-04-step-type-validation.md +211 -211
- package/src/bmb/workflows/workflow/steps-v/step-05-output-format-validation.md +200 -200
- package/src/bmb/workflows/workflow/steps-v/step-06-validation-design-check.md +195 -195
- package/src/bmb/workflows/workflow/steps-v/step-07-instruction-style-check.md +209 -209
- package/src/bmb/workflows/workflow/steps-v/step-08-collaborative-experience-check.md +199 -199
- package/src/bmb/workflows/workflow/steps-v/step-08b-subprocess-optimization.md +179 -179
- package/src/bmb/workflows/workflow/steps-v/step-09-cohesive-review.md +186 -186
- package/src/bmb/workflows/workflow/steps-v/step-10-report-complete.md +154 -154
- package/src/bmb/workflows/workflow/steps-v/step-11-plan-validation.md +237 -237
- package/src/bmb/workflows/workflow/templates/minimal-output-template.md +11 -11
- package/src/bmb/workflows/workflow/templates/step-01-init-continuable-template.md +241 -241
- package/src/bmb/workflows/workflow/templates/step-1b-template.md +224 -224
- package/src/bmb/workflows/workflow/templates/step-template.md +294 -294
- package/src/bmb/workflows/workflow/templates/workflow-template.md +102 -102
- package/src/bmb/workflows/workflow/workflow-create-workflow.md +79 -79
- package/src/bmb/workflows/workflow/workflow-edit-workflow.md +65 -65
- package/src/bmb/workflows/workflow/workflow-rework-workflow.md +65 -65
- package/src/bmb/workflows/workflow/workflow-validate-max-parallel-workflow.md +66 -66
- package/src/bmb/workflows/workflow/workflow-validate-workflow.md +65 -65
- package/src/bmm/agents/analyst.md +104 -104
- package/src/bmm/agents/dev.md +100 -100
- package/src/bmm/agents/qa.md +100 -90
- package/src/bmm/agents/tech-writer/tech-writer.md +94 -94
- package/src/bmm/module-help.csv +31 -31
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01-init.md +115 -115
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01b-continue.md +107 -107
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +141 -141
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +144 -144
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +147 -147
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +161 -161
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +99 -99
- package/src/bmm/workflows/1-analysis/create-product-brief/workflow.md +57 -57
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-01-init.md +87 -87
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-02-domain-analysis.md +156 -156
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-03-competitive-landscape.md +165 -165
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-04-regulatory-focus.md +140 -140
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-05-technical-trends.md +152 -152
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-06-research-synthesis.md +345 -345
- package/src/bmm/workflows/1-analysis/research/market-steps/step-01-init.md +92 -92
- package/src/bmm/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +164 -164
- package/src/bmm/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +174 -174
- package/src/bmm/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +184 -184
- package/src/bmm/workflows/1-analysis/research/market-steps/step-05-competitive-analysis.md +105 -105
- package/src/bmm/workflows/1-analysis/research/market-steps/step-06-research-completion.md +360 -360
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-01-init.md +87 -87
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-02-technical-overview.md +165 -165
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-03-integration-patterns.md +174 -174
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-04-architectural-patterns.md +141 -141
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-05-implementation-research.md +159 -159
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-06-research-synthesis.md +387 -387
- package/src/bmm/workflows/1-analysis/research/workflow-domain-research.md +54 -54
- package/src/bmm/workflows/1-analysis/research/workflow-market-research.md +54 -54
- package/src/bmm/workflows/1-analysis/research/workflow-technical-research.md +54 -54
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-01b-continue.md +100 -100
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02-discovery.md +160 -160
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02b-vision.md +88 -88
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02c-executive-summary.md +99 -99
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md +169 -169
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +156 -156
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +136 -136
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +176 -176
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-07-project-type.md +184 -184
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-08-scoping.md +174 -174
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md +175 -175
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-10-nonfunctional.md +189 -189
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-11-polish.md +162 -162
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-12-complete.md +79 -79
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +183 -183
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md +149 -149
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md +187 -187
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md +192 -192
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-04-complete.md +108 -108
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +166 -166
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md +131 -131
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md +150 -150
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md +118 -118
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md +155 -155
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md +170 -170
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md +158 -158
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md +147 -147
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md +182 -182
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md +202 -202
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +148 -148
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +201 -201
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md +179 -179
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +164 -164
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-create-prd.md +65 -65
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-edit-prd.md +65 -65
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +63 -63
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01b-continue.md +63 -63
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +106 -106
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +111 -111
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +115 -115
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +127 -127
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +167 -167
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +143 -143
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +118 -118
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +154 -154
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +136 -136
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +165 -165
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +135 -135
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +192 -192
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +101 -101
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +45 -45
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-01-document-discovery.md +185 -185
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-02-prd-analysis.md +129 -129
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-03-epic-coverage-validation.md +130 -130
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-04-ux-alignment.md +93 -93
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-05-epic-quality-review.md +196 -196
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +129 -129
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/workflow.md +54 -54
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-01b-continue.md +82 -82
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +106 -106
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +138 -138
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +129 -129
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +166 -166
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +186 -186
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +163 -163
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +38 -38
- package/src/bmm/workflows/3-solutioning/create-architecture/workflow.md +49 -49
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +124 -124
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +122 -122
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +84 -84
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +58 -58
- package/src/bmm/workflows/4-implementation/code-review/workflow.yaml +43 -43
- package/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +53 -53
- package/src/bmm/workflows/4-implementation/create-story/checklist.md +159 -159
- package/src/bmm/workflows/4-implementation/create-story/template.md +79 -79
- package/src/bmm/workflows/4-implementation/create-story/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +20 -20
- package/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +25 -25
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-01-mode-detection.md +158 -158
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-02-context-gathering.md +122 -122
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-03-execute.md +93 -93
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-04-self-check.md +93 -93
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-05-adversarial-review.md +87 -87
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-06-resolve-findings.md +146 -146
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +50 -50
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-02-investigate.md +152 -152
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-03-generate.md +123 -123
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +201 -201
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +79 -79
- package/src/bmm/workflows/document-project/workflow.yaml +22 -22
- package/src/bmm/workflows/generate-project-context/steps/step-01-discover.md +184 -184
- package/src/bmm/workflows/generate-project-context/steps/step-02-generate.md +322 -322
- package/src/bmm/workflows/generate-project-context/steps/step-03-complete.md +235 -235
- package/src/bmm/workflows/generate-project-context/workflow.md +49 -49
- package/src/bmm/workflows/qa/automate/workflow.yaml +233 -233
- package/src/bmm/workflows/qa-generate-e2e-tests/workflow.yaml +42 -42
- package/src/core/config.yaml +9 -9
- package/src/core/module-help.csv +10 -10
- package/src/core/scripts/generate-loop-report.py +72 -72
- package/src/core/tasks/editorial-review-prose.xml +101 -101
- package/src/core/tasks/editorial-review-structure.xml +207 -207
- package/src/core/tasks/help.md +86 -86
- package/src/core/tasks/index-docs.xml +64 -64
- package/src/core/tasks/review-adversarial-general.xml +66 -66
- package/src/core/tasks/review-adversarial-loop.xml +46 -46
- package/src/core/tasks/review-edge-case-hunter.xml +63 -63
- package/src/core/tasks/review-party-loop.xml +46 -46
- package/src/core/tasks/shard-doc.xml +107 -107
- package/src/core/tasks/workflow.xml +235 -235
- package/src/core/templates/review-loop-report.html +88 -88
- package/src/core/templates/review-loop-report.md +5 -5
- package/src/core/workflows/advanced-elicitation/workflow.xml +117 -117
- package/src/core/workflows/brainstorming/steps/step-01-session-setup.md +212 -212
- package/src/core/workflows/brainstorming/steps/step-01b-continue.md +122 -122
- package/src/core/workflows/brainstorming/steps/step-02a-user-selected.md +225 -225
- package/src/core/workflows/brainstorming/steps/step-02b-ai-recommended.md +237 -237
- package/src/core/workflows/brainstorming/steps/step-02c-random-selection.md +209 -209
- package/src/core/workflows/brainstorming/steps/step-02d-progressive-flow.md +264 -264
- package/src/core/workflows/brainstorming/steps/step-02e-deep-dive.md +68 -68
- package/src/core/workflows/brainstorming/steps/step-03-technique-execution.md +403 -403
- package/src/core/workflows/brainstorming/steps/step-04-idea-organization.md +303 -303
- package/src/core/workflows/brainstorming/workflow.md +60 -60
- package/src/core/workflows/extract-trackers/workflow.md +45 -45
- package/src/core/workflows/party-mode/steps/step-01-agent-loading.md +142 -142
- package/src/core/workflows/party-mode/workflow.md +194 -194
- package/src/docs/dev/tmux/actions_popup.py +291 -291
- package/src/docs/dev/tmux/tmux-setup.md +62 -1
|
@@ -1,491 +1,491 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: core-bluetooth
|
|
3
|
-
description: "Scan, connect, and communicate with Bluetooth Low Energy peripherals and publish local peripheral services using Core Bluetooth. Use when implementing BLE central or peripheral roles, discovering services and characteristics, reading and writing characteristic values, subscribing to notifications, configuring background BLE modes, restoring state after app relaunch, or working with CBCentralManager, CBPeripheral, CBPeripheralManager, CBService, CBCharacteristic, CBUUID, or Bluetooth Low Energy workflows."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Core Bluetooth
|
|
7
|
-
|
|
8
|
-
Scan for, connect to, and exchange data with Bluetooth Low Energy (BLE) devices.
|
|
9
|
-
Covers the central role (scanning and connecting to peripherals), the peripheral
|
|
10
|
-
role (advertising services), background modes, and state restoration.
|
|
11
|
-
Targets Swift 6.2 / iOS 26+.
|
|
12
|
-
|
|
13
|
-
## Contents
|
|
14
|
-
|
|
15
|
-
- [Setup](#setup)
|
|
16
|
-
- [Central Role: Scanning](#central-role-scanning)
|
|
17
|
-
- [Central Role: Connecting](#central-role-connecting)
|
|
18
|
-
- [Discovering Services and Characteristics](#discovering-services-and-characteristics)
|
|
19
|
-
- [Reading, Writing, and Notifications](#reading-writing-and-notifications)
|
|
20
|
-
- [Peripheral Role: Advertising](#peripheral-role-advertising)
|
|
21
|
-
- [Background BLE](#background-ble)
|
|
22
|
-
- [State Restoration](#state-restoration)
|
|
23
|
-
- [Common Mistakes](#common-mistakes)
|
|
24
|
-
- [Review Checklist](#review-checklist)
|
|
25
|
-
- [References](#references)
|
|
26
|
-
|
|
27
|
-
## Setup
|
|
28
|
-
|
|
29
|
-
### Info.plist Keys
|
|
30
|
-
|
|
31
|
-
| Key | Purpose |
|
|
32
|
-
|---|---|
|
|
33
|
-
| `NSBluetoothAlwaysUsageDescription` | Required. Explains why the app uses Bluetooth |
|
|
34
|
-
| `UIBackgroundModes` with `bluetooth-central` | Background scanning and connecting |
|
|
35
|
-
| `UIBackgroundModes` with `bluetooth-peripheral` | Background advertising |
|
|
36
|
-
|
|
37
|
-
### Bluetooth Authorization
|
|
38
|
-
|
|
39
|
-
iOS prompts for Bluetooth permission automatically when you create a
|
|
40
|
-
`CBCentralManager` or `CBPeripheralManager`. The usage description from
|
|
41
|
-
`NSBluetoothAlwaysUsageDescription` is shown in the permission dialog.
|
|
42
|
-
|
|
43
|
-
## Central Role: Scanning
|
|
44
|
-
|
|
45
|
-
### Creating the Central Manager
|
|
46
|
-
|
|
47
|
-
Always wait for the `poweredOn` state before scanning.
|
|
48
|
-
|
|
49
|
-
```swift
|
|
50
|
-
import CoreBluetooth
|
|
51
|
-
|
|
52
|
-
final class BluetoothManager: NSObject, CBCentralManagerDelegate {
|
|
53
|
-
private var centralManager: CBCentralManager!
|
|
54
|
-
private var discoveredPeripheral: CBPeripheral?
|
|
55
|
-
|
|
56
|
-
override init() {
|
|
57
|
-
super.init()
|
|
58
|
-
centralManager = CBCentralManager(delegate: self, queue: nil)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
|
62
|
-
switch central.state {
|
|
63
|
-
case .poweredOn:
|
|
64
|
-
startScanning()
|
|
65
|
-
case .poweredOff:
|
|
66
|
-
// Bluetooth is off -- prompt user to enable
|
|
67
|
-
break
|
|
68
|
-
case .unauthorized:
|
|
69
|
-
// App not authorized for Bluetooth
|
|
70
|
-
break
|
|
71
|
-
case .unsupported:
|
|
72
|
-
// Device does not support BLE
|
|
73
|
-
break
|
|
74
|
-
case .resetting, .unknown:
|
|
75
|
-
break
|
|
76
|
-
@unknown default:
|
|
77
|
-
break
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### Scanning for Peripherals
|
|
84
|
-
|
|
85
|
-
Scan for specific service UUIDs to save power. Pass `nil` to discover all
|
|
86
|
-
peripherals (not recommended in production).
|
|
87
|
-
|
|
88
|
-
```swift
|
|
89
|
-
let heartRateServiceUUID = CBUUID(string: "180D")
|
|
90
|
-
|
|
91
|
-
func startScanning() {
|
|
92
|
-
centralManager.scanForPeripherals(
|
|
93
|
-
withServices: [heartRateServiceUUID],
|
|
94
|
-
options: [CBCentralManagerScanOptionAllowDuplicatesKey: false]
|
|
95
|
-
)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
func centralManager(
|
|
99
|
-
_ central: CBCentralManager,
|
|
100
|
-
didDiscover peripheral: CBPeripheral,
|
|
101
|
-
advertisementData: [String: Any],
|
|
102
|
-
rssi RSSI: NSNumber
|
|
103
|
-
) {
|
|
104
|
-
guard RSSI.intValue > -70 else { return } // Filter weak signals
|
|
105
|
-
|
|
106
|
-
// IMPORTANT: Retain the peripheral -- it will be deallocated otherwise
|
|
107
|
-
discoveredPeripheral = peripheral
|
|
108
|
-
centralManager.stopScan()
|
|
109
|
-
centralManager.connect(peripheral, options: nil)
|
|
110
|
-
}
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## Central Role: Connecting
|
|
114
|
-
|
|
115
|
-
```swift
|
|
116
|
-
func centralManager(
|
|
117
|
-
_ central: CBCentralManager,
|
|
118
|
-
didConnect peripheral: CBPeripheral
|
|
119
|
-
) {
|
|
120
|
-
peripheral.delegate = self
|
|
121
|
-
peripheral.discoverServices([heartRateServiceUUID])
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
func centralManager(
|
|
125
|
-
_ central: CBCentralManager,
|
|
126
|
-
didFailToConnect peripheral: CBPeripheral,
|
|
127
|
-
error: Error?
|
|
128
|
-
) {
|
|
129
|
-
// Handle connection failure -- retry or inform user
|
|
130
|
-
discoveredPeripheral = nil
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
func centralManager(
|
|
134
|
-
_ central: CBCentralManager,
|
|
135
|
-
didDisconnectPeripheral peripheral: CBPeripheral,
|
|
136
|
-
timestamp: CFAbsoluteTime,
|
|
137
|
-
isReconnecting: Bool,
|
|
138
|
-
error: Error?
|
|
139
|
-
) {
|
|
140
|
-
if isReconnecting {
|
|
141
|
-
// System is automatically reconnecting
|
|
142
|
-
return
|
|
143
|
-
}
|
|
144
|
-
// Handle disconnection -- optionally reconnect
|
|
145
|
-
discoveredPeripheral = nil
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
## Discovering Services and Characteristics
|
|
150
|
-
|
|
151
|
-
Implement `CBPeripheralDelegate` to walk the service/characteristic tree.
|
|
152
|
-
|
|
153
|
-
```swift
|
|
154
|
-
extension BluetoothManager: CBPeripheralDelegate {
|
|
155
|
-
func peripheral(
|
|
156
|
-
_ peripheral: CBPeripheral,
|
|
157
|
-
didDiscoverServices error: Error?
|
|
158
|
-
) {
|
|
159
|
-
guard let services = peripheral.services else { return }
|
|
160
|
-
for service in services {
|
|
161
|
-
peripheral.discoverCharacteristics(nil, for: service)
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
func peripheral(
|
|
166
|
-
_ peripheral: CBPeripheral,
|
|
167
|
-
didDiscoverCharacteristicsFor service: CBService,
|
|
168
|
-
error: Error?
|
|
169
|
-
) {
|
|
170
|
-
guard let characteristics = service.characteristics else { return }
|
|
171
|
-
for characteristic in characteristics {
|
|
172
|
-
if characteristic.properties.contains(.notify) {
|
|
173
|
-
peripheral.setNotifyValue(true, for: characteristic)
|
|
174
|
-
}
|
|
175
|
-
if characteristic.properties.contains(.read) {
|
|
176
|
-
peripheral.readValue(for: characteristic)
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### Common Service and Characteristic UUIDs
|
|
184
|
-
|
|
185
|
-
| Service | UUID | Characteristics |
|
|
186
|
-
|---|---|---|
|
|
187
|
-
| Heart Rate | `180D` | Heart Rate Measurement (`2A37`), Body Sensor Location (`2A38`) |
|
|
188
|
-
| Battery | `180F` | Battery Level (`2A19`) |
|
|
189
|
-
| Device Information | `180A` | Manufacturer Name (`2A29`), Model Number (`2A24`) |
|
|
190
|
-
| Generic Access | `1800` | Device Name (`2A00`), Appearance (`2A01`) |
|
|
191
|
-
|
|
192
|
-
```swift
|
|
193
|
-
let heartRateMeasurementUUID = CBUUID(string: "2A37")
|
|
194
|
-
let batteryLevelUUID = CBUUID(string: "2A19")
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
## Reading, Writing, and Notifications
|
|
198
|
-
|
|
199
|
-
### Reading a Value
|
|
200
|
-
|
|
201
|
-
```swift
|
|
202
|
-
func peripheral(
|
|
203
|
-
_ peripheral: CBPeripheral,
|
|
204
|
-
didUpdateValueFor characteristic: CBCharacteristic,
|
|
205
|
-
error: Error?
|
|
206
|
-
) {
|
|
207
|
-
guard let data = characteristic.value else { return }
|
|
208
|
-
|
|
209
|
-
switch characteristic.uuid {
|
|
210
|
-
case CBUUID(string: "2A37"):
|
|
211
|
-
let heartRate = parseHeartRate(data)
|
|
212
|
-
print("Heart rate: \(heartRate) bpm")
|
|
213
|
-
case CBUUID(string: "2A19"):
|
|
214
|
-
let batteryLevel = data.first.map { Int($0) } ?? 0
|
|
215
|
-
print("Battery: \(batteryLevel)%")
|
|
216
|
-
default:
|
|
217
|
-
break
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
private func parseHeartRate(_ data: Data) -> Int {
|
|
222
|
-
let flags = data[0]
|
|
223
|
-
let is16Bit = (flags & 0x01) != 0
|
|
224
|
-
if is16Bit {
|
|
225
|
-
return Int(data[1]) | (Int(data[2]) << 8)
|
|
226
|
-
} else {
|
|
227
|
-
return Int(data[1])
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
### Writing a Value
|
|
233
|
-
|
|
234
|
-
```swift
|
|
235
|
-
func writeValue(_ data: Data, to characteristic: CBCharacteristic,
|
|
236
|
-
on peripheral: CBPeripheral) {
|
|
237
|
-
if characteristic.properties.contains(.writeWithoutResponse) {
|
|
238
|
-
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
|
|
239
|
-
} else if characteristic.properties.contains(.write) {
|
|
240
|
-
peripheral.writeValue(data, for: characteristic, type: .withResponse)
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Confirmation callback for .withResponse writes
|
|
245
|
-
func peripheral(
|
|
246
|
-
_ peripheral: CBPeripheral,
|
|
247
|
-
didWriteValueFor characteristic: CBCharacteristic,
|
|
248
|
-
error: Error?
|
|
249
|
-
) {
|
|
250
|
-
if let error {
|
|
251
|
-
print("Write failed: \(error.localizedDescription)")
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
### Subscribing to Notifications
|
|
257
|
-
|
|
258
|
-
```swift
|
|
259
|
-
// Subscribe
|
|
260
|
-
peripheral.setNotifyValue(true, for: characteristic)
|
|
261
|
-
|
|
262
|
-
// Unsubscribe
|
|
263
|
-
peripheral.setNotifyValue(false, for: characteristic)
|
|
264
|
-
|
|
265
|
-
// Confirmation
|
|
266
|
-
func peripheral(
|
|
267
|
-
_ peripheral: CBPeripheral,
|
|
268
|
-
didUpdateNotificationStateFor characteristic: CBCharacteristic,
|
|
269
|
-
error: Error?
|
|
270
|
-
) {
|
|
271
|
-
if characteristic.isNotifying {
|
|
272
|
-
print("Now receiving notifications for \(characteristic.uuid)")
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
## Peripheral Role: Advertising
|
|
278
|
-
|
|
279
|
-
Publish services from the local device using `CBPeripheralManager`.
|
|
280
|
-
|
|
281
|
-
```swift
|
|
282
|
-
final class BLEPeripheralManager: NSObject, CBPeripheralManagerDelegate {
|
|
283
|
-
private var peripheralManager: CBPeripheralManager!
|
|
284
|
-
private let serviceUUID = CBUUID(string: "12345678-1234-1234-1234-123456789ABC")
|
|
285
|
-
private let charUUID = CBUUID(string: "12345678-1234-1234-1234-123456789ABD")
|
|
286
|
-
|
|
287
|
-
override init() {
|
|
288
|
-
super.init()
|
|
289
|
-
peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
|
|
293
|
-
guard peripheral.state == .poweredOn else { return }
|
|
294
|
-
setupService()
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
private func setupService() {
|
|
298
|
-
let characteristic = CBMutableCharacteristic(
|
|
299
|
-
type: charUUID,
|
|
300
|
-
properties: [.read, .notify],
|
|
301
|
-
value: nil,
|
|
302
|
-
permissions: [.readable]
|
|
303
|
-
)
|
|
304
|
-
|
|
305
|
-
let service = CBMutableService(type: serviceUUID, primary: true)
|
|
306
|
-
service.characteristics = [characteristic]
|
|
307
|
-
peripheralManager.add(service)
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
func peripheralManager(
|
|
311
|
-
_ peripheral: CBPeripheralManager,
|
|
312
|
-
didAdd service: CBService,
|
|
313
|
-
error: Error?
|
|
314
|
-
) {
|
|
315
|
-
guard error == nil else { return }
|
|
316
|
-
peripheralManager.startAdvertising([
|
|
317
|
-
CBAdvertisementDataServiceUUIDsKey: [serviceUUID],
|
|
318
|
-
CBAdvertisementDataLocalNameKey: "MyDevice"
|
|
319
|
-
])
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
## Background BLE
|
|
325
|
-
|
|
326
|
-
### Background Central Mode
|
|
327
|
-
|
|
328
|
-
Add `bluetooth-central` to `UIBackgroundModes`. In the background:
|
|
329
|
-
|
|
330
|
-
- Scanning continues but only for specific service UUIDs
|
|
331
|
-
- `CBCentralManagerScanOptionAllowDuplicatesKey` is ignored (always `false`)
|
|
332
|
-
- Discovery callbacks are coalesced and delivered in batches
|
|
333
|
-
|
|
334
|
-
### Background Peripheral Mode
|
|
335
|
-
|
|
336
|
-
Add `bluetooth-peripheral` to `UIBackgroundModes`. In the background:
|
|
337
|
-
|
|
338
|
-
- Advertising continues but data is reduced to service UUIDs only
|
|
339
|
-
- The local name is not included in background advertisements
|
|
340
|
-
|
|
341
|
-
## State Restoration
|
|
342
|
-
|
|
343
|
-
State restoration allows the system to re-create your central or peripheral
|
|
344
|
-
manager after your app is terminated and relaunched for a BLE event.
|
|
345
|
-
|
|
346
|
-
### Central Manager State Restoration
|
|
347
|
-
|
|
348
|
-
```swift
|
|
349
|
-
// 1. Create with a restoration identifier
|
|
350
|
-
centralManager = CBCentralManager(
|
|
351
|
-
delegate: self,
|
|
352
|
-
queue: nil,
|
|
353
|
-
options: [CBCentralManagerOptionRestoreIdentifierKey: "myCentral"]
|
|
354
|
-
)
|
|
355
|
-
|
|
356
|
-
// 2. Implement the restoration delegate method
|
|
357
|
-
func centralManager(
|
|
358
|
-
_ central: CBCentralManager,
|
|
359
|
-
willRestoreState dict: [String: Any]
|
|
360
|
-
) {
|
|
361
|
-
if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey]
|
|
362
|
-
as? [CBPeripheral] {
|
|
363
|
-
for peripheral in peripherals {
|
|
364
|
-
// Re-assign delegate and retain
|
|
365
|
-
peripheral.delegate = self
|
|
366
|
-
discoveredPeripheral = peripheral
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
### Peripheral Manager State Restoration
|
|
373
|
-
|
|
374
|
-
```swift
|
|
375
|
-
peripheralManager = CBPeripheralManager(
|
|
376
|
-
delegate: self,
|
|
377
|
-
queue: nil,
|
|
378
|
-
options: [CBPeripheralManagerOptionRestoreIdentifierKey: "myPeripheral"]
|
|
379
|
-
)
|
|
380
|
-
|
|
381
|
-
func peripheralManager(
|
|
382
|
-
_ peripheral: CBPeripheralManager,
|
|
383
|
-
willRestoreState dict: [String: Any]
|
|
384
|
-
) {
|
|
385
|
-
// Restore published services, advertising state, etc.
|
|
386
|
-
}
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
## Common Mistakes
|
|
390
|
-
|
|
391
|
-
### DON'T: Scan or connect before poweredOn
|
|
392
|
-
|
|
393
|
-
```swift
|
|
394
|
-
// WRONG: Scanning immediately -- manager may not be ready
|
|
395
|
-
let manager = CBCentralManager(delegate: self, queue: nil)
|
|
396
|
-
manager.scanForPeripherals(withServices: nil) // May silently fail
|
|
397
|
-
|
|
398
|
-
// CORRECT: Wait for poweredOn in the delegate
|
|
399
|
-
func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
|
400
|
-
if central.state == .poweredOn {
|
|
401
|
-
central.scanForPeripherals(withServices: [serviceUUID])
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
### DON'T: Lose the peripheral reference
|
|
407
|
-
|
|
408
|
-
Core Bluetooth does not retain discovered peripherals. If you don't hold a
|
|
409
|
-
strong reference, the peripheral is deallocated and the connection fails silently.
|
|
410
|
-
|
|
411
|
-
```swift
|
|
412
|
-
// WRONG: No strong reference kept
|
|
413
|
-
func centralManager(_ central: CBCentralManager,
|
|
414
|
-
didDiscover peripheral: CBPeripheral, ...) {
|
|
415
|
-
central.connect(peripheral) // peripheral may be deallocated
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// CORRECT: Retain the peripheral
|
|
419
|
-
func centralManager(_ central: CBCentralManager,
|
|
420
|
-
didDiscover peripheral: CBPeripheral, ...) {
|
|
421
|
-
self.discoveredPeripheral = peripheral // Strong reference
|
|
422
|
-
central.connect(peripheral)
|
|
423
|
-
}
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
### DON'T: Scan for nil services in production
|
|
427
|
-
|
|
428
|
-
```swift
|
|
429
|
-
// WRONG: Discovers every BLE device in range -- drains battery
|
|
430
|
-
centralManager.scanForPeripherals(withServices: nil)
|
|
431
|
-
|
|
432
|
-
// CORRECT: Specify the service UUIDs you need
|
|
433
|
-
centralManager.scanForPeripherals(withServices: [targetServiceUUID])
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
### DON'T: Assume connection order or timing
|
|
437
|
-
|
|
438
|
-
```swift
|
|
439
|
-
// WRONG: Assuming immediate connection
|
|
440
|
-
centralManager.connect(peripheral)
|
|
441
|
-
discoverServicesNow() // Peripheral not connected yet
|
|
442
|
-
|
|
443
|
-
// CORRECT: Discover services in the didConnect callback
|
|
444
|
-
func centralManager(_ central: CBCentralManager,
|
|
445
|
-
didConnect peripheral: CBPeripheral) {
|
|
446
|
-
peripheral.delegate = self
|
|
447
|
-
peripheral.discoverServices([serviceUUID])
|
|
448
|
-
}
|
|
449
|
-
```
|
|
450
|
-
|
|
451
|
-
### DON'T: Write to a characteristic without checking properties
|
|
452
|
-
|
|
453
|
-
```swift
|
|
454
|
-
// WRONG: Crashes or silently fails if write is unsupported
|
|
455
|
-
peripheral.writeValue(data, for: characteristic, type: .withResponse)
|
|
456
|
-
|
|
457
|
-
// CORRECT: Check properties first
|
|
458
|
-
if characteristic.properties.contains(.write) {
|
|
459
|
-
peripheral.writeValue(data, for: characteristic, type: .withResponse)
|
|
460
|
-
} else if characteristic.properties.contains(.writeWithoutResponse) {
|
|
461
|
-
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
|
|
462
|
-
}
|
|
463
|
-
```
|
|
464
|
-
|
|
465
|
-
## Review Checklist
|
|
466
|
-
|
|
467
|
-
- [ ] `NSBluetoothAlwaysUsageDescription` added to Info.plist
|
|
468
|
-
- [ ] All BLE operations gated on `centralManagerDidUpdateState` returning `.poweredOn`
|
|
469
|
-
- [ ] Discovered peripherals retained with a strong reference
|
|
470
|
-
- [ ] Scanning uses specific service UUIDs (not `nil`) in production
|
|
471
|
-
- [ ] `CBPeripheralDelegate` set before calling `discoverServices`
|
|
472
|
-
- [ ] Characteristic properties checked before read/write/notify
|
|
473
|
-
- [ ] Background mode (`bluetooth-central` or `bluetooth-peripheral`) added if needed
|
|
474
|
-
- [ ] State restoration identifier set if app needs relaunch-on-BLE-event support
|
|
475
|
-
- [ ] `willRestoreState` delegate method implemented when using state restoration
|
|
476
|
-
- [ ] Scanning stopped after discovering the target peripheral
|
|
477
|
-
- [ ] Disconnection handled with optional automatic reconnect logic
|
|
478
|
-
- [ ] Write type matches characteristic properties (`.withResponse` vs `.withoutResponse`)
|
|
479
|
-
|
|
480
|
-
## References
|
|
481
|
-
|
|
482
|
-
- Extended patterns (reconnection strategies, data parsing, SwiftUI integration): `references/ble-patterns.md`
|
|
483
|
-
- [Core Bluetooth framework](https://sosumi.ai/documentation/corebluetooth)
|
|
484
|
-
- [CBCentralManager](https://sosumi.ai/documentation/corebluetooth/cbcentralmanager)
|
|
485
|
-
- [CBPeripheral](https://sosumi.ai/documentation/corebluetooth/cbperipheral)
|
|
486
|
-
- [CBPeripheralManager](https://sosumi.ai/documentation/corebluetooth/cbperipheralmanager)
|
|
487
|
-
- [CBService](https://sosumi.ai/documentation/corebluetooth/cbservice)
|
|
488
|
-
- [CBCharacteristic](https://sosumi.ai/documentation/corebluetooth/cbcharacteristic)
|
|
489
|
-
- [CBUUID](https://sosumi.ai/documentation/corebluetooth/cbuuid)
|
|
490
|
-
- [CBCentralManagerDelegate](https://sosumi.ai/documentation/corebluetooth/cbcentralmanagerdelegate)
|
|
491
|
-
- [CBPeripheralDelegate](https://sosumi.ai/documentation/corebluetooth/cbperipheraldelegate)
|
|
1
|
+
---
|
|
2
|
+
name: core-bluetooth
|
|
3
|
+
description: "Scan, connect, and communicate with Bluetooth Low Energy peripherals and publish local peripheral services using Core Bluetooth. Use when implementing BLE central or peripheral roles, discovering services and characteristics, reading and writing characteristic values, subscribing to notifications, configuring background BLE modes, restoring state after app relaunch, or working with CBCentralManager, CBPeripheral, CBPeripheralManager, CBService, CBCharacteristic, CBUUID, or Bluetooth Low Energy workflows."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Core Bluetooth
|
|
7
|
+
|
|
8
|
+
Scan for, connect to, and exchange data with Bluetooth Low Energy (BLE) devices.
|
|
9
|
+
Covers the central role (scanning and connecting to peripherals), the peripheral
|
|
10
|
+
role (advertising services), background modes, and state restoration.
|
|
11
|
+
Targets Swift 6.2 / iOS 26+.
|
|
12
|
+
|
|
13
|
+
## Contents
|
|
14
|
+
|
|
15
|
+
- [Setup](#setup)
|
|
16
|
+
- [Central Role: Scanning](#central-role-scanning)
|
|
17
|
+
- [Central Role: Connecting](#central-role-connecting)
|
|
18
|
+
- [Discovering Services and Characteristics](#discovering-services-and-characteristics)
|
|
19
|
+
- [Reading, Writing, and Notifications](#reading-writing-and-notifications)
|
|
20
|
+
- [Peripheral Role: Advertising](#peripheral-role-advertising)
|
|
21
|
+
- [Background BLE](#background-ble)
|
|
22
|
+
- [State Restoration](#state-restoration)
|
|
23
|
+
- [Common Mistakes](#common-mistakes)
|
|
24
|
+
- [Review Checklist](#review-checklist)
|
|
25
|
+
- [References](#references)
|
|
26
|
+
|
|
27
|
+
## Setup
|
|
28
|
+
|
|
29
|
+
### Info.plist Keys
|
|
30
|
+
|
|
31
|
+
| Key | Purpose |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `NSBluetoothAlwaysUsageDescription` | Required. Explains why the app uses Bluetooth |
|
|
34
|
+
| `UIBackgroundModes` with `bluetooth-central` | Background scanning and connecting |
|
|
35
|
+
| `UIBackgroundModes` with `bluetooth-peripheral` | Background advertising |
|
|
36
|
+
|
|
37
|
+
### Bluetooth Authorization
|
|
38
|
+
|
|
39
|
+
iOS prompts for Bluetooth permission automatically when you create a
|
|
40
|
+
`CBCentralManager` or `CBPeripheralManager`. The usage description from
|
|
41
|
+
`NSBluetoothAlwaysUsageDescription` is shown in the permission dialog.
|
|
42
|
+
|
|
43
|
+
## Central Role: Scanning
|
|
44
|
+
|
|
45
|
+
### Creating the Central Manager
|
|
46
|
+
|
|
47
|
+
Always wait for the `poweredOn` state before scanning.
|
|
48
|
+
|
|
49
|
+
```swift
|
|
50
|
+
import CoreBluetooth
|
|
51
|
+
|
|
52
|
+
final class BluetoothManager: NSObject, CBCentralManagerDelegate {
|
|
53
|
+
private var centralManager: CBCentralManager!
|
|
54
|
+
private var discoveredPeripheral: CBPeripheral?
|
|
55
|
+
|
|
56
|
+
override init() {
|
|
57
|
+
super.init()
|
|
58
|
+
centralManager = CBCentralManager(delegate: self, queue: nil)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
|
62
|
+
switch central.state {
|
|
63
|
+
case .poweredOn:
|
|
64
|
+
startScanning()
|
|
65
|
+
case .poweredOff:
|
|
66
|
+
// Bluetooth is off -- prompt user to enable
|
|
67
|
+
break
|
|
68
|
+
case .unauthorized:
|
|
69
|
+
// App not authorized for Bluetooth
|
|
70
|
+
break
|
|
71
|
+
case .unsupported:
|
|
72
|
+
// Device does not support BLE
|
|
73
|
+
break
|
|
74
|
+
case .resetting, .unknown:
|
|
75
|
+
break
|
|
76
|
+
@unknown default:
|
|
77
|
+
break
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Scanning for Peripherals
|
|
84
|
+
|
|
85
|
+
Scan for specific service UUIDs to save power. Pass `nil` to discover all
|
|
86
|
+
peripherals (not recommended in production).
|
|
87
|
+
|
|
88
|
+
```swift
|
|
89
|
+
let heartRateServiceUUID = CBUUID(string: "180D")
|
|
90
|
+
|
|
91
|
+
func startScanning() {
|
|
92
|
+
centralManager.scanForPeripherals(
|
|
93
|
+
withServices: [heartRateServiceUUID],
|
|
94
|
+
options: [CBCentralManagerScanOptionAllowDuplicatesKey: false]
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func centralManager(
|
|
99
|
+
_ central: CBCentralManager,
|
|
100
|
+
didDiscover peripheral: CBPeripheral,
|
|
101
|
+
advertisementData: [String: Any],
|
|
102
|
+
rssi RSSI: NSNumber
|
|
103
|
+
) {
|
|
104
|
+
guard RSSI.intValue > -70 else { return } // Filter weak signals
|
|
105
|
+
|
|
106
|
+
// IMPORTANT: Retain the peripheral -- it will be deallocated otherwise
|
|
107
|
+
discoveredPeripheral = peripheral
|
|
108
|
+
centralManager.stopScan()
|
|
109
|
+
centralManager.connect(peripheral, options: nil)
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Central Role: Connecting
|
|
114
|
+
|
|
115
|
+
```swift
|
|
116
|
+
func centralManager(
|
|
117
|
+
_ central: CBCentralManager,
|
|
118
|
+
didConnect peripheral: CBPeripheral
|
|
119
|
+
) {
|
|
120
|
+
peripheral.delegate = self
|
|
121
|
+
peripheral.discoverServices([heartRateServiceUUID])
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
func centralManager(
|
|
125
|
+
_ central: CBCentralManager,
|
|
126
|
+
didFailToConnect peripheral: CBPeripheral,
|
|
127
|
+
error: Error?
|
|
128
|
+
) {
|
|
129
|
+
// Handle connection failure -- retry or inform user
|
|
130
|
+
discoveredPeripheral = nil
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
func centralManager(
|
|
134
|
+
_ central: CBCentralManager,
|
|
135
|
+
didDisconnectPeripheral peripheral: CBPeripheral,
|
|
136
|
+
timestamp: CFAbsoluteTime,
|
|
137
|
+
isReconnecting: Bool,
|
|
138
|
+
error: Error?
|
|
139
|
+
) {
|
|
140
|
+
if isReconnecting {
|
|
141
|
+
// System is automatically reconnecting
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
// Handle disconnection -- optionally reconnect
|
|
145
|
+
discoveredPeripheral = nil
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Discovering Services and Characteristics
|
|
150
|
+
|
|
151
|
+
Implement `CBPeripheralDelegate` to walk the service/characteristic tree.
|
|
152
|
+
|
|
153
|
+
```swift
|
|
154
|
+
extension BluetoothManager: CBPeripheralDelegate {
|
|
155
|
+
func peripheral(
|
|
156
|
+
_ peripheral: CBPeripheral,
|
|
157
|
+
didDiscoverServices error: Error?
|
|
158
|
+
) {
|
|
159
|
+
guard let services = peripheral.services else { return }
|
|
160
|
+
for service in services {
|
|
161
|
+
peripheral.discoverCharacteristics(nil, for: service)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
func peripheral(
|
|
166
|
+
_ peripheral: CBPeripheral,
|
|
167
|
+
didDiscoverCharacteristicsFor service: CBService,
|
|
168
|
+
error: Error?
|
|
169
|
+
) {
|
|
170
|
+
guard let characteristics = service.characteristics else { return }
|
|
171
|
+
for characteristic in characteristics {
|
|
172
|
+
if characteristic.properties.contains(.notify) {
|
|
173
|
+
peripheral.setNotifyValue(true, for: characteristic)
|
|
174
|
+
}
|
|
175
|
+
if characteristic.properties.contains(.read) {
|
|
176
|
+
peripheral.readValue(for: characteristic)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Common Service and Characteristic UUIDs
|
|
184
|
+
|
|
185
|
+
| Service | UUID | Characteristics |
|
|
186
|
+
|---|---|---|
|
|
187
|
+
| Heart Rate | `180D` | Heart Rate Measurement (`2A37`), Body Sensor Location (`2A38`) |
|
|
188
|
+
| Battery | `180F` | Battery Level (`2A19`) |
|
|
189
|
+
| Device Information | `180A` | Manufacturer Name (`2A29`), Model Number (`2A24`) |
|
|
190
|
+
| Generic Access | `1800` | Device Name (`2A00`), Appearance (`2A01`) |
|
|
191
|
+
|
|
192
|
+
```swift
|
|
193
|
+
let heartRateMeasurementUUID = CBUUID(string: "2A37")
|
|
194
|
+
let batteryLevelUUID = CBUUID(string: "2A19")
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Reading, Writing, and Notifications
|
|
198
|
+
|
|
199
|
+
### Reading a Value
|
|
200
|
+
|
|
201
|
+
```swift
|
|
202
|
+
func peripheral(
|
|
203
|
+
_ peripheral: CBPeripheral,
|
|
204
|
+
didUpdateValueFor characteristic: CBCharacteristic,
|
|
205
|
+
error: Error?
|
|
206
|
+
) {
|
|
207
|
+
guard let data = characteristic.value else { return }
|
|
208
|
+
|
|
209
|
+
switch characteristic.uuid {
|
|
210
|
+
case CBUUID(string: "2A37"):
|
|
211
|
+
let heartRate = parseHeartRate(data)
|
|
212
|
+
print("Heart rate: \(heartRate) bpm")
|
|
213
|
+
case CBUUID(string: "2A19"):
|
|
214
|
+
let batteryLevel = data.first.map { Int($0) } ?? 0
|
|
215
|
+
print("Battery: \(batteryLevel)%")
|
|
216
|
+
default:
|
|
217
|
+
break
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
private func parseHeartRate(_ data: Data) -> Int {
|
|
222
|
+
let flags = data[0]
|
|
223
|
+
let is16Bit = (flags & 0x01) != 0
|
|
224
|
+
if is16Bit {
|
|
225
|
+
return Int(data[1]) | (Int(data[2]) << 8)
|
|
226
|
+
} else {
|
|
227
|
+
return Int(data[1])
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Writing a Value
|
|
233
|
+
|
|
234
|
+
```swift
|
|
235
|
+
func writeValue(_ data: Data, to characteristic: CBCharacteristic,
|
|
236
|
+
on peripheral: CBPeripheral) {
|
|
237
|
+
if characteristic.properties.contains(.writeWithoutResponse) {
|
|
238
|
+
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
|
|
239
|
+
} else if characteristic.properties.contains(.write) {
|
|
240
|
+
peripheral.writeValue(data, for: characteristic, type: .withResponse)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Confirmation callback for .withResponse writes
|
|
245
|
+
func peripheral(
|
|
246
|
+
_ peripheral: CBPeripheral,
|
|
247
|
+
didWriteValueFor characteristic: CBCharacteristic,
|
|
248
|
+
error: Error?
|
|
249
|
+
) {
|
|
250
|
+
if let error {
|
|
251
|
+
print("Write failed: \(error.localizedDescription)")
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Subscribing to Notifications
|
|
257
|
+
|
|
258
|
+
```swift
|
|
259
|
+
// Subscribe
|
|
260
|
+
peripheral.setNotifyValue(true, for: characteristic)
|
|
261
|
+
|
|
262
|
+
// Unsubscribe
|
|
263
|
+
peripheral.setNotifyValue(false, for: characteristic)
|
|
264
|
+
|
|
265
|
+
// Confirmation
|
|
266
|
+
func peripheral(
|
|
267
|
+
_ peripheral: CBPeripheral,
|
|
268
|
+
didUpdateNotificationStateFor characteristic: CBCharacteristic,
|
|
269
|
+
error: Error?
|
|
270
|
+
) {
|
|
271
|
+
if characteristic.isNotifying {
|
|
272
|
+
print("Now receiving notifications for \(characteristic.uuid)")
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Peripheral Role: Advertising
|
|
278
|
+
|
|
279
|
+
Publish services from the local device using `CBPeripheralManager`.
|
|
280
|
+
|
|
281
|
+
```swift
|
|
282
|
+
final class BLEPeripheralManager: NSObject, CBPeripheralManagerDelegate {
|
|
283
|
+
private var peripheralManager: CBPeripheralManager!
|
|
284
|
+
private let serviceUUID = CBUUID(string: "12345678-1234-1234-1234-123456789ABC")
|
|
285
|
+
private let charUUID = CBUUID(string: "12345678-1234-1234-1234-123456789ABD")
|
|
286
|
+
|
|
287
|
+
override init() {
|
|
288
|
+
super.init()
|
|
289
|
+
peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
|
|
293
|
+
guard peripheral.state == .poweredOn else { return }
|
|
294
|
+
setupService()
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private func setupService() {
|
|
298
|
+
let characteristic = CBMutableCharacteristic(
|
|
299
|
+
type: charUUID,
|
|
300
|
+
properties: [.read, .notify],
|
|
301
|
+
value: nil,
|
|
302
|
+
permissions: [.readable]
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
let service = CBMutableService(type: serviceUUID, primary: true)
|
|
306
|
+
service.characteristics = [characteristic]
|
|
307
|
+
peripheralManager.add(service)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
func peripheralManager(
|
|
311
|
+
_ peripheral: CBPeripheralManager,
|
|
312
|
+
didAdd service: CBService,
|
|
313
|
+
error: Error?
|
|
314
|
+
) {
|
|
315
|
+
guard error == nil else { return }
|
|
316
|
+
peripheralManager.startAdvertising([
|
|
317
|
+
CBAdvertisementDataServiceUUIDsKey: [serviceUUID],
|
|
318
|
+
CBAdvertisementDataLocalNameKey: "MyDevice"
|
|
319
|
+
])
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## Background BLE
|
|
325
|
+
|
|
326
|
+
### Background Central Mode
|
|
327
|
+
|
|
328
|
+
Add `bluetooth-central` to `UIBackgroundModes`. In the background:
|
|
329
|
+
|
|
330
|
+
- Scanning continues but only for specific service UUIDs
|
|
331
|
+
- `CBCentralManagerScanOptionAllowDuplicatesKey` is ignored (always `false`)
|
|
332
|
+
- Discovery callbacks are coalesced and delivered in batches
|
|
333
|
+
|
|
334
|
+
### Background Peripheral Mode
|
|
335
|
+
|
|
336
|
+
Add `bluetooth-peripheral` to `UIBackgroundModes`. In the background:
|
|
337
|
+
|
|
338
|
+
- Advertising continues but data is reduced to service UUIDs only
|
|
339
|
+
- The local name is not included in background advertisements
|
|
340
|
+
|
|
341
|
+
## State Restoration
|
|
342
|
+
|
|
343
|
+
State restoration allows the system to re-create your central or peripheral
|
|
344
|
+
manager after your app is terminated and relaunched for a BLE event.
|
|
345
|
+
|
|
346
|
+
### Central Manager State Restoration
|
|
347
|
+
|
|
348
|
+
```swift
|
|
349
|
+
// 1. Create with a restoration identifier
|
|
350
|
+
centralManager = CBCentralManager(
|
|
351
|
+
delegate: self,
|
|
352
|
+
queue: nil,
|
|
353
|
+
options: [CBCentralManagerOptionRestoreIdentifierKey: "myCentral"]
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
// 2. Implement the restoration delegate method
|
|
357
|
+
func centralManager(
|
|
358
|
+
_ central: CBCentralManager,
|
|
359
|
+
willRestoreState dict: [String: Any]
|
|
360
|
+
) {
|
|
361
|
+
if let peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey]
|
|
362
|
+
as? [CBPeripheral] {
|
|
363
|
+
for peripheral in peripherals {
|
|
364
|
+
// Re-assign delegate and retain
|
|
365
|
+
peripheral.delegate = self
|
|
366
|
+
discoveredPeripheral = peripheral
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Peripheral Manager State Restoration
|
|
373
|
+
|
|
374
|
+
```swift
|
|
375
|
+
peripheralManager = CBPeripheralManager(
|
|
376
|
+
delegate: self,
|
|
377
|
+
queue: nil,
|
|
378
|
+
options: [CBPeripheralManagerOptionRestoreIdentifierKey: "myPeripheral"]
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
func peripheralManager(
|
|
382
|
+
_ peripheral: CBPeripheralManager,
|
|
383
|
+
willRestoreState dict: [String: Any]
|
|
384
|
+
) {
|
|
385
|
+
// Restore published services, advertising state, etc.
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
## Common Mistakes
|
|
390
|
+
|
|
391
|
+
### DON'T: Scan or connect before poweredOn
|
|
392
|
+
|
|
393
|
+
```swift
|
|
394
|
+
// WRONG: Scanning immediately -- manager may not be ready
|
|
395
|
+
let manager = CBCentralManager(delegate: self, queue: nil)
|
|
396
|
+
manager.scanForPeripherals(withServices: nil) // May silently fail
|
|
397
|
+
|
|
398
|
+
// CORRECT: Wait for poweredOn in the delegate
|
|
399
|
+
func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
|
400
|
+
if central.state == .poweredOn {
|
|
401
|
+
central.scanForPeripherals(withServices: [serviceUUID])
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### DON'T: Lose the peripheral reference
|
|
407
|
+
|
|
408
|
+
Core Bluetooth does not retain discovered peripherals. If you don't hold a
|
|
409
|
+
strong reference, the peripheral is deallocated and the connection fails silently.
|
|
410
|
+
|
|
411
|
+
```swift
|
|
412
|
+
// WRONG: No strong reference kept
|
|
413
|
+
func centralManager(_ central: CBCentralManager,
|
|
414
|
+
didDiscover peripheral: CBPeripheral, ...) {
|
|
415
|
+
central.connect(peripheral) // peripheral may be deallocated
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// CORRECT: Retain the peripheral
|
|
419
|
+
func centralManager(_ central: CBCentralManager,
|
|
420
|
+
didDiscover peripheral: CBPeripheral, ...) {
|
|
421
|
+
self.discoveredPeripheral = peripheral // Strong reference
|
|
422
|
+
central.connect(peripheral)
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### DON'T: Scan for nil services in production
|
|
427
|
+
|
|
428
|
+
```swift
|
|
429
|
+
// WRONG: Discovers every BLE device in range -- drains battery
|
|
430
|
+
centralManager.scanForPeripherals(withServices: nil)
|
|
431
|
+
|
|
432
|
+
// CORRECT: Specify the service UUIDs you need
|
|
433
|
+
centralManager.scanForPeripherals(withServices: [targetServiceUUID])
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### DON'T: Assume connection order or timing
|
|
437
|
+
|
|
438
|
+
```swift
|
|
439
|
+
// WRONG: Assuming immediate connection
|
|
440
|
+
centralManager.connect(peripheral)
|
|
441
|
+
discoverServicesNow() // Peripheral not connected yet
|
|
442
|
+
|
|
443
|
+
// CORRECT: Discover services in the didConnect callback
|
|
444
|
+
func centralManager(_ central: CBCentralManager,
|
|
445
|
+
didConnect peripheral: CBPeripheral) {
|
|
446
|
+
peripheral.delegate = self
|
|
447
|
+
peripheral.discoverServices([serviceUUID])
|
|
448
|
+
}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
### DON'T: Write to a characteristic without checking properties
|
|
452
|
+
|
|
453
|
+
```swift
|
|
454
|
+
// WRONG: Crashes or silently fails if write is unsupported
|
|
455
|
+
peripheral.writeValue(data, for: characteristic, type: .withResponse)
|
|
456
|
+
|
|
457
|
+
// CORRECT: Check properties first
|
|
458
|
+
if characteristic.properties.contains(.write) {
|
|
459
|
+
peripheral.writeValue(data, for: characteristic, type: .withResponse)
|
|
460
|
+
} else if characteristic.properties.contains(.writeWithoutResponse) {
|
|
461
|
+
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
|
|
462
|
+
}
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
## Review Checklist
|
|
466
|
+
|
|
467
|
+
- [ ] `NSBluetoothAlwaysUsageDescription` added to Info.plist
|
|
468
|
+
- [ ] All BLE operations gated on `centralManagerDidUpdateState` returning `.poweredOn`
|
|
469
|
+
- [ ] Discovered peripherals retained with a strong reference
|
|
470
|
+
- [ ] Scanning uses specific service UUIDs (not `nil`) in production
|
|
471
|
+
- [ ] `CBPeripheralDelegate` set before calling `discoverServices`
|
|
472
|
+
- [ ] Characteristic properties checked before read/write/notify
|
|
473
|
+
- [ ] Background mode (`bluetooth-central` or `bluetooth-peripheral`) added if needed
|
|
474
|
+
- [ ] State restoration identifier set if app needs relaunch-on-BLE-event support
|
|
475
|
+
- [ ] `willRestoreState` delegate method implemented when using state restoration
|
|
476
|
+
- [ ] Scanning stopped after discovering the target peripheral
|
|
477
|
+
- [ ] Disconnection handled with optional automatic reconnect logic
|
|
478
|
+
- [ ] Write type matches characteristic properties (`.withResponse` vs `.withoutResponse`)
|
|
479
|
+
|
|
480
|
+
## References
|
|
481
|
+
|
|
482
|
+
- Extended patterns (reconnection strategies, data parsing, SwiftUI integration): `references/ble-patterns.md`
|
|
483
|
+
- [Core Bluetooth framework](https://sosumi.ai/documentation/corebluetooth)
|
|
484
|
+
- [CBCentralManager](https://sosumi.ai/documentation/corebluetooth/cbcentralmanager)
|
|
485
|
+
- [CBPeripheral](https://sosumi.ai/documentation/corebluetooth/cbperipheral)
|
|
486
|
+
- [CBPeripheralManager](https://sosumi.ai/documentation/corebluetooth/cbperipheralmanager)
|
|
487
|
+
- [CBService](https://sosumi.ai/documentation/corebluetooth/cbservice)
|
|
488
|
+
- [CBCharacteristic](https://sosumi.ai/documentation/corebluetooth/cbcharacteristic)
|
|
489
|
+
- [CBUUID](https://sosumi.ai/documentation/corebluetooth/cbuuid)
|
|
490
|
+
- [CBCentralManagerDelegate](https://sosumi.ai/documentation/corebluetooth/cbcentralmanagerdelegate)
|
|
491
|
+
- [CBPeripheralDelegate](https://sosumi.ai/documentation/corebluetooth/cbperipheraldelegate)
|