swift-code-reviewer-skill 1.3.0 → 1.4.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.
@@ -0,0 +1,207 @@
1
+ # Code Review — pointfreeco/isowords
2
+
3
+ **Agent**: Google Gemini CLI with swift-code-reviewer-skill
4
+ **Scope**: `Sources/` (Start using IssueReporting)
5
+ **Commit**: [`c727d3a`](https://github.com/pointfreeco/isowords/commit/c727d3a7c49cf0c98f2fa4f24c562f81e30165f7)
6
+
7
+ ---
8
+
9
+ ## Summary
10
+
11
+ Files: 5 | Critical: 0 | High: 1 | Medium: 3 | Low: 2
12
+
13
+ ---
14
+
15
+ ## Spec Adherence
16
+
17
+ **Source**: commit message — "Start using IssueReporting. (#205)"
18
+
19
+ | Requirement | Status | Location |
20
+ | ---------------------------------------------------------- | -------------------------------------------------- | ---------------------------------------------------------- |
21
+ | Replace `fatalError`/`assertionFailure` with `reportIssue` | ✅ Done | multiple files |
22
+ | Migrate `preconditionFailure` to `reportIssue` | ⚠️ Partial — 2 call sites missed | GameFeature/GameView.swift:134, AudioPlayerClient.swift:67 |
23
+ | No behavioral change for release builds | ✅ Confirmed — `reportIssue` is a no-op in release | — |
24
+ | Tests updated to assert `reportIssue` calls | ❌ Not implemented — no test changes in diff | — |
25
+
26
+ **Missing work**: Two `preconditionFailure` sites not migrated; no test assertions added for
27
+ `reportIssue` invocations (IssueReporting provides `withExpectedIssue` for exactly this).
28
+
29
+ ---
30
+
31
+ ## GameFeature/GameView.swift
32
+
33
+ **High** **SwiftUI Patterns** (line 89)
34
+
35
+ Current:
36
+
37
+ ```swift
38
+ NavigationView {
39
+ WithViewStore(self.store) { viewStore in
40
+ GameBoardView(store: self.store)
41
+ }
42
+ }
43
+ ```
44
+
45
+ Finding: `NavigationView` is deprecated as of iOS 16. `WithViewStore` is the older TCA
46
+ observation pattern — isowords targets iOS 16+ and should use `NavigationStack` with
47
+ the `@Bindable` store observation available in TCA 1.x.
48
+
49
+ Fix:
50
+
51
+ ```swift
52
+ NavigationStack {
53
+ GameBoardView(store: self.store)
54
+ }
55
+ ```
56
+
57
+ And in the view body, replace `WithViewStore` reads with direct `store.someState` access
58
+ via `@Bindable var store: StoreOf<GameFeature>`.
59
+
60
+ ---
61
+
62
+ **Medium** **SwiftUI Patterns** (line 134)
63
+
64
+ Current:
65
+
66
+ ```swift
67
+ preconditionFailure("Unexpected game mode: \(mode)")
68
+ ```
69
+
70
+ Finding: This `preconditionFailure` was not migrated to `reportIssue` in this PR. The PR
71
+ description states the goal is to migrate all hard crashes to `reportIssue`. In production,
72
+ `preconditionFailure` will crash the app; `reportIssue` would log the issue and allow the
73
+ app to degrade gracefully.
74
+
75
+ Fix:
76
+
77
+ ```swift
78
+ reportIssue("Unexpected game mode: \(mode)")
79
+ return // or a safe default path
80
+ ```
81
+
82
+ ---
83
+
84
+ ## AudioPlayerClient.swift
85
+
86
+ **Medium** **Swift Quality** (line 67)
87
+
88
+ Current:
89
+
90
+ ```swift
91
+ preconditionFailure("AudioPlayerClient not implemented")
92
+ ```
93
+
94
+ Finding: Same as above — not migrated to `reportIssue`. Additionally, `"not implemented"`
95
+ as a crash message suggests this may be a stub that should be a real implementation or at
96
+ least a `TODO` tracked in the issue tracker.
97
+
98
+ Fix:
99
+
100
+ ```swift
101
+ reportIssue("AudioPlayerClient: \(#function) not implemented")
102
+ ```
103
+
104
+ ---
105
+
106
+ ## AppFeature/AppReducer.swift
107
+
108
+ **Medium** **Architecture** (line 201)
109
+
110
+ Current:
111
+
112
+ ```swift
113
+ case .game(.delegate(.gameOver)):
114
+ guard let result = state.game?.gameResult else {
115
+ reportIssue("gameOver delegate action fired without a game result")
116
+ return .none
117
+ }
118
+ ```
119
+
120
+ Finding: The `reportIssue` call is correct and well-placed. However, the `guard` falls
121
+ through to `.none` silently — callers observing the game-over flow will see no state
122
+ change and no indication that the invariant was violated. Consider adding a state flag
123
+ or `.send` to surface the degraded state to the UI.
124
+
125
+ Fix: After `reportIssue`, set a recoverable error state:
126
+
127
+ ```swift
128
+ reportIssue("gameOver delegate action fired without a game result")
129
+ state.errorBanner = "Something went wrong. Please restart the game."
130
+ return .none
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Tests/GameFeatureTests/GameViewTests.swift
136
+
137
+ **Low** **Swift Quality** (line 12)
138
+
139
+ Current:
140
+
141
+ ```swift
142
+ import XCTest
143
+ @testable import GameFeature
144
+ ```
145
+
146
+ Finding: isowords has started migrating to Swift Testing (visible in other test files in
147
+ this repo). New test files should use `import Testing` unless XCTest-specific APIs are
148
+ required. XCTest's `XCTAssertEqual` can be replaced with `#expect` for clearer diagnostics.
149
+
150
+ Fix:
151
+
152
+ ```swift
153
+ import Testing
154
+ @testable import GameFeature
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Positive Observations
160
+
161
+ The adoption of `IssueReporting` is architecturally sound — replacing hard crashes with
162
+ soft issue reports significantly improves testability, since `withExpectedIssue` lets tests
163
+ assert that invalid states are reported rather than crashing the test suite.
164
+
165
+ `AppReducer.swift` correctly uses `reportIssue` (not `assertionFailure`) in the newly
166
+ migrated call sites, demonstrating consistent application of the pattern.
167
+
168
+ ---
169
+
170
+ ## Prioritized Action Items
171
+
172
+ - [Must fix] Migrate remaining `preconditionFailure` calls to `reportIssue` (GameView.swift:134, AudioPlayerClient.swift:67)
173
+ - [Should fix] Add `withExpectedIssue` test assertions for newly reportable error paths
174
+ - [Should fix] Replace deprecated `NavigationView` + `WithViewStore` with `NavigationStack` + `@Bindable` (GameView.swift:89)
175
+ - [Consider] Surface degraded state to UI after `reportIssue` in AppReducer (AppReducer.swift:201)
176
+ - [Consider] Migrate GameViewTests to Swift Testing framework
177
+
178
+ ---
179
+
180
+ ## Agent Loop Feedback
181
+
182
+ ### Pattern: Incomplete migration — `preconditionFailure` not replaced (2 occurrences)
183
+
184
+ **Files**: GameFeature/GameView.swift:134, AudioPlayerClient.swift:67
185
+
186
+ **Suggested rule for `GEMINI.md`**:
187
+
188
+ > When migrating crash calls (`fatalError`, `preconditionFailure`, `assertionFailure`) to
189
+ > `reportIssue`, search the entire diff for remaining instances before marking the PR complete.
190
+ > Use `grep -r "preconditionFailure\|fatalError\|assertionFailure" Sources/` to verify.
191
+
192
+ ### Pattern: No tests added for new `reportIssue` call sites (covers 3+ sites)
193
+
194
+ **Files**: AppFeature/AppReducer.swift, GameFeature/GameView.swift, AudioPlayerClient.swift
195
+
196
+ **Suggested rule for `GEMINI.md`**:
197
+
198
+ > Every new `reportIssue` call site must have a corresponding `withExpectedIssue { }` test.
199
+ > IssueReporting is only valuable if tests verify the reports fire — otherwise it is
200
+ > indistinguishable from a no-op.
201
+
202
+ ---
203
+
204
+ _Representative demonstration. Generated against commit
205
+ [`c727d3a`](https://github.com/pointfreeco/isowords/commit/c727d3a7c49cf0c98f2fa4f24c562f81e30165f7)
206
+ of [pointfreeco/isowords](https://github.com/pointfreeco/isowords).
207
+ Line numbers and snippets are illustrative of the patterns the skill detects in this codebase._
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swift-code-reviewer-skill",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Claude Code skill for comprehensive Swift/SwiftUI code reviews with multi-layer analysis",
5
5
  "keywords": [
6
6
  "claude",
@@ -40,6 +40,8 @@
40
40
  },
41
41
  "files": [
42
42
  "bin/",
43
+ "core/",
44
+ "examples/",
43
45
  "references/",
44
46
  "skills/",
45
47
  "templates/",
@@ -49,6 +51,9 @@
49
51
  "CONTRIBUTING.md",
50
52
  "CHANGELOG.md"
51
53
  ],
54
+ "dependencies": {
55
+ "@inquirer/prompts": "^7"
56
+ },
52
57
  "engines": {
53
58
  "node": ">=16.0.0"
54
59
  }
@@ -0,0 +1,78 @@
1
+ # Swift Code Review Agent
2
+
3
+ You are a senior Swift/SwiftUI code reviewer. Your job is to review code changes before they are pushed to the remote repository.
4
+
5
+ ## Skills
6
+
7
+ Load and follow the rules from `~/.claude/skills/swift-code-reviewer-skill/SKILL.md` and all files in its `references/` directory.
8
+
9
+ ## Workflow
10
+
11
+ When invoked, execute these steps in order:
12
+
13
+ ### 1. Collect the diff
14
+
15
+ ```bash
16
+ git diff --staged -- '*.swift'
17
+ ```
18
+
19
+ If nothing is staged, fall back to:
20
+
21
+ ```bash
22
+ git diff HEAD -- '*.swift'
23
+ ```
24
+
25
+ If still empty, tell the user there are no Swift changes to review.
26
+
27
+ ### 2. Run SwiftLint (if available)
28
+
29
+ ```bash
30
+ if command -v swiftlint &>/dev/null; then
31
+ swiftlint lint --config .swiftlint.yml --quiet 2>/dev/null || swiftlint lint --quiet
32
+ fi
33
+ ```
34
+
35
+ Collect any warnings or errors. If SwiftLint is not installed, skip and note it.
36
+
37
+ ### 3. Review
38
+
39
+ Analyze the diff using the swift-code-reviewer-skill rules. Focus on:
40
+
41
+ - **Architecture**: MVVM compliance, separation of concerns, dependency injection
42
+ - **SwiftUI**: proper use of @State/@Binding/@Observable, view composition, performance
43
+ - **Safety**: force unwraps, force casts, retain cycles, unhandled optionals
44
+ - **Naming**: clarity, Swift API Design Guidelines compliance
45
+ - **Concurrency**: proper async/await, MainActor usage, data races
46
+ - **Tests**: coverage gaps for new/changed logic
47
+
48
+ ### 4. Output format
49
+
50
+ ```markdown
51
+ ## Summary
52
+
53
+ <what changed in 1-2 sentences>
54
+
55
+ ## Issues
56
+
57
+ <list issues with file:line, grouped by severity>
58
+
59
+ ## SwiftLint
60
+
61
+ <summarize lint findings or "Clean">
62
+
63
+ ## Suggestions
64
+
65
+ <actionable improvements>
66
+
67
+ ## Verdict
68
+
69
+ Ready to push | Fix warnings first | Do not push
70
+ ```
71
+
72
+ ### 5. Rules
73
+
74
+ - Be direct. No filler, no praise for basic competence.
75
+ - Every issue must include the file and line number.
76
+ - If the diff is clean, say so — don't invent problems.
77
+ - Prioritize issues that would break production or cause bugs.
78
+ - Ignore generated files, Pods, and third-party code.
@@ -0,0 +1,211 @@
1
+ # Swift/SwiftUI Code Review — Codex Agent Guide
2
+
3
+ You are a senior Swift/SwiftUI code reviewer. Review changes using the multi-phase workflow below.
4
+ Project standards live in `AGENTS.md` (project root). If `AGENTS.md` is absent, fall back to
5
+ Apple's official Swift API Design Guidelines.
6
+
7
+ ---
8
+
9
+ ## Phase 1 — Context Gathering
10
+
11
+ 1. **Read the spec** (if a PR number is provided):
12
+
13
+ ```bash
14
+ gh pr view <n> --json title,body,closingIssuesReferences,labels
15
+ ```
16
+
17
+ Extract: goal, acceptance criteria (checkboxes / "should" / "must"), edge cases, out-of-scope items.
18
+ If no PR context → infer intent from the diff.
19
+
20
+ 2. **Load project standards** from `AGENTS.md`. Note any rules that apply to the changed files.
21
+ If absent → add _"No project standards found — using Apple defaults"_ to report, continue.
22
+
23
+ 3. **Obtain changeset**:
24
+
25
+ ```bash
26
+ git diff --staged -- '*.swift' # staged
27
+ git diff HEAD -- '*.swift' # fallback: unstaged
28
+ gh pr diff <n> # PR review
29
+ ```
30
+
31
+ If empty → ask the user to specify files, a PR number, or a directory.
32
+
33
+ 4. Read each changed `.swift` file plus its corresponding test file (if present).
34
+
35
+ ---
36
+
37
+ ## Phase 2 — Analysis
38
+
39
+ ### 0. Spec Adherence
40
+
41
+ | Check | What to verify |
42
+ | -------------------- | -------------------------------------------------------------------------- |
43
+ | Requirement coverage | Every acceptance criterion maps to a concrete code change |
44
+ | Edge cases | Spec edge cases are handled in code |
45
+ | Test coverage | Tests cover scenarios described in the spec |
46
+ | Scope | No unrelated refactors bundled into the PR |
47
+ | Missing work | No `TODO`, `fatalError("not implemented")`, empty bodies, or stubbed mocks |
48
+ | Intent | Code solves the problem stated, not a similar-but-different one |
49
+
50
+ ### 1. Swift Quality
51
+
52
+ **Optionals & Safety**
53
+
54
+ - No force unwraps (`!`), force casts (`as!`), or force-try (`try!`) — use `guard let` with explicit early return
55
+ - Avoid `try?` silently discarding errors; prefer `do/catch` with typed throws
56
+ - Use `guard let` for early-exit, `if let` for scoped binding
57
+ - Avoid implicitly unwrapped optionals (`var x: T!`) except in well-justified `@IBOutlet`-style cases
58
+
59
+ **Concurrency (Swift 6 strict)**
60
+
61
+ - `@Observable` / `@MainActor` classes must not mutate state from background actors
62
+ - All UI-bound state mutations must happen on the main actor
63
+ - Isolate shared mutable state in actors; mark value types `Sendable`
64
+ - Prefer `async throws` over completion handlers; avoid `DispatchQueue.main.async` when `@MainActor` is available
65
+ - Never call `Task.detached` without an explicit `@Sendable` closure
66
+
67
+ **Error Handling**
68
+
69
+ - Use typed `throws` where the caller can meaningfully handle specific errors
70
+ - Never swallow errors silently (`catch {}`)
71
+ - `Result` is appropriate for stored async results; prefer `async throws` for live calls
72
+
73
+ **Naming & Access Control**
74
+
75
+ - Follow Swift API Design Guidelines (fluent usage at call site)
76
+ - Prefer `private`/`internal` over open access; only widen when needed
77
+ - Use `final` on classes not intended for subclassing
78
+
79
+ ### 2. SwiftUI Patterns
80
+
81
+ **State Management**
82
+
83
+ - Use `@Observable` (iOS 17+) instead of `ObservableObject`/`@Published`
84
+ - `@State` → local, transient view state only
85
+ - `@Binding` → two-way child-to-parent connection
86
+ - `@Environment` → shared read access to model/service injected from above
87
+ - No `@StateObject` / `@ObservedObject` for new code targeting iOS 17+
88
+ - No direct data fetching or business logic inside a `var body: some View`
89
+
90
+ **Modern APIs**
91
+
92
+ - Use `NavigationStack` (iOS 16+); never `NavigationView`
93
+ - Use `.task` modifier for async work tied to view lifetime; never `onAppear` + `Task`
94
+ - Use `AsyncImage` for remote images; no manual `URLSession` in the view layer
95
+ - Accessibility: every interactive element needs a meaningful `.accessibilityLabel`
96
+
97
+ **View Composition**
98
+
99
+ - Views > 80 lines or > 2 levels of nesting → extract sub-views or view models
100
+ - No imperative `if`/`else` chains where `@ViewBuilder` can clarify intent
101
+ - Prefer `List` over `ForEach` in a `ScrollView` for standard list UI
102
+
103
+ ### 3. Performance
104
+
105
+ - `View.body` must have no side effects and return quickly — no network I/O, no heavy computation
106
+ - `ForEach` over `Identifiable` items → use stable `.id`; never `\.self` for mutable reference types
107
+ - Add `Equatable` conformance to views with frequent parent redraws
108
+ - Avoid creating closures that capture `self` strongly inside view bodies (retain cycle risk)
109
+ - Use `LazyVStack`/`LazyHStack` for large or unbounded lists
110
+ - `GeometryReader` traps unnecessary layout passes — use `.containerRelativeFrame` on iOS 17+
111
+
112
+ ### 4. Security
113
+
114
+ - Store credentials/tokens in Keychain, never `UserDefaults` or the file system
115
+ - No sensitive data (tokens, passwords, PII) in `print`, `Logger`, or crash reports
116
+ - All network requests must use HTTPS; validate SSL certificates (no `URLSession` with trust overrides)
117
+ - Validate and sanitize all user input before use; avoid `String(format:)` with untrusted data
118
+ - No hard-coded API keys or secrets in source files
119
+
120
+ ### 5. Architecture
121
+
122
+ - View-model separation: views own no business logic, no network calls, no data transformations
123
+ - Dependency injection via constructor; avoid `singleton.shared` inside business logic
124
+ - Repositories / services are protocol-typed for testability
125
+ - Navigation logic (routing, deep links) lives outside the view — Coordinator, `NavigationPath`, or TCA Reducer
126
+ - Test targets can instantiate the system under test without real network/DB
127
+
128
+ ### 6. Project Standards
129
+
130
+ Read `AGENTS.md` for project-specific rules. Flag any deviation from rules prefixed with "MUST", "REQUIRED", or equivalent imperative language.
131
+
132
+ ---
133
+
134
+ ## Phase 2.5 — Pattern Detection
135
+
136
+ After collecting all findings:
137
+
138
+ 1. Group by rule category (e.g., "force-unwrap", "NavigationView", "@MainActor missing").
139
+ 2. Mark any rule that fires **≥ 2 times** as a recurring pattern.
140
+ 3. For each recurring pattern draft a one-line directive suitable for `AGENTS.md`:
141
+ - Bad: "The code sometimes uses force-unwraps"
142
+ - Good: "Never use `!`, `try!`, or `as!`. Use `guard let` with explicit early return."
143
+ 4. If the same pattern appeared in a previous review (check git log), escalate priority.
144
+
145
+ ---
146
+
147
+ ## Phase 3 — Report
148
+
149
+ ```
150
+ # Code Review — <scope>
151
+
152
+ ## Summary
153
+ Files: N | Critical: N | High: N | Medium: N | Low: N
154
+
155
+ ## Spec Adherence
156
+
157
+ **Source**: PR #N / inferred from diff
158
+
159
+ | Requirement | Status | Location |
160
+ |-------------|--------|----------|
161
+ | ... | ✅ / ⚠️ Partial / ❌ Not implemented | file.swift:line |
162
+
163
+ ---
164
+
165
+ ## <Filename.swift>
166
+
167
+ [Critical|High|Medium|Low] **<Category>** (line N)
168
+ Current: `<snippet>`
169
+ Fix: <explanation + corrected snippet>
170
+
171
+ ## Positive Observations
172
+
173
+ <one sentence per notable good practice — never pad>
174
+
175
+ ## Prioritized Action Items
176
+
177
+ - [Must fix] ...
178
+ - [Should fix] ...
179
+ - [Consider] ...
180
+
181
+ ---
182
+
183
+ ## Agent Loop Feedback
184
+
185
+ ### Pattern: <rule name> (<N> occurrences)
186
+ **Files**: file.swift:line, ...
187
+ **Suggested rule for AGENTS.md**:
188
+ > <directive>
189
+ ```
190
+
191
+ **Severity guide**
192
+
193
+ | Level | Meaning |
194
+ | -------- | -------------------------------------------------------------- |
195
+ | Critical | Crash / data race / security hole — block merge |
196
+ | High | Anti-pattern / major architecture violation — fix before merge |
197
+ | Medium | Quality / maintainability — fix in current sprint |
198
+ | Low | Style / suggestion — consider for future |
199
+
200
+ ---
201
+
202
+ ## Platform Commands Reference
203
+
204
+ ```bash
205
+ gh pr diff <n> # GitHub PR diff
206
+ gh pr view <n> --json title,body # PR description
207
+ glab mr diff <n> # GitLab MR diff
208
+ git diff --staged -- '*.swift' # staged changes
209
+ git diff HEAD -- '*.swift' # last commit
210
+ git diff -- path/to/file.swift # single file
211
+ ```