agentic-team-templates 0.13.1 → 0.14.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 (54) hide show
  1. package/README.md +6 -1
  2. package/package.json +1 -1
  3. package/src/index.js +22 -2
  4. package/src/index.test.js +5 -0
  5. package/templates/cpp-expert/.cursorrules/concurrency.md +211 -0
  6. package/templates/cpp-expert/.cursorrules/error-handling.md +170 -0
  7. package/templates/cpp-expert/.cursorrules/memory-and-ownership.md +220 -0
  8. package/templates/cpp-expert/.cursorrules/modern-cpp.md +211 -0
  9. package/templates/cpp-expert/.cursorrules/overview.md +87 -0
  10. package/templates/cpp-expert/.cursorrules/performance.md +223 -0
  11. package/templates/cpp-expert/.cursorrules/testing.md +230 -0
  12. package/templates/cpp-expert/.cursorrules/tooling.md +312 -0
  13. package/templates/cpp-expert/CLAUDE.md +242 -0
  14. package/templates/csharp-expert/.cursorrules/aspnet-core.md +311 -0
  15. package/templates/csharp-expert/.cursorrules/async-patterns.md +206 -0
  16. package/templates/csharp-expert/.cursorrules/dependency-injection.md +206 -0
  17. package/templates/csharp-expert/.cursorrules/error-handling.md +235 -0
  18. package/templates/csharp-expert/.cursorrules/language-features.md +204 -0
  19. package/templates/csharp-expert/.cursorrules/overview.md +92 -0
  20. package/templates/csharp-expert/.cursorrules/performance.md +251 -0
  21. package/templates/csharp-expert/.cursorrules/testing.md +282 -0
  22. package/templates/csharp-expert/.cursorrules/tooling.md +254 -0
  23. package/templates/csharp-expert/CLAUDE.md +360 -0
  24. package/templates/java-expert/.cursorrules/concurrency.md +209 -0
  25. package/templates/java-expert/.cursorrules/error-handling.md +205 -0
  26. package/templates/java-expert/.cursorrules/modern-java.md +216 -0
  27. package/templates/java-expert/.cursorrules/overview.md +81 -0
  28. package/templates/java-expert/.cursorrules/performance.md +239 -0
  29. package/templates/java-expert/.cursorrules/persistence.md +262 -0
  30. package/templates/java-expert/.cursorrules/spring-boot.md +262 -0
  31. package/templates/java-expert/.cursorrules/testing.md +272 -0
  32. package/templates/java-expert/.cursorrules/tooling.md +301 -0
  33. package/templates/java-expert/CLAUDE.md +325 -0
  34. package/templates/javascript-expert/.cursorrules/overview.md +5 -3
  35. package/templates/javascript-expert/.cursorrules/typescript-deep-dive.md +348 -0
  36. package/templates/javascript-expert/CLAUDE.md +34 -3
  37. package/templates/kotlin-expert/.cursorrules/coroutines.md +237 -0
  38. package/templates/kotlin-expert/.cursorrules/error-handling.md +149 -0
  39. package/templates/kotlin-expert/.cursorrules/frameworks.md +227 -0
  40. package/templates/kotlin-expert/.cursorrules/language-features.md +231 -0
  41. package/templates/kotlin-expert/.cursorrules/overview.md +77 -0
  42. package/templates/kotlin-expert/.cursorrules/performance.md +185 -0
  43. package/templates/kotlin-expert/.cursorrules/testing.md +213 -0
  44. package/templates/kotlin-expert/.cursorrules/tooling.md +258 -0
  45. package/templates/kotlin-expert/CLAUDE.md +276 -0
  46. package/templates/swift-expert/.cursorrules/concurrency.md +230 -0
  47. package/templates/swift-expert/.cursorrules/error-handling.md +213 -0
  48. package/templates/swift-expert/.cursorrules/language-features.md +246 -0
  49. package/templates/swift-expert/.cursorrules/overview.md +88 -0
  50. package/templates/swift-expert/.cursorrules/performance.md +260 -0
  51. package/templates/swift-expert/.cursorrules/swiftui.md +260 -0
  52. package/templates/swift-expert/.cursorrules/testing.md +286 -0
  53. package/templates/swift-expert/.cursorrules/tooling.md +285 -0
  54. package/templates/swift-expert/CLAUDE.md +275 -0
@@ -0,0 +1,260 @@
1
+ # SwiftUI
2
+
3
+ Declarative UI with composable views, state management, and the observation framework.
4
+
5
+ ## View Fundamentals
6
+
7
+ ```swift
8
+ struct UserProfileView: View {
9
+ let user: User
10
+
11
+ var body: some View {
12
+ VStack(alignment: .leading, spacing: 12) {
13
+ AsyncImage(url: user.avatarURL) { image in
14
+ image.resizable().scaledToFill()
15
+ } placeholder: {
16
+ ProgressView()
17
+ }
18
+ .frame(width: 80, height: 80)
19
+ .clipShape(Circle())
20
+
21
+ Text(user.name)
22
+ .font(.title2)
23
+ .fontWeight(.bold)
24
+
25
+ Text(user.bio)
26
+ .font(.body)
27
+ .foregroundStyle(.secondary)
28
+ }
29
+ .padding()
30
+ }
31
+ }
32
+ ```
33
+
34
+ ## State Management
35
+
36
+ ```swift
37
+ // @State — view-local mutable state (value types)
38
+ struct CounterView: View {
39
+ @State private var count = 0
40
+
41
+ var body: some View {
42
+ Button("Count: \(count)") { count += 1 }
43
+ }
44
+ }
45
+
46
+ // @Binding — two-way connection to parent's state
47
+ struct ToggleRow: View {
48
+ let title: String
49
+ @Binding var isOn: Bool
50
+
51
+ var body: some View {
52
+ Toggle(title, isOn: $isOn)
53
+ }
54
+ }
55
+
56
+ // @StateObject — owned reference type (create once)
57
+ struct UserListView: View {
58
+ @StateObject private var viewModel = UserListViewModel()
59
+
60
+ var body: some View {
61
+ List(viewModel.users) { user in
62
+ UserRow(user: user)
63
+ }
64
+ .task { await viewModel.loadUsers() }
65
+ }
66
+ }
67
+
68
+ // @ObservedObject — non-owned reference type (passed in)
69
+ struct UserDetailView: View {
70
+ @ObservedObject var viewModel: UserDetailViewModel
71
+ // ...
72
+ }
73
+
74
+ // @EnvironmentObject — shared dependency via environment
75
+ struct SettingsView: View {
76
+ @EnvironmentObject var theme: ThemeManager
77
+ // ...
78
+ }
79
+ ```
80
+
81
+ ## Observation Framework (iOS 17+)
82
+
83
+ ```swift
84
+ // @Observable replaces ObservableObject
85
+ @Observable
86
+ class UserViewModel {
87
+ var users: [User] = []
88
+ var isLoading = false
89
+ var error: AppError?
90
+
91
+ func loadUsers() async {
92
+ isLoading = true
93
+ defer { isLoading = false }
94
+ do {
95
+ users = try await userService.fetchAll()
96
+ } catch {
97
+ self.error = AppError(error)
98
+ }
99
+ }
100
+ }
101
+
102
+ // No @Published needed. SwiftUI tracks property access automatically
103
+ struct UserListView: View {
104
+ var viewModel = UserViewModel()
105
+
106
+ var body: some View {
107
+ List(viewModel.users) { user in
108
+ Text(user.name)
109
+ }
110
+ .overlay { if viewModel.isLoading { ProgressView() } }
111
+ .task { await viewModel.loadUsers() }
112
+ }
113
+ }
114
+ ```
115
+
116
+ ## Navigation
117
+
118
+ ```swift
119
+ // NavigationStack with type-safe routing
120
+ enum Route: Hashable {
121
+ case userDetail(User)
122
+ case settings
123
+ case editProfile
124
+ }
125
+
126
+ struct ContentView: View {
127
+ @State private var path = NavigationPath()
128
+
129
+ var body: some View {
130
+ NavigationStack(path: $path) {
131
+ HomeView()
132
+ .navigationDestination(for: Route.self) { route in
133
+ switch route {
134
+ case .userDetail(let user):
135
+ UserDetailView(user: user)
136
+ case .settings:
137
+ SettingsView()
138
+ case .editProfile:
139
+ EditProfileView()
140
+ }
141
+ }
142
+ }
143
+ }
144
+ }
145
+ ```
146
+
147
+ ## Composition Patterns
148
+
149
+ ```swift
150
+ // Small, composable views
151
+ struct AvatarView: View {
152
+ let url: URL?
153
+ var size: CGFloat = 40
154
+
155
+ var body: some View {
156
+ AsyncImage(url: url) { image in
157
+ image.resizable().scaledToFill()
158
+ } placeholder: {
159
+ Image(systemName: "person.circle.fill")
160
+ .foregroundStyle(.secondary)
161
+ }
162
+ .frame(width: size, height: size)
163
+ .clipShape(Circle())
164
+ }
165
+ }
166
+
167
+ // ViewModifier for reusable styling
168
+ struct CardModifier: ViewModifier {
169
+ func body(content: Content) -> some View {
170
+ content
171
+ .padding()
172
+ .background(.background)
173
+ .clipShape(RoundedRectangle(cornerRadius: 12))
174
+ .shadow(radius: 2)
175
+ }
176
+ }
177
+
178
+ extension View {
179
+ func cardStyle() -> some View {
180
+ modifier(CardModifier())
181
+ }
182
+ }
183
+
184
+ // Usage: Text("Hello").cardStyle()
185
+ ```
186
+
187
+ ## Lists and Performance
188
+
189
+ ```swift
190
+ // Lazy loading
191
+ struct UserListView: View {
192
+ let users: [User]
193
+
194
+ var body: some View {
195
+ List {
196
+ ForEach(users) { user in
197
+ UserRow(user: user)
198
+ }
199
+ }
200
+ .listStyle(.plain)
201
+ }
202
+ }
203
+
204
+ // LazyVStack for custom layouts
205
+ ScrollView {
206
+ LazyVStack(spacing: 8) {
207
+ ForEach(items) { item in
208
+ ItemView(item: item) // Only created when visible
209
+ }
210
+ }
211
+ }
212
+ ```
213
+
214
+ ## Previews
215
+
216
+ ```swift
217
+ #Preview("User Profile") {
218
+ UserProfileView(user: .preview)
219
+ .padding()
220
+ }
221
+
222
+ #Preview("Loading State") {
223
+ UserProfileView(user: .preview)
224
+ .redacted(reason: .placeholder)
225
+ }
226
+
227
+ // Preview data
228
+ extension User {
229
+ static var preview: User {
230
+ User(id: UUID(), name: "Jane Doe", email: "jane@example.com")
231
+ }
232
+ }
233
+ ```
234
+
235
+ ## Anti-Patterns
236
+
237
+ ```swift
238
+ // Never: massive body properties
239
+ var body: some View {
240
+ // 200 lines of nested views
241
+ }
242
+ // Use: extract subviews as separate structs or computed properties
243
+
244
+ // Never: business logic in views
245
+ var body: some View {
246
+ Button("Submit") {
247
+ let valid = email.contains("@") && password.count >= 8
248
+ if valid { /* ... */ }
249
+ }
250
+ }
251
+ // Use: view model with dedicated validation
252
+
253
+ // Never: @ObservedObject for view-created objects
254
+ @ObservedObject var vm = MyViewModel() // Recreated on every view update!
255
+ // Use: @StateObject for view-owned objects
256
+
257
+ // Never: ignoring .task lifecycle
258
+ .onAppear { Task { await load() } } // No automatic cancellation
259
+ // Use: .task { await load() } — cancelled when view disappears
260
+ ```
@@ -0,0 +1,286 @@
1
+ # Swift Testing
2
+
3
+ XCTest, Swift Testing framework, and UI testing. Test behavior with expressive assertions.
4
+
5
+ ## Framework Stack
6
+
7
+ | Tool | Purpose |
8
+ |------|---------|
9
+ | Swift Testing | Modern test framework (Swift 5.10+) |
10
+ | XCTest | Traditional test framework |
11
+ | ViewInspector | SwiftUI view testing |
12
+ | XCUITest | UI automation testing |
13
+ | swift-snapshot-testing | Snapshot/screenshot testing |
14
+ | OHHTTPStubs / URLProtocol | Network mocking |
15
+
16
+ ## Swift Testing Framework
17
+
18
+ ```swift
19
+ import Testing
20
+
21
+ @Suite("UserService")
22
+ struct UserServiceTests {
23
+ let sut: UserService
24
+ let mockRepo: MockUserRepository
25
+
26
+ init() {
27
+ mockRepo = MockUserRepository()
28
+ sut = UserService(repository: mockRepo)
29
+ }
30
+
31
+ @Test("creates user with valid input")
32
+ func createUserValid() async throws {
33
+ let request = CreateUserRequest(name: "Alice", email: "alice@test.com")
34
+
35
+ let user = try await sut.create(request)
36
+
37
+ #expect(user.name == "Alice")
38
+ #expect(user.email == "alice@test.com")
39
+ #expect(user.id != UUID())
40
+ }
41
+
42
+ @Test("rejects duplicate email")
43
+ func rejectsDuplicateEmail() async {
44
+ mockRepo.existingEmails = ["alice@test.com"]
45
+ let request = CreateUserRequest(name: "Alice", email: "alice@test.com")
46
+
47
+ await #expect(throws: ValidationError.duplicateEmail) {
48
+ try await sut.create(request)
49
+ }
50
+ }
51
+
52
+ @Test("validates email format", arguments: [
53
+ "invalid",
54
+ "@missing.local",
55
+ "no-at-sign",
56
+ "",
57
+ ])
58
+ func invalidEmails(email: String) async {
59
+ let request = CreateUserRequest(name: "Test", email: email)
60
+
61
+ await #expect(throws: ValidationError.invalidEmail) {
62
+ try await sut.create(request)
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+ ## XCTest (Traditional)
69
+
70
+ ```swift
71
+ final class OrderServiceTests: XCTestCase {
72
+ private var sut: OrderService!
73
+ private var mockInventory: MockInventoryClient!
74
+
75
+ override func setUp() {
76
+ super.setUp()
77
+ mockInventory = MockInventoryClient()
78
+ sut = OrderService(inventory: mockInventory)
79
+ }
80
+
81
+ override func tearDown() {
82
+ sut = nil
83
+ mockInventory = nil
84
+ super.tearDown()
85
+ }
86
+
87
+ func test_createOrder_withValidItems_succeeds() async throws {
88
+ // Arrange
89
+ mockInventory.availableStock = ["SKU-001": 10]
90
+ let request = CreateOrderRequest(items: [.init(sku: "SKU-001", quantity: 2)])
91
+
92
+ // Act
93
+ let order = try await sut.create(request)
94
+
95
+ // Assert
96
+ XCTAssertEqual(order.items.count, 1)
97
+ XCTAssertEqual(order.status, .pending)
98
+ XCTAssertEqual(mockInventory.reserveCalls.count, 1)
99
+ }
100
+
101
+ func test_createOrder_withInsufficientStock_throws() async {
102
+ mockInventory.availableStock = ["SKU-001": 0]
103
+ let request = CreateOrderRequest(items: [.init(sku: "SKU-001", quantity: 5)])
104
+
105
+ do {
106
+ _ = try await sut.create(request)
107
+ XCTFail("Expected OrderError.insufficientStock")
108
+ } catch let error as OrderError {
109
+ XCTAssertEqual(error, .insufficientStock("SKU-001"))
110
+ } catch {
111
+ XCTFail("Unexpected error: \(error)")
112
+ }
113
+ }
114
+ }
115
+ ```
116
+
117
+ ## Async Testing
118
+
119
+ ```swift
120
+ // Swift Testing — async is native
121
+ @Test func fetchUsers() async throws {
122
+ let users = try await sut.fetchAll()
123
+ #expect(users.count == 3)
124
+ }
125
+
126
+ // XCTest — async/await support
127
+ func test_fetchUsers() async throws {
128
+ let users = try await sut.fetchAll()
129
+ XCTAssertEqual(users.count, 3)
130
+ }
131
+
132
+ // Testing with timeouts (XCTest)
133
+ func test_longRunningOperation() async throws {
134
+ let expectation = expectation(description: "completes")
135
+
136
+ Task {
137
+ _ = try await sut.processLargeDataset()
138
+ expectation.fulfill()
139
+ }
140
+
141
+ await fulfillment(of: [expectation], timeout: 10)
142
+ }
143
+ ```
144
+
145
+ ## Mocking with Protocols
146
+
147
+ ```swift
148
+ // Protocol-based dependency
149
+ protocol UserRepository {
150
+ func findById(_ id: UUID) async throws -> User?
151
+ func save(_ user: User) async throws -> User
152
+ func delete(_ id: UUID) async throws
153
+ }
154
+
155
+ // Mock implementation
156
+ final class MockUserRepository: UserRepository {
157
+ var users: [UUID: User] = [:]
158
+ var saveCalls: [User] = []
159
+ var deleteCalls: [UUID] = []
160
+ var findByIdError: Error?
161
+
162
+ func findById(_ id: UUID) async throws -> User? {
163
+ if let error = findByIdError { throw error }
164
+ return users[id]
165
+ }
166
+
167
+ func save(_ user: User) async throws -> User {
168
+ saveCalls.append(user)
169
+ users[user.id] = user
170
+ return user
171
+ }
172
+
173
+ func delete(_ id: UUID) async throws {
174
+ deleteCalls.append(id)
175
+ users.removeValue(forKey: id)
176
+ }
177
+ }
178
+ ```
179
+
180
+ ## Network Mocking
181
+
182
+ ```swift
183
+ // URLProtocol-based mock
184
+ class MockURLProtocol: URLProtocol {
185
+ static var requestHandler: ((URLRequest) throws -> (HTTPURLResponse, Data))?
186
+
187
+ override class func canInit(with request: URLRequest) -> Bool { true }
188
+ override class func canonicalRequest(for request: URLRequest) -> URLRequest { request }
189
+
190
+ override func startLoading() {
191
+ guard let handler = Self.requestHandler else {
192
+ fatalError("requestHandler not set")
193
+ }
194
+ do {
195
+ let (response, data) = try handler(request)
196
+ client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
197
+ client?.urlProtocol(self, didLoad: data)
198
+ client?.urlProtocolDidFinishLoading(self)
199
+ } catch {
200
+ client?.urlProtocol(self, didFailWithError: error)
201
+ }
202
+ }
203
+
204
+ override func stopLoading() {}
205
+ }
206
+
207
+ // Usage in tests
208
+ func test_fetchUser_decodesResponse() async throws {
209
+ let userData = try JSONEncoder().encode(User.preview)
210
+ MockURLProtocol.requestHandler = { request in
211
+ let response = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)!
212
+ return (response, userData)
213
+ }
214
+
215
+ let config = URLSessionConfiguration.ephemeral
216
+ config.protocolClasses = [MockURLProtocol.self]
217
+ let session = URLSession(configuration: config)
218
+ let client = APIClient(session: session)
219
+
220
+ let user = try await client.fetchUser(id: UUID())
221
+ XCTAssertEqual(user.name, "Jane Doe")
222
+ }
223
+ ```
224
+
225
+ ## UI Testing
226
+
227
+ ```swift
228
+ final class LoginUITests: XCTestCase {
229
+ let app = XCUIApplication()
230
+
231
+ override func setUp() {
232
+ super.setUp()
233
+ continueAfterFailure = false
234
+ app.launchArguments = ["--uitesting"]
235
+ app.launch()
236
+ }
237
+
238
+ func test_loginFlow_withValidCredentials() {
239
+ let emailField = app.textFields["email-field"]
240
+ emailField.tap()
241
+ emailField.typeText("user@test.com")
242
+
243
+ let passwordField = app.secureTextFields["password-field"]
244
+ passwordField.tap()
245
+ passwordField.typeText("password123")
246
+
247
+ app.buttons["login-button"].tap()
248
+
249
+ XCTAssertTrue(app.staticTexts["welcome-label"].waitForExistence(timeout: 5))
250
+ }
251
+ }
252
+ ```
253
+
254
+ ## Test Naming
255
+
256
+ ```swift
257
+ // XCTest: test_[method]_[condition]_[expected]
258
+ func test_validate_emptyEmail_throwsValidationError()
259
+ func test_create_validRequest_returnsNewUser()
260
+ func test_delete_nonexistentUser_throwsNotFound()
261
+
262
+ // Swift Testing: descriptive strings
263
+ @Test("validates email format rejects empty string")
264
+ @Test("creates user with all required fields")
265
+ @Test("deletes existing user successfully")
266
+ ```
267
+
268
+ ## Anti-Patterns
269
+
270
+ ```swift
271
+ // Never: testing implementation details
272
+ XCTAssertEqual(viewModel.fetchCallCount, 1) // Fragile
273
+ // Test the observable outcome instead
274
+
275
+ // Never: shared mutable state between tests
276
+ static var sharedDatabase = Database() // Tests affect each other
277
+ // Use: setUp/tearDown for fresh state
278
+
279
+ // Never: testing with real network calls
280
+ let user = try await realAPIClient.fetchUser(id: uuid) // Flaky
281
+ // Use: protocol mocking or URLProtocol
282
+
283
+ // Never: sleeping in tests
284
+ try await Task.sleep(for: .seconds(2)) // Slow and flaky
285
+ // Use: expectations with timeouts, or test schedulers
286
+ ```