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,847 @@
1
+ # AsyncAlgorithms Package
2
+
3
+ Use this when:
4
+
5
+ - You need time-based operators (debounce, throttle, timers).
6
+ - You need to combine multiple async sequences (merge, combineLatest, zip).
7
+ - You are migrating from Combine or RxSwift operators to Swift Concurrency equivalents.
8
+
9
+ Skip this file if:
10
+
11
+ - You need basic `AsyncStream` bridging for callbacks or delegates. Use `async-sequences.md`.
12
+ - You are choosing between `Task`, `async let`, or task groups. Use `tasks.md`.
13
+
14
+ Jump to:
15
+
16
+ - Quick Start
17
+ - Time-Based Operators
18
+ - Combining Operators
19
+ - Multi-Consumer Scenarios
20
+ - Combine Migration Guide
21
+ - Best Practices
22
+
23
+ ---
24
+
25
+ ## Quick Start
26
+
27
+ Top 5 most common operators:
28
+
29
+ ```swift
30
+ import AsyncAlgorithms
31
+
32
+ // 1. Debounce rapid inputs
33
+ for await query in searchQueryStream.debounce(for: .milliseconds(500)) {
34
+ await performSearch(query)
35
+ }
36
+
37
+ // 2. Throttle repeated actions
38
+ for await _ in buttonClicks.throttle(for: .seconds(1)) {
39
+ await performAction()
40
+ }
41
+
42
+ // 3. Merge multiple independent streams
43
+ for await message in chat1Messages.merge(chat2Messages) {
44
+ display(message)
45
+ }
46
+
47
+ // 4. Combine dependent values
48
+ for await (username, email) in usernameStream.combineLatest(emailStream) {
49
+ validateForm(username: username, email: email)
50
+ }
51
+
52
+ // 5. Zip paired operations
53
+ for await (image, metadata) in imageStream.zip(metadataStream) {
54
+ await cache(image: image, metadata: metadata)
55
+ }
56
+ ```
57
+
58
+ > **See**: [AsyncAlgorithms on GitHub](https://github.com/apple/swift-async-algorithms)
59
+
60
+ ---
61
+
62
+ ## Overview & Installation
63
+
64
+ ### What is AsyncAlgorithms?
65
+
66
+ Extends Swift's AsyncSequence with time-based operators, stream combination tools, and multi-consumer primitives.
67
+
68
+ **Use for**:
69
+ - Time-based operations: debounce, throttle, timers
70
+ - Combining streams: merge, combineLatest, zip, chain
71
+ - Multi-consumer scenarios: AsyncChannel for backpressure
72
+ - Specific operators: removeDuplicates, chunks, adjacentPairs, compacted
73
+
74
+ **Use standard library for**:
75
+ - Bridging callbacks: AsyncStream
76
+ - Simple iteration: for await in sequence
77
+ - Single-value operations: async/await
78
+
79
+ ### Installation
80
+
81
+ ```swift
82
+ dependencies: [
83
+ .package(url: "https://github.com/apple/swift-async-algorithms", from: "1.0.0")
84
+ ]
85
+
86
+ targets: [
87
+ .target(
88
+ name: "MyTarget",
89
+ dependencies: [
90
+ .product(name: "AsyncAlgorithms", package: "swift-async-algorithms")
91
+ ]
92
+ )
93
+ ]
94
+ ```
95
+
96
+ Import:
97
+
98
+ ```swift
99
+ import AsyncAlgorithms
100
+ ```
101
+
102
+ ---
103
+
104
+ ## Time-Based Operators
105
+
106
+ ### debounce(for:tolerance:clock:)
107
+
108
+ Wait for inactivity before emitting. Use for rapid inputs like search fields.
109
+
110
+ #### Example: ArticleSearcher
111
+
112
+ ```swift
113
+ import AsyncAlgorithms
114
+
115
+ @Observable
116
+ final class ArticleSearcher {
117
+ @MainActor private(set) var results: [Article] = []
118
+ private var searchQueryContinuation: AsyncStream<String>.Continuation?
119
+
120
+ private lazy var searchQueryStream: AsyncStream<String> = {
121
+ AsyncStream { continuation in
122
+ searchQueryContinuation = continuation
123
+ }
124
+ }()
125
+
126
+ func search(_ query: String) {
127
+ searchQueryContinuation?.yield(query)
128
+ }
129
+
130
+ func startDebouncedSearch() {
131
+ Task { @MainActor in
132
+ for await query in searchQueryStream.debounce(for: .milliseconds(500)) {
133
+ self.results = []
134
+ self.results = await APIClient.searchArticles(query)
135
+ }
136
+ }
137
+ }
138
+ }
139
+ ```
140
+
141
+ **Benefits**: Automatic cancellation, backpressure, cleaner than manual Task.sleep.
142
+
143
+ #### ❌ Anti-Pattern
144
+
145
+ ```swift
146
+ // Bad: Every keystroke spawns new task
147
+ func search(_ query: String) {
148
+ Task {
149
+ try? await Task.sleep(for: .milliseconds(500))
150
+ await performSearch(query)
151
+ }
152
+ }
153
+ ```
154
+
155
+ **Problem**: Multiple tasks execute simultaneously, causing out-of-order results.
156
+
157
+ **Solution**: Use `debounce()` for automatic backpressure.
158
+
159
+ ---
160
+
161
+ ### throttle(for:clock:reducing:)
162
+
163
+ Emit at most one value per interval. Use for repeated actions like button taps.
164
+
165
+ #### Example: Like Button
166
+
167
+ ```swift
168
+ import AsyncAlgorithms
169
+
170
+ struct LikeButton: View {
171
+ @State private var tapStream = AsyncStream<Void> { continuation in
172
+ // Continuation stored externally
173
+ }
174
+ @State private var isLiked = false
175
+
176
+ var body: some View {
177
+ Button(action: {
178
+ tapStream.continuation?.yield()
179
+ }) {
180
+ Image(systemName: isLiked ? "heart.fill" : "heart")
181
+ }
182
+ .task {
183
+ await handleThrottledTaps()
184
+ }
185
+ }
186
+
187
+ private func handleThrottledTaps() async {
188
+ for await _ in tapStream.throttle(for: .seconds(1)) {
189
+ await toggleLike()
190
+ }
191
+ }
192
+
193
+ private func toggleLike() async {
194
+ isLiked.toggle()
195
+ await APIClient.updateLikeStatus(isLiked: isLiked)
196
+ }
197
+ }
198
+ ```
199
+
200
+ #### Understanding reducing Parameter
201
+
202
+ ```swift
203
+ // .latest (default): Keep most recent value
204
+ for await value in events.throttle(for: .seconds(1)) {
205
+ process(value)
206
+ }
207
+
208
+ // .oldest: Keep first value
209
+ for await value in events.throttle(for: .seconds(1), reducing: .oldest) {
210
+ process(value)
211
+ }
212
+
213
+ // Custom: Sum all values
214
+ for await value in events.throttle(for: .seconds(1)) { $0 + $1 } {
215
+ process(value)
216
+ }
217
+ ```
218
+
219
+ ---
220
+
221
+ ### AsyncTimerSequence
222
+
223
+ Emit values at regular intervals. Use for periodic refresh or countdown timers.
224
+
225
+ #### Example: Feed Refresh
226
+
227
+ ```swift
228
+ import AsyncAlgorithms
229
+
230
+ @MainActor @Observable
231
+ final class FeedViewModel {
232
+ private(set) var articles: [Article] = []
233
+ private var refreshTask: Task<Void, Never>?
234
+
235
+ func startAutoRefresh() {
236
+ refreshTask = Task {
237
+ for await _ in AsyncTimerSequence(interval: .seconds(30)) {
238
+ await refreshFeed()
239
+ }
240
+ }
241
+ }
242
+
243
+ private func refreshFeed() async {
244
+ articles = await APIClient.fetchLatestArticles()
245
+ }
246
+ }
247
+ ```
248
+
249
+ #### ❌ Anti-Pattern
250
+
251
+ ```swift
252
+ // Bad: Manual timer implementation
253
+ func startTimer() {
254
+ Task {
255
+ while !Task.isCancelled {
256
+ performAction()
257
+ try? await Task.sleep(for: .seconds(1))
258
+ }
259
+ }
260
+ }
261
+ ```
262
+
263
+ **Solution**: Use `AsyncTimerSequence`.
264
+
265
+ ---
266
+
267
+ ## Combining Operators
268
+
269
+ ### merge(_:...)
270
+
271
+ Combine sequences into one, emitting as they arrive. **Stable operator ✅**
272
+
273
+ Use for independent data sources that don't depend on each other.
274
+
275
+ #### Example: Multi-Room Chat
276
+
277
+ ```swift
278
+ import AsyncAlgorithms
279
+
280
+ actor ChatManager {
281
+ private var messageContinuations: [String: AsyncStream<ChatMessage>.Continuation] = [:]
282
+
283
+ func getMessagesStream(roomID: String) -> AsyncStream<ChatMessage> {
284
+ AsyncStream { continuation in
285
+ messageContinuations[roomID] = continuation
286
+ }
287
+ }
288
+
289
+ func receiveMessage(_ message: ChatMessage) {
290
+ messageContinuations[message.roomID]?.yield(message)
291
+ }
292
+
293
+ func startMonitoring(rooms: [String]) -> AsyncStream<ChatMessage> {
294
+ let streams = rooms.map { getMessagesStream(roomID: $0) }
295
+ return streams.merge()
296
+ }
297
+ }
298
+
299
+ // Usage
300
+ let manager = ChatManager()
301
+ let mergedMessages = await manager.startMonitoring(rooms: ["general", "random"])
302
+
303
+ for await message in mergedMessages {
304
+ print("[\(message.roomID)] \(message.text)")
305
+ }
306
+ ```
307
+
308
+ **Behavior**: Values emit as they arrive from any source. Order interleaved by timing. Cancellation propagates to all sources.
309
+
310
+ ---
311
+
312
+ ### combineLatest(_:...)
313
+
314
+ Combine sequences, emitting tuple when any source emits. Always uses latest values. **Stable operator ✅**
315
+
316
+ Use for dependent values that need synchronization.
317
+
318
+ #### Example: Form Validation
319
+
320
+ ```swift
321
+ import AsyncAlgorithms
322
+
323
+ struct SignupForm: View {
324
+ @State private var usernameStream = AsyncStream<String> { /* ... */ }
325
+ @State private var emailStream = AsyncStream<String> { /* ... */ }
326
+ @State private var passwordStream = AsyncStream<String> { /* ... */ }
327
+ @State private var formState = FormState.incomplete
328
+
329
+ var body: some View {
330
+ Form {
331
+ TextField("Username", text: $username)
332
+ TextField("Email", text: $email)
333
+ SecureField("Password", text: $password)
334
+ }
335
+ .task {
336
+ await validateForm()
337
+ }
338
+ }
339
+
340
+ private func validateForm() async {
341
+ for await (username, email, password) in
342
+ usernameStream.combineLatest(emailStream, passwordStream)
343
+ {
344
+ formState = await validate(
345
+ username: username,
346
+ email: email,
347
+ password: password
348
+ )
349
+ }
350
+ }
351
+ }
352
+ ```
353
+
354
+ #### ❌ Anti-Pattern
355
+
356
+ ```swift
357
+ // Bad: Manual value combining
358
+ actor FormValidator {
359
+ private var currentUsername: String = ""
360
+ private var currentEmail: String = ""
361
+
362
+ func updateUsername(_ username: String) {
363
+ currentUsername = username
364
+ checkForm()
365
+ }
366
+ }
367
+ ```
368
+
369
+ **Solution**: Use `combineLatest()`.
370
+
371
+ ---
372
+
373
+ ### zip(_:...)
374
+
375
+ Combine sequences by pairing elements in order. **Stable operator ✅**
376
+
377
+ #### Example: Image + Metadata
378
+
379
+ ```swift
380
+ import AsyncAlgorithms
381
+
382
+ struct ImageLoader {
383
+ func loadImagesWithMetadata(urls: [URL]) async throws -> [LoadedImage] {
384
+ let imageStream = AsyncThrowingStream<UIImage, Error> { continuation in
385
+ Task {
386
+ for url in urls {
387
+ let image = try await downloadImage(from: url)
388
+ continuation.yield(image)
389
+ }
390
+ continuation.finish()
391
+ }
392
+ }
393
+
394
+ let metadataStream = AsyncThrowingStream<ImageMetadata, Error> { continuation in
395
+ Task {
396
+ for url in urls {
397
+ let metadata = try await fetchMetadata(for: url)
398
+ continuation.yield(metadata)
399
+ }
400
+ continuation.finish()
401
+ }
402
+ }
403
+
404
+ var results: [LoadedImage] = []
405
+ for try await (image, metadata) in imageStream.zip(metadataStream) {
406
+ results.append(LoadedImage(image: image, metadata: metadata))
407
+ }
408
+ return results
409
+ }
410
+ }
411
+ ```
412
+
413
+ **Behavior**: Emits tuple when all sequences emit. Maintains order. Finishes when shortest sequence finishes.
414
+
415
+ ---
416
+
417
+ ### chain(_:...)
418
+
419
+ Concatenate sequences sequentially. **Stable operator ✅**
420
+
421
+ #### Example: Paginated Loading
422
+
423
+ ```swift
424
+ import AsyncAlgorithms
425
+
426
+ struct ArticlePaginator {
427
+ func loadAllArticles() -> AsyncStream<[Article]> {
428
+ AsyncStream { continuation in
429
+ Task {
430
+ var page = 1
431
+ var hasMore = true
432
+ while hasMore {
433
+ let articles = try await fetchPage(page: page)
434
+ continuation.yield(articles)
435
+ hasMore = articles.count == 20
436
+ page += 1
437
+ }
438
+ continuation.finish()
439
+ }
440
+ }
441
+ }
442
+ }
443
+
444
+ // Usage: Chain cache + network
445
+ for await articles in loadFromCacheStream().chain(loadFromNetworkStream()) {
446
+ display(articles)
447
+ }
448
+ ```
449
+
450
+ **Behavior**: Emits all values from first sequence before starting second.
451
+
452
+ ---
453
+
454
+ ## Utility Operators
455
+
456
+ ### removeDuplicates()
457
+
458
+ Remove adjacent duplicates. **Stable operator ✅**
459
+
460
+ ```swift
461
+ import AsyncAlgorithms
462
+
463
+ actor ChatHistory {
464
+ private var messageStream = AsyncStream<ChatMessage> { /* ... */ }
465
+
466
+ func getUniqueMessages() -> AsyncStream<ChatMessage> {
467
+ messageStream.removeDuplicates()
468
+ }
469
+ }
470
+ ```
471
+
472
+ ---
473
+
474
+ ### chunks() and chunked()
475
+
476
+ Collect values into batches. **Stable operator ✅**
477
+
478
+ ```swift
479
+ import AsyncAlgorithms
480
+
481
+ struct BatchProcessor {
482
+ func processLargeDataset(dataStream: AsyncStream<DataItem>) async {
483
+ for await batch in dataStream.chunks(count: 100) {
484
+ await processBatch(batch)
485
+ }
486
+ }
487
+
488
+ func chunkedByTime(dataStream: AsyncStream<DataItem>) async {
489
+ for await batch in dataStream.chunked(by: .seconds(5)) {
490
+ await processBatch(batch)
491
+ }
492
+ }
493
+ }
494
+ ```
495
+
496
+ ---
497
+
498
+ ### compacted() and adjacentPairs()
499
+
500
+ ```swift
501
+ import AsyncAlgorithms
502
+
503
+ // Remove nil values
504
+ for await value in optionalValuesStream.compacted() {
505
+ process(value)
506
+ }
507
+
508
+ // Pair adjacent elements
509
+ for await (previous, current) in valuesStream.adjacentPairs() {
510
+ let difference = current - previous
511
+ }
512
+ ```
513
+
514
+ ---
515
+
516
+ ## Multi-Consumer Scenarios
517
+
518
+ ### AsyncChannel
519
+
520
+ AsyncSequence with backpressure. **Stable operator ✅**
521
+
522
+ Use for producer-consumer patterns with flow control.
523
+
524
+ #### Example: Message Queue
525
+
526
+ ```swift
527
+ import AsyncAlgorithms
528
+
529
+ actor MessageQueue {
530
+ private let channel = AsyncChannel<Message>()
531
+
532
+ func getMessages() -> AsyncStream<Message> {
533
+ channel
534
+ }
535
+
536
+ func enqueue(_ message: Message) async {
537
+ await channel.send(message)
538
+ }
539
+
540
+ func startProcessing() {
541
+ Task {
542
+ for await message in channel {
543
+ await process(message)
544
+ }
545
+ }
546
+ }
547
+ }
548
+
549
+ // Multiple producers
550
+ let queue = MessageQueue()
551
+ Task { await queue.enqueue(Message(type: .userAction, content: "tap")) }
552
+ Task { await queue.enqueue(Message(type: .network, content: "data")) }
553
+ queue.startProcessing()
554
+ ```
555
+
556
+ #### ❌ Anti-Pattern
557
+
558
+ ```swift
559
+ // Bad: Values split unpredictably
560
+ let stream = AsyncStream<Int> { continuation in
561
+ for i in 1...10 {
562
+ continuation.yield(i)
563
+ }
564
+ continuation.finish()
565
+ }
566
+
567
+ Task { for await value in stream { print("Consumer 1: \(value)") } }
568
+ Task { for await value in stream { print("Consumer 2: \(value)") } }
569
+ ```
570
+
571
+ **Problem**: Each value goes to only one consumer.
572
+
573
+ **Solution**: Use `AsyncChannel` for multi-consumer scenarios.
574
+
575
+ ---
576
+
577
+ ### AsyncThrowingChannel
578
+
579
+ Like AsyncChannel but can emit errors. **Stable operator ✅**
580
+
581
+ #### Example: WebSocket
582
+
583
+ ```swift
584
+ import AsyncAlgorithms
585
+
586
+ actor WebSocketConnection {
587
+ private let channel = AsyncThrowingChannel<WebSocketMessage, Error>()
588
+
589
+ func getMessages() -> AsyncThrowingStream<WebSocketMessage, Error> {
590
+ channel
591
+ }
592
+
593
+ func receiveMessage(_ message: WebSocketMessage) async {
594
+ await channel.send(message)
595
+ }
596
+
597
+ func reportError(_ error: Error) async {
598
+ await channel.finish(throwing: error)
599
+ }
600
+ }
601
+
602
+ // Usage
603
+ do {
604
+ for await message in connection.getMessages() {
605
+ handle(message)
606
+ }
607
+ } catch {
608
+ print("WebSocket error: \(error)")
609
+ }
610
+ ```
611
+
612
+ ---
613
+
614
+ ## Combine Migration Guide
615
+
616
+ ### Operator Mapping Table
617
+
618
+ | Combine | AsyncAlgorithms | Status | Alternative |
619
+ |---------|-----------------|---------|-------------|
620
+ | `.debounce()` | `debounce()` | ✅ Stable | - |
621
+ | `.throttle()` | `throttle()` | ✅ Stable | - |
622
+ | `.merge()` | `merge()` | ✅ Stable | - |
623
+ | `.combineLatest()` | `combineLatest()` | ✅ Stable | - |
624
+ | `.zip()` | `zip()` | ✅ Stable | - |
625
+ | `.concat()` | `chain()` | ✅ Stable | - |
626
+ | `.removeDuplicates()` | `removeDuplicates()` | ✅ Stable | - |
627
+ | `.timer()` | `AsyncTimerSequence` | ✅ Stable | - |
628
+ | `.share()` | - | - | `AsyncChannel` |
629
+ | `.flatMap()` | - | - | `TaskGroup` |
630
+ | `.receive(on:)` | - | - | `Task` / `@MainActor` |
631
+ | `.eraseToAnyPublisher()` | - | - | `any AsyncSequence` |
632
+
633
+ ---
634
+
635
+ ### Migration Examples
636
+
637
+ #### Example 1: ArticleSearcher
638
+
639
+ **Before: Combine**
640
+
641
+ ```swift
642
+ import Combine
643
+
644
+ final class ArticleSearcher: ObservableObject {
645
+ @Published private(set) var results: [Article] = []
646
+ @Published var searchQuery = ""
647
+
648
+ init() {
649
+ $searchQuery
650
+ .debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)
651
+ .removeDuplicates()
652
+ .flatMap { query in
653
+ APIClient.searchArticles(query)
654
+ .catch { _ in Just([]) }
655
+ }
656
+ .receive(on: DispatchQueue.main)
657
+ .assign(to: &$results)
658
+ }
659
+ }
660
+ ```
661
+
662
+ **After: AsyncAlgorithms**
663
+
664
+ ```swift
665
+ import AsyncAlgorithms
666
+
667
+ @Observable
668
+ final class ArticleSearcher {
669
+ @MainActor private(set) var results: [Article] = []
670
+ private var searchQueryContinuation: AsyncStream<String>.Continuation?
671
+
672
+ private lazy var searchQueryStream: AsyncStream<String> = {
673
+ AsyncStream { continuation in
674
+ searchQueryContinuation = continuation
675
+ }
676
+ }()
677
+
678
+ func search(_ query: String) {
679
+ searchQueryContinuation?.yield(query)
680
+ }
681
+
682
+ func startDebouncedSearch() {
683
+ Task { @MainActor in
684
+ for await query in searchQueryStream
685
+ .debounce(for: .milliseconds(500))
686
+ .removeDuplicates()
687
+ {
688
+ do {
689
+ self.results = try await APIClient.searchArticles(query)
690
+ } catch {
691
+ self.results = []
692
+ }
693
+ }
694
+ }
695
+ }
696
+ }
697
+ ```
698
+
699
+ **Benefits**: Simpler error handling, no cancellables, automatic cancellation.
700
+
701
+ ---
702
+
703
+ #### Example 2: Multi-Source Loading
704
+
705
+ **Before: Combine Merge**
706
+
707
+ ```swift
708
+ import Combine
709
+
710
+ final class ArticleLoader: ObservableObject {
711
+ @Published private(set) var items: [Item] = []
712
+
713
+ func loadAllSources() {
714
+ let source1 = APIClient.fetchItems(from: .source1)
715
+ let source2 = APIClient.fetchItems(from: .source2)
716
+
717
+ Publishers.Merge(source1, source2)
718
+ .scan([]) { accumulated, new in
719
+ accumulated + new
720
+ }
721
+ .receive(on: DispatchQueue.main)
722
+ .assign(to: &$items)
723
+ }
724
+ }
725
+ ```
726
+
727
+ **After: TaskGroup**
728
+
729
+ ```swift
730
+ import AsyncAlgorithms
731
+
732
+ @Observable
733
+ final class ArticleLoader {
734
+ @MainActor private(set) var items: [Item] = []
735
+
736
+ func loadAllSourcesParallel() async {
737
+ await withTaskGroup(of: [Item].self) { group in
738
+ group.addTask {
739
+ await APIClient.fetchItems(from: .source1)
740
+ }
741
+ group.addTask {
742
+ await APIClient.fetchItems(from: .source2)
743
+ }
744
+
745
+ for await newItems in group {
746
+ items.append(contentsOf: newItems)
747
+ }
748
+ }
749
+ }
750
+ }
751
+ ```
752
+
753
+ **Key difference**: For parallel execution, use `TaskGroup` instead of `flatMap`.
754
+
755
+ ---
756
+
757
+ #### Example 3: Form Validation
758
+
759
+ **Before: Combine**
760
+
761
+ ```swift
762
+ import Combine
763
+
764
+ final class FormValidator: ObservableObject {
765
+ @Published var username = ""
766
+ @Published var email = ""
767
+
768
+ @Published private(set) var formState: FormState = .incomplete
769
+
770
+ init() {
771
+ Publishers.CombineLatest2($username, $email)
772
+ .map { username, email in
773
+ validate(username: username, email: email)
774
+ }
775
+ .assign(to: &$formState)
776
+ }
777
+ }
778
+ ```
779
+
780
+ **After: AsyncAlgorithms or async let**
781
+
782
+ ```swift
783
+ import AsyncAlgorithms
784
+
785
+ @Observable
786
+ final class FormValidator {
787
+ var username = ""
788
+ var email = ""
789
+
790
+ @MainActor private(set) var formState: FormState = .incomplete
791
+
792
+ // Option 1: combineLatest for stream-based validation
793
+ func startStreamValidation() {
794
+ Task { @MainActor in
795
+ for await (username, email) in
796
+ usernameStream.combineLatest(emailStream)
797
+ {
798
+ self.formState = validate(
799
+ username: username,
800
+ email: email
801
+ )
802
+ }
803
+ }
804
+ }
805
+
806
+ // Option 2: async let for simple validation
807
+ func validateForm() async {
808
+ let (username, email) = await (username, email)
809
+ formState = validate(
810
+ username: username,
811
+ email: email
812
+ )
813
+ }
814
+ }
815
+ ```
816
+
817
+ **Choose**:
818
+ - `combineLatest()`: Continuous validation as fields change
819
+ - `async let`: One-time validation when all values available
820
+
821
+ ---
822
+
823
+ ## Common Mistakes Agents Make
824
+
825
+ - **Manual debounce with `Task.sleep`**: This creates multiple concurrent tasks and risks out-of-order results. Use the stream-based `debounce(for:)` operator from AsyncAlgorithms instead.
826
+ - **Sharing `AsyncStream` across multiple consumers**: Values split unpredictably between consumers. Use `AsyncChannel` for multi-consumer scenarios with backpressure. Note: `AsyncChannel` is point-to-point, not broadcast like Combine's `.share()`.
827
+ - **Looking for a `.flatMap` equivalent**: Use `TaskGroup` for fan-out; the semantics differ from Combine/Rx `flatMap`.
828
+ - **Looking for `.receive(on:)` equivalent**: Use `@MainActor` or `Task` context for isolation instead.
829
+
830
+ ## Best Practices
831
+
832
+ 1. **Use time-based operators** for rapid inputs: debounce() for search, throttle() for buttons
833
+ 2. **Combine streams** with merge/combineLatest instead of manual state management
834
+ 3. **Use AsyncChannel** for multi-consumer scenarios with backpressure
835
+ 4. **Ensure Sendable conformance** when using operators across isolation boundaries
836
+ 5. **Leverage cancellation** - Task cancellation propagates through all operators
837
+ 6. **Choose right tool**: AsyncAlgorithms for complex streams, AsyncStream for bridging callbacks
838
+ 7. **Avoid manual sleep loops** - use AsyncTimerSequence instead
839
+
840
+ ---
841
+
842
+ ## Further Learning
843
+
844
+ - [AsyncAlgorithms Documentation](https://github.com/apple/swift-async-algorithms)
845
+ - [Combine Migration Guide](migration.md)
846
+ - [Async Sequences](async-sequences.md)
847
+ - [Tasks](tasks.md) - Task groups and structured concurrency