@mmerterden/multi-agent-pipeline 20.7.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 (264) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +266 -267
  5. package/package.json +2 -2
  6. package/pipeline/scripts/_notices.mjs +1 -1
  7. package/pipeline/skills/.skill-manifest.json +68 -68
  8. package/pipeline/skills/shared/README.md +70 -70
  9. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  10. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  11. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  12. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  13. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  14. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  15. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  16. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  17. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  18. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  19. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  20. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  21. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  22. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  23. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  24. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  25. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  26. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  27. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  28. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  29. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  30. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  31. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  32. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  33. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  34. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  35. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  36. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  37. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  38. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  39. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  40. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  41. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  42. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  43. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  44. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  45. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  46. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  47. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  48. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  49. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  50. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  51. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  52. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  53. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  54. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  55. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  56. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  57. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  58. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  59. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  60. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  61. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  62. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  63. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  64. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  65. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  66. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  67. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  68. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  69. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  70. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  71. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  72. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  73. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  74. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  75. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  76. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  77. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  78. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  79. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  80. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  81. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  82. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  83. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  84. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  85. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  86. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  87. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  88. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  89. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  90. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  91. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  92. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  93. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  94. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  95. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  96. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  97. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  98. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  99. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  100. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  101. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  102. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  103. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  104. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  105. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  106. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  107. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  108. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  109. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  110. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  111. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  112. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  113. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  114. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  115. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  116. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  117. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  118. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  119. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  120. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  121. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  122. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  123. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  124. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  125. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  126. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  127. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  128. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  129. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  130. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  131. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  132. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  133. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  134. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  135. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  136. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  137. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  138. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  139. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  140. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  141. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  142. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  143. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  144. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  145. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  146. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  147. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  148. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  149. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  150. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  151. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  152. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  153. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  154. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  155. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  156. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  157. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  158. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  159. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  160. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  161. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  162. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  163. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  164. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  165. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  166. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  167. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  168. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  169. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  170. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  171. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  172. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  173. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  174. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  175. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  176. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  177. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  178. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  179. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  180. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  181. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  182. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  183. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  184. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  185. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  186. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  187. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  188. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  189. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  190. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  191. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  192. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  193. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  194. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  195. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  196. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  197. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  198. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  199. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  200. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  201. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  202. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  203. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  204. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  205. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  206. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  207. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  208. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  209. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  210. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  211. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  212. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  213. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  214. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  215. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  216. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  217. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  218. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  219. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  220. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  221. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  222. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  223. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  224. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  225. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  226. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  227. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  228. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  229. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  230. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  231. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  232. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  233. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  234. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  235. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  236. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  237. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  238. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  239. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  240. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  241. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  242. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  243. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  244. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  245. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  246. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  247. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  248. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  249. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  250. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  251. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  252. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  253. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  254. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  255. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  256. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  257. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  258. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  259. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  260. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  261. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  262. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  263. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  264. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,169 +1,204 @@
1
- # Sheets
1
+ # Sheet Routing
2
2
 
3
- ## Contents
3
+ Part of the `swiftui-navigation` skill. Routing every modal through one place
4
+ lets any view open a sheet without threading bindings through its parents, and
5
+ it keeps working as screens are added.
4
6
 
5
- - [Intent](#intent)
6
- - [Core architecture](#core-architecture)
7
- - [Example: SheetDestination enum](#example-sheetdestination-enum)
8
- - [Example: withSheetDestinations modifier](#example-withsheetdestinations-modifier)
9
- - [Example: presenting from a child view](#example-presenting-from-a-child-view)
10
- - [Required wiring](#required-wiring)
11
- - [Example: sheets that need their own navigation](#example-sheets-that-need-their-own-navigation)
12
- - [Design choices to keep](#design-choices-to-keep)
13
- - [iOS 26 Presentation Sizing](#ios-26-presentation-sizing)
14
- - [Pitfalls](#pitfalls)
7
+ ## Building blocks
15
8
 
16
- ## Intent
9
+ - A `SheetDestination` enum, `Identifiable`, with one case per modal.
10
+ - `presentedSheet: SheetDestination?` stored on the router.
11
+ - A modifier, here `withSheetDestinations(sheet:)`, that turns a case into its
12
+ view.
13
+ - The router in the environment, so children assign `presentedSheet` directly.
17
14
 
18
- Use a centralized sheet routing pattern so any view can present modals without prop-drilling. This keeps sheet state in one place and scales as the app grows.
19
-
20
- ## Core architecture
21
-
22
- - Define a `SheetDestination` enum that describes every modal and is `Identifiable`.
23
- - Store the current sheet in a router object (`presentedSheet: SheetDestination?`).
24
- - Create a view modifier like `withSheetDestinations(...)` that maps the enum to concrete sheet views.
25
- - Inject the router into the environment so child views can set `presentedSheet` directly.
26
-
27
- ## Example: SheetDestination enum
15
+ ## The destination enum
28
16
 
29
17
  ```swift
30
- enum SheetDestination: Identifiable, Hashable {
31
- case composer
32
- case editProfile
33
- case settings
34
- case report(itemID: String)
35
-
36
- var id: String {
37
- switch self {
38
- case .composer, .editProfile:
39
- // Use the same id to ensure only one editor-like sheet is active at a time.
40
- return "editor"
41
- case .settings:
42
- return "settings"
43
- case .report:
44
- return "report"
18
+ enum SheetDestination: Hashable, Identifiable {
19
+ case newTrip
20
+ case editTrip(Trip.ID)
21
+ case sharePhoto(Photo.ID)
22
+ case report(itemID: String)
23
+
24
+ var id: String {
25
+ if case .sharePhoto = self { return "share" }
26
+ if case .report = self { return "report" }
27
+ return "trip-editor"
45
28
  }
46
- }
47
29
  }
48
30
  ```
49
31
 
50
- ## Example: withSheetDestinations modifier
32
+ `newTrip` and `editTrip` return the same `id`. They are two ways into one
33
+ editor, so they can never be on screen together.
34
+
35
+ ## The mapping modifier
51
36
 
52
37
  ```swift
53
38
  extension View {
54
- func withSheetDestinations(
55
- sheet: Binding<SheetDestination?>
56
- ) -> some View {
57
- sheet(item: sheet) { destination in
58
- Group {
59
- switch destination {
60
- case .composer:
61
- ComposerView()
62
- case .editProfile:
63
- EditProfileView()
64
- case .settings:
65
- SettingsView()
66
- case .report(let itemID):
67
- ReportView(itemID: itemID)
39
+ func withSheetDestinations(sheet: Binding<SheetDestination?>) -> some View {
40
+ self.sheet(item: sheet) { modal in
41
+ Group {
42
+ switch modal {
43
+ case .newTrip: TripEditor(trip: nil)
44
+ case .editTrip(let id): TripEditor(tripID: id)
45
+ case .sharePhoto(let id): PhotoShareView(photoID: id)
46
+ case .report(let itemID): ReportForm(itemID: itemID)
47
+ }
48
+ }
68
49
  }
69
- }
70
50
  }
71
- }
72
51
  }
73
52
  ```
74
53
 
75
- ## Example: presenting from a child view
54
+ ## Opening a sheet from deep in the tree
76
55
 
77
56
  ```swift
78
- struct StatusRow: View {
79
- @Environment(RouterPath.self) private var router
80
-
81
- var body: some View {
82
- Button("Report") {
83
- router.presentedSheet = .report(itemID: "123")
57
+ struct CommentRow: View {
58
+ @Environment(Router.self) private var router
59
+ let comment: Comment
60
+
61
+ var body: some View {
62
+ Text(comment.body)
63
+ .contextMenu {
64
+ Button("Report", systemImage: "flag") {
65
+ router.presentedSheet = .report(itemID: comment.id)
66
+ }
67
+ }
84
68
  }
85
- }
86
69
  }
87
70
  ```
88
71
 
89
- ## Required wiring
72
+ ## Wiring at the root
73
+
74
+ 1. The parent owns the router instance.
75
+ 2. It installs `withSheetDestinations(sheet: $router.presentedSheet)`; a plain
76
+ `sheet(item:)` does the same job.
77
+ 3. `.environment(router)` comes later in the chain than the sheet modifier, so
78
+ whatever the sheet shows can read the router as well.
90
79
 
91
- For the child view to work, a parent view must:
92
- - own the router instance,
93
- - attach `withSheetDestinations(sheet: $router.presentedSheet)` (or an equivalent `sheet(item:)` handler), and
94
- - inject it with `.environment(router)` after the sheet modifier so the modal content inherits it.
80
+ ```swift
81
+ struct TripsRoot: View {
82
+ @State private var router = Router()
83
+
84
+ var body: some View {
85
+ NavigationStack(path: $router.path) { TripsList().withAppRouter() }
86
+ .withSheetDestinations(sheet: $router.presentedSheet)
87
+ .environment(router)
88
+ }
89
+ }
90
+ ```
95
91
 
96
- This makes the child assignment to `router.presentedSheet` drive presentation at the root.
92
+ With that in place, a child that sets `presentedSheet` makes the root present
93
+ the sheet.
97
94
 
98
- ## Example: sheets that need their own navigation
95
+ ## Sheets that push their own screens
99
96
 
100
- Wrap sheet content in a `NavigationStack` so it can push within the modal.
97
+ Wrap the content in a stack with a close button when a sheet needs its own
98
+ navigation.
101
99
 
102
100
  ```swift
103
101
  struct NavigationSheet<Content: View>: View {
104
- var content: () -> Content
105
-
106
- var body: some View {
107
- NavigationStack {
108
- content()
109
- .toolbar { CloseToolbarItem() }
102
+ @ViewBuilder var content: Content
103
+ @Environment(\.dismiss) private var close
104
+
105
+ var body: some View {
106
+ NavigationStack {
107
+ content
108
+ .toolbar {
109
+ ToolbarItem(placement: .cancellationAction) {
110
+ Button("Close", systemImage: "xmark") { close() }
111
+ }
112
+ }
113
+ }
110
114
  }
111
- }
112
115
  }
113
116
  ```
114
117
 
115
- ## Design choices to keep
118
+ ## Rules worth keeping
116
119
 
117
- - Centralize sheet routing so features can present modals without wiring bindings through many layers.
118
- - Use `sheet(item:)` to guarantee a single sheet is active and to drive presentation from the enum.
119
- - Group related sheets under the same `id` when they are mutually exclusive (e.g., editor flows).
120
- - Keep sheet views lightweight and composed from smaller views; avoid large monoliths.
120
+ - Route sheets centrally so features do not pass bindings through layers.
121
+ - `sheet(item:)` keeps exactly one sheet active, chosen by the enum.
122
+ - Mutually exclusive sheets share an `id`.
123
+ - Sheet views stay small and composed from pieces.
121
124
 
122
- ## iOS 26 Presentation Sizing
125
+ ## Presentation sizing
123
126
 
124
- Control sheet dimensions with `presentationSizing(_:)` (iOS 18+):
127
+ The section concerns iOS 26 layouts, but `presentationSizing(_:)` itself is
128
+ available from iOS 18. Values: `.automatic`, `.page`, `.form`, `.fitted`.
129
+ `.fitted(horizontal:vertical:)` fits only the axes you pass, and
130
+ `.sticky(horizontal:vertical:)` lets the sheet grow along them without
131
+ shrinking.
125
132
 
126
133
  ```swift
127
- .sheet(item: $selectedItem) { item in
128
- EditItemSheet(item: item)
129
- .presentationSizing(.form)
130
- }
134
+ TripEditor(trip: nil)
135
+ .presentationSizing(.form.sticky(horizontal: false, vertical: true))
131
136
  ```
132
137
 
133
- `PresentationSizing` values:
134
- - `.automatic` -- platform default
135
- - `.page` -- roughly paper size, for informational content
136
- - `.form` -- slightly narrower than page, for form-style UI
137
- - `.fitted` -- sized by the content's ideal size
138
+ ## Confirming dismissal
138
139
 
139
- Modifier methods for fine-tuning:
140
- - `.fitted(horizontal:vertical:)` -- constrain fitting to specific axes
141
- - `.sticky(horizontal:vertical:)` -- grow but do not shrink in specified dimensions
142
-
143
- ### Dismissal Confirmation (macOS 15+ / iOS 26+)
144
-
145
- Show a confirmation dialog when the user tries to dismiss a sheet with unsaved changes:
140
+ On iOS, block the swipe with `.interactiveDismissDisabled(_:)` while there are
141
+ unsaved edits, and ask from your own Close button with `confirmationDialog`:
146
142
 
147
143
  ```swift
148
- .sheet(item: $selectedItem) { item in
149
- EditItemSheet(item: item)
150
- .dismissalConfirmationDialog(
151
- "Discard changes?",
152
- shouldPresent: hasUnsavedChanges
153
- ) {
154
- Button("Discard", role: .destructive) { discardChanges() }
144
+ struct TripEditorSheet: View {
145
+ let id: Trip.ID
146
+ let hasEdits: Bool
147
+ let draft: Draft
148
+ @State private var confirmsDiscard = false
149
+ @Environment(\.dismiss) private var dismiss
150
+
151
+ var body: some View {
152
+ NavigationStack {
153
+ TripEditor(tripID: id)
154
+ .toolbar {
155
+ ToolbarItem(placement: .cancellationAction) {
156
+ Button("Close", systemImage: "xmark") {
157
+ if hasEdits { confirmsDiscard = true } else { dismiss() }
158
+ }
159
+ .confirmationDialog("Throw away your edits?", isPresented: $confirmsDiscard) {
160
+ Button("Throw Away", role: .destructive) {
161
+ draft.revert()
162
+ dismiss()
163
+ }
164
+ Button("Save and Close") {
165
+ draft.save()
166
+ dismiss()
167
+ }
168
+ }
169
+ }
170
+ }
155
171
  }
172
+ .interactiveDismissDisabled(hasEdits)
173
+ }
156
174
  }
157
175
  ```
158
176
 
159
- - Cancel action is included automatically and prevents dismissal
160
- - All other action buttons allow dismissal to proceed
161
- - Use `.keyboardShortcut(.defaultAction)` to set the default button
177
+ On macOS 15 and later, `dismissalConfirmationDialog(_:shouldPresent:)` does
178
+ this for you. The SDK marks it unavailable on iOS, iPadOS, tvOS, watchOS and
179
+ visionOS, so it only compiles in a macOS target:
180
+
181
+ ```swift
182
+ TripEditor(tripID: id)
183
+ .dismissalConfirmationDialog("Throw away your edits?", shouldPresent: hasEdits) {
184
+ Button("Throw Away", role: .destructive) { draft.revert() }
185
+ Button("Save and Close") { draft.save() }
186
+ .keyboardShortcut(.defaultAction)
187
+ }
188
+ ```
189
+
190
+ The system adds Cancel on its own, and Cancel keeps the sheet open. Any other
191
+ button lets the dismissal go ahead. `.keyboardShortcut(.defaultAction)` marks
192
+ the default choice.
162
193
 
163
194
  ## Pitfalls
164
195
 
165
- - Avoid mixing `sheet(isPresented:)` and `sheet(item:)` for the same concern; prefer a single enum.
166
- - Do not store heavy state inside `SheetDestination`; pass lightweight identifiers or models.
167
- - If multiple sheets can appear from the same screen, give them distinct `id` values.
168
- - Use `presentationSizing(.form)` for form sheets instead of hard-coding frame dimensions.
169
- - Always pair `dismissalConfirmationDialog` with a `shouldPresent` condition; showing it when there are no changes is confusing.
196
+ - Two presentation styles, `sheet(isPresented:)` plus `sheet(item:)`, for one
197
+ concern. A single enum is enough.
198
+ - Carrying heavy state inside `SheetDestination`. Pass identifiers or small
199
+ models.
200
+ - Reusing an `id` for sheets that may legitimately come from the same screen
201
+ one after another; give them distinct values.
202
+ - Fixed frames instead of `presentationSizing(.form)`.
203
+ - A dismissal dialog without a real `shouldPresent` condition. Asking when
204
+ nothing changed only confuses people.
@@ -1,178 +1,144 @@
1
- # TabView
1
+ # TabView Architecture
2
2
 
3
- ## Contents
3
+ Part of the `swiftui-navigation` skill. Goal: tabs that scale across platforms,
4
+ with one source of truth for what each tab is and shows, different tab sets and
5
+ sidebar groupings per platform, tabs generated from data, and a hook that can
6
+ intercept special tabs.
4
7
 
5
- - [Intent](#intent)
6
- - [Core architecture](#core-architecture)
7
- - [Example: custom binding with side effects](#example-custom-binding-with-side-effects)
8
- - [Example: direct binding without side effects](#example-direct-binding-without-side-effects)
9
- - [Design choices to keep](#design-choices-to-keep)
10
- - [Dynamic tabs pattern](#dynamic-tabs-pattern)
11
- - [iOS 26 Tab API](#ios-26-tab-api)
12
- - [Pitfalls](#pitfalls)
8
+ ## Building blocks
13
9
 
14
- ## Intent
10
+ - `AppTab` enum: identity, title, icon and a builder for its content.
11
+ - `SidebarSections` enum: which tabs appear under which sidebar heading. Give
12
+ its `title` the type `LocalizedStringKey`. With a `String` title,
13
+ `TabSection(group.title)` makes `Tab(value:)` ambiguous and the view does not
14
+ compile.
15
+ - `AppView`: owns the `TabView` and the selection, and routes selection changes
16
+ through `updateTab(with:)`.
15
17
 
16
- Use this pattern for a scalable, multi-platform tab architecture with:
17
- - a single source of truth for tab identity and content,
18
- - platform-specific tab sets and sidebar sections,
19
- - dynamic tabs sourced from data,
20
- - an interception hook for special tabs (e.g., compose).
21
-
22
- ## Core architecture
23
-
24
- - `AppTab` enum defines identity, labels, icons, and content builder.
25
- - `SidebarSections` enum groups tabs for sidebar sections.
26
- - `AppView` owns the `TabView` and selection binding, and routes tab changes through `updateTab`.
27
-
28
- ## Example: custom binding with side effects
29
-
30
- Use this when tab selection needs side effects, like intercepting a special tab to perform an action instead of changing selection.
18
+ ## Selection with side effects
31
19
 
32
20
  ```swift
33
- @MainActor
34
21
  struct AppView: View {
35
- @Binding var selectedTab: AppTab
36
-
37
- var body: some View {
38
- TabView(selection: .init(
39
- get: { selectedTab },
40
- set: { updateTab(with: $0) }
41
- )) {
42
- ForEach(availableSections) { section in
43
- TabSection(section.title) {
44
- ForEach(section.tabs) { tab in
45
- Tab(value: tab) {
46
- tab.makeContentView(
47
- homeTimeline: $timeline,
48
- selectedTab: $selectedTab,
49
- pinnedFilters: $pinnedFilters
50
- )
51
- } label: {
52
- tab.label
53
- }
54
- .tabPlacement(tab.tabPlacement)
55
- }
56
- }
57
- .tabPlacement(.sidebarOnly)
58
- }
59
- }
60
- }
22
+ let sections: [SidebarSections]
23
+ @State private var scrollTarget: AppTab?
24
+ @State private var showsComposer = false
25
+ @State private var selectedTab: AppTab = .home
61
26
 
62
- private func updateTab(with newTab: AppTab) {
63
- if newTab == .post {
64
- // Intercept special tabs (compose) instead of changing selection.
65
- presentComposer()
66
- return
27
+ private var selection: Binding<AppTab> {
28
+ Binding(get: { selectedTab }, set: updateTab(with:))
67
29
  }
68
- selectedTab = newTab
69
- }
70
- }
71
- ```
72
-
73
- ## Example: direct binding without side effects
74
30
 
75
- Use this when selection is purely state-driven.
76
-
77
- ```swift
78
- @MainActor
79
- struct AppView: View {
80
- @Binding var selectedTab: AppTab
81
-
82
- var body: some View {
83
- TabView(selection: $selectedTab) {
84
- ForEach(availableSections) { section in
85
- TabSection(section.title) {
86
- ForEach(section.tabs) { tab in
87
- Tab(value: tab) {
88
- tab.makeContentView(
89
- homeTimeline: $timeline,
90
- selectedTab: $selectedTab,
91
- pinnedFilters: $pinnedFilters
92
- )
93
- } label: {
94
- tab.label
31
+ var body: some View {
32
+ TabView(selection: selection) {
33
+ ForEach(sections) { group in
34
+ TabSection(group.title) {
35
+ ForEach(group.tabs) { entry in
36
+ Tab(value: entry) {
37
+ entry.makeContentView(scrollTarget: $scrollTarget)
38
+ } label: {
39
+ entry.label
40
+ }
41
+ .tabPlacement(entry.tabPlacement)
42
+ }
43
+ }
44
+ .tabPlacement(.sidebarOnly)
95
45
  }
96
- .tabPlacement(tab.tabPlacement)
97
- }
98
46
  }
99
- .tabPlacement(.sidebarOnly)
100
- }
47
+ .sheet(isPresented: $showsComposer) { ComposerView() }
48
+ }
49
+
50
+ private func updateTab(with next: AppTab) {
51
+ if next == .post {
52
+ showsComposer = true
53
+ return
54
+ }
55
+ if next == selectedTab {
56
+ scrollTarget = next
57
+ }
58
+ selectedTab = next
101
59
  }
102
- }
103
60
  }
104
61
  ```
105
62
 
106
- ## Design choices to keep
63
+ Choosing `.post` opens the composer and leaves the selection where it was.
64
+ Choosing the current tab again asks it to scroll to the top.
107
65
 
108
- - Centralize tab identity and content in `AppTab` with `makeContentView(...)`.
109
- - Use `Tab(value:)` with `selection` binding for state-driven tab selection.
110
- - Route selection changes through `updateTab` to handle special tabs and scroll-to-top behavior.
111
- - Use `TabSection` + `.tabPlacement(.sidebarOnly)` for sidebar structure.
112
- - Use `.tabPlacement(.pinned)` in `AppTab.tabPlacement` for a single pinned tab; this is commonly used for iOS 26 `.searchable` tab content, but can be used for any tab.
66
+ ## Selection without side effects
113
67
 
114
- ## Dynamic tabs pattern
68
+ If selection is pure state, bind directly: `TabView(selection: $selectedTab)`
69
+ with the same `TabSection` and `Tab` structure inside.
115
70
 
116
- - `SidebarSections` handles dynamic data tabs.
117
- - `AppTab.anyTimelineFilter(filter:)` wraps dynamic tabs in a single enum case.
118
- - The enum provides label/icon/title for dynamic tabs via the filter type.
71
+ ## Rules worth keeping
119
72
 
120
- ## iOS 26 Tab API
73
+ - `AppTab` is the single home for identity and content, through
74
+ `makeContentView(...)`.
75
+ - Tabs use `Tab(value:)` together with a selection binding.
76
+ - Selection goes through `updateTab(with:)`; that one function deals with
77
+ compose-style tabs and with re-tapping to scroll up.
78
+ - Sidebar structure comes from `TabSection` plus `.tabPlacement(.sidebarOnly)`.
79
+ - `.tabPlacement(.pinned)` keeps one tab fixed in place. It is typical for an
80
+ iOS 26 `.searchable` tab but works for any tab.
121
81
 
122
- iOS 26 expands the Tab API with minimize behavior, roles, and accessory placements.
82
+ ## Tabs generated from data
123
83
 
124
- ### Tab Bar Minimization
84
+ `SidebarSections` can hold tabs that come from user data, such as saved
85
+ filters. Represent them with one case that carries a payload, for example
86
+ `AppTab.savedFilter(SavedFilter)`, and read the title and icon from the filter.
125
87
 
126
88
  ```swift
127
- TabView(selection: $selectedTab) {
128
- // tabs
129
- }
130
- .tabBarMinimizeBehavior(.onScrollDown) // iPhone only
131
- ```
132
-
133
- `TabBarMinimizeBehavior` values:
134
- - `.automatic` -- determine behavior from context
135
- - `.onScrollDown` -- minimize when user scrolls down (iPhone only)
136
- - `.onScrollUp` -- minimize when user scrolls up (iPhone only)
137
- - `.never` -- never minimize the tab bar
89
+ enum AppTab: Hashable, Identifiable {
90
+ case home, search, post, profile
91
+ case savedFilter(SavedFilter)
138
92
 
139
- ### Tab Search Role
140
-
141
- Replace the tab bar with a search field when the search tab is active:
93
+ var id: String {
94
+ guard case .savedFilter(let filter) = self else { return String(describing: self) }
95
+ return "filter-\(filter.id)"
96
+ }
142
97
 
143
- ```swift
144
- Tab(role: .search) {
145
- SearchView()
98
+ @ViewBuilder var label: some View {
99
+ switch self {
100
+ case .savedFilter(let filter): Label(filter.name, systemImage: filter.symbol)
101
+ case .home: Label("Start", systemImage: "house")
102
+ case .search: Label("Search", systemImage: "magnifyingglass")
103
+ case .post: Label("Post", systemImage: "square.and.pencil")
104
+ case .profile: Label("Profile", systemImage: "person")
105
+ }
106
+ }
146
107
  }
147
108
  ```
148
109
 
149
- ### Sidebar Customization
110
+ ## iOS 26 tab API
150
111
 
151
112
  ```swift
152
113
  TabView {
153
- // tabs
114
+ Tab("Feed", systemImage: "list.bullet") { FeedView() }
115
+ Tab(role: .search) { SearchView() }
154
116
  }
155
- .tabViewSidebarHeader { SidebarHeaderView() }
156
- .tabViewSidebarFooter { SidebarFooterView() }
157
- .tabViewSidebarBottomBar { BottomBarView() }
117
+ .tabBarMinimizeBehavior(.onScrollDown)
118
+ .tabViewBottomAccessory { MiniPlayerBar() }
119
+ .tabViewSidebarHeader { AccountHeader() }
120
+ .tabViewSidebarFooter { StorageFooter() }
121
+ .tabViewSidebarBottomBar { SettingsButton() }
158
122
  ```
159
123
 
160
- ### Bottom Accessory
161
-
162
- Use `TabViewBottomAccessoryPlacement` for content below the tab bar:
163
-
164
- ```swift
165
- TabView {
166
- // tabs
167
- }
168
- .tabViewBottomAccessory { NowPlayingBar() }
169
- ```
124
+ - `TabBarMinimizeBehavior`: `.automatic` (decided by context), `.onScrollDown`,
125
+ `.onScrollUp` and `.never`. The two scroll behaviours apply on iPhone only.
126
+ - `Tab(role: .search)` replaces the bar with a search field while that tab is
127
+ active.
128
+ - Sidebar customisation: `.tabViewSidebarHeader { }`,
129
+ `.tabViewSidebarFooter { }` and `.tabViewSidebarBottomBar { }`.
130
+ - `.tabViewBottomAccessory { }` shows content just above the tab bar; its
131
+ placement is described by `TabViewBottomAccessoryPlacement`.
170
132
 
171
133
  ## Pitfalls
172
134
 
173
- - Avoid adding ViewModels for tabs; keep state local or in `@Observable` services.
174
- - Do not nest `@Observable` objects inside other `@Observable` objects.
175
- - Ensure `AppTab.id` values are stable; dynamic cases should hash on stable IDs.
176
- - Special tabs (compose) should not change selection.
177
- - Prefer `Tab(value:)` with `TabView(selection:)` over the older `.tabItem { }` API for typed tab selection.
178
- - `tabBarMinimizeBehavior` only works on iPhone; it has no effect on iPad or Mac.
135
+ - A view model per tab. Keep state local to views or in shared `@Observable`
136
+ services.
137
+ - `@Observable` objects nested inside each other.
138
+ - An `AppTab.id` that changes between launches; dynamic cases must hash on a
139
+ stable identifier.
140
+ - Special tabs such as compose that change the selection.
141
+ - `.tabItem { }` instead of `Tab(value:)` with `TabView(selection:)`, which
142
+ loses typed selection.
143
+ - Expecting `tabBarMinimizeBehavior` to work on iPad or Mac; it does nothing
144
+ there.