buildanything 1.7.0 → 1.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 (222) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +55 -0
  4. package/README.md +71 -61
  5. package/agents/ios-app-review-guardian.md +49 -0
  6. package/agents/ios-foundation-models-specialist.md +46 -0
  7. package/agents/ios-storekit-specialist.md +52 -0
  8. package/agents/ios-swift-architect.md +102 -0
  9. package/agents/ios-swift-search.md +130 -0
  10. package/agents/ios-swift-ui-design.md +104 -0
  11. package/commands/build.md +80 -176
  12. package/commands/fix.md +65 -0
  13. package/commands/setup.md +73 -0
  14. package/commands/ux-review.md +63 -0
  15. package/commands/verify.md +72 -0
  16. package/hooks/session-start +18 -1
  17. package/package.json +5 -2
  18. package/protocols/brainstorm.md +99 -0
  19. package/protocols/build-fix.md +52 -0
  20. package/protocols/cleanup.md +54 -0
  21. package/protocols/design.md +269 -0
  22. package/protocols/eval-harness.md +61 -0
  23. package/protocols/fake-data-detector.md +64 -0
  24. package/protocols/ios-context.md +235 -0
  25. package/protocols/ios-frameworks-map.md +323 -0
  26. package/protocols/ios-phase-branches.md +162 -0
  27. package/protocols/ios-preflight.md +27 -0
  28. package/protocols/metric-loop.md +93 -0
  29. package/protocols/planning.md +87 -0
  30. package/protocols/smoke-test.md +110 -0
  31. package/protocols/verify.md +67 -0
  32. package/protocols/web-phase-branches.md +201 -0
  33. package/skills/ios/_VENDORED.md +60 -0
  34. package/skills/ios/activitykit/LICENSE +131 -0
  35. package/skills/ios/activitykit/SKILL.md +505 -0
  36. package/skills/ios/activitykit/references/activitykit-patterns.md +868 -0
  37. package/skills/ios/app-intents/LICENSE +131 -0
  38. package/skills/ios/app-intents/SKILL.md +494 -0
  39. package/skills/ios/app-intents/references/appintents-advanced.md +1076 -0
  40. package/skills/ios/apple-on-device-ai/LICENSE +131 -0
  41. package/skills/ios/apple-on-device-ai/SKILL.md +505 -0
  42. package/skills/ios/apple-on-device-ai/references/coreml-conversion.md +425 -0
  43. package/skills/ios/apple-on-device-ai/references/coreml-optimization.md +344 -0
  44. package/skills/ios/apple-on-device-ai/references/foundation-models.md +508 -0
  45. package/skills/ios/apple-on-device-ai/references/mlx-swift.md +285 -0
  46. package/skills/ios/ios-26-platform/SKILL.md +53 -0
  47. package/skills/ios/ios-26-platform/references/automatic-adoption.md +161 -0
  48. package/skills/ios/ios-26-platform/references/backward-compat.md +238 -0
  49. package/skills/ios/ios-26-platform/references/liquid-glass.md +255 -0
  50. package/skills/ios/ios-26-platform/references/swiftui-apis.md +277 -0
  51. package/skills/ios/ios-26-platform/references/toolbar-navigation.md +250 -0
  52. package/skills/ios/ios-bootstrap/SKILL.md +98 -0
  53. package/skills/ios/ios-bootstrap/references/apple-docs-mcp-config.md +28 -0
  54. package/skills/ios/ios-bootstrap/references/new-project-dialog.md +41 -0
  55. package/skills/ios/ios-bootstrap/references/xcode-mcp-config.md +29 -0
  56. package/skills/ios/ios-debugger-agent/LICENSE +21 -0
  57. package/skills/ios/ios-debugger-agent/SKILL.md +58 -0
  58. package/skills/ios/ios-debugger-agent/agents/openai.yaml +4 -0
  59. package/skills/ios/ios-entitlements-generator/SKILL.md +47 -0
  60. package/skills/ios/ios-hig/SKILL.md +41 -0
  61. package/skills/ios/ios-hig/references/accessibility.md +81 -0
  62. package/skills/ios/ios-hig/references/content.md +142 -0
  63. package/skills/ios/ios-hig/references/feedback.md +123 -0
  64. package/skills/ios/ios-hig/references/interaction.md +199 -0
  65. package/skills/ios/ios-hig/references/performance-platform.md +129 -0
  66. package/skills/ios/ios-hig/references/privacy-permissions.md +181 -0
  67. package/skills/ios/ios-hig/references/visual-design.md +84 -0
  68. package/skills/ios/ios-info-plist-hardening/SKILL.md +130 -0
  69. package/skills/ios/ios-maestro-flow-author/SKILL.md +68 -0
  70. package/skills/ios/ios-maestro-flow-author/references/input-and-scroll.yaml +17 -0
  71. package/skills/ios/ios-maestro-flow-author/references/modal-and-dismiss.yaml +14 -0
  72. package/skills/ios/ios-maestro-flow-author/references/onboarding-flow.yaml +16 -0
  73. package/skills/ios/ios-maestro-flow-author/references/tab-navigation.yaml +13 -0
  74. package/skills/ios/ios-maestro-flow-author/references/tap-and-assert.yaml +9 -0
  75. package/skills/ios/swift-accessibility/LICENSE +21 -0
  76. package/skills/ios/swift-accessibility/SKILL.md +371 -0
  77. package/skills/ios/swift-accessibility/examples/before-after-appkit.md +446 -0
  78. package/skills/ios/swift-accessibility/examples/before-after-swiftui.md +441 -0
  79. package/skills/ios/swift-accessibility/examples/before-after-uikit.md +464 -0
  80. package/skills/ios/swift-accessibility/references/assistive-access.md +441 -0
  81. package/skills/ios/swift-accessibility/references/display-settings.md +491 -0
  82. package/skills/ios/swift-accessibility/references/dynamic-type.md +420 -0
  83. package/skills/ios/swift-accessibility/references/media-accessibility.md +421 -0
  84. package/skills/ios/swift-accessibility/references/motor-input.md +393 -0
  85. package/skills/ios/swift-accessibility/references/nutrition-labels.md +362 -0
  86. package/skills/ios/swift-accessibility/references/platform-specifics.md +515 -0
  87. package/skills/ios/swift-accessibility/references/semantic-structure.md +585 -0
  88. package/skills/ios/swift-accessibility/references/testing-auditing.md +507 -0
  89. package/skills/ios/swift-accessibility/references/voice-control.md +317 -0
  90. package/skills/ios/swift-accessibility/references/voiceover-swiftui.md +584 -0
  91. package/skills/ios/swift-accessibility/references/voiceover-uikit.md +519 -0
  92. package/skills/ios/swift-accessibility/references/wcag-mapping.md +167 -0
  93. package/skills/ios/swift-accessibility/resources/audit-template.swift +128 -0
  94. package/skills/ios/swift-accessibility/resources/qa-checklist.md +258 -0
  95. package/skills/ios/swift-concurrency/LICENSE +21 -0
  96. package/skills/ios/swift-concurrency/SKILL.md +171 -0
  97. package/skills/ios/swift-concurrency/references/_index.md +50 -0
  98. package/skills/ios/swift-concurrency/references/actors.md +660 -0
  99. package/skills/ios/swift-concurrency/references/async-algorithms.md +847 -0
  100. package/skills/ios/swift-concurrency/references/async-await-basics.md +266 -0
  101. package/skills/ios/swift-concurrency/references/async-sequences.md +710 -0
  102. package/skills/ios/swift-concurrency/references/core-data.md +560 -0
  103. package/skills/ios/swift-concurrency/references/glossary.md +135 -0
  104. package/skills/ios/swift-concurrency/references/linting.md +155 -0
  105. package/skills/ios/swift-concurrency/references/memory-management.md +569 -0
  106. package/skills/ios/swift-concurrency/references/migration.md +1104 -0
  107. package/skills/ios/swift-concurrency/references/performance.md +593 -0
  108. package/skills/ios/swift-concurrency/references/sendable.md +598 -0
  109. package/skills/ios/swift-concurrency/references/tasks.md +636 -0
  110. package/skills/ios/swift-concurrency/references/testing.md +592 -0
  111. package/skills/ios/swift-concurrency/references/threading.md +495 -0
  112. package/skills/ios/swift-security-expert/LICENSE +21 -0
  113. package/skills/ios/swift-security-expert/SKILL.md +470 -0
  114. package/skills/ios/swift-security-expert/references/biometric-authentication.md +565 -0
  115. package/skills/ios/swift-security-expert/references/certificate-trust.md +592 -0
  116. package/skills/ios/swift-security-expert/references/common-anti-patterns.md +690 -0
  117. package/skills/ios/swift-security-expert/references/compliance-owasp-mapping.md +537 -0
  118. package/skills/ios/swift-security-expert/references/credential-storage-patterns.md +721 -0
  119. package/skills/ios/swift-security-expert/references/cryptokit-public-key.md +505 -0
  120. package/skills/ios/swift-security-expert/references/cryptokit-symmetric.md +497 -0
  121. package/skills/ios/swift-security-expert/references/keychain-access-control.md +508 -0
  122. package/skills/ios/swift-security-expert/references/keychain-fundamentals.md +596 -0
  123. package/skills/ios/swift-security-expert/references/keychain-item-classes.md +476 -0
  124. package/skills/ios/swift-security-expert/references/keychain-sharing.md +458 -0
  125. package/skills/ios/swift-security-expert/references/migration-legacy-stores.md +727 -0
  126. package/skills/ios/swift-security-expert/references/secure-enclave.md +539 -0
  127. package/skills/ios/swift-security-expert/references/testing-security-code.md +781 -0
  128. package/skills/ios/swift-testing-expert/LICENSE +21 -0
  129. package/skills/ios/swift-testing-expert/SKILL.md +79 -0
  130. package/skills/ios/swift-testing-expert/references/_index.md +12 -0
  131. package/skills/ios/swift-testing-expert/references/async-testing-and-waiting.md +127 -0
  132. package/skills/ios/swift-testing-expert/references/expectations.md +145 -0
  133. package/skills/ios/swift-testing-expert/references/fundamentals.md +141 -0
  134. package/skills/ios/swift-testing-expert/references/migration-from-xctest.md +127 -0
  135. package/skills/ios/swift-testing-expert/references/parallelization-and-isolation.md +95 -0
  136. package/skills/ios/swift-testing-expert/references/parameterized-testing.md +284 -0
  137. package/skills/ios/swift-testing-expert/references/performance-and-best-practices.md +187 -0
  138. package/skills/ios/swift-testing-expert/references/traits-and-tags.md +114 -0
  139. package/skills/ios/swift-testing-expert/references/xcode-workflows.md +70 -0
  140. package/skills/ios/swiftdata-pro/LICENSE +21 -0
  141. package/skills/ios/swiftdata-pro/SKILL.md +102 -0
  142. package/skills/ios/swiftdata-pro/agents/openai.yaml +10 -0
  143. package/skills/ios/swiftdata-pro/assets/swiftdata-pro-icon.png +0 -0
  144. package/skills/ios/swiftdata-pro/assets/swiftdata-pro-icon.svg +29 -0
  145. package/skills/ios/swiftdata-pro/references/class-inheritance.md +104 -0
  146. package/skills/ios/swiftdata-pro/references/cloudkit.md +10 -0
  147. package/skills/ios/swiftdata-pro/references/core-rules.md +20 -0
  148. package/skills/ios/swiftdata-pro/references/indexing.md +27 -0
  149. package/skills/ios/swiftdata-pro/references/predicates.md +73 -0
  150. package/skills/ios/swiftui-design-principles/AGENTS.md +21 -0
  151. package/skills/ios/swiftui-design-principles/LICENSE +21 -0
  152. package/skills/ios/swiftui-design-principles/README.md +41 -0
  153. package/skills/ios/swiftui-design-principles/SKILL.md +605 -0
  154. package/skills/ios/swiftui-design-principles/metadata.json +10 -0
  155. package/skills/ios/swiftui-liquid-glass/LICENSE +21 -0
  156. package/skills/ios/swiftui-liquid-glass/SKILL.md +95 -0
  157. package/skills/ios/swiftui-liquid-glass/agents/openai.yaml +4 -0
  158. package/skills/ios/swiftui-liquid-glass/references/liquid-glass.md +280 -0
  159. package/skills/ios/swiftui-performance-audit/LICENSE +21 -0
  160. package/skills/ios/swiftui-performance-audit/SKILL.md +111 -0
  161. package/skills/ios/swiftui-performance-audit/agents/openai.yaml +4 -0
  162. package/skills/ios/swiftui-performance-audit/references/code-smells.md +150 -0
  163. package/skills/ios/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
  164. package/skills/ios/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
  165. package/skills/ios/swiftui-performance-audit/references/profiling-intake.md +44 -0
  166. package/skills/ios/swiftui-performance-audit/references/report-template.md +47 -0
  167. package/skills/ios/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
  168. package/skills/ios/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
  169. package/skills/ios/swiftui-pro/LICENSE +21 -0
  170. package/skills/ios/swiftui-pro/SKILL.md +108 -0
  171. package/skills/ios/swiftui-pro/agents/openai.yaml +10 -0
  172. package/skills/ios/swiftui-pro/assets/swiftui-pro-icon.png +0 -0
  173. package/skills/ios/swiftui-pro/assets/swiftui-pro-icon.svg +29 -0
  174. package/skills/ios/swiftui-pro/references/accessibility.md +13 -0
  175. package/skills/ios/swiftui-pro/references/api.md +39 -0
  176. package/skills/ios/swiftui-pro/references/data.md +43 -0
  177. package/skills/ios/swiftui-pro/references/design.md +31 -0
  178. package/skills/ios/swiftui-pro/references/hygiene.md +9 -0
  179. package/skills/ios/swiftui-pro/references/navigation.md +14 -0
  180. package/skills/ios/swiftui-pro/references/performance.md +46 -0
  181. package/skills/ios/swiftui-pro/references/swift.md +56 -0
  182. package/skills/ios/swiftui-pro/references/views.md +35 -0
  183. package/skills/ios/swiftui-ui-patterns/LICENSE +21 -0
  184. package/skills/ios/swiftui-ui-patterns/SKILL.md +100 -0
  185. package/skills/ios/swiftui-ui-patterns/agents/openai.yaml +4 -0
  186. package/skills/ios/swiftui-ui-patterns/references/app-wiring.md +201 -0
  187. package/skills/ios/swiftui-ui-patterns/references/async-state.md +96 -0
  188. package/skills/ios/swiftui-ui-patterns/references/components-index.md +50 -0
  189. package/skills/ios/swiftui-ui-patterns/references/controls.md +57 -0
  190. package/skills/ios/swiftui-ui-patterns/references/deeplinks.md +66 -0
  191. package/skills/ios/swiftui-ui-patterns/references/focus.md +90 -0
  192. package/skills/ios/swiftui-ui-patterns/references/form.md +97 -0
  193. package/skills/ios/swiftui-ui-patterns/references/grids.md +71 -0
  194. package/skills/ios/swiftui-ui-patterns/references/haptics.md +71 -0
  195. package/skills/ios/swiftui-ui-patterns/references/input-toolbar.md +51 -0
  196. package/skills/ios/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
  197. package/skills/ios/swiftui-ui-patterns/references/list.md +86 -0
  198. package/skills/ios/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
  199. package/skills/ios/swiftui-ui-patterns/references/macos-settings.md +71 -0
  200. package/skills/ios/swiftui-ui-patterns/references/matched-transitions.md +59 -0
  201. package/skills/ios/swiftui-ui-patterns/references/media.md +73 -0
  202. package/skills/ios/swiftui-ui-patterns/references/menu-bar.md +101 -0
  203. package/skills/ios/swiftui-ui-patterns/references/navigationstack.md +159 -0
  204. package/skills/ios/swiftui-ui-patterns/references/overlay.md +45 -0
  205. package/skills/ios/swiftui-ui-patterns/references/performance.md +62 -0
  206. package/skills/ios/swiftui-ui-patterns/references/previews.md +48 -0
  207. package/skills/ios/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
  208. package/skills/ios/swiftui-ui-patterns/references/scrollview.md +87 -0
  209. package/skills/ios/swiftui-ui-patterns/references/searchable.md +71 -0
  210. package/skills/ios/swiftui-ui-patterns/references/sheets.md +155 -0
  211. package/skills/ios/swiftui-ui-patterns/references/split-views.md +72 -0
  212. package/skills/ios/swiftui-ui-patterns/references/tabview.md +114 -0
  213. package/skills/ios/swiftui-ui-patterns/references/theming.md +71 -0
  214. package/skills/ios/swiftui-ui-patterns/references/title-menus.md +93 -0
  215. package/skills/ios/swiftui-ui-patterns/references/top-bar.md +49 -0
  216. package/skills/ios/swiftui-view-refactor/LICENSE +21 -0
  217. package/skills/ios/swiftui-view-refactor/SKILL.md +207 -0
  218. package/skills/ios/swiftui-view-refactor/agents/openai.yaml +4 -0
  219. package/skills/ios/swiftui-view-refactor/references/mv-patterns.md +161 -0
  220. package/skills/ios/widgetkit/LICENSE +131 -0
  221. package/skills/ios/widgetkit/SKILL.md +502 -0
  222. package/skills/ios/widgetkit/references/widgetkit-advanced.md +871 -0
@@ -0,0 +1,93 @@
1
+ # Title menus
2
+
3
+ ## Intent
4
+
5
+ Use a title menu in the navigation bar to provide context‑specific filtering or quick actions without adding extra chrome.
6
+
7
+ ## Core patterns
8
+
9
+ - Use `ToolbarTitleMenu` to attach a menu to the navigation title.
10
+ - Keep the menu content compact and grouped with dividers.
11
+
12
+ ## Example: title menu for filters
13
+
14
+ ```swift
15
+ @ToolbarContentBuilder
16
+ private var toolbarView: some ToolbarContent {
17
+ ToolbarTitleMenu {
18
+ Button("Latest") { timeline = .latest }
19
+ Button("Resume") { timeline = .resume }
20
+ Divider()
21
+ Button("Local") { timeline = .local }
22
+ Button("Federated") { timeline = .federated }
23
+ }
24
+ }
25
+ ```
26
+
27
+ ## Example: attach to a view
28
+
29
+ ```swift
30
+ NavigationStack {
31
+ TimelineView()
32
+ .toolbar {
33
+ toolbarView
34
+ }
35
+ }
36
+ ```
37
+
38
+ ## Example: title + menu together
39
+
40
+ ```swift
41
+ struct TimelineScreen: View {
42
+ @State private var timeline: TimelineFilter = .home
43
+
44
+ var body: some View {
45
+ NavigationStack {
46
+ TimelineView()
47
+ .toolbar {
48
+ ToolbarItem(placement: .principal) {
49
+ VStack(spacing: 2) {
50
+ Text(timeline.title)
51
+ .font(.headline)
52
+ Text(timeline.subtitle)
53
+ .font(.caption)
54
+ .foregroundStyle(.secondary)
55
+ }
56
+ }
57
+
58
+ ToolbarTitleMenu {
59
+ Button("Home") { timeline = .home }
60
+ Button("Local") { timeline = .local }
61
+ Button("Federated") { timeline = .federated }
62
+ }
63
+ }
64
+ .navigationBarTitleDisplayMode(.inline)
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ ## Example: title + subtitle with menu
71
+
72
+ ```swift
73
+ ToolbarItem(placement: .principal) {
74
+ VStack(spacing: 2) {
75
+ Text(title)
76
+ .font(.headline)
77
+ Text(subtitle)
78
+ .font(.caption)
79
+ .foregroundStyle(.secondary)
80
+ }
81
+ }
82
+ ```
83
+
84
+ ## Design choices to keep
85
+
86
+ - Only show the title menu when filtering or context switching is available.
87
+ - Keep the title readable; avoid long labels that truncate.
88
+ - Use secondary text below the title if extra context is needed.
89
+
90
+ ## Pitfalls
91
+
92
+ - Don’t overload the menu with too many options.
93
+ - Avoid using title menus for destructive actions.
@@ -0,0 +1,49 @@
1
+ # Top bar overlays (iOS 26+ and fallback)
2
+
3
+ ## Intent
4
+
5
+ Provide a custom top selector or pill row that sits above scroll content, using `safeAreaBar(.top)` on iOS 26 and a compatible fallback on earlier OS versions.
6
+
7
+ ## iOS 26+ approach
8
+
9
+ Use `safeAreaBar(edge: .top)` to attach the view to the safe area bar.
10
+
11
+ ```swift
12
+ if #available(iOS 26.0, *) {
13
+ content
14
+ .safeAreaBar(edge: .top) {
15
+ TopSelectorView()
16
+ .padding(.horizontal, .layoutPadding)
17
+ }
18
+ }
19
+ ```
20
+
21
+ ## Fallback for earlier iOS
22
+
23
+ Use `.safeAreaInset(edge: .top)` and hide the toolbar background to avoid double layers.
24
+
25
+ ```swift
26
+ content
27
+ .toolbarBackground(.hidden, for: .navigationBar)
28
+ .safeAreaInset(edge: .top, spacing: 0) {
29
+ VStack(spacing: 0) {
30
+ TopSelectorView()
31
+ .padding(.vertical, 8)
32
+ .padding(.horizontal, .layoutPadding)
33
+ .background(Color.primary.opacity(0.06))
34
+ .background(Material.ultraThin)
35
+ Divider()
36
+ }
37
+ }
38
+ ```
39
+
40
+ ## Design choices to keep
41
+
42
+ - Use `safeAreaBar` when available; it integrates better with the navigation bar.
43
+ - Use a subtle background + divider in the fallback to keep separation from content.
44
+ - Keep the selector height compact to avoid pushing content too far down.
45
+
46
+ ## Pitfalls
47
+
48
+ - Don’t stack multiple top insets; it can create extra padding.
49
+ - Avoid heavy, opaque backgrounds that fight the navigation bar.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Thomas Ricouard
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,207 @@
1
+ ---
2
+ name: swiftui-view-refactor
3
+ description: Refactor and review SwiftUI view files with strong defaults for small dedicated subviews, MV-over-MVVM data flow, stable view trees, explicit dependency injection, and correct Observation usage. Use when cleaning up a SwiftUI view, splitting long bodies, removing inline actions or side effects, reducing computed `some View` helpers, or standardizing `@Observable` and view model initialization patterns.
4
+ ---
5
+
6
+ # SwiftUI View Refactor
7
+
8
+ ## Overview
9
+ Refactor SwiftUI views toward small, explicit, stable view types. Default to vanilla SwiftUI: local state in the view, shared dependencies in the environment, business logic in services/models, and view models only when the request or existing code clearly requires one.
10
+
11
+ ## Core Guidelines
12
+
13
+ ### 1) View ordering (top → bottom)
14
+ - Enforce this ordering unless the existing file has a stronger local convention you must preserve.
15
+ - Environment
16
+ - `private`/`public` `let`
17
+ - `@State` / other stored properties
18
+ - computed `var` (non-view)
19
+ - `init`
20
+ - `body`
21
+ - computed view builders / other view helpers
22
+ - helper / async functions
23
+
24
+ ### 2) Default to MV, not MVVM
25
+ - Views should be lightweight state expressions and orchestration points, not containers for business logic.
26
+ - Favor `@State`, `@Environment`, `@Query`, `.task`, `.task(id:)`, and `onChange` before reaching for a view model.
27
+ - Inject services and shared models via `@Environment`; keep domain logic in services/models, not in the view body.
28
+ - Do not introduce a view model just to mirror local view state or wrap environment dependencies.
29
+ - If a screen is getting large, split the UI into subviews before inventing a new view model layer.
30
+
31
+ ### 3) Strongly prefer dedicated subview types over computed `some View` helpers
32
+ - Flag `body` properties that are longer than roughly one screen or contain multiple logical sections.
33
+ - Prefer extracting dedicated `View` types for non-trivial sections, especially when they have state, async work, branching, or deserve their own preview.
34
+ - Keep computed `some View` helpers rare and small. Do not build an entire screen out of `private var header: some View`-style fragments.
35
+ - Pass small, explicit inputs (data, bindings, callbacks) into extracted subviews instead of handing down the entire parent state.
36
+ - If an extracted subview becomes reusable or independently meaningful, move it to its own file.
37
+
38
+ Prefer:
39
+
40
+ ```swift
41
+ var body: some View {
42
+ List {
43
+ HeaderSection(title: title, subtitle: subtitle)
44
+ FilterSection(
45
+ filterOptions: filterOptions,
46
+ selectedFilter: $selectedFilter
47
+ )
48
+ ResultsSection(items: filteredItems)
49
+ FooterSection()
50
+ }
51
+ }
52
+
53
+ private struct HeaderSection: View {
54
+ let title: String
55
+ let subtitle: String
56
+
57
+ var body: some View {
58
+ VStack(alignment: .leading, spacing: 6) {
59
+ Text(title).font(.title2)
60
+ Text(subtitle).font(.subheadline)
61
+ }
62
+ }
63
+ }
64
+
65
+ private struct FilterSection: View {
66
+ let filterOptions: [FilterOption]
67
+ @Binding var selectedFilter: FilterOption
68
+
69
+ var body: some View {
70
+ ScrollView(.horizontal, showsIndicators: false) {
71
+ HStack {
72
+ ForEach(filterOptions, id: \.self) { option in
73
+ FilterChip(option: option, isSelected: option == selectedFilter)
74
+ .onTapGesture { selectedFilter = option }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ ```
81
+
82
+ Avoid:
83
+
84
+ ```swift
85
+ var body: some View {
86
+ List {
87
+ header
88
+ filters
89
+ results
90
+ footer
91
+ }
92
+ }
93
+
94
+ private var header: some View {
95
+ VStack(alignment: .leading, spacing: 6) {
96
+ Text(title).font(.title2)
97
+ Text(subtitle).font(.subheadline)
98
+ }
99
+ }
100
+ ```
101
+
102
+ ### 3b) Extract actions and side effects out of `body`
103
+ - Do not keep non-trivial button actions inline in the view body.
104
+ - Do not bury business logic inside `.task`, `.onAppear`, `.onChange`, or `.refreshable`.
105
+ - Prefer calling small private methods from the view, and move real business logic into services/models.
106
+ - The body should read like UI, not like a view controller.
107
+
108
+ ```swift
109
+ Button("Save", action: save)
110
+ .disabled(isSaving)
111
+
112
+ .task(id: searchText) {
113
+ await reload(for: searchText)
114
+ }
115
+
116
+ private func save() {
117
+ Task { await saveAsync() }
118
+ }
119
+
120
+ private func reload(for searchText: String) async {
121
+ guard !searchText.isEmpty else {
122
+ results = []
123
+ return
124
+ }
125
+ await searchService.search(searchText)
126
+ }
127
+ ```
128
+
129
+ ### 4) Keep a stable view tree (avoid top-level conditional view swapping)
130
+ - Avoid `body` or computed views that return completely different root branches via `if/else`.
131
+ - Prefer a single stable base view with conditions inside sections/modifiers (`overlay`, `opacity`, `disabled`, `toolbar`, etc.).
132
+ - Root-level branch swapping causes identity churn, broader invalidation, and extra recomputation.
133
+
134
+ Prefer:
135
+
136
+ ```swift
137
+ var body: some View {
138
+ List {
139
+ documentsListContent
140
+ }
141
+ .toolbar {
142
+ if canEdit {
143
+ editToolbar
144
+ }
145
+ }
146
+ }
147
+ ```
148
+
149
+ Avoid:
150
+
151
+ ```swift
152
+ var documentsListView: some View {
153
+ if canEdit {
154
+ editableDocumentsList
155
+ } else {
156
+ readOnlyDocumentsList
157
+ }
158
+ }
159
+ ```
160
+
161
+ ### 5) View model handling (only if already present or explicitly requested)
162
+ - Treat view models as a legacy or explicit-need pattern, not the default.
163
+ - Do not introduce a view model unless the request or existing code clearly calls for one.
164
+ - If a view model exists, make it non-optional when possible.
165
+ - Pass dependencies to the view via `init`, then create the view model in the view's `init`.
166
+ - Avoid `bootstrapIfNeeded` patterns and other delayed setup workarounds.
167
+
168
+ Example (Observation-based):
169
+
170
+ ```swift
171
+ @State private var viewModel: SomeViewModel
172
+
173
+ init(dependency: Dependency) {
174
+ _viewModel = State(initialValue: SomeViewModel(dependency: dependency))
175
+ }
176
+ ```
177
+
178
+ ### 6) Observation usage
179
+ - For `@Observable` reference types on iOS 17+, store them as `@State` in the owning view.
180
+ - Pass observables down explicitly; avoid optional state unless the UI genuinely needs it.
181
+ - If the deployment target includes iOS 16 or earlier, use `@StateObject` at the owner and `@ObservedObject` when injecting legacy observable models.
182
+
183
+ ## Workflow
184
+
185
+ 1. Reorder the view to match the ordering rules.
186
+ 2. Remove inline actions and side effects from `body`; move business logic into services/models and keep only thin orchestration in the view.
187
+ 3. Shorten long bodies by extracting dedicated subview types; avoid rebuilding the screen out of many computed `some View` helpers.
188
+ 4. Ensure stable view structure: avoid top-level `if`-based branch swapping; move conditions to localized sections/modifiers.
189
+ 5. If a view model exists or is explicitly required, replace optional view models with a non-optional `@State` view model initialized in `init`.
190
+ 6. Confirm Observation usage: `@State` for root `@Observable` models on iOS 17+, legacy wrappers only when the deployment target requires them.
191
+ 7. Keep behavior intact: do not change layout or business logic unless requested.
192
+
193
+ ## Notes
194
+
195
+ - Prefer small, explicit view types over large conditional blocks and large computed `some View` properties.
196
+ - Keep computed view builders below `body` and non-view computed vars above `init`.
197
+ - A good SwiftUI refactor should make the view read top-to-bottom as data flow plus layout, not as mixed layout and imperative logic.
198
+ - For MV-first guidance and rationale, see `references/mv-patterns.md`.
199
+
200
+ ## Large-view handling
201
+
202
+ When a SwiftUI view file exceeds ~300 lines, split it aggressively. Extract meaningful sections into dedicated `View` types instead of hiding complexity in many computed properties. Use `private` extensions with `// MARK: -` comments for actions and helpers, but do not treat extensions as a substitute for breaking a giant screen into smaller view types. If an extracted subview is reused or independently meaningful, move it into its own file.
203
+
204
+
205
+ ---
206
+
207
+ Vendored from: https://github.com/Dimillian/Skills/tree/main/swiftui-view-refactor
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "SwiftUI View Refactor"
3
+ short_description: "Refactor large SwiftUI view files"
4
+ default_prompt: "Use $swiftui-view-refactor to clean up and split this SwiftUI view without changing its behavior."
@@ -0,0 +1,161 @@
1
+ # MV Patterns Reference
2
+
3
+ Distilled guidance for deciding whether a SwiftUI feature should stay as plain MV or introduce a view model.
4
+
5
+ Inspired by the user's provided source, "SwiftUI in 2025: Forget MVVM" (Thomas Ricouard), but rewritten here as a practical refactoring reference.
6
+
7
+ ## Default stance
8
+
9
+ - Default to MV: views are lightweight state expressions and orchestration points.
10
+ - Prefer `@State`, `@Environment`, `@Query`, `.task`, `.task(id:)`, and `onChange` before reaching for a view model.
11
+ - Keep business logic in services, models, or domain types, not in the view body.
12
+ - Split large screens into smaller view types before inventing a view model layer.
13
+ - Avoid manual fetching or state plumbing that duplicates SwiftUI or SwiftData mechanisms.
14
+ - Test services, models, and transformations first; views should stay simple and declarative.
15
+
16
+ ## When to avoid a view model
17
+
18
+ Do not introduce a view model when it would mostly:
19
+ - mirror local view state,
20
+ - wrap values already available through `@Environment`,
21
+ - duplicate `@Query`, `@State`, or `Binding`-based data flow,
22
+ - exist only because the view body is too long,
23
+ - hold one-off async loading logic that can live in `.task` plus local view state.
24
+
25
+ In these cases, simplify the view and data flow instead of adding indirection.
26
+
27
+ ## When a view model may be justified
28
+
29
+ A view model can be reasonable when at least one of these is true:
30
+ - the user explicitly asks for one,
31
+ - the codebase already standardizes on a view model pattern for that feature,
32
+ - the screen needs a long-lived reference model with behavior that does not fit naturally in services alone,
33
+ - the feature is adapting a non-SwiftUI API that needs a dedicated bridge object,
34
+ - multiple views share the same presentation-specific state and that state is not better modeled as app-level environment data.
35
+
36
+ Even then, keep the view model small, explicit, and non-optional when possible.
37
+
38
+ ## Preferred pattern: local state plus environment
39
+
40
+ ```swift
41
+ struct FeedView: View {
42
+ @Environment(BlueSkyClient.self) private var client
43
+
44
+ enum ViewState {
45
+ case loading
46
+ case error(String)
47
+ case loaded([Post])
48
+ }
49
+
50
+ @State private var viewState: ViewState = .loading
51
+
52
+ var body: some View {
53
+ List {
54
+ switch viewState {
55
+ case .loading:
56
+ ProgressView("Loading feed...")
57
+ case .error(let message):
58
+ ErrorStateView(message: message, retryAction: { await loadFeed() })
59
+ case .loaded(let posts):
60
+ ForEach(posts) { post in
61
+ PostRowView(post: post)
62
+ }
63
+ }
64
+ }
65
+ .task { await loadFeed() }
66
+ }
67
+
68
+ private func loadFeed() async {
69
+ do {
70
+ let posts = try await client.getFeed()
71
+ viewState = .loaded(posts)
72
+ } catch {
73
+ viewState = .error(error.localizedDescription)
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ Why this is preferred:
80
+ - state stays close to the UI that renders it,
81
+ - dependencies come from the environment instead of a wrapper object,
82
+ - the view coordinates UI flow while the service owns the real work.
83
+
84
+ ## Preferred pattern: use modifiers as lightweight orchestration
85
+
86
+ ```swift
87
+ .task(id: searchText) {
88
+ guard !searchText.isEmpty else {
89
+ results = []
90
+ return
91
+ }
92
+ await searchFeed(query: searchText)
93
+ }
94
+
95
+ .onChange(of: isInSearch, initial: false) {
96
+ guard !isInSearch else { return }
97
+ Task { await fetchSuggestedFeed() }
98
+ }
99
+ ```
100
+
101
+ Use view lifecycle modifiers for simple, local orchestration. Do not convert these into a view model by default unless the behavior clearly outgrows the view.
102
+
103
+ ## SwiftData note
104
+
105
+ SwiftData is a strong argument for keeping data flow inside the view when possible.
106
+
107
+ Prefer:
108
+
109
+ ```swift
110
+ struct BookListView: View {
111
+ @Query private var books: [Book]
112
+ @Environment(\.modelContext) private var modelContext
113
+
114
+ var body: some View {
115
+ List {
116
+ ForEach(books) { book in
117
+ BookRowView(book: book)
118
+ .swipeActions {
119
+ Button("Delete", role: .destructive) {
120
+ modelContext.delete(book)
121
+ }
122
+ }
123
+ }
124
+ }
125
+ }
126
+ }
127
+ ```
128
+
129
+ Avoid adding a view model that manually fetches and mirrors the same state unless the feature has an explicit reason to do so.
130
+
131
+ ## Testing guidance
132
+
133
+ Prefer to test:
134
+ - services and business rules,
135
+ - models and state transformations,
136
+ - async workflows at the service layer,
137
+ - UI behavior with previews or higher-level UI tests.
138
+
139
+ Do not introduce a view model primarily to make a simple SwiftUI view "testable." That usually adds ceremony without improving the architecture.
140
+
141
+ ## Refactor checklist
142
+
143
+ When refactoring toward MV:
144
+ - Remove view models that only wrap environment dependencies or local view state.
145
+ - Replace optional or delayed-initialized view models when plain view state is enough.
146
+ - Pull business logic out of the view body and into services/models.
147
+ - Keep the view as a thin coordinator of UI state, navigation, and user actions.
148
+ - Split large bodies into smaller view types before adding new layers of indirection.
149
+
150
+ ## Bottom line
151
+
152
+ Treat view models as the exception, not the default.
153
+
154
+ In modern SwiftUI, the default stack is:
155
+ - `@State` for local state,
156
+ - `@Environment` for shared dependencies,
157
+ - `@Query` for SwiftData-backed collections,
158
+ - lifecycle modifiers for lightweight orchestration,
159
+ - services and models for business logic.
160
+
161
+ Reach for a view model only when the feature clearly needs one.
@@ -0,0 +1,131 @@
1
+ Required Notice: Copyright (c) 2025 dpearson2699 (https://github.com/dpearson2699)
2
+
3
+ # PolyForm Perimeter License 1.0.0
4
+
5
+ <https://polyformproject.org/licenses/perimeter/1.0.0>
6
+
7
+ ## Acceptance
8
+
9
+ In order to get any license under these terms, you must agree
10
+ to them as both strict obligations and conditions to all
11
+ your licenses.
12
+
13
+ ## Copyright License
14
+
15
+ The licensor grants you a copyright license for the
16
+ software to do everything you might do with the software
17
+ that would otherwise infringe the licensor's copyright
18
+ in it for any permitted purpose. However, you may
19
+ only distribute the software according to [Distribution
20
+ License](#distribution-license) and make changes or new works
21
+ based on the software according to [Changes and New Works
22
+ License](#changes-and-new-works-license).
23
+
24
+ ## Distribution License
25
+
26
+ The licensor grants you an additional copyright license
27
+ to distribute copies of the software. Your license
28
+ to distribute covers distributing the software with
29
+ changes and new works permitted by [Changes and New Works
30
+ License](#changes-and-new-works-license).
31
+
32
+ ## Notices
33
+
34
+ You must ensure that anyone who gets a copy of any part of
35
+ the software from you also gets a copy of these terms or the
36
+ URL for them above, as well as copies of any plain-text lines
37
+ beginning with `Required Notice:` that the licensor provided
38
+ with the software. For example:
39
+
40
+ > Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
41
+
42
+ ## Changes and New Works License
43
+
44
+ The licensor grants you an additional copyright license to
45
+ make changes and new works based on the software for any
46
+ permitted purpose.
47
+
48
+ ## Patent License
49
+
50
+ The licensor grants you a patent license for the software that
51
+ covers patent claims the licensor can license, or becomes able
52
+ to license, that you would infringe by using the software.
53
+
54
+ ## Noncompete
55
+
56
+ Any purpose is a permitted purpose, except for providing to
57
+ others any product that competes with the software.
58
+
59
+ ## Competition
60
+
61
+ If you use this software to market a product as a substitute
62
+ for the functionality or value of the software, it competes
63
+ with the software. A product may compete regardless how it is
64
+ designed or deployed. For example, a product may compete even
65
+ if it provides its functionality via any kind of interface
66
+ (including services, libraries or plug-ins), even if it is
67
+ ported to a different platforms or programming languages,
68
+ and even if it is provided free of charge.
69
+
70
+ ## Fair Use
71
+
72
+ You may have "fair use" rights for the software under the
73
+ law. These terms do not limit them.
74
+
75
+ ## No Other Rights
76
+
77
+ These terms do not allow you to sublicense or transfer any of
78
+ your licenses to anyone else, or prevent the licensor from
79
+ granting licenses to anyone else. These terms do not imply
80
+ any other licenses.
81
+
82
+ ## Patent Defense
83
+
84
+ If you make any written claim that the software infringes or
85
+ contributes to infringement of any patent, your patent license
86
+ for the software granted under these terms ends immediately. If
87
+ your company makes such a claim, your patent license ends
88
+ immediately for work on behalf of your company.
89
+
90
+ ## Violations
91
+
92
+ The first time you are notified in writing that you have
93
+ violated any of these terms, or done anything with the software
94
+ not covered by your licenses, your licenses can nonetheless
95
+ continue if you come into full compliance with these terms,
96
+ and take practical steps to correct past violations, within
97
+ 32 days of receiving notice. Otherwise, all your licenses
98
+ end immediately.
99
+
100
+ ## No Liability
101
+
102
+ ***As far as the law allows, the software comes as is, without
103
+ any warranty or condition, and the licensor will not be liable
104
+ to you for any damages arising out of these terms or the use
105
+ or nature of the software, under any kind of legal claim.***
106
+
107
+ ## Definitions
108
+
109
+ The **licensor** is the individual or entity offering these
110
+ terms, and the **software** is the software the licensor makes
111
+ available under these terms.
112
+
113
+ A **product** can be a good or service, or a combination
114
+ of them.
115
+
116
+ **You** refers to the individual or entity agreeing to these
117
+ terms.
118
+
119
+ **Your company** is any legal entity, sole proprietorship,
120
+ or other kind of organization that you work for, plus all
121
+ organizations that have control over, are under the control of,
122
+ or are under common control with that organization. **Control**
123
+ means ownership of substantially all the assets of an entity,
124
+ or the power to direct its management and policies by vote,
125
+ contract, or otherwise. Control can be direct or indirect.
126
+
127
+ **Your licenses** are all the licenses granted to you for the
128
+ software under these terms.
129
+
130
+ **Use** means anything you do with the software requiring one
131
+ of your licenses.