@mmerterden/multi-agent-pipeline 20.6.0 → 20.8.0

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.
Files changed (326) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +328 -329
  5. package/package.json +2 -2
  6. package/pipeline/multi-agent-refs/features/design-conformance.md +62 -64
  7. package/pipeline/scripts/_notices.mjs +12 -1
  8. package/pipeline/scripts/gen-skills-index.mjs +1 -1
  9. package/pipeline/skills/.skill-manifest.json +106 -106
  10. package/pipeline/skills/shared/README.md +71 -71
  11. package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +1 -0
  12. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  13. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  14. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  15. package/pipeline/skills/shared/external/android-architecture/SKILL.md +2 -0
  16. package/pipeline/skills/shared/external/android-performance/SKILL.md +2 -0
  17. package/pipeline/skills/shared/external/android-security/SKILL.md +2 -0
  18. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  19. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  20. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  21. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  22. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  23. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  24. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  25. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  26. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  27. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  28. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  29. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  30. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  31. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  32. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  33. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  34. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  35. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  36. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  37. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  38. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  39. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  40. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  41. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  42. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  43. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  44. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  45. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  46. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  47. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  48. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  49. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  50. package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
  51. package/pipeline/skills/shared/external/backlog/SKILL.md +56 -33
  52. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  53. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  54. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  55. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -0
  56. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  57. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  58. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  59. package/pipeline/skills/shared/external/compose-components/SKILL.md +2 -0
  60. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +3 -2
  61. package/pipeline/skills/shared/external/compose-testing/SKILL.md +2 -0
  62. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  63. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  64. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  65. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  66. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  67. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  68. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  69. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  70. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  71. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  72. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  73. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  74. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  75. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  76. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  77. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  78. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  79. package/pipeline/skills/shared/external/council/SKILL.md +1 -0
  80. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  81. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  82. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  83. package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -0
  84. package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -0
  85. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  86. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  87. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  88. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  89. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  90. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  91. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  92. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  93. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  94. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  95. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  96. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  97. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  98. package/pipeline/skills/shared/external/evidence-github/SKILL.md +2 -0
  99. package/pipeline/skills/shared/external/evidence-registry/SKILL.md +2 -0
  100. package/pipeline/skills/shared/external/gradle-kotlin-dsl/SKILL.md +2 -0
  101. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  102. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  103. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  104. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  105. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  106. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  107. package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -0
  108. package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -0
  109. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  110. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  111. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  112. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  113. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  114. package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +1 -0
  115. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  116. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  117. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  118. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  119. package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +1 -0
  120. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  121. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  122. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  123. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  124. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  125. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  126. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  127. package/pipeline/skills/shared/external/ios-security/SKILL.md +2 -0
  128. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  129. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  130. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  131. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  132. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  133. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  134. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +91 -283
  135. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +119 -151
  136. package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +60 -90
  137. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +119 -156
  138. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +726 -787
  139. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +253 -288
  140. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +243 -304
  141. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +88 -104
  142. package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +181 -235
  143. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +198 -263
  144. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +461 -466
  145. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +145 -151
  146. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +123 -141
  147. package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +146 -157
  148. package/pipeline/skills/shared/external/localization-reuse-map/scripts/snapshot-resources.sh +22 -19
  149. package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +156 -140
  150. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  151. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  152. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  153. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  154. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  155. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  156. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  157. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  158. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  159. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  160. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  161. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  162. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  163. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -0
  164. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  165. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  166. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  167. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  168. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  169. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  170. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  171. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  172. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  173. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  174. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  175. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  176. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  177. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  178. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  179. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  180. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  181. package/pipeline/skills/shared/external/play-store-review/SKILL.md +2 -0
  182. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  183. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  184. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  185. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  186. package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -0
  187. package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -0
  188. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  189. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  190. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  191. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -0
  192. package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +2 -0
  193. package/pipeline/skills/shared/external/room-database/SKILL.md +2 -0
  194. package/pipeline/skills/shared/external/search-first/SKILL.md +1 -0
  195. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  196. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  197. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  198. package/pipeline/skills/shared/external/signal-community/SKILL.md +2 -0
  199. package/pipeline/skills/shared/external/skill-creator/SKILL.md +80 -41
  200. package/pipeline/skills/shared/external/skill-creator/audit.md +63 -59
  201. package/pipeline/skills/shared/external/skill-creator/checklist.md +28 -20
  202. package/pipeline/skills/shared/external/skill-creator/examples.md +40 -40
  203. package/pipeline/skills/shared/external/skill-creator/label-check.md +48 -36
  204. package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +91 -100
  205. package/pipeline/skills/shared/external/skill-creator/template.md +51 -39
  206. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  207. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  208. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  209. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  210. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  211. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  212. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  213. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  214. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  215. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  216. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  217. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  218. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  219. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  220. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  221. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  222. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  223. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  224. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  225. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  226. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  227. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  228. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  229. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  230. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  231. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  232. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  233. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  234. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  235. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  236. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  237. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  238. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  239. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  240. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  241. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  242. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  243. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  244. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  245. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  246. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  247. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  248. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  249. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  250. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  251. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  252. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  253. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  254. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  255. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  256. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  257. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  258. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  259. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  260. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  261. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  262. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  263. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  264. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  265. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  266. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  267. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  268. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  269. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  270. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  271. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  272. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  273. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  274. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  275. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  276. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  277. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  278. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  279. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  280. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  281. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  282. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  283. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  284. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  285. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  286. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  287. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  288. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  289. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  290. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  291. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  292. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  293. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  294. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  295. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  296. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  297. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  298. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  299. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  300. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  301. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  302. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  303. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  304. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  305. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  306. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  307. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  308. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  309. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  310. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -0
  311. package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -0
  312. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  313. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  314. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -0
  315. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  316. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  317. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  318. package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -0
  319. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  320. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  321. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -0
  322. package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -0
  323. package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -0
  324. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  325. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  326. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,444 +1,276 @@
1
- # CallKit + PushKit Extended Patterns
1
+ # CallKit Patterns
2
2
 
3
- Overflow reference for the `callkit` skill. Contains advanced patterns that exceed the main skill file's scope.
3
+ Longer examples that back the `callkit-voip` skill. Read its SKILL.md first;
4
+ this file assumes the provider setup, push rules and audio rules described
5
+ there.
4
6
 
5
- ## Contents
7
+ ## An observable call manager
6
8
 
7
- - [Full Call Manager](#full-call-manager)
8
- - [Hold and Mute Actions](#hold-and-mute-actions)
9
- - [Multiple Concurrent Calls](#multiple-concurrent-calls)
10
- - [Call State Tracking](#call-state-tracking)
11
- - [Encrypted VoIP Push Filtering](#encrypted-voip-push-filtering)
12
- - [Call Directory Incremental Updates](#call-directory-incremental-updates)
13
- - [Testing VoIP Locally](#testing-voip-locally)
14
-
15
- ## Full Call Manager
9
+ A `@MainActor` model that SwiftUI can watch. It owns the provider and the
10
+ controller and keeps a table of live calls.
16
11
 
17
12
  ```swift
18
13
  import CallKit
19
- import AVFoundation
20
- import PushKit
21
-
22
- @Observable
23
- @MainActor
24
- final class VoIPCallManager: NSObject {
25
- let provider: CXProvider
26
- let callController = CXCallController()
27
-
28
- private(set) var activeCalls: [UUID: CallInfo] = [:]
29
-
30
- struct CallInfo {
31
- let uuid: UUID
32
- let handle: String
33
- let isOutgoing: Bool
34
- var isOnHold: Bool = false
35
- var isMuted: Bool = false
36
- var isConnected: Bool = false
37
- }
14
+ import Observation
15
+
16
+ struct LiveCall: Identifiable, Sendable {
17
+ let id: UUID
18
+ let address: String
19
+ let outgoing: Bool
20
+ var held = false
21
+ var muted = false
22
+ var connected = false
23
+ }
24
+
25
+ @Observable @MainActor
26
+ final class Switchboard: NSObject {
27
+ @ObservationIgnored let provider: CXProvider
28
+ @ObservationIgnored let controller = CXCallController()
29
+ private(set) var calls: [UUID: LiveCall] = [:]
38
30
 
39
31
  override init() {
40
- let config = CXProviderConfiguration()
41
- config.localizedName = "My VoIP"
42
- config.supportsVideo = true
43
- config.maximumCallGroups = 2
44
- config.maximumCallsPerCallGroup = 1
45
- config.supportedHandleTypes = [.phoneNumber]
46
- config.includesCallsInRecents = true
47
-
48
- provider = CXProvider(configuration: config)
32
+ let setup = CXProviderConfiguration()
33
+ setup.supportedHandleTypes = [.phoneNumber]
34
+ setup.includesCallsInRecents = true
35
+ setup.maximumCallsPerCallGroup = 1
36
+ setup.maximumCallGroups = 2
37
+ setup.supportsVideo = true
38
+ provider = CXProvider(configuration: setup)
49
39
  super.init()
50
40
  provider.setDelegate(self, queue: nil)
51
41
  }
52
42
 
53
- // MARK: - Incoming
54
-
55
- func reportIncoming(
56
- uuid: UUID,
57
- handle: String,
58
- callerName: String,
59
- hasVideo: Bool
60
- ) async throws {
61
- let update = CXCallUpdate()
62
- update.remoteHandle = CXHandle(type: .phoneNumber, value: handle)
63
- update.localizedCallerName = callerName
64
- update.hasVideo = hasVideo
65
- update.supportsHolding = true
66
- update.supportsDTMF = true
67
- update.supportsGrouping = false
68
- update.supportsUngrouping = false
69
-
70
- try await withCheckedThrowingContinuation {
71
- (continuation: CheckedContinuation<Void, Error>) in
72
- provider.reportNewIncomingCall(
73
- with: uuid, update: update
74
- ) { error in
75
- if let error {
76
- continuation.resume(throwing: error)
77
- } else {
78
- continuation.resume()
79
- }
80
- }
81
- }
82
-
83
- activeCalls[uuid] = CallInfo(
84
- uuid: uuid, handle: handle, isOutgoing: false
85
- )
43
+ func reportIncoming(id: UUID, address: String, name: String) async throws {
44
+ let info = CXCallUpdate()
45
+ info.localizedCallerName = name
46
+ info.remoteHandle = CXHandle(type: .generic, value: address)
47
+ info.supportsDTMF = true
48
+ info.supportsHolding = true
49
+ info.supportsUngrouping = false
50
+ info.supportsGrouping = false
51
+ try await provider.reportNewIncomingCall(with: id, update: info)
52
+ calls[id] = LiveCall(id: id, address: address, outgoing: false)
86
53
  }
87
54
 
88
- // MARK: - Outgoing
89
-
90
- func startCall(handle: String, hasVideo: Bool) {
91
- let uuid = UUID()
92
- let cxHandle = CXHandle(type: .phoneNumber, value: handle)
93
- let action = CXStartCallAction(call: uuid, handle: cxHandle)
94
- action.isVideo = hasVideo
95
-
96
- callController.request(
97
- CXTransaction(action: action)
98
- ) { error in
99
- if let error {
100
- print("Start call failed: \(error)")
101
- }
102
- }
103
-
104
- activeCalls[uuid] = CallInfo(
105
- uuid: uuid, handle: handle, isOutgoing: true
106
- )
55
+ func startCall(to address: String) async throws {
56
+ let id = UUID()
57
+ let action = CXStartCallAction(call: id, handle: CXHandle(type: .phoneNumber, value: address))
58
+ try await controller.request(CXTransaction(action: action))
59
+ calls[id] = LiveCall(id: id, address: address, outgoing: true)
107
60
  }
108
61
 
109
- // MARK: - Actions
110
-
111
- func endCall(uuid: UUID) {
112
- let action = CXEndCallAction(call: uuid)
113
- callController.request(CXTransaction(action: action)) { error in
114
- if let error { print("End call failed: \(error)") }
115
- }
62
+ func hangUp(_ id: UUID) async throws {
63
+ try await controller.request(CXTransaction(action: CXEndCallAction(call: id)))
116
64
  }
117
65
 
118
- func setHeld(uuid: UUID, onHold: Bool) {
119
- let action = CXSetHeldCallAction(call: uuid, onHold: onHold)
120
- callController.request(CXTransaction(action: action)) { error in
121
- if let error { print("Hold failed: \(error)") }
122
- }
66
+ func setHeld(_ id: UUID, _ held: Bool) async throws {
67
+ try await controller.request(CXTransaction(action: CXSetHeldCallAction(call: id, onHold: held)))
123
68
  }
124
69
 
125
- func setMuted(uuid: UUID, muted: Bool) {
126
- let action = CXSetMutedCallAction(call: uuid, muted: muted)
127
- callController.request(CXTransaction(action: action)) { error in
128
- if let error { print("Mute failed: \(error)") }
129
- }
70
+ func setMuted(_ id: UUID, _ muted: Bool) async throws {
71
+ try await controller.request(CXTransaction(action: CXSetMutedCallAction(call: id, muted: muted)))
130
72
  }
131
73
  }
132
74
  ```
133
75
 
134
- ## Hold and Mute Actions
76
+ A call enters `calls` only after its incoming report succeeds; an outgoing call
77
+ enters after the start transaction was accepted. Hanging up, holding and muting
78
+ all follow the same shape: build the action, wrap it in a `CXTransaction`, send
79
+ it with `request`.
135
80
 
136
- ```swift
137
- extension VoIPCallManager: CXProviderDelegate {
138
- nonisolated func providerDidReset(_ provider: CXProvider) {
139
- Task { @MainActor in
140
- for uuid in activeCalls.keys {
141
- disconnectCall(uuid)
142
- }
143
- activeCalls.removeAll()
144
- }
145
- }
146
-
147
- nonisolated func provider(
148
- _ provider: CXProvider,
149
- perform action: CXSetHeldCallAction
150
- ) {
151
- Task { @MainActor in
152
- activeCalls[action.callUUID]?.isOnHold = action.isOnHold
153
- if action.isOnHold {
154
- pauseAudio(for: action.callUUID)
155
- } else {
156
- resumeAudio(for: action.callUUID)
157
- }
158
- action.fulfill()
159
- }
160
- }
81
+ ## Hold and mute in the delegate
161
82
 
162
- nonisolated func provider(
163
- _ provider: CXProvider,
164
- perform action: CXSetMutedCallAction
165
- ) {
166
- Task { @MainActor in
167
- activeCalls[action.callUUID]?.isMuted = action.isMuted
168
- // If call translation is active, mute app input without deactivating
169
- // upstream audio that translated audio may need.
170
- setMicrophoneMuted(action.isMuted)
171
- action.fulfill()
172
- }
173
- }
83
+ The provider calls its delegate on the main queue here (`queue: nil`), so the
84
+ conformance is `@preconcurrency`: the methods stay main-actor isolated and
85
+ touch `calls` directly. Marking them `nonisolated` and hopping back with
86
+ `Task { @MainActor in ... }` does not compile under Swift 6, because the task
87
+ would carry the non-`Sendable` `CXAction` off the delegate call ("sending
88
+ 'hold' risks causing data races").
174
89
 
175
- nonisolated func provider(
176
- _ provider: CXProvider,
177
- perform action: CXAnswerCallAction
178
- ) {
179
- Task { @MainActor in
180
- configureAudioSession()
181
- connectToServer(callUUID: action.callUUID) { success in
182
- if success {
183
- activeCalls[action.callUUID]?.isConnected = true
184
- action.fulfill()
185
- } else {
186
- provider.reportCall(
187
- with: action.callUUID,
188
- endedAt: Date(),
189
- reason: .failed
190
- )
191
- action.fail()
192
- }
193
- }
194
- }
195
- }
196
-
197
- nonisolated func provider(
198
- _ provider: CXProvider,
199
- perform action: CXStartCallAction
200
- ) {
201
- Task { @MainActor in
202
- configureAudioSession()
203
- provider.reportOutgoingCall(
204
- with: action.callUUID,
205
- startedConnectingAt: Date()
206
- )
207
- connectToServer(callUUID: action.callUUID)
208
- provider.reportOutgoingCall(
209
- with: action.callUUID,
210
- connectedAt: Date()
211
- )
212
- activeCalls[action.callUUID]?.isConnected = true
213
- action.fulfill()
214
- }
215
- }
216
-
217
- nonisolated func provider(
218
- _ provider: CXProvider,
219
- perform action: CXEndCallAction
220
- ) {
221
- Task { @MainActor in
222
- disconnectCall(action.callUUID)
223
- activeCalls.removeValue(forKey: action.callUUID)
224
- action.fulfill()
90
+ ```swift
91
+ extension Switchboard: @preconcurrency CXProviderDelegate {
92
+ func providerDidReset(_ cx: CXProvider) {
93
+ Task {
94
+ for id in calls.keys { await CallMedia.shared.disconnect(id) }
95
+ calls.removeAll()
225
96
  }
226
97
  }
227
98
 
228
- nonisolated func provider(
229
- _ provider: CXProvider,
230
- didActivate audioSession: AVAudioSession
231
- ) {
232
- Task { @MainActor in
233
- startAudioEngine()
234
- }
99
+ func provider(_ cx: CXProvider, perform hold: CXSetHeldCallAction) {
100
+ let id = hold.callUUID
101
+ calls[id]?.held = hold.isOnHold
102
+ if hold.isOnHold { CallMedia.shared.pause(id) } else { CallMedia.shared.resume(id) }
103
+ hold.fulfill()
235
104
  }
236
105
 
237
- nonisolated func provider(
238
- _ provider: CXProvider,
239
- didDeactivate audioSession: AVAudioSession
240
- ) {
241
- Task { @MainActor in
242
- stopAudioEngine()
243
- }
106
+ func provider(_ cx: CXProvider, perform mute: CXSetMutedCallAction) {
107
+ calls[mute.callUUID]?.muted = mute.isMuted
108
+ CallMedia.shared.setMicrophoneMuted(mute.isMuted)
109
+ mute.fulfill()
244
110
  }
245
111
  }
246
112
  ```
247
113
 
248
- ## Multiple Concurrent Calls
114
+ Muting only silences the microphone input. Upstream audio keeps flowing,
115
+ because iOS 26 call translation depends on it.
249
116
 
250
- When a second call arrives while one is active, CallKit automatically puts
251
- the first call on hold. Handle the hold action to pause your audio stream:
117
+ The answer, start, end, `didActivate` and `didDeactivate` handlers are the same
118
+ as in SKILL.md, with bookkeeping added: set `connected = true` once media
119
+ connects, and remove the entry when the call ends.
252
120
 
253
- ```swift
254
- nonisolated func provider(
255
- _ provider: CXProvider,
256
- perform action: CXSetHeldCallAction
257
- ) {
258
- Task { @MainActor in
259
- if action.isOnHold {
260
- // Pause the RTP stream for this call
261
- pauseMediaStream(for: action.callUUID)
262
- } else {
263
- // Resume the RTP stream
264
- resumeMediaStream(for: action.callUUID)
265
- }
266
- activeCalls[action.callUUID]?.isOnHold = action.isOnHold
267
- action.fulfill()
268
- }
269
- }
270
- ```
121
+ ## Several calls at once
271
122
 
272
- Configure `maximumCallGroups` and `maximumCallsPerCallGroup` in
273
- `CXProviderConfiguration` to control how many concurrent calls your app
274
- supports.
123
+ When a second call rings while one is active and the user accepts it, CallKit
124
+ holds the first call on its own. The app sees a `CXSetHeldCallAction` for the
125
+ first call and must pause or resume its media stream (for example the RTP
126
+ session) in response. How many calls may coexist is set by
127
+ `maximumCallGroups` and `maximumCallsPerCallGroup` in the configuration.
275
128
 
276
- ## Call State Tracking
129
+ ## Watching call state
277
130
 
278
- Use `CXCallObserver` to monitor call state changes from outside the provider
279
- delegate:
131
+ `CXCallObserver` reports every call on the device, which is useful outside the
132
+ provider delegate, for example in a status view.
280
133
 
281
134
  ```swift
282
135
  import CallKit
283
136
 
284
- final class CallStateObserver: NSObject, CXCallObserverDelegate {
285
- let observer = CXCallObserver()
137
+ final class CallWatcher: NSObject, CXCallObserverDelegate {
138
+ private let monitor = CXCallObserver()
286
139
 
287
140
  override init() {
288
141
  super.init()
289
- observer.setDelegate(self, queue: nil)
142
+ monitor.setDelegate(self, queue: .main)
290
143
  }
291
144
 
292
- func callObserver(
293
- _ callObserver: CXCallObserver,
294
- callChanged call: CXCall
295
- ) {
145
+ func callObserver(_ watcher: CXCallObserver, callChanged call: CXCall) {
146
+ let phase: String
296
147
  if call.hasEnded {
297
- print("Call \(call.uuid) ended")
148
+ phase = "ended"
298
149
  } else if call.hasConnected {
299
- print("Call \(call.uuid) connected")
150
+ phase = "connected"
300
151
  } else if call.isOutgoing {
301
- print("Outgoing call \(call.uuid) ringing")
152
+ phase = "dialing"
302
153
  } else {
303
- print("Incoming call \(call.uuid) ringing")
154
+ phase = "ringing"
304
155
  }
156
+ Log.calls.info("\(call.uuid) is \(phase)")
305
157
  }
306
158
  }
307
159
  ```
308
160
 
309
- ## Encrypted VoIP Push Filtering
161
+ ## Filtering encrypted VoIP pushes
310
162
 
311
- Use a notification service extension with
312
- `CXProvider.reportNewIncomingVoIPPushPayload` only when server-side metadata
313
- encryption means the server cannot determine whether the outgoing notification
314
- is a VoIP call request or some other data. If the server knows the content is
315
- a VoIP call, send a normal PushKit VoIP push instead.
163
+ When the server sends end-to-end encrypted content and cannot tell whether it
164
+ is a call, a notification service extension decrypts it and hands call
165
+ payloads to CallKit.
316
166
 
317
167
  ```swift
318
- import UserNotifications
319
168
  import CallKit
169
+ import UserNotifications
320
170
 
321
- final class NotificationService: UNNotificationServiceExtension {
322
- override func didReceive(
323
- _ request: UNNotificationRequest,
324
- withContentHandler contentHandler:
325
- @escaping (UNNotificationContent) -> Void
326
- ) {
327
- guard let encryptedPayload = request.content
328
- .userInfo["encrypted"] as? [AnyHashable: Any] else {
329
- contentHandler(request.content)
171
+ final class PushFilter: UNNotificationServiceExtension {
172
+ override func didReceive(_ incoming: UNNotificationRequest,
173
+ withContentHandler deliver: @escaping (UNNotificationContent) -> Void) {
174
+ guard let sealed = incoming.content.userInfo["sealed"] as? String,
175
+ let opened = Envelope.open(sealed) else {
176
+ deliver(incoming.content)
330
177
  return
331
178
  }
332
-
333
- let decryptedPayload = decryptPayload(encryptedPayload)
334
-
335
- CXProvider.reportNewIncomingVoIPPushPayload(
336
- decryptedPayload
337
- ) { error in
338
- if let error {
339
- // Show a missed-call notification instead
340
- let content = UNMutableNotificationContent()
341
- content.title = "Missed Call"
342
- content.body = decryptedPayload["callerName"] as? String ?? ""
343
- contentHandler(content)
344
- } else {
345
- // Call was reported; suppress the notification
346
- contentHandler(UNNotificationContent())
179
+ nonisolated(unsafe) let deliver = deliver
180
+ CXProvider.reportNewIncomingVoIPPushPayload(opened) { failure in
181
+ guard failure != nil else {
182
+ deliver(UNNotificationContent())
183
+ return
347
184
  }
185
+ let missed = UNMutableNotificationContent()
186
+ missed.title = String(localized: "Missed call")
187
+ deliver(missed)
348
188
  }
349
189
  }
350
190
  }
351
191
  ```
352
192
 
353
- This requires the `com.apple.developer.usernotifications.filtering` entitlement.
193
+ Content that was not encrypted passes through untouched. The content handler
194
+ is not `Sendable`, and both forms of `reportNewIncomingVoIPPushPayload` need it
195
+ somewhere concurrent: the completion form runs its callback as `@Sendable`, and
196
+ the async form needs a `Task` whose closure Swift 6 rejects for capturing the
197
+ handler. The `nonisolated(unsafe)` copy lets the `@Sendable` callback hold it. A failed report turns
198
+ into a missed-call notification; a successful one is suppressed with empty
199
+ content. If the server does know the push is a call, skip all of this and use
200
+ an ordinary PushKit VoIP push. Entitlement required for the extension:
201
+ `com.apple.developer.usernotifications.filtering`.
354
202
 
355
- ## Call Directory Incremental Updates
203
+ ## Incremental Call Directory updates
356
204
 
357
- After the first full load, use incremental updates to add or remove entries
358
- without reloading the entire dataset:
205
+ Once the initial complete load has run, the extension can add and remove individual numbers
206
+ instead of rebuilding everything.
359
207
 
360
208
  ```swift
361
- private func addOrRemoveIncrementalEntries(
362
- to context: CXCallDirectoryExtensionContext
363
- ) {
364
- let removedNumbers: [CXCallDirectoryPhoneNumber] = fetchRemovedNumbers()
365
- for number in removedNumbers {
366
- context.removeBlockingEntry(withPhoneNumber: number)
367
- context.removeIdentificationEntry(withPhoneNumber: number)
368
- }
369
-
370
- let newBlocked: [CXCallDirectoryPhoneNumber] = fetchNewBlockedNumbers()
371
- for number in newBlocked.sorted() {
372
- context.addBlockingEntry(withNextSequentialPhoneNumber: number)
373
- }
374
-
375
- let newIdentified: [(CXCallDirectoryPhoneNumber, String)] = fetchNewIdentified()
376
- for (number, label) in newIdentified.sorted(by: { $0.0 < $1.0 }) {
377
- context.addIdentificationEntry(
378
- withNextSequentialPhoneNumber: number,
379
- label: label
380
- )
209
+ extension SpamListProvider {
210
+ func applyChanges(to context: CXCallDirectoryExtensionContext) {
211
+ let delta = SharedStore.pendingDelta()
212
+ for number in delta.unblocked {
213
+ context.removeBlockingEntry(withPhoneNumber: number)
214
+ }
215
+ for number in delta.unlabeled {
216
+ context.removeIdentificationEntry(withPhoneNumber: number)
217
+ }
218
+ for number in delta.blocked.sorted() {
219
+ context.addBlockingEntry(withNextSequentialPhoneNumber: number)
220
+ }
221
+ for pair in delta.labeled.sorted(by: { $0.key < $1.key }) {
222
+ context.addIdentificationEntry(withNextSequentialPhoneNumber: pair.key, label: pair.value)
223
+ }
224
+ SharedStore.clearDelta()
381
225
  }
382
226
  }
383
227
  ```
384
228
 
385
- Call Directory data is bulk data. The system calls `beginRequest(with:)` when
386
- loading the extension, not for each individual incoming call, so keep web
387
- lookups and dataset sync in the containing app before reloading the extension.
388
-
389
- ## Testing VoIP Locally
229
+ Additions are sorted before they are added. The system runs
230
+ `beginRequest(with:)` when it loads the extension, never per incoming call, so
231
+ any web lookup and dataset sync happens in the containing app before it calls
232
+ `reloadExtension(withIdentifier:)`.
390
233
 
391
- ### Simulating VoIP Pushes
234
+ ## Testing VoIP locally
392
235
 
393
- Use the Push Notifications Console or a command-line tool to send test pushes.
394
- The payload must target the VoIP topic (`<bundle-id>.voip`):
236
+ - Fire test pushes with the Push Notifications Console, or with any APNs
237
+ client you run from a terminal. The topic is the bundle identifier with `.voip` appended, for example
238
+ `com.example.dialer.voip`.
239
+ - A test payload needs only an empty `aps` plus your own keys:
395
240
 
396
241
  ```json
397
242
  {
398
- "aps": {},
399
- "handle": "+15551234567",
400
- "callerName": "Test Caller",
401
- "hasVideo": false
243
+ "aps": {},
244
+ "from": "+14155550123",
245
+ "display": "Test Caller",
246
+ "video": false
402
247
  }
403
248
  ```
404
249
 
405
- ### Testing Without a Server
406
-
407
- For development, you can bypass PushKit and directly call the incoming call
408
- reporting method:
250
+ - Without a server, a debug-only helper can call the incoming report directly:
409
251
 
410
252
  ```swift
411
253
  #if DEBUG
412
- func simulateIncomingCall() {
413
- let uuid = UUID()
414
- Task {
415
- try? await CallManager.shared.reportIncomingCall(
416
- uuid: uuid,
417
- handle: "+15551234567",
418
- hasVideo: false
419
- )
254
+ extension Switchboard {
255
+ func simulateIncomingCall() async {
256
+ try? await reportIncoming(id: UUID(), address: "+14155550123", name: "Test Caller")
420
257
  }
421
258
  }
422
259
  #endif
423
260
  ```
424
261
 
425
- ### Checking Extension Status
426
-
427
- Verify that the Call Directory extension is enabled:
262
+ - Check the Call Directory extension state from the app:
428
263
 
429
264
  ```swift
430
- CXCallDirectoryManager.sharedInstance.getEnabledStatusForExtension(
431
- withIdentifier: "com.example.app.CallDirectory"
432
- ) { status, error in
433
- switch status {
434
- case .enabled:
435
- print("Extension is enabled")
436
- case .disabled:
437
- print("Extension is disabled -- prompt user to enable in Settings")
438
- case .unknown:
439
- print("Status unknown")
440
- @unknown default:
441
- break
265
+ func checkBlockerStatus() {
266
+ let manager = CXCallDirectoryManager.sharedInstance
267
+ manager.getEnabledStatusForExtension(withIdentifier: "org.sample.dialer.blocker") { state, failure in
268
+ switch state {
269
+ case .enabled: Log.calls.info("blocker active")
270
+ case .disabled: Log.calls.info("ask the user to enable it in Settings")
271
+ case .unknown: Log.calls.info("status unknown: \(String(describing: failure))")
272
+ @unknown default: break
273
+ }
442
274
  }
443
275
  }
444
276
  ```
@@ -2,6 +2,7 @@
2
2
  name: ci-cd-pipelines
3
3
  description: "CI/CD pipelines: GitHub Actions workflows, Docker multi-stage builds, environment management, secret management, deployment strategies. Use when setting up or fixing a build, test or deploy pipeline."
4
4
  metadata:
5
+ source: multi-agent-pipeline
5
6
  tags: [ci-cd, github-actions, docker, deployment, devops, backend]
6
7
  version: "2025.1"
7
8
  ---