@devo-bmad-custom/agent-orchestration 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/installer.js +33 -0
- package/package.json +1 -1
- package/src/.agents/skills/audit-website/README.md +20 -20
- package/src/.agents/skills/audit-website/SKILL.md +470 -470
- package/src/.agents/skills/audit-website/agents/openai.yaml +6 -6
- package/src/.agents/skills/audit-website/assets/icon-small.svg +41 -41
- package/src/.agents/skills/audit-website/references/OUTPUT-FORMAT.md +250 -250
- package/src/.agents/skills/clean-code-standards/SKILL.md +104 -104
- package/src/.agents/skills/excalidraw-dark-standard/SKILL.md +281 -281
- package/src/.agents/skills/frontend-responsive-design-standards/SKILL.md +434 -434
- package/src/.agents/skills/java-fundamentals/SKILL.md +116 -116
- package/src/.agents/skills/java-performance/SKILL.md +119 -119
- package/src/.agents/skills/next-best-practices/SKILL.md +153 -153
- package/src/.agents/skills/next-best-practices/async-patterns.md +87 -87
- package/src/.agents/skills/next-best-practices/bundling.md +180 -180
- package/src/.agents/skills/next-best-practices/data-patterns.md +297 -297
- package/src/.agents/skills/next-best-practices/debug-tricks.md +105 -105
- package/src/.agents/skills/next-best-practices/directives.md +73 -73
- package/src/.agents/skills/next-best-practices/error-handling.md +227 -227
- package/src/.agents/skills/next-best-practices/file-conventions.md +140 -140
- package/src/.agents/skills/next-best-practices/font.md +245 -245
- package/src/.agents/skills/next-best-practices/functions.md +108 -108
- package/src/.agents/skills/next-best-practices/hydration-error.md +91 -91
- package/src/.agents/skills/next-best-practices/image.md +173 -173
- package/src/.agents/skills/next-best-practices/metadata.md +301 -301
- package/src/.agents/skills/next-best-practices/parallel-routes.md +287 -287
- package/src/.agents/skills/next-best-practices/route-handlers.md +146 -146
- package/src/.agents/skills/next-best-practices/rsc-boundaries.md +159 -159
- package/src/.agents/skills/next-best-practices/runtime-selection.md +39 -39
- package/src/.agents/skills/next-best-practices/scripts.md +141 -141
- package/src/.agents/skills/next-best-practices/self-hosting.md +371 -371
- package/src/.agents/skills/next-best-practices/suspense-boundaries.md +67 -67
- package/src/.agents/skills/nextjs-app-router-patterns/SKILL.md +537 -537
- package/src/.agents/skills/postgresql-optimization/SKILL.md +404 -404
- package/src/.agents/skills/python-backend/SKILL.md +153 -153
- package/src/.agents/skills/python-fundamentals/SKILL.md +234 -234
- package/src/.agents/skills/python-performance/SKILL.md +404 -404
- package/src/.agents/skills/react-expert/SKILL.md +335 -335
- package/src/.agents/skills/redis-best-practices/SKILL.md +438 -438
- package/src/.agents/skills/security-best-practices/SKILL.md +288 -288
- package/src/.agents/skills/security-review/LICENSE +22 -22
- package/src/.agents/skills/security-review/SKILL.md +312 -312
- package/src/.agents/skills/security-review/infrastructure/docker.md +432 -432
- package/src/.agents/skills/security-review/languages/javascript.md +388 -388
- package/src/.agents/skills/security-review/languages/python.md +363 -363
- package/src/.agents/skills/security-review/references/api-security.md +519 -519
- package/src/.agents/skills/security-review/references/authentication.md +353 -353
- package/src/.agents/skills/security-review/references/authorization.md +372 -372
- package/src/.agents/skills/security-review/references/business-logic.md +443 -443
- package/src/.agents/skills/security-review/references/cryptography.md +329 -329
- package/src/.agents/skills/security-review/references/csrf.md +398 -398
- package/src/.agents/skills/security-review/references/data-protection.md +378 -378
- package/src/.agents/skills/security-review/references/deserialization.md +410 -410
- package/src/.agents/skills/security-review/references/error-handling.md +436 -436
- package/src/.agents/skills/security-review/references/file-security.md +457 -457
- package/src/.agents/skills/security-review/references/injection.md +259 -259
- package/src/.agents/skills/security-review/references/logging.md +433 -433
- package/src/.agents/skills/security-review/references/misconfiguration.md +435 -435
- package/src/.agents/skills/security-review/references/modern-threats.md +475 -475
- package/src/.agents/skills/security-review/references/ssrf.md +415 -415
- package/src/.agents/skills/security-review/references/supply-chain.md +405 -405
- package/src/.agents/skills/security-review/references/xss.md +336 -336
- package/src/.agents/skills/subagent-driven-development/SKILL.md +275 -275
- package/src/.agents/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -26
- package/src/.agents/skills/subagent-driven-development/implementer-prompt.md +113 -113
- package/src/.agents/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -61
- package/src/.agents/skills/systematic-debugging/CREATION-LOG.md +119 -119
- package/src/.agents/skills/systematic-debugging/SKILL.md +296 -296
- package/src/.agents/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
- package/src/.agents/skills/systematic-debugging/condition-based-waiting.md +115 -115
- package/src/.agents/skills/systematic-debugging/defense-in-depth.md +122 -122
- package/src/.agents/skills/systematic-debugging/root-cause-tracing.md +169 -169
- package/src/.agents/skills/systematic-debugging/test-academic.md +14 -14
- package/src/.agents/skills/systematic-debugging/test-pressure-1.md +58 -58
- package/src/.agents/skills/systematic-debugging/test-pressure-2.md +68 -68
- package/src/.agents/skills/systematic-debugging/test-pressure-3.md +69 -69
- package/src/.agents/skills/typescript-best-practices/SKILL.md +373 -373
- package/src/.agents/skills/ui-ux-pro-custom/SKILL.md +348 -348
- package/src/.agents/skills/ui-ux-pro-custom/data/charts.csv +26 -26
- package/src/.agents/skills/ui-ux-pro-custom/data/colors.csv +97 -97
- package/src/.agents/skills/ui-ux-pro-custom/data/icons.csv +101 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/SKILL.md +106 -106
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/accessibility.md +475 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/animation.md +466 -466
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/composition-locals.md +231 -231
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/deprecated-patterns.md +323 -323
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/lists-scrolling.md +400 -400
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/modifiers.md +331 -331
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/navigation.md +416 -416
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/performance.md +446 -446
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/side-effects.md +516 -516
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/foundation-source.md +13327 -13327
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/material3-source.md +19097 -19097
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/navigation-source.md +2947 -2947
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/runtime-source.md +11316 -11316
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/source-code/ui-source.md +7896 -7896
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/state-management.md +377 -377
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/styles-experimental.md +470 -470
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/theming-material3.md +349 -349
- package/src/.agents/skills/ui-ux-pro-custom/data/jetpack-compose-expert-skill/references/view-composition.md +595 -595
- package/src/.agents/skills/ui-ux-pro-custom/data/landing.csv +31 -31
- package/src/.agents/skills/ui-ux-pro-custom/data/mobile-ui-layout.md +654 -654
- package/src/.agents/skills/ui-ux-pro-custom/data/products.csv +96 -96
- package/src/.agents/skills/ui-ux-pro-custom/data/react-performance.csv +45 -45
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/astro.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/flutter.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/html-tailwind.csv +56 -56
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/jetpack-compose.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nextjs.csv +53 -53
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nuxt-ui.csv +51 -51
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/nuxtjs.csv +59 -59
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/react-native.csv +56 -56
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/react.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/shadcn.csv +61 -61
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/svelte.csv +54 -54
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/swiftui.csv +51 -51
- package/src/.agents/skills/ui-ux-pro-custom/data/stacks/vue.csv +50 -50
- package/src/.agents/skills/ui-ux-pro-custom/data/styles.csv +68 -68
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/alarmkit/SKILL.md +438 -438
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/alarmkit/references/alarmkit-patterns.md +584 -584
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-clips/SKILL.md +436 -436
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-intents/SKILL.md +489 -489
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-intents/references/appintents-advanced.md +1076 -1076
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/SKILL.md +340 -340
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/references/privacy-manifest.md +90 -90
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/app-store-review/references/review-checklists.md +106 -106
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/coreml-conversion.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/coreml-optimization.md +344 -344
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/foundation-models.md +508 -508
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/apple-on-device-ai/references/mlx-swift.md +285 -285
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/authentication/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/authentication/references/keychain-biometric.md +211 -211
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/background-processing/SKILL.md +499 -499
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/background-processing/references/background-task-patterns.md +390 -390
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/callkit-voip/SKILL.md +461 -461
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/callkit-voip/references/callkit-patterns.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/cloudkit-sync/SKILL.md +492 -492
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/cloudkit-sync/references/cloudkit-patterns.md +461 -461
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/codable-patterns/SKILL.md +467 -467
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/contacts-framework/SKILL.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/contacts-framework/references/contacts-patterns.md +409 -409
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-bluetooth/SKILL.md +491 -491
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-bluetooth/references/ble-patterns.md +435 -435
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-motion/SKILL.md +388 -388
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-motion/references/motion-patterns.md +405 -405
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-nfc/SKILL.md +495 -495
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/core-nfc/references/nfc-patterns.md +420 -420
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/coreml/SKILL.md +459 -459
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/coreml/references/coreml-swift-integration.md +765 -765
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/SKILL.md +422 -422
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/references/instruments-guide.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/debugging-instruments/references/lldb-patterns.md +298 -298
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/device-integrity/SKILL.md +477 -477
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/energykit/SKILL.md +460 -460
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/energykit/references/energykit-patterns.md +541 -541
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/eventkit-calendar/SKILL.md +483 -483
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/eventkit-calendar/references/eventkit-patterns.md +326 -326
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/healthkit/SKILL.md +498 -498
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/healthkit/references/healthkit-patterns.md +602 -602
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/homekit-matter/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/homekit-matter/references/matter-commissioning.md +455 -455
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-accessibility/SKILL.md +301 -301
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-accessibility/references/a11y-patterns.md +140 -140
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/SKILL.md +418 -418
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/references/formatstyle-locale.md +627 -627
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-localization/references/string-catalogs.md +462 -462
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/SKILL.md +441 -441
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/background-websocket.md +862 -862
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/lightweight-clients.md +93 -93
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/network-framework.md +563 -563
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-networking/references/urlsession-patterns.md +1116 -1116
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/SKILL.md +496 -496
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/app-review-guidelines.md +174 -174
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/cryptokit-advanced.md +296 -296
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/file-storage-patterns.md +354 -354
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/ios-security/references/privacy-manifest.md +117 -117
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/live-activities/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/live-activities/references/live-activity-patterns.md +868 -868
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/SKILL.md +485 -485
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/references/corelocation-patterns.md +730 -730
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/mapkit-location/references/mapkit-patterns.md +748 -748
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/metrickit-diagnostics/SKILL.md +479 -479
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/musickit-audio/SKILL.md +395 -395
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/musickit-audio/references/musickit-patterns.md +363 -363
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/natural-language/SKILL.md +412 -412
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/natural-language/references/translation-patterns.md +311 -311
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/passkit-wallet/SKILL.md +398 -398
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/passkit-wallet/references/wallet-passes.md +254 -254
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/SKILL.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/references/paperkit-integration.md +376 -376
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/pencilkit-drawing/references/pencilkit-patterns.md +302 -302
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/permissionkit/SKILL.md +446 -446
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/permissionkit/references/permissionkit-patterns.md +435 -435
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/av-playback.md +701 -701
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/camera-capture.md +774 -774
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/image-loading-caching.md +869 -869
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/photos-camera-media/references/photospicker-patterns.md +597 -597
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/SKILL.md +500 -500
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/references/notification-patterns.md +677 -677
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/push-notifications/references/rich-notifications.md +745 -745
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/realitykit-ar/SKILL.md +479 -479
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/realitykit-ar/references/realitykit-patterns.md +480 -480
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/shareplay-activities/SKILL.md +483 -483
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/shareplay-activities/references/shareplay-patterns.md +544 -544
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/speech-recognition/SKILL.md +485 -485
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/SKILL.md +478 -478
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/references/app-review-guidelines.md +58 -58
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/storekit/references/storekit-advanced.md +755 -755
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-charts/SKILL.md +487 -487
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-charts/references/charts-patterns.md +895 -895
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/SKILL.md +408 -408
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/approachable-concurrency.md +80 -80
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/swift-6-2-concurrency.md +233 -233
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/swiftui-concurrency.md +187 -187
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-concurrency/references/synchronization-primitives.md +341 -341
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-language/SKILL.md +498 -498
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-language/references/swift-patterns-extended.md +505 -505
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-testing/SKILL.md +467 -467
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swift-testing/references/testing-patterns.md +504 -504
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/SKILL.md +334 -334
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/core-data-coexistence.md +504 -504
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/swiftdata-advanced.md +975 -975
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftdata/references/swiftdata-queries.md +675 -675
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/SKILL.md +481 -481
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/references/animation-advanced.md +804 -804
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-animation/references/core-animation-bridge.md +553 -553
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-gestures/SKILL.md +450 -450
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-gestures/references/gesture-patterns.md +425 -425
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/SKILL.md +336 -336
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/form.md +97 -97
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/grids.md +69 -69
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/list.md +99 -99
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-layout-components/references/scrollview.md +147 -147
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-liquid-glass/SKILL.md +325 -325
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-liquid-glass/references/liquid-glass.md +387 -387
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/SKILL.md +262 -262
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/deeplinks.md +207 -207
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/navigationstack.md +177 -177
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/sheets.md +169 -169
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-navigation/references/tabview.md +178 -178
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/SKILL.md +381 -381
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/architecture-patterns.md +486 -486
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/deprecated-migration.md +1097 -1097
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/design-polish.md +780 -780
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-patterns/references/platform-and-sharing.md +696 -696
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/SKILL.md +491 -491
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +46 -46
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +29 -29
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/understanding-hangs-in-your-app.md +33 -33
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-performance/references/understanding-improving-swiftui-performance.md +52 -52
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/SKILL.md +428 -428
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/references/hosting-migration.md +534 -534
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/swiftui-uikit-interop/references/representable-recipes.md +1133 -1133
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/tipkit/SKILL.md +494 -494
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/tipkit/references/tipkit-patterns.md +782 -782
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/SKILL.md +475 -475
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/vision-requests.md +736 -736
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/vision-framework/references/visionkit-scanner.md +738 -738
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/SKILL.md +410 -410
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/weatherkit/references/weatherkit-patterns.md +567 -567
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/SKILL.md +497 -497
- package/src/.agents/skills/ui-ux-pro-custom/data/swift-ios-skills/widgetkit/references/widgetkit-advanced.md +871 -871
- package/src/.agents/skills/ui-ux-pro-custom/data/typography.csv +57 -57
- package/src/.agents/skills/ui-ux-pro-custom/data/ui-reasoning.csv +101 -101
- package/src/.agents/skills/ui-ux-pro-custom/data/ux-guidelines.csv +99 -99
- package/src/.agents/skills/ui-ux-pro-custom/data/web-interface.csv +31 -31
- package/src/.agents/skills/ui-ux-pro-custom/scripts/core.py +253 -253
- package/src/.agents/skills/ui-ux-pro-custom/scripts/design_system.py +1067 -1067
- package/src/.agents/skills/ui-ux-pro-custom/scripts/search.py +114 -114
- package/src/.agents/skills/ux-audit/SKILL.md +150 -150
- package/src/.agents/skills/websocket-engineer/SKILL.md +168 -168
- package/src/.agents/skills/websocket-engineer/references/alternatives.md +391 -391
- package/src/.agents/skills/websocket-engineer/references/patterns.md +400 -400
- package/src/.agents/skills/websocket-engineer/references/protocol.md +195 -195
- package/src/.agents/skills/websocket-engineer/references/scaling.md +333 -333
- package/src/.agents/skills/websocket-engineer/references/security.md +474 -474
- package/src/.agents/skills/writing-skills/SKILL.md +655 -655
- package/src/.agents/skills/writing-skills/anthropic-best-practices.md +1150 -1150
- package/src/.agents/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -189
- package/src/.agents/skills/writing-skills/graphviz-conventions.dot +171 -171
- package/src/.agents/skills/writing-skills/persuasion-principles.md +187 -187
- package/src/.agents/skills/writing-skills/render-graphs.js +168 -168
- package/src/.agents/skills/writing-skills/testing-skills-with-subagents.md +384 -384
- package/src/.claude/commands/master-orchestrator.md +15 -0
- package/src/_memory/config.yaml +11 -11
- package/src/_memory/master-orchestrator-sidecar/instructions.md +85 -32
- package/src/_memory/skills/nimbalyst-tracking/SKILL.md +103 -103
- package/src/_memory/skills/writing-skills/SKILL.md +655 -655
- package/src/bmb/agents/agent-builder.md +59 -59
- package/src/bmb/agents/module-builder.md +60 -60
- package/src/bmb/agents/workflow-builder.md +61 -61
- package/src/bmb/config.yaml +12 -12
- package/src/bmb/module-help.csv +13 -13
- package/src/bmb/workflows/agent/data/agent-architecture.md +258 -258
- package/src/bmb/workflows/agent/data/agent-compilation.md +185 -185
- package/src/bmb/workflows/agent/data/agent-menu-patterns.md +189 -189
- package/src/bmb/workflows/agent/data/agent-metadata.md +133 -133
- package/src/bmb/workflows/agent/data/agent-validation.md +111 -111
- package/src/bmb/workflows/agent/data/brainstorm-context.md +96 -96
- package/src/bmb/workflows/agent/data/communication-presets.csv +61 -61
- package/src/bmb/workflows/agent/data/critical-actions.md +75 -75
- package/src/bmb/workflows/agent/data/persona-properties.md +252 -252
- package/src/bmb/workflows/agent/data/principles-crafting.md +142 -142
- package/src/bmb/workflows/agent/data/reference/module-examples/architect.md +68 -68
- package/src/bmb/workflows/agent/data/reference/with-sidecar/journal-keeper/journal-keeper-sidecar/entries/yy-mm-dd-entry-template.md +16 -16
- package/src/bmb/workflows/agent/data/understanding-agent-types.md +126 -126
- package/src/bmb/workflows/agent/steps-c/step-01-brainstorm.md +129 -129
- package/src/bmb/workflows/agent/steps-c/step-02-discovery.md +170 -170
- package/src/bmb/workflows/agent/steps-c/step-03-sidecar-metadata.md +309 -309
- package/src/bmb/workflows/agent/steps-c/step-04-persona.md +213 -213
- package/src/bmb/workflows/agent/steps-c/step-05-commands-menu.md +179 -179
- package/src/bmb/workflows/agent/steps-c/step-06-activation.md +278 -278
- package/src/bmb/workflows/agent/steps-c/step-07-build-agent.md +316 -316
- package/src/bmb/workflows/agent/steps-c/step-08-celebrate.md +247 -247
- package/src/bmb/workflows/agent/steps-e/e-01-load-existing.md +221 -221
- package/src/bmb/workflows/agent/steps-e/e-02-discover-edits.md +195 -195
- package/src/bmb/workflows/agent/steps-e/e-04-sidecar-metadata.md +126 -126
- package/src/bmb/workflows/agent/steps-e/e-05-persona.md +135 -135
- package/src/bmb/workflows/agent/steps-e/e-06-commands-menu.md +123 -123
- package/src/bmb/workflows/agent/steps-e/e-07-activation.md +124 -124
- package/src/bmb/workflows/agent/steps-e/e-08-edit-agent.md +197 -197
- package/src/bmb/workflows/agent/steps-e/e-09-celebrate.md +155 -155
- package/src/bmb/workflows/agent/steps-v/v-01-load-review.md +137 -137
- package/src/bmb/workflows/agent/steps-v/v-02a-validate-metadata.md +116 -116
- package/src/bmb/workflows/agent/steps-v/v-02b-validate-persona.md +124 -124
- package/src/bmb/workflows/agent/steps-v/v-02c-validate-menu.md +127 -127
- package/src/bmb/workflows/agent/steps-v/v-02d-validate-structure.md +134 -134
- package/src/bmb/workflows/agent/steps-v/v-02e-validate-sidecar.md +134 -134
- package/src/bmb/workflows/agent/steps-v/v-03-summary.md +104 -104
- package/src/bmb/workflows/agent/templates/agent-plan.template.md +5 -5
- package/src/bmb/workflows/agent/templates/agent-template.md +89 -89
- package/src/bmb/workflows/agent/workflow-create-agent.md +72 -72
- package/src/bmb/workflows/agent/workflow-edit-agent.md +75 -75
- package/src/bmb/workflows/agent/workflow-validate-agent.md +73 -73
- package/src/bmb/workflows/module/data/agent-architecture.md +179 -179
- package/src/bmb/workflows/module/data/agent-spec-template.md +79 -79
- package/src/bmb/workflows/module/data/module-standards.md +263 -263
- package/src/bmb/workflows/module/data/module-yaml-conventions.md +392 -392
- package/src/bmb/workflows/module/module-help-generate.md +254 -254
- package/src/bmb/workflows/module/steps-b/step-01-welcome.md +148 -148
- package/src/bmb/workflows/module/steps-b/step-02-spark.md +141 -141
- package/src/bmb/workflows/module/steps-b/step-03-module-type.md +149 -149
- package/src/bmb/workflows/module/steps-b/step-04-vision.md +83 -83
- package/src/bmb/workflows/module/steps-b/step-05-identity.md +97 -97
- package/src/bmb/workflows/module/steps-b/step-06-users.md +86 -86
- package/src/bmb/workflows/module/steps-b/step-07-value.md +76 -76
- package/src/bmb/workflows/module/steps-b/step-08-agents.md +97 -97
- package/src/bmb/workflows/module/steps-b/step-09-workflows.md +83 -83
- package/src/bmb/workflows/module/steps-b/step-10-tools.md +91 -91
- package/src/bmb/workflows/module/steps-b/step-11-scenarios.md +84 -84
- package/src/bmb/workflows/module/steps-b/step-12-creative.md +95 -95
- package/src/bmb/workflows/module/steps-b/step-13-review.md +105 -105
- package/src/bmb/workflows/module/steps-b/step-14-finalize.md +117 -117
- package/src/bmb/workflows/module/steps-c/step-01-load-brief.md +179 -179
- package/src/bmb/workflows/module/steps-c/step-01b-continue.md +82 -82
- package/src/bmb/workflows/module/steps-c/step-02-structure.md +105 -105
- package/src/bmb/workflows/module/steps-c/step-03-config.md +119 -119
- package/src/bmb/workflows/module/steps-c/step-04-agents.md +168 -168
- package/src/bmb/workflows/module/steps-c/step-05-workflows.md +184 -184
- package/src/bmb/workflows/module/steps-c/step-06-docs.md +401 -401
- package/src/bmb/workflows/module/steps-c/step-07-complete.md +152 -152
- package/src/bmb/workflows/module/steps-e/step-01-load-target.md +81 -81
- package/src/bmb/workflows/module/steps-e/step-02-select-edit.md +77 -77
- package/src/bmb/workflows/module/steps-e/step-03-apply-edit.md +77 -77
- package/src/bmb/workflows/module/steps-e/step-04-review.md +80 -80
- package/src/bmb/workflows/module/steps-e/step-05-confirm.md +75 -75
- package/src/bmb/workflows/module/steps-v/step-01-load-target.md +96 -96
- package/src/bmb/workflows/module/steps-v/step-02-file-structure.md +93 -93
- package/src/bmb/workflows/module/steps-v/step-03-module-yaml.md +99 -99
- package/src/bmb/workflows/module/steps-v/step-04-agent-specs.md +152 -152
- package/src/bmb/workflows/module/steps-v/step-05-workflow-specs.md +152 -152
- package/src/bmb/workflows/module/steps-v/step-06-documentation.md +143 -143
- package/src/bmb/workflows/module/steps-v/step-07-installation.md +102 -102
- package/src/bmb/workflows/module/steps-v/step-08-report.md +197 -197
- package/src/bmb/workflows/module/templates/brief-template.md +154 -154
- package/src/bmb/workflows/module/templates/workflow-spec-template.md +96 -96
- package/src/bmb/workflows/module/workflow-create-module-brief.md +71 -71
- package/src/bmb/workflows/module/workflow-create-module.md +86 -86
- package/src/bmb/workflows/module/workflow-edit-module.md +66 -66
- package/src/bmb/workflows/module/workflow-validate-module.md +66 -66
- package/src/bmb/workflows/workflow/data/architecture.md +150 -150
- package/src/bmb/workflows/workflow/data/common-workflow-tools.csv +19 -19
- package/src/bmb/workflows/workflow/data/csv-data-file-standards.md +53 -53
- package/src/bmb/workflows/workflow/data/frontmatter-standards.md +184 -184
- package/src/bmb/workflows/workflow/data/input-discovery-standards.md +191 -191
- package/src/bmb/workflows/workflow/data/intent-vs-prescriptive-spectrum.md +44 -44
- package/src/bmb/workflows/workflow/data/menu-handling-standards.md +133 -133
- package/src/bmb/workflows/workflow/data/output-format-standards.md +135 -135
- package/src/bmb/workflows/workflow/data/step-file-rules.md +235 -235
- package/src/bmb/workflows/workflow/data/step-type-patterns.md +257 -257
- package/src/bmb/workflows/workflow/data/subprocess-optimization-patterns.md +188 -188
- package/src/bmb/workflows/workflow/data/trimodal-workflow-structure.md +164 -164
- package/src/bmb/workflows/workflow/data/workflow-chaining-standards.md +222 -222
- package/src/bmb/workflows/workflow/data/workflow-examples.md +232 -232
- package/src/bmb/workflows/workflow/data/workflow-type-criteria.md +134 -134
- package/src/bmb/workflows/workflow/steps-c/step-00-conversion.md +263 -263
- package/src/bmb/workflows/workflow/steps-c/step-01-discovery.md +194 -194
- package/src/bmb/workflows/workflow/steps-c/step-01b-continuation.md +3 -3
- package/src/bmb/workflows/workflow/steps-c/step-02-classification.md +270 -270
- package/src/bmb/workflows/workflow/steps-c/step-03-requirements.md +283 -283
- package/src/bmb/workflows/workflow/steps-c/step-04-tools.md +282 -282
- package/src/bmb/workflows/workflow/steps-c/step-05-plan-review.md +243 -243
- package/src/bmb/workflows/workflow/steps-c/step-06-design.md +330 -330
- package/src/bmb/workflows/workflow/steps-c/step-07-foundation.md +239 -239
- package/src/bmb/workflows/workflow/steps-c/step-08-build-step-01.md +379 -379
- package/src/bmb/workflows/workflow/steps-c/step-09-build-next-step.md +350 -350
- package/src/bmb/workflows/workflow/steps-c/step-10-confirmation.md +322 -322
- package/src/bmb/workflows/workflow/steps-c/step-11-completion.md +191 -191
- package/src/bmb/workflows/workflow/steps-e/step-e-01-assess-workflow.md +237 -237
- package/src/bmb/workflows/workflow/steps-e/step-e-02-discover-edits.md +251 -251
- package/src/bmb/workflows/workflow/steps-e/step-e-03-fix-validation.md +254 -254
- package/src/bmb/workflows/workflow/steps-e/step-e-04-direct-edit.md +277 -277
- package/src/bmb/workflows/workflow/steps-e/step-e-05-apply-edit.md +154 -154
- package/src/bmb/workflows/workflow/steps-e/step-e-06-validate-after.md +190 -190
- package/src/bmb/workflows/workflow/steps-e/step-e-07-complete.md +206 -206
- package/src/bmb/workflows/workflow/steps-v/step-01-validate-max-mode.md +109 -109
- package/src/bmb/workflows/workflow/steps-v/step-01-validate.md +221 -221
- package/src/bmb/workflows/workflow/steps-v/step-01b-structure.md +152 -152
- package/src/bmb/workflows/workflow/steps-v/step-02-frontmatter-validation.md +199 -199
- package/src/bmb/workflows/workflow/steps-v/step-02b-path-violations.md +265 -265
- package/src/bmb/workflows/workflow/steps-v/step-03-menu-validation.md +164 -164
- package/src/bmb/workflows/workflow/steps-v/step-04-step-type-validation.md +211 -211
- package/src/bmb/workflows/workflow/steps-v/step-05-output-format-validation.md +200 -200
- package/src/bmb/workflows/workflow/steps-v/step-06-validation-design-check.md +195 -195
- package/src/bmb/workflows/workflow/steps-v/step-07-instruction-style-check.md +209 -209
- package/src/bmb/workflows/workflow/steps-v/step-08-collaborative-experience-check.md +199 -199
- package/src/bmb/workflows/workflow/steps-v/step-08b-subprocess-optimization.md +179 -179
- package/src/bmb/workflows/workflow/steps-v/step-09-cohesive-review.md +186 -186
- package/src/bmb/workflows/workflow/steps-v/step-10-report-complete.md +154 -154
- package/src/bmb/workflows/workflow/steps-v/step-11-plan-validation.md +237 -237
- package/src/bmb/workflows/workflow/templates/minimal-output-template.md +11 -11
- package/src/bmb/workflows/workflow/templates/step-01-init-continuable-template.md +241 -241
- package/src/bmb/workflows/workflow/templates/step-1b-template.md +224 -224
- package/src/bmb/workflows/workflow/templates/step-template.md +294 -294
- package/src/bmb/workflows/workflow/templates/workflow-template.md +102 -102
- package/src/bmb/workflows/workflow/workflow-create-workflow.md +79 -79
- package/src/bmb/workflows/workflow/workflow-edit-workflow.md +65 -65
- package/src/bmb/workflows/workflow/workflow-rework-workflow.md +65 -65
- package/src/bmb/workflows/workflow/workflow-validate-max-parallel-workflow.md +66 -66
- package/src/bmb/workflows/workflow/workflow-validate-workflow.md +65 -65
- package/src/bmm/agents/analyst.md +104 -104
- package/src/bmm/agents/dev.md +100 -100
- package/src/bmm/agents/qa.md +100 -90
- package/src/bmm/agents/tech-writer/tech-writer.md +94 -94
- package/src/bmm/module-help.csv +31 -31
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01-init.md +115 -115
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01b-continue.md +107 -107
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +141 -141
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +144 -144
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +147 -147
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +161 -161
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +99 -99
- package/src/bmm/workflows/1-analysis/create-product-brief/workflow.md +57 -57
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-01-init.md +87 -87
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-02-domain-analysis.md +156 -156
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-03-competitive-landscape.md +165 -165
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-04-regulatory-focus.md +140 -140
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-05-technical-trends.md +152 -152
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-06-research-synthesis.md +345 -345
- package/src/bmm/workflows/1-analysis/research/market-steps/step-01-init.md +92 -92
- package/src/bmm/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +164 -164
- package/src/bmm/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +174 -174
- package/src/bmm/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +184 -184
- package/src/bmm/workflows/1-analysis/research/market-steps/step-05-competitive-analysis.md +105 -105
- package/src/bmm/workflows/1-analysis/research/market-steps/step-06-research-completion.md +360 -360
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-01-init.md +87 -87
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-02-technical-overview.md +165 -165
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-03-integration-patterns.md +174 -174
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-04-architectural-patterns.md +141 -141
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-05-implementation-research.md +159 -159
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-06-research-synthesis.md +387 -387
- package/src/bmm/workflows/1-analysis/research/workflow-domain-research.md +54 -54
- package/src/bmm/workflows/1-analysis/research/workflow-market-research.md +54 -54
- package/src/bmm/workflows/1-analysis/research/workflow-technical-research.md +54 -54
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-01b-continue.md +100 -100
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02-discovery.md +160 -160
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02b-vision.md +88 -88
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02c-executive-summary.md +99 -99
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md +169 -169
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +156 -156
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +136 -136
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +176 -176
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-07-project-type.md +184 -184
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-08-scoping.md +174 -174
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md +175 -175
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-10-nonfunctional.md +189 -189
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-11-polish.md +162 -162
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-12-complete.md +79 -79
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +183 -183
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md +149 -149
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md +187 -187
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md +192 -192
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-04-complete.md +108 -108
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +166 -166
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md +131 -131
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md +150 -150
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md +118 -118
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md +155 -155
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md +170 -170
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md +158 -158
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md +147 -147
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md +182 -182
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md +202 -202
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +148 -148
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +201 -201
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md +179 -179
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +164 -164
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-create-prd.md +65 -65
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-edit-prd.md +65 -65
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +63 -63
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01b-continue.md +63 -63
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +106 -106
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +111 -111
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +115 -115
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +127 -127
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +167 -167
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +143 -143
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +118 -118
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +154 -154
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +136 -136
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +165 -165
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +135 -135
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +192 -192
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +101 -101
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +45 -45
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-01-document-discovery.md +185 -185
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-02-prd-analysis.md +129 -129
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-03-epic-coverage-validation.md +130 -130
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-04-ux-alignment.md +93 -93
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-05-epic-quality-review.md +196 -196
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +129 -129
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/workflow.md +54 -54
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-01b-continue.md +82 -82
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +106 -106
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +138 -138
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +129 -129
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +166 -166
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +186 -186
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +163 -163
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +38 -38
- package/src/bmm/workflows/3-solutioning/create-architecture/workflow.md +49 -49
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +124 -124
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +122 -122
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +84 -84
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +58 -58
- package/src/bmm/workflows/4-implementation/code-review/workflow.yaml +43 -43
- package/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +53 -53
- package/src/bmm/workflows/4-implementation/create-story/checklist.md +159 -159
- package/src/bmm/workflows/4-implementation/create-story/template.md +79 -79
- package/src/bmm/workflows/4-implementation/create-story/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +20 -20
- package/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +52 -52
- package/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +25 -25
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-01-mode-detection.md +158 -158
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-02-context-gathering.md +122 -122
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-03-execute.md +93 -93
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-04-self-check.md +93 -93
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-05-adversarial-review.md +87 -87
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-06-resolve-findings.md +146 -146
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +50 -50
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-02-investigate.md +152 -152
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-03-generate.md +123 -123
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +201 -201
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +79 -79
- package/src/bmm/workflows/document-project/workflow.yaml +22 -22
- package/src/bmm/workflows/generate-project-context/steps/step-01-discover.md +184 -184
- package/src/bmm/workflows/generate-project-context/steps/step-02-generate.md +322 -322
- package/src/bmm/workflows/generate-project-context/steps/step-03-complete.md +235 -235
- package/src/bmm/workflows/generate-project-context/workflow.md +49 -49
- package/src/bmm/workflows/qa/automate/workflow.yaml +233 -233
- package/src/bmm/workflows/qa-generate-e2e-tests/workflow.yaml +42 -42
- package/src/core/config.yaml +9 -9
- package/src/core/module-help.csv +10 -10
- package/src/core/scripts/generate-loop-report.py +72 -72
- package/src/core/tasks/editorial-review-prose.xml +101 -101
- package/src/core/tasks/editorial-review-structure.xml +207 -207
- package/src/core/tasks/help.md +86 -86
- package/src/core/tasks/index-docs.xml +64 -64
- package/src/core/tasks/review-adversarial-general.xml +66 -66
- package/src/core/tasks/review-adversarial-loop.xml +46 -46
- package/src/core/tasks/review-edge-case-hunter.xml +63 -63
- package/src/core/tasks/review-party-loop.xml +46 -46
- package/src/core/tasks/shard-doc.xml +107 -107
- package/src/core/tasks/workflow.xml +235 -235
- package/src/core/templates/review-loop-report.html +88 -88
- package/src/core/templates/review-loop-report.md +5 -5
- package/src/core/workflows/advanced-elicitation/workflow.xml +117 -117
- package/src/core/workflows/brainstorming/steps/step-01-session-setup.md +212 -212
- package/src/core/workflows/brainstorming/steps/step-01b-continue.md +122 -122
- package/src/core/workflows/brainstorming/steps/step-02a-user-selected.md +225 -225
- package/src/core/workflows/brainstorming/steps/step-02b-ai-recommended.md +237 -237
- package/src/core/workflows/brainstorming/steps/step-02c-random-selection.md +209 -209
- package/src/core/workflows/brainstorming/steps/step-02d-progressive-flow.md +264 -264
- package/src/core/workflows/brainstorming/steps/step-02e-deep-dive.md +68 -68
- package/src/core/workflows/brainstorming/steps/step-03-technique-execution.md +403 -403
- package/src/core/workflows/brainstorming/steps/step-04-idea-organization.md +303 -303
- package/src/core/workflows/brainstorming/workflow.md +60 -60
- package/src/core/workflows/extract-trackers/workflow.md +45 -45
- package/src/core/workflows/party-mode/steps/step-01-agent-loading.md +142 -142
- package/src/core/workflows/party-mode/workflow.md +194 -194
- package/src/docs/dev/tmux/actions_popup.py +291 -291
- package/src/docs/dev/tmux/tmux-setup.md +62 -1
|
@@ -1,461 +1,461 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: callkit-voip
|
|
3
|
-
description: "Implement VoIP calling with CallKit and PushKit. Use when building incoming/outgoing call flows, registering for VoIP push notifications, configuring CXProvider and CXCallController, handling call actions, coordinating audio sessions, or creating Call Directory extensions for caller ID and call blocking."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# CallKit + PushKit VoIP
|
|
7
|
-
|
|
8
|
-
Build VoIP calling features that integrate with the native iOS call UI using
|
|
9
|
-
CallKit and PushKit. Covers incoming/outgoing call flows, VoIP push
|
|
10
|
-
registration, audio session coordination, and call directory extensions.
|
|
11
|
-
Targets Swift 6.2 / iOS 26+.
|
|
12
|
-
|
|
13
|
-
## Contents
|
|
14
|
-
|
|
15
|
-
- [Setup](#setup)
|
|
16
|
-
- [Provider Configuration](#provider-configuration)
|
|
17
|
-
- [Incoming Call Flow](#incoming-call-flow)
|
|
18
|
-
- [Outgoing Call Flow](#outgoing-call-flow)
|
|
19
|
-
- [PushKit VoIP Registration](#pushkit-voip-registration)
|
|
20
|
-
- [Audio Session Coordination](#audio-session-coordination)
|
|
21
|
-
- [Call Directory Extension](#call-directory-extension)
|
|
22
|
-
- [Common Mistakes](#common-mistakes)
|
|
23
|
-
- [Review Checklist](#review-checklist)
|
|
24
|
-
- [References](#references)
|
|
25
|
-
|
|
26
|
-
## Setup
|
|
27
|
-
|
|
28
|
-
### Project Configuration
|
|
29
|
-
|
|
30
|
-
1. Enable the **Voice over IP** background mode in Signing & Capabilities
|
|
31
|
-
2. Add the **Push Notifications** capability
|
|
32
|
-
3. For call directory extensions, add a **Call Directory Extension** target
|
|
33
|
-
|
|
34
|
-
### Key Types
|
|
35
|
-
|
|
36
|
-
| Type | Role |
|
|
37
|
-
|---|---|
|
|
38
|
-
| `CXProvider` | Reports calls to the system, receives call actions |
|
|
39
|
-
| `CXCallController` | Requests call actions (start, end, hold, mute) |
|
|
40
|
-
| `CXCallUpdate` | Describes call metadata (caller name, video, handle) |
|
|
41
|
-
| `CXProviderDelegate` | Handles system call actions and audio session events |
|
|
42
|
-
| `PKPushRegistry` | Registers for and receives VoIP push notifications |
|
|
43
|
-
|
|
44
|
-
## Provider Configuration
|
|
45
|
-
|
|
46
|
-
Create a single `CXProvider` at app launch and keep it alive for the app
|
|
47
|
-
lifetime. Configure it with a `CXProviderConfiguration` that describes your
|
|
48
|
-
calling capabilities.
|
|
49
|
-
|
|
50
|
-
```swift
|
|
51
|
-
import CallKit
|
|
52
|
-
|
|
53
|
-
/// CXProvider dispatches all delegate calls to the queue passed to `setDelegate(_:queue:)`.
|
|
54
|
-
/// The `let` properties are initialized once and never mutated, making this type
|
|
55
|
-
/// safe to share across concurrency domains despite @unchecked Sendable.
|
|
56
|
-
final class CallManager: NSObject, @unchecked Sendable {
|
|
57
|
-
static let shared = CallManager()
|
|
58
|
-
|
|
59
|
-
let provider: CXProvider
|
|
60
|
-
let callController = CXCallController()
|
|
61
|
-
|
|
62
|
-
private override init() {
|
|
63
|
-
let config = CXProviderConfiguration()
|
|
64
|
-
config.localizedName = "My VoIP App"
|
|
65
|
-
config.supportsVideo = true
|
|
66
|
-
config.maximumCallsPerCallGroup = 1
|
|
67
|
-
config.maximumCallGroups = 2
|
|
68
|
-
config.supportedHandleTypes = [.phoneNumber, .emailAddress]
|
|
69
|
-
config.includesCallsInRecents = true
|
|
70
|
-
|
|
71
|
-
provider = CXProvider(configuration: config)
|
|
72
|
-
super.init()
|
|
73
|
-
provider.setDelegate(self, queue: nil)
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## Incoming Call Flow
|
|
79
|
-
|
|
80
|
-
When a VoIP push arrives, report the incoming call to CallKit immediately.
|
|
81
|
-
The system displays the native call UI. You must report the call before the
|
|
82
|
-
PushKit completion handler returns -- failure to do so causes the system to
|
|
83
|
-
terminate your app.
|
|
84
|
-
|
|
85
|
-
```swift
|
|
86
|
-
func reportIncomingCall(
|
|
87
|
-
uuid: UUID,
|
|
88
|
-
handle: String,
|
|
89
|
-
hasVideo: Bool
|
|
90
|
-
) async throws {
|
|
91
|
-
let update = CXCallUpdate()
|
|
92
|
-
update.remoteHandle = CXHandle(type: .phoneNumber, value: handle)
|
|
93
|
-
update.hasVideo = hasVideo
|
|
94
|
-
update.localizedCallerName = "Jane Doe"
|
|
95
|
-
|
|
96
|
-
try await withCheckedThrowingContinuation {
|
|
97
|
-
(continuation: CheckedContinuation<Void, Error>) in
|
|
98
|
-
provider.reportNewIncomingCall(
|
|
99
|
-
with: uuid,
|
|
100
|
-
update: update
|
|
101
|
-
) { error in
|
|
102
|
-
if let error {
|
|
103
|
-
continuation.resume(throwing: error)
|
|
104
|
-
} else {
|
|
105
|
-
continuation.resume()
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Handling the Answer Action
|
|
113
|
-
|
|
114
|
-
Implement `CXProviderDelegate` to respond when the user answers:
|
|
115
|
-
|
|
116
|
-
```swift
|
|
117
|
-
extension CallManager: CXProviderDelegate {
|
|
118
|
-
func providerDidReset(_ provider: CXProvider) {
|
|
119
|
-
// End all calls, reset audio
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
|
123
|
-
// Configure audio, connect to call server
|
|
124
|
-
configureAudioSession()
|
|
125
|
-
connectToCallServer(callUUID: action.callUUID)
|
|
126
|
-
action.fulfill()
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
|
|
130
|
-
disconnectFromCallServer(callUUID: action.callUUID)
|
|
131
|
-
action.fulfill()
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
## Outgoing Call Flow
|
|
137
|
-
|
|
138
|
-
Use `CXCallController` to request an outgoing call. The system routes the
|
|
139
|
-
request through your `CXProviderDelegate`.
|
|
140
|
-
|
|
141
|
-
```swift
|
|
142
|
-
func startOutgoingCall(handle: String, hasVideo: Bool) {
|
|
143
|
-
let uuid = UUID()
|
|
144
|
-
let handle = CXHandle(type: .phoneNumber, value: handle)
|
|
145
|
-
let startAction = CXStartCallAction(call: uuid, handle: handle)
|
|
146
|
-
startAction.isVideo = hasVideo
|
|
147
|
-
|
|
148
|
-
let transaction = CXTransaction(action: startAction)
|
|
149
|
-
callController.request(transaction) { error in
|
|
150
|
-
if let error {
|
|
151
|
-
print("Failed to start call: \(error)")
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### Delegate Methods for Outgoing Calls
|
|
158
|
-
|
|
159
|
-
```swift
|
|
160
|
-
extension CallManager {
|
|
161
|
-
func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
|
|
162
|
-
configureAudioSession()
|
|
163
|
-
// Begin connecting to server
|
|
164
|
-
provider.reportOutgoingCall(
|
|
165
|
-
with: action.callUUID,
|
|
166
|
-
startedConnectingAt: Date()
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
connectToServer(callUUID: action.callUUID) {
|
|
170
|
-
provider.reportOutgoingCall(
|
|
171
|
-
with: action.callUUID,
|
|
172
|
-
connectedAt: Date()
|
|
173
|
-
)
|
|
174
|
-
}
|
|
175
|
-
action.fulfill()
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
## PushKit VoIP Registration
|
|
181
|
-
|
|
182
|
-
Register for VoIP pushes at every app launch. Send the token to your server
|
|
183
|
-
whenever it changes.
|
|
184
|
-
|
|
185
|
-
```swift
|
|
186
|
-
import PushKit
|
|
187
|
-
|
|
188
|
-
final class PushManager: NSObject, PKPushRegistryDelegate {
|
|
189
|
-
let registry: PKPushRegistry
|
|
190
|
-
|
|
191
|
-
override init() {
|
|
192
|
-
registry = PKPushRegistry(queue: .main)
|
|
193
|
-
super.init()
|
|
194
|
-
registry.delegate = self
|
|
195
|
-
registry.desiredPushTypes = [.voIP]
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
func pushRegistry(
|
|
199
|
-
_ registry: PKPushRegistry,
|
|
200
|
-
didUpdate pushCredentials: PKPushCredentials,
|
|
201
|
-
for type: PKPushType
|
|
202
|
-
) {
|
|
203
|
-
let token = pushCredentials.token
|
|
204
|
-
.map { String(format: "%02x", $0) }
|
|
205
|
-
.joined()
|
|
206
|
-
// Send token to your server
|
|
207
|
-
sendTokenToServer(token)
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
func pushRegistry(
|
|
211
|
-
_ registry: PKPushRegistry,
|
|
212
|
-
didReceiveIncomingPushWith payload: PKPushPayload,
|
|
213
|
-
for type: PKPushType,
|
|
214
|
-
completion: @escaping () -> Void
|
|
215
|
-
) {
|
|
216
|
-
guard type == .voIP else {
|
|
217
|
-
completion()
|
|
218
|
-
return
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
let callUUID = UUID()
|
|
222
|
-
let handle = payload.dictionaryPayload["handle"] as? String ?? "Unknown"
|
|
223
|
-
|
|
224
|
-
Task {
|
|
225
|
-
do {
|
|
226
|
-
try await CallManager.shared.reportIncomingCall(
|
|
227
|
-
uuid: callUUID,
|
|
228
|
-
handle: handle,
|
|
229
|
-
hasVideo: false
|
|
230
|
-
)
|
|
231
|
-
} catch {
|
|
232
|
-
// Call was filtered by DND or block list
|
|
233
|
-
}
|
|
234
|
-
completion()
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
## Audio Session Coordination
|
|
241
|
-
|
|
242
|
-
CallKit manages audio session activation/deactivation. Configure your audio
|
|
243
|
-
session when CallKit tells you to, not before.
|
|
244
|
-
|
|
245
|
-
```swift
|
|
246
|
-
extension CallManager {
|
|
247
|
-
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
|
|
248
|
-
// Audio session is now active -- start audio engine / WebRTC
|
|
249
|
-
startAudioEngine()
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
|
|
253
|
-
// Audio session deactivated -- stop audio engine
|
|
254
|
-
stopAudioEngine()
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
func configureAudioSession() {
|
|
258
|
-
let session = AVAudioSession.sharedInstance()
|
|
259
|
-
do {
|
|
260
|
-
try session.setCategory(
|
|
261
|
-
.playAndRecord,
|
|
262
|
-
mode: .voiceChat,
|
|
263
|
-
options: [.allowBluetooth, .allowBluetoothA2DP]
|
|
264
|
-
)
|
|
265
|
-
} catch {
|
|
266
|
-
print("Audio session configuration failed: \(error)")
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
## Call Directory Extension
|
|
273
|
-
|
|
274
|
-
Create a Call Directory extension to provide caller ID and call blocking.
|
|
275
|
-
|
|
276
|
-
```swift
|
|
277
|
-
import CallKit
|
|
278
|
-
|
|
279
|
-
final class CallDirectoryHandler: CXCallDirectoryProvider {
|
|
280
|
-
override func beginRequest(
|
|
281
|
-
with context: CXCallDirectoryExtensionContext
|
|
282
|
-
) {
|
|
283
|
-
if context.isIncremental {
|
|
284
|
-
addOrRemoveIncrementalEntries(to: context)
|
|
285
|
-
} else {
|
|
286
|
-
addAllEntries(to: context)
|
|
287
|
-
}
|
|
288
|
-
context.completeRequest()
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
private func addAllEntries(
|
|
292
|
-
to context: CXCallDirectoryExtensionContext
|
|
293
|
-
) {
|
|
294
|
-
// Phone numbers must be in ascending order (E.164 format as Int64)
|
|
295
|
-
let blockedNumbers: [CXCallDirectoryPhoneNumber] = [
|
|
296
|
-
18005551234, 18005555678
|
|
297
|
-
]
|
|
298
|
-
for number in blockedNumbers {
|
|
299
|
-
context.addBlockingEntry(
|
|
300
|
-
withNextSequentialPhoneNumber: number
|
|
301
|
-
)
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
let identifiedNumbers: [(CXCallDirectoryPhoneNumber, String)] = [
|
|
305
|
-
(18005551111, "Local Pizza"),
|
|
306
|
-
(18005552222, "Dentist Office")
|
|
307
|
-
]
|
|
308
|
-
for (number, label) in identifiedNumbers {
|
|
309
|
-
context.addIdentificationEntry(
|
|
310
|
-
withNextSequentialPhoneNumber: number,
|
|
311
|
-
label: label
|
|
312
|
-
)
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
Reload the extension from the main app after data changes:
|
|
319
|
-
|
|
320
|
-
```swift
|
|
321
|
-
CXCallDirectoryManager.sharedInstance.reloadExtension(
|
|
322
|
-
withIdentifier: "com.example.app.CallDirectory"
|
|
323
|
-
) { error in
|
|
324
|
-
if let error { print("Reload failed: \(error)") }
|
|
325
|
-
}
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
## Common Mistakes
|
|
329
|
-
|
|
330
|
-
### DON'T: Fail to report a call on VoIP push receipt
|
|
331
|
-
|
|
332
|
-
If your PushKit delegate receives a VoIP push but does not call
|
|
333
|
-
`reportNewIncomingCall(with:update:completion:)`, iOS terminates your app and
|
|
334
|
-
may stop delivering pushes entirely.
|
|
335
|
-
|
|
336
|
-
```swift
|
|
337
|
-
// WRONG -- no call reported
|
|
338
|
-
func pushRegistry(
|
|
339
|
-
_ registry: PKPushRegistry,
|
|
340
|
-
didReceiveIncomingPushWith payload: PKPushPayload,
|
|
341
|
-
for type: PKPushType,
|
|
342
|
-
completion: @escaping () -> Void
|
|
343
|
-
) {
|
|
344
|
-
// Just process data, no call reported
|
|
345
|
-
processPayload(payload)
|
|
346
|
-
completion()
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// CORRECT -- always report a call
|
|
350
|
-
func pushRegistry(
|
|
351
|
-
_ registry: PKPushRegistry,
|
|
352
|
-
didReceiveIncomingPushWith payload: PKPushPayload,
|
|
353
|
-
for type: PKPushType,
|
|
354
|
-
completion: @escaping () -> Void
|
|
355
|
-
) {
|
|
356
|
-
let uuid = UUID()
|
|
357
|
-
provider.reportNewIncomingCall(
|
|
358
|
-
with: uuid, update: makeUpdate(from: payload)
|
|
359
|
-
) { _ in completion() }
|
|
360
|
-
}
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
### DON'T: Start audio before CallKit activates the session
|
|
364
|
-
|
|
365
|
-
Starting your audio engine before `provider(_:didActivate:)` causes silence
|
|
366
|
-
or immediate deactivation. CallKit manages session priority with the system.
|
|
367
|
-
|
|
368
|
-
```swift
|
|
369
|
-
// WRONG
|
|
370
|
-
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
|
371
|
-
startAudioEngine() // Too early -- session not active yet
|
|
372
|
-
action.fulfill()
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// CORRECT
|
|
376
|
-
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
|
377
|
-
prepareAudioEngine() // Prepare, but do not start
|
|
378
|
-
action.fulfill()
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
|
|
382
|
-
startAudioEngine() // Now it's safe
|
|
383
|
-
}
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
### DON'T: Forget to call action.fulfill() or action.fail()
|
|
387
|
-
|
|
388
|
-
Failing to fulfill or fail an action leaves the call in a limbo state and
|
|
389
|
-
triggers the timeout handler.
|
|
390
|
-
|
|
391
|
-
```swift
|
|
392
|
-
// WRONG
|
|
393
|
-
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
|
394
|
-
connectToServer()
|
|
395
|
-
// Forgot action.fulfill()
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// CORRECT
|
|
399
|
-
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
|
400
|
-
connectToServer()
|
|
401
|
-
action.fulfill()
|
|
402
|
-
}
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
### DON'T: Ignore push token refresh
|
|
406
|
-
|
|
407
|
-
The VoIP push token can change at any time. If your server has a stale token,
|
|
408
|
-
pushes silently fail and incoming calls never arrive.
|
|
409
|
-
|
|
410
|
-
```swift
|
|
411
|
-
// WRONG -- only send token once at first registration
|
|
412
|
-
func pushRegistry(
|
|
413
|
-
_ registry: PKPushRegistry,
|
|
414
|
-
didUpdate pushCredentials: PKPushCredentials,
|
|
415
|
-
for type: PKPushType
|
|
416
|
-
) {
|
|
417
|
-
// Token saved locally but never updated on server
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// CORRECT -- always update server
|
|
421
|
-
func pushRegistry(
|
|
422
|
-
_ registry: PKPushRegistry,
|
|
423
|
-
didUpdate pushCredentials: PKPushCredentials,
|
|
424
|
-
for type: PKPushType
|
|
425
|
-
) {
|
|
426
|
-
let token = pushCredentials.token.map { String(format: "%02x", $0) }.joined()
|
|
427
|
-
sendTokenToServer(token) // Always send to server
|
|
428
|
-
}
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
## Review Checklist
|
|
432
|
-
|
|
433
|
-
- [ ] VoIP background mode enabled in capabilities
|
|
434
|
-
- [ ] Single `CXProvider` instance created at app launch and retained
|
|
435
|
-
- [ ] `CXProviderDelegate` set before reporting any calls
|
|
436
|
-
- [ ] Every VoIP push results in a `reportNewIncomingCall` call
|
|
437
|
-
- [ ] `action.fulfill()` or `action.fail()` called for every provider delegate action
|
|
438
|
-
- [ ] Audio engine started only after `provider(_:didActivate:)` callback
|
|
439
|
-
- [ ] Audio engine stopped in `provider(_:didDeactivate:)` callback
|
|
440
|
-
- [ ] Audio session category set to `.playAndRecord` with `.voiceChat` mode
|
|
441
|
-
- [ ] VoIP push token sent to server on every `didUpdate pushCredentials` callback
|
|
442
|
-
- [ ] `PKPushRegistry` created at every app launch (not lazily)
|
|
443
|
-
- [ ] Call Directory phone numbers added in ascending E.164 order
|
|
444
|
-
- [ ] `CXCallUpdate` populated with `localizedCallerName` and `remoteHandle`
|
|
445
|
-
- [ ] Outgoing calls report `startedConnectingAt` and `connectedAt` timestamps
|
|
446
|
-
|
|
447
|
-
## References
|
|
448
|
-
|
|
449
|
-
- Extended patterns (hold, mute, group calls, delegate lifecycle): `references/callkit-patterns.md`
|
|
450
|
-
- [CallKit framework](https://sosumi.ai/documentation/callkit)
|
|
451
|
-
- [CXProvider](https://sosumi.ai/documentation/callkit/cxprovider)
|
|
452
|
-
- [CXCallController](https://sosumi.ai/documentation/callkit/cxcallcontroller)
|
|
453
|
-
- [CXCallAction](https://sosumi.ai/documentation/callkit/cxcallaction)
|
|
454
|
-
- [CXCallUpdate](https://sosumi.ai/documentation/callkit/cxcallupdate)
|
|
455
|
-
- [CXProviderConfiguration](https://sosumi.ai/documentation/callkit/cxproviderconfiguration)
|
|
456
|
-
- [CXProviderDelegate](https://sosumi.ai/documentation/callkit/cxproviderdelegate)
|
|
457
|
-
- [PKPushRegistry](https://sosumi.ai/documentation/pushkit/pkpushregistry)
|
|
458
|
-
- [PKPushRegistryDelegate](https://sosumi.ai/documentation/pushkit/pkpushregistrydelegate)
|
|
459
|
-
- [CXCallDirectoryProvider](https://sosumi.ai/documentation/callkit/cxcalldirectoryprovider)
|
|
460
|
-
- [Making and receiving VoIP calls](https://sosumi.ai/documentation/callkit/making-and-receiving-voip-calls)
|
|
461
|
-
- [Responding to VoIP Notifications from PushKit](https://sosumi.ai/documentation/pushkit/responding-to-voip-notifications-from-pushkit)
|
|
1
|
+
---
|
|
2
|
+
name: callkit-voip
|
|
3
|
+
description: "Implement VoIP calling with CallKit and PushKit. Use when building incoming/outgoing call flows, registering for VoIP push notifications, configuring CXProvider and CXCallController, handling call actions, coordinating audio sessions, or creating Call Directory extensions for caller ID and call blocking."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# CallKit + PushKit VoIP
|
|
7
|
+
|
|
8
|
+
Build VoIP calling features that integrate with the native iOS call UI using
|
|
9
|
+
CallKit and PushKit. Covers incoming/outgoing call flows, VoIP push
|
|
10
|
+
registration, audio session coordination, and call directory extensions.
|
|
11
|
+
Targets Swift 6.2 / iOS 26+.
|
|
12
|
+
|
|
13
|
+
## Contents
|
|
14
|
+
|
|
15
|
+
- [Setup](#setup)
|
|
16
|
+
- [Provider Configuration](#provider-configuration)
|
|
17
|
+
- [Incoming Call Flow](#incoming-call-flow)
|
|
18
|
+
- [Outgoing Call Flow](#outgoing-call-flow)
|
|
19
|
+
- [PushKit VoIP Registration](#pushkit-voip-registration)
|
|
20
|
+
- [Audio Session Coordination](#audio-session-coordination)
|
|
21
|
+
- [Call Directory Extension](#call-directory-extension)
|
|
22
|
+
- [Common Mistakes](#common-mistakes)
|
|
23
|
+
- [Review Checklist](#review-checklist)
|
|
24
|
+
- [References](#references)
|
|
25
|
+
|
|
26
|
+
## Setup
|
|
27
|
+
|
|
28
|
+
### Project Configuration
|
|
29
|
+
|
|
30
|
+
1. Enable the **Voice over IP** background mode in Signing & Capabilities
|
|
31
|
+
2. Add the **Push Notifications** capability
|
|
32
|
+
3. For call directory extensions, add a **Call Directory Extension** target
|
|
33
|
+
|
|
34
|
+
### Key Types
|
|
35
|
+
|
|
36
|
+
| Type | Role |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `CXProvider` | Reports calls to the system, receives call actions |
|
|
39
|
+
| `CXCallController` | Requests call actions (start, end, hold, mute) |
|
|
40
|
+
| `CXCallUpdate` | Describes call metadata (caller name, video, handle) |
|
|
41
|
+
| `CXProviderDelegate` | Handles system call actions and audio session events |
|
|
42
|
+
| `PKPushRegistry` | Registers for and receives VoIP push notifications |
|
|
43
|
+
|
|
44
|
+
## Provider Configuration
|
|
45
|
+
|
|
46
|
+
Create a single `CXProvider` at app launch and keep it alive for the app
|
|
47
|
+
lifetime. Configure it with a `CXProviderConfiguration` that describes your
|
|
48
|
+
calling capabilities.
|
|
49
|
+
|
|
50
|
+
```swift
|
|
51
|
+
import CallKit
|
|
52
|
+
|
|
53
|
+
/// CXProvider dispatches all delegate calls to the queue passed to `setDelegate(_:queue:)`.
|
|
54
|
+
/// The `let` properties are initialized once and never mutated, making this type
|
|
55
|
+
/// safe to share across concurrency domains despite @unchecked Sendable.
|
|
56
|
+
final class CallManager: NSObject, @unchecked Sendable {
|
|
57
|
+
static let shared = CallManager()
|
|
58
|
+
|
|
59
|
+
let provider: CXProvider
|
|
60
|
+
let callController = CXCallController()
|
|
61
|
+
|
|
62
|
+
private override init() {
|
|
63
|
+
let config = CXProviderConfiguration()
|
|
64
|
+
config.localizedName = "My VoIP App"
|
|
65
|
+
config.supportsVideo = true
|
|
66
|
+
config.maximumCallsPerCallGroup = 1
|
|
67
|
+
config.maximumCallGroups = 2
|
|
68
|
+
config.supportedHandleTypes = [.phoneNumber, .emailAddress]
|
|
69
|
+
config.includesCallsInRecents = true
|
|
70
|
+
|
|
71
|
+
provider = CXProvider(configuration: config)
|
|
72
|
+
super.init()
|
|
73
|
+
provider.setDelegate(self, queue: nil)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Incoming Call Flow
|
|
79
|
+
|
|
80
|
+
When a VoIP push arrives, report the incoming call to CallKit immediately.
|
|
81
|
+
The system displays the native call UI. You must report the call before the
|
|
82
|
+
PushKit completion handler returns -- failure to do so causes the system to
|
|
83
|
+
terminate your app.
|
|
84
|
+
|
|
85
|
+
```swift
|
|
86
|
+
func reportIncomingCall(
|
|
87
|
+
uuid: UUID,
|
|
88
|
+
handle: String,
|
|
89
|
+
hasVideo: Bool
|
|
90
|
+
) async throws {
|
|
91
|
+
let update = CXCallUpdate()
|
|
92
|
+
update.remoteHandle = CXHandle(type: .phoneNumber, value: handle)
|
|
93
|
+
update.hasVideo = hasVideo
|
|
94
|
+
update.localizedCallerName = "Jane Doe"
|
|
95
|
+
|
|
96
|
+
try await withCheckedThrowingContinuation {
|
|
97
|
+
(continuation: CheckedContinuation<Void, Error>) in
|
|
98
|
+
provider.reportNewIncomingCall(
|
|
99
|
+
with: uuid,
|
|
100
|
+
update: update
|
|
101
|
+
) { error in
|
|
102
|
+
if let error {
|
|
103
|
+
continuation.resume(throwing: error)
|
|
104
|
+
} else {
|
|
105
|
+
continuation.resume()
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Handling the Answer Action
|
|
113
|
+
|
|
114
|
+
Implement `CXProviderDelegate` to respond when the user answers:
|
|
115
|
+
|
|
116
|
+
```swift
|
|
117
|
+
extension CallManager: CXProviderDelegate {
|
|
118
|
+
func providerDidReset(_ provider: CXProvider) {
|
|
119
|
+
// End all calls, reset audio
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
|
123
|
+
// Configure audio, connect to call server
|
|
124
|
+
configureAudioSession()
|
|
125
|
+
connectToCallServer(callUUID: action.callUUID)
|
|
126
|
+
action.fulfill()
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
|
|
130
|
+
disconnectFromCallServer(callUUID: action.callUUID)
|
|
131
|
+
action.fulfill()
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Outgoing Call Flow
|
|
137
|
+
|
|
138
|
+
Use `CXCallController` to request an outgoing call. The system routes the
|
|
139
|
+
request through your `CXProviderDelegate`.
|
|
140
|
+
|
|
141
|
+
```swift
|
|
142
|
+
func startOutgoingCall(handle: String, hasVideo: Bool) {
|
|
143
|
+
let uuid = UUID()
|
|
144
|
+
let handle = CXHandle(type: .phoneNumber, value: handle)
|
|
145
|
+
let startAction = CXStartCallAction(call: uuid, handle: handle)
|
|
146
|
+
startAction.isVideo = hasVideo
|
|
147
|
+
|
|
148
|
+
let transaction = CXTransaction(action: startAction)
|
|
149
|
+
callController.request(transaction) { error in
|
|
150
|
+
if let error {
|
|
151
|
+
print("Failed to start call: \(error)")
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Delegate Methods for Outgoing Calls
|
|
158
|
+
|
|
159
|
+
```swift
|
|
160
|
+
extension CallManager {
|
|
161
|
+
func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
|
|
162
|
+
configureAudioSession()
|
|
163
|
+
// Begin connecting to server
|
|
164
|
+
provider.reportOutgoingCall(
|
|
165
|
+
with: action.callUUID,
|
|
166
|
+
startedConnectingAt: Date()
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
connectToServer(callUUID: action.callUUID) {
|
|
170
|
+
provider.reportOutgoingCall(
|
|
171
|
+
with: action.callUUID,
|
|
172
|
+
connectedAt: Date()
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
action.fulfill()
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## PushKit VoIP Registration
|
|
181
|
+
|
|
182
|
+
Register for VoIP pushes at every app launch. Send the token to your server
|
|
183
|
+
whenever it changes.
|
|
184
|
+
|
|
185
|
+
```swift
|
|
186
|
+
import PushKit
|
|
187
|
+
|
|
188
|
+
final class PushManager: NSObject, PKPushRegistryDelegate {
|
|
189
|
+
let registry: PKPushRegistry
|
|
190
|
+
|
|
191
|
+
override init() {
|
|
192
|
+
registry = PKPushRegistry(queue: .main)
|
|
193
|
+
super.init()
|
|
194
|
+
registry.delegate = self
|
|
195
|
+
registry.desiredPushTypes = [.voIP]
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
func pushRegistry(
|
|
199
|
+
_ registry: PKPushRegistry,
|
|
200
|
+
didUpdate pushCredentials: PKPushCredentials,
|
|
201
|
+
for type: PKPushType
|
|
202
|
+
) {
|
|
203
|
+
let token = pushCredentials.token
|
|
204
|
+
.map { String(format: "%02x", $0) }
|
|
205
|
+
.joined()
|
|
206
|
+
// Send token to your server
|
|
207
|
+
sendTokenToServer(token)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
func pushRegistry(
|
|
211
|
+
_ registry: PKPushRegistry,
|
|
212
|
+
didReceiveIncomingPushWith payload: PKPushPayload,
|
|
213
|
+
for type: PKPushType,
|
|
214
|
+
completion: @escaping () -> Void
|
|
215
|
+
) {
|
|
216
|
+
guard type == .voIP else {
|
|
217
|
+
completion()
|
|
218
|
+
return
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
let callUUID = UUID()
|
|
222
|
+
let handle = payload.dictionaryPayload["handle"] as? String ?? "Unknown"
|
|
223
|
+
|
|
224
|
+
Task {
|
|
225
|
+
do {
|
|
226
|
+
try await CallManager.shared.reportIncomingCall(
|
|
227
|
+
uuid: callUUID,
|
|
228
|
+
handle: handle,
|
|
229
|
+
hasVideo: false
|
|
230
|
+
)
|
|
231
|
+
} catch {
|
|
232
|
+
// Call was filtered by DND or block list
|
|
233
|
+
}
|
|
234
|
+
completion()
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Audio Session Coordination
|
|
241
|
+
|
|
242
|
+
CallKit manages audio session activation/deactivation. Configure your audio
|
|
243
|
+
session when CallKit tells you to, not before.
|
|
244
|
+
|
|
245
|
+
```swift
|
|
246
|
+
extension CallManager {
|
|
247
|
+
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
|
|
248
|
+
// Audio session is now active -- start audio engine / WebRTC
|
|
249
|
+
startAudioEngine()
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
|
|
253
|
+
// Audio session deactivated -- stop audio engine
|
|
254
|
+
stopAudioEngine()
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
func configureAudioSession() {
|
|
258
|
+
let session = AVAudioSession.sharedInstance()
|
|
259
|
+
do {
|
|
260
|
+
try session.setCategory(
|
|
261
|
+
.playAndRecord,
|
|
262
|
+
mode: .voiceChat,
|
|
263
|
+
options: [.allowBluetooth, .allowBluetoothA2DP]
|
|
264
|
+
)
|
|
265
|
+
} catch {
|
|
266
|
+
print("Audio session configuration failed: \(error)")
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Call Directory Extension
|
|
273
|
+
|
|
274
|
+
Create a Call Directory extension to provide caller ID and call blocking.
|
|
275
|
+
|
|
276
|
+
```swift
|
|
277
|
+
import CallKit
|
|
278
|
+
|
|
279
|
+
final class CallDirectoryHandler: CXCallDirectoryProvider {
|
|
280
|
+
override func beginRequest(
|
|
281
|
+
with context: CXCallDirectoryExtensionContext
|
|
282
|
+
) {
|
|
283
|
+
if context.isIncremental {
|
|
284
|
+
addOrRemoveIncrementalEntries(to: context)
|
|
285
|
+
} else {
|
|
286
|
+
addAllEntries(to: context)
|
|
287
|
+
}
|
|
288
|
+
context.completeRequest()
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
private func addAllEntries(
|
|
292
|
+
to context: CXCallDirectoryExtensionContext
|
|
293
|
+
) {
|
|
294
|
+
// Phone numbers must be in ascending order (E.164 format as Int64)
|
|
295
|
+
let blockedNumbers: [CXCallDirectoryPhoneNumber] = [
|
|
296
|
+
18005551234, 18005555678
|
|
297
|
+
]
|
|
298
|
+
for number in blockedNumbers {
|
|
299
|
+
context.addBlockingEntry(
|
|
300
|
+
withNextSequentialPhoneNumber: number
|
|
301
|
+
)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
let identifiedNumbers: [(CXCallDirectoryPhoneNumber, String)] = [
|
|
305
|
+
(18005551111, "Local Pizza"),
|
|
306
|
+
(18005552222, "Dentist Office")
|
|
307
|
+
]
|
|
308
|
+
for (number, label) in identifiedNumbers {
|
|
309
|
+
context.addIdentificationEntry(
|
|
310
|
+
withNextSequentialPhoneNumber: number,
|
|
311
|
+
label: label
|
|
312
|
+
)
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Reload the extension from the main app after data changes:
|
|
319
|
+
|
|
320
|
+
```swift
|
|
321
|
+
CXCallDirectoryManager.sharedInstance.reloadExtension(
|
|
322
|
+
withIdentifier: "com.example.app.CallDirectory"
|
|
323
|
+
) { error in
|
|
324
|
+
if let error { print("Reload failed: \(error)") }
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Common Mistakes
|
|
329
|
+
|
|
330
|
+
### DON'T: Fail to report a call on VoIP push receipt
|
|
331
|
+
|
|
332
|
+
If your PushKit delegate receives a VoIP push but does not call
|
|
333
|
+
`reportNewIncomingCall(with:update:completion:)`, iOS terminates your app and
|
|
334
|
+
may stop delivering pushes entirely.
|
|
335
|
+
|
|
336
|
+
```swift
|
|
337
|
+
// WRONG -- no call reported
|
|
338
|
+
func pushRegistry(
|
|
339
|
+
_ registry: PKPushRegistry,
|
|
340
|
+
didReceiveIncomingPushWith payload: PKPushPayload,
|
|
341
|
+
for type: PKPushType,
|
|
342
|
+
completion: @escaping () -> Void
|
|
343
|
+
) {
|
|
344
|
+
// Just process data, no call reported
|
|
345
|
+
processPayload(payload)
|
|
346
|
+
completion()
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// CORRECT -- always report a call
|
|
350
|
+
func pushRegistry(
|
|
351
|
+
_ registry: PKPushRegistry,
|
|
352
|
+
didReceiveIncomingPushWith payload: PKPushPayload,
|
|
353
|
+
for type: PKPushType,
|
|
354
|
+
completion: @escaping () -> Void
|
|
355
|
+
) {
|
|
356
|
+
let uuid = UUID()
|
|
357
|
+
provider.reportNewIncomingCall(
|
|
358
|
+
with: uuid, update: makeUpdate(from: payload)
|
|
359
|
+
) { _ in completion() }
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### DON'T: Start audio before CallKit activates the session
|
|
364
|
+
|
|
365
|
+
Starting your audio engine before `provider(_:didActivate:)` causes silence
|
|
366
|
+
or immediate deactivation. CallKit manages session priority with the system.
|
|
367
|
+
|
|
368
|
+
```swift
|
|
369
|
+
// WRONG
|
|
370
|
+
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
|
371
|
+
startAudioEngine() // Too early -- session not active yet
|
|
372
|
+
action.fulfill()
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// CORRECT
|
|
376
|
+
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
|
377
|
+
prepareAudioEngine() // Prepare, but do not start
|
|
378
|
+
action.fulfill()
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
|
|
382
|
+
startAudioEngine() // Now it's safe
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### DON'T: Forget to call action.fulfill() or action.fail()
|
|
387
|
+
|
|
388
|
+
Failing to fulfill or fail an action leaves the call in a limbo state and
|
|
389
|
+
triggers the timeout handler.
|
|
390
|
+
|
|
391
|
+
```swift
|
|
392
|
+
// WRONG
|
|
393
|
+
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
|
394
|
+
connectToServer()
|
|
395
|
+
// Forgot action.fulfill()
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// CORRECT
|
|
399
|
+
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
|
|
400
|
+
connectToServer()
|
|
401
|
+
action.fulfill()
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### DON'T: Ignore push token refresh
|
|
406
|
+
|
|
407
|
+
The VoIP push token can change at any time. If your server has a stale token,
|
|
408
|
+
pushes silently fail and incoming calls never arrive.
|
|
409
|
+
|
|
410
|
+
```swift
|
|
411
|
+
// WRONG -- only send token once at first registration
|
|
412
|
+
func pushRegistry(
|
|
413
|
+
_ registry: PKPushRegistry,
|
|
414
|
+
didUpdate pushCredentials: PKPushCredentials,
|
|
415
|
+
for type: PKPushType
|
|
416
|
+
) {
|
|
417
|
+
// Token saved locally but never updated on server
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// CORRECT -- always update server
|
|
421
|
+
func pushRegistry(
|
|
422
|
+
_ registry: PKPushRegistry,
|
|
423
|
+
didUpdate pushCredentials: PKPushCredentials,
|
|
424
|
+
for type: PKPushType
|
|
425
|
+
) {
|
|
426
|
+
let token = pushCredentials.token.map { String(format: "%02x", $0) }.joined()
|
|
427
|
+
sendTokenToServer(token) // Always send to server
|
|
428
|
+
}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## Review Checklist
|
|
432
|
+
|
|
433
|
+
- [ ] VoIP background mode enabled in capabilities
|
|
434
|
+
- [ ] Single `CXProvider` instance created at app launch and retained
|
|
435
|
+
- [ ] `CXProviderDelegate` set before reporting any calls
|
|
436
|
+
- [ ] Every VoIP push results in a `reportNewIncomingCall` call
|
|
437
|
+
- [ ] `action.fulfill()` or `action.fail()` called for every provider delegate action
|
|
438
|
+
- [ ] Audio engine started only after `provider(_:didActivate:)` callback
|
|
439
|
+
- [ ] Audio engine stopped in `provider(_:didDeactivate:)` callback
|
|
440
|
+
- [ ] Audio session category set to `.playAndRecord` with `.voiceChat` mode
|
|
441
|
+
- [ ] VoIP push token sent to server on every `didUpdate pushCredentials` callback
|
|
442
|
+
- [ ] `PKPushRegistry` created at every app launch (not lazily)
|
|
443
|
+
- [ ] Call Directory phone numbers added in ascending E.164 order
|
|
444
|
+
- [ ] `CXCallUpdate` populated with `localizedCallerName` and `remoteHandle`
|
|
445
|
+
- [ ] Outgoing calls report `startedConnectingAt` and `connectedAt` timestamps
|
|
446
|
+
|
|
447
|
+
## References
|
|
448
|
+
|
|
449
|
+
- Extended patterns (hold, mute, group calls, delegate lifecycle): `references/callkit-patterns.md`
|
|
450
|
+
- [CallKit framework](https://sosumi.ai/documentation/callkit)
|
|
451
|
+
- [CXProvider](https://sosumi.ai/documentation/callkit/cxprovider)
|
|
452
|
+
- [CXCallController](https://sosumi.ai/documentation/callkit/cxcallcontroller)
|
|
453
|
+
- [CXCallAction](https://sosumi.ai/documentation/callkit/cxcallaction)
|
|
454
|
+
- [CXCallUpdate](https://sosumi.ai/documentation/callkit/cxcallupdate)
|
|
455
|
+
- [CXProviderConfiguration](https://sosumi.ai/documentation/callkit/cxproviderconfiguration)
|
|
456
|
+
- [CXProviderDelegate](https://sosumi.ai/documentation/callkit/cxproviderdelegate)
|
|
457
|
+
- [PKPushRegistry](https://sosumi.ai/documentation/pushkit/pkpushregistry)
|
|
458
|
+
- [PKPushRegistryDelegate](https://sosumi.ai/documentation/pushkit/pkpushregistrydelegate)
|
|
459
|
+
- [CXCallDirectoryProvider](https://sosumi.ai/documentation/callkit/cxcalldirectoryprovider)
|
|
460
|
+
- [Making and receiving VoIP calls](https://sosumi.ai/documentation/callkit/making-and-receiving-voip-calls)
|
|
461
|
+
- [Responding to VoIP Notifications from PushKit](https://sosumi.ai/documentation/pushkit/responding-to-voip-notifications-from-pushkit)
|