@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,500 +1,468 @@
1
1
  ---
2
2
  name: pdfkit
3
- description: "Display and manipulate PDF documents using PDFKit. Use when embedding PDFView to show PDF files, creating or modifying PDFDocument instances, adding annotations (highlights, notes, signature widgets), extracting text with PDFSelection, navigating pages, generating thumbnails, filling PDF forms, or wrapping PDFView in SwiftUI."
3
+ description: "PDFKit on iOS: PDFView display and SwiftUI wrapping, creating and editing PDFDocument and PDFPage, highlight, note, signature and form annotations, PDFSelection search and text extraction, page navigation, thumbnails, form filling, encrypted saving. Use when an app displays, searches, annotates, fills, builds or saves PDFs."
4
4
  metadata:
5
- source: "dpearson2699/swift-ios-skills (PolyForm Perimeter 1.0.0)"
5
+ source: multi-agent-pipeline
6
6
  ---
7
- # PDFKit
8
7
 
9
- Display, navigate, search, annotate, and manipulate PDF documents with `PDFView`, `PDFDocument`, `PDFPage`, `PDFAnnotation`, and `PDFSelection`. Targets Swift 6.3 / iOS 26+.
8
+ # PDFKit
10
9
 
11
- ## Contents
10
+ PDFKit renders, searches and edits PDF files. Most work touches five types:
11
+ `PDFView` (the on-screen viewer), `PDFDocument` (the file), `PDFPage` (one
12
+ page), `PDFAnnotation` (marks and form fields on a page) and `PDFSelection`
13
+ (a run of text). Examples target Swift 6.3 and iOS 26.
12
14
 
13
- - [Setup](#setup)
14
- - [Displaying PDFs](#displaying-pdfs)
15
- - [Loading Documents](#loading-documents)
16
- - [Page Navigation](#page-navigation)
17
- - [Text Search and Selection](#text-search-and-selection)
18
- - [Annotations](#annotations)
19
- - [Thumbnails](#thumbnails)
20
- - [SwiftUI Integration](#swiftui-integration)
21
- - [Common Mistakes](#common-mistakes)
22
- - [Review Checklist](#review-checklist)
23
- - [References](#references)
15
+ Freehand drawing tools are not PDFKit work: use PencilKit or PaperKit.
24
16
 
25
17
  ## Setup
26
18
 
27
- PDFKit requires no entitlements or Info.plist entries.
19
+ No entitlement and no Info.plist key is needed.
28
20
 
29
21
  ```swift
30
22
  import PDFKit
31
23
  ```
32
24
 
33
- **Platform availability:** iOS 11+, iPadOS 11+, Mac Catalyst 13.1+, macOS 10.4+, tvOS 11+, visionOS 1.0+.
25
+ | Platform | Minimum |
26
+ |---|---|
27
+ | iOS, iPadOS | 11 |
28
+ | Mac Catalyst | 13.1 |
29
+ | macOS | 10.4 |
30
+ | tvOS | 11 |
31
+ | visionOS | 1.0 |
34
32
 
35
- ## Displaying PDFs
33
+ ## Showing a PDF
36
34
 
37
- `PDFView` is a `UIView` subclass that renders PDF content, handles zoom,
38
- scroll, text selection, and page navigation out of the box.
35
+ `PDFView` is a `UIView` subclass. Out of the box it zooms, scrolls, selects text
36
+ and pages through the document.
39
37
 
40
38
  ```swift
41
39
  import PDFKit
42
40
  import UIKit
43
41
 
44
- class PDFViewController: UIViewController {
45
- let pdfView = PDFView()
42
+ final class ManualViewController: UIViewController {
43
+ private let reader = PDFView()
46
44
 
47
45
  override func viewDidLoad() {
48
46
  super.viewDidLoad()
49
- pdfView.frame = view.bounds
50
- pdfView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
51
- view.addSubview(pdfView)
52
-
53
- pdfView.autoScales = true
54
- pdfView.displayMode = .singlePageContinuous
55
- pdfView.displayDirection = .vertical
56
-
57
- if let url = Bundle.main.url(forResource: "sample", withExtension: "pdf") {
58
- pdfView.document = PDFDocument(url: url)
47
+ reader.frame = view.bounds
48
+ reader.autoresizingMask = [.flexibleWidth, .flexibleHeight]
49
+ reader.autoScales = true
50
+ reader.displayMode = .singlePageContinuous
51
+ reader.displayDirection = .vertical
52
+ view.addSubview(reader)
53
+
54
+ if let url = Bundle.main.url(forResource: "assembly-guide", withExtension: "pdf"),
55
+ let file = PDFDocument(url: url) {
56
+ reader.document = file
59
57
  }
60
58
  }
61
59
  }
62
60
  ```
63
61
 
64
- ### Display Modes
62
+ ### Display modes
65
63
 
66
- | Mode | Behavior |
64
+ | Mode | Layout |
67
65
  |---|---|
68
- | `.singlePage` | One page at a time |
69
- | `.singlePageContinuous` | Pages stacked vertically, scrollable |
70
- | `.twoUp` | Two pages side by side |
71
- | `.twoUpContinuous` | Two-up with continuous scrolling |
66
+ | `.singlePage` | one page on screen at a time |
67
+ | `.singlePageContinuous` | one column of pages, scrolling |
68
+ | `.twoUp` | facing pages side by side |
69
+ | `.twoUpContinuous` | facing pages, scrolling |
72
70
 
73
- ### Scaling and Appearance
71
+ ### Scale and look
74
72
 
75
73
  ```swift
76
- pdfView.autoScales = true
77
- pdfView.minScaleFactor = pdfView.scaleFactorForSizeToFit
78
- pdfView.maxScaleFactor = 4.0
74
+ import PDFKit
79
75
 
80
- pdfView.displaysPageBreaks = true
81
- pdfView.pageShadowsEnabled = true
82
- pdfView.interpolationQuality = .high
76
+ @MainActor
77
+ func tune(_ reader: PDFView) {
78
+ reader.autoScales = true
79
+ reader.minScaleFactor = reader.scaleFactorForSizeToFit
80
+ reader.maxScaleFactor = 5.0
81
+ reader.displaysPageBreaks = true
82
+ reader.pageShadowsEnabled = false
83
+ reader.interpolationQuality = .high
84
+ }
83
85
  ```
84
86
 
85
- ## Loading Documents
87
+ ## Loading documents
86
88
 
87
- `PDFDocument` loads from a URL, `Data`, or can be created empty.
89
+ There are three initializers: `PDFDocument(url:)`, `PDFDocument(data:)` and
90
+ the empty `PDFDocument()`. The first two are failable.
88
91
 
89
- ```swift
90
- let fileDoc = PDFDocument(url: fileURL)
91
- let dataDoc = PDFDocument(data: pdfData)
92
- let emptyDoc = PDFDocument()
93
- ```
94
-
95
- ### Password-Protected PDFs
92
+ ### Locked files
96
93
 
97
94
  ```swift
98
- guard let document = PDFDocument(url: url) else { return }
99
- if document.isLocked {
100
- if !document.unlock(withPassword: userPassword) {
101
- // Show password prompt
102
- }
95
+ import PDFKit
96
+
97
+ func open(_ file: PDFDocument, passcode: String) -> Bool {
98
+ guard file.isLocked else { return true }
99
+ return file.unlock(withPassword: passcode)
103
100
  }
104
101
  ```
105
102
 
106
- ### Saving and Page Manipulation
103
+ If `unlock(withPassword:)` returns `false`, ask the user for the password again.
104
+
105
+ ### Saving and rearranging pages
107
106
 
108
107
  ```swift
109
- document.write(to: outputURL)
110
- document.write(to: outputURL, withOptions: [
111
- .ownerPasswordOption: "ownerPass", .userPasswordOption: "userPass"
112
- ])
113
- let data = document.dataRepresentation()
114
-
115
- // Pages are zero-based. Validate indices; out-of-range calls raise exceptions.
116
- let count = document.pageCount
117
- document.insert(PDFPage(), at: count)
118
- if document.pageCount > 2 {
119
- document.removePage(at: 2)
108
+ import PDFKit
109
+
110
+ func export(_ file: PDFDocument, to url: URL, ownerKey: String, readerKey: String) -> Bool {
111
+ file.write(to: url, withOptions: [
112
+ .ownerPasswordOption: ownerKey,
113
+ .userPasswordOption: readerKey
114
+ ])
120
115
  }
121
- if document.pageCount > 3 {
122
- document.exchangePage(at: 0, withPageAt: 3)
116
+
117
+ func reorder(_ file: PDFDocument) {
118
+ let blank = PDFPage()
119
+ file.insert(blank, at: file.pageCount)
120
+ if file.pageCount > 2 {
121
+ file.exchangePage(at: 0, withPageAt: 2)
122
+ }
123
+ if file.pageCount > 1 {
124
+ file.removePage(at: 1)
125
+ }
123
126
  }
124
127
  ```
125
128
 
126
- ## Page Navigation
127
-
128
- `PDFView` provides built-in navigation with history tracking.
129
-
130
- ```swift
131
- // Go to a specific page
132
- let pageIndex = 5
133
- if let document = pdfView.document,
134
- pageIndex >= 0,
135
- pageIndex < document.pageCount,
136
- let page = document.page(at: pageIndex) {
137
- pdfView.go(to: page)
138
- }
129
+ - `write(to:)` saves as is; `write(to:withOptions:)` with
130
+ `.ownerPasswordOption` and `.userPasswordOption` encrypts.
131
+ - `dataRepresentation()` returns `Data?` for upload or sharing.
132
+ - Page indices start at 0. Inserting at `pageCount` appends.
133
+ - An index outside `0..<pageCount` raises an Objective-C exception rather than
134
+ returning `nil`, so check it before `page(at:)`, `insert(_:at:)`,
135
+ `removePage(at:)` or `exchangePage(at:withPageAt:)`.
139
136
 
140
- // Sequential navigation
141
- pdfView.goToNextPage(nil)
142
- pdfView.goToPreviousPage(nil)
143
- pdfView.goToFirstPage(nil)
144
- pdfView.goToLastPage(nil)
137
+ ## Navigating
145
138
 
146
- // Check navigation state
147
- if pdfView.canGoToNextPage { /* ... */ }
139
+ `PDFView` keeps its own history of where the user has been.
148
140
 
149
- // History navigation
150
- if pdfView.canGoBack { pdfView.goBack(nil) }
141
+ ```swift
142
+ import PDFKit
151
143
 
152
- // Go to a specific point on the current page
153
- if let page = pdfView.currentPage {
154
- let destination = PDFDestination(page: page, at: CGPoint(x: 0, y: 500))
155
- pdfView.go(to: destination)
144
+ @MainActor
145
+ func show(pageNumber index: Int, in reader: PDFView) {
146
+ guard let file = reader.document, index >= 0, index < file.pageCount,
147
+ let target = file.page(at: index) else { return }
148
+ reader.go(to: target)
156
149
  }
157
- ```
158
150
 
159
- ### Observing Page Changes
151
+ @MainActor
152
+ func stepThrough(_ reader: PDFView) {
153
+ if reader.canGoToNextPage { reader.goToNextPage(nil) }
154
+ reader.goToPreviousPage(nil)
155
+ reader.goToFirstPage(nil)
156
+ reader.goToLastPage(nil)
157
+ if reader.canGoBack { reader.goBack(nil) }
158
+ }
160
159
 
161
- ```swift
162
- NotificationCenter.default.addObserver(
163
- self, selector: #selector(pageChanged),
164
- name: .PDFViewPageChanged, object: pdfView
165
- )
166
-
167
- @objc func pageChanged(_ notification: Notification) {
168
- guard let page = pdfView.currentPage,
169
- let doc = pdfView.document else { return }
170
- let index = doc.index(for: page)
171
- pageLabel.text = "Page \(index + 1) of \(doc.pageCount)"
160
+ @MainActor
161
+ func jump(to point: CGPoint, on page: PDFPage, in reader: PDFView) {
162
+ reader.go(to: PDFDestination(page: page, at: point))
163
+ _ = reader.currentPage
172
164
  }
173
165
  ```
174
166
 
175
- ## Text Search and Selection
176
-
177
- ### Synchronous Search
167
+ ### Tracking the current page
178
168
 
179
169
  ```swift
180
- let results: [PDFSelection] = document.findString(
181
- "search term", withOptions: [.caseInsensitive]
182
- )
170
+ import PDFKit
171
+
172
+ @MainActor
173
+ func watchPages(of reader: PDFView, update: @escaping @MainActor @Sendable (String) -> Void) -> NSObjectProtocol {
174
+ NotificationCenter.default.addObserver(forName: .PDFViewPageChanged, object: reader, queue: .main) { _ in
175
+ MainActor.assumeIsolated {
176
+ guard let file = reader.document, let page = reader.currentPage else { return }
177
+ update("\(file.index(for: page) + 1) / \(file.pageCount)")
178
+ }
179
+ }
180
+ }
183
181
  ```
184
182
 
185
- ### Asynchronous Search
183
+ ## Search and text
186
184
 
187
- Use `PDFDocumentDelegate` for background searches on large documents.
188
- Implement `didMatchString(_:)` to receive each match and
189
- `documentDidEndDocumentFind(_:)` for completion.
185
+ ### Synchronous
190
186
 
191
- ### Incremental Search and Find Interaction
187
+ `findString(_:withOptions:)` returns every match as `[PDFSelection]`:
192
188
 
193
189
  ```swift
194
- // Find next match from current selection
195
- let next = document.findString("term", fromSelection: current, withOptions: [.caseInsensitive])
190
+ import PDFKit
196
191
 
197
- // System find bar (iOS 16+)
198
- pdfView.isFindInteractionEnabled = true
192
+ func matches(of term: String, in file: PDFDocument) -> [PDFSelection] {
193
+ file.findString(term, withOptions: [.caseInsensitive])
194
+ }
199
195
  ```
200
196
 
201
- ### Text Extraction
197
+ ### Asynchronous
198
+
199
+ For long documents, search in the background with `beginFindString(_:withOptions:)`
200
+ and a `PDFDocumentDelegate`. `didMatchString(_:)` is called per hit and
201
+ `documentDidEndDocumentFind(_:)` when the pass finishes.
202
202
 
203
203
  ```swift
204
- let fullText = document.string // Entire document
205
- let firstPage = document.pageCount > 0 ? document.page(at: 0) : nil
206
- let pageText = firstPage?.string // Single page
207
- let attributed = firstPage?.attributedString // With formatting
208
-
209
- // Region-based extraction
210
- if let page = firstPage {
211
- let selection = page.selection(for: CGRect(x: 50, y: 50, width: 400, height: 200))
212
- let text = selection?.string
213
- }
214
- ```
204
+ import PDFKit
215
205
 
216
- ### Highlighting Search Results
206
+ final class ContractSearch: NSObject, PDFDocumentDelegate {
207
+ private(set) var hits: [PDFSelection] = []
208
+ var onFinish: (([PDFSelection]) -> Void)?
217
209
 
218
- ```swift
219
- let results = document.findString("important", withOptions: [.caseInsensitive])
220
- for selection in results { selection.color = .yellow }
221
- pdfView.highlightedSelections = results
210
+ func run(_ term: String, in file: PDFDocument) {
211
+ hits.removeAll()
212
+ file.delegate = self
213
+ file.beginFindString(term, withOptions: [.caseInsensitive])
214
+ }
222
215
 
223
- if let first = results.first {
224
- pdfView.setCurrentSelection(first, animate: true)
225
- pdfView.go(to: first)
216
+ func didMatchString(_ instance: PDFSelection) {
217
+ hits.append(instance)
218
+ }
219
+
220
+ func documentDidEndDocumentFind(_ notification: Notification) {
221
+ onFinish?(hits)
222
+ }
226
223
  }
227
224
  ```
228
225
 
229
- ## Annotations
226
+ ### Next match and the system find bar
230
227
 
231
- Annotations are created with `PDFAnnotation(bounds:forType:withProperties:)`
232
- and added to a `PDFPage`.
228
+ - `findString(_:fromSelection:withOptions:)` returns the first hit after a
229
+ given selection, which is how "Find next" works.
230
+ - `reader.isFindInteractionEnabled = true` turns on the system find bar
231
+ (iOS 16+).
233
232
 
234
- ### Highlight Annotation
233
+ ### Extracting text
235
234
 
236
235
  ```swift
237
- func addHighlight(to page: PDFPage, selection: PDFSelection) {
238
- let highlight = PDFAnnotation(
239
- bounds: selection.bounds(for: page),
240
- forType: .highlight, withProperties: nil
241
- )
242
- highlight.color = UIColor.yellow.withAlphaComponent(0.5)
243
- page.addAnnotation(highlight)
236
+ import PDFKit
237
+
238
+ func textSamples(from file: PDFDocument) -> (all: String?, first: String?, box: String?) {
239
+ let all = file.string
240
+ guard file.pageCount > 0, let first = file.page(at: 0) else { return (all, nil, nil) }
241
+ _ = first.attributedString
242
+ let box = first.selection(for: CGRect(x: 36, y: 700, width: 300, height: 60))?.string
243
+ return (all, first.string, box)
244
244
  }
245
245
  ```
246
246
 
247
- ### Text Note Annotation
248
-
249
- ```swift
250
- let note = PDFAnnotation(
251
- bounds: CGRect(x: 100, y: 700, width: 30, height: 30),
252
- forType: .text, withProperties: nil
253
- )
254
- note.contents = "This is a sticky note."
255
- note.color = .systemYellow
256
- note.iconType = .comment
257
- page.addAnnotation(note)
258
- ```
247
+ `document.string` is the whole document, `page.string` one page,
248
+ `page.attributedString` keeps fonts and styles, and `page.selection(for:)`
249
+ limits extraction to a rectangle. Check `pageCount > 0` before asking for
250
+ page 0.
259
251
 
260
- ### Free Text Annotation
252
+ ### Highlighting hits
261
253
 
262
254
  ```swift
263
- let freeText = PDFAnnotation(
264
- bounds: CGRect(x: 50, y: 600, width: 300, height: 40),
265
- forType: .freeText, withProperties: nil
266
- )
267
- freeText.contents = "Added commentary"
268
- freeText.font = UIFont.systemFont(ofSize: 14)
269
- freeText.fontColor = .darkGray
270
- page.addAnnotation(freeText)
255
+ import PDFKit
256
+
257
+ @MainActor
258
+ func mark(_ hits: [PDFSelection], in reader: PDFView) {
259
+ for hit in hits { hit.color = .systemOrange }
260
+ reader.highlightedSelections = hits
261
+ if let firstHit = hits.first {
262
+ reader.setCurrentSelection(firstHit, animate: true)
263
+ reader.go(to: firstHit)
264
+ }
265
+ }
271
266
  ```
272
267
 
273
- ### Link Annotation
268
+ ## Annotations
269
+
270
+ Create an annotation with `PDFAnnotation(bounds:forType:withProperties:)` and
271
+ attach it with `page.addAnnotation(_:)`.
274
272
 
275
273
  ```swift
276
- let link = PDFAnnotation(
277
- bounds: CGRect(x: 50, y: 500, width: 200, height: 20),
278
- forType: .link, withProperties: nil
279
- )
280
- link.url = URL(string: "https://example.com")
281
- page.addAnnotation(link)
282
-
283
- // Internal page link
284
- link.destination = PDFDestination(page: targetPage, at: .zero)
285
- ```
274
+ import PDFKit
275
+ import UIKit
286
276
 
287
- ### Removing Annotations
277
+ func annotate(_ page: PDFPage, hit: PDFSelection, target: PDFPage) {
278
+ let marker = PDFAnnotation(bounds: hit.bounds(for: page), forType: .highlight, withProperties: nil)
279
+ marker.color = UIColor.systemGreen.withAlphaComponent(0.5)
280
+ page.addAnnotation(marker)
281
+
282
+ let note = PDFAnnotation(bounds: CGRect(x: 40, y: 40, width: 24, height: 24), forType: .text, withProperties: nil)
283
+ note.contents = "Check this total"
284
+ note.color = .systemBlue
285
+ note.iconType = .comment
286
+ page.addAnnotation(note)
287
+
288
+ let label = PDFAnnotation(bounds: CGRect(x: 72, y: 120, width: 220, height: 30), forType: .freeText, withProperties: nil)
289
+ label.contents = "Approved"
290
+ label.font = .boldSystemFont(ofSize: 16)
291
+ label.fontColor = .systemRed
292
+ page.addAnnotation(label)
293
+
294
+ let web = PDFAnnotation(bounds: CGRect(x: 72, y: 170, width: 160, height: 20), forType: .link, withProperties: nil)
295
+ web.url = URL(string: "https://example.org/terms")
296
+ page.addAnnotation(web)
297
+
298
+ let internalJump = PDFAnnotation(bounds: CGRect(x: 72, y: 200, width: 160, height: 20), forType: .link, withProperties: nil)
299
+ internalJump.destination = PDFDestination(page: target, at: CGPoint(x: 0, y: 792))
300
+ page.addAnnotation(internalJump)
301
+ }
288
302
 
289
- ```swift
290
- for annotation in page.annotations {
291
- page.removeAnnotation(annotation)
303
+ func stripMarkup(from page: PDFPage) {
304
+ for item in page.annotations {
305
+ page.removeAnnotation(item)
306
+ }
292
307
  }
293
308
  ```
294
309
 
295
- Common subtypes include `.highlight`, `.underline`, `.strikeOut`, `.text`,
296
- `.freeText`, `.ink`, `.link`, `.line`, `.square`, `.circle`, `.stamp`, and
310
+ Commonly used subtypes: `.highlight`, `.underline`, `.strikeOut`, `.text`,
311
+ `.freeText`, `.ink`, `.link`, `.line`, `.square`, `.circle`, `.stamp`,
297
312
  `.widget`.
298
313
 
299
314
  ## Thumbnails
300
315
 
301
316
  ### PDFThumbnailView
302
317
 
303
- `PDFThumbnailView` shows a strip of page thumbnails linked to a `PDFView`.
318
+ `PDFThumbnailView` shows a strip of page previews. Point its `pdfView` at the
319
+ main viewer so taps navigate and the current page is highlighted.
304
320
 
305
321
  ```swift
306
- let thumbnailView = PDFThumbnailView()
307
- thumbnailView.pdfView = pdfView
308
- thumbnailView.thumbnailSize = CGSize(width: 60, height: 80)
309
- thumbnailView.layoutMode = .vertical
310
- thumbnailView.translatesAutoresizingMaskIntoConstraints = false
311
- view.addSubview(thumbnailView)
322
+ import PDFKit
323
+
324
+ @MainActor
325
+ func makeStrip(for reader: PDFView) -> PDFThumbnailView {
326
+ let strip = PDFThumbnailView()
327
+ strip.pdfView = reader
328
+ strip.thumbnailSize = CGSize(width: 48, height: 64)
329
+ strip.layoutMode = .vertical
330
+ return strip
331
+ }
312
332
  ```
313
333
 
314
- ### Generating Thumbnails Programmatically
334
+ ### Generating images
315
335
 
316
336
  ```swift
317
- let thumbnail = page.thumbnail(of: CGSize(width: 120, height: 160), for: .mediaBox)
337
+ import PDFKit
338
+ import UIKit
318
339
 
319
- // All pages
320
- let thumbnails = (0..<document.pageCount).compactMap {
321
- document.page(at: $0)?.thumbnail(of: CGSize(width: 120, height: 160), for: .mediaBox)
340
+ func previews(of file: PDFDocument) -> [UIImage] {
341
+ let size = CGSize(width: 120, height: 160)
342
+ let cover = file.page(at: 0)?.thumbnail(of: size, for: .mediaBox)
343
+ _ = cover
344
+ return (0..<file.pageCount).compactMap { file.page(at: $0)?.thumbnail(of: size, for: .mediaBox) }
322
345
  }
323
346
  ```
324
347
 
325
- ## SwiftUI Integration
348
+ ## SwiftUI
326
349
 
327
- Wrap `PDFView` in a `UIViewRepresentable` for SwiftUI. PDF-specific wrappers
328
- that configure `PDFView`, pages, annotations, search, thumbnails, or overlays
329
- belong in this skill; route only generic representable lifecycle, layout, or SwiftUI state architecture questions to SwiftUI/UIKit interop guidance.
350
+ Wrap `PDFView` in a `UIViewRepresentable`. Wrappers that configure the viewer,
351
+ move between pages, manage annotations, search, show thumbnails or install
352
+ overlays belong to this skill. Only generic representable questions (lifecycle,
353
+ sizing, state architecture) go to `swiftui-uikit-interop`.
330
354
 
331
355
  ```swift
332
- import SwiftUI
333
356
  import PDFKit
357
+ import SwiftUI
334
358
 
335
- struct PDFKitView: UIViewRepresentable {
359
+ struct PDFReader: UIViewRepresentable {
336
360
  let document: PDFDocument
337
361
 
338
362
  func makeUIView(context: Context) -> PDFView {
339
- let pdfView = PDFView()
340
- pdfView.autoScales = true
341
- pdfView.displayMode = .singlePageContinuous
342
- pdfView.document = document
343
- return pdfView
363
+ let reader = PDFView()
364
+ reader.autoScales = true
365
+ reader.displayMode = .singlePageContinuous
366
+ reader.document = document
367
+ return reader
344
368
  }
345
369
 
346
- func updateUIView(_ pdfView: PDFView, context: Context) {
347
- if pdfView.document !== document {
348
- pdfView.document = document
370
+ func updateUIView(_ reader: PDFView, context: Context) {
371
+ if reader.document !== document {
372
+ reader.document = document
349
373
  }
350
374
  }
351
375
  }
352
- ```
353
-
354
- ### Usage
355
376
 
356
- ```swift
357
- struct DocumentScreen: View {
358
- let url: URL
377
+ struct InvoiceScreen: View {
378
+ let fileURL: URL
359
379
 
360
380
  var body: some View {
361
- if let document = PDFDocument(url: url) {
362
- PDFKitView(document: document)
381
+ if let file = PDFDocument(url: fileURL) {
382
+ PDFReader(document: file)
363
383
  .ignoresSafeArea()
364
384
  } else {
365
- ContentUnavailableView("Unable to load PDF", systemImage: "doc.questionmark")
385
+ ContentUnavailableView("Cannot open invoice", systemImage: "doc.questionmark")
366
386
  }
367
387
  }
368
388
  }
369
389
  ```
370
390
 
371
- For interactive wrappers with page tracking, annotation hit detection, and
372
- coordinator patterns, see [references/pdfkit-patterns.md](references/pdfkit-patterns.md).
391
+ A version that binds the current page, reports annotation taps and uses a
392
+ coordinator is in [the patterns reference](references/pdfkit-patterns.md#coordinator-based-swiftui-wrapper).
373
393
 
374
- ### Page Overlays (iOS 16+)
394
+ ### Page overlays (iOS 16+)
375
395
 
376
- `PDFPageOverlayViewProvider` places UIKit views on top of individual pages
377
- for interactive controls or custom rendering beyond standard annotations.
396
+ `PDFPageOverlayViewProvider` places a UIKit view above each page, for
397
+ interactive controls or custom drawing. Implement
398
+ `pdfView(_:overlayViewFor:) -> UIView?` and assign the provider to
399
+ `pdfView.pageOverlayViewProvider`. That property is weak, so something else
400
+ must keep the provider alive.
378
401
 
379
402
  ```swift
380
- class OverlayProvider: NSObject, PDFPageOverlayViewProvider {
403
+ import PDFKit
404
+ import UIKit
405
+
406
+ @MainActor
407
+ final class StampOverlays: NSObject, @preconcurrency PDFPageOverlayViewProvider {
381
408
  func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? {
382
- let overlay = UIView()
383
- // Add custom subviews
384
- return overlay
409
+ let badge = UILabel()
410
+ badge.text = "DRAFT"
411
+ badge.textColor = .systemRed
412
+ badge.sizeToFit()
413
+ return badge
385
414
  }
386
415
  }
387
416
 
388
- class PDFOverlayController: UIViewController {
389
- let pdfView = PDFView()
390
- private let overlayProvider = OverlayProvider()
417
+ final class DraftViewer: UIViewController {
418
+ private let reader = PDFView()
419
+ private let overlays = StampOverlays()
391
420
 
392
421
  override func viewDidLoad() {
393
422
  super.viewDidLoad()
394
- pdfView.pageOverlayViewProvider = overlayProvider
395
- }
396
- }
397
- ```
398
-
399
- `pageOverlayViewProvider` is weak, so keep the provider strongly owned. For overlay lifecycle and save handling, read [references/pdfkit-patterns.md](references/pdfkit-patterns.md).
400
-
401
- ## Common Mistakes
402
-
403
- ### DON'T: Force-unwrap PDFDocument init
404
-
405
- `PDFDocument(url:)` and `PDFDocument(data:)` are failable initializers.
406
-
407
- ```swift
408
- // WRONG
409
- let document = PDFDocument(url: url)!
410
-
411
- // CORRECT
412
- guard let document = PDFDocument(url: url) else { return }
413
- ```
414
-
415
- ### DON'T: Forget autoScales on PDFView
416
-
417
- Without `autoScales`, the PDF renders at its native resolution.
418
-
419
- ```swift
420
- // WRONG
421
- pdfView.document = document
422
-
423
- // CORRECT
424
- pdfView.autoScales = true
425
- pdfView.document = document
426
- ```
427
-
428
- ### DON'T: Ignore PDF coordinate system in annotations
429
-
430
- PDF page coordinates have origin at the bottom-left with Y increasing
431
- upward -- opposite of UIKit.
432
-
433
- ```swift
434
- // WRONG: UIKit coordinates
435
- let bounds = CGRect(x: 50, y: 50, width: 200, height: 30)
436
-
437
- // CORRECT: PDF coordinates (origin bottom-left)
438
- let pageBounds = page.bounds(for: .mediaBox)
439
- let pdfY = pageBounds.height - 50 - 30
440
- let bounds = CGRect(x: 50, y: pdfY, width: 200, height: 30)
441
- ```
442
-
443
- ### DON'T: Modify annotations on a background thread
444
-
445
- PDFKit classes are not thread-safe.
446
-
447
- ```swift
448
- // WRONG
449
- DispatchQueue.global().async { page.addAnnotation(annotation) }
450
-
451
- // CORRECT
452
- DispatchQueue.main.async { page.addAnnotation(annotation) }
453
- ```
454
-
455
- ### DON'T: Compare PDFDocument with == in UIViewRepresentable
456
-
457
- `PDFDocument` is a reference type. Use identity (`!==`).
458
-
459
- ```swift
460
- // WRONG: Always replaces document
461
- func updateUIView(_ pdfView: PDFView, context: Context) {
462
- pdfView.document = document
463
- }
464
-
465
- // CORRECT
466
- func updateUIView(_ pdfView: PDFView, context: Context) {
467
- if pdfView.document !== document {
468
- pdfView.document = document
423
+ reader.pageOverlayViewProvider = overlays
469
424
  }
470
425
  }
471
426
  ```
472
427
 
473
- ## Review Checklist
474
-
475
- - [ ] `PDFDocument` init uses optional binding, not force-unwrap
476
- - [ ] `pdfView.autoScales = true` set for proper initial display
477
- - [ ] Page indices checked against `pageCount` before access
478
- - [ ] `displayMode` and `displayDirection` configured to match design
479
- - [ ] Annotations use PDF coordinate space (origin bottom-left, Y up)
480
- - [ ] All PDFKit mutations happen on the main thread
481
- - [ ] Password-protected PDFs handled with `isLocked` / `unlock(withPassword:)`
482
- - [ ] SwiftUI wrapper uses `!==` identity check in `updateUIView`
483
- - [ ] `PDFViewPageChanged` notification observed for page tracking
484
- - [ ] `PDFThumbnailView.pdfView` linked to the main `PDFView`
485
- - [ ] Large-document search uses async `beginFindString` with delegate
486
- - [ ] Saved documents use `write(to:withOptions:)` when encryption needed
428
+ ## Common mistakes
429
+
430
+ - **Force-unwrapping the initializers.** `PDFDocument(url:)` and
431
+ `PDFDocument(data:)` return `nil` for a bad file. Use `guard let`.
432
+ - **Forgetting `autoScales`.** Without it, pages appear at their native size.
433
+ - **Using UIKit coordinates on a page.** PDF space starts at the bottom-left and
434
+ y grows upward. To place something at a UIKit-style top offset, compute
435
+ `page.bounds(for: .mediaBox).height - topOffset - itemHeight`.
436
+ - **Mutating from a background queue.** PDFKit classes are not thread-safe.
437
+ Add or change annotations on the main thread.
438
+ - **Reassigning the document in `updateUIView`.** `PDFDocument` is a class;
439
+ compare with `!==` first, otherwise every SwiftUI update reloads the file.
440
+
441
+ ## Review checklist
442
+
443
+ - [ ] `PDFDocument` is created with optional binding
444
+ - [ ] `autoScales = true` is set
445
+ - [ ] Every page index is checked against `pageCount`
446
+ - [ ] `displayMode` and `displayDirection` match the design
447
+ - [ ] Annotation rectangles are in PDF coordinate space
448
+ - [ ] All PDFKit mutation happens on the main thread
449
+ - [ ] Locked files go through `isLocked` and `unlock(withPassword:)`
450
+ - [ ] The SwiftUI wrapper compares documents with `!==` in `updateUIView`
451
+ - [ ] `PDFViewPageChanged` drives any page indicator
452
+ - [ ] `PDFThumbnailView.pdfView` points at the main `PDFView`
453
+ - [ ] Long documents are searched with `beginFindString` and the delegate
454
+ - [ ] `write(to:withOptions:)` is used when the file must be encrypted
487
455
 
488
456
  ## References
489
457
 
490
- - Extended patterns (forms, watermarks, merging, printing, overlays, outlines, custom drawing): [references/pdfkit-patterns.md](references/pdfkit-patterns.md)
491
- - [PDFKit framework](https://sosumi.ai/documentation/pdfkit)
492
- - [PDFView](https://sosumi.ai/documentation/pdfkit/pdfview)
493
- - [PDFDocument](https://sosumi.ai/documentation/pdfkit/pdfdocument)
494
- - [PDFPage](https://sosumi.ai/documentation/pdfkit/pdfpage)
495
- - [PDFAnnotation](https://sosumi.ai/documentation/pdfkit/pdfannotation)
496
- - [PDFSelection](https://sosumi.ai/documentation/pdfkit/pdfselection)
497
- - [PDFThumbnailView](https://sosumi.ai/documentation/pdfkit/pdfthumbnailview)
498
- - [PDFPageOverlayViewProvider](https://sosumi.ai/documentation/pdfkit/pdfpageoverlayviewprovider)
499
- - [Adding Widgets to a PDF Document](https://sosumi.ai/documentation/pdfkit/adding-widgets-to-a-pdf-document)
500
- - [Adding Custom Graphics to a PDF](https://sosumi.ai/documentation/pdfkit/adding-custom-graphics-to-a-pdf)
458
+ - [PDFKit patterns](references/pdfkit-patterns.md) - forms, building PDFs, watermarks, merging and splitting, printing, outlines, custom annotation and page classes, overlay lifecycle, rendering, rotation and crop, burn-in, permissions, coordinator wrapper
459
+ - [PDFKit](https://developer.apple.com/documentation/pdfkit)
460
+ - [PDFView](https://developer.apple.com/documentation/pdfkit/pdfview)
461
+ - [PDFDocument](https://developer.apple.com/documentation/pdfkit/pdfdocument)
462
+ - [PDFPage](https://developer.apple.com/documentation/pdfkit/pdfpage)
463
+ - [PDFAnnotation](https://developer.apple.com/documentation/pdfkit/pdfannotation)
464
+ - [PDFSelection](https://developer.apple.com/documentation/pdfkit/pdfselection)
465
+ - [PDFThumbnailView](https://developer.apple.com/documentation/pdfkit/pdfthumbnailview)
466
+ - [PDFPageOverlayViewProvider](https://developer.apple.com/documentation/pdfkit/pdfpageoverlayviewprovider)
467
+ - [Adding widgets to a PDF document](https://developer.apple.com/documentation/pdfkit/adding-widgets-to-a-pdf-document)
468
+ - [Adding custom graphics to a PDF](https://developer.apple.com/documentation/pdfkit/adding-custom-graphics-to-a-pdf)